update to upstream sqlite 3.6.17

This commit is contained in:
Stephen Lombardo
2009-08-11 16:01:51 -04:00
parent b9df4d3c78
commit db1d641a44
191 changed files with 28797 additions and 20496 deletions
+4 -2
View File
@@ -488,6 +488,8 @@ sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h
mkdir -p tsrc
cp $(SRC) tsrc
rm tsrc/sqlite.h.in tsrc/parse.y
$(TCLSH_CMD) $(TOP)/tool/vdbe-compress.tcl <tsrc/vdbe.c >vdbe.new
mv vdbe.new tsrc/vdbe.c
touch .target_source
sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl
@@ -495,9 +497,9 @@ sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl
# Rules to build the LEMON compiler generator
#
lemon$(BEXE): $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
lemon$(BEXE): $(TOP)/tool/lemon.c $(TOP)/src/lempar.c
$(BCC) -o $@ $(TOP)/tool/lemon.c
cp $(TOP)/tool/lempar.c .
cp $(TOP)/src/lempar.c .
# Rule to build the amalgamation
+2 -2
View File
@@ -489,9 +489,9 @@ fts3amal.c: target_source $(TOP)/ext/fts3/mkfts3amal.tcl
# Rules to build the LEMON compiler generator
#
lemon: $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
lemon: $(TOP)/tool/lemon.c $(TOP)/src/lempar.c
$(BCC) -o lemon $(TOP)/tool/lemon.c
cp $(TOP)/tool/lempar.c .
cp $(TOP)/src/lempar.c .
# Rules to build individual *.o files from generated *.c files. This
# applies to:
+1 -1
View File
@@ -1 +1 @@
3.6.14
3.6.17
File diff suppressed because it is too large Load Diff
+67
View File
@@ -0,0 +1,67 @@
# This file was generated.
# It contains the lists of macros which have been traced.
# It can be safely removed.
@request = (
bless( [
'0',
1,
[
'/usr/share/autoconf'
],
[
'/usr/share/autoconf/autoconf/autoconf.m4f',
'aclocal.m4',
'configure.ac'
],
{
'_LT_AC_TAGCONFIG' => 1,
'AM_PROG_F77_C_O' => 1,
'AC_INIT' => 1,
'm4_pattern_forbid' => 1,
'_AM_COND_IF' => 1,
'AC_CANONICAL_TARGET' => 1,
'AC_SUBST' => 1,
'AC_CONFIG_LIBOBJ_DIR' => 1,
'AC_FC_SRCEXT' => 1,
'AC_CANONICAL_HOST' => 1,
'AC_PROG_LIBTOOL' => 1,
'AM_INIT_AUTOMAKE' => 1,
'AC_CONFIG_SUBDIRS' => 1,
'AM_AUTOMAKE_VERSION' => 1,
'LT_CONFIG_LTDL_DIR' => 1,
'AC_REQUIRE_AUX_FILE' => 1,
'AC_CONFIG_LINKS' => 1,
'm4_sinclude' => 1,
'LT_SUPPORTED_TAG' => 1,
'AM_MAINTAINER_MODE' => 1,
'AM_GNU_GETTEXT_INTL_SUBDIR' => 1,
'_m4_warn' => 1,
'AM_PROG_CXX_C_O' => 1,
'_AM_COND_ENDIF' => 1,
'AM_ENABLE_MULTILIB' => 1,
'AC_CONFIG_FILES' => 1,
'include' => 1,
'LT_INIT' => 1,
'AM_GNU_GETTEXT' => 1,
'AC_LIBSOURCE' => 1,
'AM_PROG_FC_C_O' => 1,
'AC_CANONICAL_BUILD' => 1,
'AC_FC_FREEFORM' => 1,
'AH_OUTPUT' => 1,
'_AM_SUBST_NOTMAKE' => 1,
'AC_CONFIG_AUX_DIR' => 1,
'sinclude' => 1,
'm4_pattern_allow' => 1,
'AM_PROG_CC_C_O' => 1,
'AC_CANONICAL_SYSTEM' => 1,
'AM_CONDITIONAL' => 1,
'AC_CONFIG_HEADERS' => 1,
'AC_DEFINE_TRACE_LITERAL' => 1,
'm4_include' => 1,
'_AM_COND_ELSE' => 1,
'AC_SUBST_TRACE' => 1
}
], 'Autom4te::Request' )
);
+610
View File
@@ -0,0 +1,610 @@
m4trace:configure.ac:90: -1- AC_INIT([sqlite], [3.6.17])
m4trace:configure.ac:90: -1- m4_pattern_forbid([^_?A[CHUM]_])
m4trace:configure.ac:90: -1- m4_pattern_forbid([_AC_])
m4trace:configure.ac:90: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section `AC_LIBOBJ vs LIBOBJS'])
m4trace:configure.ac:90: -1- m4_pattern_allow([^AS_FLAGS$])
m4trace:configure.ac:90: -1- m4_pattern_forbid([^_?m4_])
m4trace:configure.ac:90: -1- m4_pattern_forbid([^dnl$])
m4trace:configure.ac:90: -1- m4_pattern_forbid([^_?AS_])
m4trace:configure.ac:90: -1- AC_SUBST([SHELL], [${CONFIG_SHELL-/bin/sh}])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([SHELL])
m4trace:configure.ac:90: -1- m4_pattern_allow([^SHELL$])
m4trace:configure.ac:90: -1- AC_SUBST([PATH_SEPARATOR])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([PATH_SEPARATOR])
m4trace:configure.ac:90: -1- m4_pattern_allow([^PATH_SEPARATOR$])
m4trace:configure.ac:90: -1- AC_SUBST([PACKAGE_NAME], [m4_ifdef([AC_PACKAGE_NAME], ['AC_PACKAGE_NAME'])])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([PACKAGE_NAME])
m4trace:configure.ac:90: -1- m4_pattern_allow([^PACKAGE_NAME$])
m4trace:configure.ac:90: -1- AC_SUBST([PACKAGE_TARNAME], [m4_ifdef([AC_PACKAGE_TARNAME], ['AC_PACKAGE_TARNAME'])])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([PACKAGE_TARNAME])
m4trace:configure.ac:90: -1- m4_pattern_allow([^PACKAGE_TARNAME$])
m4trace:configure.ac:90: -1- AC_SUBST([PACKAGE_VERSION], [m4_ifdef([AC_PACKAGE_VERSION], ['AC_PACKAGE_VERSION'])])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([PACKAGE_VERSION])
m4trace:configure.ac:90: -1- m4_pattern_allow([^PACKAGE_VERSION$])
m4trace:configure.ac:90: -1- AC_SUBST([PACKAGE_STRING], [m4_ifdef([AC_PACKAGE_STRING], ['AC_PACKAGE_STRING'])])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([PACKAGE_STRING])
m4trace:configure.ac:90: -1- m4_pattern_allow([^PACKAGE_STRING$])
m4trace:configure.ac:90: -1- AC_SUBST([PACKAGE_BUGREPORT], [m4_ifdef([AC_PACKAGE_BUGREPORT], ['AC_PACKAGE_BUGREPORT'])])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([PACKAGE_BUGREPORT])
m4trace:configure.ac:90: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$])
m4trace:configure.ac:90: -1- AC_SUBST([exec_prefix], [NONE])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([exec_prefix])
m4trace:configure.ac:90: -1- m4_pattern_allow([^exec_prefix$])
m4trace:configure.ac:90: -1- AC_SUBST([prefix], [NONE])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([prefix])
m4trace:configure.ac:90: -1- m4_pattern_allow([^prefix$])
m4trace:configure.ac:90: -1- AC_SUBST([program_transform_name], [s,x,x,])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([program_transform_name])
m4trace:configure.ac:90: -1- m4_pattern_allow([^program_transform_name$])
m4trace:configure.ac:90: -1- AC_SUBST([bindir], ['${exec_prefix}/bin'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([bindir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^bindir$])
m4trace:configure.ac:90: -1- AC_SUBST([sbindir], ['${exec_prefix}/sbin'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([sbindir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^sbindir$])
m4trace:configure.ac:90: -1- AC_SUBST([libexecdir], ['${exec_prefix}/libexec'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([libexecdir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^libexecdir$])
m4trace:configure.ac:90: -1- AC_SUBST([datarootdir], ['${prefix}/share'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([datarootdir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^datarootdir$])
m4trace:configure.ac:90: -1- AC_SUBST([datadir], ['${datarootdir}'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([datadir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^datadir$])
m4trace:configure.ac:90: -1- AC_SUBST([sysconfdir], ['${prefix}/etc'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([sysconfdir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^sysconfdir$])
m4trace:configure.ac:90: -1- AC_SUBST([sharedstatedir], ['${prefix}/com'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([sharedstatedir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^sharedstatedir$])
m4trace:configure.ac:90: -1- AC_SUBST([localstatedir], ['${prefix}/var'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([localstatedir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^localstatedir$])
m4trace:configure.ac:90: -1- AC_SUBST([includedir], ['${prefix}/include'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([includedir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^includedir$])
m4trace:configure.ac:90: -1- AC_SUBST([oldincludedir], ['/usr/include'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([oldincludedir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^oldincludedir$])
m4trace:configure.ac:90: -1- AC_SUBST([docdir], [m4_ifset([AC_PACKAGE_TARNAME],
['${datarootdir}/doc/${PACKAGE_TARNAME}'],
['${datarootdir}/doc/${PACKAGE}'])])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([docdir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^docdir$])
m4trace:configure.ac:90: -1- AC_SUBST([infodir], ['${datarootdir}/info'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([infodir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^infodir$])
m4trace:configure.ac:90: -1- AC_SUBST([htmldir], ['${docdir}'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([htmldir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^htmldir$])
m4trace:configure.ac:90: -1- AC_SUBST([dvidir], ['${docdir}'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([dvidir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^dvidir$])
m4trace:configure.ac:90: -1- AC_SUBST([pdfdir], ['${docdir}'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([pdfdir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^pdfdir$])
m4trace:configure.ac:90: -1- AC_SUBST([psdir], ['${docdir}'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([psdir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^psdir$])
m4trace:configure.ac:90: -1- AC_SUBST([libdir], ['${exec_prefix}/lib'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([libdir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^libdir$])
m4trace:configure.ac:90: -1- AC_SUBST([localedir], ['${datarootdir}/locale'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([localedir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^localedir$])
m4trace:configure.ac:90: -1- AC_SUBST([mandir], ['${datarootdir}/man'])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([mandir])
m4trace:configure.ac:90: -1- m4_pattern_allow([^mandir$])
m4trace:configure.ac:90: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_NAME])
m4trace:configure.ac:90: -1- m4_pattern_allow([^PACKAGE_NAME$])
m4trace:configure.ac:90: -1- AH_OUTPUT([PACKAGE_NAME], [/* Define to the full name of this package. */
#undef PACKAGE_NAME])
m4trace:configure.ac:90: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_TARNAME])
m4trace:configure.ac:90: -1- m4_pattern_allow([^PACKAGE_TARNAME$])
m4trace:configure.ac:90: -1- AH_OUTPUT([PACKAGE_TARNAME], [/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME])
m4trace:configure.ac:90: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_VERSION])
m4trace:configure.ac:90: -1- m4_pattern_allow([^PACKAGE_VERSION$])
m4trace:configure.ac:90: -1- AH_OUTPUT([PACKAGE_VERSION], [/* Define to the version of this package. */
#undef PACKAGE_VERSION])
m4trace:configure.ac:90: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_STRING])
m4trace:configure.ac:90: -1- m4_pattern_allow([^PACKAGE_STRING$])
m4trace:configure.ac:90: -1- AH_OUTPUT([PACKAGE_STRING], [/* Define to the full name and version of this package. */
#undef PACKAGE_STRING])
m4trace:configure.ac:90: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_BUGREPORT])
m4trace:configure.ac:90: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$])
m4trace:configure.ac:90: -1- AH_OUTPUT([PACKAGE_BUGREPORT], [/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT])
m4trace:configure.ac:90: -1- AC_SUBST([DEFS])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([DEFS])
m4trace:configure.ac:90: -1- m4_pattern_allow([^DEFS$])
m4trace:configure.ac:90: -1- AC_SUBST([ECHO_C])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([ECHO_C])
m4trace:configure.ac:90: -1- m4_pattern_allow([^ECHO_C$])
m4trace:configure.ac:90: -1- AC_SUBST([ECHO_N])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([ECHO_N])
m4trace:configure.ac:90: -1- m4_pattern_allow([^ECHO_N$])
m4trace:configure.ac:90: -1- AC_SUBST([ECHO_T])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([ECHO_T])
m4trace:configure.ac:90: -1- m4_pattern_allow([^ECHO_T$])
m4trace:configure.ac:90: -1- AC_SUBST([LIBS])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([LIBS])
m4trace:configure.ac:90: -1- m4_pattern_allow([^LIBS$])
m4trace:configure.ac:90: -1- AC_SUBST([build_alias])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([build_alias])
m4trace:configure.ac:90: -1- m4_pattern_allow([^build_alias$])
m4trace:configure.ac:90: -1- AC_SUBST([host_alias])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([host_alias])
m4trace:configure.ac:90: -1- m4_pattern_allow([^host_alias$])
m4trace:configure.ac:90: -1- AC_SUBST([target_alias])
m4trace:configure.ac:90: -1- AC_SUBST_TRACE([target_alias])
m4trace:configure.ac:90: -1- m4_pattern_allow([^target_alias$])
m4trace:configure.ac:109: -1- AC_PROG_LIBTOOL
m4trace:configure.ac:109: -1- _m4_warn([obsolete], [The macro `AC_PROG_LIBTOOL' is obsolete.
You should run autoupdate.], [aclocal.m4:115: AC_PROG_LIBTOOL is expanded from...
configure.ac:109: the top level])
m4trace:configure.ac:109: -1- LT_INIT
m4trace:configure.ac:109: -1- m4_pattern_forbid([^_?LT_[A-Z_]+$])
m4trace:configure.ac:109: -1- m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])
m4trace:configure.ac:109: -1- AC_REQUIRE_AUX_FILE([ltmain.sh])
m4trace:configure.ac:109: -1- AC_SUBST([LIBTOOL])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([LIBTOOL])
m4trace:configure.ac:109: -1- m4_pattern_allow([^LIBTOOL$])
m4trace:configure.ac:109: -1- AC_CANONICAL_HOST
m4trace:configure.ac:109: -1- AC_CANONICAL_BUILD
m4trace:configure.ac:109: -1- AC_REQUIRE_AUX_FILE([config.sub])
m4trace:configure.ac:109: -1- AC_REQUIRE_AUX_FILE([config.guess])
m4trace:configure.ac:109: -1- AC_SUBST([build], [$ac_cv_build])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([build])
m4trace:configure.ac:109: -1- m4_pattern_allow([^build$])
m4trace:configure.ac:109: -1- AC_SUBST([build_cpu], [$[1]])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([build_cpu])
m4trace:configure.ac:109: -1- m4_pattern_allow([^build_cpu$])
m4trace:configure.ac:109: -1- AC_SUBST([build_vendor], [$[2]])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([build_vendor])
m4trace:configure.ac:109: -1- m4_pattern_allow([^build_vendor$])
m4trace:configure.ac:109: -1- AC_SUBST([build_os])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([build_os])
m4trace:configure.ac:109: -1- m4_pattern_allow([^build_os$])
m4trace:configure.ac:109: -1- AC_SUBST([host], [$ac_cv_host])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([host])
m4trace:configure.ac:109: -1- m4_pattern_allow([^host$])
m4trace:configure.ac:109: -1- AC_SUBST([host_cpu], [$[1]])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([host_cpu])
m4trace:configure.ac:109: -1- m4_pattern_allow([^host_cpu$])
m4trace:configure.ac:109: -1- AC_SUBST([host_vendor], [$[2]])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([host_vendor])
m4trace:configure.ac:109: -1- m4_pattern_allow([^host_vendor$])
m4trace:configure.ac:109: -1- AC_SUBST([host_os])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([host_os])
m4trace:configure.ac:109: -1- m4_pattern_allow([^host_os$])
m4trace:configure.ac:109: -1- AC_SUBST([CC])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([CC])
m4trace:configure.ac:109: -1- m4_pattern_allow([^CC$])
m4trace:configure.ac:109: -1- AC_SUBST([CFLAGS])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([CFLAGS])
m4trace:configure.ac:109: -1- m4_pattern_allow([^CFLAGS$])
m4trace:configure.ac:109: -1- AC_SUBST([LDFLAGS])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([LDFLAGS])
m4trace:configure.ac:109: -1- m4_pattern_allow([^LDFLAGS$])
m4trace:configure.ac:109: -1- AC_SUBST([LIBS])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([LIBS])
m4trace:configure.ac:109: -1- m4_pattern_allow([^LIBS$])
m4trace:configure.ac:109: -1- AC_SUBST([CPPFLAGS])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([CPPFLAGS])
m4trace:configure.ac:109: -1- m4_pattern_allow([^CPPFLAGS$])
m4trace:configure.ac:109: -1- AC_SUBST([CC])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([CC])
m4trace:configure.ac:109: -1- m4_pattern_allow([^CC$])
m4trace:configure.ac:109: -1- AC_SUBST([CC])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([CC])
m4trace:configure.ac:109: -1- m4_pattern_allow([^CC$])
m4trace:configure.ac:109: -1- AC_SUBST([CC])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([CC])
m4trace:configure.ac:109: -1- m4_pattern_allow([^CC$])
m4trace:configure.ac:109: -1- AC_SUBST([CC])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([CC])
m4trace:configure.ac:109: -1- m4_pattern_allow([^CC$])
m4trace:configure.ac:109: -1- AC_SUBST([ac_ct_CC])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([ac_ct_CC])
m4trace:configure.ac:109: -1- m4_pattern_allow([^ac_ct_CC$])
m4trace:configure.ac:109: -1- AC_SUBST([EXEEXT], [$ac_cv_exeext])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([EXEEXT])
m4trace:configure.ac:109: -1- m4_pattern_allow([^EXEEXT$])
m4trace:configure.ac:109: -1- AC_SUBST([OBJEXT], [$ac_cv_objext])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([OBJEXT])
m4trace:configure.ac:109: -1- m4_pattern_allow([^OBJEXT$])
m4trace:configure.ac:109: -1- AC_SUBST([SED])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([SED])
m4trace:configure.ac:109: -1- m4_pattern_allow([^SED$])
m4trace:configure.ac:109: -1- AC_SUBST([GREP])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([GREP])
m4trace:configure.ac:109: -1- m4_pattern_allow([^GREP$])
m4trace:configure.ac:109: -1- AC_SUBST([EGREP])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([EGREP])
m4trace:configure.ac:109: -1- m4_pattern_allow([^EGREP$])
m4trace:configure.ac:109: -1- AC_SUBST([FGREP])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([FGREP])
m4trace:configure.ac:109: -1- m4_pattern_allow([^FGREP$])
m4trace:configure.ac:109: -1- AC_SUBST([GREP])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([GREP])
m4trace:configure.ac:109: -1- m4_pattern_allow([^GREP$])
m4trace:configure.ac:109: -1- AC_SUBST([LD])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([LD])
m4trace:configure.ac:109: -1- m4_pattern_allow([^LD$])
m4trace:configure.ac:109: -1- AC_SUBST([DUMPBIN])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([DUMPBIN])
m4trace:configure.ac:109: -1- m4_pattern_allow([^DUMPBIN$])
m4trace:configure.ac:109: -1- AC_SUBST([ac_ct_DUMPBIN])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([ac_ct_DUMPBIN])
m4trace:configure.ac:109: -1- m4_pattern_allow([^ac_ct_DUMPBIN$])
m4trace:configure.ac:109: -1- AC_SUBST([DUMPBIN])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([DUMPBIN])
m4trace:configure.ac:109: -1- m4_pattern_allow([^DUMPBIN$])
m4trace:configure.ac:109: -1- AC_SUBST([NM])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([NM])
m4trace:configure.ac:109: -1- m4_pattern_allow([^NM$])
m4trace:configure.ac:109: -1- AC_SUBST([LN_S], [$as_ln_s])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([LN_S])
m4trace:configure.ac:109: -1- m4_pattern_allow([^LN_S$])
m4trace:configure.ac:109: -1- AC_SUBST([OBJDUMP])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([OBJDUMP])
m4trace:configure.ac:109: -1- m4_pattern_allow([^OBJDUMP$])
m4trace:configure.ac:109: -1- AC_SUBST([OBJDUMP])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([OBJDUMP])
m4trace:configure.ac:109: -1- m4_pattern_allow([^OBJDUMP$])
m4trace:configure.ac:109: -1- AC_SUBST([AR])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([AR])
m4trace:configure.ac:109: -1- m4_pattern_allow([^AR$])
m4trace:configure.ac:109: -1- AC_SUBST([STRIP])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([STRIP])
m4trace:configure.ac:109: -1- m4_pattern_allow([^STRIP$])
m4trace:configure.ac:109: -1- AC_SUBST([RANLIB])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([RANLIB])
m4trace:configure.ac:109: -1- m4_pattern_allow([^RANLIB$])
m4trace:configure.ac:109: -1- m4_pattern_allow([LT_OBJDIR])
m4trace:configure.ac:109: -1- AC_DEFINE_TRACE_LITERAL([LT_OBJDIR])
m4trace:configure.ac:109: -1- m4_pattern_allow([^LT_OBJDIR$])
m4trace:configure.ac:109: -1- AH_OUTPUT([LT_OBJDIR], [/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#undef LT_OBJDIR])
m4trace:configure.ac:109: -1- AC_SUBST([lt_ECHO])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([lt_ECHO])
m4trace:configure.ac:109: -1- m4_pattern_allow([^lt_ECHO$])
m4trace:configure.ac:109: -1- LT_SUPPORTED_TAG([CC])
m4trace:configure.ac:109: -1- AC_SUBST([DSYMUTIL])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([DSYMUTIL])
m4trace:configure.ac:109: -1- m4_pattern_allow([^DSYMUTIL$])
m4trace:configure.ac:109: -1- AC_SUBST([NMEDIT])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([NMEDIT])
m4trace:configure.ac:109: -1- m4_pattern_allow([^NMEDIT$])
m4trace:configure.ac:109: -1- AC_SUBST([LIPO])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([LIPO])
m4trace:configure.ac:109: -1- m4_pattern_allow([^LIPO$])
m4trace:configure.ac:109: -1- AC_SUBST([OTOOL])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([OTOOL])
m4trace:configure.ac:109: -1- m4_pattern_allow([^OTOOL$])
m4trace:configure.ac:109: -1- AC_SUBST([OTOOL64])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([OTOOL64])
m4trace:configure.ac:109: -1- m4_pattern_allow([^OTOOL64$])
m4trace:configure.ac:109: -1- AH_OUTPUT([HAVE_DLFCN_H], [/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H])
m4trace:configure.ac:109: -1- AC_SUBST([CPP])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([CPP])
m4trace:configure.ac:109: -1- m4_pattern_allow([^CPP$])
m4trace:configure.ac:109: -1- AC_SUBST([CPPFLAGS])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([CPPFLAGS])
m4trace:configure.ac:109: -1- m4_pattern_allow([^CPPFLAGS$])
m4trace:configure.ac:109: -1- AC_SUBST([CPP])
m4trace:configure.ac:109: -1- AC_SUBST_TRACE([CPP])
m4trace:configure.ac:109: -1- m4_pattern_allow([^CPP$])
m4trace:configure.ac:109: -1- AC_DEFINE_TRACE_LITERAL([STDC_HEADERS])
m4trace:configure.ac:109: -1- m4_pattern_allow([^STDC_HEADERS$])
m4trace:configure.ac:109: -1- AH_OUTPUT([STDC_HEADERS], [/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS])
m4trace:configure.ac:109: -1- AH_OUTPUT([HAVE_SYS_TYPES_H], [/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H])
m4trace:configure.ac:109: -1- AH_OUTPUT([HAVE_SYS_STAT_H], [/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H])
m4trace:configure.ac:109: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H])
m4trace:configure.ac:109: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H])
m4trace:configure.ac:109: -1- AH_OUTPUT([HAVE_MEMORY_H], [/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H])
m4trace:configure.ac:109: -1- AH_OUTPUT([HAVE_STRINGS_H], [/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H])
m4trace:configure.ac:109: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H])
m4trace:configure.ac:109: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H])
m4trace:configure.ac:109: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H])
m4trace:configure.ac:110: -1- AC_REQUIRE_AUX_FILE([install-sh])
m4trace:configure.ac:110: -1- AC_SUBST([INSTALL_PROGRAM])
m4trace:configure.ac:110: -1- AC_SUBST_TRACE([INSTALL_PROGRAM])
m4trace:configure.ac:110: -1- m4_pattern_allow([^INSTALL_PROGRAM$])
m4trace:configure.ac:110: -1- AC_SUBST([INSTALL_SCRIPT])
m4trace:configure.ac:110: -1- AC_SUBST_TRACE([INSTALL_SCRIPT])
m4trace:configure.ac:110: -1- m4_pattern_allow([^INSTALL_SCRIPT$])
m4trace:configure.ac:110: -1- AC_SUBST([INSTALL_DATA])
m4trace:configure.ac:110: -1- AC_SUBST_TRACE([INSTALL_DATA])
m4trace:configure.ac:110: -1- m4_pattern_allow([^INSTALL_DATA$])
m4trace:configure.ac:111: -1- AC_SUBST([AWK])
m4trace:configure.ac:111: -1- AC_SUBST_TRACE([AWK])
m4trace:configure.ac:111: -1- m4_pattern_allow([^AWK$])
m4trace:configure.ac:116: -1- AC_DEFINE_TRACE_LITERAL([_FILE_OFFSET_BITS])
m4trace:configure.ac:116: -1- m4_pattern_allow([^_FILE_OFFSET_BITS$])
m4trace:configure.ac:116: -1- AH_OUTPUT([_FILE_OFFSET_BITS], [/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS])
m4trace:configure.ac:116: -1- AC_DEFINE_TRACE_LITERAL([_LARGE_FILES])
m4trace:configure.ac:116: -1- m4_pattern_allow([^_LARGE_FILES$])
m4trace:configure.ac:116: -1- AH_OUTPUT([_LARGE_FILES], [/* Define for large files, on AIX-style hosts. */
#undef _LARGE_FILES])
m4trace:configure.ac:120: -1- AC_DEFINE_TRACE_LITERAL([HAVE_INT8_T])
m4trace:configure.ac:120: -1- m4_pattern_allow([^HAVE_INT8_T$])
m4trace:configure.ac:120: -1- AH_OUTPUT([HAVE_INT8_T], [/* Define to 1 if the system has the type `int8_t\'. */
#undef HAVE_INT8_T])
m4trace:configure.ac:120: -1- AC_DEFINE_TRACE_LITERAL([HAVE_INT16_T])
m4trace:configure.ac:120: -1- m4_pattern_allow([^HAVE_INT16_T$])
m4trace:configure.ac:120: -1- AH_OUTPUT([HAVE_INT16_T], [/* Define to 1 if the system has the type `int16_t\'. */
#undef HAVE_INT16_T])
m4trace:configure.ac:120: -1- AC_DEFINE_TRACE_LITERAL([HAVE_INT32_T])
m4trace:configure.ac:120: -1- m4_pattern_allow([^HAVE_INT32_T$])
m4trace:configure.ac:120: -1- AH_OUTPUT([HAVE_INT32_T], [/* Define to 1 if the system has the type `int32_t\'. */
#undef HAVE_INT32_T])
m4trace:configure.ac:120: -1- AC_DEFINE_TRACE_LITERAL([HAVE_INT64_T])
m4trace:configure.ac:120: -1- m4_pattern_allow([^HAVE_INT64_T$])
m4trace:configure.ac:120: -1- AH_OUTPUT([HAVE_INT64_T], [/* Define to 1 if the system has the type `int64_t\'. */
#undef HAVE_INT64_T])
m4trace:configure.ac:120: -1- AC_DEFINE_TRACE_LITERAL([HAVE_INTPTR_T])
m4trace:configure.ac:120: -1- m4_pattern_allow([^HAVE_INTPTR_T$])
m4trace:configure.ac:120: -1- AH_OUTPUT([HAVE_INTPTR_T], [/* Define to 1 if the system has the type `intptr_t\'. */
#undef HAVE_INTPTR_T])
m4trace:configure.ac:120: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UINT8_T])
m4trace:configure.ac:120: -1- m4_pattern_allow([^HAVE_UINT8_T$])
m4trace:configure.ac:120: -1- AH_OUTPUT([HAVE_UINT8_T], [/* Define to 1 if the system has the type `uint8_t\'. */
#undef HAVE_UINT8_T])
m4trace:configure.ac:120: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UINT16_T])
m4trace:configure.ac:120: -1- m4_pattern_allow([^HAVE_UINT16_T$])
m4trace:configure.ac:120: -1- AH_OUTPUT([HAVE_UINT16_T], [/* Define to 1 if the system has the type `uint16_t\'. */
#undef HAVE_UINT16_T])
m4trace:configure.ac:120: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UINT32_T])
m4trace:configure.ac:120: -1- m4_pattern_allow([^HAVE_UINT32_T$])
m4trace:configure.ac:120: -1- AH_OUTPUT([HAVE_UINT32_T], [/* Define to 1 if the system has the type `uint32_t\'. */
#undef HAVE_UINT32_T])
m4trace:configure.ac:120: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UINT64_T])
m4trace:configure.ac:120: -1- m4_pattern_allow([^HAVE_UINT64_T$])
m4trace:configure.ac:120: -1- AH_OUTPUT([HAVE_UINT64_T], [/* Define to 1 if the system has the type `uint64_t\'. */
#undef HAVE_UINT64_T])
m4trace:configure.ac:120: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UINTPTR_T])
m4trace:configure.ac:120: -1- m4_pattern_allow([^HAVE_UINTPTR_T$])
m4trace:configure.ac:120: -1- AH_OUTPUT([HAVE_UINTPTR_T], [/* Define to 1 if the system has the type `uintptr_t\'. */
#undef HAVE_UINTPTR_T])
m4trace:configure.ac:125: -1- AH_OUTPUT([HAVE_SYS_TYPES_H], [/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H])
m4trace:configure.ac:125: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H])
m4trace:configure.ac:125: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H])
m4trace:configure.ac:125: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H])
m4trace:configure.ac:130: -1- AH_OUTPUT([HAVE_USLEEP], [/* Define to 1 if you have the `usleep\' function. */
#undef HAVE_USLEEP])
m4trace:configure.ac:130: -1- AH_OUTPUT([HAVE_FDATASYNC], [/* Define to 1 if you have the `fdatasync\' function. */
#undef HAVE_FDATASYNC])
m4trace:configure.ac:130: -1- AH_OUTPUT([HAVE_LOCALTIME_R], [/* Define to 1 if you have the `localtime_r\' function. */
#undef HAVE_LOCALTIME_R])
m4trace:configure.ac:130: -1- AH_OUTPUT([HAVE_GMTIME_R], [/* Define to 1 if you have the `gmtime_r\' function. */
#undef HAVE_GMTIME_R])
m4trace:configure.ac:130: -1- AH_OUTPUT([HAVE_LOCALTIME_S], [/* Define to 1 if you have the `localtime_s\' function. */
#undef HAVE_LOCALTIME_S])
m4trace:configure.ac:142: -1- AC_SUBST([TCLSH_CMD])
m4trace:configure.ac:142: -1- AC_SUBST_TRACE([TCLSH_CMD])
m4trace:configure.ac:142: -1- m4_pattern_allow([^TCLSH_CMD$])
m4trace:configure.ac:150: -1- AC_SUBST([TCLSH_CMD])
m4trace:configure.ac:150: -1- AC_SUBST_TRACE([TCLSH_CMD])
m4trace:configure.ac:150: -1- m4_pattern_allow([^TCLSH_CMD$])
m4trace:configure.ac:152: -1- AC_SUBST([TCLLIBDIR])
m4trace:configure.ac:152: -1- AC_SUBST_TRACE([TCLLIBDIR])
m4trace:configure.ac:152: -1- m4_pattern_allow([^TCLLIBDIR$])
m4trace:configure.ac:169: -1- AC_SUBST([program_prefix])
m4trace:configure.ac:169: -1- AC_SUBST_TRACE([program_prefix])
m4trace:configure.ac:169: -1- m4_pattern_allow([^program_prefix$])
m4trace:configure.ac:173: -1- AC_SUBST([VERSION])
m4trace:configure.ac:173: -1- AC_SUBST_TRACE([VERSION])
m4trace:configure.ac:173: -1- m4_pattern_allow([^VERSION$])
m4trace:configure.ac:176: -1- AC_SUBST([RELEASE])
m4trace:configure.ac:176: -1- AC_SUBST_TRACE([RELEASE])
m4trace:configure.ac:176: -1- m4_pattern_allow([^RELEASE$])
m4trace:configure.ac:181: -1- AC_SUBST([VERSION_NUMBER])
m4trace:configure.ac:181: -1- AC_SUBST_TRACE([VERSION_NUMBER])
m4trace:configure.ac:181: -1- m4_pattern_allow([^VERSION_NUMBER$])
m4trace:configure.ac:191: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete.
You should run autoupdate.], [../../lib/autoconf/general.m4:209: AC_HELP_STRING is expanded from...
configure.ac:191: the top level])
m4trace:configure.ac:227: -1- AC_SUBST([BUILD_CC])
m4trace:configure.ac:227: -1- AC_SUBST_TRACE([BUILD_CC])
m4trace:configure.ac:227: -1- m4_pattern_allow([^BUILD_CC$])
m4trace:configure.ac:233: -1- AC_SUBST([BUILD_CC])
m4trace:configure.ac:233: -1- AC_SUBST_TRACE([BUILD_CC])
m4trace:configure.ac:233: -1- m4_pattern_allow([^BUILD_CC$])
m4trace:configure.ac:239: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete.
You should run autoupdate.], [../../lib/autoconf/general.m4:209: AC_HELP_STRING is expanded from...
configure.ac:239: the top level])
m4trace:configure.ac:248: -1- AC_SUBST([SQLITE_THREADSAFE])
m4trace:configure.ac:248: -1- AC_SUBST_TRACE([SQLITE_THREADSAFE])
m4trace:configure.ac:248: -1- m4_pattern_allow([^SQLITE_THREADSAFE$])
m4trace:configure.ac:260: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete.
You should run autoupdate.], [../../lib/autoconf/general.m4:209: AC_HELP_STRING is expanded from...
configure.ac:260: the top level])
m4trace:configure.ac:269: -1- AC_SUBST([XTHREADCONNECT])
m4trace:configure.ac:269: -1- AC_SUBST_TRACE([XTHREADCONNECT])
m4trace:configure.ac:269: -1- m4_pattern_allow([^XTHREADCONNECT$])
m4trace:configure.ac:278: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete.
You should run autoupdate.], [../../lib/autoconf/general.m4:209: AC_HELP_STRING is expanded from...
configure.ac:278: the top level])
m4trace:configure.ac:287: -1- AC_SUBST([THREADSOVERRIDELOCKS])
m4trace:configure.ac:287: -1- AC_SUBST_TRACE([THREADSOVERRIDELOCKS])
m4trace:configure.ac:287: -1- m4_pattern_allow([^THREADSOVERRIDELOCKS$])
m4trace:configure.ac:293: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete.
You should run autoupdate.], [../../lib/autoconf/general.m4:209: AC_HELP_STRING is expanded from...
configure.ac:293: the top level])
m4trace:configure.ac:302: -1- AC_SUBST([ALLOWRELEASE])
m4trace:configure.ac:302: -1- AC_SUBST_TRACE([ALLOWRELEASE])
m4trace:configure.ac:302: -1- m4_pattern_allow([^ALLOWRELEASE$])
m4trace:configure.ac:308: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete.
You should run autoupdate.], [../../lib/autoconf/general.m4:209: AC_HELP_STRING is expanded from...
configure.ac:308: the top level])
m4trace:configure.ac:333: -1- AC_SUBST([TEMP_STORE])
m4trace:configure.ac:333: -1- AC_SUBST_TRACE([TEMP_STORE])
m4trace:configure.ac:333: -1- m4_pattern_allow([^TEMP_STORE$])
m4trace:configure.ac:348: -1- _m4_warn([obsolete], [The macro `AC_CYGWIN' is obsolete.
You should run autoupdate.], [../../lib/autoconf/specific.m4:338: AC_CYGWIN is expanded from...
configure.ac:348: the top level])
m4trace:configure.ac:348: -1- AC_CANONICAL_HOST
m4trace:configure.ac:348: -1- AC_SUBST([host], [$ac_cv_host])
m4trace:configure.ac:348: -1- AC_SUBST_TRACE([host])
m4trace:configure.ac:348: -1- m4_pattern_allow([^host$])
m4trace:configure.ac:348: -1- AC_SUBST([host_cpu], [$[1]])
m4trace:configure.ac:348: -1- AC_SUBST_TRACE([host_cpu])
m4trace:configure.ac:348: -1- m4_pattern_allow([^host_cpu$])
m4trace:configure.ac:348: -1- AC_SUBST([host_vendor], [$[2]])
m4trace:configure.ac:348: -1- AC_SUBST_TRACE([host_vendor])
m4trace:configure.ac:348: -1- m4_pattern_allow([^host_vendor$])
m4trace:configure.ac:348: -1- AC_SUBST([host_os])
m4trace:configure.ac:348: -1- AC_SUBST_TRACE([host_os])
m4trace:configure.ac:348: -1- m4_pattern_allow([^host_os$])
m4trace:configure.ac:379: -1- AC_SUBST([BUILD_EXEEXT])
m4trace:configure.ac:379: -1- AC_SUBST_TRACE([BUILD_EXEEXT])
m4trace:configure.ac:379: -1- m4_pattern_allow([^BUILD_EXEEXT$])
m4trace:configure.ac:380: -1- AC_SUBST([SQLITE_OS_UNIX])
m4trace:configure.ac:380: -1- AC_SUBST_TRACE([SQLITE_OS_UNIX])
m4trace:configure.ac:380: -1- m4_pattern_allow([^SQLITE_OS_UNIX$])
m4trace:configure.ac:381: -1- AC_SUBST([SQLITE_OS_WIN])
m4trace:configure.ac:381: -1- AC_SUBST_TRACE([SQLITE_OS_WIN])
m4trace:configure.ac:381: -1- m4_pattern_allow([^SQLITE_OS_WIN$])
m4trace:configure.ac:382: -1- AC_SUBST([SQLITE_OS_OS2])
m4trace:configure.ac:382: -1- AC_SUBST_TRACE([SQLITE_OS_OS2])
m4trace:configure.ac:382: -1- m4_pattern_allow([^SQLITE_OS_OS2$])
m4trace:configure.ac:383: -1- AC_SUBST([TARGET_EXEEXT])
m4trace:configure.ac:383: -1- AC_SUBST_TRACE([TARGET_EXEEXT])
m4trace:configure.ac:383: -1- m4_pattern_allow([^TARGET_EXEEXT$])
m4trace:configure.ac:393: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete.
You should run autoupdate.], [../../lib/autoconf/general.m4:209: AC_HELP_STRING is expanded from...
configure.ac:393: the top level])
m4trace:configure.ac:396: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete.
You should run autoupdate.], [../../lib/autoconf/general.m4:209: AC_HELP_STRING is expanded from...
configure.ac:396: the top level])
m4trace:configure.ac:517: -1- AC_SUBST([TCL_VERSION])
m4trace:configure.ac:517: -1- AC_SUBST_TRACE([TCL_VERSION])
m4trace:configure.ac:517: -1- m4_pattern_allow([^TCL_VERSION$])
m4trace:configure.ac:518: -1- AC_SUBST([TCL_BIN_DIR])
m4trace:configure.ac:518: -1- AC_SUBST_TRACE([TCL_BIN_DIR])
m4trace:configure.ac:518: -1- m4_pattern_allow([^TCL_BIN_DIR$])
m4trace:configure.ac:519: -1- AC_SUBST([TCL_SRC_DIR])
m4trace:configure.ac:519: -1- AC_SUBST_TRACE([TCL_SRC_DIR])
m4trace:configure.ac:519: -1- m4_pattern_allow([^TCL_SRC_DIR$])
m4trace:configure.ac:520: -1- AC_SUBST([TCL_LIBS])
m4trace:configure.ac:520: -1- AC_SUBST_TRACE([TCL_LIBS])
m4trace:configure.ac:520: -1- m4_pattern_allow([^TCL_LIBS$])
m4trace:configure.ac:521: -1- AC_SUBST([TCL_INCLUDE_SPEC])
m4trace:configure.ac:521: -1- AC_SUBST_TRACE([TCL_INCLUDE_SPEC])
m4trace:configure.ac:521: -1- m4_pattern_allow([^TCL_INCLUDE_SPEC$])
m4trace:configure.ac:523: -1- AC_SUBST([TCL_LIB_FILE])
m4trace:configure.ac:523: -1- AC_SUBST_TRACE([TCL_LIB_FILE])
m4trace:configure.ac:523: -1- m4_pattern_allow([^TCL_LIB_FILE$])
m4trace:configure.ac:524: -1- AC_SUBST([TCL_LIB_FLAG])
m4trace:configure.ac:524: -1- AC_SUBST_TRACE([TCL_LIB_FLAG])
m4trace:configure.ac:524: -1- m4_pattern_allow([^TCL_LIB_FLAG$])
m4trace:configure.ac:525: -1- AC_SUBST([TCL_LIB_SPEC])
m4trace:configure.ac:525: -1- AC_SUBST_TRACE([TCL_LIB_SPEC])
m4trace:configure.ac:525: -1- m4_pattern_allow([^TCL_LIB_SPEC$])
m4trace:configure.ac:527: -1- AC_SUBST([TCL_STUB_LIB_FILE])
m4trace:configure.ac:527: -1- AC_SUBST_TRACE([TCL_STUB_LIB_FILE])
m4trace:configure.ac:527: -1- m4_pattern_allow([^TCL_STUB_LIB_FILE$])
m4trace:configure.ac:528: -1- AC_SUBST([TCL_STUB_LIB_FLAG])
m4trace:configure.ac:528: -1- AC_SUBST_TRACE([TCL_STUB_LIB_FLAG])
m4trace:configure.ac:528: -1- m4_pattern_allow([^TCL_STUB_LIB_FLAG$])
m4trace:configure.ac:529: -1- AC_SUBST([TCL_STUB_LIB_SPEC])
m4trace:configure.ac:529: -1- AC_SUBST_TRACE([TCL_STUB_LIB_SPEC])
m4trace:configure.ac:529: -1- m4_pattern_allow([^TCL_STUB_LIB_SPEC$])
m4trace:configure.ac:537: -1- AC_SUBST([HAVE_TCL])
m4trace:configure.ac:537: -1- AC_SUBST_TRACE([HAVE_TCL])
m4trace:configure.ac:537: -1- m4_pattern_allow([^HAVE_TCL$])
m4trace:configure.ac:546: -1- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete.
You should run autoupdate.], [../../lib/autoconf/general.m4:209: AC_HELP_STRING is expanded from...
../../lib/autoconf/general.m4:1424: AC_ARG_ENABLE is expanded from...
configure.ac:546: the top level])
m4trace:configure.ac:554: -1- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete.
You should run autoupdate.], [../../lib/autoconf/general.m4:209: AC_HELP_STRING is expanded from...
../../lib/autoconf/general.m4:1443: AC_ARG_WITH is expanded from...
configure.ac:554: the top level])
m4trace:configure.ac:569: -1- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete.
You should run autoupdate.], [../../lib/autoconf/general.m4:209: AC_HELP_STRING is expanded from...
../../lib/autoconf/general.m4:1443: AC_ARG_WITH is expanded from...
configure.ac:569: the top level])
m4trace:configure.ac:574: -1- _m4_warn([cross], [cannot check for file existence when cross compiling], [../../lib/autoconf/general.m4:2604: AC_CHECK_FILE is expanded from...
../../lib/m4sugar/m4sh.m4:508: AS_IF is expanded from...
../../lib/autoconf/headers.m4:87: AC_CHECK_HEADER is expanded from...
configure.ac:574: the top level])
m4trace:configure.ac:602: -1- AC_SUBST([TARGET_READLINE_LIBS])
m4trace:configure.ac:602: -1- AC_SUBST_TRACE([TARGET_READLINE_LIBS])
m4trace:configure.ac:602: -1- m4_pattern_allow([^TARGET_READLINE_LIBS$])
m4trace:configure.ac:603: -1- AC_SUBST([TARGET_READLINE_INC])
m4trace:configure.ac:603: -1- AC_SUBST_TRACE([TARGET_READLINE_INC])
m4trace:configure.ac:603: -1- m4_pattern_allow([^TARGET_READLINE_INC$])
m4trace:configure.ac:604: -1- AC_SUBST([TARGET_HAVE_READLINE])
m4trace:configure.ac:604: -1- AC_SUBST_TRACE([TARGET_HAVE_READLINE])
m4trace:configure.ac:604: -1- m4_pattern_allow([^TARGET_HAVE_READLINE$])
m4trace:configure.ac:614: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete.
You should run autoupdate.], [../../lib/autoconf/general.m4:209: AC_HELP_STRING is expanded from...
configure.ac:614: the top level])
m4trace:configure.ac:621: -1- AC_SUBST([TARGET_DEBUG])
m4trace:configure.ac:621: -1- AC_SUBST_TRACE([TARGET_DEBUG])
m4trace:configure.ac:621: -1- m4_pattern_allow([^TARGET_DEBUG$])
m4trace:configure.ac:625: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete.
You should run autoupdate.], [../../lib/autoconf/general.m4:209: AC_HELP_STRING is expanded from...
configure.ac:625: the top level])
m4trace:configure.ac:631: -1- AC_SUBST([USE_AMALGAMATION])
m4trace:configure.ac:631: -1- AC_SUBST_TRACE([USE_AMALGAMATION])
m4trace:configure.ac:631: -1- m4_pattern_allow([^USE_AMALGAMATION$])
m4trace:configure.ac:635: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete.
You should run autoupdate.], [../../lib/autoconf/general.m4:209: AC_HELP_STRING is expanded from...
configure.ac:635: the top level])
m4trace:configure.ac:653: -1- AC_SUBST([OPT_FEATURE_FLAGS])
m4trace:configure.ac:653: -1- AC_SUBST_TRACE([OPT_FEATURE_FLAGS])
m4trace:configure.ac:653: -1- m4_pattern_allow([^OPT_FEATURE_FLAGS$])
m4trace:configure.ac:697: -2- _m4_warn([obsolete], [The macro `AC_HELP_STRING' is obsolete.
You should run autoupdate.], [../../lib/autoconf/general.m4:209: AC_HELP_STRING is expanded from...
configure.ac:697: the top level])
m4trace:configure.ac:705: -1- AC_SUBST([USE_GCOV])
m4trace:configure.ac:705: -1- AC_SUBST_TRACE([USE_GCOV])
m4trace:configure.ac:705: -1- m4_pattern_allow([^USE_GCOV$])
m4trace:configure.ac:710: -1- AC_CONFIG_HEADERS([config.h])
m4trace:configure.ac:715: -1- AC_SUBST([BUILD_CFLAGS])
m4trace:configure.ac:715: -1- AC_SUBST_TRACE([BUILD_CFLAGS])
m4trace:configure.ac:715: -1- m4_pattern_allow([^BUILD_CFLAGS$])
m4trace:configure.ac:716: -1- AC_CONFIG_FILES([
Makefile
sqlite3.pc
])
m4trace:configure.ac:716: -1- _m4_warn([obsolete], [AC_OUTPUT should be used without arguments.
You should run autoupdate.], [])
m4trace:configure.ac:716: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs])
m4trace:configure.ac:716: -1- AC_SUBST_TRACE([LIB@&t@OBJS])
m4trace:configure.ac:716: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:716: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs])
m4trace:configure.ac:716: -1- AC_SUBST_TRACE([LTLIBOBJS])
m4trace:configure.ac:716: -1- m4_pattern_allow([^LTLIBOBJS$])
m4trace:configure.ac:716: -1- AC_SUBST_TRACE([top_builddir])
m4trace:configure.ac:716: -1- AC_SUBST_TRACE([top_build_prefix])
m4trace:configure.ac:716: -1- AC_SUBST_TRACE([srcdir])
m4trace:configure.ac:716: -1- AC_SUBST_TRACE([abs_srcdir])
m4trace:configure.ac:716: -1- AC_SUBST_TRACE([top_srcdir])
m4trace:configure.ac:716: -1- AC_SUBST_TRACE([abs_top_srcdir])
m4trace:configure.ac:716: -1- AC_SUBST_TRACE([builddir])
m4trace:configure.ac:716: -1- AC_SUBST_TRACE([abs_builddir])
m4trace:configure.ac:716: -1- AC_SUBST_TRACE([abs_top_builddir])
m4trace:configure.ac:716: -1- AC_SUBST_TRACE([INSTALL])
m4trace:configure.ac:716: -1- AC_REQUIRE_AUX_FILE([ltmain.sh])
Vendored
+2502 -1876
View File
File diff suppressed because it is too large Load Diff
+5 -2
View File
@@ -10,7 +10,7 @@
**
*************************************************************************
**
** $Id: sqlite3async.c,v 1.6 2009/04/30 17:45:34 shane Exp $
** $Id: sqlite3async.c,v 1.7 2009/07/18 11:52:04 danielk1977 Exp $
**
** This file contains the implementation of an asynchronous IO backend
** for SQLite.
@@ -1065,7 +1065,10 @@ static int asyncOpen(
if( !isAsyncOpen ){
int flagsout;
rc = pVfs->xOpen(pVfs, pData->zName, pData->pBaseRead, flags, &flagsout);
if( rc==SQLITE_OK && (flagsout&SQLITE_OPEN_READWRITE) ){
if( rc==SQLITE_OK
&& (flagsout&SQLITE_OPEN_READWRITE)
&& (flags&SQLITE_OPEN_EXCLUSIVE)==0
){
rc = pVfs->xOpen(pVfs, pData->zName, pData->pBaseWrite, flags, 0);
}
if( pOutFlags ){
+10
View File
@@ -2,6 +2,13 @@
#ifndef __SQLITEASYNC_H_
#define __SQLITEASYNC_H_ 1
/*
** Make sure we can call this stuff from C++.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define SQLITEASYNC_VFSNAME "sqlite3async"
/*
@@ -209,5 +216,8 @@ int sqlite3async_control(int op, ...);
#define SQLITEASYNC_HALT_NOW 1 /* Halt as soon as possible */
#define SQLITEASYNC_HALT_IDLE 2 /* Halt when write-queue is empty */
#ifdef __cplusplus
} /* End of the 'extern "C"' block */
#endif
#endif /* ifndef __SQLITEASYNC_H_ */
+10 -4
View File
@@ -421,7 +421,9 @@ static int getNextNode(
for(ii=0; ii<pParse->nCol; ii++){
const char *zStr = pParse->azCol[ii];
int nStr = strlen(zStr);
if( nInput>nStr && zInput[nStr]==':' && memcmp(zStr, zInput, nStr)==0 ){
if( nInput>nStr && zInput[nStr]==':'
&& sqlite3_strnicmp(zStr, zInput, nStr)==0
){
iCol = ii;
iColLen = ((zInput - z) + nStr + 1);
break;
@@ -538,10 +540,10 @@ static int fts3ExprParse(
pNot->eType = FTSQUERY_NOT;
pNot->pRight = p;
if( pNotBranch ){
pNotBranch->pLeft = p;
pNot->pRight = pNotBranch;
pNot->pLeft = pNotBranch;
}
pNotBranch = pNot;
p = pPrev;
}else{
int eType = p->eType;
assert( eType!=FTSQUERY_PHRASE || !p->pPhrase->isNot );
@@ -623,7 +625,11 @@ static int fts3ExprParse(
if( !pRet ){
rc = SQLITE_ERROR;
}else{
pNotBranch->pLeft = pRet;
Fts3Expr *pIter = pNotBranch;
while( pIter->pLeft ){
pIter = pIter->pLeft;
}
pIter->pLeft = pRet;
pRet = pNotBranch;
}
}
+5 -3
View File
@@ -12,7 +12,7 @@
** This file contains code for implementations of the r-tree and r*-tree
** algorithms packaged as an SQLite virtual table module.
**
** $Id: rtree.c,v 1.12 2008/12/22 15:04:32 danielk1977 Exp $
** $Id: rtree.c,v 1.14 2009/08/06 18:36:47 danielk1977 Exp $
*/
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RTREE)
@@ -2342,7 +2342,7 @@ static int hashIsEmpty(Rtree *pRtree){
/*
** The xUpdate method for rtree module virtual tables.
*/
int rtreeUpdate(
static int rtreeUpdate(
sqlite3_vtab *pVtab,
int nData,
sqlite3_value **azData,
@@ -2737,8 +2737,10 @@ static int rtreeInit(
zSql = sqlite3_mprintf("%s);", zTmp);
sqlite3_free(zTmp);
}
if( !zSql || sqlite3_declare_vtab(db, zSql) ){
if( !zSql ){
rc = SQLITE_NOMEM;
}else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}
sqlite3_free(zSql);
}
+9 -1
View File
@@ -11,7 +11,7 @@
#
# The focus of this file is testing the r-tree extension.
#
# $Id: rtree1.test,v 1.6 2008/12/22 15:04:32 danielk1977 Exp $
# $Id: rtree1.test,v 1.7 2009/07/17 16:54:48 danielk1977 Exp $
#
if {![info exists testdir]} {
@@ -393,4 +393,12 @@ do_test rtree-9.3 {
}
} {1600}
#-------------------------------------------------------------------------
# Ticket #3970: Check that the error message is meaningful when a
# keyword is used as a column name.
#
do_test rtree-10.1 {
catchsql { CREATE VIRTUAL TABLE t7 USING rtree(index, x1, y1, x2, y2) }
} {1 {near "index": syntax error}}
finish_test
+5 -3
View File
@@ -323,11 +323,13 @@ objects: $(LIBOBJ_ORIG)
# files are automatically generated. This target takes care of
# all that automatic generation.
#
target_source: $(SRC)
target_source: $(SRC) $(TOP)/tool/vdbe-compress.tcl
rm -rf tsrc
mkdir tsrc
cp -f $(SRC) tsrc
rm tsrc/sqlite.h.in tsrc/parse.y
tclsh $(TOP)/tool/vdbe-compress.tcl <tsrc/vdbe.c >vdbe.new
mv vdbe.new tsrc/vdbe.c
touch target_source
sqlite3.c: target_source $(TOP)/tool/mksqlite3c.tcl
@@ -343,9 +345,9 @@ fts3amal.c: target_source $(TOP)/ext/fts3/mkfts3amal.tcl
# Rules to build the LEMON compiler generator
#
lemon: $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
lemon: $(TOP)/tool/lemon.c $(TOP)/src/lempar.c
$(BCC) -o lemon $(TOP)/tool/lemon.c
cp $(TOP)/tool/lempar.c .
cp $(TOP)/src/lempar.c .
# Rules to build individual *.o files from generated *.c files. This
# applies to:
-3392
View File
File diff suppressed because it is too large Load Diff
-2200
View File
File diff suppressed because it is too large Load Diff
-387
View File
@@ -1,387 +0,0 @@
/*
** 2009 April 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 contains the implementation of the RowHash data structure.
** A RowHash has the following properties:
**
** * A RowHash stores an unordered "bag" of 64-bit integer rowids.
** There is no other content.
**
** * Primative operations are CREATE, INSERT, TEST, and DESTROY.
** There is no way to remove individual elements from the RowHash
** once they are inserted.
**
** * INSERT operations are batched. TEST operation will ignore
** elements in the current INSERT batch. Only elements inserted
** in prior batches will be seen by a TEST.
**
** The insert batch number is a parameter to the TEST primitive. The
** hash table is rebuilt whenever the batch number increases. TEST
** operations only look for INSERTs that occurred in prior batches.
**
** The caller is responsible for insuring that there are no duplicate
** INSERTs.
**
** $Id: rowhash.c,v 1.1 2009/04/21 09:02:47 danielk1977 Exp $
*/
#include "sqliteInt.h"
/*
** An upper bound on the size of heap allocations made by this module.
** Limiting the size of allocations helps to avoid memory fragmentation.
*/
#define ROWHASH_ALLOCATION 1024
/*
** If there are less than this number of elements in the RowHash, do not
** bother building a hash-table. Just do a linear search.
*/
#define ROWHASH_LINEAR_SEARCH_LIMIT 10
/*
** This value is what we want the average length of the collision hash
** chain to be.
*/
#define ROWHASH_COLLISION_LENGTH 3
/* Forward references to data structures. */
typedef struct RowHashElem RowHashElem;
typedef struct RowHashBlock RowHashBlock;
typedef union RowHashPtr RowHashPtr;
typedef struct RowHashPage RowHashPage;
/*
** Number of elements in the RowHashBlock.aElem[] array. This array is
** sized to make RowHashBlock very close to (without exceeding)
** ROWHASH_ALLOCATION bytes in size.
*/
#define ROWHASH_ELEM_PER_BLOCK ( \
(ROWHASH_ALLOCATION - ROUND8(sizeof(struct RowHashBlockData))) / \
sizeof(RowHashElem) \
)
/*
** Number of pointers that fit into a single allocation of
** ROWHASH_ALLOCATION bytes.
*/
#define ROWHASH_POINTER_PER_PAGE (ROWHASH_ALLOCATION/sizeof(RowHashPtr))
/*
** A page of pointers used to construct a hash table.
**
** The hash table is actually a tree composed of instances of this
** object. Leaves of the tree use the a[].pElem pointer to point
** to RowHashElem entries. Interior nodes of the tree use the
** a[].pPage element to point to subpages.
**
** The hash table is split into a tree in order to avoid having
** to make large memory allocations, since large allocations can
** result in unwanted memory fragmentation.
*/
struct RowHashPage {
union RowHashPtr {
RowHashPage *pPage; /* Used by interior nodes. Pointer to subtree. */
RowHashElem *pElem; /* Used by leaves. Pointer to hash entry. */
} a[ROWHASH_POINTER_PER_PAGE];
};
/*
** Each 64-bit integer in a RowHash is stored as an instance of
** this object.
**
** Instances of this object are not allocated separately. They are
** allocated in large blocks using the RowHashBlock object as a container.
*/
struct RowHashElem {
i64 iVal; /* The value being stored. A rowid. */
RowHashElem *pNext; /* Next element with the same hash */
};
/*
** In order to avoid many small allocations of RowHashElem objects,
** multiple RowHashElem objects are allocated at once, as an instance
** of this object, and then used as needed.
**
** A single RowHash object will allocate one or more of these RowHashBlock
** objects. As many are allocated as are needed to store all of the
** content. All RowHashBlocks are kept on a linked list formed using
** RowHashBlock.data.pNext so that they can be freed when the RowHash
** is destroyed.
**
** The linked list of RowHashBlock objects also provides a way to sequentially
** scan all elements in the RowHash. This sequential scan is used when
** rebuilding the hash table. The hash table is rebuilt after every
** batch of inserts.
*/
struct RowHashBlock {
struct RowHashBlockData {
int nUsed; /* Num of aElem[] currently used in this block */
RowHashBlock *pNext; /* Next RowHashBlock object in list of them all */
} data;
RowHashElem aElem[ROWHASH_ELEM_PER_BLOCK]; /* Available RowHashElem objects */
};
/*
** RowHash structure. References to a structure of this type are passed
** around and used as opaque handles by code in other modules.
*/
struct RowHash {
unsigned int nEntry; /* Number of used entries over all RowHashBlocks */
int iBatch; /* The current insert batch number */
u8 nHeight; /* Height of tree of hash pages */
u8 nLinearLimit; /* Linear search limit (used if pHash==0) */
int nBucket; /* Number of buckets in hash table */
RowHashPage *pHash; /* Pointer to root of hash table tree */
RowHashBlock *pBlock; /* Linked list of RowHashBlocks */
sqlite3 *db; /* Associated database connection */
};
/*
** Allocate a hash table tree of height nHeight with *pnLeaf leaf pages.
** Set *pp to point to the root of the tree. If the maximum number of leaf
** pages in a tree of height nHeight is less than *pnLeaf, allocate only
** that part of the tree that is necessary to account for all leaves.
**
** Before returning, subtract the number of leaves in the tree allocated
** from *pnLeaf.
**
** This routine returns SQLITE_NOMEM if a malloc() fails, or SQLITE_OK
** otherwise.
*/
static int allocHashTable(RowHashPage **pp, int nHeight, int *pnLeaf){
RowHashPage *p = (RowHashPage *)sqlite3MallocZero(sizeof(*p));
if( !p ){
return SQLITE_NOMEM;
}
*pp = p;
if( nHeight==0 ){
(*pnLeaf)--;
}else{
int ii;
for(ii=0; ii<ROWHASH_POINTER_PER_PAGE && *pnLeaf>0; ii++){
if( allocHashTable(&p->a[ii].pPage, nHeight-1, pnLeaf) ){
return SQLITE_NOMEM;
}
}
}
return SQLITE_OK;
}
/*
** Delete the hash table tree of height nHeight passed as the first argument.
*/
static void deleteHashTable(RowHashPage *p, int nHeight){
if( p ){
if( nHeight>0 ){
int ii;
for(ii=0; ii<ROWHASH_POINTER_PER_PAGE; ii++){
deleteHashTable(p->a[ii].pPage, nHeight-1);
}
}
sqlite3_free(p);
}
}
/*
** Find the hash-bucket associated with value iVal. Return a pointer to it.
**
** By "hash-bucket", we mean the RowHashPage.a[].pElem pointer that
** corresponds to a particular hash entry.
*/
static RowHashElem **findHashBucket(RowHash *pRowHash, i64 iVal){
int aOffset[16];
int n;
RowHashPage *pPage = pRowHash->pHash;
int h = (((u64)iVal) % pRowHash->nBucket);
assert( pRowHash->nHeight < sizeof(aOffset)/sizeof(aOffset[0]) );
for(n=0; n<pRowHash->nHeight; n++){
int h1 = h / ROWHASH_POINTER_PER_PAGE;
aOffset[n] = h - (h1 * ROWHASH_POINTER_PER_PAGE);
h = h1;
}
aOffset[n] = h;
for(n=pRowHash->nHeight; n>0; n--){
pPage = pPage->a[aOffset[n]].pPage;
}
return &pPage->a[aOffset[0]].pElem;
}
/*
** Build a new hash table tree in p->pHash. The new hash table should
** contain all p->nEntry entries in the p->pBlock list. If there
** existed a prior tree, delete the old tree first before constructing
** the new one.
**
** If the number of entries (p->nEntry) is less than
** ROWHASH_LINEAR_SEARCH_LIMIT, then we are guessing that a linear
** search is going to be faster than a lookup, so do not bother
** building the hash table.
*/
static int makeHashTable(RowHash *p, int iBatch){
RowHashBlock *pBlock;
int nBucket;
int nLeaf, n;
/* Delete the old hash table. */
deleteHashTable(p->pHash, p->nHeight);
assert( p->iBatch!=iBatch );
p->iBatch = iBatch;
/* Skip building the hash table if the number of elements is small */
if( p->nEntry<ROWHASH_LINEAR_SEARCH_LIMIT ){
p->nLinearLimit = p->nEntry;
p->pHash = 0;
return SQLITE_OK;
}
/* Determine how many leaves the hash-table will comprise. */
nLeaf = 1 + (p->nEntry / (ROWHASH_POINTER_PER_PAGE*ROWHASH_COLLISION_LENGTH));
p->nBucket = nBucket = nLeaf*ROWHASH_POINTER_PER_PAGE;
/* Set nHeight to the height of the tree that contains the leaf pages. If
** RowHash.nHeight is zero, then the whole hash-table fits on a single
** leaf. If RowHash.nHeight is 1, then RowHash.pHash points to an array
** of pointers to leaf pages. If 2, pHash points to an array of pointers
** to arrays of pointers to leaf pages. And so on.
*/
p->nHeight = 0;
n = nLeaf;
while( n>1 ){
n = (n+ROWHASH_POINTER_PER_PAGE-1) / ROWHASH_POINTER_PER_PAGE;
p->nHeight++;
}
/* Allocate the hash-table. */
if( allocHashTable(&p->pHash, p->nHeight, &nLeaf) ){
return SQLITE_NOMEM;
}
/* Insert all values into the hash-table. */
for(pBlock=p->pBlock; pBlock; pBlock=pBlock->data.pNext){
RowHashElem * const pEnd = &pBlock->aElem[pBlock->data.nUsed];
RowHashElem *pIter;
for(pIter=pBlock->aElem; pIter<pEnd; pIter++){
RowHashElem **ppElem = findHashBucket(p, pIter->iVal);
pIter->pNext = *ppElem;
*ppElem = pIter;
}
}
return SQLITE_OK;
}
/*
** Check to see if iVal has been inserted into the hash table "p"
** in some batch prior to iBatch. If so, set *pExists to 1.
** If not, set *pExists to 0.
**
** The hash table is rebuilt whenever iBatch changes. A hash table
** rebuild might encounter an out-of-memory condition. If that happens,
** return SQLITE_NOMEM. If there are no problems, return SQLITE_OK.
**
** The initial "batch" is 0. So, if there were prior calls to
** sqlite3RowhashInsert() and then this routine is invoked with iBatch==0,
** because all prior inserts where in the same batch, none of the prior
** inserts will be visible and this routine will indicate not found.
** Hence, the first invocation of this routine should probably use
** a batch number of 1.
*/
int sqlite3RowhashTest(
RowHash *p, /* The RowHash to search in */
int iBatch, /* Look for values inserted in batches prior to this batch */
i64 iVal, /* The rowid value we are looking for */
int *pExists /* Store 0 or 1 hear to indicate not-found or found */
){
*pExists = 0;
if( p ){
assert( p->pBlock );
if( iBatch!=p->iBatch && makeHashTable(p, iBatch) ){
return SQLITE_NOMEM;
}
if( p->pHash ){
RowHashElem *pElem = *findHashBucket(p, iVal);
for(; pElem; pElem=pElem->pNext){
if( pElem->iVal==iVal ){
*pExists = 1;
break;
}
}
}else{
int ii;
RowHashElem *aElem = p->pBlock->aElem;
for(ii=0; ii<p->nLinearLimit; ii++){
if( aElem[ii].iVal==iVal ){
*pExists = 1;
break;
}
}
}
}
return SQLITE_OK;
}
/*
** Insert value iVal into the RowHash object. Allocate a new RowHash
** object if necessary.
**
** Return SQLITE_OK if all goes as planned. If a malloc() fails, return
** SQLITE_NOMEM.
*/
int sqlite3RowhashInsert(sqlite3 *db, RowHash **pp, i64 iVal){
RowHash *p = *pp;
/* If the RowHash structure has not been allocated, allocate it now. */
if( !p ){
p = (RowHash*)sqlite3DbMallocZero(db, sizeof(RowHash));
if( !p ){
return SQLITE_NOMEM;
}
p->db = db;
*pp = p;
}
/* If the current RowHashBlock is full, or if the first RowHashBlock has
** not yet been allocated, allocate one now. */
if( !p->pBlock || p->pBlock->data.nUsed==ROWHASH_ELEM_PER_BLOCK ){
RowHashBlock *pBlock = (RowHashBlock*)sqlite3Malloc(sizeof(RowHashBlock));
if( !pBlock ){
return SQLITE_NOMEM;
}
pBlock->data.nUsed = 0;
pBlock->data.pNext = p->pBlock;
p->pBlock = pBlock;
}
/* Add iVal to the current RowHashBlock. */
p->pBlock->aElem[p->pBlock->data.nUsed].iVal = iVal;
p->pBlock->data.nUsed++;
p->nEntry++;
return SQLITE_OK;
}
/*
** Destroy the RowHash object passed as the first argument.
*/
void sqlite3RowhashDestroy(RowHash *p){
if( p ){
RowHashBlock *pBlock, *pNext;
deleteHashTable(p->pHash, p->nHeight);
for(pBlock=p->pBlock; pBlock; pBlock=pNext){
pNext = pBlock->data.pNext;
sqlite3_free(pBlock);
}
sqlite3DbFree(p->db, p);
}
}
-1006
View File
File diff suppressed because it is too large Load Diff
-3578
View File
File diff suppressed because it is too large Load Diff
+40 -11
View File
@@ -12,7 +12,7 @@
** This file contains C code routines that used to generate VDBE code
** that implements the ALTER TABLE command.
**
** $Id: alter.c,v 1.57 2009/04/16 16:30:18 drh Exp $
** $Id: alter.c,v 1.62 2009/07/24 17:58:53 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -66,7 +66,7 @@ static void renameTableFunc(
}
/* Store the token that zCsr points to in tname. */
tname.z = zCsr;
tname.z = (char*)zCsr;
tname.n = len;
/* Advance zCsr to the next token. Store that token type in 'token',
@@ -79,7 +79,7 @@ static void renameTableFunc(
assert( len>0 );
} while( token!=TK_LP && token!=TK_USING );
zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", tname.z - zSql, zSql,
zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", ((u8*)tname.z) - zSql, zSql,
zTableName, tname.z+tname.n);
sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC);
}
@@ -125,7 +125,7 @@ static void renameTriggerFunc(
}
/* Store the token that zCsr points to in tname. */
tname.z = zCsr;
tname.z = (char*)zCsr;
tname.n = len;
/* Advance zCsr to the next token. Store that token type in 'token',
@@ -155,7 +155,7 @@ static void renameTriggerFunc(
/* Variable tname now contains the token that is the old table-name
** in the CREATE TRIGGER statement.
*/
zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", tname.z - zSql, zSql,
zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", ((u8*)tname.z) - zSql, zSql,
zTableName, tname.z+tname.n);
sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC);
}
@@ -277,7 +277,7 @@ void sqlite3AlterRenameTable(
#ifndef SQLITE_OMIT_TRIGGER
char *zWhere = 0; /* Where clause to locate temp triggers */
#endif
int isVirtualRename = 0; /* True if this is a v-table with an xRename() */
VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */
if( NEVER(db->mallocFailed) ) goto exit_rename_table;
assert( pSrc->nSrc==1 );
@@ -332,8 +332,11 @@ void sqlite3AlterRenameTable(
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto exit_rename_table;
}
if( IsVirtual(pTab) && pTab->pMod->pModule->xRename ){
isVirtualRename = 1;
if( IsVirtual(pTab) ){
pVTab = sqlite3GetVTable(db, pTab);
if( pVTab->pVtab->pModule->xRename==0 ){
pVTab = 0;
}
}
#endif
@@ -346,7 +349,7 @@ void sqlite3AlterRenameTable(
if( v==0 ){
goto exit_rename_table;
}
sqlite3BeginWriteOperation(pParse, isVirtualRename, iDb);
sqlite3BeginWriteOperation(pParse, pVTab!=0, iDb);
sqlite3ChangeCookie(pParse, iDb);
/* If this is a virtual table, invoke the xRename() function if
@@ -355,10 +358,10 @@ void sqlite3AlterRenameTable(
** SQLite tables) that are identified by the name of the virtual table.
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( isVirtualRename ){
if( pVTab ){
int i = ++pParse->nMem;
sqlite3VdbeAddOp4(v, OP_String8, 0, i, 0, zName, 0);
sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pTab->pVtab, P4_VTAB);
sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB);
}
#endif
@@ -426,6 +429,31 @@ exit_rename_table:
}
/*
** Generate code to make sure the file format number is at least minFormat.
** The generated code will increase the file format number if necessary.
*/
void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){
Vdbe *v;
v = sqlite3GetVdbe(pParse);
/* The VDBE should have been allocated before this routine is called.
** If that allocation failed, we would have quit before reaching this
** point */
if( ALWAYS(v) ){
int r1 = sqlite3GetTempReg(pParse);
int r2 = sqlite3GetTempReg(pParse);
int j1;
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT);
sqlite3VdbeUsesBtree(v, iDb);
sqlite3VdbeAddOp2(v, OP_Integer, minFormat, r2);
j1 = sqlite3VdbeAddOp3(v, OP_Ge, r2, 0, r1);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, r2);
sqlite3VdbeJumpHere(v, j1);
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ReleaseTempReg(pParse, r2);
}
}
/*
** This function is called after an "ALTER TABLE ... ADD" statement
** has been parsed. Argument pColDef contains the text of the new
@@ -611,6 +639,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
pCol->zColl = 0;
pCol->zType = 0;
pCol->pDflt = 0;
pCol->zDflt = 0;
}
pNew->pSchema = db->aDb[iDb].pSchema;
pNew->addColOffset = pTab->addColOffset;
+17 -18
View File
@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands.
**
** $Id: attach.c,v 1.90 2009/05/01 06:19:21 danielk1977 Exp $
** $Id: attach.c,v 1.93 2009/05/31 21:21:41 drh Exp $
*/
#include "sqliteInt.h"
@@ -41,7 +41,7 @@ static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
if( pExpr->op!=TK_ID ){
rc = sqlite3ResolveExprNames(pName, pExpr);
if( rc==SQLITE_OK && !sqlite3ExprIsConstant(pExpr) ){
sqlite3ErrorMsg(pName->pParse, "invalid name: \"%T\"", &pExpr->span);
sqlite3ErrorMsg(pName->pParse, "invalid name: \"%s\"", pExpr->u.zToken);
return SQLITE_ERROR;
}
}else{
@@ -298,21 +298,6 @@ static void codeAttach(
sqlite3* db = pParse->db;
int regArgs;
#ifndef SQLITE_OMIT_AUTHORIZATION
assert( db->mallocFailed || pAuthArg );
if( pAuthArg ){
char *zAuthArg = sqlite3NameFromToken(db, &pAuthArg->span);
if( !zAuthArg ){
goto attach_end;
}
rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0);
sqlite3DbFree(db, zAuthArg);
if(rc!=SQLITE_OK ){
goto attach_end;
}
}
#endif /* SQLITE_OMIT_AUTHORIZATION */
memset(&sName, 0, sizeof(NameContext));
sName.pParse = pParse;
@@ -325,6 +310,20 @@ static void codeAttach(
goto attach_end;
}
#ifndef SQLITE_OMIT_AUTHORIZATION
if( pAuthArg ){
char *zAuthArg = pAuthArg->u.zToken;
if( NEVER(zAuthArg==0) ){
goto attach_end;
}
rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0);
if(rc!=SQLITE_OK ){
goto attach_end;
}
}
#endif /* SQLITE_OMIT_AUTHORIZATION */
v = sqlite3GetVdbe(pParse);
regArgs = sqlite3GetTempRange(pParse, 4);
sqlite3ExprCode(pParse, pFilename, regArgs);
@@ -487,7 +486,7 @@ int sqlite3FixExpr(
Expr *pExpr /* The expression to be fixed to one database */
){
while( pExpr ){
if( ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_SpanToken) ) break;
if( ExprHasAnyProperty(pExpr, EP_TokenOnly) ) break;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
}else{
+10 -10
View File
@@ -14,7 +14,7 @@
** systems that do not need this facility may omit it by recompiling
** the library with -DSQLITE_OMIT_AUTHORIZATION=1
**
** $Id: auth.c,v 1.31 2009/05/04 18:01:40 drh Exp $
** $Id: auth.c,v 1.32 2009/07/02 18:40:35 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -112,7 +112,6 @@ void sqlite3AuthRead(
const char *zCol; /* Name of the column of the table */
int iSrc; /* Index in pTabList->a[] of table being read */
const char *zDBase; /* Name of database being accessed */
TriggerStack *pStack; /* The stack of current triggers */
int iDb; /* The index of the database the expression refers to */
if( db->xAuth==0 ) return;
@@ -124,17 +123,18 @@ void sqlite3AuthRead(
return;
}
if( pTabList ){
for(iSrc=0; ALWAYS(iSrc<pTabList->nSrc); iSrc++){
if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break;
for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
if( pExpr->iTable==pTabList->a[iSrc].iCursor ){
pTab = pTabList->a[iSrc].pTab;
break;
}
}
assert( iSrc<pTabList->nSrc );
pTab = pTabList->a[iSrc].pTab;
}else{
pStack = pParse->trigStack;
}
if( !pTab ){
TriggerStack *pStack = pParse->trigStack;
if( ALWAYS(pStack) ){
/* This must be an attempt to read the NEW or OLD pseudo-tables
** of a trigger.
*/
** of a trigger. */
assert( pExpr->iTable==pStack->newIdx || pExpr->iTable==pStack->oldIdx );
pTab = pStack->pTab;
}
+48 -29
View File
@@ -12,7 +12,7 @@
** This file contains the implementation of the sqlite3_backup_XXX()
** API functions and the related features.
**
** $Id: backup.c,v 1.13 2009/03/16 13:19:36 danielk1977 Exp $
** $Id: backup.c,v 1.19 2009/07/06 19:03:13 drh Exp $
*/
#include "sqliteInt.h"
#include "btreeInt.h"
@@ -44,6 +44,7 @@ struct sqlite3_backup {
Pgno nRemaining; /* Number of pages left to copy */
Pgno nPagecount; /* Total number of pages to copy */
int isAttached; /* True once backup has been registered with pager */
sqlite3_backup *pNext; /* Next backup associated with source pager */
};
@@ -90,15 +91,24 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
int i = sqlite3FindDbName(pDb, zDb);
if( i==1 ){
Parse sParse;
memset(&sParse, 0, sizeof(sParse));
sParse.db = pDb;
if( sqlite3OpenTempDatabase(&sParse) ){
sqlite3ErrorClear(&sParse);
sqlite3Error(pErrorDb, sParse.rc, "%s", sParse.zErrMsg);
Parse *pParse;
int rc = 0;
pParse = sqlite3StackAllocZero(pErrorDb, sizeof(*pParse));
if( pParse==0 ){
sqlite3Error(pErrorDb, SQLITE_NOMEM, "out of memory");
rc = SQLITE_NOMEM;
}else{
pParse->db = pDb;
if( sqlite3OpenTempDatabase(pParse) ){
sqlite3ErrorClear(pParse);
sqlite3Error(pErrorDb, pParse->rc, "%s", pParse->zErrMsg);
rc = SQLITE_ERROR;
}
sqlite3StackFree(pErrorDb, pParse);
}
if( rc ){
return 0;
}
assert( sParse.zErrMsg==0 );
}
if( i<0 ){
@@ -157,6 +167,7 @@ sqlite3_backup *sqlite3_backup_init(
p->pDestDb = pDestDb;
p->pSrcDb = pSrcDb;
p->iNext = 1;
p->isAttached = 0;
if( 0==p->pSrc || 0==p->pDest ){
/* One (or both) of the named databases did not exist. An error has
@@ -167,18 +178,7 @@ sqlite3_backup *sqlite3_backup_init(
p = 0;
}
}
/* If everything has gone as planned, attach the backup object to the
** source pager. The source pager calls BackupUpdate() and BackupRestart()
** to notify this module if the source file is modified mid-backup.
*/
if( p ){
sqlite3_backup **pp; /* Pointer to head of pagers backup list */
sqlite3BtreeEnter(p->pSrc);
pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc));
p->pNext = *pp;
*pp = p;
sqlite3BtreeLeave(p->pSrc);
p->pSrc->nBackup++;
}
@@ -193,7 +193,7 @@ sqlite3_backup *sqlite3_backup_init(
** are considered fatal except for SQLITE_BUSY and SQLITE_LOCKED.
*/
static int isFatalError(int rc){
return (rc!=SQLITE_OK && rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED);
return (rc!=SQLITE_OK && rc!=SQLITE_BUSY && ALWAYS(rc!=SQLITE_LOCKED));
}
/*
@@ -271,6 +271,19 @@ static int backupTruncateFile(sqlite3_file *pFile, i64 iSize){
return rc;
}
/*
** Register this backup object with the associated source pager for
** callbacks when pages are changed or the cache invalidated.
*/
static void attachBackupObject(sqlite3_backup *p){
sqlite3_backup **pp;
assert( sqlite3BtreeHoldsMutex(p->pSrc) );
pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc));
p->pNext = *pp;
*pp = p;
p->isAttached = 1;
}
/*
** Copy nPage pages from the source b-tree to the destination.
*/
@@ -305,7 +318,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
&& SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2))
){
p->bDestLocked = 1;
rc = sqlite3BtreeGetMeta(p->pDest, 1, &p->iDestSchema);
sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema);
}
/* If there is no open read-transaction on the source database, open
@@ -340,20 +353,23 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
p->nRemaining = nSrcPage+1-p->iNext;
if( p->iNext>(Pgno)nSrcPage ){
rc = SQLITE_DONE;
}else if( !p->isAttached ){
attachBackupObject(p);
}
}
if( rc==SQLITE_DONE ){
/* Update the schema version field in the destination database. This
** is to make sure that the schema-version really does change in
** the case where the source and destination databases have the
** same schema version.
*/
if( rc==SQLITE_DONE
&& (rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1))==SQLITE_OK
){
const int nSrcPagesize = sqlite3BtreeGetPageSize(p->pSrc);
const int nDestPagesize = sqlite3BtreeGetPageSize(p->pDest);
int nDestTruncate;
/* Update the schema version field in the destination database. This
** is to make sure that the schema-version really does change in
** the case where the source and destination databases have the
** same schema version.
*/
sqlite3BtreeUpdateMeta(p->pDest, 1, p->iDestSchema+1);
if( p->pDestDb ){
sqlite3ResetInternalSchema(p->pDestDb, 0);
}
@@ -463,6 +479,7 @@ int sqlite3_backup_finish(sqlite3_backup *p){
int rc; /* Value to return */
/* Enter the mutexes */
if( p==0 ) return SQLITE_OK;
sqlite3_mutex_enter(p->pSrcDb->mutex);
sqlite3BtreeEnter(p->pSrc);
mutex = p->pSrcDb->mutex;
@@ -472,12 +489,14 @@ int sqlite3_backup_finish(sqlite3_backup *p){
/* Detach this backup from the source pager. */
if( p->pDestDb ){
p->pSrc->nBackup--;
}
if( p->isAttached ){
pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc));
while( *pp!=p ){
pp = &(*pp)->pNext;
}
*pp = p->pNext;
p->pSrc->nBackup--;
}
/* If a transaction is still open on the Btree, roll it back. */
+33 -19
View File
@@ -34,7 +34,7 @@
** start of a transaction, and is thus usually less than a few thousand,
** but can be as large as 2 billion for a really big database.
**
** @(#) $Id: bitvec.c,v 1.14 2009/04/01 23:49:04 drh Exp $
** @(#) $Id: bitvec.c,v 1.17 2009/07/25 17:33:26 drh Exp $
*/
#include "sqliteInt.h"
@@ -146,8 +146,7 @@ int sqlite3BitvecTest(Bitvec *p, u32 i){
u32 h = BITVEC_HASH(i++);
while( p->u.aHash[h] ){
if( p->u.aHash[h]==i ) return 1;
h++;
if( h>=BITVEC_NINT ) h = 0;
h = (h+1) % BITVEC_NINT;
}
return 0;
}
@@ -167,7 +166,7 @@ int sqlite3BitvecTest(Bitvec *p, u32 i){
*/
int sqlite3BitvecSet(Bitvec *p, u32 i){
u32 h;
assert( p!=0 );
if( p==0 ) return SQLITE_OK;
assert( i>0 );
assert( i<=p->iSize );
i--;
@@ -209,15 +208,20 @@ bitvec_set_rehash:
if( p->nSet>=BITVEC_MXHASH ){
unsigned int j;
int rc;
u32 aiValues[BITVEC_NINT];
memcpy(aiValues, p->u.aHash, sizeof(aiValues));
memset(p->u.apSub, 0, sizeof(aiValues));
p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR;
rc = sqlite3BitvecSet(p, i);
for(j=0; j<BITVEC_NINT; j++){
if( aiValues[j] ) rc |= sqlite3BitvecSet(p, aiValues[j]);
u32 *aiValues = sqlite3StackAllocRaw(0, sizeof(p->u.aHash));
if( aiValues==0 ){
return SQLITE_NOMEM;
}else{
memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
memset(p->u.apSub, 0, sizeof(p->u.apSub));
p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR;
rc = sqlite3BitvecSet(p, i);
for(j=0; j<BITVEC_NINT; j++){
if( aiValues[j] ) rc |= sqlite3BitvecSet(p, aiValues[j]);
}
sqlite3StackFree(0, aiValues);
return rc;
}
return rc;
}
bitvec_set_end:
p->nSet++;
@@ -227,9 +231,12 @@ bitvec_set_end:
/*
** Clear the i-th bit.
**
** pBuf must be a pointer to at least BITVEC_SZ bytes of temporary storage
** that BitvecClear can use to rebuilt its hash table.
*/
void sqlite3BitvecClear(Bitvec *p, u32 i){
assert( p!=0 );
void sqlite3BitvecClear(Bitvec *p, u32 i, void *pBuf){
if( p==0 ) return;
assert( i>0 );
i--;
while( p->iDivisor ){
@@ -244,9 +251,9 @@ void sqlite3BitvecClear(Bitvec *p, u32 i){
p->u.aBitmap[i/BITVEC_SZELEM] &= ~(1 << (i&(BITVEC_SZELEM-1)));
}else{
unsigned int j;
u32 aiValues[BITVEC_NINT];
memcpy(aiValues, p->u.aHash, sizeof(aiValues));
memset(p->u.aHash, 0, sizeof(aiValues));
u32 *aiValues = pBuf;
memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
memset(p->u.aHash, 0, sizeof(p->u.aHash));
p->nSet = 0;
for(j=0; j<BITVEC_NINT; j++){
if( aiValues[j] && aiValues[j]!=(i+1) ){
@@ -330,14 +337,20 @@ int sqlite3BitvecBuiltinTest(int sz, int *aOp){
unsigned char *pV = 0;
int rc = -1;
int i, nx, pc, op;
void *pTmpSpace;
/* Allocate the Bitvec to be tested and a linear array of
** bits to act as the reference */
pBitvec = sqlite3BitvecCreate( sz );
pV = sqlite3_malloc( (sz+7)/8 + 1 );
if( pBitvec==0 || pV==0 ) goto bitvec_end;
pTmpSpace = sqlite3_malloc(BITVEC_SZ);
if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end;
memset(pV, 0, (sz+7)/8 + 1);
/* NULL pBitvec tests */
sqlite3BitvecSet(0, 1);
sqlite3BitvecClear(0, 1, pTmpSpace);
/* Run the program */
pc = 0;
while( (op = aOp[pc])!=0 ){
@@ -368,7 +381,7 @@ int sqlite3BitvecBuiltinTest(int sz, int *aOp){
}
}else{
CLEARBIT(pV, (i+1));
sqlite3BitvecClear(pBitvec, i+1);
sqlite3BitvecClear(pBitvec, i+1, pTmpSpace);
}
}
@@ -389,6 +402,7 @@ int sqlite3BitvecBuiltinTest(int sz, int *aOp){
/* Free allocated structure */
bitvec_end:
sqlite3_free(pTmpSpace);
sqlite3_free(pV);
sqlite3BitvecDestroy(pBitvec);
return rc;
+11 -5
View File
@@ -10,7 +10,7 @@
**
*************************************************************************
**
** $Id: btmutex.c,v 1.15 2009/04/10 12:55:17 danielk1977 Exp $
** $Id: btmutex.c,v 1.17 2009/07/20 12:33:33 drh Exp $
**
** This file contains code used to implement mutexes on Btree objects.
** This code really belongs in btree.c. But btree.c is getting too
@@ -197,7 +197,9 @@ void sqlite3BtreeEnterAll(sqlite3 *db){
if( !p->locked ){
assert( p->wantToLock==1 );
while( p->pPrev ) p = p->pPrev;
while( p->locked && p->pNext ) p = p->pNext;
/* Reason for ALWAYS: There must be at least on unlocked Btree in
** the chain. Otherwise the !p->locked test above would have failed */
while( p->locked && ALWAYS(p->pNext) ) p = p->pNext;
for(pLater = p->pNext; pLater; pLater=pLater->pNext){
if( pLater->locked ){
unlockBtreeMutex(pLater);
@@ -308,8 +310,12 @@ void sqlite3BtreeMutexArrayEnter(BtreeMutexArray *pArray){
/* We should already hold a lock on the database connection */
assert( sqlite3_mutex_held(p->db->mutex) );
/* The Btree is sharable because only sharable Btrees are entered
** into the array in the first place. */
assert( p->sharable );
p->wantToLock++;
if( !p->locked && p->sharable ){
if( !p->locked ){
lockBtreeMutex(p);
}
}
@@ -324,14 +330,14 @@ void sqlite3BtreeMutexArrayLeave(BtreeMutexArray *pArray){
Btree *p = pArray->aBtree[i];
/* Some basic sanity checking */
assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt );
assert( p->locked || !p->sharable );
assert( p->locked );
assert( p->wantToLock>0 );
/* We should already hold a lock on the database connection */
assert( sqlite3_mutex_held(p->db->mutex) );
p->wantToLock--;
if( p->wantToLock==0 && p->locked ){
if( p->wantToLock==0 ){
unlockBtreeMutex(p);
}
}
+1777 -1672
View File
File diff suppressed because it is too large Load Diff
+33 -16
View File
@@ -13,7 +13,7 @@
** subsystem. See comments in the source code for a detailed description
** of what each interface routine does.
**
** @(#) $Id: btree.h,v 1.114 2009/05/04 11:42:30 danielk1977 Exp $
** @(#) $Id: btree.h,v 1.120 2009/07/22 00:35:24 drh Exp $
*/
#ifndef _BTREE_H_
#define _BTREE_H_
@@ -58,7 +58,7 @@ struct BtreeMutexArray {
int sqlite3BtreeOpen(
const char *zFilename, /* Name of database file to open */
sqlite3 *db, /* Associated database connection */
Btree **, /* Return open Btree* here */
Btree **ppBtree, /* Return open Btree* here */
int flags, /* Flags */
int vfsFlags /* Flags passed through to VFS open */
);
@@ -80,7 +80,7 @@ int sqlite3BtreeClose(Btree*);
int sqlite3BtreeSetCacheSize(Btree*,int);
int sqlite3BtreeSetSafetyLevel(Btree*,int,int);
int sqlite3BtreeSyncDisabled(Btree*);
int sqlite3BtreeSetPageSize(Btree*,int,int,int);
int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
int sqlite3BtreeGetPageSize(Btree*);
int sqlite3BtreeMaxPageCount(Btree*,int);
int sqlite3BtreeGetReserve(Btree*);
@@ -97,8 +97,8 @@ int sqlite3BtreeIsInTrans(Btree*);
int sqlite3BtreeIsInReadTrans(Btree*);
int sqlite3BtreeIsInBackup(Btree*);
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
int sqlite3BtreeSchemaLocked(Btree *);
int sqlite3BtreeLockTable(Btree *, int, u8);
int sqlite3BtreeSchemaLocked(Btree *pBtree);
int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock);
int sqlite3BtreeSavepoint(Btree *, int, int);
const char *sqlite3BtreeGetFilename(Btree *);
@@ -116,10 +116,32 @@ int sqlite3BtreeIncrVacuum(Btree *);
int sqlite3BtreeDropTable(Btree*, int, int*);
int sqlite3BtreeClearTable(Btree*, int, int*);
int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue);
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
void sqlite3BtreeTripAllCursors(Btree*, int);
void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
/*
** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta
** should be one of the following values. The integer values are assigned
** to constants so that the offset of the corresponding field in an
** SQLite database header may be found using the following formula:
**
** offset = 36 + (idx * 4)
**
** For example, the free-page-count field is located at byte offset 36 of
** the database file header. The incr-vacuum-flag field is located at
** byte offset 64 (== 36+4*7).
*/
#define BTREE_FREE_PAGE_COUNT 0
#define BTREE_SCHEMA_VERSION 1
#define BTREE_FILE_FORMAT 2
#define BTREE_DEFAULT_CACHE_SIZE 3
#define BTREE_LARGEST_ROOT_PAGE 4
#define BTREE_TEXT_ENCODING 5
#define BTREE_USER_VERSION 6
#define BTREE_INCR_VACUUM 7
int sqlite3BtreeCursor(
Btree*, /* BTree containing table to open */
int iTable, /* Index of root page */
@@ -130,13 +152,6 @@ int sqlite3BtreeCursor(
int sqlite3BtreeCursorSize(void);
int sqlite3BtreeCloseCursor(BtCursor*);
int sqlite3BtreeMoveto(
BtCursor*,
const void *pKey,
i64 nKey,
int bias,
int *pRes
);
int sqlite3BtreeMovetoUnpacked(
BtCursor*,
UnpackedRecord *pUnKey,
@@ -153,11 +168,9 @@ int sqlite3BtreeFirst(BtCursor*, int *pRes);
int sqlite3BtreeLast(BtCursor*, int *pRes);
int sqlite3BtreeNext(BtCursor*, int *pRes);
int sqlite3BtreeEof(BtCursor*);
int sqlite3BtreeFlags(BtCursor*);
int sqlite3BtreePrevious(BtCursor*, int *pRes);
int sqlite3BtreeKeySize(BtCursor*, i64 *pSize);
int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
sqlite3 *sqlite3BtreeCursorDb(const BtCursor*);
const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt);
const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
@@ -172,6 +185,10 @@ int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
void sqlite3BtreeCacheOverflow(BtCursor *);
void sqlite3BtreeClearCursor(BtCursor *);
#ifndef NDEBUG
int sqlite3BtreeCursorIsValid(BtCursor*);
#endif
#ifndef SQLITE_OMIT_BTREECOUNT
int sqlite3BtreeCount(BtCursor *, i64 *);
#endif
+34 -35
View File
@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btreeInt.h,v 1.46 2009/03/20 14:18:52 danielk1977 Exp $
** $Id: btreeInt.h,v 1.52 2009/07/15 17:25:46 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@@ -71,6 +71,17 @@
** 36 4 Number of freelist pages in the file
** 40 60 15 4-byte meta values passed to higher layers
**
** 40 4 Schema cookie
** 44 4 File format of schema layer
** 48 4 Size of page cache
** 52 4 Largest root-page (auto/incr_vacuum)
** 56 4 1=UTF-8 2=UTF16le 3=UTF16be
** 60 4 User version
** 64 4 Incremental vacuum mode
** 68 4 unused
** 72 4 unused
** 76 4 unused
**
** All of the integer values are big-endian (most significant byte first).
**
** The file change counter is incremented when the database is changed
@@ -291,6 +302,24 @@ struct MemPage {
*/
#define EXTRA_SIZE sizeof(MemPage)
/*
** A linked list of the following structures is stored at BtShared.pLock.
** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor
** is opened on the table with root page BtShared.iTable. Locks are removed
** from this list when a transaction is committed or rolled back, or when
** a btree handle is closed.
*/
struct BtLock {
Btree *pBtree; /* Btree handle holding this lock */
Pgno iTable; /* Root page of table */
u8 eLock; /* READ_LOCK or WRITE_LOCK */
BtLock *pNext; /* Next in BtShared.pLock list */
};
/* Candidate values for BtLock.eLock */
#define READ_LOCK 1
#define WRITE_LOCK 2
/* A Btree handle
**
** A database connection contains a pointer to an instance of
@@ -322,6 +351,9 @@ struct Btree {
int nBackup; /* Number of backup operations reading this btree */
Btree *pNext; /* List of other sharable Btrees from the same db */
Btree *pPrev; /* Back pointer of the same list */
#ifndef SQLITE_OMIT_SHARED_CACHE
BtLock lock; /* Object used to lock page 1 */
#endif
};
/*
@@ -460,13 +492,10 @@ struct BtCursor {
u8 eState; /* One of the CURSOR_XXX constants (see below) */
void *pKey; /* Saved key that was cursor's last known position */
i64 nKey; /* Size of pKey, or last integer key */
int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */
int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
#ifndef SQLITE_OMIT_INCRBLOB
u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
Pgno *aOverflow; /* Cache of overflow page locations */
#endif
#ifndef NDEBUG
u8 pagesShuffled; /* True if Btree pages are rearranged by balance()*/
#endif
i16 iPage; /* Index of current page in apPage */
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
@@ -508,24 +537,6 @@ struct BtCursor {
*/
# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
/*
** A linked list of the following structures is stored at BtShared.pLock.
** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor
** is opened on the table with root page BtShared.iTable. Locks are removed
** from this list when a transaction is committed or rolled back, or when
** a btree handle is closed.
*/
struct BtLock {
Btree *pBtree; /* Btree handle holding this lock */
Pgno iTable; /* Root page of table */
u8 eLock; /* READ_LOCK or WRITE_LOCK */
BtLock *pNext; /* Next in BtShared.pLock list */
};
/* Candidate values for BtLock.eLock */
#define READ_LOCK 1
#define WRITE_LOCK 2
/*
** These macros define the location of the pointer-map entry for a
** database page. The first argument to each is the number of usable
@@ -627,15 +638,3 @@ struct IntegrityCk {
#define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v))
#define get4byte sqlite3Get4byte
#define put4byte sqlite3Put4byte
/*
** Internal routines that should be accessed by the btree layer only.
*/
int sqlite3BtreeGetPage(BtShared*, Pgno, MemPage**, int);
int sqlite3BtreeInitPage(MemPage *pPage);
void sqlite3BtreeParseCellPtr(MemPage*, u8*, CellInfo*);
void sqlite3BtreeParseCell(MemPage*, int, CellInfo*);
int sqlite3BtreeRestoreCursorPosition(BtCursor *pCur);
void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur);
void sqlite3BtreeReleaseTempCursor(BtCursor *pCur);
void sqlite3BtreeMoveToParent(BtCursor *pCur);
+247 -265
View File
File diff suppressed because it is too large Load Diff
+23 -26
View File
@@ -13,7 +13,7 @@
** This file contains functions used to access the internal hash tables
** of user defined functions and collation sequences.
**
** $Id: callback.c,v 1.39 2009/05/03 20:23:53 drh Exp $
** $Id: callback.c,v 1.42 2009/06/17 00:35:31 drh Exp $
*/
#include "sqliteInt.h"
@@ -23,11 +23,10 @@
** in the database text encoding of name zName, length nName.
** If the collation sequence
*/
static void callCollNeeded(sqlite3 *db, const char *zName, int nName){
static void callCollNeeded(sqlite3 *db, const char *zName){
assert( !db->xCollNeeded || !db->xCollNeeded16 );
if( nName<0 ) nName = sqlite3Strlen30(zName);
if( db->xCollNeeded ){
char *zExternal = sqlite3DbStrNDup(db, zName, nName);
char *zExternal = sqlite3DbStrDup(db, zName);
if( !zExternal ) return;
db->xCollNeeded(db->pCollNeededArg, db, (int)ENC(db), zExternal);
sqlite3DbFree(db, zExternal);
@@ -36,7 +35,7 @@ static void callCollNeeded(sqlite3 *db, const char *zName, int nName){
if( db->xCollNeeded16 ){
char const *zExternal;
sqlite3_value *pTmp = sqlite3ValueNew(db);
sqlite3ValueSetStr(pTmp, nName, zName, SQLITE_UTF8, SQLITE_STATIC);
sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF8, SQLITE_STATIC);
zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE);
if( zExternal ){
db->xCollNeeded16(db->pCollNeededArg, db, (int)ENC(db), zExternal);
@@ -56,11 +55,10 @@ static void callCollNeeded(sqlite3 *db, const char *zName, int nName){
static int synthCollSeq(sqlite3 *db, CollSeq *pColl){
CollSeq *pColl2;
char *z = pColl->zName;
int n = sqlite3Strlen30(z);
int i;
static const u8 aEnc[] = { SQLITE_UTF16BE, SQLITE_UTF16LE, SQLITE_UTF8 };
for(i=0; i<3; i++){
pColl2 = sqlite3FindCollSeq(db, aEnc[i], z, n, 0);
pColl2 = sqlite3FindCollSeq(db, aEnc[i], z, 0);
if( pColl2->xCmp!=0 ){
memcpy(pColl, pColl2, sizeof(CollSeq));
pColl->xDel = 0; /* Do not copy the destructor */
@@ -82,25 +80,26 @@ static int synthCollSeq(sqlite3 *db, CollSeq *pColl){
** The return value is either the collation sequence to be used in database
** db for collation type name zName, length nName, or NULL, if no collation
** sequence can be found.
**
** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq()
*/
CollSeq *sqlite3GetCollSeq(
sqlite3* db,
CollSeq *pColl,
const char *zName,
int nName
sqlite3* db, /* The database connection */
CollSeq *pColl, /* Collating sequence with native encoding, or NULL */
const char *zName /* Collating sequence name */
){
CollSeq *p;
p = pColl;
if( !p ){
p = sqlite3FindCollSeq(db, ENC(db), zName, nName, 0);
p = sqlite3FindCollSeq(db, ENC(db), zName, 0);
}
if( !p || !p->xCmp ){
/* No collation sequence of this type for this encoding is registered.
** Call the collation factory to see if it can supply us with one.
*/
callCollNeeded(db, zName, nName);
p = sqlite3FindCollSeq(db, ENC(db), zName, nName, 0);
callCollNeeded(db, zName);
p = sqlite3FindCollSeq(db, ENC(db), zName, 0);
}
if( p && !p->xCmp && synthCollSeq(db, p) ){
p = 0;
@@ -123,11 +122,9 @@ CollSeq *sqlite3GetCollSeq(
int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
if( pColl ){
const char *zName = pColl->zName;
CollSeq *p = sqlite3GetCollSeq(pParse->db, pColl, zName, -1);
CollSeq *p = sqlite3GetCollSeq(pParse->db, pColl, zName);
if( !p ){
if( pParse->nErr==0 ){
sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
}
sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
pParse->nErr++;
return SQLITE_ERROR;
}
@@ -152,13 +149,12 @@ int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
** each collation sequence structure.
*/
static CollSeq *findCollSeqEntry(
sqlite3 *db,
const char *zName,
int nName,
int create
sqlite3 *db, /* Database connection */
const char *zName, /* Name of the collating sequence */
int create /* Create a new entry if true */
){
CollSeq *pColl;
if( nName<0 ) nName = sqlite3Strlen30(zName);
int nName = sqlite3Strlen30(zName);
pColl = sqlite3HashFind(&db->aCollSeq, zName, nName);
if( 0==pColl && create ){
@@ -202,17 +198,18 @@ static CollSeq *findCollSeqEntry(
** this routine. sqlite3LocateCollSeq() invokes the collation factory
** if necessary and generates an error message if the collating sequence
** cannot be found.
**
** See also: sqlite3LocateCollSeq(), sqlite3GetCollSeq()
*/
CollSeq *sqlite3FindCollSeq(
sqlite3 *db,
u8 enc,
const char *zName,
int nName,
int create
){
CollSeq *pColl;
if( zName ){
pColl = findCollSeqEntry(db, zName, nName, create);
pColl = findCollSeqEntry(db, zName, create);
}else{
pColl = db->pDfltColl;
}
@@ -295,6 +292,7 @@ void sqlite3FuncDefInsert(
int h = (sqlite3UpperToLower[c1] + nName) % ArraySize(pHash->a);
pOther = functionSearch(pHash, h, pDef->zName, nName);
if( pOther ){
assert( pOther!=pDef && pOther->pNext!=pDef );
pDef->pNext = pOther->pNext;
pOther->pNext = pDef;
}else{
@@ -341,7 +339,6 @@ FuncDef *sqlite3FindFunction(
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
if( nArg<-1 ) nArg = -1;
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a);
/* First search for a match amongst the application-defined functions.
+48 -25
View File
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** in order to generate code for DELETE FROM statements.
**
** $Id: delete.c,v 1.201 2009/05/01 21:13:37 drh Exp $
** $Id: delete.c,v 1.207 2009/08/08 18:01:08 drh Exp $
*/
#include "sqliteInt.h"
@@ -43,16 +43,26 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
** writable return 0;
*/
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
if( ((pTab->tabFlags & TF_Readonly)!=0
&& (pParse->db->flags & SQLITE_WriteSchema)==0
&& pParse->nested==0)
#ifndef SQLITE_OMIT_VIRTUALTABLE
|| (pTab->pMod && pTab->pMod->pModule->xUpdate==0)
#endif
/* A table is not writable under the following circumstances:
**
** 1) It is a virtual table and no implementation of the xUpdate method
** has been provided, or
** 2) It is a system table (i.e. sqlite_master), this call is not
** part of a nested parse and writable_schema pragma has not
** been specified.
**
** In either case leave an error message in pParse and return non-zero.
*/
if( ( IsVirtual(pTab)
&& sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 )
|| ( (pTab->tabFlags & TF_Readonly)!=0
&& (pParse->db->flags & SQLITE_WriteSchema)==0
&& pParse->nested==0 )
){
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
return 1;
}
#ifndef SQLITE_OMIT_VIEW
if( !viewOk && pTab->pSelect ){
sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
@@ -82,13 +92,18 @@ void sqlite3MaterializeView(
pDup = sqlite3SelectDup(db, pView->pSelect, 0);
if( pWhere ){
SrcList *pFrom;
Token viewName;
pWhere = sqlite3ExprDup(db, pWhere, 0);
viewName.z = (u8*)pView->zName;
viewName.n = (unsigned int)sqlite3Strlen30((const char*)viewName.z);
viewName.quoted = 0;
pFrom = sqlite3SrcListAppendFromTerm(pParse, 0, 0, 0, &viewName, pDup, 0,0);
pFrom = sqlite3SrcListAppend(db, 0, 0, 0);
if( pFrom ){
assert( pFrom->nSrc==1 );
pFrom->a[0].zAlias = sqlite3DbStrDup(db, pView->zName);
pFrom->a[0].pSelect = pDup;
assert( pFrom->a[0].pOn==0 );
assert( pFrom->a[0].pUsing==0 );
}else{
sqlite3SelectDelete(db, pDup);
}
pDup = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
}
sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
@@ -148,9 +163,9 @@ Expr *sqlite3LimitWhere(
** );
*/
pSelectRowid = sqlite3Expr(pParse->db, TK_ROW, 0, 0, 0);
pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
if( pSelectRowid == 0 ) goto limit_where_cleanup_2;
pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid, 0);
pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid);
if( pEList == 0 ) goto limit_where_cleanup_2;
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
@@ -167,7 +182,7 @@ Expr *sqlite3LimitWhere(
if( pSelect == 0 ) return 0;
/* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
pWhereRowid = sqlite3Expr(pParse->db, TK_ROW, 0, 0, 0);
pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
if( pWhereRowid == 0 ) goto limit_where_cleanup_1;
pInClause = sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0);
if( pInClause == 0 ) goto limit_where_cleanup_1;
@@ -229,7 +244,7 @@ void sqlite3DeleteFrom(
int iEndBeforeTrigger = 0; /* Exit of before trigger program */
u32 old_col_mask = 0; /* Mask of OLD.* columns in use */
sContext.pParse = 0;
memset(&sContext, 0, sizeof(sContext));
db = pParse->db;
if( pParse->nErr || db->mallocFailed ){
goto delete_from_cleanup;
@@ -259,6 +274,12 @@ void sqlite3DeleteFrom(
# define isView 0
#endif
/* If pTab is really a view, make sure it has been initialized.
*/
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto delete_from_cleanup;
}
if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
goto delete_from_cleanup;
}
@@ -272,12 +293,6 @@ void sqlite3DeleteFrom(
}
assert(!isView || pTrigger);
/* If pTab is really a view, make sure it has been initialized.
*/
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto delete_from_cleanup;
}
/* Allocate a cursor used to store the old.* data for a trigger.
*/
if( pTrigger ){
@@ -438,9 +453,9 @@ void sqlite3DeleteFrom(
/* Delete the row */
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
const char *pVtab = (const char *)pTab->pVtab;
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
sqlite3VtabMakeWritable(pParse, pTab);
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, pVtab, P4_VTAB);
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, pVTab, P4_VTAB);
}else
#endif
{
@@ -470,6 +485,14 @@ void sqlite3DeleteFrom(
}
}
/* Update the sqlite_sequence table by storing the content of the
** maximum rowid counter values recorded while inserting into
** autoincrement tables.
*/
if( pParse->nested==0 && pParse->trigStack==0 ){
sqlite3AutoincrementEnd(pParse);
}
/*
** Return the number of rows that were deleted. If this routine is
** generating code because of a call to sqlite3NestedParse(), do not
@@ -594,7 +617,7 @@ int sqlite3GenerateIndexKey(
sqlite3VdbeAddOp2(v, OP_SCopy, regBase+nCol, regBase+j);
}else{
sqlite3VdbeAddOp3(v, OP_Column, iCur, idx, regBase+j);
sqlite3ColumnDefault(v, pTab, idx);
sqlite3ColumnDefault(v, pTab, idx, -1);
}
}
if( doMakeRec ){
+482 -387
View File
File diff suppressed because it is too large Load Diff
+15 -17
View File
@@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: func.c,v 1.234 2009/04/20 12:07:37 drh Exp $
** $Id: func.c,v 1.239 2009/06/19 16:44:41 drh Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@@ -247,7 +247,7 @@ static void substrFunc(
static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
int n = 0;
double r;
char zBuf[500]; /* larger than the %f representation of the largest double */
char *zBuf;
assert( argc==1 || argc==2 );
if( argc==2 ){
if( SQLITE_NULL==sqlite3_value_type(argv[1]) ) return;
@@ -257,9 +257,14 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
r = sqlite3_value_double(argv[0]);
sqlite3_snprintf(sizeof(zBuf),zBuf,"%.*f",n,r);
sqlite3AtoF(zBuf, &r);
sqlite3_result_double(context, r);
zBuf = sqlite3_mprintf("%.*f",n,r);
if( zBuf==0 ){
sqlite3_result_error_nomem(context);
}else{
sqlite3AtoF(zBuf, &r);
sqlite3_free(zBuf);
sqlite3_result_double(context, r);
}
}
#endif
@@ -1260,15 +1265,10 @@ static void groupConcatStep(
if( pAccum ){
sqlite3 *db = sqlite3_context_db_handle(context);
int n;
int firstTerm = pAccum->useMalloc==0;
pAccum->useMalloc = 1;
pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH];
#ifdef SQLITE_OMIT_DEPRECATED
n = context->pMem->n;
#else
n = sqlite3_aggregate_count(context);
#endif
if( n>1 ){
if( !firstTerm ){
if( argc==2 ){
zSep = (char*)sqlite3_value_text(argv[1]);
nSep = sqlite3_value_bytes(argv[1]);
@@ -1314,9 +1314,6 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
db->mallocFailed = 1;
}
}
#ifdef SQLITE_SSE
(void)sqlite3SseFunctions(db);
#endif
}
/*
@@ -1368,8 +1365,9 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
return 0;
}
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pDef = sqlite3FindFunction(db, (char*)pExpr->token.z, pExpr->token.n, 2,
SQLITE_UTF8, 0);
pDef = sqlite3FindFunction(db, pExpr->u.zToken,
sqlite3Strlen30(pExpr->u.zToken),
2, SQLITE_UTF8, 0);
if( NEVER(pDef==0) || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){
return 0;
}
+3 -2
View File
@@ -12,7 +12,7 @@
** This is the implementation of generic hash-tables
** used in SQLite.
**
** $Id: hash.c,v 1.37 2009/05/02 13:29:38 drh Exp $
** $Id: hash.c,v 1.38 2009/05/09 23:29:12 drh Exp $
*/
#include "sqliteInt.h"
#include <assert.h>
@@ -265,7 +265,8 @@ void *sqlite3HashInsert(Hash *pH, const char *pKey, int nKey, void *data){
new_elem->data = data;
pH->count++;
if( pH->count>=10 && pH->count > 2*pH->htsize ){
if( rehash(pH, pH->count*2) && pH->htsize ){
if( rehash(pH, pH->count*2) ){
assert( pH->htsize>0 );
h = strHash(pKey, nKey) % pH->htsize;
}
}
+122 -77
View File
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
** $Id: insert.c,v 1.267 2009/05/04 11:42:30 danielk1977 Exp $
** $Id: insert.c,v 1.270 2009/07/24 17:58:53 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -131,9 +131,14 @@ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
** a statement of the form "INSERT INTO <iDb, pTab> SELECT ..." can
** run without using temporary table for the results of the SELECT.
*/
static int readsTable(Vdbe *v, int iStartAddr, int iDb, Table *pTab){
static int readsTable(Parse *p, int iStartAddr, int iDb, Table *pTab){
Vdbe *v = sqlite3GetVdbe(p);
int i;
int iEnd = sqlite3VdbeCurrentAddr(v);
#ifndef SQLITE_OMIT_VIRTUALTABLE
VTable *pVTab = IsVirtual(pTab) ? sqlite3GetVTable(p->db, pTab) : 0;
#endif
for(i=iStartAddr; i<iEnd; i++){
VdbeOp *pOp = sqlite3VdbeGetOp(v, i);
assert( pOp!=0 );
@@ -150,7 +155,7 @@ static int readsTable(Vdbe *v, int iStartAddr, int iDb, Table *pTab){
}
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( pOp->opcode==OP_VOpen && pOp->p4.pVtab==pTab->pVtab ){
if( pOp->opcode==OP_VOpen && pOp->p4.pVtab==pVTab ){
assert( pOp->p4.pVtab!=0 );
assert( pOp->p4type==P4_VTAB );
return 1;
@@ -162,22 +167,24 @@ static int readsTable(Vdbe *v, int iStartAddr, int iDb, Table *pTab){
#ifndef SQLITE_OMIT_AUTOINCREMENT
/*
** Write out code to initialize the autoincrement logic. This code
** looks up the current autoincrement value in the sqlite_sequence
** table and stores that value in a register. Code generated by
** autoIncStep() will keep that register holding the largest
** rowid value. Code generated by autoIncEnd() will write the new
** largest value of the counter back into the sqlite_sequence table.
** Locate or create an AutoincInfo structure associated with table pTab
** which is in database iDb. Return the register number for the register
** that holds the maximum rowid.
**
** This routine returns the index of the mem[] cell that contains
** the maximum rowid counter.
** There is at most one AutoincInfo structure per table even if the
** same table is autoincremented multiple times due to inserts within
** triggers. A new AutoincInfo structure is created if this is the
** first use of table pTab. On 2nd and subsequent uses, the original
** AutoincInfo structure is used.
**
** Three consecutive registers are allocated by this routine. The
** first two hold the name of the target table and the maximum rowid
** inserted into the target table, respectively.
** The third holds the rowid in sqlite_sequence where we will
** write back the revised maximum rowid. This routine returns the
** index of the second of these three registers.
** Three memory locations are allocated:
**
** (1) Register to hold the name of the pTab table.
** (2) Register to hold the maximum ROWID of pTab.
** (3) Register to hold the rowid in sqlite_sequence of pTab
**
** The 2nd register is the one that is returned. That is all the
** insert routine needs to know about.
*/
static int autoIncBegin(
Parse *pParse, /* Parsing context */
@@ -186,31 +193,58 @@ static int autoIncBegin(
){
int memId = 0; /* Register holding maximum rowid */
if( pTab->tabFlags & TF_Autoincrement ){
Vdbe *v = pParse->pVdbe;
Db *pDb = &pParse->db->aDb[iDb];
int iCur = pParse->nTab++;
int addr; /* Address of the top of the loop */
assert( v );
pParse->nMem++; /* Holds name of table */
memId = ++pParse->nMem;
pParse->nMem++;
sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
addr = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, pTab->zName, 0);
sqlite3VdbeAddOp2(v, OP_Rewind, iCur, addr+9);
sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, memId);
sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId);
sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, memId+1);
sqlite3VdbeAddOp3(v, OP_Column, iCur, 1, memId);
sqlite3VdbeAddOp2(v, OP_Goto, 0, addr+9);
sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+2);
sqlite3VdbeAddOp2(v, OP_Integer, 0, memId);
sqlite3VdbeAddOp2(v, OP_Close, iCur, 0);
AutoincInfo *pInfo;
pInfo = pParse->pAinc;
while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
if( pInfo==0 ){
pInfo = sqlite3DbMallocRaw(pParse->db, sizeof(*pInfo));
if( pInfo==0 ) return 0;
pInfo->pNext = pParse->pAinc;
pParse->pAinc = pInfo;
pInfo->pTab = pTab;
pInfo->iDb = iDb;
pParse->nMem++; /* Register to hold name of table */
pInfo->regCtr = ++pParse->nMem; /* Max rowid register */
pParse->nMem++; /* Rowid in sqlite_sequence */
}
memId = pInfo->regCtr;
}
return memId;
}
/*
** This routine generates code that will initialize all of the
** register used by the autoincrement tracker.
*/
void sqlite3AutoincrementBegin(Parse *pParse){
AutoincInfo *p; /* Information about an AUTOINCREMENT */
sqlite3 *db = pParse->db; /* The database connection */
Db *pDb; /* Database only autoinc table */
int memId; /* Register holding max rowid */
int addr; /* A VDBE address */
Vdbe *v = pParse->pVdbe; /* VDBE under construction */
assert( v ); /* We failed long ago if this is not so */
for(p = pParse->pAinc; p; p = p->pNext){
pDb = &db->aDb[p->iDb];
memId = p->regCtr;
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
addr = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, p->pTab->zName, 0);
sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9);
sqlite3VdbeAddOp3(v, OP_Column, 0, 0, memId);
sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId);
sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1);
sqlite3VdbeAddOp3(v, OP_Column, 0, 1, memId);
sqlite3VdbeAddOp2(v, OP_Goto, 0, addr+9);
sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2);
sqlite3VdbeAddOp2(v, OP_Integer, 0, memId);
sqlite3VdbeAddOp0(v, OP_Close);
}
}
/*
** Update the maximum rowid for an autoincrement calculation.
**
@@ -226,32 +260,43 @@ static void autoIncStep(Parse *pParse, int memId, int regRowid){
}
/*
** After doing one or more inserts, the maximum rowid is stored
** in reg[memId]. Generate code to write this value back into the
** the sqlite_sequence table.
** This routine generates the code needed to write autoincrement
** maximum rowid values back into the sqlite_sequence register.
** Every statement that might do an INSERT into an autoincrement
** table (either directly or through triggers) needs to call this
** routine just before the "exit" code.
*/
static void autoIncEnd(
Parse *pParse, /* The parsing context */
int iDb, /* Index of the database holding pTab */
Table *pTab, /* Table we are inserting into */
int memId /* Memory cell holding the maximum rowid */
){
if( pTab->tabFlags & TF_Autoincrement ){
int iCur = pParse->nTab++;
Vdbe *v = pParse->pVdbe;
Db *pDb = &pParse->db->aDb[iDb];
int j1;
int iRec = ++pParse->nMem; /* Memory cell used for record */
void sqlite3AutoincrementEnd(Parse *pParse){
AutoincInfo *p;
Vdbe *v = pParse->pVdbe;
sqlite3 *db = pParse->db;
assert( v );
sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
assert( v );
for(p = pParse->pAinc; p; p = p->pNext){
Db *pDb = &db->aDb[p->iDb];
int j1, j2, j3, j4, j5;
int iRec;
int memId = p->regCtr;
iRec = sqlite3GetTempReg(pParse);
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1);
sqlite3VdbeAddOp2(v, OP_NewRowid, iCur, memId+1);
j2 = sqlite3VdbeAddOp0(v, OP_Rewind);
j3 = sqlite3VdbeAddOp3(v, OP_Column, 0, 0, iRec);
j4 = sqlite3VdbeAddOp3(v, OP_Eq, memId-1, 0, iRec);
sqlite3VdbeAddOp2(v, OP_Next, 0, j3);
sqlite3VdbeJumpHere(v, j2);
sqlite3VdbeAddOp2(v, OP_NewRowid, 0, memId+1);
j5 = sqlite3VdbeAddOp0(v, OP_Goto);
sqlite3VdbeJumpHere(v, j4);
sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1);
sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeJumpHere(v, j5);
sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec);
sqlite3VdbeAddOp3(v, OP_Insert, iCur, iRec, memId+1);
sqlite3VdbeAddOp3(v, OP_Insert, 0, iRec, memId+1);
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
sqlite3VdbeAddOp1(v, OP_Close, iCur);
sqlite3VdbeAddOp0(v, OP_Close);
sqlite3ReleaseTempReg(pParse, iRec);
}
}
#else
@@ -261,7 +306,6 @@ static void autoIncEnd(
*/
# define autoIncBegin(A,B,C) (0)
# define autoIncStep(A,B,C)
# define autoIncEnd(A,B,C,D)
#endif /* SQLITE_OMIT_AUTOINCREMENT */
@@ -465,15 +509,6 @@ void sqlite3Insert(
#endif
assert( (pTrigger && tmask) || (pTrigger==0 && tmask==0) );
/* Ensure that:
* (a) the table is not read-only,
* (b) that if it is a view then ON INSERT triggers exist
*/
if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
goto insert_cleanup;
}
assert( pTab!=0 );
/* If pTab is really a view, make sure it has been initialized.
** ViewGetColumnNames() is a no-op if pTab is not a view (or virtual
** module table).
@@ -482,6 +517,14 @@ void sqlite3Insert(
goto insert_cleanup;
}
/* Ensure that:
* (a) the table is not read-only,
* (b) that if it is a view then ON INSERT triggers exist
*/
if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
goto insert_cleanup;
}
/* Allocate a VDBE
*/
v = sqlite3GetVdbe(pParse);
@@ -507,7 +550,7 @@ void sqlite3Insert(
if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){
assert( !pTrigger );
assert( pList==0 );
goto insert_cleanup;
goto insert_end;
}
#endif /* SQLITE_OMIT_XFER_OPT */
@@ -581,7 +624,7 @@ void sqlite3Insert(
** of the tables being read by the SELECT statement. Also use a
** temp table in the case of row triggers.
*/
if( pTrigger || readsTable(v, addrSelect, iDb, pTab) ){
if( pTrigger || readsTable(pParse, addrSelect, iDb, pTab) ){
useTempTable = 1;
}
@@ -862,7 +905,7 @@ void sqlite3Insert(
}else{
VdbeOp *pOp;
sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regRowid);
pOp = sqlite3VdbeGetOp(v, sqlite3VdbeCurrentAddr(v) - 1);
pOp = sqlite3VdbeGetOp(v, -1);
if( ALWAYS(pOp) && pOp->opcode==OP_Null && !IsVirtual(pTab) ){
appendFlag = 1;
pOp->opcode = OP_NewRowid;
@@ -937,9 +980,9 @@ void sqlite3Insert(
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
sqlite3VtabMakeWritable(pParse, pTab);
sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns,
(const char*)pTab->pVtab, P4_VTAB);
sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB);
}else
#endif
{
@@ -989,11 +1032,14 @@ void sqlite3Insert(
}
}
insert_end:
/* Update the sqlite_sequence table by storing the content of the
** counter value in memory regAutoinc back into the sqlite_sequence
** table.
** maximum rowid counter values recorded while inserting into
** autoincrement tables.
*/
autoIncEnd(pParse, iDb, pTab, regAutoinc);
if( pParse->nested==0 && pParse->trigStack==0 ){
sqlite3AutoincrementEnd(pParse);
}
/*
** Return the number of rows inserted. If this routine is
@@ -1716,7 +1762,6 @@ static int xferOptimization(
sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1);
autoIncEnd(pParse, iDbDest, pDest, regAutoinc);
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){
if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
+4 -1
View File
@@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: legacy.c,v 1.33 2009/05/05 20:02:48 drh Exp $
** $Id: legacy.c,v 1.35 2009/08/07 16:56:00 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -132,6 +132,9 @@ exec_out:
*pzErrMsg = sqlite3Malloc(nErrMsg);
if( *pzErrMsg ){
memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg);
}else{
rc = SQLITE_NOMEM;
sqlite3Error(db, SQLITE_NOMEM, 0);
}
}else if( pzErrMsg ){
*pzErrMsg = 0;
+854
View File
@@ -0,0 +1,854 @@
/* Driver template for the LEMON parser generator.
** The author disclaims copyright to this source code.
**
** This version of "lempar.c" is modified, slightly, for use by SQLite.
** The only modifications are the addition of a couple of NEVER()
** macros to disable tests that are needed in the case of a general
** LALR(1) grammar but which are always false in the
** specific grammar used by SQLite.
*/
/* First off, code is included that follows the "include" declaration
** in the input grammar file. */
#include <stdio.h>
%%
/* Next is all token values, in a form suitable for use by makeheaders.
** This section will be null unless lemon is run with the -m switch.
*/
/*
** These constants (all generated automatically by the parser generator)
** specify the various kinds of tokens (terminals) that the parser
** understands.
**
** Each symbol here is a terminal symbol in the grammar.
*/
%%
/* Make sure the INTERFACE macro is defined.
*/
#ifndef INTERFACE
# define INTERFACE 1
#endif
/* The next thing included is series of defines which control
** various aspects of the generated parser.
** YYCODETYPE is the data type used for storing terminal
** and nonterminal numbers. "unsigned char" is
** used if there are fewer than 250 terminals
** and nonterminals. "int" is used otherwise.
** YYNOCODE is a number of type YYCODETYPE which corresponds
** to no legal terminal or nonterminal number. This
** number is used to fill in empty slots of the hash
** table.
** YYFALLBACK If defined, this indicates that one or more tokens
** have fall-back values which should be used if the
** original value of the token will not parse.
** YYACTIONTYPE is the data type used for storing terminal
** and nonterminal numbers. "unsigned char" is
** used if there are fewer than 250 rules and
** states combined. "int" is used otherwise.
** ParseTOKENTYPE is the data type used for minor tokens given
** directly to the parser from the tokenizer.
** YYMINORTYPE is the data type used for all minor tokens.
** This is typically a union of many types, one of
** which is ParseTOKENTYPE. The entry in the union
** for base tokens is called "yy0".
** YYSTACKDEPTH is the maximum depth of the parser's stack. If
** zero the stack is dynamically sized using realloc()
** ParseARG_SDECL A static variable declaration for the %extra_argument
** ParseARG_PDECL A parameter declaration for the %extra_argument
** ParseARG_STORE Code to store %extra_argument into yypParser
** ParseARG_FETCH Code to extract %extra_argument from yypParser
** YYNSTATE the combined number of states.
** YYNRULE the number of rules in the grammar
** YYERRORSYMBOL is the code number of the error symbol. If not
** defined, then do no error processing.
*/
%%
#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
/* The yyzerominor constant is used to initialize instances of
** YYMINORTYPE objects to zero. */
static const YYMINORTYPE yyzerominor = { 0 };
/* Define the yytestcase() macro to be a no-op if is not already defined
** otherwise.
**
** Applications can choose to define yytestcase() in the %include section
** to a macro that can assist in verifying code coverage. For production
** code the yytestcase() macro should be turned off. But it is useful
** for testing.
*/
#ifndef yytestcase
# define yytestcase(X)
#endif
/* Next are the tables used to determine what action to take based on the
** current state and lookahead token. These tables are used to implement
** functions that take a state number and lookahead value and return an
** action integer.
**
** Suppose the action integer is N. Then the action is determined as
** follows
**
** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
** token onto the stack and goto state N.
**
** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
**
** N == YYNSTATE+YYNRULE A syntax error has occurred.
**
** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
**
** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
** slots in the yy_action[] table.
**
** The action table is constructed as a single large table named yy_action[].
** Given state S and lookahead X, the action is computed as
**
** yy_action[ yy_shift_ofst[S] + X ]
**
** If the index value yy_shift_ofst[S]+X is out of range or if the value
** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
** and that yy_default[S] should be used instead.
**
** The formula above is for computing the action when the lookahead is
** a terminal symbol. If the lookahead is a non-terminal (as occurs after
** a reduce action) then the yy_reduce_ofst[] array is used in place of
** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
** YY_SHIFT_USE_DFLT.
**
** The following are the tables generated in this section:
**
** yy_action[] A single table containing all actions.
** yy_lookahead[] A table containing the lookahead for each entry in
** yy_action. Used to detect hash collisions.
** yy_shift_ofst[] For each state, the offset into yy_action for
** shifting terminals.
** yy_reduce_ofst[] For each state, the offset into yy_action for
** shifting non-terminals after a reduce.
** yy_default[] Default action for each state.
*/
%%
#define YY_SZ_ACTTAB (int)(sizeof(yy_action)/sizeof(yy_action[0]))
/* The next table maps tokens into fallback tokens. If a construct
** like the following:
**
** %fallback ID X Y Z.
**
** appears in the grammar, then ID becomes a fallback token for X, Y,
** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
** but it does not parse, the type of the token is changed to ID and
** the parse is retried before an error is thrown.
*/
#ifdef YYFALLBACK
static const YYCODETYPE yyFallback[] = {
%%
};
#endif /* YYFALLBACK */
/* The following structure represents a single element of the
** parser's stack. Information stored includes:
**
** + The state number for the parser at this level of the stack.
**
** + The value of the token stored at this level of the stack.
** (In other words, the "major" token.)
**
** + The semantic value stored at this level of the stack. This is
** the information used by the action routines in the grammar.
** It is sometimes called the "minor" token.
*/
struct yyStackEntry {
YYACTIONTYPE stateno; /* The state-number */
YYCODETYPE major; /* The major token value. This is the code
** number for the token at this stack level */
YYMINORTYPE minor; /* The user-supplied minor token value. This
** is the value of the token */
};
typedef struct yyStackEntry yyStackEntry;
/* The state of the parser is completely contained in an instance of
** the following structure */
struct yyParser {
int yyidx; /* Index of top element in stack */
#ifdef YYTRACKMAXSTACKDEPTH
int yyidxMax; /* Maximum value of yyidx */
#endif
int yyerrcnt; /* Shifts left before out of the error */
ParseARG_SDECL /* A place to hold %extra_argument */
#if YYSTACKDEPTH<=0
int yystksz; /* Current side of the stack */
yyStackEntry *yystack; /* The parser's stack */
#else
yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
#endif
};
typedef struct yyParser yyParser;
#ifndef NDEBUG
#include <stdio.h>
static FILE *yyTraceFILE = 0;
static char *yyTracePrompt = 0;
#endif /* NDEBUG */
#ifndef NDEBUG
/*
** Turn parser tracing on by giving a stream to which to write the trace
** and a prompt to preface each trace message. Tracing is turned off
** by making either argument NULL
**
** Inputs:
** <ul>
** <li> A FILE* to which trace output should be written.
** If NULL, then tracing is turned off.
** <li> A prefix string written at the beginning of every
** line of trace output. If NULL, then tracing is
** turned off.
** </ul>
**
** Outputs:
** None.
*/
void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
yyTraceFILE = TraceFILE;
yyTracePrompt = zTracePrompt;
if( yyTraceFILE==0 ) yyTracePrompt = 0;
else if( yyTracePrompt==0 ) yyTraceFILE = 0;
}
#endif /* NDEBUG */
#ifndef NDEBUG
/* For tracing shifts, the names of all terminals and nonterminals
** are required. The following table supplies these names */
static const char *const yyTokenName[] = {
%%
};
#endif /* NDEBUG */
#ifndef NDEBUG
/* For tracing reduce actions, the names of all rules are required.
*/
static const char *const yyRuleName[] = {
%%
};
#endif /* NDEBUG */
#if YYSTACKDEPTH<=0
/*
** Try to increase the size of the parser stack.
*/
static void yyGrowStack(yyParser *p){
int newSize;
yyStackEntry *pNew;
newSize = p->yystksz*2 + 100;
pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
if( pNew ){
p->yystack = pNew;
p->yystksz = newSize;
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sStack grows to %d entries!\n",
yyTracePrompt, p->yystksz);
}
#endif
}
}
#endif
/*
** This function allocates a new parser.
** The only argument is a pointer to a function which works like
** malloc.
**
** Inputs:
** A pointer to the function used to allocate memory.
**
** Outputs:
** A pointer to a parser. This pointer is used in subsequent calls
** to Parse and ParseFree.
*/
void *ParseAlloc(void *(*mallocProc)(size_t)){
yyParser *pParser;
pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
if( pParser ){
pParser->yyidx = -1;
#ifdef YYTRACKMAXSTACKDEPTH
pParser->yyidxMax = 0;
#endif
#if YYSTACKDEPTH<=0
pParser->yystack = NULL;
pParser->yystksz = 0;
yyGrowStack(pParser);
#endif
}
return pParser;
}
/* The following function deletes the value associated with a
** symbol. The symbol can be either a terminal or nonterminal.
** "yymajor" is the symbol code, and "yypminor" is a pointer to
** the value.
*/
static void yy_destructor(
yyParser *yypParser, /* The parser */
YYCODETYPE yymajor, /* Type code for object to destroy */
YYMINORTYPE *yypminor /* The object to be destroyed */
){
ParseARG_FETCH;
switch( yymajor ){
/* Here is inserted the actions which take place when a
** terminal or non-terminal is destroyed. This can happen
** when the symbol is popped from the stack during a
** reduce or during error processing or when a parser is
** being destroyed before it is finished parsing.
**
** Note: during a reduce, the only symbols destroyed are those
** which appear on the RHS of the rule, but which are not used
** inside the C code.
*/
%%
default: break; /* If no destructor action specified: do nothing */
}
}
/*
** Pop the parser's stack once.
**
** If there is a destructor routine associated with the token which
** is popped from the stack, then call it.
**
** Return the major token number for the symbol popped.
*/
static int yy_pop_parser_stack(yyParser *pParser){
YYCODETYPE yymajor;
yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
/* There is no mechanism by which the parser stack can be popped below
** empty in SQLite. */
if( NEVER(pParser->yyidx<0) ) return 0;
#ifndef NDEBUG
if( yyTraceFILE && pParser->yyidx>=0 ){
fprintf(yyTraceFILE,"%sPopping %s\n",
yyTracePrompt,
yyTokenName[yytos->major]);
}
#endif
yymajor = yytos->major;
yy_destructor(pParser, yymajor, &yytos->minor);
pParser->yyidx--;
return yymajor;
}
/*
** Deallocate and destroy a parser. Destructors are all called for
** all stack elements before shutting the parser down.
**
** Inputs:
** <ul>
** <li> A pointer to the parser. This should be a pointer
** obtained from ParseAlloc.
** <li> A pointer to a function used to reclaim memory obtained
** from malloc.
** </ul>
*/
void ParseFree(
void *p, /* The parser to be deleted */
void (*freeProc)(void*) /* Function used to reclaim memory */
){
yyParser *pParser = (yyParser*)p;
/* In SQLite, we never try to destroy a parser that was not successfully
** created in the first place. */
if( NEVER(pParser==0) ) return;
while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
#if YYSTACKDEPTH<=0
free(pParser->yystack);
#endif
(*freeProc)((void*)pParser);
}
/*
** Return the peak depth of the stack for a parser.
*/
#ifdef YYTRACKMAXSTACKDEPTH
int ParseStackPeak(void *p){
yyParser *pParser = (yyParser*)p;
return pParser->yyidxMax;
}
#endif
/*
** Find the appropriate action for a parser given the terminal
** look-ahead token iLookAhead.
**
** If the look-ahead token is YYNOCODE, then check to see if the action is
** independent of the look-ahead. If it is, return the action, otherwise
** return YY_NO_ACTION.
*/
static int yy_find_shift_action(
yyParser *pParser, /* The parser */
YYCODETYPE iLookAhead /* The look-ahead token */
){
int i;
int stateno = pParser->yystack[pParser->yyidx].stateno;
if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
return yy_default[stateno];
}
assert( iLookAhead!=YYNOCODE );
i += iLookAhead;
if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
/* The user of ";" instead of "\000" as a statement terminator in SQLite
** means that we always have a look-ahead token. */
if( iLookAhead>0 ){
#ifdef YYFALLBACK
YYCODETYPE iFallback; /* Fallback token */
if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
&& (iFallback = yyFallback[iLookAhead])!=0 ){
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
}
#endif
return yy_find_shift_action(pParser, iFallback);
}
#endif
#ifdef YYWILDCARD
{
int j = i - iLookAhead + YYWILDCARD;
if( j>=0 && j<YY_SZ_ACTTAB && yy_lookahead[j]==YYWILDCARD ){
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]);
}
#endif /* NDEBUG */
return yy_action[j];
}
}
#endif /* YYWILDCARD */
}
return yy_default[stateno];
}else{
return yy_action[i];
}
}
/*
** Find the appropriate action for a parser given the non-terminal
** look-ahead token iLookAhead.
**
** If the look-ahead token is YYNOCODE, then check to see if the action is
** independent of the look-ahead. If it is, return the action, otherwise
** return YY_NO_ACTION.
*/
static int yy_find_reduce_action(
int stateno, /* Current state number */
YYCODETYPE iLookAhead /* The look-ahead token */
){
int i;
#ifdef YYERRORSYMBOL
if( stateno>YY_REDUCE_MAX ){
return yy_default[stateno];
}
#else
assert( stateno<=YY_REDUCE_MAX );
#endif
i = yy_reduce_ofst[stateno];
assert( i!=YY_REDUCE_USE_DFLT );
assert( iLookAhead!=YYNOCODE );
i += iLookAhead;
#ifdef YYERRORSYMBOL
if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
return yy_default[stateno];
}
#else
assert( i>=0 && i<YY_SZ_ACTTAB );
assert( yy_lookahead[i]==iLookAhead );
#endif
return yy_action[i];
}
/*
** The following routine is called if the stack overflows.
*/
static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
ParseARG_FETCH;
yypParser->yyidx--;
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
}
#endif
while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
/* Here code is inserted which will execute if the parser
** stack every overflows */
%%
ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
}
/*
** Perform a shift action.
*/
static void yy_shift(
yyParser *yypParser, /* The parser to be shifted */
int yyNewState, /* The new state to shift in */
int yyMajor, /* The major token to shift in */
YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */
){
yyStackEntry *yytos;
yypParser->yyidx++;
#ifdef YYTRACKMAXSTACKDEPTH
if( yypParser->yyidx>yypParser->yyidxMax ){
yypParser->yyidxMax = yypParser->yyidx;
}
#endif
#if YYSTACKDEPTH>0
if( yypParser->yyidx>=YYSTACKDEPTH ){
yyStackOverflow(yypParser, yypMinor);
return;
}
#else
if( yypParser->yyidx>=yypParser->yystksz ){
yyGrowStack(yypParser);
if( yypParser->yyidx>=yypParser->yystksz ){
yyStackOverflow(yypParser, yypMinor);
return;
}
}
#endif
yytos = &yypParser->yystack[yypParser->yyidx];
yytos->stateno = (YYACTIONTYPE)yyNewState;
yytos->major = (YYCODETYPE)yyMajor;
yytos->minor = *yypMinor;
#ifndef NDEBUG
if( yyTraceFILE && yypParser->yyidx>0 ){
int i;
fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
for(i=1; i<=yypParser->yyidx; i++)
fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
fprintf(yyTraceFILE,"\n");
}
#endif
}
/* The following table contains information about every rule that
** is used during the reduce.
*/
static const struct {
YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
unsigned char nrhs; /* Number of right-hand side symbols in the rule */
} yyRuleInfo[] = {
%%
};
static void yy_accept(yyParser*); /* Forward Declaration */
/*
** Perform a reduce action and the shift that must immediately
** follow the reduce.
*/
static void yy_reduce(
yyParser *yypParser, /* The parser */
int yyruleno /* Number of the rule by which to reduce */
){
int yygoto; /* The next state */
int yyact; /* The next action */
YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
yyStackEntry *yymsp; /* The top of the parser's stack */
int yysize; /* Amount to pop the stack */
ParseARG_FETCH;
yymsp = &yypParser->yystack[yypParser->yyidx];
#ifndef NDEBUG
if( yyTraceFILE && yyruleno>=0
&& yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
yyRuleName[yyruleno]);
}
#endif /* NDEBUG */
/* Silence complaints from purify about yygotominor being uninitialized
** in some cases when it is copied into the stack after the following
** switch. yygotominor is uninitialized when a rule reduces that does
** not set the value of its left-hand side nonterminal. Leaving the
** value of the nonterminal uninitialized is utterly harmless as long
** as the value is never used. So really the only thing this code
** accomplishes is to quieten purify.
**
** 2007-01-16: The wireshark project (www.wireshark.org) reports that
** without this code, their parser segfaults. I'm not sure what there
** parser is doing to make this happen. This is the second bug report
** from wireshark this week. Clearly they are stressing Lemon in ways
** that it has not been previously stressed... (SQLite ticket #2172)
*/
/*memset(&yygotominor, 0, sizeof(yygotominor));*/
yygotominor = yyzerominor;
switch( yyruleno ){
/* Beginning here are the reduction cases. A typical example
** follows:
** case 0:
** #line <lineno> <grammarfile>
** { ... } // User supplied code
** #line <lineno> <thisfile>
** break;
*/
%%
};
yygoto = yyRuleInfo[yyruleno].lhs;
yysize = yyRuleInfo[yyruleno].nrhs;
yypParser->yyidx -= yysize;
yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
if( yyact < YYNSTATE ){
#ifdef NDEBUG
/* If we are not debugging and the reduce action popped at least
** one element off the stack, then we can push the new element back
** onto the stack here, and skip the stack overflow test in yy_shift().
** That gives a significant speed improvement. */
if( yysize ){
yypParser->yyidx++;
yymsp -= yysize-1;
yymsp->stateno = (YYACTIONTYPE)yyact;
yymsp->major = (YYCODETYPE)yygoto;
yymsp->minor = yygotominor;
}else
#endif
{
yy_shift(yypParser,yyact,yygoto,&yygotominor);
}
}else{
assert( yyact == YYNSTATE + YYNRULE + 1 );
yy_accept(yypParser);
}
}
/*
** The following code executes when the parse fails
*/
#ifndef YYNOERRORRECOVERY
static void yy_parse_failed(
yyParser *yypParser /* The parser */
){
ParseARG_FETCH;
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
}
#endif
while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
/* Here code is inserted which will be executed whenever the
** parser fails */
%%
ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
#endif /* YYNOERRORRECOVERY */
/*
** The following code executes when a syntax error first occurs.
*/
static void yy_syntax_error(
yyParser *yypParser, /* The parser */
int yymajor, /* The major type of the error token */
YYMINORTYPE yyminor /* The minor type of the error token */
){
ParseARG_FETCH;
#define TOKEN (yyminor.yy0)
%%
ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
/*
** The following is executed when the parser accepts
*/
static void yy_accept(
yyParser *yypParser /* The parser */
){
ParseARG_FETCH;
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
}
#endif
while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
/* Here code is inserted which will be executed whenever the
** parser accepts */
%%
ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
/* The main parser program.
** The first argument is a pointer to a structure obtained from
** "ParseAlloc" which describes the current state of the parser.
** The second argument is the major token number. The third is
** the minor token. The fourth optional argument is whatever the
** user wants (and specified in the grammar) and is available for
** use by the action routines.
**
** Inputs:
** <ul>
** <li> A pointer to the parser (an opaque structure.)
** <li> The major token number.
** <li> The minor token number.
** <li> An option argument of a grammar-specified type.
** </ul>
**
** Outputs:
** None.
*/
void Parse(
void *yyp, /* The parser */
int yymajor, /* The major token code number */
ParseTOKENTYPE yyminor /* The value for the token */
ParseARG_PDECL /* Optional %extra_argument parameter */
){
YYMINORTYPE yyminorunion;
int yyact; /* The parser action. */
int yyendofinput; /* True if we are at the end of input */
#ifdef YYERRORSYMBOL
int yyerrorhit = 0; /* True if yymajor has invoked an error */
#endif
yyParser *yypParser; /* The parser */
/* (re)initialize the parser, if necessary */
yypParser = (yyParser*)yyp;
if( yypParser->yyidx<0 ){
#if YYSTACKDEPTH<=0
if( yypParser->yystksz <=0 ){
/*memset(&yyminorunion, 0, sizeof(yyminorunion));*/
yyminorunion = yyzerominor;
yyStackOverflow(yypParser, &yyminorunion);
return;
}
#endif
yypParser->yyidx = 0;
yypParser->yyerrcnt = -1;
yypParser->yystack[0].stateno = 0;
yypParser->yystack[0].major = 0;
}
yyminorunion.yy0 = yyminor;
yyendofinput = (yymajor==0);
ParseARG_STORE;
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
}
#endif
do{
yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
if( yyact<YYNSTATE ){
assert( !yyendofinput ); /* Impossible to shift the $ token */
yy_shift(yypParser,yyact,yymajor,&yyminorunion);
yypParser->yyerrcnt--;
yymajor = YYNOCODE;
}else if( yyact < YYNSTATE + YYNRULE ){
yy_reduce(yypParser,yyact-YYNSTATE);
}else{
assert( yyact == YY_ERROR_ACTION );
#ifdef YYERRORSYMBOL
int yymx;
#endif
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
}
#endif
#ifdef YYERRORSYMBOL
/* A syntax error has occurred.
** The response to an error depends upon whether or not the
** grammar defines an error token "ERROR".
**
** This is what we do if the grammar does define ERROR:
**
** * Call the %syntax_error function.
**
** * Begin popping the stack until we enter a state where
** it is legal to shift the error symbol, then shift
** the error symbol.
**
** * Set the error count to three.
**
** * Begin accepting and shifting new tokens. No new error
** processing will occur until three tokens have been
** shifted successfully.
**
*/
if( yypParser->yyerrcnt<0 ){
yy_syntax_error(yypParser,yymajor,yyminorunion);
}
yymx = yypParser->yystack[yypParser->yyidx].major;
if( yymx==YYERRORSYMBOL || yyerrorhit ){
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sDiscard input token %s\n",
yyTracePrompt,yyTokenName[yymajor]);
}
#endif
yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion);
yymajor = YYNOCODE;
}else{
while(
yypParser->yyidx >= 0 &&
yymx != YYERRORSYMBOL &&
(yyact = yy_find_reduce_action(
yypParser->yystack[yypParser->yyidx].stateno,
YYERRORSYMBOL)) >= YYNSTATE
){
yy_pop_parser_stack(yypParser);
}
if( yypParser->yyidx < 0 || yymajor==0 ){
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
yy_parse_failed(yypParser);
yymajor = YYNOCODE;
}else if( yymx!=YYERRORSYMBOL ){
YYMINORTYPE u2;
u2.YYERRSYMDT = 0;
yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
}
}
yypParser->yyerrcnt = 3;
yyerrorhit = 1;
#elif defined(YYNOERRORRECOVERY)
/* If the YYNOERRORRECOVERY macro is defined, then do not attempt to
** do any kind of error recovery. Instead, simply invoke the syntax
** error routine and continue going as if nothing had happened.
**
** Applications can set this macro (for example inside %include) if
** they intend to abandon the parse upon the first syntax error seen.
*/
yy_syntax_error(yypParser,yymajor,yyminorunion);
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
yymajor = YYNOCODE;
#else /* YYERRORSYMBOL is not defined */
/* This is what we do if the grammar does not define ERROR:
**
** * Report an error message, and throw away the input token.
**
** * If the input token is $, then fail the parse.
**
** As before, subsequent error messages are suppressed until
** three input tokens have been successfully shifted.
*/
if( yypParser->yyerrcnt<=0 ){
yy_syntax_error(yypParser,yymajor,yyminorunion);
}
yypParser->yyerrcnt = 3;
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
if( yyendofinput ){
yy_parse_failed(yypParser);
}
yymajor = YYNOCODE;
#endif
}
}while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
return;
}
+28 -20
View File
@@ -12,7 +12,7 @@
** This file contains code used to dynamically load extensions into
** the SQLite library.
**
** $Id: loadext.c,v 1.58 2009/01/20 16:53:40 danielk1977 Exp $
** $Id: loadext.c,v 1.60 2009/06/03 01:24:54 drh Exp $
*/
#ifndef SQLITE_CORE
@@ -354,6 +354,9 @@ static int sqlite3LoadExtension(
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
char *zErrmsg = 0;
void **aHandle;
const int nMsg = 300;
if( pzErrMsg ) *pzErrMsg = 0;
/* Ticket #1863. To avoid a creating security problems for older
** applications that relink against newer versions of SQLite, the
@@ -375,12 +378,14 @@ static int sqlite3LoadExtension(
handle = sqlite3OsDlOpen(pVfs, zFile);
if( handle==0 ){
if( pzErrMsg ){
char zErr[256];
zErr[sizeof(zErr)-1] = '\0';
sqlite3_snprintf(sizeof(zErr)-1, zErr,
"unable to open shared library [%s]", zFile);
sqlite3OsDlError(pVfs, sizeof(zErr)-1, zErr);
*pzErrMsg = sqlite3DbStrDup(0, zErr);
zErrmsg = sqlite3StackAllocZero(db, nMsg);
if( zErrmsg ){
sqlite3_snprintf(nMsg, zErrmsg,
"unable to open shared library [%s]", zFile);
sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
*pzErrMsg = sqlite3DbStrDup(0, zErrmsg);
sqlite3StackFree(db, zErrmsg);
}
}
return SQLITE_ERROR;
}
@@ -388,12 +393,14 @@ static int sqlite3LoadExtension(
sqlite3OsDlSym(pVfs, handle, zProc);
if( xInit==0 ){
if( pzErrMsg ){
char zErr[256];
zErr[sizeof(zErr)-1] = '\0';
sqlite3_snprintf(sizeof(zErr)-1, zErr,
"no entry point [%s] in shared library [%s]", zProc,zFile);
sqlite3OsDlError(pVfs, sizeof(zErr)-1, zErr);
*pzErrMsg = sqlite3DbStrDup(0, zErr);
zErrmsg = sqlite3StackAllocZero(db, nMsg);
if( zErrmsg ){
sqlite3_snprintf(nMsg, zErrmsg,
"no entry point [%s] in shared library [%s]", zProc,zFile);
sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
*pzErrMsg = sqlite3DbStrDup(0, zErrmsg);
sqlite3StackFree(db, zErrmsg);
}
sqlite3OsDlClose(pVfs, handle);
}
return SQLITE_ERROR;
@@ -429,6 +436,7 @@ int sqlite3_load_extension(
int rc;
sqlite3_mutex_enter(db->mutex);
rc = sqlite3LoadExtension(db, zFile, zProc, pzErrMsg);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
}
@@ -565,20 +573,21 @@ void sqlite3_reset_auto_extension(void){
/*
** Load all automatic extensions.
**
** If anything goes wrong, set an error in the database connection.
*/
int sqlite3AutoLoadExtensions(sqlite3 *db){
void sqlite3AutoLoadExtensions(sqlite3 *db){
int i;
int go = 1;
int rc = SQLITE_OK;
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
wsdAutoextInit;
if( wsdAutoext.nExt==0 ){
/* Common case: early out without every having to acquire a mutex */
return SQLITE_OK;
return;
}
for(i=0; go; i++){
char *zErrmsg = 0;
char *zErrmsg;
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
@@ -591,13 +600,12 @@ int sqlite3AutoLoadExtensions(sqlite3 *db){
wsdAutoext.aExt[i];
}
sqlite3_mutex_leave(mutex);
zErrmsg = 0;
if( xInit && xInit(db, &zErrmsg, &sqlite3Apis) ){
sqlite3Error(db, SQLITE_ERROR,
"automatic extension loading failed: %s", zErrmsg);
go = 0;
rc = SQLITE_ERROR;
sqlite3_free(zErrmsg);
}
sqlite3_free(zErrmsg);
}
return rc;
}
+92 -28
View File
@@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.548 2009/05/06 19:03:14 drh Exp $
** $Id: main.c,v 1.562 2009/07/20 11:32:03 drh Exp $
*/
#include "sqliteInt.h"
@@ -310,7 +310,7 @@ int sqlite3_config(int op, ...){
break;
}
case SQLITE_CONFIG_PAGECACHE: {
/* Designate a buffer for scratch memory space */
/* Designate a buffer for page cache memory space */
sqlite3GlobalConfig.pPage = va_arg(ap, void*);
sqlite3GlobalConfig.szPage = va_arg(ap, int);
sqlite3GlobalConfig.nPage = va_arg(ap, int);
@@ -318,7 +318,7 @@ int sqlite3_config(int op, ...){
}
case SQLITE_CONFIG_PCACHE: {
/* Specify an alternative malloc implementation */
/* Specify an alternative page cache implementation */
sqlite3GlobalConfig.pcache = *va_arg(ap, sqlite3_pcache_methods*);
break;
}
@@ -349,7 +349,6 @@ int sqlite3_config(int op, ...){
/* The heap pointer is not NULL, then install one of the
** mem5.c/mem3.c methods. If neither ENABLE_MEMSYS3 nor
** ENABLE_MEMSYS5 is defined, return an error.
** the default case and return an error.
*/
#ifdef SQLITE_ENABLE_MEMSYS3
sqlite3GlobalConfig.m = *sqlite3MemGetMemsys3();
@@ -584,13 +583,6 @@ int sqlite3_close(sqlite3 *db){
}
sqlite3_mutex_enter(db->mutex);
#ifdef SQLITE_SSE
{
extern void sqlite3SseCleanup(sqlite3*);
sqlite3SseCleanup(db);
}
#endif
sqlite3ResetInternalSchema(db, 0);
/* If a transaction is open, the ResetInternalSchema() call above
@@ -757,7 +749,7 @@ const char *sqlite3ErrStr(int rc){
/* SQLITE_PROTOCOL */ 0,
/* SQLITE_EMPTY */ "table contains no data",
/* SQLITE_SCHEMA */ "database schema has changed",
/* SQLITE_TOOBIG */ "String or BLOB exceeded size limit",
/* SQLITE_TOOBIG */ "string or blob too big",
/* SQLITE_CONSTRAINT */ "constraint failed",
/* SQLITE_MISMATCH */ "datatype mismatch",
/* SQLITE_MISUSE */ "library routine called out of sequence",
@@ -931,8 +923,7 @@ int sqlite3CreateFunc(
(!xFunc && (!xFinal && xStep)) ||
(nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) ||
(255<(nName = sqlite3Strlen30( zFunctionName))) ){
sqlite3Error(db, SQLITE_ERROR, "bad parameters");
return SQLITE_ERROR;
return SQLITE_MISUSE;
}
#ifndef SQLITE_OMIT_UTF16
@@ -1193,7 +1184,8 @@ int sqlite3TempInMemory(const sqlite3 *db){
#endif
#if SQLITE_TEMP_STORE==3
return 1;
#else
#endif
#if SQLITE_TEMP_STORE<1 || SQLITE_TEMP_STORE>3
return 0;
#endif
}
@@ -1362,7 +1354,7 @@ static int createCollation(
){
CollSeq *pColl;
int enc2;
int nName;
int nName = sqlite3Strlen30(zName);
assert( sqlite3_mutex_held(db->mutex) );
@@ -1384,8 +1376,7 @@ static int createCollation(
** sequence. If so, and there are active VMs, return busy. If there
** are no active VMs, invalidate any pre-compiled statements.
*/
nName = sqlite3Strlen30(zName);
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, nName, 0);
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 0);
if( pColl && pColl->xCmp ){
if( db->activeVdbeCnt ){
sqlite3Error(db, SQLITE_BUSY,
@@ -1415,7 +1406,7 @@ static int createCollation(
}
}
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, nName, 1);
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 1);
if( pColl ){
pColl->xCmp = xCompare;
pColl->pUser = pCtx;
@@ -1537,8 +1528,16 @@ static int openDatabase(
isThreadsafe = sqlite3GlobalConfig.bFullMutex;
}
/* Remove harmful bits from the flags parameter */
/* Remove harmful bits from the flags parameter
**
** The SQLITE_OPEN_NOMUTEX and SQLITE_OPEN_FULLMUTEX flags were
** dealt with in the previous code block. Besides these, the only
** valid input flags for sqlite3_open_v2() are SQLITE_OPEN_READONLY,
** SQLITE_OPEN_READWRITE, and SQLITE_OPEN_CREATE. Silently mask
** off all other flags.
*/
flags &= ~( SQLITE_OPEN_DELETEONCLOSE |
SQLITE_OPEN_EXCLUSIVE |
SQLITE_OPEN_MAIN_DB |
SQLITE_OPEN_TEMP_DB |
SQLITE_OPEN_TRANSIENT_DB |
@@ -1563,7 +1562,6 @@ static int openDatabase(
}
sqlite3_mutex_enter(db->mutex);
db->errMask = 0xff;
db->priorNewRowid = 0;
db->nDb = 2;
db->magic = SQLITE_MAGIC_BUSY;
db->aDb = db->aDbStatic;
@@ -1604,7 +1602,7 @@ static int openDatabase(
if( db->mallocFailed ){
goto opendb_out;
}
db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0);
db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 0);
assert( db->pDfltColl!=0 );
/* Also add a UTF-8 case-insensitive collation sequence. */
@@ -1612,7 +1610,7 @@ static int openDatabase(
/* Set flags on the built-in collating sequences */
db->pDfltColl->type = SQLITE_COLL_BINARY;
pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "NOCASE", 6, 0);
pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "NOCASE", 0);
if( pColl ){
pColl->type = SQLITE_COLL_NOCASE;
}
@@ -1638,10 +1636,8 @@ static int openDatabase(
*/
db->aDb[0].zName = "main";
db->aDb[0].safety_level = 3;
#ifndef SQLITE_OMIT_TEMPDB
db->aDb[1].zName = "temp";
db->aDb[1].safety_level = 1;
#endif
db->magic = SQLITE_MAGIC_OPEN;
if( db->mallocFailed ){
@@ -1658,8 +1654,9 @@ static int openDatabase(
/* Load automatic extensions - extensions that have been registered
** using the sqlite3_automatic_extension() API.
*/
(void)sqlite3AutoLoadExtensions(db);
if( sqlite3_errcode(db)!=SQLITE_OK ){
sqlite3AutoLoadExtensions(db);
rc = sqlite3_errcode(db);
if( rc!=SQLITE_OK ){
goto opendb_out;
}
@@ -2177,7 +2174,7 @@ int sqlite3_test_control(int op, ...){
}
/*
** sqlite3_test_control(PENDING_BYTE, unsigned int X)
** sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE, unsigned int X)
**
** Set the PENDING byte to the value in the argument, if X>0.
** Make no changes if X==0. Return the value of the pending byte
@@ -2194,6 +2191,73 @@ int sqlite3_test_control(int op, ...){
if( newVal ) sqlite3PendingByte = newVal;
break;
}
/*
** sqlite3_test_control(SQLITE_TESTCTRL_ASSERT, int X)
**
** This action provides a run-time test to see whether or not
** assert() was enabled at compile-time. If X is true and assert()
** is enabled, then the return value is true. If X is true and
** assert() is disabled, then the return value is zero. If X is
** false and assert() is enabled, then the assertion fires and the
** process aborts. If X is false and assert() is disabled, then the
** return value is zero.
*/
case SQLITE_TESTCTRL_ASSERT: {
volatile int x = 0;
assert( (x = va_arg(ap,int))!=0 );
rc = x;
break;
}
/*
** sqlite3_test_control(SQLITE_TESTCTRL_ALWAYS, int X)
**
** This action provides a run-time test to see how the ALWAYS and
** NEVER macros were defined at compile-time.
**
** The return value is ALWAYS(X).
**
** The recommended test is X==2. If the return value is 2, that means
** ALWAYS() and NEVER() are both no-op pass-through macros, which is the
** default setting. If the return value is 1, then ALWAYS() is either
** hard-coded to true or else it asserts if its argument is false.
** The first behavior (hard-coded to true) is the case if
** SQLITE_TESTCTRL_ASSERT shows that assert() is disabled and the second
** behavior (assert if the argument to ALWAYS() is false) is the case if
** SQLITE_TESTCTRL_ASSERT shows that assert() is enabled.
**
** The run-time test procedure might look something like this:
**
** if( sqlite3_test_control(SQLITE_TESTCTRL_ALWAYS, 2)==2 ){
** // ALWAYS() and NEVER() are no-op pass-through macros
** }else if( sqlite3_test_control(SQLITE_TESTCTRL_ASSERT, 1) ){
** // ALWAYS(x) asserts that x is true. NEVER(x) asserts x is false.
** }else{
** // ALWAYS(x) is a constant 1. NEVER(x) is a constant 0.
** }
*/
case SQLITE_TESTCTRL_ALWAYS: {
int x = va_arg(ap,int);
rc = ALWAYS(x);
break;
}
/* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N)
**
** Set the nReserve size to N for the main database on the database
** connection db.
*/
case SQLITE_TESTCTRL_RESERVE: {
sqlite3 *db = va_arg(ap, sqlite3*);
int x = va_arg(ap,int);
sqlite3_mutex_enter(db->mutex);
sqlite3BtreeSetPageSize(db->aDb[0].pBt, 0, x, 0);
sqlite3_mutex_leave(db->mutex);
break;
}
}
va_end(ap);
#endif /* SQLITE_OMIT_BUILTIN_TEST */
+19 -22
View File
@@ -12,7 +12,7 @@
**
** Memory allocation functions used throughout sqlite.
**
** $Id: malloc.c,v 1.62 2009/05/03 20:23:54 drh Exp $
** $Id: malloc.c,v 1.66 2009/07/17 11:44:07 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
@@ -88,13 +88,11 @@ static SQLITE_WSD struct Mem0Global {
** The alarm callback and its arguments. The mem0.mutex lock will
** be held while the callback is running. Recursive calls into
** the memory subsystem are allowed, but no new callbacks will be
** issued. The alarmBusy variable is set to prevent recursive
** callbacks.
** issued.
*/
sqlite3_int64 alarmThreshold;
void (*alarmCallback)(void*, sqlite3_int64,int);
void *alarmArg;
int alarmBusy;
/*
** Pointers to the end of sqlite3GlobalConfig.pScratch and
@@ -103,7 +101,7 @@ static SQLITE_WSD struct Mem0Global {
*/
u32 *aScratchFree;
u32 *aPageFree;
} mem0 = { 62560955, 0, 0, 0, 0, 0, 0, 0, 0 };
} mem0 = { 0, 0, 0, 0, 0, 0, 0, 0 };
#define mem0 GLOBAL(struct Mem0Global, mem0)
@@ -220,15 +218,16 @@ static void sqlite3MallocAlarm(int nByte){
void (*xCallback)(void*,sqlite3_int64,int);
sqlite3_int64 nowUsed;
void *pArg;
if( mem0.alarmCallback==0 || mem0.alarmBusy ) return;
mem0.alarmBusy = 1;
if( mem0.alarmCallback==0 ) return;
xCallback = mem0.alarmCallback;
nowUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
pArg = mem0.alarmArg;
mem0.alarmCallback = 0;
sqlite3_mutex_leave(mem0.mutex);
xCallback(pArg, nowUsed, nByte);
sqlite3_mutex_enter(mem0.mutex);
mem0.alarmBusy = 0;
mem0.alarmCallback = xCallback;
mem0.alarmArg = pArg;
}
/*
@@ -266,15 +265,12 @@ static int mallocWithAlarm(int n, void **pp){
*/
void *sqlite3Malloc(int n){
void *p;
if( n<=0 || NEVER(n>=0x7fffff00) ){
/* The NEVER(n>=0x7fffff00) term is added out of paranoia. We want to make
** absolutely sure that there is nothing within SQLite that can cause a
** memory allocation of a number of bytes which is near the maximum signed
** integer value and thus cause an integer overflow inside of the xMalloc()
** implementation. The n>=0x7fffff00 gives us 255 bytes of headroom. The
** test should never be true because SQLITE_MAX_LENGTH should be much
** less than 0x7fffff00 and it should catch large memory allocations
** before they reach this point. */
if( n<=0 || n>=0x7fffff00 ){
/* A memory allocation of a number of bytes which is near the maximum
** signed integer value might cause an integer overflow inside of the
** xMalloc(). Hence we limit the maximum size to 0x7fffff00, giving
** 255 bytes of overhead. SQLite itself will never use anything near
** this amount. The only way to reach the limit is with sqlite3_malloc() */
p = 0;
}else if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
@@ -427,9 +423,7 @@ int sqlite3MallocSize(void *p){
}
int sqlite3DbMallocSize(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) );
if( p==0 ){
return 0;
}else if( isLookaside(db, p) ){
if( isLookaside(db, p) ){
return db->lookaside.sz;
}else{
return sqlite3GlobalConfig.m.xSize(p);
@@ -476,11 +470,14 @@ void *sqlite3Realloc(void *pOld, int nBytes){
if( pOld==0 ){
return sqlite3Malloc(nBytes);
}
if( nBytes<=0 || NEVER(nBytes>=0x7fffff00) ){
/* The NEVER(...) term is explained in comments on sqlite3Malloc() */
if( nBytes<=0 ){
sqlite3_free(pOld);
return 0;
}
if( nBytes>=0x7fffff00 ){
/* The 0x7ffff00 limit term is explained in comments on sqlite3Malloc() */
return 0;
}
nOld = sqlite3MallocSize(pOld);
if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
+9 -25
View File
@@ -14,7 +14,7 @@
** This file contains code that is common across all mutex implementations.
**
** $Id: mutex.c,v 1.30 2009/02/17 16:29:11 danielk1977 Exp $
** $Id: mutex.c,v 1.31 2009/07/16 18:21:18 drh Exp $
*/
#include "sqliteInt.h"
@@ -30,32 +30,16 @@ int sqlite3MutexInit(void){
** install a mutex implementation via sqlite3_config() prior to
** sqlite3_initialize() being called. This block copies pointers to
** the default implementation into the sqlite3GlobalConfig structure.
**
** The danger is that although sqlite3_config() is not a threadsafe
** API, sqlite3_initialize() is, and so multiple threads may be
** attempting to run this function simultaneously. To guard write
** access to the sqlite3GlobalConfig structure, the 'MASTER' static mutex
** is obtained before modifying it.
*/
sqlite3_mutex_methods *p = sqlite3DefaultMutex();
sqlite3_mutex *pMaster = 0;
rc = p->xMutexInit();
if( rc==SQLITE_OK ){
pMaster = p->xMutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
assert(pMaster);
p->xMutexEnter(pMaster);
assert( sqlite3GlobalConfig.mutex.xMutexAlloc==0
|| sqlite3GlobalConfig.mutex.xMutexAlloc==p->xMutexAlloc
);
if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
sqlite3GlobalConfig.mutex = *p;
}
p->xMutexLeave(pMaster);
}
}else{
rc = sqlite3GlobalConfig.mutex.xMutexInit();
sqlite3_mutex_methods *pFrom = sqlite3DefaultMutex();
sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));
memcpy(&pTo->xMutexFree, &pFrom->xMutexFree,
sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree));
pTo->xMutexAlloc = pFrom->xMutexAlloc;
}
rc = sqlite3GlobalConfig.mutex.xMutexInit();
}
return rc;
+45 -20
View File
@@ -11,7 +11,7 @@
*************************************************************************
** This file contains the C functions that implement mutexes for win32
**
** $Id: mutex_w32.c,v 1.15 2009/01/30 16:09:23 shane Exp $
** $Id: mutex_w32.c,v 1.18 2009/08/10 03:23:21 shane Exp $
*/
#include "sqliteInt.h"
@@ -82,8 +82,46 @@ static int winMutexNotheld(sqlite3_mutex *p){
/*
** Initialize and deinitialize the mutex subsystem.
*/
static int winMutexInit(void){ return SQLITE_OK; }
static int winMutexEnd(void){ return SQLITE_OK; }
static sqlite3_mutex winMutex_staticMutexes[6];
static int winMutex_isInit = 0;
/* As winMutexInit() and winMutexEnd() are called as part
** of the sqlite3_initialize and sqlite3_shutdown()
** processing, the "interlocked" magic is probably not
** strictly necessary.
*/
static long winMutex_lock = 0;
static int winMutexInit(void){
/* The first to increment to 1 does actual initialization */
if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){
int i;
for(i=0; i<sizeof(winMutex_staticMutexes)/sizeof(winMutex_staticMutexes[0]); i++){
InitializeCriticalSection(&winMutex_staticMutexes[i].mutex);
}
winMutex_isInit = 1;
}else{
/* Someone else is in the process of initing the static mutexes */
while( !winMutex_isInit ){
Sleep(1);
}
}
return SQLITE_OK;
}
static int winMutexEnd(void){
/* The first to decrement to 0 does actual shutdown
** (which should be the last to shutdown.) */
if( InterlockedCompareExchange(&winMutex_lock, 0, 1)==1 ){
if( winMutex_isInit==1 ){
int i;
for(i=0; i<sizeof(winMutex_staticMutexes)/sizeof(winMutex_staticMutexes[0]); i++){
DeleteCriticalSection(&winMutex_staticMutexes[i].mutex);
}
winMutex_isInit = 0;
}
}
return SQLITE_OK;
}
/*
** The sqlite3_mutex_alloc() routine allocates a new
@@ -131,30 +169,17 @@ static sqlite3_mutex *winMutexAlloc(int iType){
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
if( p ){
p->id = iType;
InitializeCriticalSection(&p->mutex);
}
break;
}
default: {
static sqlite3_mutex staticMutexes[6];
static int isInit = 0;
while( !isInit ){
static long lock = 0;
if( InterlockedIncrement(&lock)==1 ){
int i;
for(i=0; i<sizeof(staticMutexes)/sizeof(staticMutexes[0]); i++){
InitializeCriticalSection(&staticMutexes[i].mutex);
}
isInit = 1;
}else{
Sleep(1);
}
}
assert( winMutex_isInit==1 );
assert( iType-2 >= 0 );
assert( iType-2 < sizeof(staticMutexes)/sizeof(staticMutexes[0]) );
p = &staticMutexes[iType-2];
assert( iType-2 < sizeof(winMutex_staticMutexes)/sizeof(winMutex_staticMutexes[0]) );
p = &winMutex_staticMutexes[iType-2];
p->id = iType;
break;
}
+14 -14
View File
@@ -13,7 +13,7 @@
** This file contains OS interface code that is common to all
** architectures.
**
** $Id: os.c,v 1.126 2009/03/25 14:24:42 drh Exp $
** $Id: os.c,v 1.127 2009/07/27 11:41:21 danielk1977 Exp $
*/
#define _SQLITE_OS_C_ 1
#include "sqliteInt.h"
@@ -37,13 +37,13 @@
**
*/
#if defined(SQLITE_TEST) && (SQLITE_OS_WIN==0)
#define DO_OS_MALLOC_TEST if (1) { \
void *pTstAlloc = sqlite3Malloc(10); \
if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \
sqlite3_free(pTstAlloc); \
#define DO_OS_MALLOC_TEST(x) if (!x || !sqlite3IsMemJournal(x)) { \
void *pTstAlloc = sqlite3Malloc(10); \
if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \
sqlite3_free(pTstAlloc); \
}
#else
#define DO_OS_MALLOC_TEST
#define DO_OS_MALLOC_TEST(x)
#endif
/*
@@ -61,33 +61,33 @@ int sqlite3OsClose(sqlite3_file *pId){
return rc;
}
int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){
DO_OS_MALLOC_TEST;
DO_OS_MALLOC_TEST(id);
return id->pMethods->xRead(id, pBuf, amt, offset);
}
int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){
DO_OS_MALLOC_TEST;
DO_OS_MALLOC_TEST(id);
return id->pMethods->xWrite(id, pBuf, amt, offset);
}
int sqlite3OsTruncate(sqlite3_file *id, i64 size){
return id->pMethods->xTruncate(id, size);
}
int sqlite3OsSync(sqlite3_file *id, int flags){
DO_OS_MALLOC_TEST;
DO_OS_MALLOC_TEST(id);
return id->pMethods->xSync(id, flags);
}
int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
DO_OS_MALLOC_TEST;
DO_OS_MALLOC_TEST(id);
return id->pMethods->xFileSize(id, pSize);
}
int sqlite3OsLock(sqlite3_file *id, int lockType){
DO_OS_MALLOC_TEST;
DO_OS_MALLOC_TEST(id);
return id->pMethods->xLock(id, lockType);
}
int sqlite3OsUnlock(sqlite3_file *id, int lockType){
return id->pMethods->xUnlock(id, lockType);
}
int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){
DO_OS_MALLOC_TEST;
DO_OS_MALLOC_TEST(id);
return id->pMethods->xCheckReservedLock(id, pResOut);
}
int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
@@ -113,7 +113,7 @@ int sqlite3OsOpen(
int *pFlagsOut
){
int rc;
DO_OS_MALLOC_TEST;
DO_OS_MALLOC_TEST(0);
rc = pVfs->xOpen(pVfs, zPath, pFile, flags, pFlagsOut);
assert( rc==SQLITE_OK || pFile->pMethods==0 );
return rc;
@@ -127,7 +127,7 @@ int sqlite3OsAccess(
int flags,
int *pResOut
){
DO_OS_MALLOC_TEST;
DO_OS_MALLOC_TEST(0);
return pVfs->xAccess(pVfs, zPath, flags, pResOut);
}
int sqlite3OsFullPathname(
+14 -8
View File
@@ -43,7 +43,7 @@
** * Definitions of sqlite3_vfs objects for all locking methods
** plus implementations of sqlite3_os_init() and sqlite3_os_end().
**
** $Id: os_unix.c,v 1.250 2009/04/07 05:35:04 chw Exp $
** $Id: os_unix.c,v 1.254 2009/07/03 12:57:58 drh Exp $
*/
#include "sqliteInt.h"
#if SQLITE_OS_UNIX /* This file is used on unix only */
@@ -839,13 +839,14 @@ static void testThreadLockingBehavior(int fd_orig){
d.fd = fd;
d.lock = l;
d.lock.l_type = F_WRLCK;
pthread_create(&t, 0, threadLockingTest, &d);
pthread_join(t, 0);
if( pthread_create(&t, 0, threadLockingTest, &d)==0 ){
pthread_join(t, 0);
}
close(fd);
if( d.result!=0 ) return;
threadsOverrideEachOthersLocks = (d.lock.l_type==F_UNLCK);
}
#endif /* SQLITE_THERADSAFE && defined(__linux__) */
#endif /* SQLITE_THREADSAFE && defined(__linux__) */
/*
** Release a unixLockInfo structure previously allocated by findLockInfo().
@@ -911,7 +912,7 @@ static int findLockInfo(
struct unixLockKey lockKey; /* Lookup key for the unixLockInfo structure */
struct unixFileId fileId; /* Lookup key for the unixOpenCnt struct */
struct stat statbuf; /* Low-level file information */
struct unixLockInfo *pLock; /* Candidate unixLockInfo object */
struct unixLockInfo *pLock = 0;/* Candidate unixLockInfo object */
struct unixOpenCnt *pOpen; /* Candidate unixOpenCnt object */
/* Get low-level information about the file that we can used to
@@ -1815,7 +1816,8 @@ static int dotlockUnlock(sqlite3_file *id, int locktype) {
/* To fully unlock the database, delete the lock file */
assert( locktype==NO_LOCK );
if( unlink(zLockFile) ){
int rc, tErrno = errno;
int rc = 0;
int tErrno = errno;
if( ENOENT != tErrno ){
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
}
@@ -4065,7 +4067,11 @@ int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */
** return 0. Return 1 if the time and date cannot be found.
*/
static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
#if defined(NO_GETTOD)
#if defined(SQLITE_OMIT_FLOATING_POINT)
time_t t;
time(&t);
*prNow = (((sqlite3_int64)t)/8640 + 24405875)/10;
#elif defined(NO_GETTOD)
time_t t;
time(&t);
*prNow = t/86400.0 + 2440587.5;
@@ -4427,8 +4433,8 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
len = strlcat(lPath, "sqliteplocks", maxLen);
if( mkdir(lPath, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){
/* if mkdir fails, handle as lock file creation failure */
int err = errno;
# ifdef SQLITE_DEBUG
int err = errno;
if( err!=EEXIST ){
fprintf(stderr, "proxyGetLockPath: mkdir(%s,0%o) error %d %s\n", lPath,
SQLITE_DEFAULT_PROXYDIR_PERMISSIONS, err, strerror(err));
+4 -4
View File
@@ -12,7 +12,7 @@
**
** This file contains code that is specific to windows.
**
** $Id: os_win.c,v 1.156 2009/04/23 19:08:33 shane Exp $
** $Id: os_win.c,v 1.157 2009/08/05 04:08:30 shane Exp $
*/
#include "sqliteInt.h"
#if SQLITE_OS_WIN /* This file is used for windows only */
@@ -483,9 +483,8 @@ static BOOL winceLockFile(
}
/* Want a read-only lock? */
else if ((dwFileOffsetLow >= SHARED_FIRST &&
dwFileOffsetLow < SHARED_FIRST + SHARED_SIZE) &&
nNumberOfBytesToLockLow == 1){
else if (dwFileOffsetLow == SHARED_FIRST &&
nNumberOfBytesToLockLow == 1){
if (pFile->shared->bExclusive == 0){
pFile->local.nReaders ++;
if (pFile->local.nReaders == 1){
@@ -504,6 +503,7 @@ static BOOL winceLockFile(
bReturn = TRUE;
}
}
/* Want a reserved lock? */
else if (dwFileOffsetLow == RESERVED_BYTE && nNumberOfBytesToLockLow == 1){
if (pFile->shared->bReserved == 0) {
+366 -307
View File
File diff suppressed because it is too large Load Diff
+12 -9
View File
@@ -13,7 +13,7 @@
** subsystem. The page cache subsystem reads and writes a file a page
** at a time and provides a journal for rollback.
**
** @(#) $Id: pager.h,v 1.101 2009/04/30 09:10:38 danielk1977 Exp $
** @(#) $Id: pager.h,v 1.104 2009/07/24 19:01:19 drh Exp $
*/
#ifndef _PAGER_H_
@@ -86,14 +86,21 @@ typedef struct PgHdr DbPage;
*/
/* Open and close a Pager connection. */
int sqlite3PagerOpen(sqlite3_vfs *, Pager **ppPager, const char*, int,int,int);
int sqlite3PagerOpen(
sqlite3_vfs*,
Pager **ppPager,
const char*,
int,
int,
int,
void(*)(DbPage*)
);
int sqlite3PagerClose(Pager *pPager);
int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
/* Functions used to configure a Pager object. */
void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*));
int sqlite3PagerSetPagesize(Pager*, u16*);
int sqlite3PagerSetPagesize(Pager*, u16*, int);
int sqlite3PagerMaxPageCount(Pager*, int);
void sqlite3PagerSetCachesize(Pager*, int);
void sqlite3PagerSetSafetyLevel(Pager*,int,int);
@@ -126,6 +133,7 @@ int sqlite3PagerCommitPhaseTwo(Pager*);
int sqlite3PagerRollback(Pager*);
int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
int sqlite3PagerSharedLock(Pager *pPager);
/* Functions used to query pager state and configuration. */
u8 sqlite3PagerIsreadonly(Pager*);
@@ -141,11 +149,6 @@ int sqlite3PagerIsMemdb(Pager*);
/* Functions used to truncate the database file. */
void sqlite3PagerTruncateImage(Pager*,Pgno);
/* Used by encryption extensions. */
#ifdef SQLITE_HAS_CODEC
void sqlite3PagerSetCodec(Pager*,void*(*)(void*,void*,Pgno,int),void*);
#endif
/* Functions to support testing and debugging. */
#if !defined(NDEBUG) || defined(SQLITE_TEST)
Pgno sqlite3PagerPagenumber(DbPage*);
+333 -208
View File
@@ -14,7 +14,7 @@
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.275 2009/05/01 21:13:37 drh Exp $
** @(#) $Id: parse.y,v 1.286 2009/08/10 03:57:58 shane Exp $
*/
// All token codes are small integers with #defines that begin with "TK_"
@@ -53,6 +53,17 @@
%include {
#include "sqliteInt.h"
/*
** Disable all error recovery processing in the parser push-down
** automaton.
*/
#define YYNOERRORRECOVERY 1
/*
** Make yytestcase() the same as testcase()
*/
#define yytestcase(X) testcase(X)
/*
** An instance of this structure holds information about the
** LIMIT clause of a SELECT statement.
@@ -166,8 +177,6 @@ columnlist ::= column.
column(A) ::= columnid(X) type carglist. {
A.z = X.z;
A.n = (int)(pParse->sLastToken.z-X.z) + pParse->sLastToken.n;
A.quoted = 0;
A.dyn = 0;
}
columnid(A) ::= nm(X). {
sqlite3AddColumn(pParse,&X);
@@ -264,32 +273,35 @@ carglist ::= carglist carg.
carglist ::= .
carg ::= CONSTRAINT nm ccons.
carg ::= ccons.
ccons ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,X);}
ccons ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,X);}
ccons ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,X);}
ccons ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,&X);}
ccons ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,&X);}
ccons ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,&X);}
ccons ::= DEFAULT MINUS(A) term(X). {
Expr *p = sqlite3PExpr(pParse, TK_UMINUS, X, 0, 0);
sqlite3ExprSpan(p,&A,&X->span);
sqlite3AddDefaultValue(pParse,p);
ExprSpan v;
v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, X.pExpr, 0, 0);
v.zStart = A.z;
v.zEnd = X.zEnd;
sqlite3AddDefaultValue(pParse,&v);
}
ccons ::= DEFAULT id(X). {
Expr *p = sqlite3PExpr(pParse, TK_STRING, 0, 0, &X);
sqlite3AddDefaultValue(pParse,p);
ExprSpan v;
spanExpr(&v, pParse, TK_STRING, &X);
sqlite3AddDefaultValue(pParse,&v);
}
// In addition to the type name, we also care about the primary key and
// UNIQUE constraints.
//
ccons ::= NULL onconf.
ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);}
ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);}
ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I).
{sqlite3AddPrimaryKey(pParse,0,R,I,Z);}
ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0);}
ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X);}
{sqlite3AddPrimaryKey(pParse,0,R,I,Z);}
ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0);}
ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X.pExpr);}
ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
{sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);}
ccons ::= COLLATE ids(C). {sqlite3AddCollateType(pParse, &C);}
{sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);}
ccons ::= COLLATE ids(C). {sqlite3AddCollateType(pParse, &C);}
// The optional AUTOINCREMENT keyword
%type autoinc {int}
@@ -332,10 +344,11 @@ conslist ::= conslist tcons.
conslist ::= tcons.
tcons ::= CONSTRAINT nm.
tcons ::= PRIMARY KEY LP idxlist(X) autoinc(I) RP onconf(R).
{sqlite3AddPrimaryKey(pParse,X,R,I,0);}
{sqlite3AddPrimaryKey(pParse,X,R,I,0);}
tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
{sqlite3CreateIndex(pParse,0,0,0,X,R,0,0,0,0);}
tcons ::= CHECK LP expr(E) RP onconf. {sqlite3AddCheckConstraint(pParse,E);}
tcons ::= CHECK LP expr(E) RP onconf.
{sqlite3AddCheckConstraint(pParse,E.pExpr);}
tcons ::= FOREIGN KEY LP idxlist(FA) RP
REFERENCES nm(T) idxlist_opt(TA) refargs(R) defer_subclause_opt(D). {
sqlite3CreateForeignKey(pParse, FA, &T, TA, R);
@@ -349,12 +362,12 @@ defer_subclause_opt(A) ::= defer_subclause(X). {A = X;}
// default behavior when there is a constraint conflict.
//
%type onconf {int}
%type orconf {int}
%type orconf {u8}
%type resolvetype {int}
onconf(A) ::= . {A = OE_Default;}
onconf(A) ::= ON CONFLICT resolvetype(X). {A = X;}
orconf(A) ::= . {A = OE_Default;}
orconf(A) ::= OR resolvetype(X). {A = X;}
orconf(A) ::= OR resolvetype(X). {A = (u8)X;}
resolvetype(A) ::= raisetype(X). {A = X;}
resolvetype(A) ::= IGNORE. {A = OE_Ignore;}
resolvetype(A) ::= REPLACE. {A = OE_Replace;}
@@ -433,17 +446,19 @@ distinct(A) ::= . {A = 0;}
sclp(A) ::= selcollist(X) COMMA. {A = X;}
sclp(A) ::= . {A = 0;}
selcollist(A) ::= sclp(P) expr(X) as(Y). {
A = sqlite3ExprListAppend(pParse,P,X,Y.n?&Y:0);
A = sqlite3ExprListAppend(pParse, P, X.pExpr);
if( Y.n>0 ) sqlite3ExprListSetName(pParse, A, &Y, 1);
sqlite3ExprListSetSpan(pParse,A,&X);
}
selcollist(A) ::= sclp(P) STAR. {
Expr *p = sqlite3PExpr(pParse, TK_ALL, 0, 0, 0);
A = sqlite3ExprListAppend(pParse, P, p, 0);
Expr *p = sqlite3Expr(pParse->db, TK_ALL, 0);
A = sqlite3ExprListAppend(pParse, P, p);
}
selcollist(A) ::= sclp(P) nm(X) DOT STAR(Y). {
Expr *pRight = sqlite3PExpr(pParse, TK_ALL, 0, 0, &Y);
Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
A = sqlite3ExprListAppend(pParse,P, pDot, 0);
A = sqlite3ExprListAppend(pParse,P, pDot);
}
// An option "AS <id>" phrase that can follow one of the expressions that
@@ -475,7 +490,7 @@ from(A) ::= FROM seltablist(X). {
//
stl_prefix(A) ::= seltablist(X) joinop(Y). {
A = X;
if( A && A->nSrc>0 ) A->a[A->nSrc-1].jointype = (u8)Y;
if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].jointype = (u8)Y;
}
stl_prefix(A) ::= . {A = 0;}
seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) indexed_opt(I) on_opt(N) using_opt(U). {
@@ -530,7 +545,7 @@ joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN.
%type on_opt {Expr*}
%destructor on_opt {sqlite3ExprDelete(pParse->db, $$);}
on_opt(N) ::= ON expr(E). {N = E;}
on_opt(N) ::= ON expr(E). {N = E.pExpr;}
on_opt(N) ::= . {N = 0;}
// Note that this block abuses the Token type just a little. If there is
@@ -564,14 +579,14 @@ using_opt(U) ::= . {U = 0;}
orderby_opt(A) ::= . {A = 0;}
orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;}
sortlist(A) ::= sortlist(X) COMMA sortitem(Y) sortorder(Z). {
A = sqlite3ExprListAppend(pParse,X,Y,0);
A = sqlite3ExprListAppend(pParse,X,Y);
if( A ) A->a[A->nExpr-1].sortOrder = (u8)Z;
}
sortlist(A) ::= sortitem(Y) sortorder(Z). {
A = sqlite3ExprListAppend(pParse,0,Y,0);
if( A && A->a ) A->a[0].sortOrder = (u8)Z;
A = sqlite3ExprListAppend(pParse,0,Y);
if( A && ALWAYS(A->a) ) A->a[0].sortOrder = (u8)Z;
}
sortitem(A) ::= expr(X). {A = X;}
sortitem(A) ::= expr(X). {A = X.pExpr;}
%type sortorder {int}
@@ -587,7 +602,7 @@ groupby_opt(A) ::= GROUP BY nexprlist(X). {A = X;}
%type having_opt {Expr*}
%destructor having_opt {sqlite3ExprDelete(pParse->db, $$);}
having_opt(A) ::= . {A = 0;}
having_opt(A) ::= HAVING expr(X). {A = X;}
having_opt(A) ::= HAVING expr(X). {A = X.pExpr;}
%type limit_opt {struct LimitVal}
@@ -602,12 +617,12 @@ having_opt(A) ::= HAVING expr(X). {A = X;}
// sqlite3ExprDelete(pParse->db, $$.pLimit);
// sqlite3ExprDelete(pParse->db, $$.pOffset);
//}
limit_opt(A) ::= . {A.pLimit = 0; A.pOffset = 0;}
limit_opt(A) ::= LIMIT expr(X). {A.pLimit = X; A.pOffset = 0;}
limit_opt(A) ::= . {A.pLimit = 0; A.pOffset = 0;}
limit_opt(A) ::= LIMIT expr(X). {A.pLimit = X.pExpr; A.pOffset = 0;}
limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y).
{A.pLimit = X; A.pOffset = Y;}
{A.pLimit = X.pExpr; A.pOffset = Y.pExpr;}
limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y).
{A.pOffset = X; A.pLimit = Y;}
{A.pOffset = X.pExpr; A.pLimit = Y.pExpr;}
/////////////////////////// The DELETE statement /////////////////////////////
//
@@ -630,7 +645,7 @@ cmd ::= DELETE FROM fullname(X) indexed_opt(I) where_opt(W). {
%destructor where_opt {sqlite3ExprDelete(pParse->db, $$);}
where_opt(A) ::= . {A = 0;}
where_opt(A) ::= WHERE expr(X). {A = X;}
where_opt(A) ::= WHERE expr(X). {A = X.pExpr;}
////////////////////////// The UPDATE command ////////////////////////////////
//
@@ -653,10 +668,14 @@ cmd ::= UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) where_opt(W).
%type setlist {ExprList*}
%destructor setlist {sqlite3ExprListDelete(pParse->db, $$);}
setlist(A) ::= setlist(Z) COMMA nm(X) EQ expr(Y).
{A = sqlite3ExprListAppend(pParse,Z,Y,&X);}
setlist(A) ::= nm(X) EQ expr(Y).
{A = sqlite3ExprListAppend(pParse,0,Y,&X);}
setlist(A) ::= setlist(Z) COMMA nm(X) EQ expr(Y). {
A = sqlite3ExprListAppend(pParse, Z, Y.pExpr);
sqlite3ExprListSetName(pParse, A, &X, 1);
}
setlist(A) ::= nm(X) EQ expr(Y). {
A = sqlite3ExprListAppend(pParse, 0, Y.pExpr);
sqlite3ExprListSetName(pParse, A, &X, 1);
}
////////////////////////// The INSERT command /////////////////////////////////
//
@@ -668,7 +687,7 @@ cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) select(S).
cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) DEFAULT VALUES.
{sqlite3Insert(pParse, X, 0, 0, F, R);}
%type insert_cmd {int}
%type insert_cmd {u8}
insert_cmd(A) ::= INSERT orconf(R). {A = R;}
insert_cmd(A) ::= REPLACE. {A = OE_Replace;}
@@ -677,9 +696,9 @@ insert_cmd(A) ::= REPLACE. {A = OE_Replace;}
%destructor itemlist {sqlite3ExprListDelete(pParse->db, $$);}
itemlist(A) ::= itemlist(X) COMMA expr(Y).
{A = sqlite3ExprListAppend(pParse,X,Y,0);}
{A = sqlite3ExprListAppend(pParse,X,Y.pExpr);}
itemlist(A) ::= expr(X).
{A = sqlite3ExprListAppend(pParse,0,X,0);}
{A = sqlite3ExprListAppend(pParse,0,X.pExpr);}
%type inscollist_opt {IdList*}
%destructor inscollist_opt {sqlite3IdListDelete(pParse->db, $$);}
@@ -696,240 +715,319 @@ inscollist(A) ::= nm(Y).
/////////////////////////// Expression Processing /////////////////////////////
//
%type expr {Expr*}
%destructor expr {sqlite3ExprDelete(pParse->db, $$);}
%type term {Expr*}
%destructor term {sqlite3ExprDelete(pParse->db, $$);}
%type expr {ExprSpan}
%destructor expr {sqlite3ExprDelete(pParse->db, $$.pExpr);}
%type term {ExprSpan}
%destructor term {sqlite3ExprDelete(pParse->db, $$.pExpr);}
%include {
/* This is a utility routine used to set the ExprSpan.zStart and
** ExprSpan.zEnd values of pOut so that the span covers the complete
** range of text beginning with pStart and going to the end of pEnd.
*/
static void spanSet(ExprSpan *pOut, Token *pStart, Token *pEnd){
pOut->zStart = pStart->z;
pOut->zEnd = &pEnd->z[pEnd->n];
}
/* Construct a new Expr object from a single identifier. Use the
** new Expr to populate pOut. Set the span of pOut to be the identifier
** that created the expression.
*/
static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token *pValue){
pOut->pExpr = sqlite3PExpr(pParse, op, 0, 0, pValue);
pOut->zStart = pValue->z;
pOut->zEnd = &pValue->z[pValue->n];
}
}
expr(A) ::= term(X). {A = X;}
expr(A) ::= LP(B) expr(X) RP(E). {A = X; sqlite3ExprSpan(A,&B,&E); }
term(A) ::= NULL(X). {A = sqlite3PExpr(pParse, @X, 0, 0, &X);}
expr(A) ::= id(X). {A = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);}
expr(A) ::= JOIN_KW(X). {A = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);}
expr(A) ::= LP(B) expr(X) RP(E). {A.pExpr = X.pExpr; spanSet(&A,&B,&E);}
term(A) ::= NULL(X). {spanExpr(&A, pParse, @X, &X);}
expr(A) ::= id(X). {spanExpr(&A, pParse, TK_ID, &X);}
expr(A) ::= JOIN_KW(X). {spanExpr(&A, pParse, TK_ID, &X);}
expr(A) ::= nm(X) DOT nm(Y). {
Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
A = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
spanSet(&A,&X,&Y);
}
expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Z);
Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0);
A = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
spanSet(&A,&X,&Z);
}
term(A) ::= INTEGER|FLOAT|BLOB(X). {spanExpr(&A, pParse, @X, &X);}
term(A) ::= STRING(X). {spanExpr(&A, pParse, @X, &X);}
expr(A) ::= REGISTER(X). {
/* When doing a nested parse, one can include terms in an expression
** that look like this: #1 #2 ... These terms refer to registers
** in the virtual machine. #N is the N-th register. */
if( pParse->nested==0 ){
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &X);
A.pExpr = 0;
}else{
A.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &X);
if( A.pExpr ) sqlite3GetInt32(&X.z[1], &A.pExpr->iTable);
}
spanSet(&A, &X, &X);
}
term(A) ::= INTEGER|FLOAT|BLOB(X). {A = sqlite3PExpr(pParse, @X, 0, 0, &X);}
term(A) ::= STRING(X). {A = sqlite3PExpr(pParse, @X, 0, 0, &X);}
expr(A) ::= REGISTER(X). {A = sqlite3RegisterExpr(pParse, &X);}
expr(A) ::= VARIABLE(X). {
Token *pToken = &X;
Expr *pExpr = A = sqlite3PExpr(pParse, TK_VARIABLE, 0, 0, pToken);
sqlite3ExprAssignVarNumber(pParse, pExpr);
spanExpr(&A, pParse, TK_VARIABLE, &X);
sqlite3ExprAssignVarNumber(pParse, A.pExpr);
spanSet(&A, &X, &X);
}
expr(A) ::= expr(E) COLLATE ids(C). {
A = sqlite3ExprSetColl(pParse, E, &C);
A.pExpr = sqlite3ExprSetColl(pParse, E.pExpr, &C);
A.zStart = E.zStart;
A.zEnd = &C.z[C.n];
}
%ifndef SQLITE_OMIT_CAST
expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
A = sqlite3PExpr(pParse, TK_CAST, E, 0, &T);
sqlite3ExprSpan(A,&X,&Y);
A.pExpr = sqlite3PExpr(pParse, TK_CAST, E.pExpr, 0, &T);
spanSet(&A,&X,&Y);
}
%endif SQLITE_OMIT_CAST
expr(A) ::= ID(X) LP distinct(D) exprlist(Y) RP(E). {
if( Y && Y->nExpr>SQLITE_MAX_FUNCTION_ARG ){
if( Y && Y->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X);
}
A = sqlite3ExprFunction(pParse, Y, &X);
sqlite3ExprSpan(A,&X,&E);
if( D && A ){
A->flags |= EP_Distinct;
A.pExpr = sqlite3ExprFunction(pParse, Y, &X);
spanSet(&A,&X,&E);
if( D && A.pExpr ){
A.pExpr->flags |= EP_Distinct;
}
}
expr(A) ::= ID(X) LP STAR RP(E). {
A = sqlite3ExprFunction(pParse, 0, &X);
sqlite3ExprSpan(A,&X,&E);
A.pExpr = sqlite3ExprFunction(pParse, 0, &X);
spanSet(&A,&X,&E);
}
term(A) ::= CTIME_KW(OP). {
/* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are
** treated as functions that return constants */
A = sqlite3ExprFunction(pParse, 0,&OP);
if( A ){
A->op = TK_CONST_FUNC;
A->span = OP;
A.pExpr = sqlite3ExprFunction(pParse, 0,&OP);
if( A.pExpr ){
A.pExpr->op = TK_CONST_FUNC;
}
spanSet(&A, &OP, &OP);
}
%include {
/* This routine constructs a binary expression node out of two ExprSpan
** objects and uses the result to populate a new ExprSpan object.
*/
static void spanBinaryExpr(
ExprSpan *pOut, /* Write the result here */
Parse *pParse, /* The parsing context. Errors accumulate here */
int op, /* The binary operation */
ExprSpan *pLeft, /* The left operand */
ExprSpan *pRight /* The right operand */
){
pOut->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr, 0);
pOut->zStart = pLeft->zStart;
pOut->zEnd = pRight->zEnd;
}
}
expr(A) ::= expr(X) AND(OP) expr(Y). {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
expr(A) ::= expr(X) OR(OP) expr(Y). {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
expr(A) ::= expr(X) AND(OP) expr(Y). {spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
expr(A) ::= expr(X) OR(OP) expr(Y). {spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
expr(A) ::= expr(X) LT|GT|GE|LE(OP) expr(Y).
{A = sqlite3PExpr(pParse,@OP,X,Y,0);}
expr(A) ::= expr(X) EQ|NE(OP) expr(Y). {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
{spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
expr(A) ::= expr(X) EQ|NE(OP) expr(Y). {spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
expr(A) ::= expr(X) BITAND|BITOR|LSHIFT|RSHIFT(OP) expr(Y).
{A = sqlite3PExpr(pParse,@OP,X,Y,0);}
expr(A) ::= expr(X) PLUS|MINUS(OP) expr(Y).{A = sqlite3PExpr(pParse,@OP,X,Y,0);}
{spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
expr(A) ::= expr(X) PLUS|MINUS(OP) expr(Y).
{spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
expr(A) ::= expr(X) STAR|SLASH|REM(OP) expr(Y).
{A = sqlite3PExpr(pParse,@OP,X,Y,0);}
expr(A) ::= expr(X) CONCAT(OP) expr(Y). {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
{spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
expr(A) ::= expr(X) CONCAT(OP) expr(Y). {spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
%type likeop {struct LikeOp}
likeop(A) ::= LIKE_KW(X). {A.eOperator = X; A.not = 0;}
likeop(A) ::= NOT LIKE_KW(X). {A.eOperator = X; A.not = 1;}
likeop(A) ::= MATCH(X). {A.eOperator = X; A.not = 0;}
likeop(A) ::= NOT MATCH(X). {A.eOperator = X; A.not = 1;}
%type escape {Expr*}
%destructor escape {sqlite3ExprDelete(pParse->db, $$);}
%type escape {ExprSpan}
%destructor escape {sqlite3ExprDelete(pParse->db, $$.pExpr);}
escape(X) ::= ESCAPE expr(A). [ESCAPE] {X = A;}
escape(X) ::= . [ESCAPE] {X = 0;}
escape(X) ::= . [ESCAPE] {memset(&X,0,sizeof(X));}
expr(A) ::= expr(X) likeop(OP) expr(Y) escape(E). [LIKE_KW] {
ExprList *pList;
pList = sqlite3ExprListAppend(pParse,0, Y, 0);
pList = sqlite3ExprListAppend(pParse,pList, X, 0);
if( E ){
pList = sqlite3ExprListAppend(pParse,pList, E, 0);
pList = sqlite3ExprListAppend(pParse,0, Y.pExpr);
pList = sqlite3ExprListAppend(pParse,pList, X.pExpr);
if( E.pExpr ){
pList = sqlite3ExprListAppend(pParse,pList, E.pExpr);
}
A = sqlite3ExprFunction(pParse, pList, &OP.eOperator);
if( OP.not ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
sqlite3ExprSpan(A, &X->span, &Y->span);
if( A ) A->flags |= EP_InfixFunc;
A.pExpr = sqlite3ExprFunction(pParse, pList, &OP.eOperator);
if( OP.not ) A.pExpr = sqlite3PExpr(pParse, TK_NOT, A.pExpr, 0, 0);
A.zStart = X.zStart;
A.zEnd = Y.zEnd;
if( A.pExpr ) A.pExpr->flags |= EP_InfixFunc;
}
expr(A) ::= expr(X) ISNULL|NOTNULL(E). {
A = sqlite3PExpr(pParse, @E, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
%include {
/* Construct an expression node for a unary postfix operator
*/
static void spanUnaryPostfix(
ExprSpan *pOut, /* Write the new expression node here */
Parse *pParse, /* Parsing context to record errors */
int op, /* The operator */
ExprSpan *pOperand, /* The operand */
Token *pPostOp /* The operand token for setting the span */
){
pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
pOut->zStart = pOperand->zStart;
pOut->zEnd = &pPostOp->z[pPostOp->n];
}
}
expr(A) ::= expr(X) IS NULL(E). {
A = sqlite3PExpr(pParse, TK_ISNULL, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) NOT NULL(E). {
A = sqlite3PExpr(pParse, TK_NOTNULL, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) IS NOT NULL(E). {
A = sqlite3PExpr(pParse, TK_NOTNULL, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= NOT(B) expr(X). {
A = sqlite3PExpr(pParse, @B, X, 0, 0);
sqlite3ExprSpan(A,&B,&X->span);
}
expr(A) ::= BITNOT(B) expr(X). {
A = sqlite3PExpr(pParse, @B, X, 0, 0);
sqlite3ExprSpan(A,&B,&X->span);
}
expr(A) ::= MINUS(B) expr(X). [UMINUS] {
A = sqlite3PExpr(pParse, TK_UMINUS, X, 0, 0);
sqlite3ExprSpan(A,&B,&X->span);
}
expr(A) ::= PLUS(B) expr(X). [UPLUS] {
A = sqlite3PExpr(pParse, TK_UPLUS, X, 0, 0);
sqlite3ExprSpan(A,&B,&X->span);
expr(A) ::= expr(X) ISNULL|NOTNULL(E). {spanUnaryPostfix(&A,pParse,@E,&X,&E);}
expr(A) ::= expr(X) IS NULL(E). {spanUnaryPostfix(&A,pParse,TK_ISNULL,&X,&E);}
expr(A) ::= expr(X) NOT NULL(E). {spanUnaryPostfix(&A,pParse,TK_NOTNULL,&X,&E);}
expr(A) ::= expr(X) IS NOT NULL(E).
{spanUnaryPostfix(&A,pParse,TK_NOTNULL,&X,&E);}
%include {
/* Construct an expression node for a unary prefix operator
*/
static void spanUnaryPrefix(
ExprSpan *pOut, /* Write the new expression node here */
Parse *pParse, /* Parsing context to record errors */
int op, /* The operator */
ExprSpan *pOperand, /* The operand */
Token *pPreOp /* The operand token for setting the span */
){
pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
pOut->zStart = pPreOp->z;
pOut->zEnd = pOperand->zEnd;
}
}
expr(A) ::= NOT(B) expr(X). {spanUnaryPrefix(&A,pParse,@B,&X,&B);}
expr(A) ::= BITNOT(B) expr(X). {spanUnaryPrefix(&A,pParse,@B,&X,&B);}
expr(A) ::= MINUS(B) expr(X). [UMINUS]
{spanUnaryPrefix(&A,pParse,TK_UMINUS,&X,&B);}
expr(A) ::= PLUS(B) expr(X). [UPLUS]
{spanUnaryPrefix(&A,pParse,TK_UPLUS,&X,&B);}
%type between_op {int}
between_op(A) ::= BETWEEN. {A = 0;}
between_op(A) ::= NOT BETWEEN. {A = 1;}
expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
ExprList *pList = sqlite3ExprListAppend(pParse,0, X, 0);
pList = sqlite3ExprListAppend(pParse,pList, Y, 0);
A = sqlite3PExpr(pParse, TK_BETWEEN, W, 0, 0);
if( A ){
A->x.pList = pList;
ExprList *pList = sqlite3ExprListAppend(pParse,0, X.pExpr);
pList = sqlite3ExprListAppend(pParse,pList, Y.pExpr);
A.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, W.pExpr, 0, 0);
if( A.pExpr ){
A.pExpr->x.pList = pList;
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&W->span,&Y->span);
if( N ) A.pExpr = sqlite3PExpr(pParse, TK_NOT, A.pExpr, 0, 0);
A.zStart = W.zStart;
A.zEnd = Y.zEnd;
}
%ifndef SQLITE_OMIT_SUBQUERY
%type in_op {int}
in_op(A) ::= IN. {A = 0;}
in_op(A) ::= NOT IN. {A = 1;}
expr(A) ::= expr(X) in_op(N) LP exprlist(Y) RP(E). [IN] {
A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
if( A ){
A->x.pList = Y;
sqlite3ExprSetHeight(pParse, A);
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
if( A.pExpr ){
A.pExpr->x.pList = Y;
sqlite3ExprSetHeight(pParse, A.pExpr);
}else{
sqlite3ExprListDelete(pParse->db, Y);
}
if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
if( N ) A.pExpr = sqlite3PExpr(pParse, TK_NOT, A.pExpr, 0, 0);
A.zStart = X.zStart;
A.zEnd = &E.z[E.n];
}
expr(A) ::= LP(B) select(X) RP(E). {
A = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
if( A ){
A->x.pSelect = X;
ExprSetProperty(A, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, A);
A.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
if( A.pExpr ){
A.pExpr->x.pSelect = X;
ExprSetProperty(A.pExpr, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, A.pExpr);
}else{
sqlite3SelectDelete(pParse->db, X);
}
sqlite3ExprSpan(A,&B,&E);
A.zStart = B.z;
A.zEnd = &E.z[E.n];
}
expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] {
A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
if( A ){
A->x.pSelect = Y;
ExprSetProperty(A, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, A);
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
if( A.pExpr ){
A.pExpr->x.pSelect = Y;
ExprSetProperty(A.pExpr, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, A.pExpr);
}else{
sqlite3SelectDelete(pParse->db, Y);
}
if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
if( N ) A.pExpr = sqlite3PExpr(pParse, TK_NOT, A.pExpr, 0, 0);
A.zStart = X.zStart;
A.zEnd = &E.z[E.n];
}
expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] {
SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&Y,&Z);
A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
if( A ){
A->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
ExprSetProperty(A, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, A);
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
if( A.pExpr ){
A.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
ExprSetProperty(A.pExpr, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, A.pExpr);
}else{
sqlite3SrcListDelete(pParse->db, pSrc);
}
if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,Z.z?&Z:&Y);
if( N ) A.pExpr = sqlite3PExpr(pParse, TK_NOT, A.pExpr, 0, 0);
A.zStart = X.zStart;
A.zEnd = Z.z ? &Z.z[Z.n] : &Y.z[Y.n];
}
expr(A) ::= EXISTS(B) LP select(Y) RP(E). {
Expr *p = A = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
Expr *p = A.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
if( p ){
p->x.pSelect = Y;
ExprSetProperty(A, EP_xIsSelect);
sqlite3ExprSpan(p,&B,&E);
sqlite3ExprSetHeight(pParse, A);
ExprSetProperty(p, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, p);
}else{
sqlite3SelectDelete(pParse->db, Y);
}
A.zStart = B.z;
A.zEnd = &E.z[E.n];
}
%endif SQLITE_OMIT_SUBQUERY
/* CASE expressions */
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
A = sqlite3PExpr(pParse, TK_CASE, X, Z, 0);
if( A ){
A->x.pList = Y;
sqlite3ExprSetHeight(pParse, A);
A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, Z, 0);
if( A.pExpr ){
A.pExpr->x.pList = Y;
sqlite3ExprSetHeight(pParse, A.pExpr);
}else{
sqlite3ExprListDelete(pParse->db, Y);
}
sqlite3ExprSpan(A, &C, &E);
A.zStart = C.z;
A.zEnd = &E.z[E.n];
}
%type case_exprlist {ExprList*}
%destructor case_exprlist {sqlite3ExprListDelete(pParse->db, $$);}
case_exprlist(A) ::= case_exprlist(X) WHEN expr(Y) THEN expr(Z). {
A = sqlite3ExprListAppend(pParse,X, Y, 0);
A = sqlite3ExprListAppend(pParse,A, Z, 0);
A = sqlite3ExprListAppend(pParse,X, Y.pExpr);
A = sqlite3ExprListAppend(pParse,A, Z.pExpr);
}
case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). {
A = sqlite3ExprListAppend(pParse,0, Y, 0);
A = sqlite3ExprListAppend(pParse,A, Z, 0);
A = sqlite3ExprListAppend(pParse,0, Y.pExpr);
A = sqlite3ExprListAppend(pParse,A, Z.pExpr);
}
%type case_else {Expr*}
%destructor case_else {sqlite3ExprDelete(pParse->db, $$);}
case_else(A) ::= ELSE expr(X). {A = X;}
case_else(A) ::= ELSE expr(X). {A = X.pExpr;}
case_else(A) ::= . {A = 0;}
%type case_operand {Expr*}
%destructor case_operand {sqlite3ExprDelete(pParse->db, $$);}
case_operand(A) ::= expr(X). {A = X;}
case_operand(A) ::= expr(X). {A = X.pExpr;}
case_operand(A) ::= . {A = 0;}
%type exprlist {ExprList*}
@@ -940,9 +1038,9 @@ case_operand(A) ::= . {A = 0;}
exprlist(A) ::= nexprlist(X). {A = X;}
exprlist(A) ::= . {A = 0;}
nexprlist(A) ::= nexprlist(X) COMMA expr(Y).
{A = sqlite3ExprListAppend(pParse,X,Y,0);}
{A = sqlite3ExprListAppend(pParse,X,Y.pExpr);}
nexprlist(A) ::= expr(Y).
{A = sqlite3ExprListAppend(pParse,0,Y,0);}
{A = sqlite3ExprListAppend(pParse,0,Y.pExpr);}
///////////////////////////// The CREATE INDEX command ///////////////////////
@@ -968,10 +1066,11 @@ idxlist_opt(A) ::= LP idxlist(X) RP. {A = X;}
idxlist(A) ::= idxlist(X) COMMA nm(Y) collate(C) sortorder(Z). {
Expr *p = 0;
if( C.n>0 ){
p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
p = sqlite3Expr(pParse->db, TK_COLUMN, 0);
sqlite3ExprSetColl(pParse, p, &C);
}
A = sqlite3ExprListAppend(pParse,X, p, &Y);
A = sqlite3ExprListAppend(pParse,X, p);
sqlite3ExprListSetName(pParse,A,&Y,1);
sqlite3ExprListCheckLength(pParse, A, "index");
if( A ) A->a[A->nExpr-1].sortOrder = (u8)Z;
}
@@ -981,13 +1080,14 @@ idxlist(A) ::= nm(Y) collate(C) sortorder(Z). {
p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
sqlite3ExprSetColl(pParse, p, &C);
}
A = sqlite3ExprListAppend(pParse,0, p, &Y);
A = sqlite3ExprListAppend(pParse,0, p);
sqlite3ExprListSetName(pParse, A, &Y, 1);
sqlite3ExprListCheckLength(pParse, A, "index");
if( A ) A->a[A->nExpr-1].sortOrder = (u8)Z;
}
%type collate {Token}
collate(C) ::= . {C.z = 0; C.n = 0;}
collate(C) ::= . {C.z = 0; C.n = 0;}
collate(C) ::= COLLATE ids(X). {C = X;}
@@ -1006,7 +1106,6 @@ cmd ::= VACUUM nm. {sqlite3Vacuum(pParse);}
///////////////////////////// The PRAGMA command /////////////////////////////
//
%ifndef SQLITE_OMIT_PARSER
%ifndef SQLITE_OMIT_PRAGMA
cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ nmnum(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
@@ -1022,7 +1121,6 @@ nmnum(A) ::= ON(X). {A = X;}
nmnum(A) ::= DELETE(X). {A = X;}
nmnum(A) ::= DEFAULT(X). {A = X;}
%endif SQLITE_OMIT_PRAGMA
%endif SQLITE_OMIT_PARSER
plus_num(A) ::= plus_opt number(X). {A = X;}
minus_num(A) ::= MINUS number(X). {A = X;}
number(A) ::= INTEGER|FLOAT(X). {A = X;}
@@ -1065,46 +1163,70 @@ foreach_clause ::= FOR EACH ROW.
%type when_clause {Expr*}
%destructor when_clause {sqlite3ExprDelete(pParse->db, $$);}
when_clause(A) ::= . { A = 0; }
when_clause(A) ::= WHEN expr(X). { A = X; }
when_clause(A) ::= WHEN expr(X). { A = X.pExpr; }
%type trigger_cmd_list {TriggerStep*}
%destructor trigger_cmd_list {sqlite3DeleteTriggerStep(pParse->db, $$);}
trigger_cmd_list(A) ::= trigger_cmd_list(Y) trigger_cmd(X) SEMI. {
/*
if( Y ){
Y->pLast->pNext = X;
}else{
Y = X;
}
*/
assert( Y!=0 );
Y->pLast->pNext = X;
Y->pLast = X;
A = Y;
}
trigger_cmd_list(A) ::= trigger_cmd(X) SEMI. {
/* if( X ) */
assert( X!=0 );
X->pLast = X;
A = X;
}
// Disallow qualified table names on INSERT, UPDATE, and DELETE statements
// within a trigger. The table to INSERT, UPDATE, or DELETE is always in
// the same database as the table that the trigger fires on.
//
%type trnm {Token}
trnm(A) ::= nm(X). {A = X;}
trnm(A) ::= nm DOT nm(X). {
A = X;
sqlite3ErrorMsg(pParse,
"qualified table names are not allowed on INSERT, UPDATE, and DELETE "
"statements within triggers");
}
// Disallow the INDEX BY and NOT INDEXED clauses on UPDATE and DELETE
// statements within triggers. We make a specific error message for this
// since it is an exception to the default grammar rules.
//
tridxby ::= .
tridxby ::= INDEXED BY nm. {
sqlite3ErrorMsg(pParse,
"the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
tridxby ::= NOT INDEXED. {
sqlite3ErrorMsg(pParse,
"the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
%type trigger_cmd {TriggerStep*}
%destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);}
// UPDATE
trigger_cmd(A) ::= UPDATE orconf(R) nm(X) SET setlist(Y) where_opt(Z).
{ A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R); }
trigger_cmd(A) ::=
UPDATE orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z).
{ A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R); }
// INSERT
trigger_cmd(A) ::= insert_cmd(R) INTO nm(X) inscollist_opt(F)
VALUES LP itemlist(Y) RP.
{A = sqlite3TriggerInsertStep(pParse->db, &X, F, Y, 0, R);}
trigger_cmd(A) ::=
insert_cmd(R) INTO trnm(X) inscollist_opt(F) VALUES LP itemlist(Y) RP.
{A = sqlite3TriggerInsertStep(pParse->db, &X, F, Y, 0, R);}
trigger_cmd(A) ::= insert_cmd(R) INTO nm(X) inscollist_opt(F) select(S).
trigger_cmd(A) ::= insert_cmd(R) INTO trnm(X) inscollist_opt(F) select(S).
{A = sqlite3TriggerInsertStep(pParse->db, &X, F, 0, S, R);}
// DELETE
trigger_cmd(A) ::= DELETE FROM nm(X) where_opt(Y).
trigger_cmd(A) ::= DELETE FROM trnm(X) tridxby where_opt(Y).
{A = sqlite3TriggerDeleteStep(pParse->db, &X, Y);}
// SELECT
@@ -1112,18 +1234,20 @@ trigger_cmd(A) ::= select(X). {A = sqlite3TriggerSelectStep(pParse->db, X); }
// The special RAISE expression that may occur in trigger programs
expr(A) ::= RAISE(X) LP IGNORE RP(Y). {
A = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
if( A ){
A->affinity = OE_Ignore;
sqlite3ExprSpan(A, &X, &Y);
A.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
if( A.pExpr ){
A.pExpr->affinity = OE_Ignore;
}
A.zStart = X.z;
A.zEnd = &Y.z[Y.n];
}
expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
A = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &Z);
if( A ) {
A->affinity = (char)T;
sqlite3ExprSpan(A, &X, &Y);
A.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &Z);
if( A.pExpr ) {
A.pExpr->affinity = (char)T;
}
A.zStart = X.z;
A.zEnd = &Y.z[Y.n];
}
%endif !SQLITE_OMIT_TRIGGER
@@ -1143,16 +1267,16 @@ cmd ::= DROP TRIGGER ifexists(NOERR) fullname(X). {
//////////////////////// ATTACH DATABASE file AS name /////////////////////////
%ifndef SQLITE_OMIT_ATTACH
cmd ::= ATTACH database_kw_opt expr(F) AS expr(D) key_opt(K). {
sqlite3Attach(pParse, F, D, K);
sqlite3Attach(pParse, F.pExpr, D.pExpr, K);
}
cmd ::= DETACH database_kw_opt expr(D). {
sqlite3Detach(pParse, D);
sqlite3Detach(pParse, D.pExpr);
}
%type key_opt {Expr*}
%destructor key_opt {sqlite3ExprDelete(pParse->db, $$);}
key_opt(A) ::= . { A = 0; }
key_opt(A) ::= KEY expr(X). { A = X; }
key_opt(A) ::= KEY expr(X). { A = X.pExpr; }
database_kw_opt ::= DATABASE.
database_kw_opt ::= .
@@ -1201,5 +1325,6 @@ vtabargtoken ::= ANY(X). {sqlite3VtabArgExtend(pParse,&X);}
vtabargtoken ::= lp anylist RP(X). {sqlite3VtabArgExtend(pParse,&X);}
lp ::= LP(X). {sqlite3VtabArgExtend(pParse,&X);}
anylist ::= .
anylist ::= anylist ANY(X). {sqlite3VtabArgExtend(pParse,&X);}
anylist ::= anylist LP anylist RP.
anylist ::= anylist ANY.
%endif SQLITE_OMIT_VIRTUALTABLE
+15 -21
View File
@@ -11,7 +11,7 @@
*************************************************************************
** This file implements that page cache.
**
** @(#) $Id: pcache.c,v 1.44 2009/03/31 01:32:18 drh Exp $
** @(#) $Id: pcache.c,v 1.47 2009/07/25 11:46:49 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -208,6 +208,7 @@ int sqlite3PcacheFetch(
int eCreate;
assert( pCache!=0 );
assert( createFlag==1 || createFlag==0 );
assert( pgno>0 );
/* If the pluggable cache (sqlite3_pcache*) has not been allocated,
@@ -225,10 +226,7 @@ int sqlite3PcacheFetch(
pCache->pCache = p;
}
eCreate = createFlag ? 1 : 0;
if( eCreate && (!pCache->bPurgeable || !pCache->pDirty) ){
eCreate = 2;
}
eCreate = createFlag * (1 + (!pCache->bPurgeable || !pCache->pDirty));
if( pCache->pCache ){
pPage = sqlite3GlobalConfig.pcache.xFetch(pCache->pCache, pgno, eCreate);
}
@@ -470,24 +468,22 @@ static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
** Sort the list of pages in accending order by pgno. Pages are
** connected by pDirty pointers. The pDirtyPrev pointers are
** corrupted by this sort.
**
** Since there cannot be more than 2^31 distinct pages in a database,
** there cannot be more than 31 buckets required by the merge sorter.
** One extra bucket is added to catch overflow in case something
** ever changes to make the previous sentence incorrect.
*/
#define N_SORT_BUCKET_ALLOC 25
#define N_SORT_BUCKET 25
#ifdef SQLITE_TEST
int sqlite3_pager_n_sort_bucket = 0;
#undef N_SORT_BUCKET
#define N_SORT_BUCKET \
(sqlite3_pager_n_sort_bucket?sqlite3_pager_n_sort_bucket:N_SORT_BUCKET_ALLOC)
#endif
#define N_SORT_BUCKET 32
static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
PgHdr *a[N_SORT_BUCKET_ALLOC], *p;
PgHdr *a[N_SORT_BUCKET], *p;
int i;
memset(a, 0, sizeof(a));
while( pIn ){
p = pIn;
pIn = p->pDirty;
p->pDirty = 0;
for(i=0; i<N_SORT_BUCKET-1; i++){
for(i=0; ALWAYS(i<N_SORT_BUCKET-1); i++){
if( a[i]==0 ){
a[i] = p;
break;
@@ -496,11 +492,9 @@ static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
a[i] = 0;
}
}
if( i==N_SORT_BUCKET-1 ){
/* Coverage: To get here, there need to be 2^(N_SORT_BUCKET)
** elements in the input list. This is possible, but impractical.
** Testing this line is the point of global variable
** sqlite3_pager_n_sort_bucket.
if( NEVER(i==N_SORT_BUCKET-1) ){
/* To get here, there need to be 2^(N_SORT_BUCKET) elements in
** the input list. But that is impossible.
*/
a[i] = pcacheMergeDirtyList(a[i], p);
}
@@ -567,7 +561,7 @@ void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
}
}
#ifdef SQLITE_CHECK_PAGES
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
/*
** For all dirty pages currently in the cache, invoke the specified
** callback. This is only used if the SQLITE_CHECK_PAGES macro is
+2 -2
View File
@@ -12,7 +12,7 @@
** This header file defines the interface that the sqlite page cache
** subsystem.
**
** @(#) $Id: pcache.h,v 1.19 2009/01/20 17:06:27 danielk1977 Exp $
** @(#) $Id: pcache.h,v 1.20 2009/07/25 11:46:49 danielk1977 Exp $
*/
#ifndef _PCACHE_H_
@@ -124,7 +124,7 @@ int sqlite3PcachePageRefcount(PgHdr*);
/* Return the total number of pages stored in the cache */
int sqlite3PcachePagecount(PCache*);
#ifdef SQLITE_CHECK_PAGES
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
/* Iterate through all dirty pages currently stored in the cache. This
** interface is only available if SQLITE_CHECK_PAGES is defined when the
** library is built.
+69 -34
View File
@@ -16,7 +16,7 @@
** If the default page cache implementation is overriden, then neither of
** these two features are available.
**
** @(#) $Id: pcache1.c,v 1.11 2009/04/14 18:44:39 aswift Exp $
** @(#) $Id: pcache1.c,v 1.19 2009/07/17 11:44:07 drh Exp $
*/
#include "sqliteInt.h"
@@ -54,7 +54,7 @@ struct PCache1 {
/*
** Each cache entry is represented by an instance of the following
** structure. A buffer of PgHdr1.pCache->szPage bytes is allocated
** directly after the structure in memory (see the PGHDR1_TO_PAGE()
** directly before this structure in memory (see the PGHDR1_TO_PAGE()
** macro below).
*/
struct PgHdr1 {
@@ -88,6 +88,7 @@ static SQLITE_WSD struct PCacheGlobal {
int szSlot; /* Size of each free slot */
void *pStart, *pEnd; /* Bounds of pagecache malloc range */
PgFreeslot *pFree; /* Free page blocks */
int isInit; /* True if initialized */
} pcache1_g;
/*
@@ -99,7 +100,7 @@ static SQLITE_WSD struct PCacheGlobal {
/*
** When a PgHdr1 structure is allocated, the associated PCache1.szPage
** bytes of data are located directly after it in memory (i.e. the total
** bytes of data are located directly before it in memory (i.e. the total
** size of the allocation is sizeof(PgHdr1)+PCache1.szPage byte). The
** PGHDR1_TO_PAGE() macro takes a pointer to a PgHdr1 structure as
** an argument and returns a pointer to the associated block of szPage
@@ -107,10 +108,10 @@ static SQLITE_WSD struct PCacheGlobal {
** a pointer to a block of szPage bytes of data and the return value is
** a pointer to the associated PgHdr1 structure.
**
** assert( PGHDR1_TO_PAGE(PAGE_TO_PGHDR1(X))==X );
** assert( PGHDR1_TO_PAGE(PAGE_TO_PGHDR1(pCache, X))==X );
*/
#define PGHDR1_TO_PAGE(p) (void *)(&((unsigned char *)p)[sizeof(PgHdr1)])
#define PAGE_TO_PGHDR1(p) (PgHdr1 *)(&((unsigned char *)p)[-1*(int)sizeof(PgHdr1)])
#define PGHDR1_TO_PAGE(p) (void*)(((char*)p) - p->pCache->szPage)
#define PAGE_TO_PGHDR1(c, p) (PgHdr1*)(((char*)p) + c->szPage)
/*
** Macros to enter and leave the global LRU mutex.
@@ -128,18 +129,20 @@ static SQLITE_WSD struct PCacheGlobal {
** enough to contain 'n' buffers of 'sz' bytes each.
*/
void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
PgFreeslot *p;
sz = ROUNDDOWN8(sz);
pcache1.szSlot = sz;
pcache1.pStart = pBuf;
pcache1.pFree = 0;
while( n-- ){
p = (PgFreeslot*)pBuf;
p->pNext = pcache1.pFree;
pcache1.pFree = p;
pBuf = (void*)&((char*)pBuf)[sz];
if( pcache1.isInit ){
PgFreeslot *p;
sz = ROUNDDOWN8(sz);
pcache1.szSlot = sz;
pcache1.pStart = pBuf;
pcache1.pFree = 0;
while( n-- ){
p = (PgFreeslot*)pBuf;
p->pNext = pcache1.pFree;
pcache1.pFree = p;
pBuf = (void*)&((char*)pBuf)[sz];
}
pcache1.pEnd = pBuf;
}
pcache1.pEnd = pBuf;
}
/*
@@ -152,6 +155,7 @@ static void *pcache1Alloc(int nByte){
void *p;
assert( sqlite3_mutex_held(pcache1.mutex) );
if( nByte<=pcache1.szSlot && pcache1.pFree ){
assert( pcache1.isInit );
p = (PgHdr1 *)pcache1.pFree;
pcache1.pFree = pcache1.pFree->pNext;
sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
@@ -199,24 +203,32 @@ static void pcache1Free(void *p){
*/
static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
int nByte = sizeof(PgHdr1) + pCache->szPage;
PgHdr1 *p = (PgHdr1 *)pcache1Alloc(nByte);
if( p ){
void *pPg = pcache1Alloc(nByte);
PgHdr1 *p;
if( pPg ){
p = PAGE_TO_PGHDR1(pCache, pPg);
if( pCache->bPurgeable ){
pcache1.nCurrentPage++;
}
}else{
p = 0;
}
return p;
}
/*
** Free a page object allocated by pcache1AllocPage().
**
** The pointer is allowed to be NULL, which is prudent. But it turns out
** that the current implementation happens to never call this routine
** with a NULL pointer, so we mark the NULL test with ALWAYS().
*/
static void pcache1FreePage(PgHdr1 *p){
if( p ){
if( ALWAYS(p) ){
if( p->pCache->bPurgeable ){
pcache1.nCurrentPage--;
}
pcache1Free(p);
pcache1Free(PGHDR1_TO_PAGE(p));
}
}
@@ -360,6 +372,7 @@ static void pcache1TruncateUnsafe(
PCache1 *pCache,
unsigned int iLimit
){
TESTONLY( unsigned int nPage = 0; ) /* Used to assert pCache->nPage is correct */
unsigned int h;
assert( sqlite3_mutex_held(pcache1.mutex) );
for(h=0; h<pCache->nHash; h++){
@@ -367,14 +380,17 @@ static void pcache1TruncateUnsafe(
PgHdr1 *pPage;
while( (pPage = *pp)!=0 ){
if( pPage->iKey>=iLimit ){
pcache1PinPage(pPage);
pCache->nPage--;
*pp = pPage->pNext;
pcache1PinPage(pPage);
pcache1FreePage(pPage);
}else{
pp = &pPage->pNext;
TESTONLY( nPage++; )
}
}
}
assert( pCache->nPage==nPage );
}
/******************************************************************************/
@@ -385,10 +401,12 @@ static void pcache1TruncateUnsafe(
*/
static int pcache1Init(void *NotUsed){
UNUSED_PARAMETER(NotUsed);
assert( pcache1.isInit==0 );
memset(&pcache1, 0, sizeof(pcache1));
if( sqlite3GlobalConfig.bCoreMutex ){
pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
}
pcache1.isInit = 1;
return SQLITE_OK;
}
@@ -397,7 +415,8 @@ static int pcache1Init(void *NotUsed){
*/
static void pcache1Shutdown(void *NotUsed){
UNUSED_PARAMETER(NotUsed);
/* no-op */
assert( pcache1.isInit!=0 );
memset(&pcache1, 0, sizeof(pcache1));
}
/*
@@ -456,7 +475,14 @@ static int pcache1Pagecount(sqlite3_pcache *p){
** Fetch a page by key value.
**
** Whether or not a new page may be allocated by this function depends on
** the value of the createFlag argument.
** the value of the createFlag argument. 0 means do not allocate a new
** page. 1 means allocate a new page if space is easily available. 2
** means to try really hard to allocate a new page.
**
** For a non-purgeable cache (a cache used as the storage for an in-memory
** database) there is really no difference between createFlag 1 and 2. So
** the calling function (pcache.c) will never have a createFlag of 1 on
** a non-purgable cache.
**
** There are three different approaches to obtaining space for a page,
** depending on the value of parameter createFlag (which may be 0, 1 or 2).
@@ -467,9 +493,8 @@ static int pcache1Pagecount(sqlite3_pcache *p){
** 2. If createFlag==0 and the page is not already in the cache, NULL is
** returned.
**
** 3. If createFlag is 1, the cache is marked as purgeable and the page is
** not already in the cache, and if either of the following are true,
** return NULL:
** 3. If createFlag is 1, and the page is not already in the cache,
** and if either of the following are true, return NULL:
**
** (a) the number of pages pinned by the cache is greater than
** PCache1.nMax, or
@@ -498,6 +523,7 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = 0;
assert( pCache->bPurgeable || createFlag!=1 );
pcache1EnterMutex();
if( createFlag==1 ) sqlite3BeginBenignMalloc();
@@ -514,7 +540,7 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
/* Step 3 of header comment. */
nPinned = pCache->nPage - pCache->nRecyclable;
if( createFlag==1 && pCache->bPurgeable && (
if( createFlag==1 && (
nPinned>=(pcache1.nMaxPage+pCache->nMin-pcache1.nMinPage)
|| nPinned>=(pCache->nMax * 9 / 10)
)){
@@ -549,13 +575,13 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
if( pPage ){
unsigned int h = iKey % pCache->nHash;
*(void **)(PGHDR1_TO_PAGE(pPage)) = 0;
pCache->nPage++;
pPage->iKey = iKey;
pPage->pNext = pCache->apHash[h];
pPage->pCache = pCache;
pPage->pLruPrev = 0;
pPage->pLruNext = 0;
*(void **)(PGHDR1_TO_PAGE(pPage)) = 0;
pCache->apHash[h] = pPage;
}
@@ -576,8 +602,9 @@ fetch_out:
*/
static void pcache1Unpin(sqlite3_pcache *p, void *pPg, int reuseUnlikely){
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = PAGE_TO_PGHDR1(pPg);
PgHdr1 *pPage = PAGE_TO_PGHDR1(pCache, pPg);
assert( pPage->pCache==pCache );
pcache1EnterMutex();
/* It is an error to call this function if the page is already
@@ -619,10 +646,11 @@ static void pcache1Rekey(
unsigned int iNew
){
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = PAGE_TO_PGHDR1(pPg);
PgHdr1 *pPage = PAGE_TO_PGHDR1(pCache, pPg);
PgHdr1 **pp;
unsigned int h;
assert( pPage->iKey==iOld );
assert( pPage->pCache==pCache );
pcache1EnterMutex();
@@ -638,7 +666,14 @@ static void pcache1Rekey(
pPage->pNext = pCache->apHash[h];
pCache->apHash[h] = pPage;
if( iNew>pCache->iMaxKey ){
/* The xRekey() interface is only used to move pages earlier in the
** database file (in order to move all free pages to the end of the
** file where they can be truncated off.) Hence, it is not possible
** for the new page number to be greater than the largest previously
** fetched page. But we retain the following test in case xRekey()
** begins to be used in different ways in the future.
*/
if( NEVER(iNew>pCache->iMaxKey) ){
pCache->iMaxKey = iNew;
}
@@ -717,7 +752,7 @@ int sqlite3PcacheReleaseMemory(int nReq){
PgHdr1 *p;
pcache1EnterMutex();
while( (nReq<0 || nFree<nReq) && (p=pcache1.pLruTail) ){
nFree += sqlite3MallocSize(p);
nFree += sqlite3MallocSize(PGHDR1_TO_PAGE(p));
pcache1PinPage(p);
pcache1RemoveFromHash(p);
pcache1FreePage(p);
+31 -42
View File
@@ -11,13 +11,13 @@
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
** $Id: pragma.c,v 1.209 2009/04/07 22:05:43 drh Exp $
** $Id: pragma.c,v 1.214 2009/07/02 07:47:33 danielk1977 Exp $
*/
#include "sqliteInt.h"
/* Ignore this whole file if pragmas are disabled
*/
#if !defined(SQLITE_OMIT_PRAGMA) && !defined(SQLITE_OMIT_PARSER)
#if !defined(SQLITE_OMIT_PRAGMA)
/*
** Interpret the given string as a safety level. Return 0 for OFF,
@@ -318,12 +318,13 @@ void sqlite3Pragma(
*/
if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){
static const VdbeOpList getCacheSize[] = {
{ OP_ReadCookie, 0, 1, 2}, /* 0 */
{ OP_IfPos, 1, 6, 0},
{ OP_Transaction, 0, 0, 0}, /* 0 */
{ OP_ReadCookie, 0, 1, BTREE_DEFAULT_CACHE_SIZE}, /* 1 */
{ OP_IfPos, 1, 7, 0},
{ OP_Integer, 0, 2, 0},
{ OP_Subtract, 1, 2, 1},
{ OP_IfPos, 1, 6, 0},
{ OP_Integer, 0, 1, 0}, /* 5 */
{ OP_IfPos, 1, 7, 0},
{ OP_Integer, 0, 1, 0}, /* 6 */
{ OP_ResultRow, 1, 1, 0},
};
int addr;
@@ -335,17 +336,18 @@ void sqlite3Pragma(
pParse->nMem += 2;
addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
sqlite3VdbeChangeP1(v, addr, iDb);
sqlite3VdbeChangeP1(v, addr+5, SQLITE_DEFAULT_CACHE_SIZE);
sqlite3VdbeChangeP1(v, addr+1, iDb);
sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
}else{
int size = atoi(zRight);
if( size<0 ) size = -size;
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, 2, 2);
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, 2, BTREE_DEFAULT_CACHE_SIZE);
addr = sqlite3VdbeAddOp2(v, OP_IfPos, 2, 0);
sqlite3VdbeAddOp2(v, OP_Integer, -size, 1);
sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, 2, 1);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
pDb->pSchema->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
}
@@ -582,12 +584,12 @@ void sqlite3Pragma(
** that this really is an auto-vacuum capable database.
*/
static const VdbeOpList setMeta6[] = {
{ OP_Transaction, 0, 1, 0}, /* 0 */
{ OP_ReadCookie, 0, 1, 3}, /* 1 */
{ OP_If, 1, 0, 0}, /* 2 */
{ OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */
{ OP_Integer, 0, 1, 0}, /* 4 */
{ OP_SetCookie, 0, 6, 1}, /* 5 */
{ OP_Transaction, 0, 1, 0}, /* 0 */
{ OP_ReadCookie, 0, 1, BTREE_LARGEST_ROOT_PAGE},
{ OP_If, 1, 0, 0}, /* 2 */
{ OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */
{ OP_Integer, 0, 1, 0}, /* 4 */
{ OP_SetCookie, 0, BTREE_INCR_VACUUM, 1}, /* 5 */
};
int iAddr;
iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6);
@@ -840,10 +842,8 @@ void sqlite3Pragma(
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
pCol->zType ? pCol->zType : "", 0);
sqlite3VdbeAddOp2(v, OP_Integer, (pCol->notNull ? 1 : 0), 4);
if( pCol->pDflt ){
const Token *p = &pCol->pDflt->span;
assert( p->z );
sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)p->z, p->n);
if( pCol->zDflt ){
sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pCol->zDflt, 0);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
}
@@ -1275,23 +1275,21 @@ void sqlite3Pragma(
|| sqlite3StrICmp(zLeft, "user_version")==0
|| sqlite3StrICmp(zLeft, "freelist_count")==0
){
int iCookie; /* Cookie index. 0 for schema-cookie, 6 for user-cookie. */
int iCookie; /* Cookie index. 1 for schema-cookie, 6 for user-cookie. */
sqlite3VdbeUsesBtree(v, iDb);
switch( zLeft[0] ){
case 's': case 'S':
iCookie = 0;
break;
case 'f': case 'F':
iCookie = 1;
iDb = (-1*(iDb+1));
assert(iDb<=0);
iCookie = BTREE_FREE_PAGE_COUNT;
break;
case 's': case 'S':
iCookie = BTREE_SCHEMA_VERSION;
break;
default:
iCookie = 5;
iCookie = BTREE_USER_VERSION;
break;
}
if( zRight && iDb>=0 ){
if( zRight && iCookie!=BTREE_FREE_PAGE_COUNT ){
/* Write the specified cookie value */
static const VdbeOpList setCookie[] = {
{ OP_Transaction, 0, 1, 0}, /* 0 */
@@ -1306,12 +1304,14 @@ void sqlite3Pragma(
}else{
/* Read the specified cookie value */
static const VdbeOpList readCookie[] = {
{ OP_ReadCookie, 0, 1, 0}, /* 0 */
{ OP_Transaction, 0, 0, 0}, /* 0 */
{ OP_ReadCookie, 0, 1, 0}, /* 1 */
{ OP_ResultRow, 1, 1, 0}
};
int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie);
sqlite3VdbeChangeP1(v, addr, iDb);
sqlite3VdbeChangeP3(v, addr, iCookie);
sqlite3VdbeChangeP1(v, addr+1, iDb);
sqlite3VdbeChangeP3(v, addr+1, iCookie);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
}
@@ -1352,17 +1352,6 @@ void sqlite3Pragma(
}else
#endif
#ifdef SQLITE_SSE
/*
** Check to see if the sqlite_statements table exists. Create it
** if it does not.
*/
if( sqlite3StrICmp(zLeft, "create_sqlite_statement_table")==0 ){
extern int sqlite3CreateStatementsTable(Parse*);
sqlite3CreateStatementsTable(pParse);
}else
#endif
#if SQLITE_HAS_CODEC
if( sqlite3StrICmp(zLeft, "key")==0 && zRight ){
sqlite3_key(db, zRight, sqlite3Strlen30(zRight));
@@ -1427,4 +1416,4 @@ pragma_out:
sqlite3DbFree(db, zRight);
}
#endif /* SQLITE_OMIT_PRAGMA || SQLITE_OMIT_PARSER */
#endif /* SQLITE_OMIT_PRAGMA */
+156 -125
View File
@@ -13,7 +13,7 @@
** interface, and routines that contribute to loading the database schema
** from disk.
**
** $Id: prepare.c,v 1.117 2009/04/20 17:43:03 drh Exp $
** $Id: prepare.c,v 1.131 2009/08/06 17:43:31 drh Exp $
*/
#include "sqliteInt.h"
@@ -29,14 +29,14 @@ static void corruptSchema(
sqlite3 *db = pData->db;
if( !db->mallocFailed && (db->flags & SQLITE_RecoveryMode)==0 ){
if( zObj==0 ) zObj = "?";
sqlite3SetString(pData->pzErrMsg, pData->db,
"malformed database schema (%s)", zObj);
if( zExtra && zExtra[0] ){
*pData->pzErrMsg = sqlite3MAppendf(pData->db, *pData->pzErrMsg, "%s - %s",
*pData->pzErrMsg, zExtra);
sqlite3SetString(pData->pzErrMsg, db,
"malformed database schema (%s)", zObj);
if( zExtra ){
*pData->pzErrMsg = sqlite3MAppendf(db, *pData->pzErrMsg,
"%s - %s", *pData->pzErrMsg, zExtra);
}
}
pData->rc = SQLITE_CORRUPT;
pData->rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_CORRUPT;
}
/*
@@ -62,7 +62,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
DbClearProperty(db, iDb, DB_Empty);
if( db->mallocFailed ){
corruptSchema(pData, argv[0], 0);
return SQLITE_NOMEM;
return 1;
}
assert( iDb>=0 && iDb<db->nDb );
@@ -80,15 +80,20 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
assert( db->init.busy );
db->init.iDb = iDb;
db->init.newTnum = atoi(argv[1]);
db->init.orphanTrigger = 0;
rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
db->init.iDb = 0;
assert( rc!=SQLITE_OK || zErr==0 );
if( SQLITE_OK!=rc ){
pData->rc = rc;
if( rc==SQLITE_NOMEM ){
db->mallocFailed = 1;
}else if( rc!=SQLITE_INTERRUPT && (rc&0xff)!=SQLITE_LOCKED ){
corruptSchema(pData, argv[0], zErr);
if( db->init.orphanTrigger ){
assert( iDb==1 );
}else{
pData->rc = rc;
if( rc==SQLITE_NOMEM ){
db->mallocFailed = 1;
}else if( rc!=SQLITE_INTERRUPT && rc!=SQLITE_LOCKED ){
corruptSchema(pData, argv[0], zErr);
}
}
sqlite3DbFree(db, zErr);
}
@@ -103,15 +108,15 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
*/
Index *pIndex;
pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zName);
if( pIndex==0 || pIndex->tnum!=0 ){
if( pIndex==0 ){
/* This can occur if there exists an index on a TEMP table which
** has the same name as another index on a permanent index. Since
** the permanent table is hidden by the TEMP table, we can also
** safely ignore the index on the permanent table.
*/
/* Do Nothing */;
}else{
pIndex->tnum = atoi(argv[1]);
}else if( sqlite3GetInt32(argv[1], &pIndex->tnum)==0 ){
corruptSchema(pData, argv[0], "invalid rootpage");
}
}
return 0;
@@ -128,15 +133,15 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
int rc;
int i;
BtCursor *curMain;
int size;
Table *pTab;
Db *pDb;
char const *azArg[4];
int meta[10];
int meta[5];
InitData initData;
char const *zMasterSchema;
char const *zMasterName = SCHEMA_TABLE(iDb);
int openedTransaction = 0;
/*
** The master database table has a structure like this
@@ -197,7 +202,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
goto error_out;
}
pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName);
if( pTab ){
if( ALWAYS(pTab) ){
pTab->tabFlags |= TF_Readonly;
}
@@ -205,22 +210,23 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
*/
pDb = &db->aDb[iDb];
if( pDb->pBt==0 ){
if( !OMIT_TEMPDB && iDb==1 ){
if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){
DbSetProperty(db, 1, DB_SchemaLoaded);
}
return SQLITE_OK;
}
curMain = sqlite3MallocZero(sqlite3BtreeCursorSize());
if( !curMain ){
rc = SQLITE_NOMEM;
goto error_out;
}
/* If there is not already a read-only (or read-write) transaction opened
** on the b-tree database, open one now. If a transaction is opened, it
** will be closed before this function returns. */
sqlite3BtreeEnter(pDb->pBt);
rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, curMain);
if( rc==SQLITE_EMPTY ) rc = SQLITE_OK;
if( rc!=SQLITE_OK ){
sqlite3SetString(pzErrMsg, db, "%s", sqlite3ErrStr(rc));
goto initone_error_out;
if( !sqlite3BtreeIsInReadTrans(pDb->pBt) ){
rc = sqlite3BtreeBeginTrans(pDb->pBt, 0);
if( rc!=SQLITE_OK ){
sqlite3SetString(pzErrMsg, db, "%s", sqlite3ErrStr(rc));
goto initone_error_out;
}
openedTransaction = 1;
}
/* Get the database meta information.
@@ -229,39 +235,38 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
** meta[0] Schema cookie. Changes with each schema change.
** meta[1] File format of schema layer.
** meta[2] Size of the page cache.
** meta[3] Use freelist if 0. Autovacuum if greater than zero.
** meta[3] Largest rootpage (auto/incr_vacuum mode)
** meta[4] Db text encoding. 1:UTF-8 2:UTF-16LE 3:UTF-16BE
** meta[5] The user cookie. Used by the application.
** meta[6] Incremental-vacuum flag.
** meta[7]
** meta[8]
** meta[9]
** meta[5] User version
** meta[6] Incremental vacuum mode
** meta[7] unused
** meta[8] unused
** meta[9] unused
**
** Note: The #defined SQLITE_UTF* symbols in sqliteInt.h correspond to
** the possible values of meta[4].
*/
for(i=0; i<ArraySize(meta); i++){
rc = sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]);
if( rc ){
sqlite3SetString(pzErrMsg, db, "%s", sqlite3ErrStr(rc));
goto initone_error_out;
}
sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]);
}
pDb->pSchema->schema_cookie = meta[0];
pDb->pSchema->schema_cookie = meta[BTREE_SCHEMA_VERSION-1];
/* If opening a non-empty database, check the text encoding. For the
** main database, set sqlite3.enc to the encoding of the main database.
** For an attached db, it is an error if the encoding is not the same
** as sqlite3.enc.
*/
if( meta[4] ){ /* text encoding */
if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */
if( iDb==0 ){
u8 encoding;
/* If opening the main database, set ENC(db). */
ENC(db) = (u8)meta[4];
db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0);
encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3;
if( encoding==0 ) encoding = SQLITE_UTF8;
ENC(db) = encoding;
db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 0);
}else{
/* If opening an attached database, the encoding much match ENC(db) */
if( meta[4]!=ENC(db) ){
if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){
sqlite3SetString(pzErrMsg, db, "attached databases must use the same"
" text encoding as main database");
rc = SQLITE_ERROR;
@@ -274,7 +279,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
pDb->pSchema->enc = ENC(db);
if( pDb->pSchema->cache_size==0 ){
size = meta[2];
size = meta[BTREE_DEFAULT_CACHE_SIZE-1];
if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; }
if( size<0 ) size = -size;
pDb->pSchema->cache_size = size;
@@ -287,7 +292,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
** file_format==3 Version 3.1.4. // ditto but with non-NULL defaults
** file_format==4 Version 3.3.0. // DESC indices. Boolean constants
*/
pDb->pSchema->file_format = (u8)meta[1];
pDb->pSchema->file_format = (u8)meta[BTREE_FILE_FORMAT-1];
if( pDb->pSchema->file_format==0 ){
pDb->pSchema->file_format = 1;
}
@@ -302,17 +307,14 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
** not downgrade the database and thus invalidate any descending
** indices that the user might have created.
*/
if( iDb==0 && meta[1]>=4 ){
if( iDb==0 && meta[BTREE_FILE_FORMAT-1]>=4 ){
db->flags &= ~SQLITE_LegacyFileFmt;
}
/* Read the schema information out of the schema tables
*/
assert( db->init.busy );
if( rc==SQLITE_EMPTY ){
/* For an empty database, there is nothing to read */
rc = SQLITE_OK;
}else{
{
char *zSql;
zSql = sqlite3MPrintf(db,
"SELECT name, rootpage, sql FROM '%q'.%s",
@@ -360,8 +362,9 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
** before that point, jump to error_out.
*/
initone_error_out:
sqlite3BtreeCloseCursor(curMain);
sqlite3_free(curMain);
if( openedTransaction ){
sqlite3BtreeCommit(pDb->pBt);
}
sqlite3BtreeLeave(pDb->pBt);
error_out:
@@ -386,7 +389,6 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
int commit_internal = !(db->flags&SQLITE_InternChanges);
assert( sqlite3_mutex_held(db->mutex) );
if( db->init.busy ) return SQLITE_OK;
rc = SQLITE_OK;
db->init.busy = 1;
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
@@ -402,7 +404,8 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
** schema may contain references to objects in other databases.
*/
#ifndef SQLITE_OMIT_TEMPDB
if( rc==SQLITE_OK && db->nDb>1 && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
if( rc==SQLITE_OK && ALWAYS(db->nDb>1)
&& !DbHasProperty(db, 1, DB_SchemaLoaded) ){
rc = sqlite3InitOne(db, 1, pzErrMsg);
if( rc ){
sqlite3ResetInternalSchema(db, 1);
@@ -439,42 +442,47 @@ int sqlite3ReadSchema(Parse *pParse){
/*
** Check schema cookies in all databases. If any cookie is out
** of date, return 0. If all schema cookies are current, return 1.
** of date set pParse->rc to SQLITE_SCHEMA. If all schema cookies
** make no changes to pParse->rc.
*/
static int schemaIsValid(sqlite3 *db){
static void schemaIsValid(Parse *pParse){
sqlite3 *db = pParse->db;
int iDb;
int rc;
BtCursor *curTemp;
int cookie;
int allOk = 1;
curTemp = (BtCursor *)sqlite3Malloc(sqlite3BtreeCursorSize());
if( curTemp ){
assert( sqlite3_mutex_held(db->mutex) );
for(iDb=0; allOk && iDb<db->nDb; iDb++){
Btree *pBt;
pBt = db->aDb[iDb].pBt;
if( pBt==0 ) continue;
memset(curTemp, 0, sqlite3BtreeCursorSize());
rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, curTemp);
if( rc==SQLITE_OK ){
rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie);
if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){
allOk = 0;
}
sqlite3BtreeCloseCursor(curTemp);
}
assert( pParse->checkSchema );
assert( sqlite3_mutex_held(db->mutex) );
for(iDb=0; iDb<db->nDb; iDb++){
int openedTransaction = 0; /* True if a transaction is opened */
Btree *pBt = db->aDb[iDb].pBt; /* Btree database to read cookie from */
if( pBt==0 ) continue;
/* If there is not already a read-only (or read-write) transaction opened
** on the b-tree database, open one now. If a transaction is opened, it
** will be closed immediately after reading the meta-value. */
if( !sqlite3BtreeIsInReadTrans(pBt) ){
rc = sqlite3BtreeBeginTrans(pBt, 0);
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
db->mallocFailed = 1;
}
if( rc!=SQLITE_OK ) return;
openedTransaction = 1;
}
sqlite3_free(curTemp);
}else{
allOk = 0;
db->mallocFailed = 1;
}
return allOk;
/* Read the schema cookie from the database. If it does not match the
** value stored as part of the in the in-memory schema representation,
** set Parse.rc to SQLITE_SCHEMA. */
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie);
if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){
pParse->rc = SQLITE_SCHEMA;
}
/* Close the transaction, if one was opened. */
if( openedTransaction ){
sqlite3BtreeCommit(pBt);
}
}
}
/*
@@ -520,12 +528,22 @@ static int sqlite3Prepare(
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const char **pzTail /* OUT: End of parsed string */
){
Parse sParse;
char *zErrMsg = 0;
int rc = SQLITE_OK;
int i;
Parse *pParse; /* Parsing context */
char *zErrMsg = 0; /* Error message */
int rc = SQLITE_OK; /* Result code */
int i; /* Loop counter */
if( sqlite3SafetyOn(db) ) return SQLITE_MISUSE;
/* Allocate the parsing context */
pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
if( pParse==0 ){
rc = SQLITE_NOMEM;
goto end_prepare;
}
if( sqlite3SafetyOn(db) ){
rc = SQLITE_MISUSE;
goto end_prepare;
}
assert( ppStmt && *ppStmt==0 );
assert( !db->mallocFailed );
assert( sqlite3_mutex_held(db->mutex) );
@@ -563,68 +581,74 @@ static int sqlite3Prepare(
sqlite3Error(db, rc, "database schema is locked: %s", zDb);
(void)sqlite3SafetyOff(db);
testcase( db->flags & SQLITE_ReadUncommitted );
return sqlite3ApiExit(db, rc);
goto end_prepare;
}
}
}
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
sqlite3VtabUnlockList(db);
pParse->db = db;
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
char *zSqlCopy;
int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
testcase( nBytes==mxLen );
testcase( nBytes==mxLen+1 );
if( nBytes>mxLen ){
sqlite3Error(db, SQLITE_TOOBIG, "statement too long");
(void)sqlite3SafetyOff(db);
return sqlite3ApiExit(db, SQLITE_TOOBIG);
rc = sqlite3ApiExit(db, SQLITE_TOOBIG);
goto end_prepare;
}
zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
if( zSqlCopy ){
sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
sqlite3RunParser(pParse, zSqlCopy, &zErrMsg);
sqlite3DbFree(db, zSqlCopy);
sParse.zTail = &zSql[sParse.zTail-zSqlCopy];
pParse->zTail = &zSql[pParse->zTail-zSqlCopy];
}else{
sParse.zTail = &zSql[nBytes];
pParse->zTail = &zSql[nBytes];
}
}else{
sqlite3RunParser(&sParse, zSql, &zErrMsg);
sqlite3RunParser(pParse, zSql, &zErrMsg);
}
if( db->mallocFailed ){
sParse.rc = SQLITE_NOMEM;
pParse->rc = SQLITE_NOMEM;
}
if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
if( sParse.checkSchema && !schemaIsValid(db) ){
sParse.rc = SQLITE_SCHEMA;
if( pParse->rc==SQLITE_DONE ) pParse->rc = SQLITE_OK;
if( pParse->checkSchema ){
schemaIsValid(pParse);
}
if( sParse.rc==SQLITE_SCHEMA ){
if( pParse->rc==SQLITE_SCHEMA ){
sqlite3ResetInternalSchema(db, 0);
}
if( db->mallocFailed ){
sParse.rc = SQLITE_NOMEM;
pParse->rc = SQLITE_NOMEM;
}
if( pzTail ){
*pzTail = sParse.zTail;
*pzTail = pParse->zTail;
}
rc = sParse.rc;
rc = pParse->rc;
#ifndef SQLITE_OMIT_EXPLAIN
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
if( sParse.explain==2 ){
sqlite3VdbeSetNumCols(sParse.pVdbe, 3);
sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "order", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "from", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "detail", SQLITE_STATIC);
if( rc==SQLITE_OK && pParse->pVdbe && pParse->explain ){
static const char * const azColName[] = {
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
"order", "from", "detail"
};
int iFirst, mx;
if( pParse->explain==2 ){
sqlite3VdbeSetNumCols(pParse->pVdbe, 3);
iFirst = 8;
mx = 11;
}else{
sqlite3VdbeSetNumCols(sParse.pVdbe, 8);
sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "addr", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "opcode", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "p1", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 3, COLNAME_NAME, "p2", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 4, COLNAME_NAME, "p3", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 5, COLNAME_NAME, "p4", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 6, COLNAME_NAME, "p5", SQLITE_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 7, COLNAME_NAME, "comment", SQLITE_STATIC);
sqlite3VdbeSetNumCols(pParse->pVdbe, 8);
iFirst = 0;
mx = 8;
}
for(i=iFirst; i<mx; i++){
sqlite3VdbeSetColName(pParse->pVdbe, i-iFirst, COLNAME_NAME,
azColName[i], SQLITE_STATIC);
}
}
#endif
@@ -635,14 +659,14 @@ static int sqlite3Prepare(
assert( db->init.busy==0 || saveSqlFlag==0 );
if( db->init.busy==0 ){
Vdbe *pVdbe = sParse.pVdbe;
sqlite3VdbeSetSql(pVdbe, zSql, (int)(sParse.zTail-zSql), saveSqlFlag);
Vdbe *pVdbe = pParse->pVdbe;
sqlite3VdbeSetSql(pVdbe, zSql, (int)(pParse->zTail-zSql), saveSqlFlag);
}
if( sParse.pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
sqlite3VdbeFinalize(sParse.pVdbe);
if( pParse->pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
sqlite3VdbeFinalize(pParse->pVdbe);
assert(!(*ppStmt));
}else{
*ppStmt = (sqlite3_stmt*)sParse.pVdbe;
*ppStmt = (sqlite3_stmt*)pParse->pVdbe;
}
if( zErrMsg ){
@@ -652,6 +676,9 @@ static int sqlite3Prepare(
sqlite3Error(db, rc, 0);
}
end_prepare:
sqlite3StackFree(db, pParse);
rc = sqlite3ApiExit(db, rc);
assert( (rc&db->errMask)==rc );
return rc;
@@ -673,6 +700,10 @@ static int sqlite3LockAndPrepare(
sqlite3_mutex_enter(db->mutex);
sqlite3BtreeEnterAll(db);
rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, ppStmt, pzTail);
if( rc==SQLITE_SCHEMA ){
sqlite3_finalize(*ppStmt);
rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, ppStmt, pzTail);
}
sqlite3BtreeLeaveAll(db);
sqlite3_mutex_leave(db->mutex);
return rc;
+7 -4
View File
@@ -5,7 +5,7 @@
** an historical reference. Most of the "enhancements" have been backed
** out so that the functionality is now the same as standard printf().
**
** $Id: printf.c,v 1.103 2009/05/04 20:20:16 drh Exp $
** $Id: printf.c,v 1.104 2009/06/03 01:24:54 drh Exp $
**
**************************************************************************
**
@@ -189,11 +189,14 @@ static void appendSpace(StrAccum *pAccum, int N){
/*
** On machines with a small stack size, you can redefine the
** SQLITE_PRINT_BUF_SIZE to be less than 350. But beware - for
** smaller values some %f conversions may go into an infinite loop.
** SQLITE_PRINT_BUF_SIZE to be less than 350.
*/
#ifndef SQLITE_PRINT_BUF_SIZE
# define SQLITE_PRINT_BUF_SIZE 350
# if defined(SQLITE_SMALL_STACK)
# define SQLITE_PRINT_BUF_SIZE 50
# else
# define SQLITE_PRINT_BUF_SIZE 350
# endif
#endif
#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */
+68 -82
View File
@@ -14,7 +14,7 @@
** resolve all identifiers by associating them with a particular
** table and column.
**
** $Id: resolve.c,v 1.22 2009/05/05 15:46:43 drh Exp $
** $Id: resolve.c,v 1.30 2009/06/15 23:15:59 drh Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@@ -63,16 +63,27 @@ static void resolveAlias(
assert( pOrig!=0 );
assert( pOrig->flags & EP_Resolved );
db = pParse->db;
pDup = sqlite3ExprDup(db, pOrig, 0);
if( pDup==0 ) return;
sqlite3TokenCopy(db, &pDup->token, &pOrig->token);
if( pDup->op!=TK_COLUMN && zType[0]!='G' ){
if( pOrig->op!=TK_COLUMN && zType[0]!='G' ){
pDup = sqlite3ExprDup(db, pOrig, 0);
pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0);
if( pDup==0 ) return;
if( pEList->a[iCol].iAlias==0 ){
pEList->a[iCol].iAlias = (u16)(++pParse->nAlias);
}
pDup->iTable = pEList->a[iCol].iAlias;
}else if( ExprHasProperty(pOrig, EP_IntValue) || pOrig->u.zToken==0 ){
pDup = sqlite3ExprDup(db, pOrig, 0);
if( pDup==0 ) return;
}else{
char *zToken = pOrig->u.zToken;
assert( zToken!=0 );
pOrig->u.zToken = 0;
pDup = sqlite3ExprDup(db, pOrig, 0);
pOrig->u.zToken = zToken;
if( pDup==0 ) return;
assert( (pDup->flags & (EP_Reduced|EP_TokenOnly))==0 );
pDup->flags2 |= EP2_MallocedToken;
pDup->u.zToken = sqlite3DbStrDup(db, zToken);
}
if( pExpr->flags & EP_ExpCollate ){
pDup->pColl = pExpr->pColl;
@@ -100,27 +111,24 @@ static void resolveAlias(
** pExpr->pLeft Any expression this points to is deleted
** pExpr->pRight Any expression this points to is deleted.
**
** The pDbToken is the name of the database (the "X"). This value may be
** The zDb variable is the name of the database (the "X"). This value may be
** NULL meaning that name is of the form Y.Z or Z. Any available database
** can be used. The pTableToken is the name of the table (the "Y"). This
** value can be NULL if pDbToken is also NULL. If pTableToken is NULL it
** can be used. The zTable variable is the name of the table (the "Y"). This
** value can be NULL if zDb is also NULL. If zTable is NULL it
** means that the form of the name is Z and that columns from any table
** can be used.
**
** If the name cannot be resolved unambiguously, leave an error message
** in pParse and return non-zero. Return zero on success.
** in pParse and return WRC_Abort. Return WRC_Prune on success.
*/
static int lookupName(
Parse *pParse, /* The parsing context */
Token *pDbToken, /* Name of the database containing table, or NULL */
Token *pTableToken, /* Name of table containing column, or NULL */
Token *pColumnToken, /* Name of the column. */
const char *zDb, /* Name of the database containing table, or NULL */
const char *zTab, /* Name of table containing column, or NULL */
const char *zCol, /* Name of the column. */
NameContext *pNC, /* The name context used to resolve the name */
Expr *pExpr /* Make this EXPR node point to the selected column */
){
char *zDb = 0; /* Name of the database. The "X" in X.Y.Z */
char *zTab = 0; /* Name of the table. The "Y" in X.Y.Z or Y.Z */
char *zCol = 0; /* Name of the column. The "Z" */
int i, j; /* Loop counters */
int cnt = 0; /* Number of matching column names */
int cntTab = 0; /* Number of matching table names */
@@ -130,20 +138,14 @@ static int lookupName(
NameContext *pTopNC = pNC; /* First namecontext in the list */
Schema *pSchema = 0; /* Schema of the expression */
assert( pNC ); /* the name context cannot be NULL. */
assert( pColumnToken && pColumnToken->z ); /* The Z in X.Y.Z cannot be NULL */
/* Dequote and zero-terminate the names */
zDb = sqlite3NameFromToken(db, pDbToken);
zTab = sqlite3NameFromToken(db, pTableToken);
zCol = sqlite3NameFromToken(db, pColumnToken);
if( db->mallocFailed ){
goto lookupname_end;
}
assert( pNC ); /* the name context cannot be NULL. */
assert( zCol ); /* The Z in X.Y.Z cannot be NULL */
assert( ~ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) );
/* Initialize the node to no-match */
pExpr->iTable = -1;
pExpr->pTab = 0;
ExprSetIrreducible(pExpr);
/* Start at the inner-most context and move outward until a match is found */
while( pNC && cnt==0 ){
@@ -166,7 +168,9 @@ static int lookupName(
if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
}else{
char *zTabName = pTab->zName;
if( zTabName==0 || sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
if( NEVER(zTabName==0) || sqlite3StrICmp(zTabName, zTab)!=0 ){
continue;
}
if( zDb!=0 && sqlite3StrICmp(db->aDb[iDb].zName, zDb)!=0 ){
continue;
}
@@ -187,7 +191,7 @@ static int lookupName(
pMatch = pItem;
pSchema = pTab->pSchema;
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
pExpr->iColumn = j==pTab->iPKey ? -1 : j;
pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
if( i<pSrcList->nSrc-1 ){
if( pItem[1].jointype & JT_NATURAL ){
/* If this match occurred in the left table of a natural join,
@@ -243,16 +247,14 @@ static int lookupName(
for(iCol=0; iCol < pTab->nCol; iCol++, pCol++) {
if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
cnt++;
pExpr->iColumn = iCol==pTab->iPKey ? -1 : iCol;
pExpr->iColumn = iCol==pTab->iPKey ? -1 : (i16)iCol;
pExpr->pTab = pTab;
if( iCol>=0 ){
testcase( iCol==31 );
testcase( iCol==32 );
if( iCol>=32 ){
*piColMask = 0xffffffff;
}else{
*piColMask |= ((u32)1)<<iCol;
}
testcase( iCol==31 );
testcase( iCol==32 );
if( iCol>=32 ){
*piColMask = 0xffffffff;
}else{
*piColMask |= ((u32)1)<<iCol;
}
break;
}
@@ -293,14 +295,13 @@ static int lookupName(
pOrig = pEList->a[j].pExpr;
if( !pNC->allowAgg && ExprHasProperty(pOrig, EP_Agg) ){
sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
sqlite3DbFree(db, zCol);
return 2;
return WRC_Abort;
}
resolveAlias(pParse, pEList, j, pExpr, "");
cnt = 1;
pMatch = 0;
assert( zTab==0 && zDb==0 );
goto lookupname_end_2;
goto lookupname_end;
}
}
}
@@ -324,10 +325,9 @@ static int lookupName(
** fields are not changed in any context.
*/
if( cnt==0 && zTab==0 && ExprHasProperty(pExpr,EP_DblQuoted) ){
sqlite3DbFree(db, zCol);
pExpr->op = TK_STRING;
pExpr->pTab = 0;
return 0;
return WRC_Prune;
}
/*
@@ -363,18 +363,14 @@ static int lookupName(
pMatch->colUsed |= ((Bitmask)1)<<n;
}
lookupname_end:
/* Clean up and return
*/
sqlite3DbFree(db, zDb);
sqlite3DbFree(db, zTab);
sqlite3ExprDelete(db, pExpr->pLeft);
pExpr->pLeft = 0;
sqlite3ExprDelete(db, pExpr->pRight);
pExpr->pRight = 0;
pExpr->op = TK_COLUMN;
lookupname_end_2:
sqlite3DbFree(db, zCol);
lookupname_end:
if( cnt==1 ){
assert( pNC!=0 );
sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList);
@@ -386,9 +382,9 @@ lookupname_end_2:
if( pTopNC==pNC ) break;
pTopNC = pTopNC->pNext;
}
return 0;
return WRC_Prune;
} else {
return 1;
return WRC_Abort;
}
}
@@ -447,33 +443,31 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
/* A lone identifier is the name of a column.
*/
case TK_ID: {
lookupName(pParse, 0, 0, &pExpr->token, pNC, pExpr);
return WRC_Prune;
return lookupName(pParse, 0, 0, pExpr->u.zToken, pNC, pExpr);
}
/* A table name and column name: ID.ID
** Or a database, table and column: ID.ID.ID
*/
case TK_DOT: {
Token *pColumn;
Token *pTable;
Token *pDb;
const char *zColumn;
const char *zTable;
const char *zDb;
Expr *pRight;
/* if( pSrcList==0 ) break; */
pRight = pExpr->pRight;
if( pRight->op==TK_ID ){
pDb = 0;
pTable = &pExpr->pLeft->token;
pColumn = &pRight->token;
zDb = 0;
zTable = pExpr->pLeft->u.zToken;
zColumn = pRight->u.zToken;
}else{
assert( pRight->op==TK_DOT );
pDb = &pExpr->pLeft->token;
pTable = &pRight->pLeft->token;
pColumn = &pRight->pRight->token;
zDb = pExpr->pLeft->u.zToken;
zTable = pRight->pLeft->u.zToken;
zColumn = pRight->pRight->u.zToken;
}
lookupName(pParse, pDb, pTable, pColumn, pNC, pExpr);
return WRC_Prune;
return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
}
/* Resolve function names
@@ -491,9 +485,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
FuncDef *pDef; /* Information about the function */
u8 enc = ENC(pParse->db); /* The database encoding */
testcase( pExpr->op==TK_CONST_FUNC );
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
zId = (char*)pExpr->token.z;
nId = pExpr->token.n;
zId = pExpr->u.zToken;
nId = sqlite3Strlen30(zId);
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
if( pDef==0 ){
pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, enc, 0);
@@ -545,9 +540,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
}
#ifndef SQLITE_OMIT_SUBQUERY
case TK_SELECT:
case TK_EXISTS:
case TK_EXISTS: testcase( pExpr->op==TK_EXISTS );
#endif
case TK_IN: {
testcase( pExpr->op==TK_IN );
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
int nRef = pNC->nRef;
#ifndef SQLITE_OMIT_CHECK
@@ -594,20 +590,16 @@ static int resolveAsName(
){
int i; /* Loop counter */
if( pE->op==TK_ID || (pE->op==TK_STRING && pE->token.z[0]!='\'') ){
sqlite3 *db = pParse->db;
char *zCol = sqlite3NameFromToken(db, &pE->token);
if( zCol==0 ){
return -1;
}
UNUSED_PARAMETER(pParse);
if( pE->op==TK_ID ){
char *zCol = pE->u.zToken;
for(i=0; i<pEList->nExpr; i++){
char *zAs = pEList->a[i].zName;
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
sqlite3DbFree(db, zCol);
return i+1;
}
}
sqlite3DbFree(db, zCol);
}
return 0;
}
@@ -736,7 +728,7 @@ static int resolveCompoundOrderBy(
if( pItem->done ) continue;
pE = pItem->pExpr;
if( sqlite3ExprIsInteger(pE, &iCol) ){
if( iCol<0 || iCol>pEList->nExpr ){
if( iCol<=0 || iCol>pEList->nExpr ){
resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr);
return 1;
}
@@ -750,19 +742,16 @@ static int resolveCompoundOrderBy(
}
sqlite3ExprDelete(db, pDup);
}
if( iCol<0 ){
return 1;
}
}
if( iCol>0 ){
CollSeq *pColl = pE->pColl;
int flags = pE->flags & EP_ExpCollate;
sqlite3ExprDelete(db, pE);
pItem->pExpr = pE = sqlite3Expr(db, TK_INTEGER, 0, 0, 0);
pItem->pExpr = pE = sqlite3Expr(db, TK_INTEGER, 0);
if( pE==0 ) return 1;
pE->pColl = pColl;
pE->flags |= EP_IntValue | flags;
pE->iTable = iCol;
pE->u.iValue = iCol;
pItem->iCol = (u16)iCol;
pItem->done = 1;
}else{
@@ -859,9 +848,6 @@ static int resolveOrderGroupBy(
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
Expr *pE = pItem->pExpr;
iCol = resolveAsName(pParse, pSelect->pEList, pE);
if( iCol<0 ){
return 1; /* OOM error */
}
if( iCol>0 ){
/* If an AS-name match is found, mark this ORDER BY column as being
** a copy of the iCol-th result-set column. The subsequent call to
@@ -1136,7 +1122,7 @@ int sqlite3ResolveExprNames(
#if SQLITE_MAX_EXPR_DEPTH>0
pNC->pParse->nHeight -= pExpr->nHeight;
#endif
if( pNC->nErr>0 ){
if( pNC->nErr>0 || w.pParse->nErr>0 ){
ExprSetProperty(pExpr, EP_Error);
}
if( pNC->hasAgg ){
+4 -4
View File
@@ -60,7 +60,7 @@
** There is an added cost of O(N) when switching between TEST and
** SMALLEST primitives.
**
** $Id: rowset.c,v 1.6 2009/04/22 15:32:59 drh Exp $
** $Id: rowset.c,v 1.7 2009/05/22 01:00:13 drh Exp $
*/
#include "sqliteInt.h"
@@ -127,15 +127,15 @@ struct RowSet {
*/
RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){
RowSet *p;
assert( N >= sizeof(*p) );
assert( N >= ROUND8(sizeof(*p)) );
p = pSpace;
p->pChunk = 0;
p->db = db;
p->pEntry = 0;
p->pLast = 0;
p->pTree = 0;
p->pFresh = (struct RowSetEntry*)&p[1];
p->nFresh = (u16)((N - sizeof(*p))/sizeof(struct RowSetEntry));
p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p);
p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry));
p->isSorted = 1;
p->iBatch = 0;
return p;
+186 -225
View File
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
** $Id: select.c,v 1.512 2009/05/03 20:23:54 drh Exp $
** $Id: select.c,v 1.526 2009/08/01 15:09:58 drh Exp $
*/
#include "sqliteInt.h"
@@ -71,7 +71,7 @@ Select *sqlite3SelectNew(
memset(pNew, 0, sizeof(*pNew));
}
if( pEList==0 ){
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ALL,0,0,0), 0);
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ALL,0));
}
pNew->pEList = pEList;
pNew->pSrc = pSrc;
@@ -83,6 +83,7 @@ Select *sqlite3SelectNew(
pNew->op = TK_SELECT;
pNew->pLimit = pLimit;
pNew->pOffset = pOffset;
assert( pOffset==0 || pLimit!=0 );
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
pNew->addrOpenEphm[2] = -1;
@@ -125,18 +126,20 @@ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
int jointype = 0;
Token *apAll[3];
Token *p;
/* 0123456789 123456789 123456789 123 */
static const char zKeyText[] = "naturaleftouterightfullinnercross";
static const struct {
const char zKeyword[8];
u8 nChar;
u8 code;
} keywords[] = {
{ "natural", 7, JT_NATURAL },
{ "left", 4, JT_LEFT|JT_OUTER },
{ "right", 5, JT_RIGHT|JT_OUTER },
{ "full", 4, JT_LEFT|JT_RIGHT|JT_OUTER },
{ "outer", 5, JT_OUTER },
{ "inner", 5, JT_INNER },
{ "cross", 5, JT_INNER|JT_CROSS },
u8 i; /* Beginning of keyword text in zKeyText[] */
u8 nChar; /* Length of the keyword in characters */
u8 code; /* Join type mask */
} aKeyword[] = {
/* natural */ { 0, 7, JT_NATURAL },
/* left */ { 6, 4, JT_LEFT|JT_OUTER },
/* outer */ { 10, 5, JT_OUTER },
/* right */ { 14, 5, JT_RIGHT|JT_OUTER },
/* full */ { 19, 4, JT_LEFT|JT_RIGHT|JT_OUTER },
/* inner */ { 23, 5, JT_INNER },
/* cross */ { 28, 5, JT_INNER|JT_CROSS },
};
int i, j;
apAll[0] = pA;
@@ -144,14 +147,15 @@ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
apAll[2] = pC;
for(i=0; i<3 && apAll[i]; i++){
p = apAll[i];
for(j=0; j<ArraySize(keywords); j++){
if( p->n==keywords[j].nChar
&& sqlite3StrNICmp((char*)p->z, keywords[j].zKeyword, p->n)==0 ){
jointype |= keywords[j].code;
for(j=0; j<ArraySize(aKeyword); j++){
if( p->n==aKeyword[j].nChar
&& sqlite3StrNICmp((char*)p->z, &zKeyText[aKeyword[j].i], p->n)==0 ){
jointype |= aKeyword[j].code;
break;
}
}
if( j>=ArraySize(keywords) ){
testcase( j==0 || j==1 || j==2 || j==3 || j==4 || j==5 || j==6 );
if( j>=ArraySize(aKeyword) ){
jointype |= JT_ERROR;
break;
}
@@ -166,7 +170,8 @@ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
sqlite3ErrorMsg(pParse, "unknown or unsupported join type: "
"%T %T%s%T", pA, pB, zSp, pC);
jointype = JT_INNER;
}else if( jointype & JT_RIGHT ){
}else if( (jointype & JT_OUTER)!=0
&& (jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ){
sqlite3ErrorMsg(pParse,
"RIGHT and FULL OUTER JOINs are not currently supported");
jointype = JT_INNER;
@@ -186,23 +191,11 @@ static int columnIndex(Table *pTab, const char *zCol){
return -1;
}
/*
** Set the value of a token to a '\000'-terminated string.
*/
static void setToken(Token *p, const char *z){
p->z = (u8*)z;
p->n = z ? sqlite3Strlen30(z) : 0;
p->dyn = 0;
p->quoted = 0;
}
/*
** Create an expression node for an identifier with the name of zName
*/
Expr *sqlite3CreateIdExpr(Parse *pParse, const char *zName){
Token dummy;
setToken(&dummy, zName);
return sqlite3PExpr(pParse, TK_ID, 0, 0, &dummy);
return sqlite3Expr(pParse->db, TK_ID, zName);
}
/*
@@ -239,7 +232,9 @@ static void addWhereTerm(
pE = sqlite3PExpr(pParse, TK_EQ, pE1c, pE2c, 0);
if( pE && isOuterJoin ){
ExprSetProperty(pE, EP_FromJoin);
pE->iRightJoinTable = iRightJoinTable;
assert( !ExprHasAnyProperty(pE, EP_TokenOnly|EP_Reduced) );
ExprSetIrreducible(pE);
pE->iRightJoinTable = (i16)iRightJoinTable;
}
*ppExpr = sqlite3ExprAnd(pParse->db,*ppExpr, pE);
}
@@ -273,7 +268,9 @@ static void addWhereTerm(
static void setJoinExpr(Expr *p, int iTable){
while( p ){
ExprSetProperty(p, EP_FromJoin);
p->iRightJoinTable = iTable;
assert( !ExprHasAnyProperty(p, EP_TokenOnly|EP_Reduced) );
ExprSetIrreducible(p);
p->iRightJoinTable = (i16)iTable;
setJoinExpr(p->pLeft, iTable);
p = p->pRight;
}
@@ -590,6 +587,8 @@ static void selectInnerLoop(
case SRT_Table:
case SRT_EphemTab: {
int r1 = sqlite3GetTempReg(pParse);
testcase( eDest==SRT_Table );
testcase( eDest==SRT_EphemTab );
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nColumn, r1);
if( pOrderBy ){
pushOntoSorter(pParse, pOrderBy, p, r1);
@@ -658,6 +657,8 @@ static void selectInnerLoop(
*/
case SRT_Coroutine:
case SRT_Output: {
testcase( eDest==SRT_Coroutine );
testcase( eDest==SRT_Output );
if( pOrderBy ){
int r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nColumn, r1);
@@ -799,9 +800,9 @@ static void generateSortTail(
break;
}
#endif
case SRT_Output:
case SRT_Coroutine: {
default: {
int i;
assert( eDest==SRT_Output || eDest==SRT_Coroutine );
testcase( eDest==SRT_Output );
testcase( eDest==SRT_Coroutine );
sqlite3VdbeAddOp2(v, OP_Integer, 1, regRowid);
@@ -818,10 +819,6 @@ static void generateSortTail(
}
break;
}
default: {
/* Do nothing */
break;
}
}
sqlite3ReleaseTempReg(pParse, regRow);
sqlite3ReleaseTempReg(pParse, regRowid);
@@ -870,7 +867,7 @@ static const char *columnType(
char const *zOriginTab = 0;
char const *zOriginCol = 0;
int j;
if( pExpr==0 || pNC->pSrcList==0 ) return 0;
if( NEVER(pExpr==0) || pNC->pSrcList==0 ) return 0;
switch( pExpr->op ){
case TK_AGG_COLUMN:
@@ -882,6 +879,8 @@ static const char *columnType(
Table *pTab = 0; /* Table structure column is extracted from */
Select *pS = 0; /* Select the column is extracted from */
int iCol = pExpr->iColumn; /* Index of column in pTab */
testcase( pExpr->op==TK_AGG_COLUMN );
testcase( pExpr->op==TK_COLUMN );
while( pNC && !pTab ){
SrcList *pTabList = pNC->pSrcList;
for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
@@ -1035,7 +1034,6 @@ static void generateColumnNames(
}
#endif
assert( v!=0 );
if( pParse->colNamesSet || NEVER(v==0) || db->mallocFailed ) return;
pParse->colNamesSet = 1;
fullNames = (db->flags & SQLITE_FullColNames)!=0;
@@ -1044,7 +1042,7 @@ static void generateColumnNames(
for(i=0; i<pEList->nExpr; i++){
Expr *p;
p = pEList->a[i].pExpr;
if( p==0 ) continue;
if( NEVER(p==0) ) continue;
if( pEList->a[i].zName ){
char *zName = pEList->a[i].zName;
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
@@ -1066,7 +1064,7 @@ static void generateColumnNames(
}
if( !shortNames && !fullNames ){
sqlite3VdbeSetColName(v, i, COLNAME_NAME,
sqlite3DbStrNDup(db, (char*)p->span.z, p->span.n), SQLITE_DYNAMIC);
sqlite3DbStrDup(db, pEList->a[i].zSpan), SQLITE_DYNAMIC);
}else if( fullNames ){
char *zName = 0;
zName = sqlite3MPrintf(db, "%s.%s", pTab->zName, zCol);
@@ -1076,7 +1074,7 @@ static void generateColumnNames(
}
}else{
sqlite3VdbeSetColName(v, i, COLNAME_NAME,
sqlite3DbStrNDup(db, (char*)p->span.z, p->span.n), SQLITE_DYNAMIC);
sqlite3DbStrDup(db, pEList->a[i].zSpan), SQLITE_DYNAMIC);
}
}
generateColumnTypes(pParse, pTabList, pEList);
@@ -1133,7 +1131,8 @@ static int selectColumnsFromExprList(
/* Get an appropriate name for the column
*/
p = pEList->a[i].pExpr;
assert( p->pRight==0 || p->pRight->token.z==0 || p->pRight->token.z[0]!=0 );
assert( p->pRight==0 || ExprHasProperty(p->pRight, EP_IntValue)
|| p->pRight->u.zToken==0 || p->pRight->u.zToken[0]!=0 );
if( (zName = pEList->a[i].zName)!=0 ){
/* If the column contains an "AS <name>" phrase, use <name> as the name */
zName = sqlite3DbStrDup(db, zName);
@@ -1141,16 +1140,19 @@ static int selectColumnsFromExprList(
Expr *pColExpr = p; /* The expression that is the result column name */
Table *pTab; /* Table associated with this expression */
while( pColExpr->op==TK_DOT ) pColExpr = pColExpr->pRight;
if( pColExpr->op==TK_COLUMN && (pTab = pColExpr->pTab)!=0 ){
if( pColExpr->op==TK_COLUMN && ALWAYS(pColExpr->pTab!=0) ){
/* For columns use the column name name */
int iCol = pColExpr->iColumn;
pTab = pColExpr->pTab;
if( iCol<0 ) iCol = pTab->iPKey;
zName = sqlite3MPrintf(db, "%s",
iCol>=0 ? pTab->aCol[iCol].zName : "rowid");
}else if( pColExpr->op==TK_ID ){
assert( !ExprHasProperty(pColExpr, EP_IntValue) );
zName = sqlite3MPrintf(db, "%s", pColExpr->u.zToken);
}else{
/* Use the original text of the column expression as its name */
Token *pToken = (pColExpr->span.z?&pColExpr->span:&pColExpr->token);
zName = sqlite3MPrintf(db, "%T", pToken);
zName = sqlite3MPrintf(db, "%s", pEList->a[i].zSpan);
}
}
if( db->mallocFailed ){
@@ -1223,6 +1225,7 @@ static void selectAddColumnTypeAndCollation(
p = a[i].pExpr;
pCol->zType = sqlite3DbStrDup(db, columnType(&sNC, p, 0, 0, 0));
pCol->affinity = sqlite3ExprAffinity(p);
if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_NONE;
pColl = sqlite3ExprCollSeq(pParse, p);
if( pColl ){
pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
@@ -1250,7 +1253,10 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
if( pTab==0 ){
return 0;
}
pTab->dbMem = db->lookaside.bEnabled ? db : 0;
/* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside
** is disabled, so we might as well hard-code pTab->dbMem to NULL. */
assert( db->lookaside.bEnabled==0 );
pTab->dbMem = 0;
pTab->nRef = 1;
pTab->zName = 0;
selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
@@ -1313,29 +1319,24 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
** no rows.
*/
sqlite3ExprCacheClear(pParse);
assert( p->pOffset==0 || p->pLimit!=0 );
if( p->pLimit ){
p->iLimit = iLimit = ++pParse->nMem;
v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
if( NEVER(v==0) ) return; /* VDBE should have already been allocated */
sqlite3ExprCode(pParse, p->pLimit, iLimit);
sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit);
VdbeComment((v, "LIMIT counter"));
sqlite3VdbeAddOp2(v, OP_IfZero, iLimit, iBreak);
}
if( p->pOffset ){
p->iOffset = iOffset = ++pParse->nMem;
if( p->pLimit ){
if( p->pOffset ){
p->iOffset = iOffset = ++pParse->nMem;
pParse->nMem++; /* Allocate an extra register for limit+offset */
}
v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
sqlite3ExprCode(pParse, p->pOffset, iOffset);
sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset);
VdbeComment((v, "OFFSET counter"));
addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iOffset);
sqlite3VdbeAddOp2(v, OP_Integer, 0, iOffset);
sqlite3VdbeJumpHere(v, addr1);
if( p->pLimit ){
sqlite3ExprCode(pParse, p->pOffset, iOffset);
sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset);
VdbeComment((v, "OFFSET counter"));
addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iOffset);
sqlite3VdbeAddOp2(v, OP_Integer, 0, iOffset);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp3(v, OP_Add, iLimit, iOffset, iOffset+1);
VdbeComment((v, "LIMIT+OFFSET"));
addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iLimit);
@@ -1493,11 +1494,9 @@ static int multiSelect(
VdbeComment((v, "Jump ahead if LIMIT reached"));
}
rc = sqlite3Select(pParse, p, &dest);
testcase( rc!=SQLITE_OK );
pDelete = p->pPrior;
p->pPrior = pPrior;
if( rc ){
goto multi_select_end;
}
if( addr ){
sqlite3VdbeJumpHere(v, addr);
}
@@ -1512,6 +1511,8 @@ static int multiSelect(
int addr;
SelectDest uniondest;
testcase( p->op==TK_EXCEPT );
testcase( p->op==TK_UNION );
priorOp = SRT_Union;
if( dest.eDest==priorOp && ALWAYS(!p->pLimit &&!p->pOffset) ){
/* We can reuse a temporary table generated by a SELECT to our
@@ -1559,6 +1560,7 @@ static int multiSelect(
p->pOffset = 0;
uniondest.eDest = op;
rc = sqlite3Select(pParse, p, &uniondest);
testcase( rc!=SQLITE_OK );
/* Query flattening in sqlite3Select() might refill p->pOrderBy.
** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */
sqlite3ExprListDelete(db, p->pOrderBy);
@@ -1570,15 +1572,12 @@ static int multiSelect(
p->pOffset = pOffset;
p->iLimit = 0;
p->iOffset = 0;
if( rc ){
goto multi_select_end;
}
/* Convert the data in the temporary table into whatever form
** it is that we currently need.
*/
if( dest.eDest!=priorOp || unionTab!=dest.iParm ){
*/
assert( unionTab==dest.iParm || dest.eDest!=priorOp );
if( dest.eDest!=priorOp ){
int iCont, iBreak, iStart;
assert( p->pEList );
if( dest.eDest==SRT_Output ){
@@ -1600,7 +1599,7 @@ static int multiSelect(
}
break;
}
case TK_INTERSECT: {
default: assert( p->op==TK_INTERSECT ); {
int tab1, tab2;
int iCont, iBreak, iStart;
Expr *pLimit, *pOffset;
@@ -1642,14 +1641,12 @@ static int multiSelect(
p->pOffset = 0;
intersectdest.iParm = tab2;
rc = sqlite3Select(pParse, p, &intersectdest);
testcase( rc!=SQLITE_OK );
pDelete = p->pPrior;
p->pPrior = pPrior;
sqlite3ExprDelete(db, p->pLimit);
p->pLimit = pLimit;
p->pOffset = pOffset;
if( rc ){
goto multi_select_end;
}
/* Generate code to take the intersection of the two temporary
** tables.
@@ -1802,6 +1799,8 @@ static int generateOutputSubroutine(
case SRT_EphemTab: {
int r1 = sqlite3GetTempReg(pParse);
int r2 = sqlite3GetTempReg(pParse);
testcase( pDest->eDest==SRT_Table );
testcase( pDest->eDest==SRT_EphemTab );
sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iMem, pIn->nMem, r1);
sqlite3VdbeAddOp2(v, OP_NewRowid, pDest->iParm, r2);
sqlite3VdbeAddOp3(v, OP_Insert, pDest->iParm, r1, r2);
@@ -1864,26 +1863,20 @@ static int generateOutputSubroutine(
break;
}
/* Results are stored in a sequence of registers. Then the
** OP_ResultRow opcode is used to cause sqlite3_step() to return
** the next row of result.
/* If none of the above, then the result destination must be
** SRT_Output. This routine is never called with any other
** destination other than the ones handled above or SRT_Output.
**
** For SRT_Output, results are stored in a sequence of registers.
** Then the OP_ResultRow opcode is used to cause sqlite3_step() to
** return the next row of result.
*/
case SRT_Output: {
default: {
assert( pDest->eDest==SRT_Output );
sqlite3VdbeAddOp2(v, OP_ResultRow, pIn->iMem, pIn->nMem);
sqlite3ExprCacheAffinityChange(pParse, pIn->iMem, pIn->nMem);
break;
}
#if !defined(SQLITE_OMIT_TRIGGER)
/* Discard the results. This is used for SELECT statements inside
** the body of a TRIGGER. The purpose of such selects is to call
** user-defined functions that have side effects. We do not care
** about the actual results of the select.
*/
default: {
break;
}
#endif
}
/* Jump to the end of the loop if the LIMIT is reached.
@@ -2032,7 +2025,7 @@ static int multiSelectOrderBy(
assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */
db = pParse->db;
v = pParse->pVdbe;
if( v==0 ) return SQLITE_NOMEM;
assert( v!=0 ); /* Already thrown the error if VDBE alloc failed */
labelEnd = sqlite3VdbeMakeLabel(v);
labelCmpr = sqlite3VdbeMakeLabel(v);
@@ -2058,11 +2051,11 @@ static int multiSelectOrderBy(
if( pItem->iCol==i ) break;
}
if( j==nOrderBy ){
Expr *pNew = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, 0);
Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
if( pNew==0 ) return SQLITE_NOMEM;
pNew->flags |= EP_IntValue;
pNew->iTable = i;
pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew, 0);
pNew->u.iValue = i;
pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
pOrderBy->a[nOrderBy++].iCol = (u16)i;
}
}
@@ -2347,13 +2340,13 @@ static void substSelect(sqlite3*, Select *, int, ExprList *);
** changes to pExpr so that it refers directly to the source table
** of the subquery rather the result set of the subquery.
*/
static void substExpr(
static Expr *substExpr(
sqlite3 *db, /* Report malloc errors to this connection */
Expr *pExpr, /* Expr in which substitution occurs */
int iTable, /* Table to be substituted */
ExprList *pEList /* Substitute expressions */
){
if( pExpr==0 ) return;
if( pExpr==0 ) return 0;
if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
if( pExpr->iColumn<0 ){
pExpr->op = TK_NULL;
@@ -2361,38 +2354,23 @@ static void substExpr(
Expr *pNew;
assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
pNew = pEList->a[pExpr->iColumn].pExpr;
assert( pNew!=0 );
pExpr->op = pNew->op;
assert( pExpr->pLeft==0 );
pExpr->pLeft = sqlite3ExprDup(db, pNew->pLeft, 0);
assert( pExpr->pRight==0 );
pExpr->pRight = sqlite3ExprDup(db, pNew->pRight, 0);
pExpr->iTable = pNew->iTable;
pExpr->pTab = pNew->pTab;
pExpr->iColumn = pNew->iColumn;
pExpr->iAgg = pNew->iAgg;
sqlite3TokenCopy(db, &pExpr->token, &pNew->token);
sqlite3TokenCopy(db, &pExpr->span, &pNew->span);
assert( pExpr->x.pList==0 && pExpr->x.pSelect==0 );
if( ExprHasProperty(pNew, EP_xIsSelect) ){
pExpr->x.pSelect = sqlite3SelectDup(db, pNew->x.pSelect, 0);
}else{
pExpr->x.pList = sqlite3ExprListDup(db, pNew->x.pList, 0);
pNew = sqlite3ExprDup(db, pEList->a[pExpr->iColumn].pExpr, 0);
if( pNew && pExpr->pColl ){
pNew->pColl = pExpr->pColl;
}
pExpr->flags = pNew->flags;
pExpr->pAggInfo = pNew->pAggInfo;
pNew->pAggInfo = 0;
sqlite3ExprDelete(db, pExpr);
pExpr = pNew;
}
}else{
substExpr(db, pExpr->pLeft, iTable, pEList);
substExpr(db, pExpr->pRight, iTable, pEList);
pExpr->pLeft = substExpr(db, pExpr->pLeft, iTable, pEList);
pExpr->pRight = substExpr(db, pExpr->pRight, iTable, pEList);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
substSelect(db, pExpr->x.pSelect, iTable, pEList);
}else{
substExprList(db, pExpr->x.pList, iTable, pEList);
}
}
return pExpr;
}
static void substExprList(
sqlite3 *db, /* Report malloc errors here */
@@ -2403,7 +2381,7 @@ static void substExprList(
int i;
if( pList==0 ) return;
for(i=0; i<pList->nExpr; i++){
substExpr(db, pList->a[i].pExpr, iTable, pEList);
pList->a[i].pExpr = substExpr(db, pList->a[i].pExpr, iTable, pEList);
}
}
static void substSelect(
@@ -2419,8 +2397,8 @@ static void substSelect(
substExprList(db, p->pEList, iTable, pEList);
substExprList(db, p->pGroupBy, iTable, pEList);
substExprList(db, p->pOrderBy, iTable, pEList);
substExpr(db, p->pHaving, iTable, pEList);
substExpr(db, p->pWhere, iTable, pEList);
p->pHaving = substExpr(db, p->pHaving, iTable, pEList);
p->pWhere = substExpr(db, p->pWhere, iTable, pEList);
substSelect(db, p->pPrior, iTable, pEList);
pSrc = p->pSrc;
assert( pSrc ); /* Even for (SELECT 1) we have: pSrc!=0 but pSrc->nSrc==0 */
@@ -2646,9 +2624,11 @@ static int flattenSubquery(
return 0;
}
for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){
testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate );
if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0
|| (pSub1->pPrior && pSub1->op!=TK_ALL)
|| !pSub1->pSrc || pSub1->pSrc->nSrc!=1
|| NEVER(pSub1->pSrc==0) || pSub1->pSrc->nSrc!=1
){
return 0;
}
@@ -2748,8 +2728,10 @@ static int flattenSubquery(
** subquery until code generation is
** complete, since there may still exist Expr.pTab entries that
** refer to the subquery even after flattening. Ticket #3346.
**
** pSubitem->pTab is always non-NULL by test restrictions and tests above.
*/
if( pSubitem->pTab!=0 ){
if( ALWAYS(pSubitem->pTab!=0) ){
Table *pTabToDel = pSubitem->pTab;
if( pTabToDel->nRef==1 ){
pTabToDel->pNextZombie = pParse->pZombieTab;
@@ -2818,6 +2800,7 @@ static int flattenSubquery(
** outer query.
*/
for(i=0; i<nSubSrc; i++){
sqlite3IdListDelete(db, pSrc->a[i+iFrom].pUsing);
pSrc->a[i+iFrom] = pSubSrc->a[i];
memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
}
@@ -2837,16 +2820,17 @@ static int flattenSubquery(
*/
pList = pParent->pEList;
for(i=0; i<pList->nExpr; i++){
Expr *pExpr;
if( pList->a[i].zName==0 && (pExpr = pList->a[i].pExpr)->span.z!=0 ){
pList->a[i].zName =
sqlite3DbStrNDup(db, (char*)pExpr->span.z, pExpr->span.n);
if( pList->a[i].zName==0 ){
const char *zSpan = pList->a[i].zSpan;
if( ALWAYS(zSpan) ){
pList->a[i].zName = sqlite3DbStrDup(db, zSpan);
}
}
}
substExprList(db, pParent->pEList, iParent, pSub->pEList);
if( isAgg ){
substExprList(db, pParent->pGroupBy, iParent, pSub->pEList);
substExpr(db, pParent->pHaving, iParent, pSub->pEList);
pParent->pHaving = substExpr(db, pParent->pHaving, iParent, pSub->pEList);
}
if( pSub->pOrderBy ){
assert( pParent->pOrderBy==0 );
@@ -2864,13 +2848,13 @@ static int flattenSubquery(
assert( pParent->pHaving==0 );
pParent->pHaving = pParent->pWhere;
pParent->pWhere = pWhere;
substExpr(db, pParent->pHaving, iParent, pSub->pEList);
pParent->pHaving = substExpr(db, pParent->pHaving, iParent, pSub->pEList);
pParent->pHaving = sqlite3ExprAnd(db, pParent->pHaving,
sqlite3ExprDup(db, pSub->pHaving, 0));
assert( pParent->pGroupBy==0 );
pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
}else{
substExpr(db, pParent->pWhere, iParent, pSub->pEList);
pParent->pWhere = substExpr(db, pParent->pWhere, iParent, pSub->pEList);
pParent->pWhere = sqlite3ExprAnd(db, pParent->pWhere, pWhere);
}
@@ -2917,14 +2901,15 @@ static u8 minMaxQuery(Select *p){
if( pEList->nExpr!=1 ) return WHERE_ORDERBY_NORMAL;
pExpr = pEList->a[0].pExpr;
if( ExprHasProperty(pExpr, EP_xIsSelect) ) return 0;
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
if( NEVER(ExprHasProperty(pExpr, EP_xIsSelect)) ) return 0;
pEList = pExpr->x.pList;
if( pExpr->op!=TK_AGG_FUNCTION || pEList==0 || pEList->nExpr!=1 ) return 0;
if( pEList==0 || pEList->nExpr!=1 ) return 0;
if( pEList->a[0].pExpr->op!=TK_AGG_COLUMN ) return WHERE_ORDERBY_NORMAL;
if( pExpr->token.n!=3 ) return WHERE_ORDERBY_NORMAL;
if( sqlite3StrNICmp((char*)pExpr->token.z,"min",3)==0 ){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
if( sqlite3StrICmp(pExpr->u.zToken,"min")==0 ){
return WHERE_ORDERBY_MIN;
}else if( sqlite3StrNICmp((char*)pExpr->token.z,"max",3)==0 ){
}else if( sqlite3StrICmp(pExpr->u.zToken,"max")==0 ){
return WHERE_ORDERBY_MAX;
}
return WHERE_ORDERBY_NORMAL;
@@ -3024,7 +3009,7 @@ static int selectExpander(Walker *pWalker, Select *p){
if( db->mallocFailed ){
return WRC_Abort;
}
if( p->pSrc==0 || (p->selFlags & SF_Expanded)!=0 ){
if( NEVER(p->pSrc==0) || (p->selFlags & SF_Expanded)!=0 ){
return WRC_Prune;
}
p->selFlags |= SF_Expanded;
@@ -3076,16 +3061,9 @@ static int selectExpander(Walker *pWalker, Select *p){
if( pTab->pSelect || IsVirtual(pTab) ){
/* We reach here if the named table is a really a view */
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
/* If pFrom->pSelect!=0 it means we are dealing with a
** view within a view. The SELECT structure has already been
** copied by the outer view so we can skip the copy step here
** in the inner view.
*/
if( pFrom->pSelect==0 ){
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
sqlite3WalkSelect(pWalker, pFrom->pSelect);
}
assert( pFrom->pSelect==0 );
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
sqlite3WalkSelect(pWalker, pFrom->pSelect);
}
#endif
}
@@ -3115,8 +3093,9 @@ static int selectExpander(Walker *pWalker, Select *p){
for(k=0; k<pEList->nExpr; k++){
Expr *pE = pEList->a[k].pExpr;
if( pE->op==TK_ALL ) break;
if( pE->op==TK_DOT && pE->pRight && pE->pRight->op==TK_ALL
&& pE->pLeft && pE->pLeft->op==TK_ID ) break;
assert( pE->op!=TK_DOT || pE->pRight!=0 );
assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
if( pE->op==TK_DOT && pE->pRight->op==TK_ALL ) break;
}
if( k<pEList->nExpr ){
/*
@@ -3132,30 +3111,34 @@ static int selectExpander(Walker *pWalker, Select *p){
for(k=0; k<pEList->nExpr; k++){
Expr *pE = a[k].pExpr;
if( pE->op!=TK_ALL &&
(pE->op!=TK_DOT || pE->pRight==0 || pE->pRight->op!=TK_ALL) ){
assert( pE->op!=TK_DOT || pE->pRight!=0 );
if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pE->pRight->op!=TK_ALL) ){
/* This particular expression does not need to be expanded.
*/
pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr, 0);
pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
if( pNew ){
pNew->a[pNew->nExpr-1].zName = a[k].zName;
pNew->a[pNew->nExpr-1].zSpan = a[k].zSpan;
a[k].zName = 0;
a[k].zSpan = 0;
}
a[k].pExpr = 0;
a[k].zName = 0;
}else{
/* This expression is a "*" or a "TABLE.*" and needs to be
** expanded. */
int tableSeen = 0; /* Set to 1 when TABLE matches */
char *zTName; /* text of name of TABLE */
if( pE->op==TK_DOT && pE->pLeft ){
zTName = sqlite3NameFromToken(db, &pE->pLeft->token);
if( pE->op==TK_DOT ){
assert( pE->pLeft!=0 );
assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
zTName = pE->pLeft->u.zToken;
}else{
zTName = 0;
}
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
Table *pTab = pFrom->pTab;
char *zTabName = pFrom->zAlias;
if( zTabName==0 || zTabName[0]==0 ){
if( zTabName==0 ){
zTabName = pTab->zName;
}
if( db->mallocFailed ) break;
@@ -3166,6 +3149,9 @@ static int selectExpander(Walker *pWalker, Select *p){
for(j=0; j<pTab->nCol; j++){
Expr *pExpr, *pRight;
char *zName = pTab->aCol[j].zName;
char *zColname; /* The computed column name */
char *zToFree; /* Malloced string that needs to be freed */
Token sColname; /* Computed column name as a token */
/* If a column is marked as 'hidden' (currently only possible
** for virtual tables), do not include it in the expanded
@@ -3190,30 +3176,25 @@ static int selectExpander(Walker *pWalker, Select *p){
continue;
}
}
pRight = sqlite3PExpr(pParse, TK_ID, 0, 0, 0);
if( pRight==0 ) break;
setToken(&pRight->token, zName);
pRight = sqlite3Expr(db, TK_ID, zName);
zColname = zName;
zToFree = 0;
if( longNames || pTabList->nSrc>1 ){
Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, 0);
Expr *pLeft;
pLeft = sqlite3Expr(db, TK_ID, zTabName);
pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
if( pExpr==0 ) break;
setToken(&pLeft->token, zTabName);
setToken(&pExpr->span,
sqlite3MPrintf(db, "%s.%s", zTabName, zName));
pExpr->span.dyn = 1;
pExpr->token.z = 0;
pExpr->token.n = 0;
pExpr->token.dyn = 0;
if( longNames ){
zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
zToFree = zColname;
}
}else{
pExpr = pRight;
pExpr->span = pExpr->token;
pExpr->span.dyn = 0;
}
if( longNames ){
pNew = sqlite3ExprListAppend(pParse, pNew, pExpr, &pExpr->span);
}else{
pNew = sqlite3ExprListAppend(pParse, pNew, pExpr, &pRight->token);
}
pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
sColname.z = zColname;
sColname.n = sqlite3Strlen30(zColname);
sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
sqlite3DbFree(db, zToFree);
}
}
if( !tableSeen ){
@@ -3223,7 +3204,6 @@ static int selectExpander(Walker *pWalker, Select *p){
sqlite3ErrorMsg(pParse, "no tables specified");
}
}
sqlite3DbFree(db, zTName);
}
}
sqlite3ExprListDelete(db, pEList);
@@ -3294,19 +3274,18 @@ static int selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
struct SrcList_item *pFrom;
assert( p->selFlags & SF_Resolved );
if( (p->selFlags & SF_HasTypeInfo)==0 ){
p->selFlags |= SF_HasTypeInfo;
pParse = pWalker->pParse;
pTabList = p->pSrc;
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
Table *pTab = pFrom->pTab;
if( pTab && (pTab->tabFlags & TF_Ephemeral)!=0 ){
/* A sub-query in the FROM clause of a SELECT */
Select *pSel = pFrom->pSelect;
assert( pSel );
while( pSel->pPrior ) pSel = pSel->pPrior;
selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSel);
}
assert( (p->selFlags & SF_HasTypeInfo)==0 );
p->selFlags |= SF_HasTypeInfo;
pParse = pWalker->pParse;
pTabList = p->pSrc;
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
Table *pTab = pFrom->pTab;
if( ALWAYS(pTab!=0) && (pTab->tabFlags & TF_Ephemeral)!=0 ){
/* A sub-query in the FROM clause of a SELECT */
Select *pSel = pFrom->pSelect;
assert( pSel );
while( pSel->pPrior ) pSel = pSel->pPrior;
selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSel);
}
}
return WRC_Continue;
@@ -3350,10 +3329,9 @@ void sqlite3SelectPrep(
NameContext *pOuterNC /* Name context for container */
){
sqlite3 *db;
if( p==0 ) return;
if( NEVER(p==0) ) return;
db = pParse->db;
if( p->selFlags & SF_HasTypeInfo ) return;
if( pParse->nErr || db->mallocFailed ) return;
sqlite3SelectExpand(pParse, p);
if( pParse->nErr || db->mallocFailed ) return;
sqlite3ResolveSelectNames(pParse, p, pOuterNC);
@@ -3557,38 +3535,24 @@ int sqlite3Select(
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
memset(&sAggInfo, 0, sizeof(sAggInfo));
pOrderBy = p->pOrderBy;
if( IgnorableOrderby(pDest) ){
p->pOrderBy = 0;
/* In these cases the DISTINCT operator makes no difference to the
** results, so remove it if it were specified.
*/
assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union ||
pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard);
/* If ORDER BY makes no difference in the output then neither does
** DISTINCT so it can be removed too. */
sqlite3ExprListDelete(db, p->pOrderBy);
p->pOrderBy = 0;
p->selFlags &= ~SF_Distinct;
}
sqlite3SelectPrep(pParse, p, 0);
pOrderBy = p->pOrderBy;
pTabList = p->pSrc;
pEList = p->pEList;
if( pParse->nErr || db->mallocFailed ){
goto select_end;
}
p->pOrderBy = pOrderBy;
isAgg = (p->selFlags & SF_Aggregate)!=0;
if( pEList==0 ) goto select_end;
/*
** Do not even attempt to generate any code if we have already seen
** errors before this routine starts.
*/
if( pParse->nErr>0 ) goto select_end;
/* ORDER BY is ignored for some destinations.
*/
if( IgnorableOrderby(pDest) ){
pOrderBy = 0;
}
assert( pEList!=0 );
/* Begin generating code.
*/
@@ -3629,7 +3593,7 @@ int sqlite3Select(
sqlite3Select(pParse, pSub, &dest);
pItem->isPopulated = 1;
}
if( pParse->nErr || db->mallocFailed ){
if( /*pParse->nErr ||*/ db->mallocFailed ){
goto select_end;
}
pParse->nHeight -= sqlite3SelectExprHeight(p);
@@ -3680,7 +3644,8 @@ int sqlite3Select(
/* If possible, rewrite the query to use GROUP BY instead of DISTINCT.
** GROUP BY might use an index, DISTINCT never does.
*/
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct && !p->pGroupBy ){
assert( p->pGroupBy==0 || (p->selFlags & SF_Aggregate)!=0 );
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ){
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
pGroupBy = p->pGroupBy;
p->selFlags &= ~SF_Distinct;
@@ -3998,9 +3963,7 @@ int sqlite3Select(
VdbeComment((v, "Groupby result generator entry point"));
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
finalizeAggFunctions(pParse, &sAggInfo);
if( pHaving ){
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
}
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
selectInnerLoop(pParse, p, p->pEList, 0, 0, pOrderBy,
distinct, pDest,
addrOutputRow+1, addrSetAbort);
@@ -4013,7 +3976,7 @@ int sqlite3Select(
resetAccumulator(pParse, &sAggInfo);
sqlite3VdbeAddOp1(v, OP_Return, regReset);
} /* endif pGroupBy */
} /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
else {
ExprList *pDel = 0;
#ifndef SQLITE_OMIT_BTREECOUNT
@@ -4131,9 +4094,7 @@ int sqlite3Select(
}
pOrderBy = 0;
if( pHaving ){
sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
}
sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, -1,
pDest, addrEnd, addrEnd);
sqlite3ExprListDelete(db, pDel);
@@ -4190,8 +4151,8 @@ select_end:
** or from temporary "printf" statements inserted for debugging.
*/
void sqlite3PrintExpr(Expr *p){
if( p->token.z && p->token.n>0 ){
sqlite3DebugPrintf("(%.*s", p->token.n, p->token.z);
if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
sqlite3DebugPrintf("(%s", p->u.zToken);
}else{
sqlite3DebugPrintf("(%d", p->op);
}
+35 -12
View File
@@ -12,7 +12,7 @@
** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases.
**
** $Id: shell.c,v 1.207 2009/03/16 10:59:44 drh Exp $
** $Id: shell.c,v 1.210 2009/05/31 17:16:10 drh Exp $
*/
#if defined(_WIN32) || defined(WIN32)
/* This needs to come before any includes for MSVC compiler */
@@ -623,8 +623,15 @@ static void multireplace(
}
}
if( (nOut+nCopy)>nMalloc ){
char *zNew;
nMalloc = 16 + (nOut+nCopy)*2;
zOut = (char *)sqlite3_realloc(zOut, nMalloc);
zNew = (char*)sqlite3_realloc(zOut, nMalloc);
if( zNew==0 ){
sqlite3_result_error_nomem(context);
return;
}else{
zOut = zNew;
}
}
assert( nMalloc>=(nOut+nCopy) );
memcpy(&zOut[nOut], zCopy, nCopy);
@@ -1644,7 +1651,12 @@ static char *appendText(char *zIn, char const *zAppend, char quote){
** This is used, for example, to show the schema of the database by
** querying the SQLITE_MASTER table.
*/
static int run_table_dump_query(FILE *out, sqlite3 *db, const char *zSelect){
static int run_table_dump_query(
FILE *out, /* Send output here */
sqlite3 *db, /* Database to query */
const char *zSelect, /* SELECT statement to extract content */
const char *zFirstRow /* Print before first row, if not NULL */
){
sqlite3_stmt *pSelect;
int rc;
rc = sqlite3_prepare(db, zSelect, -1, &pSelect, 0);
@@ -1653,6 +1665,10 @@ static int run_table_dump_query(FILE *out, sqlite3 *db, const char *zSelect){
}
rc = sqlite3_step(pSelect);
while( rc==SQLITE_ROW ){
if( zFirstRow ){
fprintf(out, "%s", zFirstRow);
zFirstRow = 0;
}
fprintf(out, "%s;\n", sqlite3_column_text(pSelect, 0));
rc = sqlite3_step(pSelect);
}
@@ -1671,6 +1687,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
const char *zTable;
const char *zType;
const char *zSql;
const char *zPrepStmt = 0;
struct callback_data *p = (struct callback_data *)pArg;
UNUSED_PARAMETER(azCol);
@@ -1680,7 +1697,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
zSql = azArg[2];
if( strcmp(zTable, "sqlite_sequence")==0 ){
fprintf(p->out, "DELETE FROM sqlite_sequence;\n");
zPrepStmt = "DELETE FROM sqlite_sequence;\n";
}else if( strcmp(zTable, "sqlite_stat1")==0 ){
fprintf(p->out, "ANALYZE sqlite_master;\n");
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
@@ -1707,13 +1724,14 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
char *zSelect = 0;
char *zTableInfo = 0;
char *zTmp = 0;
int nRow = 0;
zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
zTableInfo = appendText(zTableInfo, zTable, '"');
zTableInfo = appendText(zTableInfo, ");", 0);
rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);
if( zTableInfo ) free(zTableInfo);
free(zTableInfo);
if( rc!=SQLITE_OK || !pTableInfo ){
return 1;
}
@@ -1735,19 +1753,20 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
}else{
zSelect = appendText(zSelect, ") ", 0);
}
nRow++;
}
rc = sqlite3_finalize(pTableInfo);
if( rc!=SQLITE_OK ){
if( zSelect ) free(zSelect);
if( rc!=SQLITE_OK || nRow==0 ){
free(zSelect);
return 1;
}
zSelect = appendText(zSelect, "|| ')' FROM ", 0);
zSelect = appendText(zSelect, zTable, '"');
rc = run_table_dump_query(p->out, p->db, zSelect);
rc = run_table_dump_query(p->out, p->db, zSelect, zPrepStmt);
if( rc==SQLITE_CORRUPT ){
zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
rc = run_table_dump_query(p->out, p->db, zSelect);
rc = run_table_dump_query(p->out, p->db, zSelect, 0);
}
if( zSelect ) free(zSelect);
}
@@ -2080,11 +2099,15 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( nArg==1 ){
run_schema_dump_query(p,
"SELECT name, type, sql FROM sqlite_master "
"WHERE sql NOT NULL AND type=='table'", 0
"WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'", 0
);
run_schema_dump_query(p,
"SELECT name, type, sql FROM sqlite_master "
"WHERE name=='sqlite_sequence'", 0
);
run_table_dump_query(p->out, p->db,
"SELECT sql FROM sqlite_master "
"WHERE sql NOT NULL AND type IN ('index','trigger','view')"
"WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
);
}else{
int i;
@@ -2098,7 +2121,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
"SELECT sql FROM sqlite_master "
"WHERE sql NOT NULL"
" AND type IN ('index','trigger','view')"
" AND tbl_name LIKE shellstatic()"
" AND tbl_name LIKE shellstatic()", 0
);
zShellStatic = 0;
}
+160 -54
View File
@@ -30,7 +30,7 @@
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
**
** @(#) $Id: sqlite.h.in,v 1.447 2009/04/30 15:59:56 drh Exp $
** @(#) $Id: sqlite.h.in,v 1.462 2009/08/06 17:40:46 drh Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
@@ -392,20 +392,20 @@ int sqlite3_exec(
** in the 4th parameter to the xOpen method of the
** [sqlite3_vfs] object.
*/
#define SQLITE_OPEN_READONLY 0x00000001
#define SQLITE_OPEN_READWRITE 0x00000002
#define SQLITE_OPEN_CREATE 0x00000004
#define SQLITE_OPEN_DELETEONCLOSE 0x00000008
#define SQLITE_OPEN_EXCLUSIVE 0x00000010
#define SQLITE_OPEN_MAIN_DB 0x00000100
#define SQLITE_OPEN_TEMP_DB 0x00000200
#define SQLITE_OPEN_TRANSIENT_DB 0x00000400
#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800
#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000
#define SQLITE_OPEN_SUBJOURNAL 0x00002000
#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000
#define SQLITE_OPEN_NOMUTEX 0x00008000
#define SQLITE_OPEN_FULLMUTEX 0x00010000
#define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */
#define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */
#define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */
#define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */
#define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */
#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */
#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */
#define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */
#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
#define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
/*
** CAPI3REF: Device Characteristics {H10240} <H11120>
@@ -494,6 +494,12 @@ struct sqlite3_file {
** This object defines the methods used to perform various operations
** against the open file represented by the [sqlite3_file] object.
**
** If the xOpen method sets the sqlite3_file.pMethods element
** to a non-NULL pointer, then the sqlite3_io_methods.xClose method
** may be invoked even if the xOpen reported that it failed. The
** only way to prevent a call to xClose following a failed xOpen
** is for the xOpen to set the sqlite3_file.pMethods element to NULL.
**
** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or
** [SQLITE_SYNC_FULL]. The first choice is the normal fsync().
** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY]
@@ -654,11 +660,11 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** is either a NULL pointer or string obtained
** from xFullPathname(). SQLite further guarantees that
** the string will be valid and unchanged until xClose() is
** called. Because of the previous sentense,
** called. Because of the previous sentence,
** the [sqlite3_file] can safely store a pointer to the
** filename if it needs to remember the filename for some reason.
** If the zFilename parameter is xOpen is a NULL pointer then xOpen
** must invite its own temporary name for the file. Whenever the
** must invent its own temporary name for the file. Whenever the
** xFilename parameter is NULL it will also be the case that the
** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE].
**
@@ -702,14 +708,24 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** deleted when it is closed. The [SQLITE_OPEN_DELETEONCLOSE]
** will be set for TEMP databases, journals and for subjournals.
**
** The [SQLITE_OPEN_EXCLUSIVE] flag means the file should be opened
** for exclusive access. This flag is set for all files except
** for the main database file.
** The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction
** with the [SQLITE_OPEN_CREATE] flag, which are both directly
** analogous to the O_EXCL and O_CREAT flags of the POSIX open()
** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the
** SQLITE_OPEN_CREATE, is used to indicate that file should always
** be created, and that it is an error if it already exists.
** It is <i>not</i> used to indicate the file should be opened
** for exclusive access.
**
** At least szOsFile bytes of memory are allocated by SQLite
** to hold the [sqlite3_file] structure passed as the third
** argument to xOpen. The xOpen method does not have to
** allocate the structure; it should just fill it in.
** allocate the structure; it should just fill it in. Note that
** the xOpen method must set the sqlite3_file.pMethods to either
** a valid [sqlite3_io_methods] object or to NULL. xOpen must do
** this even if the open fails. SQLite expects that the sqlite3_file.pMethods
** element will be valid after xOpen returns regardless of the success
** or failure of the xOpen call.
**
** The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to
@@ -1031,12 +1047,14 @@ struct sqlite3_mem_methods {
**
** <dt>SQLITE_CONFIG_SCRATCH</dt>
** <dd>This option specifies a static memory buffer that SQLite can use for
** scratch memory. There are three arguments: A pointer to the memory, the
** size of each scratch buffer (sz), and the number of buffers (N). The sz
** scratch memory. There are three arguments: A pointer an 8-byte
** aligned memory buffer from which the scrach allocations will be
** drawn, the size of each scratch allocation (sz),
** and the maximum number of scratch allocations (N). The sz
** argument must be a multiple of 16. The sz parameter should be a few bytes
** larger than the actual scratch space required due internal overhead.
** The first
** argument should point to an allocation of at least sz*N bytes of memory.
** larger than the actual scratch space required due to internal overhead.
** The first argument should pointer to an 8-byte aligned buffer
** of at least sz*N bytes of memory.
** SQLite will use no more than one scratch buffer at once per thread, so
** N should be set to the expected maximum number of threads. The sz
** parameter should be 6 times the size of the largest database page size.
@@ -1050,29 +1068,37 @@ struct sqlite3_mem_methods {
** the database page cache with the default page cache implemenation.
** This configuration should not be used if an application-define page
** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option.
** There are three arguments to this option: A pointer to the
** There are three arguments to this option: A pointer to 8-byte aligned
** memory, the size of each page buffer (sz), and the number of pages (N).
** The sz argument must be a power of two between 512 and 32768. The first
** The sz argument should be the size of the largest database page
** (a power of two between 512 and 32768) plus a little extra for each
** page header. The page header size is 20 to 40 bytes depending on
** the host architecture. It is harmless, apart from the wasted memory,
** to make sz a little too large. The first
** argument should point to an allocation of at least sz*N bytes of memory.
** SQLite will use the memory provided by the first argument to satisfy its
** memory needs for the first N pages that it adds to cache. If additional
** page cache memory is needed beyond what is provided by this option, then
** SQLite goes to [sqlite3_malloc()] for the additional storage space.
** The implementation might use one or more of the N buffers to hold
** memory accounting information. </dd>
** memory accounting information. The pointer in the first argument must
** be aligned to an 8-byte boundary or subsequent behavior of SQLite
** will be undefined.</dd>
**
** <dt>SQLITE_CONFIG_HEAP</dt>
** <dd>This option specifies a static memory buffer that SQLite will use
** for all of its dynamic memory allocation needs beyond those provided
** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE].
** There are three arguments: A pointer to the memory, the number of
** bytes in the memory buffer, and the minimum allocation size. If
** the first pointer (the memory pointer) is NULL, then SQLite reverts
** There are three arguments: An 8-byte aligned pointer to the memory,
** the number of bytes in the memory buffer, and the minimum allocation size.
** If the first pointer (the memory pointer) is NULL, then SQLite reverts
** to using its default memory allocator (the system malloc() implementation),
** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. If the
** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
** allocator is engaged to handle all of SQLites memory allocation needs.</dd>
** allocator is engaged to handle all of SQLites memory allocation needs.
** The first pointer (the memory pointer) must be aligned to an 8-byte
** boundary or subsequent behavior of SQLite will be undefined.</dd>
**
** <dt>SQLITE_CONFIG_MUTEX</dt>
** <dd>This option takes a single argument which is a pointer to an
@@ -1143,9 +1169,9 @@ struct sqlite3_mem_methods {
** <dd>This option takes three additional arguments that determine the
** [lookaside memory allocator] configuration for the [database connection].
** The first argument (the third parameter to [sqlite3_db_config()] is a
** pointer to a memory buffer to use for lookaside memory. The first
** argument may be NULL in which case SQLite will allocate the lookaside
** buffer itself using [sqlite3_malloc()]. The second argument is the
** pointer to an 8-byte aligned memory buffer to use for lookaside memory.
** The first argument may be NULL in which case SQLite will allocate the
** lookaside buffer itself using [sqlite3_malloc()]. The second argument is the
** size of each lookaside buffer slot and the third argument is the number of
** slots. The size of the buffer in the first argument must be greater than
** or equal to the product of the second and third arguments.</dd>
@@ -1277,9 +1303,9 @@ int sqlite3_changes(sqlite3*);
** [CREATE TRIGGER | trigger] contexts. However,
** the count does not include changes used to implement [REPLACE] constraints,
** do rollbacks or ABORT processing, or [DROP TABLE] processing. The
** count does not rows of views that fire an [INSTEAD OF trigger], though if
** the INSTEAD OF trigger makes changes of its own, those changes are
** counted.
** count does not include rows of views that fire an [INSTEAD OF trigger],
** though if the INSTEAD OF trigger makes changes of its own, those changes
** are counted.
** The changes are counted as soon as the statement that makes them is
** completed (when the statement handle is passed to [sqlite3_reset()] or
** [sqlite3_finalize()]).
@@ -3069,8 +3095,11 @@ int sqlite3_reset(sqlite3_stmt *pStmt);
**
** The third parameter (nArg)
** is the number of arguments that the SQL function or
** aggregate takes. If this parameter is negative, then the SQL function or
** aggregate may take any number of arguments.
** aggregate takes. If this parameter is -1, then the SQL function or
** aggregate may take any number of arguments between 0 and the limit
** set by [sqlite3_limit]([SQLITE_LIMIT_FUNCTION_ARG]). If the third
** parameter is less than -1 or greater than 127 then the behavior is
** undefined.
**
** The fourth parameter, eTextRep, specifies what
** [SQLITE_UTF8 | text encoding] this SQL function prefers for
@@ -3121,7 +3150,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt);
** statement in which the function is running.
**
** Requirements:
** [H16103] [H16106] [H16109] [H16112] [H16118] [H16121] [H16124] [H16127]
** [H16103] [H16106] [H16109] [H16112] [H16118] [H16121] [H16127]
** [H16130] [H16133] [H16136] [H16139] [H16142]
*/
int sqlite3_create_function(
@@ -3736,11 +3765,11 @@ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
** CAPI3REF: Commit And Rollback Notification Callbacks {H12950} <S60400>
**
** The sqlite3_commit_hook() interface registers a callback
** function to be invoked whenever a transaction is committed.
** function to be invoked whenever a transaction is [COMMIT | committed].
** Any callback set by a previous call to sqlite3_commit_hook()
** for the same database connection is overridden.
** The sqlite3_rollback_hook() interface registers a callback
** function to be invoked whenever a transaction is committed.
** function to be invoked whenever a transaction is [ROLLBACK | rolled back].
** Any callback set by a previous call to sqlite3_commit_hook()
** for the same database connection is overridden.
** The pArg argument is passed through to the callback.
@@ -3760,6 +3789,12 @@ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
**
** Registering a NULL function disables the callback.
**
** When the commit hook callback routine returns zero, the [COMMIT]
** operation is allowed to continue normally. If the commit hook
** returns non-zero, then the [COMMIT] is converted into a [ROLLBACK].
** The rollback hook is invoked on a rollback that results from a commit
** hook returning non-zero, just as it would be with any other rollback.
**
** For the purposes of this API, a transaction is said to have been
** rolled back if an explicit "ROLLBACK" statement is executed, or
** an error or constraint causes an implicit rollback to occur.
@@ -3769,6 +3804,8 @@ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
** rolled back because a commit callback returned non-zero.
** <todo> Check on this </todo>
**
** See also the [sqlite3_update_hook()] interface.
**
** Requirements:
** [H12951] [H12952] [H12953] [H12954] [H12955]
** [H12961] [H12962] [H12963] [H12964]
@@ -3800,6 +3837,13 @@ void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** The update hook is not invoked when internal system tables are
** modified (i.e. sqlite_master and sqlite_sequence).
**
** In the current implementation, the update hook
** is not invoked when duplication rows are deleted because of an
** [ON CONFLICT | ON CONFLICT REPLACE] clause. Nor is the update hook
** invoked when rows are deleted using the [truncate optimization].
** The exceptions defined in this paragraph might change in a future
** release of SQLite.
**
** The update hook implementation must not do anything that will modify
** the database connection that invoked the update hook. Any actions
** to modify the database connection must be deferred until after the
@@ -3810,6 +3854,9 @@ void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** If another function was previously registered, its pArg value
** is returned. Otherwise NULL is returned.
**
** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()]
** interfaces.
**
** Requirements:
** [H12971] [H12973] [H12975] [H12977] [H12979] [H12981] [H12983] [H12986]
*/
@@ -3821,7 +3868,7 @@ void *sqlite3_update_hook(
/*
** CAPI3REF: Enable Or Disable Shared Pager Cache {H10330} <S30900>
** KEYWORDS: {shared cache} {shared cache mode}
** KEYWORDS: {shared cache}
**
** This routine enables or disables the sharing of the database cache
** and schema data structures between [database connection | connections]
@@ -4284,7 +4331,7 @@ SQLITE_EXPERIMENTAL int sqlite3_create_module_v2(
*/
struct sqlite3_vtab {
const sqlite3_module *pModule; /* The module for this virtual table */
int nRef; /* Used internally */
int nRef; /* NO LONGER USED */
char *zErrMsg; /* Error message from sqlite3_mprintf() */
/* Virtual table implementations will typically add additional fields */
};
@@ -4379,7 +4426,7 @@ typedef struct sqlite3_blob sqlite3_blob;
** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
** </pre> {END}
**
** If the flags parameter is non-zero, the the BLOB is opened for read
** If the flags parameter is non-zero, then the BLOB is opened for read
** and write access. If it is zero, the BLOB is opened for read access.
**
** Note that the database name is not the filename that contains
@@ -4389,10 +4436,13 @@ typedef struct sqlite3_blob sqlite3_blob;
** For TEMP tables, the database name is "temp".
**
** On success, [SQLITE_OK] is returned and the new [BLOB handle] is written
** to *ppBlob. Otherwise an [error code] is returned and any value written
** to *ppBlob should not be used by the caller.
** to *ppBlob. Otherwise an [error code] is returned and *ppBlob is set
** to be a null pointer.
** This function sets the [database connection] error code and message
** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()].
** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()] and related
** functions. Note that the *ppBlob variable is always initialized in a
** way that makes it safe to invoke [sqlite3_blob_close()] on *ppBlob
** regardless of the success or failure of this routine.
**
** If the row that a BLOB handle points to is modified by an
** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
@@ -4405,6 +4455,19 @@ typedef struct sqlite3_blob sqlite3_blob;
** rollback by the expiration of the BLOB. Such changes will eventually
** commit if the transaction continues to completion.
**
** Use the [sqlite3_blob_bytes()] interface to determine the size of
** the opened blob. The size of a blob may not be changed by this
** underface. Use the [UPDATE] SQL command to change the size of a
** blob.
**
** The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces
** and the built-in [zeroblob] SQL function can be used, if desired,
** to create an empty, zero-filled blob in which to read or write using
** this interface.
**
** To avoid a resource leak, every open [BLOB handle] should eventually
** be released by a call to [sqlite3_blob_close()].
**
** Requirements:
** [H17813] [H17814] [H17816] [H17819] [H17821] [H17824]
*/
@@ -4427,16 +4490,19 @@ int sqlite3_blob_open(
** if there are no other BLOBs, no pending prepared statements, and the
** database connection is in [autocommit mode].
** If any writes were made to the BLOB, they might be held in cache
** until the close operation if they will fit. {END}
** until the close operation if they will fit.
**
** Closing the BLOB often forces the changes
** out to disk and so if any I/O errors occur, they will likely occur
** at the time when the BLOB is closed. {H17833} Any errors that occur during
** at the time when the BLOB is closed. Any errors that occur during
** closing are reported as a non-zero return value.
**
** The BLOB is closed unconditionally. Even if this routine returns
** an error code, the BLOB is still closed.
**
** Calling this routine with a null pointer (which as would be returned
** by failed call to [sqlite3_blob_open()]) is a harmless no-op.
**
** Requirements:
** [H17833] [H17836] [H17839]
*/
@@ -4445,8 +4511,15 @@ int sqlite3_blob_close(sqlite3_blob *);
/*
** CAPI3REF: Return The Size Of An Open BLOB {H17840} <S30230>
**
** Returns the size in bytes of the BLOB accessible via the open
** []BLOB handle] in its only argument.
** Returns the size in bytes of the BLOB accessible via the
** successfully opened [BLOB handle] in its only argument. The
** incremental blob I/O routines can only read or overwriting existing
** blob content; they cannot change the size of a blob.
**
** This routine only works on a [BLOB handle] which has been created
** by a prior successful call to [sqlite3_blob_open()] and which has not
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
** to this routine results in undefined and probably undesirable behavior.
**
** Requirements:
** [H17843]
@@ -4463,6 +4536,8 @@ int sqlite3_blob_bytes(sqlite3_blob *);
** If offset iOffset is less than N bytes from the end of the BLOB,
** [SQLITE_ERROR] is returned and no data is read. If N or iOffset is
** less than zero, [SQLITE_ERROR] is returned and no data is read.
** The size of the blob (and hence the maximum value of N+iOffset)
** can be determined using the [sqlite3_blob_bytes()] interface.
**
** An attempt to read from an expired [BLOB handle] fails with an
** error code of [SQLITE_ABORT].
@@ -4470,6 +4545,13 @@ int sqlite3_blob_bytes(sqlite3_blob *);
** On success, SQLITE_OK is returned.
** Otherwise, an [error code] or an [extended error code] is returned.
**
** This routine only works on a [BLOB handle] which has been created
** by a prior successful call to [sqlite3_blob_open()] and which has not
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
** to this routine results in undefined and probably undesirable behavior.
**
** See also: [sqlite3_blob_write()].
**
** Requirements:
** [H17853] [H17856] [H17859] [H17862] [H17863] [H17865] [H17868]
*/
@@ -4491,6 +4573,8 @@ int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
** If offset iOffset is less than N bytes from the end of the BLOB,
** [SQLITE_ERROR] is returned and no data is written. If N is
** less than zero [SQLITE_ERROR] is returned and no data is written.
** The size of the BLOB (and hence the maximum value of N+iOffset)
** can be determined using the [sqlite3_blob_bytes()] interface.
**
** An attempt to write to an expired [BLOB handle] fails with an
** error code of [SQLITE_ABORT]. Writes to the BLOB that occurred
@@ -4502,6 +4586,13 @@ int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
** On success, SQLITE_OK is returned.
** Otherwise, an [error code] or an [extended error code] is returned.
**
** This routine only works on a [BLOB handle] which has been created
** by a prior successful call to [sqlite3_blob_open()] and which has not
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
** to this routine results in undefined and probably undesirable behavior.
**
** See also: [sqlite3_blob_read()].
**
** Requirements:
** [H17873] [H17874] [H17875] [H17876] [H17877] [H17879] [H17882] [H17885]
** [H17888]
@@ -4852,6 +4943,9 @@ int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_FAULT_INSTALL 9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
#define SQLITE_TESTCTRL_PENDING_BYTE 11
#define SQLITE_TESTCTRL_ASSERT 12
#define SQLITE_TESTCTRL_ALWAYS 13
#define SQLITE_TESTCTRL_RESERVE 14
/*
** CAPI3REF: SQLite Runtime Status {H17200} <S60200>
@@ -5519,6 +5613,18 @@ int sqlite3_unlock_notify(
void *pNotifyArg /* Argument to pass to xNotify */
);
/*
** CAPI3REF: String Comparison
** EXPERIMENTAL
**
** The [sqlite3_strnicmp()] API allows applications and extensions to
** compare the contents of two buffers containing UTF-8 strings in a
** case-indendent fashion, using the same definition of case independence
** that SQLite uses internally when comparing identifiers.
*/
int sqlite3_strnicmp(const char *, const char *, int);
/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
+240 -107
View File
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.868 2009/05/04 11:42:30 danielk1977 Exp $
** @(#) $Id: sqliteInt.h,v 1.898 2009/08/10 03:57:58 shane Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -51,21 +51,36 @@
#endif
/*
* This macro is used to "hide" some ugliness in casting an int
* value to a ptr value under the MSVC 64-bit compiler. Casting
* non 64-bit values to ptr types results in a "hard" error with
* the MSVC 64-bit compiler which this attempts to avoid.
*
* A simple compiler pragma or casting sequence could not be found
* to correct this in all situations, so this macro was introduced.
*
* It could be argued that the intptr_t type could be used in this
* case, but that type is not available on all compilers, or
* requires the #include of specific headers which differs between
* platforms.
*/
#define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
#define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
** This macro is used to "hide" some ugliness in casting an int
** value to a ptr value under the MSVC 64-bit compiler. Casting
** non 64-bit values to ptr types results in a "hard" error with
** the MSVC 64-bit compiler which this attempts to avoid.
**
** A simple compiler pragma or casting sequence could not be found
** to correct this in all situations, so this macro was introduced.
**
** It could be argued that the intptr_t type could be used in this
** case, but that type is not available on all compilers, or
** requires the #include of specific headers which differs between
** platforms.
**
** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on
** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)).
** So we have to define the macros in different ways depending on the
** compiler.
*/
#if defined(__GNUC__)
# if defined(HAVE_STDINT_H)
# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
# else
# define SQLITE_INT_TO_PTR(X) ((void*)(X))
# define SQLITE_PTR_TO_INT(X) ((int)(X))
# endif
#else
# define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
#endif
/*
** These #defines should enable >2GB file support on POSIX if the
@@ -252,9 +267,8 @@
# define ALWAYS(X) (1)
# define NEVER(X) (0)
#elif !defined(NDEBUG)
int sqlite3Assert(void);
# define ALWAYS(X) ((X)?1:sqlite3Assert())
# define NEVER(X) ((X)?sqlite3Assert():0)
# define ALWAYS(X) ((X)?1:(assert(0),0))
# define NEVER(X) ((X)?(assert(0),1):0)
#else
# define ALWAYS(X) (X)
# define NEVER(X) (X)
@@ -291,11 +305,12 @@
# define double sqlite_int64
# define LONGDOUBLE_TYPE sqlite_int64
# ifndef SQLITE_BIG_DBL
# define SQLITE_BIG_DBL (0x7fffffffffffffff)
# define SQLITE_BIG_DBL (((sqlite3_int64)1)<<60)
# endif
# define SQLITE_OMIT_DATETIME_FUNCS 1
# define SQLITE_OMIT_TRACE 1
# undef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
# undef SQLITE_HAVE_ISNAN
#endif
#ifndef SQLITE_BIG_DBL
# define SQLITE_BIG_DBL (1e99)
@@ -416,6 +431,14 @@ typedef INT16_TYPE i16; /* 2-byte signed integer */
typedef UINT8_TYPE u8; /* 1-byte unsigned integer */
typedef INT8_TYPE i8; /* 1-byte signed integer */
/*
** SQLITE_MAX_U32 is a u64 constant that is the maximum u64 value
** that can be stored in a u32 without loss of data. The value
** is 0x00000000ffffffff. But because of quirks of some compilers, we
** have to specify the value in the less intuitive manner shown:
*/
#define SQLITE_MAX_U32 ((((u64)1)<<32)-1)
/*
** Macros to determine whether the machine is big or little endian,
** evaluated at runtime.
@@ -460,6 +483,7 @@ extern const int sqlite3one;
*/
#define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&7)==0)
/*
** An instance of the following structure is used to store the busy-handler
** callback for a given sqlite handle.
@@ -556,6 +580,7 @@ struct BusyHandler {
*/
typedef struct AggInfo AggInfo;
typedef struct AuthContext AuthContext;
typedef struct AutoincInfo AutoincInfo;
typedef struct Bitvec Bitvec;
typedef struct RowSet RowSet;
typedef struct CollSeq CollSeq;
@@ -564,6 +589,7 @@ typedef struct Db Db;
typedef struct Schema Schema;
typedef struct Expr Expr;
typedef struct ExprList ExprList;
typedef struct ExprSpan ExprSpan;
typedef struct FKey FKey;
typedef struct FuncDef FuncDef;
typedef struct FuncDefHash FuncDefHash;
@@ -587,6 +613,7 @@ typedef struct TriggerStack TriggerStack;
typedef struct TriggerStep TriggerStep;
typedef struct Trigger Trigger;
typedef struct UnpackedRecord UnpackedRecord;
typedef struct VTable VTable;
typedef struct Walker Walker;
typedef struct WherePlan WherePlan;
typedef struct WhereInfo WhereInfo;
@@ -618,8 +645,6 @@ struct Db {
Btree *pBt; /* The B*Tree structure for this database file */
u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */
u8 safety_level; /* How aggressive at syncing data to disk */
void *pAux; /* Auxiliary data. Usually NULL */
void (*xFreeAux)(void*); /* Routine to free pAux */
Schema *pSchema; /* Pointer to database schema (possibly shared) */
};
@@ -766,7 +791,6 @@ struct sqlite3 {
int nTable; /* Number of tables in the database */
CollSeq *pDfltColl; /* The default collating sequence (BINARY) */
i64 lastRowid; /* ROWID of most recent insert (see above) */
i64 priorNewRowid; /* Last randomly generated ROWID */
u32 magic; /* Magic number for detect library misuse */
int nChange; /* Value returned by sqlite3_changes() */
int nTotalChange; /* Value returned by sqlite3_total_changes() */
@@ -776,6 +800,7 @@ struct sqlite3 {
int iDb; /* When back is being initialized */
int newTnum; /* Rootpage of table being initialized */
u8 busy; /* TRUE if currently initializing */
u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */
} init;
int nExtension; /* Number of loaded extensions */
void **aExtension; /* Array of shared library handles */
@@ -816,17 +841,15 @@ struct sqlite3 {
#ifndef SQLITE_OMIT_VIRTUALTABLE
Hash aModule; /* populated by sqlite3_create_module() */
Table *pVTab; /* vtab with active Connect/Create method */
sqlite3_vtab **aVTrans; /* Virtual tables with open transactions */
VTable **aVTrans; /* Virtual tables with open transactions */
int nVTrans; /* Allocated size of aVTrans */
VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */
#endif
FuncDefHash aFunc; /* Hash table of connection functions */
Hash aCollSeq; /* All collating sequences */
BusyHandler busyHandler; /* Busy callback */
int busyTimeout; /* Busy handler timeout, in msec */
Db aDbStatic[2]; /* Static space for the 2 default backends */
#ifdef SQLITE_SSE
sqlite3_stmt *pFetch; /* Used by SSE to fetch stored statements */
#endif
Savepoint *pSavepoint; /* List of active savepoints */
int nSavepoint; /* Number of non-transaction savepoints */
int nStatement; /* Number of nested statement-transactions */
@@ -885,9 +908,7 @@ struct sqlite3 {
#define SQLITE_LoadExtension 0x00020000 /* Enable load_extension */
#define SQLITE_RecoveryMode 0x00040000 /* Ignore schema errors */
#define SQLITE_SharedCache 0x00080000 /* Cache sharing is enabled */
#define SQLITE_CommitBusy 0x00200000 /* In the process of committing */
#define SQLITE_ReverseOrder 0x00400000 /* Reverse unordered SELECTs */
#define SQLITE_ReverseOrder 0x00100000 /* Reverse unordered SELECTs */
/*
** Possible values for the sqlite.magic field.
@@ -938,7 +959,7 @@ struct FuncDef {
** implemented by C function xFunc that accepts nArg arguments. The
** value passed as iArg is cast to a (void*) and made available
** as the user-data (sqlite3_user_data()) for the function. If
** argument bNC is true, then the FuncDef.needCollate flag is set.
** argument bNC is true, then the SQLITE_FUNC_NEEDCOLL flag is set.
**
** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal)
** Used to create an aggregate function definition implemented by
@@ -955,13 +976,16 @@ struct FuncDef {
** parameter.
*/
#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_UTF8, bNC*8, SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0}
{nArg, SQLITE_UTF8, bNC*SQLITE_FUNC_NEEDCOLL, \
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0}
#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
{nArg, SQLITE_UTF8, bNC*8, pArg, 0, xFunc, 0, 0, #zName, 0}
{nArg, SQLITE_UTF8, bNC*SQLITE_FUNC_NEEDCOLL, \
pArg, 0, xFunc, 0, 0, #zName, 0}
#define LIKEFUNC(zName, nArg, arg, flags) \
{nArg, SQLITE_UTF8, flags, (void *)arg, 0, likeFunc, 0, 0, #zName, 0}
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
{nArg, SQLITE_UTF8, nc*8, SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0}
{nArg, SQLITE_UTF8, nc*SQLITE_FUNC_NEEDCOLL, \
SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0}
/*
** All current savepoints are stored in a linked list starting at
@@ -1002,6 +1026,7 @@ struct Module {
struct Column {
char *zName; /* Name of this column */
Expr *pDflt; /* Default value of this column */
char *zDflt; /* Original text of the default value */
char *zType; /* Data type for this column */
char *zColl; /* Collating sequence. If NULL, use the default */
u8 notNull; /* True if there is a NOT NULL constraint */
@@ -1091,6 +1116,56 @@ struct CollSeq {
#define SQLITE_JUMPIFNULL 0x08 /* jumps if either operand is NULL */
#define SQLITE_STOREP2 0x10 /* Store result in reg[P2] rather than jump */
/*
** An object of this type is created for each virtual table present in
** the database schema.
**
** If the database schema is shared, then there is one instance of this
** structure for each database connection (sqlite3*) that uses the shared
** schema. This is because each database connection requires its own unique
** instance of the sqlite3_vtab* handle used to access the virtual table
** implementation. sqlite3_vtab* handles can not be shared between
** database connections, even when the rest of the in-memory database
** schema is shared, as the implementation often stores the database
** connection handle passed to it via the xConnect() or xCreate() method
** during initialization internally. This database connection handle may
** then used by the virtual table implementation to access real tables
** within the database. So that they appear as part of the callers
** transaction, these accesses need to be made via the same database
** connection as that used to execute SQL operations on the virtual table.
**
** All VTable objects that correspond to a single table in a shared
** database schema are initially stored in a linked-list pointed to by
** the Table.pVTable member variable of the corresponding Table object.
** When an sqlite3_prepare() operation is required to access the virtual
** table, it searches the list for the VTable that corresponds to the
** database connection doing the preparing so as to use the correct
** sqlite3_vtab* handle in the compiled query.
**
** When an in-memory Table object is deleted (for example when the
** schema is being reloaded for some reason), the VTable objects are not
** deleted and the sqlite3_vtab* handles are not xDisconnect()ed
** immediately. Instead, they are moved from the Table.pVTable list to
** another linked list headed by the sqlite3.pDisconnect member of the
** corresponding sqlite3 structure. They are then deleted/xDisconnected
** next time a statement is prepared using said sqlite3*. This is done
** to avoid deadlock issues involving multiple sqlite3.mutex mutexes.
** Refer to comments above function sqlite3VtabUnlockList() for an
** explanation as to why it is safe to add an entry to an sqlite3.pDisconnect
** list without holding the corresponding sqlite3.mutex mutex.
**
** The memory for objects of this type is always allocated by
** sqlite3DbMalloc(), using the connection handle stored in VTable.db as
** the first argument.
*/
struct VTable {
sqlite3 *db; /* Database connection associated with this table */
Module *pMod; /* Pointer to module implementation */
sqlite3_vtab *pVtab; /* Pointer to vtab instance */
int nRef; /* Number of pointers to this structure */
VTable *pNext; /* Next in linked list (see above) */
};
/*
** Each SQL table is represented in memory by an instance of the
** following structure.
@@ -1142,8 +1217,7 @@ struct Table {
int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
Module *pMod; /* Pointer to the implementation of the module */
sqlite3_vtab *pVtab; /* Pointer to the module instance */
VTable *pVTable; /* List of VTable objects. */
int nModuleArg; /* Number of arguments to the module */
char **azModuleArg; /* Text of all module args. [0] is module name */
#endif
@@ -1347,10 +1421,8 @@ struct Index {
** and Token.n when Token.z==0.
*/
struct Token {
const unsigned char *z; /* Text of the token. Not NULL-terminated! */
unsigned dyn : 1; /* True for malloced memory, false for static */
unsigned quoted : 1; /* True if token still has its quotes */
unsigned n : 30; /* Number of characters in this token */
const char *z; /* Text of the token. Not NULL-terminated! */
unsigned int n; /* Number of characters in this token */
};
/*
@@ -1451,9 +1523,9 @@ struct AggInfo {
** help reduce memory requirements, sometimes an Expr object will be
** truncated. And to reduce the number of memory allocations, sometimes
** two or more Expr objects will be stored in a single memory allocation,
** together with Expr.token and/or Expr.span strings.
** together with Expr.zToken strings.
**
** If the EP_Reduced, EP_SpanToken, and EP_TokenOnly flags are set when
** If the EP_Reduced and EP_TokenOnly flags are set when
** an Expr object is truncated. When EP_Reduced is set, then all
** the child Expr objects in the Expr.pLeft and Expr.pRight subtrees
** are contained within the same memory allocation. Note, however, that
@@ -1463,22 +1535,17 @@ struct AggInfo {
struct Expr {
u8 op; /* Operation performed by this node */
char affinity; /* The affinity of the column or 0 if not a column */
VVA_ONLY(u8 vvaFlags;) /* Flags used for VV&A only. EVVA_* below. */
u16 flags; /* Various flags. EP_* See below */
Token token; /* An operand token */
union {
char *zToken; /* Token value. Zero terminated and dequoted */
int iValue; /* Integer value if EP_IntValue */
} u;
/* If the EP_TokenOnly flag is set in the Expr.flags mask, then no
** space is allocated for the fields below this point. An attempt to
** access them will result in a segfault or malfunction.
*********************************************************************/
Token span; /* Complete text of the expression */
/* If the EP_SpanToken flag is set in the Expr.flags mask, then no
** space is allocated for the fields below this point. An attempt to
** access them will result in a segfault or malfunction.
*********************************************************************/
Expr *pLeft; /* Left subnode */
Expr *pRight; /* Right subnode */
union {
@@ -1492,11 +1559,13 @@ struct Expr {
** access them will result in a segfault or malfunction.
*********************************************************************/
int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
** iColumn-th field of the iTable-th table. */
int iTable; /* TK_COLUMN: cursor number of table holding column
** TK_REGISTER: register number */
i16 iColumn; /* TK_COLUMN: column index. -1 for rowid */
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */
u16 flags2; /* Second set of flags. EP2_... */
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
int iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
int iRightJoinTable; /* If EP_FromJoin, the right table of the join */
Table *pTab; /* Table for TK_COLUMN expressions. */
#if SQLITE_MAX_EXPR_DEPTH>0
int nHeight; /* Height of the tree headed by this node */
@@ -1517,20 +1586,29 @@ struct Expr {
#define EP_ExpCollate 0x0100 /* Collating sequence specified explicitly */
#define EP_AnyAff 0x0200 /* Can take a cached column of any affinity */
#define EP_FixedDest 0x0400 /* Result needed in a specific register */
#define EP_IntValue 0x0800 /* Integer value contained in iTable */
#define EP_IntValue 0x0800 /* Integer value contained in u.iValue */
#define EP_xIsSelect 0x1000 /* x.pSelect is valid (otherwise x.pList is) */
#define EP_Reduced 0x2000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
#define EP_TokenOnly 0x4000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
#define EP_SpanToken 0x8000 /* Expr size is EXPR_SPANTOKENSIZE bytes */
#define EP_Static 0x8000 /* Held in memory not obtained from malloc() */
/*
** The following are the meanings of bits in the Expr.vvaFlags field.
** This information is only used when SQLite is compiled with
** SQLITE_DEBUG defined.
** The following are the meanings of bits in the Expr.flags2 field.
*/
#ifndef NDEBUG
#define EVVA_ReadOnlyToken 0x01 /* Expr.token.z is read-only */
#define EP2_MallocedToken 0x0001 /* Need to sqlite3DbFree() Expr.zToken */
#define EP2_Irreducible 0x0002 /* Cannot EXPRDUP_REDUCE this Expr */
/*
** The pseudo-routine sqlite3ExprSetIrreducible sets the EP2_Irreducible
** flag on an expression structure. This flag is used for VV&A only. The
** routine is implemented as a macro that only works when in debugging mode,
** so as not to burden production code.
*/
#ifdef SQLITE_DEBUG
# define ExprSetIrreducible(X) (X)->flags2 |= EP2_Irreducible
#else
# define ExprSetIrreducible(X)
#endif
/*
@@ -1549,15 +1627,13 @@ struct Expr {
*/
#define EXPR_FULLSIZE sizeof(Expr) /* Full size */
#define EXPR_REDUCEDSIZE offsetof(Expr,iTable) /* Common features */
#define EXPR_SPANTOKENSIZE offsetof(Expr,pLeft) /* Fewer features */
#define EXPR_TOKENONLYSIZE offsetof(Expr,span) /* Smallest possible */
#define EXPR_TOKENONLYSIZE offsetof(Expr,pLeft) /* Fewer features */
/*
** Flags passed to the sqlite3ExprDup() function. See the header comment
** above sqlite3ExprDup() for details.
*/
#define EXPRDUP_REDUCE 0x0001 /* Used reduced-size Expr nodes */
#define EXPRDUP_SPAN 0x0002 /* Make a copy of Expr.span */
/*
** A list of expressions. Each expression may optionally have a
@@ -1574,6 +1650,7 @@ struct ExprList {
struct ExprList_item {
Expr *pExpr; /* The list of expressions */
char *zName; /* Token associated with this expression */
char *zSpan; /* Original text of the expression */
u8 sortOrder; /* 1 for DESC or 0 for ASC */
u8 done; /* A flag to indicate when processing is finished */
u16 iCol; /* For ORDER BY, column number in result set */
@@ -1581,6 +1658,17 @@ struct ExprList {
} *a; /* One entry for each expression */
};
/*
** An instance of this structure is used by the parser to record both
** the parse tree for an expression and the span of input text for an
** expression.
*/
struct ExprSpan {
Expr *pExpr; /* The expression parse tree */
const char *zStart; /* First character of input text */
const char *zEnd; /* One character past the end of input text */
};
/*
** An instance of this structure can hold a simple list of identifiers,
** such as the list "a,b,c" in the following statements:
@@ -1887,6 +1975,22 @@ struct SelectDest {
int nMem; /* Number of registers allocated */
};
/*
** During code generation of statements that do inserts into AUTOINCREMENT
** tables, the following information is attached to the Table.u.autoInc.p
** pointer of each autoincrement table to record some side information that
** the code generator needs. We have to keep per-table autoincrement
** information in case inserts are down within triggers. Triggers do not
** normally coordinate their activities, but we do need to coordinate the
** loading and saving of autoincrement information.
*/
struct AutoincInfo {
AutoincInfo *pNext; /* Next info block in a list of them all */
Table *pTab; /* Table this info block refers to */
int iDb; /* Index in sqlite3.aDb[] of database holding pTab */
int regCtr; /* Memory register holding the rowid counter */
};
/*
** Size of the column cache
*/
@@ -1953,6 +2057,7 @@ struct Parse {
#endif
int regRowid; /* Register holding rowid of CREATE TABLE entry */
int regRoot; /* Register holding root page number for new objects */
AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */
/* Above is constant between recursions. Below is reset before and after
** each recursion */
@@ -1965,10 +2070,8 @@ struct Parse {
int nAliasAlloc; /* Number of allocated slots for aAlias[] */
int *aAlias; /* Register used to hold aliased result */
u8 explain; /* True if the EXPLAIN flag is found on the query */
Token sErrToken; /* The token at which the error occurred */
Token sNameToken; /* Token with unqualified schema object name */
Token sLastToken; /* The last token parsed */
const char *zSql; /* All SQL text */
const char *zTail; /* All SQL text past the last semicolon parsed */
Table *pNewTable; /* A table being constructed by CREATE TABLE */
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
@@ -2031,7 +2134,6 @@ struct Trigger {
Expr *pWhen; /* The WHEN clause of the expression (may be NULL) */
IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger,
the <column-list> is stored here */
Token nameToken; /* Token containing zName. Use during parsing only */
Schema *pSchema; /* Schema containing the trigger */
Schema *pTabSchema; /* Schema containing the table */
TriggerStep *step_list; /* Link list of trigger program steps */
@@ -2065,7 +2167,7 @@ struct Trigger {
* orconf -> stores the ON CONFLICT algorithm
* pSelect -> If this is an INSERT INTO ... SELECT ... statement, then
* this stores a pointer to the SELECT statement. Otherwise NULL.
* target -> A token holding the name of the table to insert into.
* target -> A token holding the quoted name of the table to insert into.
* pExprList -> If this is an INSERT INTO ... VALUES ... statement, then
* this stores values to be inserted. Otherwise NULL.
* pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
@@ -2073,12 +2175,12 @@ struct Trigger {
* inserted into.
*
* (op == TK_DELETE)
* target -> A token holding the name of the table to delete from.
* target -> A token holding the quoted name of the table to delete from.
* pWhere -> The WHERE clause of the DELETE statement if one is specified.
* Otherwise NULL.
*
* (op == TK_UPDATE)
* target -> A token holding the name of the table to update rows of.
* target -> A token holding the quoted name of the table to update rows of.
* pWhere -> The WHERE clause of the UPDATE statement if one is specified.
* Otherwise NULL.
* pExprList -> A list of the columns to update and the expressions to update
@@ -2087,17 +2189,14 @@ struct Trigger {
*
*/
struct TriggerStep {
int op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */
int orconf; /* OE_Rollback etc. */
u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */
u8 orconf; /* OE_Rollback etc. */
Trigger *pTrig; /* The trigger that this step is a part of */
Select *pSelect; /* Valid for SELECT and sometimes
INSERT steps (when pExprList == 0) */
Token target; /* Valid for DELETE, UPDATE, INSERT steps */
Expr *pWhere; /* Valid for DELETE, UPDATE steps */
ExprList *pExprList; /* Valid for UPDATE statements and sometimes
INSERT steps (when pSelect == 0) */
IdList *pIdList; /* Valid for INSERT statements only */
Select *pSelect; /* SELECT statment or RHS of INSERT INTO .. SELECT ... */
Token target; /* Target table for DELETE, UPDATE, INSERT */
Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */
ExprList *pExprList; /* SET clause for UPDATE. VALUES clause for INSERT */
IdList *pIdList; /* Column names for INSERT */
TriggerStep *pNext; /* Next in the link-list */
TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */
};
@@ -2267,6 +2366,15 @@ int sqlite3WalkSelectFrom(Walker*, Select*);
# define SQLITE_CORRUPT_BKPT SQLITE_CORRUPT
#endif
/*
** The ctype.h header is needed for non-ASCII systems. It is also
** needed by FTS3 when FTS3 is included in the amalgamation.
*/
#if !defined(SQLITE_ASCII) || \
(defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_AMALGAMATION))
# include <ctype.h>
#endif
/*
** The following macros mimic the standard library functions toupper(),
** isspace(), isalnum(), isdigit() and isxdigit(), respectively. The
@@ -2281,7 +2389,6 @@ int sqlite3WalkSelectFrom(Walker*, Select*);
# define sqlite3Isxdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x08)
# define sqlite3Tolower(x) (sqlite3UpperToLower[(unsigned char)(x)])
#else
# include <ctype.h>
# define sqlite3Toupper(x) toupper((unsigned char)(x))
# define sqlite3Isspace(x) isspace((unsigned char)(x))
# define sqlite3Isalnum(x) isalnum((unsigned char)(x))
@@ -2295,9 +2402,9 @@ int sqlite3WalkSelectFrom(Walker*, Select*);
** Internal function prototypes
*/
int sqlite3StrICmp(const char *, const char *);
int sqlite3StrNICmp(const char *, const char *, int);
int sqlite3IsNumber(const char*, int*, u8);
int sqlite3Strlen30(const char*);
#define sqlite3StrNICmp sqlite3_strnicmp
int sqlite3MallocInit(void);
void sqlite3MallocEnd(void);
@@ -2321,6 +2428,24 @@ void sqlite3MemSetDefault(void);
void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));
int sqlite3MemoryAlarm(void (*)(void*, sqlite3_int64, int), void*, sqlite3_int64);
/*
** On systems with ample stack space and that support alloca(), make
** use of alloca() to obtain space for large automatic objects. By default,
** obtain space from malloc().
**
** The alloca() routine never returns NULL. This will cause code paths
** that deal with sqlite3StackAlloc() failures to be unreachable.
*/
#ifdef SQLITE_USE_ALLOCA
# define sqlite3StackAllocRaw(D,N) alloca(N)
# define sqlite3StackAllocZero(D,N) memset(alloca(N), 0, N)
# define sqlite3StackFree(D,P)
#else
# define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N)
# define sqlite3StackAllocZero(D,N) sqlite3DbMallocZero(D,N)
# define sqlite3StackFree(D,P) sqlite3DbFree(D,P)
#endif
#ifdef SQLITE_ENABLE_MEMSYS3
const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
#endif
@@ -2363,16 +2488,18 @@ int sqlite3GetTempReg(Parse*);
void sqlite3ReleaseTempReg(Parse*,int);
int sqlite3GetTempRange(Parse*,int);
void sqlite3ReleaseTempRange(Parse*,int,int);
Expr *sqlite3Expr(sqlite3*, int, Expr*, Expr*, const Token*);
Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int);
Expr *sqlite3Expr(sqlite3*,int,const char*);
void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*);
Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*, const Token*);
Expr *sqlite3RegisterExpr(Parse*,Token*);
Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*);
void sqlite3ExprSpan(Expr*,Token*,Token*);
Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*);
void sqlite3ExprAssignVarNumber(Parse*, Expr*);
void sqlite3ExprClear(sqlite3*, Expr*);
void sqlite3ExprDelete(sqlite3*, Expr*);
ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*,Token*);
ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*);
void sqlite3ExprListDelete(sqlite3*, ExprList*);
int sqlite3Init(sqlite3*, char**);
int sqlite3InitCallback(void*, int, char**, char**);
@@ -2388,14 +2515,14 @@ void sqlite3AddNotNull(Parse*, int);
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
void sqlite3AddCheckConstraint(Parse*, Expr*);
void sqlite3AddColumnType(Parse*,Token*);
void sqlite3AddDefaultValue(Parse*,Expr*);
void sqlite3AddDefaultValue(Parse*,ExprSpan*);
void sqlite3AddCollateType(Parse*, Token*);
void sqlite3EndTable(Parse*,Token*,Token*,Select*);
Bitvec *sqlite3BitvecCreate(u32);
int sqlite3BitvecTest(Bitvec*, u32);
int sqlite3BitvecSet(Bitvec*, u32);
void sqlite3BitvecClear(Bitvec*, u32);
void sqlite3BitvecClear(Bitvec*, u32, void*);
void sqlite3BitvecDestroy(Bitvec*);
u32 sqlite3BitvecSize(Bitvec*);
int sqlite3BitvecBuiltinTest(int,int*);
@@ -2416,6 +2543,13 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
void sqlite3DropTable(Parse*, SrcList*, int, int);
void sqlite3DeleteTable(Table*);
#ifndef SQLITE_OMIT_AUTOINCREMENT
void sqlite3AutoincrementBegin(Parse *pParse);
void sqlite3AutoincrementEnd(Parse *pParse);
#else
# define sqlite3AutoincrementBegin(X)
# define sqlite3AutoincrementEnd(X)
#endif
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
void *sqlite3ArrayAllocate(sqlite3*,void*,int,int,int*,int*,int*);
IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
@@ -2502,7 +2636,6 @@ void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int,int,int);
int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
void sqlite3BeginWriteOperation(Parse*, int, int);
Expr *sqlite3ExprDup(sqlite3*,Expr*,int);
void sqlite3TokenCopy(sqlite3*,Token*,const Token*);
ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
IdList *sqlite3IdListDup(sqlite3*,IdList*);
@@ -2541,8 +2674,8 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, int);
void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*);
TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*);
TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*,
ExprList*,Select*,int);
TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, int);
ExprList*,Select*,u8);
TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8);
TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*);
void sqlite3DeleteTrigger(sqlite3*, Trigger*);
void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
@@ -2633,8 +2766,8 @@ void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
const char *sqlite3ErrStr(int);
int sqlite3ReadSchema(Parse *pParse);
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char *,int,int);
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName);
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
Expr *sqlite3ExprSetColl(Parse *pParse, Expr *, Token *);
int sqlite3CheckCollSeq(Parse *, CollSeq *);
@@ -2669,11 +2802,11 @@ void sqlite3SelectPrep(Parse*, Select*, NameContext*);
int sqlite3ResolveExprNames(NameContext*, Expr*);
void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
void sqlite3ColumnDefault(Vdbe *, Table *, int);
void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
void sqlite3AlterFinishAddColumn(Parse *, Token *);
void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
CollSeq *sqlite3GetCollSeq(sqlite3*, CollSeq *, const char *, int);
char sqlite3AffinityType(const Token*);
CollSeq *sqlite3GetCollSeq(sqlite3*, CollSeq *, const char*);
char sqlite3AffinityType(const char*);
void sqlite3Analyze(Parse*, Token*, Token*);
int sqlite3InvokeBusyHandler(BusyHandler*);
int sqlite3FindDb(sqlite3*, Token*);
@@ -2712,7 +2845,7 @@ void sqlite3Parser(void*, int, Token, Parse*);
int sqlite3ParserStackPeak(void*);
#endif
int sqlite3AutoLoadExtensions(sqlite3*);
void sqlite3AutoLoadExtensions(sqlite3*);
#ifndef SQLITE_OMIT_LOAD_EXTENSION
void sqlite3CloseExtensions(sqlite3*);
#else
@@ -2730,21 +2863,25 @@ int sqlite3AutoLoadExtensions(sqlite3*);
#endif
#ifdef SQLITE_OMIT_VIRTUALTABLE
# define sqlite3VtabClear(X)
# define sqlite3VtabClear(Y)
# define sqlite3VtabSync(X,Y) SQLITE_OK
# define sqlite3VtabRollback(X)
# define sqlite3VtabCommit(X)
# define sqlite3VtabInSync(db) 0
# define sqlite3VtabLock(X)
# define sqlite3VtabUnlock(X)
# define sqlite3VtabUnlockList(X)
#else
void sqlite3VtabClear(Table*);
int sqlite3VtabSync(sqlite3 *db, char **);
int sqlite3VtabRollback(sqlite3 *db);
int sqlite3VtabCommit(sqlite3 *db);
void sqlite3VtabLock(VTable *);
void sqlite3VtabUnlock(VTable *);
void sqlite3VtabUnlockList(sqlite3*);
# define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
#endif
void sqlite3VtabMakeWritable(Parse*,Table*);
void sqlite3VtabLock(sqlite3_vtab*);
void sqlite3VtabUnlock(sqlite3*, sqlite3_vtab*);
void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*);
void sqlite3VtabFinishParse(Parse*, Token*);
void sqlite3VtabArgInit(Parse*);
@@ -2752,7 +2889,7 @@ void sqlite3VtabArgExtend(Parse*, Token*);
int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
int sqlite3VtabCallConnect(Parse*, Table*);
int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
int sqlite3VtabBegin(sqlite3 *, sqlite3_vtab *);
int sqlite3VtabBegin(sqlite3 *, VTable *);
FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
@@ -2760,6 +2897,7 @@ int sqlite3Reprepare(Vdbe*);
void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
int sqlite3TempInMemory(const sqlite3*);
VTable *sqlite3GetVTable(sqlite3*, Table*);
@@ -2822,11 +2960,6 @@ void sqlite3Put4byte(u8*, u32);
#define sqlite3ConnectionClosed(x)
#endif
#ifdef SQLITE_SSE
#include "sseInt.h"
#endif
#ifdef SQLITE_DEBUG
void sqlite3ParserTrace(FILE*, char *);
#endif
+2 -1
View File
@@ -12,7 +12,7 @@
** A TCL Interface to SQLite. Append this file to sqlite3.c and
** compile the whole thing to build a TCL-enabled version of SQLite.
**
** $Id: tclsqlite.c,v 1.241 2009/03/27 12:44:35 drh Exp $
** $Id: tclsqlite.c,v 1.242 2009/07/03 22:54:37 drh Exp $
*/
#include "tcl.h"
#include <errno.h>
@@ -1674,6 +1674,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** which matches the next sequence of SQL.
*/
pStmt = 0;
while( isspace(zSql[0]) ){ zSql++; }
len = strlen30(zSql);
for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){
int n = pPreStmt->nSql;
+2 -2
View File
@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.353 2009/05/03 20:23:54 drh Exp $
** $Id: test1.c,v 1.354 2009/08/10 04:37:50 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@@ -1099,6 +1099,7 @@ static void t1CountFinalize(sqlite3_context *context){
}
}
#ifndef SQLITE_OMIT_DEPRECATED
static void legacyCountStep(
sqlite3_context *context,
int argc,
@@ -1107,7 +1108,6 @@ static void legacyCountStep(
/* no-op */
}
#ifndef SQLITE_OMIT_DEPRECATED
static void legacyCountFinalize(sqlite3_context *context){
sqlite3_result_int(context, sqlite3_aggregate_count(context));
}
+15 -7
View File
@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** $Id: test2.c,v 1.70 2009/02/05 16:31:46 drh Exp $
** $Id: test2.c,v 1.74 2009/07/24 19:01:20 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@@ -56,6 +56,13 @@ static char *errorName(int rc){
*/
static int test_pagesize = 1024;
/*
** Dummy page reinitializer
*/
static void pager_test_reiniter(DbPage *pNotUsed){
return;
}
/*
** Usage: pager_open FILENAME N-PAGE
**
@@ -79,14 +86,15 @@ static int pager_open(
}
if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR;
rc = sqlite3PagerOpen(sqlite3_vfs_find(0), &pPager, argv[1], 0, 0,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB,
pager_test_reiniter);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
sqlite3PagerSetCachesize(pPager, nPage);
pageSize = test_pagesize;
sqlite3PagerSetPagesize(pPager, &pageSize);
sqlite3PagerSetPagesize(pPager, &pageSize, -1);
sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPager);
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
@@ -342,7 +350,10 @@ static int page_get(
}
pPager = sqlite3TestTextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
rc = sqlite3PagerGet(pPager, pgno, &pPage);
rc = sqlite3PagerSharedLock(pPager);
if( rc==SQLITE_OK ){
rc = sqlite3PagerGet(pPager, pgno, &pPage);
}
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -623,7 +634,6 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
extern int sqlite3_io_error_hardhit;
extern int sqlite3_diskfull_pending;
extern int sqlite3_diskfull;
extern int sqlite3_pager_n_sort_bucket;
static struct {
char *zName;
Tcl_CmdProc *xProc;
@@ -668,7 +678,5 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
(char*)&sqlite3_diskfull, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_pending_byte",
(char*)&sqlite3PendingByte, TCL_LINK_INT | TCL_LINK_READ_ONLY);
Tcl_LinkVar(interp, "sqlite_pager_n_sort_bucket",
(char*)&sqlite3_pager_n_sort_bucket, TCL_LINK_INT);
return TCL_OK;
}
+42 -1005
View File
File diff suppressed because it is too large Load Diff
+1 -79
View File
@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** $Id: test_btree.c,v 1.8 2008/09/29 11:49:48 danielk1977 Exp $
** $Id: test_btree.c,v 1.9 2009/07/09 02:48:24 shane Exp $
*/
#include "btreeInt.h"
#include <tcl.h>
@@ -62,81 +62,3 @@ void sqlite3BtreeCursorList(Btree *p){
}
#endif
}
/*
** Fill aResult[] with information about the entry and page that the
** cursor is pointing to.
**
** aResult[0] = The page number
** aResult[1] = The entry number
** aResult[2] = Total number of entries on this page
** aResult[3] = Cell size (local payload + header)
** aResult[4] = Number of free bytes on this page
** aResult[5] = Number of free blocks on the page
** aResult[6] = Total payload size (local + overflow)
** aResult[7] = Header size in bytes
** aResult[8] = Local payload size
** aResult[9] = Parent page number
** aResult[10]= Page number of the first overflow page
**
** This routine is used for testing and debugging only.
*/
int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){
#if 0
int cnt, idx;
MemPage *pPage = pCur->apPage[pCur->iPage];
BtCursor tmpCur;
int rc;
if( pCur->eState==CURSOR_REQUIRESEEK ){
rc = sqlite3BtreeRestoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){
return rc;
}
}
assert( pPage->isInit );
sqlite3BtreeGetTempCursor(pCur, &tmpCur);
while( upCnt-- ){
sqlite3BtreeMoveToParent(&tmpCur);
}
pPage = tmpCur.pPage;
aResult[0] = sqlite3PagerPagenumber(pPage->pDbPage);
assert( aResult[0]==pPage->pgno );
aResult[1] = tmpCur.idx;
aResult[2] = pPage->nCell;
if( tmpCur.idx>=0 && tmpCur.idx<pPage->nCell ){
sqlite3BtreeParseCell(tmpCur.pPage, tmpCur.idx, &tmpCur.info);
aResult[3] = tmpCur.info.nSize;
aResult[6] = tmpCur.info.nData;
aResult[7] = tmpCur.info.nHeader;
aResult[8] = tmpCur.info.nLocal;
}else{
aResult[3] = 0;
aResult[6] = 0;
aResult[7] = 0;
aResult[8] = 0;
}
aResult[4] = pPage->nFree;
cnt = 0;
idx = get2byte(&pPage->aData[pPage->hdrOffset+1]);
while( idx>0 && idx<pPage->pBt->usableSize ){
cnt++;
idx = get2byte(&pPage->aData[idx]);
}
aResult[5] = cnt;
if( pPage->pParent==0 || sqlite3BtreeIsRootPage(pPage) ){
aResult[9] = 0;
}else{
aResult[9] = pPage->pParent->pgno;
}
if( tmpCur.info.iOverflow ){
aResult[10] = get4byte(&tmpCur.info.pCell[tmpCur.info.iOverflow]);
}else{
aResult[10] = 0;
}
sqlite3BtreeReleaseTempCursor(&tmpCur);
#endif
return SQLITE_OK;
}
+11 -7
View File
@@ -16,7 +16,7 @@
** The focus of this file is providing the TCL testing layer
** access to compile-time constants.
**
** $Id: test_config.c,v 1.48 2009/03/16 13:19:36 danielk1977 Exp $
** $Id: test_config.c,v 1.50 2009/06/19 14:06:03 drh Exp $
*/
#include "sqliteLimit.h"
@@ -177,6 +177,16 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "columnmetadata", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
Tcl_SetVar2(interp, "sqlite_options", "oversize_cell_check", "1",
TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "oversize_cell_check", "0",
TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_COMPLETE
Tcl_SetVar2(interp, "sqlite_options", "complete", "0", TCL_GLOBAL_ONLY);
#else
@@ -349,12 +359,6 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
Tcl_SetVar2(interp, "sqlite_options", "pager_pragmas", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_PARSER
Tcl_SetVar2(interp, "sqlite_options", "parser", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "parser", "1", TCL_GLOBAL_ONLY);
#endif
#if defined(SQLITE_OMIT_PRAGMA) || defined(SQLITE_OMIT_FLAG_PRAGMAS)
Tcl_SetVar2(interp, "sqlite_options", "pragma", "0", TCL_GLOBAL_ONLY);
Tcl_SetVar2(interp, "sqlite_options", "integrityck", "0", TCL_GLOBAL_ONLY);
+11 -25
View File
@@ -12,7 +12,7 @@
** Code for testing all sorts of SQLite interfaces. This code
** implements new SQL functions used by the test scripts.
**
** $Id: test_func.c,v 1.14 2009/03/19 18:51:07 danielk1977 Exp $
** $Id: test_func.c,v 1.16 2009/07/22 07:27:57 danielk1977 Exp $
*/
#include "sqlite3.h"
#include "tcl.h"
@@ -156,6 +156,7 @@ void sqlite3EndBenignMalloc(void);
static void test_agg_errmsg16_step(sqlite3_context *a, int b,sqlite3_value **c){
}
static void test_agg_errmsg16_final(sqlite3_context *ctx){
#ifndef SQLITE_OMIT_UTF16
const void *z;
sqlite3 * db = sqlite3_context_db_handle(ctx);
sqlite3_aggregate_context(ctx, 2048);
@@ -163,6 +164,7 @@ static void test_agg_errmsg16_final(sqlite3_context *ctx){
z = sqlite3_errmsg16(db);
sqlite3EndBenignMalloc();
sqlite3_result_text16(ctx, z, -1, SQLITE_TRANSIENT);
#endif
}
/*
@@ -393,39 +395,25 @@ static int abuse_create_function(
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
rc = sqlite3_create_function(db, "tx", 1, SQLITE_UTF8, 0, tStep,tStep,tFinal);
if( rc!=SQLITE_ERROR ) goto abuse_err;
if( sqlite3_errcode(db)!=SQLITE_ERROR ) goto abuse_err;
if( strcmp(sqlite3_errmsg(db), "bad parameters")!=0 ) goto abuse_err;
if( rc!=SQLITE_MISUSE ) goto abuse_err;
rc = sqlite3_create_function(db, "tx", 1, SQLITE_UTF8, 0, tStep, tStep, 0);
if( rc!=SQLITE_ERROR ) goto abuse_err;
if( sqlite3_errcode(db)!=SQLITE_ERROR ) goto abuse_err;
if( strcmp(sqlite3_errmsg(db), "bad parameters")!=0 ) goto abuse_err;
if( rc!=SQLITE_MISUSE ) goto abuse_err;
rc = sqlite3_create_function(db, "tx", 1, SQLITE_UTF8, 0, tStep, 0, tFinal);
if( rc!=SQLITE_ERROR ) goto abuse_err;
if( sqlite3_errcode(db)!=SQLITE_ERROR ) goto abuse_err;
if( strcmp(sqlite3_errmsg(db), "bad parameters")!=0 ) goto abuse_err;
if( rc!=SQLITE_MISUSE) goto abuse_err;
rc = sqlite3_create_function(db, "tx", 1, SQLITE_UTF8, 0, 0, 0, tFinal);
if( rc!=SQLITE_ERROR ) goto abuse_err;
if( sqlite3_errcode(db)!=SQLITE_ERROR ) goto abuse_err;
if( strcmp(sqlite3_errmsg(db), "bad parameters")!=0 ) goto abuse_err;
if( rc!=SQLITE_MISUSE ) goto abuse_err;
rc = sqlite3_create_function(db, "tx", 1, SQLITE_UTF8, 0, 0, tStep, 0);
if( rc!=SQLITE_ERROR ) goto abuse_err;
if( sqlite3_errcode(db)!=SQLITE_ERROR ) goto abuse_err;
if( strcmp(sqlite3_errmsg(db), "bad parameters")!=0 ) goto abuse_err;
if( rc!=SQLITE_MISUSE ) goto abuse_err;
rc = sqlite3_create_function(db, "tx", -2, SQLITE_UTF8, 0, tStep, 0, 0);
if( rc!=SQLITE_ERROR ) goto abuse_err;
if( sqlite3_errcode(db)!=SQLITE_ERROR ) goto abuse_err;
if( strcmp(sqlite3_errmsg(db), "bad parameters")!=0 ) goto abuse_err;
if( rc!=SQLITE_MISUSE ) goto abuse_err;
rc = sqlite3_create_function(db, "tx", 128, SQLITE_UTF8, 0, tStep, 0, 0);
if( rc!=SQLITE_ERROR ) goto abuse_err;
if( sqlite3_errcode(db)!=SQLITE_ERROR ) goto abuse_err;
if( strcmp(sqlite3_errmsg(db), "bad parameters")!=0 ) goto abuse_err;
if( rc!=SQLITE_MISUSE ) goto abuse_err;
rc = sqlite3_create_function(db, "funcxx"
"_123456789_123456789_123456789_123456789_123456789"
@@ -434,9 +422,7 @@ static int abuse_create_function(
"_123456789_123456789_123456789_123456789_123456789"
"_123456789_123456789_123456789_123456789_123456789",
1, SQLITE_UTF8, 0, tStep, 0, 0);
if( rc!=SQLITE_ERROR ) goto abuse_err;
if( sqlite3_errcode(db)!=SQLITE_ERROR ) goto abuse_err;
if( strcmp(sqlite3_errmsg(db), "bad parameters")!=0 ) goto abuse_err;
if( rc!=SQLITE_MISUSE ) goto abuse_err;
/* This last function registration should actually work. Generate
** a no-op function (that always returns NULL) and which has the
+98 -82
View File
@@ -15,7 +15,7 @@
** correctly populates and syncs a journal file before writing to a
** corresponding database file.
**
** $Id: test_journal.c,v 1.15 2009/04/07 11:21:29 danielk1977 Exp $
** $Id: test_journal.c,v 1.17 2009/06/26 10:39:36 danielk1977 Exp $
*/
#if SQLITE_TEST /* This file is used for testing only */
@@ -218,12 +218,16 @@ static void leaveJtMutex(void){
}
extern int sqlite3_io_error_pending;
static void stop_ioerr_simulation(int *piSave){
extern int sqlite3_io_error_hit;
static void stop_ioerr_simulation(int *piSave, int *piSave2){
*piSave = sqlite3_io_error_pending;
*piSave2 = sqlite3_io_error_hit;
sqlite3_io_error_pending = -1;
sqlite3_io_error_hit = 0;
}
static void start_ioerr_simulation(int iSave){
static void start_ioerr_simulation(int iSave, int iSave2){
sqlite3_io_error_pending = iSave;
sqlite3_io_error_hit = iSave2;
}
/*
@@ -366,8 +370,9 @@ static int openTransaction(jt_file *pMain, jt_file *pJournal){
}else if( pMain->nPage>0 ){
u32 iTrunk;
int iSave;
int iSave2;
stop_ioerr_simulation(&iSave);
stop_ioerr_simulation(&iSave, &iSave2);
/* Read the database free-list. Add the page-number for each free-list
** leaf to the jt_file.pWritable bitvec.
@@ -398,88 +403,13 @@ static int openTransaction(jt_file *pMain, jt_file *pJournal){
}
}
start_ioerr_simulation(iSave);
start_ioerr_simulation(iSave, iSave2);
}
sqlite3_free(aData);
return rc;
}
/*
** Write data to an jt-file.
*/
static int jtWrite(
sqlite3_file *pFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
jt_file *p = (jt_file *)pFile;
if( p->flags&SQLITE_OPEN_MAIN_JOURNAL ){
if( iOfst==0 ){
jt_file *pMain = locateDatabaseHandle(p->zName);
assert( pMain );
if( decodeJournalHdr(zBuf, 0, &pMain->nPage, 0, &pMain->nPagesize) ){
/* Zeroing the first journal-file header. This is the end of a
** transaction. */
closeTransaction(pMain);
}else{
/* Writing the first journal header to a journal file. This happens
** when a transaction is first started. */
int rc;
if( SQLITE_OK!=(rc=openTransaction(pMain, p)) ){
return rc;
}
}
}
if( p->iMaxOff<(iOfst + iAmt) ){
p->iMaxOff = iOfst + iAmt;
}
}
if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){
if( iAmt<p->nPagesize
&& p->nPagesize%iAmt==0
&& iOfst>=(PENDING_BYTE+512)
&& iOfst+iAmt<=PENDING_BYTE+p->nPagesize
){
/* No-op. This special case is hit when the backup code is copying a
** to a database with a larger page-size than the source database and
** it needs to fill in the non-locking-region part of the original
** pending-byte page.
*/
}else{
u32 pgno = iOfst/p->nPagesize + 1;
assert( (iAmt==1||iAmt==p->nPagesize) && ((iOfst+iAmt)%p->nPagesize)==0 );
assert( pgno<=p->nPage || p->nSync>0 );
assert( pgno>p->nPage || sqlite3BitvecTest(p->pWritable, pgno) );
}
}
return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
}
/*
** Truncate an jt-file.
*/
static int jtTruncate(sqlite3_file *pFile, sqlite_int64 size){
jt_file *p = (jt_file *)pFile;
if( p->flags&SQLITE_OPEN_MAIN_JOURNAL && size==0 ){
/* Truncating a journal file. This is the end of a transaction. */
jt_file *pMain = locateDatabaseHandle(p->zName);
closeTransaction(pMain);
}
if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){
u32 pgno;
u32 locking_page = (u32)(PENDING_BYTE/p->nPagesize+1);
for(pgno=size/p->nPagesize+1; pgno<=p->nPage; pgno++){
assert( pgno==locking_page || sqlite3BitvecTest(p->pWritable, pgno) );
}
}
return sqlite3OsTruncate(p->pReal, size);
}
/*
** The first argument to this function is a handle open on a journal file.
** This function reads the journal file and adds the page number for each
@@ -493,13 +423,14 @@ static int readJournalFile(jt_file *p, jt_file *pMain){
sqlite3_int64 iSize = p->iMaxOff;
unsigned char *aPage;
int iSave;
int iSave2;
aPage = sqlite3_malloc(pMain->nPagesize);
if( !aPage ){
return SQLITE_IOERR_NOMEM;
}
stop_ioerr_simulation(&iSave);
stop_ioerr_simulation(&iSave, &iSave2);
while( rc==SQLITE_OK && iOff<iSize ){
u32 nRec, nPage, nSector, nPagesize;
@@ -552,7 +483,7 @@ static int readJournalFile(jt_file *p, jt_file *pMain){
}
finish_rjf:
start_ioerr_simulation(iSave);
start_ioerr_simulation(iSave, iSave2);
sqlite3_free(aPage);
if( rc==SQLITE_IOERR_SHORT_READ ){
rc = SQLITE_OK;
@@ -560,6 +491,91 @@ finish_rjf:
return rc;
}
/*
** Write data to an jt-file.
*/
static int jtWrite(
sqlite3_file *pFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
int rc;
jt_file *p = (jt_file *)pFile;
if( p->flags&SQLITE_OPEN_MAIN_JOURNAL ){
if( iOfst==0 ){
jt_file *pMain = locateDatabaseHandle(p->zName);
assert( pMain );
if( iAmt==28 ){
/* Zeroing the first journal-file header. This is the end of a
** transaction. */
closeTransaction(pMain);
}else if( iAmt!=12 ){
/* Writing the first journal header to a journal file. This happens
** when a transaction is first started. */
u8 *z = (u8 *)zBuf;
pMain->nPage = decodeUint32(&z[16]);
pMain->nPagesize = decodeUint32(&z[24]);
if( SQLITE_OK!=(rc=openTransaction(pMain, p)) ){
return rc;
}
}
}
if( p->iMaxOff<(iOfst + iAmt) ){
p->iMaxOff = iOfst + iAmt;
}
}
if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){
if( iAmt<p->nPagesize
&& p->nPagesize%iAmt==0
&& iOfst>=(PENDING_BYTE+512)
&& iOfst+iAmt<=PENDING_BYTE+p->nPagesize
){
/* No-op. This special case is hit when the backup code is copying a
** to a database with a larger page-size than the source database and
** it needs to fill in the non-locking-region part of the original
** pending-byte page.
*/
}else{
u32 pgno = iOfst/p->nPagesize + 1;
assert( (iAmt==1||iAmt==p->nPagesize) && ((iOfst+iAmt)%p->nPagesize)==0 );
assert( pgno<=p->nPage || p->nSync>0 );
assert( pgno>p->nPage || sqlite3BitvecTest(p->pWritable, pgno) );
}
}
rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
if( (p->flags&SQLITE_OPEN_MAIN_JOURNAL) && iAmt==12 ){
jt_file *pMain = locateDatabaseHandle(p->zName);
int rc2 = readJournalFile(p, pMain);
if( rc==SQLITE_OK ) rc = rc2;
}
return rc;
}
/*
** Truncate an jt-file.
*/
static int jtTruncate(sqlite3_file *pFile, sqlite_int64 size){
jt_file *p = (jt_file *)pFile;
if( p->flags&SQLITE_OPEN_MAIN_JOURNAL && size==0 ){
/* Truncating a journal file. This is the end of a transaction. */
jt_file *pMain = locateDatabaseHandle(p->zName);
closeTransaction(pMain);
}
if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){
u32 pgno;
u32 locking_page = (u32)(PENDING_BYTE/p->nPagesize+1);
for(pgno=size/p->nPagesize+1; pgno<=p->nPage; pgno++){
assert( pgno==locking_page || sqlite3BitvecTest(p->pWritable, pgno) );
}
}
return sqlite3OsTruncate(p->pReal, size);
}
/*
** Sync an jt-file.
*/
+20 -1
View File
@@ -13,7 +13,7 @@
** This file contains code used to implement test interfaces to the
** memory allocation subsystem.
**
** $Id: test_malloc.c,v 1.54 2009/04/07 11:21:29 danielk1977 Exp $
** $Id: test_malloc.c,v 1.55 2009/07/01 18:09:02 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@@ -1342,6 +1342,24 @@ static int test_install_malloc_faultsim(
return TCL_OK;
}
/*
** sqlite3_install_memsys3
*/
static int test_install_memsys3(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int rc = SQLITE_MISUSE;
#ifdef SQLITE_ENABLE_MEMSYS3
const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
rc = sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetMemsys3());
#endif
Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
return TCL_OK;
}
/*
** Register commands with the TCL interpreter.
*/
@@ -1378,6 +1396,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
{ "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 },
{ "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
{ "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },
{ "sqlite3_install_memsys3", test_install_memsys3 ,0 },
};
int i;
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
+26 -14
View File
@@ -15,7 +15,7 @@
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id: tokenize.c,v 1.156 2009/05/01 21:13:37 drh Exp $
** $Id: tokenize.c,v 1.163 2009/07/03 22:54:37 drh Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@@ -123,6 +123,11 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
int i, c;
switch( *z ){
case ' ': case '\t': case '\n': case '\f': case '\r': {
testcase( z[0]==' ' );
testcase( z[0]=='\t' );
testcase( z[0]=='\n' );
testcase( z[0]=='\f' );
testcase( z[0]=='\r' );
for(i=1; sqlite3Isspace(z[i]); i++){}
*tokenType = TK_SPACE;
return i;
@@ -235,6 +240,9 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
case '\'':
case '"': {
int delim = z[0];
testcase( delim=='`' );
testcase( delim=='\'' );
testcase( delim=='"' );
for(i=1; (c=z[i])!=0; i++){
if( c==delim ){
if( z[i+1]==delim ){
@@ -268,6 +276,10 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' );
testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' );
testcase( z[0]=='9' );
*tokenType = TK_INTEGER;
for(i=0; sqlite3Isdigit(z[i]); i++){}
#ifndef SQLITE_OMIT_FLOATING_POINT
@@ -319,6 +331,7 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
case '@': /* For compatibility with MS SQL Server */
case ':': {
int n = 0;
testcase( z[0]=='$' ); testcase( z[0]=='@' ); testcase( z[0]==':' );
*tokenType = TK_VARIABLE;
for(i=1; (c=z[i])!=0; i++){
if( IdChar(c) ){
@@ -346,6 +359,7 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
#ifndef SQLITE_OMIT_BLOB_LITERAL
case 'x': case 'X': {
testcase( z[0]=='x' ); testcase( z[0]=='X' );
if( z[1]=='\'' ){
*tokenType = TK_BLOB;
for(i=2; (c=z[i])!=0 && c!='\''; i++){
@@ -396,7 +410,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
db->u1.isInterrupted = 0;
}
pParse->rc = SQLITE_OK;
pParse->zTail = pParse->zSql = zSql;
pParse->zTail = zSql;
i = 0;
assert( pzErrMsg!=0 );
pEngine = sqlite3ParserAlloc((void*(*)(size_t))sqlite3Malloc);
@@ -404,7 +418,6 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
db->mallocFailed = 1;
return SQLITE_NOMEM;
}
assert( pParse->sLastToken.dyn==0 );
assert( pParse->pNewTable==0 );
assert( pParse->pNewTrigger==0 );
assert( pParse->nVar==0 );
@@ -413,12 +426,9 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
assert( pParse->apVarExpr==0 );
enableLookaside = db->lookaside.bEnabled;
if( db->lookaside.pStart ) db->lookaside.bEnabled = 1;
pParse->sLastToken.quoted = 1;
while( !db->mallocFailed && zSql[i]!=0 ){
assert( i>=0 );
pParse->sLastToken.z = (u8*)&zSql[i];
assert( pParse->sLastToken.dyn==0 );
assert( pParse->sLastToken.quoted );
pParse->sLastToken.z = &zSql[i];
pParse->sLastToken.n = sqlite3GetToken((unsigned char*)&zSql[i],&tokenType);
i += pParse->sLastToken.n;
if( i>mxSqlLen ){
@@ -428,8 +438,8 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
switch( tokenType ){
case TK_SPACE: {
if( db->u1.isInterrupted ){
sqlite3ErrorMsg(pParse, "interrupt");
pParse->rc = SQLITE_INTERRUPT;
sqlite3SetString(pzErrMsg, db, "interrupt");
goto abort_parse;
}
break;
@@ -476,12 +486,9 @@ abort_parse:
if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
sqlite3SetString(&pParse->zErrMsg, db, "%s", sqlite3ErrStr(pParse->rc));
}
assert( pzErrMsg!=0 );
if( pParse->zErrMsg ){
if( *pzErrMsg==0 ){
*pzErrMsg = pParse->zErrMsg;
}else{
sqlite3DbFree(db, pParse->zErrMsg);
}
*pzErrMsg = pParse->zErrMsg;
pParse->zErrMsg = 0;
nErr++;
}
@@ -511,12 +518,17 @@ abort_parse:
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
sqlite3DbFree(db, pParse->apVarExpr);
sqlite3DbFree(db, pParse->aAlias);
while( pParse->pAinc ){
AutoincInfo *p = pParse->pAinc;
pParse->pAinc = p->pNext;
sqlite3DbFree(db, p);
}
while( pParse->pZombieTab ){
Table *p = pParse->pZombieTab;
pParse->pZombieTab = p->pNextZombie;
sqlite3DeleteTable(p);
}
if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){
if( nErr>0 && pParse->rc==SQLITE_OK ){
pParse->rc = SQLITE_ERROR;
}
return nErr;
+111 -113
View File
@@ -10,7 +10,7 @@
*************************************************************************
**
**
** $Id: trigger.c,v 1.138 2009/05/06 18:42:21 drh Exp $
** $Id: trigger.c,v 1.143 2009/08/10 03:57:58 shane Exp $
*/
#include "sqliteInt.h"
@@ -23,7 +23,6 @@ void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerStep){
TriggerStep * pTmp = pTriggerStep;
pTriggerStep = pTriggerStep->pNext;
if( pTmp->target.dyn ) sqlite3DbFree(db, (char*)pTmp->target.z);
sqlite3ExprDelete(db, pTmp->pWhere);
sqlite3ExprListDelete(db, pTmp->pExprList);
sqlite3SelectDelete(db, pTmp->pSelect);
@@ -36,6 +35,16 @@ void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerStep){
/*
** Given table pTab, return a list of all the triggers attached to
** the table. The list is connected by Trigger.pNext pointers.
**
** All of the triggers on pTab that are in the same database as pTab
** are already attached to pTab->pTrigger. But there might be additional
** triggers on pTab in the TEMP schema. This routine prepends all
** TEMP triggers on pTab to the beginning of the pTab->pTrigger list
** and returns the combined list.
**
** To state it another way: This routine returns a list of all triggers
** that fire off of pTab. The list will include any TEMP triggers on
** pTab as well as the triggers lised in pTab->pTrigger.
*/
Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
Schema * const pTmpSchema = pParse->db->aDb[1].pSchema;
@@ -77,14 +86,14 @@ void sqlite3BeginTrigger(
int isTemp, /* True if the TEMPORARY keyword is present */
int noErr /* Suppress errors if the trigger already exists */
){
Trigger *pTrigger = 0;
Table *pTab;
Trigger *pTrigger = 0; /* The new trigger */
Table *pTab; /* Table that the trigger fires off of */
char *zName = 0; /* Name of the trigger */
sqlite3 *db = pParse->db;
sqlite3 *db = pParse->db; /* The database connection */
int iDb; /* The database to store the trigger in */
Token *pName; /* The unqualified db name */
DbFixer sFix;
int iTabDb;
DbFixer sFix; /* State vector for the DB fixer */
int iTabDb; /* Index of the database holding pTab */
assert( pName1!=0 ); /* pName1->z might be NULL, but not pName1 itself */
assert( pName2!=0 );
@@ -129,6 +138,17 @@ void sqlite3BeginTrigger(
pTab = sqlite3SrcListLookup(pParse, pTableName);
if( !pTab ){
/* The table does not exist. */
if( db->init.iDb==1 ){
/* Ticket #3810.
** Normally, whenever a table is dropped, all associated triggers are
** dropped too. But if a TEMP trigger is created on a non-TEMP table
** and the table is dropped by a different database connection, the
** trigger is not visible to the database connection that does the
** drop so the trigger cannot be dropped. This results in an
** "orphaned trigger" - a trigger whose associated table is missing.
*/
db->init.orphanTrigger = 1;
}
goto trigger_cleanup;
}
if( IsVirtual(pTab) ){
@@ -208,7 +228,6 @@ void sqlite3BeginTrigger(
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
pTrigger->pColumns = sqlite3IdListDup(db, pColumns);
sqlite3TokenCopy(db, &pTrigger->nameToken,pName);
assert( pParse->pNewTrigger==0 );
pParse->pNewTrigger = pTrigger;
@@ -238,10 +257,11 @@ void sqlite3FinishTrigger(
sqlite3 *db = pParse->db; /* The database */
DbFixer sFix;
int iDb; /* Database containing the trigger */
Token nameToken; /* Trigger name for error reporting */
pTrig = pParse->pNewTrigger;
pParse->pNewTrigger = 0;
if( pParse->nErr || !pTrig ) goto triggerfinish_cleanup;
if( NEVER(pParse->nErr) || !pTrig ) goto triggerfinish_cleanup;
zName = pTrig->name;
iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
pTrig->step_list = pStepList;
@@ -249,7 +269,9 @@ void sqlite3FinishTrigger(
pStepList->pTrig = pTrig;
pStepList = pStepList->pNext;
}
if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", &pTrig->nameToken)
nameToken.z = pTrig->name;
nameToken.n = sqlite3Strlen30(nameToken.z);
if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken)
&& sqlite3FixTriggerStep(&sFix, pTrig->step_list) ){
goto triggerfinish_cleanup;
}
@@ -299,43 +321,6 @@ triggerfinish_cleanup:
sqlite3DeleteTriggerStep(db, pStepList);
}
/*
** Make a copy of all components of the given trigger step. This has
** the effect of copying all Expr.token.z values into memory obtained
** from sqlite3_malloc(). As initially created, the Expr.token.z values
** all point to the input string that was fed to the parser. But that
** string is ephemeral - it will go away as soon as the sqlite3_exec()
** call that started the parser exits. This routine makes a persistent
** copy of all the Expr.token.z strings so that the TriggerStep structure
** will be valid even after the sqlite3_exec() call returns.
*/
static void sqlitePersistTriggerStep(sqlite3 *db, TriggerStep *p){
if( p->target.z ){
p->target.z = (u8*)sqlite3DbStrNDup(db, (char*)p->target.z, p->target.n);
p->target.dyn = 1;
}
if( p->pSelect ){
Select *pNew = sqlite3SelectDup(db, p->pSelect, 1);
sqlite3SelectDelete(db, p->pSelect);
p->pSelect = pNew;
}
if( p->pWhere ){
Expr *pNew = sqlite3ExprDup(db, p->pWhere, EXPRDUP_REDUCE);
sqlite3ExprDelete(db, p->pWhere);
p->pWhere = pNew;
}
if( p->pExprList ){
ExprList *pNew = sqlite3ExprListDup(db, p->pExprList, 1);
sqlite3ExprListDelete(db, p->pExprList);
p->pExprList = pNew;
}
if( p->pIdList ){
IdList *pNew = sqlite3IdListDup(db, p->pIdList);
sqlite3IdListDelete(db, p->pIdList);
p->pIdList = pNew;
}
}
/*
** Turn a SELECT statement (that the pSelect parameter points to) into
** a trigger step. Return a pointer to a TriggerStep structure.
@@ -349,12 +334,33 @@ TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
sqlite3SelectDelete(db, pSelect);
return 0;
}
pTriggerStep->op = TK_SELECT;
pTriggerStep->pSelect = pSelect;
pTriggerStep->orconf = OE_Default;
sqlitePersistTriggerStep(db, pTriggerStep);
return pTriggerStep;
}
/*
** Allocate space to hold a new trigger step. The allocated space
** holds both the TriggerStep object and the TriggerStep.target.z string.
**
** If an OOM error occurs, NULL is returned and db->mallocFailed is set.
*/
static TriggerStep *triggerStepAllocate(
sqlite3 *db, /* Database connection */
u8 op, /* Trigger opcode */
Token *pName /* The target name */
){
TriggerStep *pTriggerStep;
pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n);
if( pTriggerStep ){
char *z = (char*)&pTriggerStep[1];
memcpy(z, pName->z, pName->n);
pTriggerStep->target.z = z;
pTriggerStep->target.n = pName->n;
pTriggerStep->op = op;
}
return pTriggerStep;
}
@@ -371,27 +377,24 @@ TriggerStep *sqlite3TriggerInsertStep(
IdList *pColumn, /* List of columns in pTableName to insert into */
ExprList *pEList, /* The VALUE clause: a list of values to be inserted */
Select *pSelect, /* A SELECT statement that supplies values */
int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
u8 orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
){
TriggerStep *pTriggerStep;
assert(pEList == 0 || pSelect == 0);
assert(pEList != 0 || pSelect != 0 || db->mallocFailed);
pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName);
if( pTriggerStep ){
pTriggerStep->op = TK_INSERT;
pTriggerStep->pSelect = pSelect;
pTriggerStep->target = *pTableName;
pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
pTriggerStep->pIdList = pColumn;
pTriggerStep->pExprList = pEList;
pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
pTriggerStep->orconf = orconf;
sqlitePersistTriggerStep(db, pTriggerStep);
}else{
sqlite3IdListDelete(db, pColumn);
sqlite3ExprListDelete(db, pEList);
sqlite3SelectDelete(db, pSelect);
}
sqlite3ExprListDelete(db, pEList);
sqlite3SelectDelete(db, pSelect);
return pTriggerStep;
}
@@ -406,22 +409,18 @@ TriggerStep *sqlite3TriggerUpdateStep(
Token *pTableName, /* Name of the table to be updated */
ExprList *pEList, /* The SET clause: list of column and new values */
Expr *pWhere, /* The WHERE clause */
int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
u8 orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
){
TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
if( pTriggerStep==0 ){
sqlite3ExprListDelete(db, pEList);
sqlite3ExprDelete(db, pWhere);
return 0;
TriggerStep *pTriggerStep;
pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName);
if( pTriggerStep ){
pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
pTriggerStep->orconf = orconf;
}
pTriggerStep->op = TK_UPDATE;
pTriggerStep->target = *pTableName;
pTriggerStep->pExprList = pEList;
pTriggerStep->pWhere = pWhere;
pTriggerStep->orconf = orconf;
sqlitePersistTriggerStep(db, pTriggerStep);
sqlite3ExprListDelete(db, pEList);
sqlite3ExprDelete(db, pWhere);
return pTriggerStep;
}
@@ -435,18 +434,14 @@ TriggerStep *sqlite3TriggerDeleteStep(
Token *pTableName, /* The table from which rows are deleted */
Expr *pWhere /* The WHERE clause */
){
TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
if( pTriggerStep==0 ){
sqlite3ExprDelete(db, pWhere);
return 0;
TriggerStep *pTriggerStep;
pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName);
if( pTriggerStep ){
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
pTriggerStep->orconf = OE_Default;
}
pTriggerStep->op = TK_DELETE;
pTriggerStep->target = *pTableName;
pTriggerStep->pWhere = pWhere;
pTriggerStep->orconf = OE_Default;
sqlitePersistTriggerStep(db, pTriggerStep);
sqlite3ExprDelete(db, pWhere);
return pTriggerStep;
}
@@ -460,7 +455,6 @@ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){
sqlite3DbFree(db, pTrigger->table);
sqlite3ExprDelete(db, pTrigger->pWhen);
sqlite3IdListDelete(db, pTrigger->pColumns);
if( pTrigger->nameToken.dyn ) sqlite3DbFree(db, (char*)pTrigger->nameToken.z);
sqlite3DbFree(db, pTrigger);
}
@@ -582,7 +576,7 @@ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
Hash *pHash = &(db->aDb[iDb].pSchema->trigHash);
Trigger *pTrigger;
pTrigger = sqlite3HashInsert(pHash, zName, sqlite3Strlen30(zName), 0);
if( pTrigger ){
if( ALWAYS(pTrigger) ){
if( pTrigger->pSchema==pTrigger->pTabSchema ){
Table *pTab = tableOfTrigger(pTrigger);
Trigger **pp;
@@ -603,9 +597,9 @@ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
** it matches anything so always return true. Return false only
** if there is no match.
*/
static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
static int checkColumnOverlap(IdList *pIdList, ExprList *pEList){
int e;
if( !pIdList || !pEList ) return 1;
if( pIdList==0 || NEVER(pEList==0) ) return 1;
for(e=0; e<pEList->nExpr; e++){
if( sqlite3IdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
}
@@ -630,7 +624,7 @@ Trigger *sqlite3TriggersExist(
Trigger *p;
assert( pList==0 || IsVirtual(pTab)==0 );
for(p=pList; p; p=p->pNext){
if( p->op==op && checkColumnOverLap(p->pColumns, pChanges) ){
if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){
mask |= p->tr_tm;
}
}
@@ -654,19 +648,19 @@ static SrcList *targetSrcList(
Parse *pParse, /* The parsing context */
TriggerStep *pStep /* The trigger containing the target token */
){
Token sDb; /* Dummy database name token */
int iDb; /* Index of the database to use */
SrcList *pSrc; /* SrcList to be returned */
iDb = sqlite3SchemaToIndex(pParse->db, pStep->pTrig->pSchema);
if( iDb==0 || iDb>=2 ){
assert( iDb<pParse->db->nDb );
sDb.z = (u8*)pParse->db->aDb[iDb].zName;
sDb.n = sqlite3Strlen30((char*)sDb.z);
sDb.quoted = 0;
pSrc = sqlite3SrcListAppend(pParse->db, 0, &sDb, &pStep->target);
} else {
pSrc = sqlite3SrcListAppend(pParse->db, 0, &pStep->target, 0);
pSrc = sqlite3SrcListAppend(pParse->db, 0, &pStep->target, 0);
if( pSrc ){
assert( pSrc->nSrc>0 );
assert( pSrc->a!=0 );
iDb = sqlite3SchemaToIndex(pParse->db, pStep->pTrig->pSchema);
if( iDb==0 || iDb>=2 ){
sqlite3 *db = pParse->db;
assert( iDb<pParse->db->nDb );
pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName);
}
}
return pSrc;
}
@@ -694,17 +688,6 @@ static int codeTriggerProgram(
orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
pParse->trigStack->orconf = orconf;
switch( pTriggerStep->op ){
case TK_SELECT: {
Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect, 0);
if( ss ){
SelectDest dest;
sqlite3SelectDestInit(&dest, SRT_Discard, 0);
sqlite3Select(pParse, ss, &dest);
sqlite3SelectDelete(db, ss);
}
break;
}
case TK_UPDATE: {
SrcList *pSrc;
pSrc = targetSrcList(pParse, pTriggerStep);
@@ -735,8 +718,17 @@ static int codeTriggerProgram(
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
break;
}
default:
assert(0);
default: assert( pTriggerStep->op==TK_SELECT ); {
Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect, 0);
if( ss ){
SelectDest dest;
sqlite3SelectDestInit(&dest, SRT_Discard, 0);
sqlite3Select(pParse, ss, &dest);
sqlite3SelectDelete(db, ss);
}
break;
}
}
pTriggerStep = pTriggerStep->pNext;
}
@@ -802,12 +794,18 @@ int sqlite3CodeRowTrigger(
for(p=pTrigger; p; p=p->pNext){
int fire_this = 0;
/* Sanity checking: The schema for the trigger and for the table are
** always defined. The trigger must be in the same schema as the table
** or else it must be a TEMP trigger. */
assert( p->pSchema!=0 );
assert( p->pTabSchema!=0 );
assert( p->pSchema==p->pTabSchema || p->pSchema==db->aDb[1].pSchema );
/* Determine whether we should code this trigger */
if(
p->op==op &&
p->tr_tm==tr_tm &&
(p->pSchema==p->pTabSchema || p->pSchema==db->aDb[1].pSchema) &&
(op!=TK_UPDATE||!p->pColumns||checkColumnOverLap(p->pColumns,pChanges))
checkColumnOverlap(p->pColumns,pChanges)
){
TriggerStack *pS; /* Pointer to trigger-stack entry */
for(pS=pParse->trigStack; pS && p!=pS->pTrigger; pS=pS->pNext){}
+33 -16
View File
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.200 2009/05/05 15:46:10 drh Exp $
** $Id: update.c,v 1.207 2009/08/08 18:01:08 drh Exp $
*/
#include "sqliteInt.h"
@@ -53,8 +53,13 @@ static void updateVirtualTable(
** the column is a literal number, string or null. The sqlite3ValueFromExpr()
** function is capable of transforming these types of expressions into
** sqlite3_value objects.
**
** If parameter iReg is not negative, code an OP_RealAffinity instruction
** on register iReg. This is used when an equivalent integer value is
** stored in place of an 8-byte floating point value in order to save
** space.
*/
void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i){
void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
assert( pTab!=0 );
if( !pTab->pSelect ){
sqlite3_value *pValue;
@@ -67,6 +72,11 @@ void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i){
if( pValue ){
sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM);
}
#ifndef SQLITE_OMIT_FLOATING_POINT
if( iReg>=0 && pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
}
#endif
}
}
@@ -127,7 +137,7 @@ void sqlite3Update(
int regData; /* New data for the row */
int regRowSet = 0; /* Rowset of rows to be updated */
sContext.pParse = 0;
memset(&sContext, 0, sizeof(sContext));
db = pParse->db;
if( pParse->nErr || db->mallocFailed ){
goto update_cleanup;
@@ -155,10 +165,10 @@ void sqlite3Update(
# define isView 0
#endif
if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto update_cleanup;
}
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
goto update_cleanup;
}
aXRef = sqlite3DbMallocRaw(db, sizeof(int) * pTab->nCol );
@@ -451,7 +461,7 @@ void sqlite3Update(
if( (i<32 && (new_col_mask&((u32)1<<i))!=0) || new_col_mask==0xffffffff ){
if( j<0 ){
sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regCols+i);
sqlite3ColumnDefault(v, pTab, i);
sqlite3ColumnDefault(v, pTab, i, -1);
}else{
sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr, regCols+i);
}
@@ -502,7 +512,7 @@ void sqlite3Update(
j = aXRef[i];
if( j<0 ){
sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regData+i);
sqlite3ColumnDefault(v, pTab, i);
sqlite3ColumnDefault(v, pTab, i, regData+i);
}else{
sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regData+i);
}
@@ -564,6 +574,14 @@ void sqlite3Update(
sqlite3VdbeAddOp2(v, OP_Close, oldIdx, 0);
}
/* Update the sqlite_sequence table by storing the content of the
** maximum rowid counter values recorded while inserting into
** autoincrement tables.
*/
if( pParse->nested==0 && pParse->trigStack==0 ){
sqlite3AutoincrementEnd(pParse);
}
/*
** Return the number of rows that were changed. If this routine is
** generating code because of a call to sqlite3NestedParse(), do not
@@ -623,17 +641,17 @@ static void updateVirtualTable(
int addr; /* Address of top of loop */
int iReg; /* First register in set passed to OP_VUpdate */
sqlite3 *db = pParse->db; /* Database connection */
const char *pVtab = (const char*)pTab->pVtab;
const char *pVTab = (const char*)sqlite3GetVTable(db, pTab);
SelectDest dest;
/* Construct the SELECT statement that will find the new values for
** all updated rows.
*/
pEList = sqlite3ExprListAppend(pParse, 0,
sqlite3CreateIdExpr(pParse, "_rowid_"), 0);
sqlite3CreateIdExpr(pParse, "_rowid_"));
if( pRowid ){
pEList = sqlite3ExprListAppend(pParse, pEList,
sqlite3ExprDup(db, pRowid, 0), 0);
sqlite3ExprDup(db, pRowid, 0));
}
assert( pTab->iPKey<0 );
for(i=0; i<pTab->nCol; i++){
@@ -642,7 +660,7 @@ static void updateVirtualTable(
}else{
pExpr = sqlite3CreateIdExpr(pParse, pTab->aCol[i].zName);
}
pEList = sqlite3ExprListAppend(pParse, pEList, pExpr, 0);
pEList = sqlite3ExprListAppend(pParse, pEList, pExpr);
}
pSelect = sqlite3SelectNew(pParse, pEList, pSrc, pWhere, 0, 0, 0, 0, 0, 0);
@@ -661,17 +679,16 @@ static void updateVirtualTable(
/* Generate code to scan the ephemeral table and call VUpdate. */
iReg = ++pParse->nMem;
pParse->nMem += pTab->nCol+1;
sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0);
addr = sqlite3VdbeCurrentAddr(v);
addr = sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0);
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, 0, iReg);
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, (pRowid?1:0), iReg+1);
for(i=0; i<pTab->nCol; i++){
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i);
}
sqlite3VtabMakeWritable(pParse, pTab);
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVtab, P4_VTAB);
sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr);
sqlite3VdbeJumpHere(v, addr-1);
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVTab, P4_VTAB);
sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1);
sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
/* Cleanup */
+22 -34
View File
@@ -14,7 +14,7 @@
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.254 2009/05/06 19:03:14 drh Exp $
** $Id: util.c,v 1.262 2009/07/28 16:44:26 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
@@ -32,27 +32,6 @@ void sqlite3Coverage(int x){
}
#endif
/*
** Routine needed to support the ALWAYS() and NEVER() macros.
**
** The argument to ALWAYS() should always be true and the argument
** to NEVER() should always be false. If either is not the case
** then this routine is called in order to throw an error.
**
** This routine only exists if assert() is operational. It always
** throws an assert on its first invocation. The variable has a long
** name to help the assert() message be more readable. The variable
** is used to prevent a too-clever optimizer from optimizing out the
** entire call.
*/
#ifndef NDEBUG
int sqlite3Assert(void){
static volatile int ALWAYS_was_false_or_NEVER_was_true = 0;
assert( ALWAYS_was_false_or_NEVER_was_true ); /* Always fails */
return ALWAYS_was_false_or_NEVER_was_true++; /* Not Reached */
}
#endif
/*
** Return true if the floating point value is Not a Number (NaN).
**
@@ -108,6 +87,7 @@ int sqlite3IsNaN(double x){
*/
int sqlite3Strlen30(const char *z){
const char *z2 = z;
if( z==0 ) return 0;
while( *z2 ){ z2++; }
return 0x3fffffff & (int)(z2 - z);
}
@@ -170,14 +150,11 @@ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
va_list ap;
sqlite3 *db = pParse->db;
pParse->nErr++;
testcase( pParse->zErrMsg!=0 );
sqlite3DbFree(db, pParse->zErrMsg);
va_start(ap, zFormat);
pParse->zErrMsg = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap);
if( pParse->rc==SQLITE_OK ){
pParse->rc = SQLITE_ERROR;
}
pParse->rc = SQLITE_ERROR;
}
/*
@@ -248,7 +225,7 @@ int sqlite3StrICmp(const char *zLeft, const char *zRight){
while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
return UpperToLower[*a] - UpperToLower[*b];
}
int sqlite3StrNICmp(const char *zLeft, const char *zRight, int N){
int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
register unsigned char *a, *b;
a = (unsigned char *)zLeft;
b = (unsigned char *)zRight;
@@ -394,7 +371,7 @@ int sqlite3AtoF(const char *z, double *pResult){
*/
static int compare2pow63(const char *zNum){
int c;
c = memcmp(zNum,"922337203685477580",18);
c = memcmp(zNum,"922337203685477580",18)*10;
if( c==0 ){
c = zNum[18] - '8';
}
@@ -449,9 +426,12 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum){
}
/*
** The string zNum represents an unsigned integer. There might be some other
** information following the integer too, but that part is ignored.
** If the integer that the prefix of zNum represents will fit in a
** The string zNum represents an unsigned integer. The zNum string
** consists of one or more digit characters and is terminated by
** a zero character. Any stray characters in zNum result in undefined
** behavior.
**
** If the unsigned integer that zNum represents will fit in a
** 64-bit signed integer, return TRUE. Otherwise return FALSE.
**
** If the negFlag parameter is true, that means that zNum really represents
@@ -463,7 +443,7 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum){
** Leading zeros are ignored.
*/
int sqlite3FitsIn64Bits(const char *zNum, int negFlag){
int i, c;
int i;
int neg = 0;
assert( zNum[0]>='0' && zNum[0]<='9' ); /* zNum is an unsigned number */
@@ -472,7 +452,7 @@ int sqlite3FitsIn64Bits(const char *zNum, int negFlag){
while( *zNum=='0' ){
zNum++; /* Skip leading zeros. Ticket #2454 */
}
for(i=0; (c=zNum[i])>='0' && c<='9'; i++){}
for(i=0; zNum[i]; i++){ assert( zNum[i]>='0' && zNum[i]<='9' ); }
if( i<19 ){
/* Guaranteed to fit if less than 19 digits */
return 1;
@@ -765,6 +745,10 @@ u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
/*
** Read a 32-bit variable-length integer from memory starting at p[0].
** Return the number of bytes read. The value is stored in *v.
**
** If the varint stored in p[0] is larger than can fit in a 32-bit unsigned
** integer, then set *v to 0xffffffff.
**
** A MACRO version, getVarint32, is provided which inlines the
** single-byte case. All code should use the MACRO version as
** this function assumes the single-byte case has already been handled.
@@ -830,7 +814,11 @@ u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
p -= 2;
n = sqlite3GetVarint(p, &v64);
assert( n>3 && n<=9 );
*v = (u32)v64;
if( (v64 & SQLITE_MAX_U32)!=v64 ){
*v = 0xffffffff;
}else{
*v = (u32)v64;
}
return n;
}
+8 -11
View File
@@ -14,7 +14,7 @@
** Most of the code in this file may be omitted by defining the
** SQLITE_OMIT_VACUUM macro.
**
** $Id: vacuum.c,v 1.88 2009/05/05 17:37:23 drh Exp $
** $Id: vacuum.c,v 1.91 2009/07/02 07:47:33 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@@ -83,14 +83,13 @@ void sqlite3Vacuum(Parse *pParse){
int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
int rc = SQLITE_OK; /* Return code from service routines */
Btree *pMain; /* The database being vacuumed */
Pager *pMainPager; /* Pager for database being vacuumed */
Btree *pTemp; /* The temporary database we vacuum into */
char *zSql = 0; /* SQL statements */
int saved_flags; /* Saved value of the db->flags */
int saved_nChange; /* Saved value of db->nChange */
int saved_nTotalChange; /* Saved value of db->nTotalChange */
Db *pDb = 0; /* Database to detach at end of vacuum */
int isMemDb; /* True is vacuuming a :memory: database */
int isMemDb; /* True if vacuuming a :memory: database */
int nRes;
if( !db->autoCommit ){
@@ -105,8 +104,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
pMain = db->aDb[0].pBt;
pMainPager = sqlite3BtreePager(pMain);
isMemDb = sqlite3PagerFile(pMainPager)->pMethods==0;
isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
/* Attach the temporary database as 'vacuum_db'. The synchronous pragma
** can be set to 'off' for this file, as it is not recovered if a crash
@@ -243,10 +241,10 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
** connections to the same database will know to reread the schema.
*/
static const unsigned char aCopy[] = {
1, 1, /* Add one to the old schema cookie */
3, 0, /* Preserve the default page cache size */
5, 0, /* Preserve the default text encoding */
6, 0, /* Preserve the user version */
BTREE_SCHEMA_VERSION, 1, /* Add one to the old schema cookie */
BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */
BTREE_TEXT_ENCODING, 0, /* Preserve the text encoding */
BTREE_USER_VERSION, 0, /* Preserve the user version */
};
assert( 1==sqlite3BtreeIsInTrans(pTemp) );
@@ -256,8 +254,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
for(i=0; i<ArraySize(aCopy); i+=2){
/* GetMeta() and UpdateMeta() cannot fail in this context because
** we already have page 1 loaded into cache and marked dirty. */
rc = sqlite3BtreeGetMeta(pMain, aCopy[i], &meta);
if( NEVER(rc!=SQLITE_OK) ) goto end_of_vacuum;
sqlite3BtreeGetMeta(pMain, aCopy[i], &meta);
rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], meta+aCopy[i+1]);
if( NEVER(rc!=SQLITE_OK) ) goto end_of_vacuum;
}
+579 -492
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.141 2009/04/10 00:56:29 drh Exp $
** $Id: vdbe.h,v 1.142 2009/07/24 17:58:53 danielk1977 Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@@ -58,7 +58,7 @@ struct VdbeOp {
VdbeFunc *pVdbeFunc; /* Used when p4type is P4_VDBEFUNC */
CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */
Mem *pMem; /* Used when p4type is P4_MEM */
sqlite3_vtab *pVtab; /* Used when p4type is P4_VTAB */
VTable *pVtab; /* Used when p4type is P4_VTAB */
KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
int *ai; /* Used when p4type is P4_INTARRAY */
} p4;
+28 -45
View File
@@ -15,19 +15,11 @@
** 6000 lines long) it was split up into several smaller files and
** this header information was factored out.
**
** $Id: vdbeInt.h,v 1.170 2009/05/04 11:42:30 danielk1977 Exp $
** $Id: vdbeInt.h,v 1.174 2009/06/23 14:15:04 drh Exp $
*/
#ifndef _VDBEINT_H_
#define _VDBEINT_H_
/*
** intToKey() and keyToInt() used to transform the rowid. But with
** the latest versions of the design they are no-ops.
*/
#define keyToInt(X) (X)
#define intToKey(X) (X)
/*
** SQL is translated into a sequence of instructions to be
** executed by a virtual machine. Each instruction is an instance
@@ -262,22 +254,25 @@ struct Context {
** method function.
*/
struct Vdbe {
sqlite3 *db; /* The whole database */
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
int nOp; /* Number of instructions in the program */
int nOpAlloc; /* Number of slots allocated for aOp[] */
Op *aOp; /* Space to hold the virtual machine's program */
int nLabel; /* Number of labels used */
int nLabelAlloc; /* Number of slots allocated in aLabel[] */
int *aLabel; /* Space to hold the labels */
Mem **apArg; /* Arguments to currently executing user function */
Mem *aColName; /* Column names to return */
int nCursor; /* Number of slots in apCsr[] */
VdbeCursor **apCsr; /* One element of this array for each open cursor */
int nVar; /* Number of entries in aVar[] */
Mem *aVar; /* Values for the OP_Variable opcode. */
char **azVar; /* Name of variables */
int okVar; /* True if azVar[] has been initialized */
sqlite3 *db; /* The database connection that owns this statement */
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
int nOp; /* Number of instructions in the program */
int nOpAlloc; /* Number of slots allocated for aOp[] */
Op *aOp; /* Space to hold the virtual machine's program */
int nLabel; /* Number of labels used */
int nLabelAlloc; /* Number of slots allocated in aLabel[] */
int *aLabel; /* Space to hold the labels */
Mem **apArg; /* Arguments to currently executing user function */
Mem *aColName; /* Column names to return */
Mem *pResultSet; /* Pointer to an array of results */
u16 nResColumn; /* Number of columns in one row of the result set */
u16 nCursor; /* Number of slots in apCsr[] */
VdbeCursor **apCsr; /* One element of this array for each open cursor */
u8 errorAction; /* Recovery action to do in case of an error */
u8 okVar; /* True if azVar[] has been initialized */
u16 nVar; /* Number of entries in aVar[] */
Mem *aVar; /* Values for the OP_Variable opcode. */
char **azVar; /* Name of variables */
u32 magic; /* Magic number for sanity checking */
int nMem; /* Number of memory locations currently allocated */
Mem *aMem; /* The memory locations */
@@ -287,11 +282,7 @@ struct Vdbe {
Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/
int pc; /* The program counter */
int rc; /* Value to return */
int errorAction; /* Recovery action to do in case of an error */
int nResColumn; /* Number of columns in one row of the result set */
char **azResColumn; /* Values for one row of result */
char *zErrMsg; /* Error message written here */
Mem *pResultSet; /* Pointer to an array of results */
u8 explain; /* True if EXPLAIN present on SQL command */
u8 changeCntOn; /* True to update the change-counter */
u8 expired; /* True if the VM needs to be recompiled */
@@ -301,23 +292,15 @@ struct Vdbe {
u8 readOnly; /* True for read-only statements */
u8 isPrepareV2; /* True if prepared with prepare_v2() */
int nChange; /* Number of db changes made since last reset */
i64 startTime; /* Time when query started - used for profiling */
int btreeMask; /* Bitmask of db->aDb[] entries referenced */
i64 startTime; /* Time when query started - used for profiling */
BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
int aCounter[2]; /* Counters used by sqlite3_stmt_status() */
char *zSql; /* Text of the SQL statement that generated this */
char *zSql; /* Text of the SQL statement that generated this */
void *pFree; /* Free this when deleting the vdbe */
#ifdef SQLITE_DEBUG
FILE *trace; /* Write an execution trace here, if not NULL */
#endif
int iStatement; /* Statement number (or 0 if has not opened stmt) */
#ifdef SQLITE_SSE
int fetchId; /* Statement number used by sqlite3_fetch_statement */
int lru; /* Counter used for LRU cache replacement */
#endif
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
Vdbe *pLruPrev;
Vdbe *pLruNext;
#ifdef SQLITE_DEBUG
FILE *trace; /* Write an execution trace here, if not NULL */
#endif
};
@@ -338,15 +321,15 @@ int sqlite3VdbeCursorMoveto(VdbeCursor*);
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
void sqlite3VdbePrintOp(FILE*, int, Op*);
#endif
int sqlite3VdbeSerialTypeLen(u32);
u32 sqlite3VdbeSerialTypeLen(u32);
u32 sqlite3VdbeSerialType(Mem*, int);
int sqlite3VdbeSerialPut(unsigned char*, int, Mem*, int);
int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
u32 sqlite3VdbeSerialPut(unsigned char*, int, Mem*, int);
u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*);
int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
int sqlite3VdbeIdxRowid(sqlite3*, BtCursor *, i64 *);
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
int sqlite3VdbeExec(Vdbe*);
int sqlite3VdbeList(Vdbe*);
+39 -182
View File
@@ -13,167 +13,11 @@
** This file contains code use to implement APIs that are part of the
** VDBE.
**
** $Id: vdbeapi.c,v 1.164 2009/04/27 18:46:06 drh Exp $
** $Id: vdbeapi.c,v 1.167 2009/06/25 01:47:12 drh Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
#if 0 && defined(SQLITE_ENABLE_MEMORY_MANAGEMENT)
/*
** The following structure contains pointers to the end points of a
** doubly-linked list of all compiled SQL statements that may be holding
** buffers eligible for release when the sqlite3_release_memory() interface is
** invoked. Access to this list is protected by the SQLITE_MUTEX_STATIC_LRU2
** mutex.
**
** Statements are added to the end of this list when sqlite3_reset() is
** called. They are removed either when sqlite3_step() or sqlite3_finalize()
** is called. When statements are added to this list, the associated
** register array (p->aMem[1..p->nMem]) may contain dynamic buffers that
** can be freed using sqlite3VdbeReleaseMemory().
**
** When statements are added or removed from this list, the mutex
** associated with the Vdbe being added or removed (Vdbe.db->mutex) is
** already held. The LRU2 mutex is then obtained, blocking if necessary,
** the linked-list pointers manipulated and the LRU2 mutex relinquished.
*/
struct StatementLruList {
Vdbe *pFirst;
Vdbe *pLast;
};
static struct StatementLruList sqlite3LruStatements;
/*
** Check that the list looks to be internally consistent. This is used
** as part of an assert() statement as follows:
**
** assert( stmtLruCheck() );
*/
#ifndef NDEBUG
static int stmtLruCheck(){
Vdbe *p;
for(p=sqlite3LruStatements.pFirst; p; p=p->pLruNext){
assert(p->pLruNext || p==sqlite3LruStatements.pLast);
assert(!p->pLruNext || p->pLruNext->pLruPrev==p);
assert(p->pLruPrev || p==sqlite3LruStatements.pFirst);
assert(!p->pLruPrev || p->pLruPrev->pLruNext==p);
}
return 1;
}
#endif
/*
** Add vdbe p to the end of the statement lru list. It is assumed that
** p is not already part of the list when this is called. The lru list
** is protected by the SQLITE_MUTEX_STATIC_LRU mutex.
*/
static void stmtLruAdd(Vdbe *p){
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU2));
if( p->pLruPrev || p->pLruNext || sqlite3LruStatements.pFirst==p ){
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU2));
return;
}
assert( stmtLruCheck() );
if( !sqlite3LruStatements.pFirst ){
assert( !sqlite3LruStatements.pLast );
sqlite3LruStatements.pFirst = p;
sqlite3LruStatements.pLast = p;
}else{
assert( !sqlite3LruStatements.pLast->pLruNext );
p->pLruPrev = sqlite3LruStatements.pLast;
sqlite3LruStatements.pLast->pLruNext = p;
sqlite3LruStatements.pLast = p;
}
assert( stmtLruCheck() );
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU2));
}
/*
** Assuming the SQLITE_MUTEX_STATIC_LRU2 mutext is already held, remove
** statement p from the least-recently-used statement list. If the
** statement is not currently part of the list, this call is a no-op.
*/
static void stmtLruRemoveNomutex(Vdbe *p){
if( p->pLruPrev || p->pLruNext || p==sqlite3LruStatements.pFirst ){
assert( stmtLruCheck() );
if( p->pLruNext ){
p->pLruNext->pLruPrev = p->pLruPrev;
}else{
sqlite3LruStatements.pLast = p->pLruPrev;
}
if( p->pLruPrev ){
p->pLruPrev->pLruNext = p->pLruNext;
}else{
sqlite3LruStatements.pFirst = p->pLruNext;
}
p->pLruNext = 0;
p->pLruPrev = 0;
assert( stmtLruCheck() );
}
}
/*
** Assuming the SQLITE_MUTEX_STATIC_LRU2 mutext is not held, remove
** statement p from the least-recently-used statement list. If the
** statement is not currently part of the list, this call is a no-op.
*/
static void stmtLruRemove(Vdbe *p){
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU2));
stmtLruRemoveNomutex(p);
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU2));
}
/*
** Try to release n bytes of memory by freeing buffers associated
** with the memory registers of currently unused vdbes.
*/
int sqlite3VdbeReleaseMemory(int n){
Vdbe *p;
Vdbe *pNext;
int nFree = 0;
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU2));
for(p=sqlite3LruStatements.pFirst; p && nFree<n; p=pNext){
pNext = p->pLruNext;
/* For each statement handle in the lru list, attempt to obtain the
** associated database mutex. If it cannot be obtained, continue
** to the next statement handle. It is not possible to block on
** the database mutex - that could cause deadlock.
*/
if( SQLITE_OK==sqlite3_mutex_try(p->db->mutex) ){
nFree += sqlite3VdbeReleaseBuffers(p);
stmtLruRemoveNomutex(p);
sqlite3_mutex_leave(p->db->mutex);
}
}
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU2));
return nFree;
}
/*
** Call sqlite3Reprepare() on the statement. Remove it from the
** lru list before doing so, as Reprepare() will free all the
** memory register buffers anyway.
*/
int vdbeReprepare(Vdbe *p){
stmtLruRemove(p);
return sqlite3Reprepare(p);
}
#else /* !SQLITE_ENABLE_MEMORY_MANAGEMENT */
#define stmtLruRemove(x)
#define stmtLruAdd(x)
#define vdbeReprepare(x) sqlite3Reprepare(x)
#endif
#ifndef SQLITE_OMIT_DEPRECATED
/*
** Return TRUE (non-zero) of the statement supplied as an argument needs
@@ -209,7 +53,6 @@ int sqlite3_finalize(sqlite3_stmt *pStmt){
sqlite3_mutex *mutex = v->db->mutex;
#endif
sqlite3_mutex_enter(mutex);
stmtLruRemove(v);
rc = sqlite3VdbeFinalize(v);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(mutex);
@@ -233,7 +76,6 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
Vdbe *v = (Vdbe*)pStmt;
sqlite3_mutex_enter(v->db->mutex);
rc = sqlite3VdbeReset(v);
stmtLruAdd(v);
sqlite3VdbeMakeReady(v, -1, 0, 0, 0);
assert( (rc & (v->db->errMask))==rc );
rc = sqlite3ApiExit(v->db, rc);
@@ -313,7 +155,22 @@ int sqlite3_value_type(sqlite3_value* pVal){
/**************************** sqlite3_result_ *******************************
** The following routines are used by user-defined functions to specify
** the function result.
**
** The setStrOrError() funtion calls sqlite3VdbeMemSetStr() to store the
** result as a string or blob but if the string or blob is too large, it
** then sets the error code to SQLITE_TOOBIG
*/
static void setResultStrOrError(
sqlite3_context *pCtx, /* Function context */
const char *z, /* String pointer */
int n, /* Bytes in string, or negative */
u8 enc, /* Encoding of z. 0 for BLOBs */
void (*xDel)(void*) /* Destructor function */
){
if( sqlite3VdbeMemSetStr(&pCtx->s, z, n, enc, xDel)==SQLITE_TOOBIG ){
sqlite3_result_error_toobig(pCtx);
}
}
void sqlite3_result_blob(
sqlite3_context *pCtx,
const void *z,
@@ -322,7 +179,7 @@ void sqlite3_result_blob(
){
assert( n>=0 );
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, 0, xDel);
setResultStrOrError(pCtx, z, n, 0, xDel);
}
void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
@@ -359,7 +216,7 @@ void sqlite3_result_text(
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, xDel);
setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel);
}
#ifndef SQLITE_OMIT_UTF16
void sqlite3_result_text16(
@@ -369,7 +226,7 @@ void sqlite3_result_text16(
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, xDel);
setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel);
}
void sqlite3_result_text16be(
sqlite3_context *pCtx,
@@ -378,7 +235,7 @@ void sqlite3_result_text16be(
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16BE, xDel);
setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel);
}
void sqlite3_result_text16le(
sqlite3_context *pCtx,
@@ -387,7 +244,7 @@ void sqlite3_result_text16le(
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16LE, xDel);
setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel);
}
#endif /* SQLITE_OMIT_UTF16 */
void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
@@ -477,7 +334,6 @@ static int sqlite3Step(Vdbe *p){
db->activeVdbeCnt++;
if( p->readOnly==0 ) db->writeVdbeCnt++;
p->pc = 0;
stmtLruRemove(p);
}
#ifndef SQLITE_OMIT_EXPLAIN
if( p->explain ){
@@ -537,19 +393,6 @@ end_of_step:
** sqlite3Step() to do most of the work. If a schema error occurs,
** call sqlite3Reprepare() and try again.
*/
#ifdef SQLITE_OMIT_PARSER
int sqlite3_step(sqlite3_stmt *pStmt){
int rc = SQLITE_MISUSE;
if( pStmt ){
Vdbe *v;
v = (Vdbe*)pStmt;
sqlite3_mutex_enter(v->db->mutex);
rc = sqlite3Step(v);
sqlite3_mutex_leave(v->db->mutex);
}
return rc;
}
#else
int sqlite3_step(sqlite3_stmt *pStmt){
int rc = SQLITE_MISUSE;
if( pStmt ){
@@ -559,7 +402,7 @@ int sqlite3_step(sqlite3_stmt *pStmt){
sqlite3_mutex_enter(db->mutex);
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
&& cnt++ < 5
&& (rc = vdbeReprepare(v))==SQLITE_OK ){
&& (rc = sqlite3Reprepare(v))==SQLITE_OK ){
sqlite3_reset(pStmt);
v->expired = 0;
}
@@ -586,7 +429,6 @@ int sqlite3_step(sqlite3_stmt *pStmt){
}
return rc;
}
#endif
/*
** Extract the user data from a sqlite3_context structure and return a
@@ -766,8 +608,23 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
vals = sqlite3_data_count(pStmt);
pOut = &pVm->pResultSet[i];
}else{
/* ((double)0) In case of SQLITE_OMIT_FLOATING_POINT... */
static const Mem nullMem = {{0}, (double)0, 0, "", 0, MEM_Null, SQLITE_NULL, 0, 0, 0 };
/* If the value passed as the second argument is out of range, return
** a pointer to the following static Mem object which contains the
** value SQL NULL. Even though the Mem structure contains an element
** of type i64, on certain architecture (x86) with certain compiler
** switches (-Os), gcc may align this Mem object on a 4-byte boundary
** instead of an 8-byte one. This all works fine, except that when
** running with SQLITE_DEBUG defined the SQLite code sometimes assert()s
** that a Mem structure is located on an 8-byte boundary. To prevent
** this assert() from failing, when building with SQLITE_DEBUG defined
** using gcc, force nullMem to be 8-byte aligned using the magical
** __attribute__((aligned(8))) macro. */
static const Mem nullMem
#if defined(SQLITE_DEBUG) && defined(__GNUC__)
__attribute__((aligned(8)))
#endif
= {{0}, (double)0, 0, "", 0, MEM_Null, SQLITE_NULL, 0, 0, 0 };
if( pVm && ALWAYS(pVm->db) ){
sqlite3_mutex_enter(pVm->db->mutex);
sqlite3Error(pVm->db, SQLITE_RANGE, 0);
+155 -99
View File
@@ -14,7 +14,7 @@
** to version 2.8.7, all this code was combined into the vdbe.c source file.
** But that file was getting too big so this subroutines were split out.
**
** $Id: vdbeaux.c,v 1.457 2009/05/06 18:57:10 shane Exp $
** $Id: vdbeaux.c,v 1.480 2009/08/08 18:01:08 drh Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@@ -145,7 +145,7 @@ int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
assert( op>0 && op<0xff );
if( p->nOpAlloc<=i ){
if( growOpArray(p) ){
return 0;
return 1;
}
}
p->nOp++;
@@ -350,7 +350,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
return 0;
}
addr = p->nOp;
if( nOp>0 ){
if( ALWAYS(nOp>0) ){
int i;
VdbeOpList const *pIn = aOp;
for(i=0; i<nOp; i++, pIn++){
@@ -386,8 +386,9 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
** few minor changes to the program.
*/
void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
assert( p==0 || p->magic==VDBE_MAGIC_INIT );
if( p && addr>=0 && p->nOp>addr && p->aOp ){
assert( p!=0 );
assert( addr>=0 );
if( p->nOp>addr ){
p->aOp[addr].p1 = val;
}
}
@@ -397,8 +398,9 @@ void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
** This routine is useful for setting a jump destination.
*/
void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
assert( p==0 || p->magic==VDBE_MAGIC_INIT );
if( p && addr>=0 && p->nOp>addr && p->aOp ){
assert( p!=0 );
assert( addr>=0 );
if( p->nOp>addr ){
p->aOp[addr].p2 = val;
}
}
@@ -407,8 +409,9 @@ void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
** Change the value of the P3 operand for a specific instruction.
*/
void sqlite3VdbeChangeP3(Vdbe *p, int addr, int val){
assert( p==0 || p->magic==VDBE_MAGIC_INIT );
if( p && addr>=0 && p->nOp>addr && p->aOp ){
assert( p!=0 );
assert( addr>=0 );
if( p->nOp>addr ){
p->aOp[addr].p3 = val;
}
}
@@ -418,8 +421,8 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, int val){
** added operation.
*/
void sqlite3VdbeChangeP5(Vdbe *p, u8 val){
assert( p==0 || p->magic==VDBE_MAGIC_INIT );
if( p && p->aOp ){
assert( p!=0 );
if( p->aOp ){
assert( p->nOp>0 );
p->aOp[p->nOp-1].p5 = val;
}
@@ -439,7 +442,7 @@ void sqlite3VdbeJumpHere(Vdbe *p, int addr){
** the FuncDef is not ephermal, then do nothing.
*/
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
if( pDef && (pDef->flags & SQLITE_FUNC_EPHEM)!=0 ){
if( ALWAYS(pDef) && (pDef->flags & SQLITE_FUNC_EPHEM)!=0 ){
sqlite3DbFree(db, pDef);
}
}
@@ -475,6 +478,10 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
sqlite3ValueFree((sqlite3_value*)p4);
break;
}
case P4_VTAB : {
sqlite3VtabUnlock((VTable *)p4);
break;
}
}
}
}
@@ -484,7 +491,7 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
** Change N opcodes starting at addr to No-ops.
*/
void sqlite3VdbeChangeToNoop(Vdbe *p, int addr, int N){
if( p && p->aOp ){
if( p->aOp ){
VdbeOp *pOp = &p->aOp[addr];
sqlite3 *db = p->db;
while( N-- ){
@@ -528,15 +535,15 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
db = p->db;
assert( p->magic==VDBE_MAGIC_INIT );
if( p->aOp==0 || db->mallocFailed ){
if (n != P4_KEYINFO) {
if ( n!=P4_KEYINFO && n!=P4_VTAB ) {
freeP4(db, n, (void*)*(char**)&zP4);
}
return;
}
assert( p->nOp>0 );
assert( addr<p->nOp );
if( addr<0 ){
addr = p->nOp - 1;
if( addr<0 ) return;
}
pOp = &p->aOp[addr];
freeP4(db, pOp->p4type, pOp->p4.p);
@@ -573,6 +580,11 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
}else if( n==P4_KEYINFO_HANDOFF ){
pOp->p4.p = (void*)zP4;
pOp->p4type = P4_KEYINFO;
}else if( n==P4_VTAB ){
pOp->p4.p = (void*)zP4;
pOp->p4type = P4_VTAB;
sqlite3VtabLock((VTable *)zP4);
assert( ((VTable *)zP4)->db==p->db );
}else if( n<0 ){
pOp->p4.p = (void*)zP4;
pOp->p4type = (signed char)n;
@@ -618,12 +630,38 @@ void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){
#endif /* NDEBUG */
/*
** Return the opcode for a given address.
** Return the opcode for a given address. If the address is -1, then
** return the most recently inserted opcode.
**
** If a memory allocation error has occurred prior to the calling of this
** routine, then a pointer to a dummy VdbeOp will be returned. That opcode
** is readable and writable, but it has no effect. The return of a dummy
** opcode allows the call to continue functioning after a OOM fault without
** having to check to see if the return from this routine is a valid pointer.
**
** About the #ifdef SQLITE_OMIT_TRACE: Normally, this routine is never called
** unless p->nOp>0. This is because in the absense of SQLITE_OMIT_TRACE,
** an OP_Trace instruction is always inserted by sqlite3VdbeGet() as soon as
** a new VDBE is created. So we are free to set addr to p->nOp-1 without
** having to double-check to make sure that the result is non-negative. But
** if SQLITE_OMIT_TRACE is defined, the OP_Trace is omitted and we do need to
** check the value of p->nOp-1 before continuing.
*/
VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
static VdbeOp dummy;
assert( p->magic==VDBE_MAGIC_INIT );
if( addr<0 ){
#ifdef SQLITE_OMIT_TRACE
if( p->nOp==0 ) return &dummy;
#endif
addr = p->nOp - 1;
}
assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed );
return ((addr>=0 && addr<p->nOp)?(&p->aOp[addr]):0);
if( p->db->mallocFailed ){
return &dummy;
}else{
return &p->aOp[addr];
}
}
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
@@ -702,7 +740,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
case P4_VTAB: {
sqlite3_vtab *pVtab = pOp->p4.pVtab;
sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab;
sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule);
break;
}
@@ -840,7 +878,7 @@ int sqlite3VdbeList(
Mem *pMem = p->pResultSet = &p->aMem[1];
assert( p->explain );
if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
assert( p->magic==VDBE_MAGIC_RUN );
assert( db->magic==SQLITE_MAGIC_BUSY );
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY || p->rc==SQLITE_NOMEM );
@@ -1026,7 +1064,7 @@ static void allocSpace(
assert( EIGHT_BYTE_ALIGNMENT(*ppFrom) );
if( (*(void**)pp)==0 ){
nByte = ROUND8(nByte);
if( (pEnd - *ppFrom)>=nByte ){
if( &(*ppFrom)[nByte] <= pEnd ){
*(void**)pp = (void *)*ppFrom;
*ppFrom += nByte;
}else{
@@ -1088,7 +1126,7 @@ void sqlite3VdbeMakeReady(
** first time this function is called for a given VDBE, not when it is
** being called from sqlite3_reset() to reset the virtual machine.
*/
if( nVar>=0 && !db->mallocFailed ){
if( nVar>=0 && ALWAYS(db->mallocFailed==0) ){
u8 *zCsr = (u8 *)&p->aOp[p->nOp];
u8 *zEnd = (u8 *)&p->aOp[p->nOpAlloc];
int nByte;
@@ -1097,12 +1135,11 @@ void sqlite3VdbeMakeReady(
if( isExplain && nMem<10 ){
nMem = 10;
}
memset(zCsr, 0, zEnd-zCsr);
zCsr += (zCsr - (u8*)0)&7;
assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
if( zEnd<zCsr ) zEnd = zCsr;
do {
memset(zCsr, 0, zEnd-zCsr);
nByte = 0;
allocSpace((char*)&p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
allocSpace((char*)&p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
@@ -1112,15 +1149,15 @@ void sqlite3VdbeMakeReady(
nCursor*sizeof(VdbeCursor*), &zCsr, zEnd, &nByte
);
if( nByte ){
p->pFree = sqlite3DbMallocRaw(db, nByte);
p->pFree = sqlite3DbMallocZero(db, nByte);
}
zCsr = p->pFree;
zEnd = &zCsr[nByte];
}while( nByte && !db->mallocFailed );
p->nCursor = nCursor;
p->nCursor = (u16)nCursor;
if( p->aVar ){
p->nVar = nVar;
p->nVar = (u16)nVar;
for(n=0; n<nVar; n++){
p->aVar[n].flags = MEM_Null;
p->aVar[n].db = db;
@@ -1193,15 +1230,14 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
}
/*
** Close all cursors except for VTab cursors that are currently
** in use.
** Close all cursors.
*/
static void closeAllCursorsExceptActiveVtabs(Vdbe *p){
static void closeAllCursors(Vdbe *p){
int i;
if( p->apCsr==0 ) return;
for(i=0; i<p->nCursor; i++){
VdbeCursor *pC = p->apCsr[i];
if( pC && (!p->inVtabMethod || !pC->pVtabCursor) ){
if( pC ){
sqlite3VdbeFreeCursor(p, pC);
p->apCsr[i] = 0;
}
@@ -1219,7 +1255,7 @@ static void Cleanup(Vdbe *p){
int i;
sqlite3 *db = p->db;
Mem *pMem;
closeAllCursorsExceptActiveVtabs(p);
closeAllCursors(p);
for(pMem=&p->aMem[1], i=1; i<=p->nMem; i++, pMem++){
if( pMem->flags & MEM_RowSet ){
sqlite3RowSetClear(pMem->u.pRowSet);
@@ -1252,7 +1288,7 @@ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
sqlite3DbFree(db, p->aColName);
n = nResColumn*COLNAME_N;
p->nResColumn = nResColumn;
p->nResColumn = (u16)nResColumn;
p->aColName = pColName = (Mem*)sqlite3DbMallocZero(db, sizeof(Mem)*n );
if( p->aColName==0 ) return;
while( n-- > 0 ){
@@ -1306,6 +1342,13 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
int rc = SQLITE_OK;
int needXcommit = 0;
#ifdef SQLITE_OMIT_VIRTUALTABLE
/* With this option, sqlite3VtabSync() is defined to be simply
** SQLITE_OK so p is not used.
*/
UNUSED_PARAMETER(p);
#endif
/* Before doing anything else, call the xSync() callback for any
** virtual module tables written in this transaction. This has to
** be done before determining whether a master journal file is
@@ -1333,12 +1376,9 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
/* If there are any write-transactions at all, invoke the commit hook */
if( needXcommit && db->xCommitCallback ){
assert( (db->flags & SQLITE_CommitBusy)==0 );
db->flags |= SQLITE_CommitBusy;
(void)sqlite3SafetyOff(db);
rc = db->xCommitCallback(db->pCommitArg);
(void)sqlite3SafetyOn(db);
db->flags &= ~SQLITE_CommitBusy;
if( rc ){
return SQLITE_CONSTRAINT;
}
@@ -1581,7 +1621,13 @@ static void invalidateCursorsOnModifiedBtrees(sqlite3 *db){
int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
sqlite3 *const db = p->db;
int rc = SQLITE_OK;
if( p->iStatement && db->nStatement ){
/* If p->iStatement is greater than zero, then this Vdbe opened a
** statement transaction that should be closed here. The only exception
** is that an IO error may have occured, causing an emergency rollback.
** In this case (db->nStatement==0), and there is nothing to do.
*/
if( db->nStatement && p->iStatement ){
int i;
const int iSavepoint = p->iStatement-1;
@@ -1673,7 +1719,7 @@ int sqlite3VdbeHalt(Vdbe *p){
if( p->db->mallocFailed ){
p->rc = SQLITE_NOMEM;
}
closeAllCursorsExceptActiveVtabs(p);
closeAllCursors(p);
if( p->magic!=VDBE_MAGIC_RUN ){
return SQLITE_OK;
}
@@ -1690,6 +1736,7 @@ int sqlite3VdbeHalt(Vdbe *p){
/* Check for one of the special errors */
mrc = p->rc & 0xff;
assert( p->rc!=SQLITE_IOERR_BLOCKED ); /* This error no longer exists */
isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR
|| mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL;
if( isSpecialError ){
@@ -1697,11 +1744,7 @@ int sqlite3VdbeHalt(Vdbe *p){
** proceed with the special handling.
*/
if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){
if( p->rc==SQLITE_IOERR_BLOCKED && p->usesStmtJournal ){
eStatementOp = SAVEPOINT_ROLLBACK;
p->rc = SQLITE_BUSY;
}else if( (mrc==SQLITE_NOMEM || mrc==SQLITE_FULL)
&& p->usesStmtJournal ){
if( (mrc==SQLITE_NOMEM || mrc==SQLITE_FULL) && p->usesStmtJournal ){
eStatementOp = SAVEPOINT_ROLLBACK;
}else{
/* We are forced to roll back the active transaction. Before doing
@@ -1724,7 +1767,6 @@ int sqlite3VdbeHalt(Vdbe *p){
if( !sqlite3VtabInSync(db)
&& db->autoCommit
&& db->writeVdbeCnt==(p->readOnly==0)
&& (db->flags & SQLITE_CommitBusy)==0
){
if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
/* The auto-commit flag is true, and the vdbe program was
@@ -1776,7 +1818,7 @@ int sqlite3VdbeHalt(Vdbe *p){
/* If this was an INSERT, UPDATE or DELETE and no statement transaction
** has been rolled back, update the database connection change-counter.
*/
if( p->changeCntOn && p->pc>=0 ){
if( p->changeCntOn ){
if( eStatementOp!=SAVEPOINT_ROLLBACK ){
sqlite3VdbeSetChanges(db, p->nChange);
}else{
@@ -1923,8 +1965,6 @@ int sqlite3VdbeFinalize(Vdbe *p){
if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){
rc = sqlite3VdbeReset(p);
assert( (rc & p->db->errMask)==rc );
}else if( p->magic!=VDBE_MAGIC_INIT ){
return SQLITE_MISUSE;
}
sqlite3VdbeDelete(p);
return rc;
@@ -1956,7 +1996,7 @@ void sqlite3VdbeDelete(Vdbe *p){
int i;
sqlite3 *db;
if( p==0 ) return;
if( NEVER(p==0) ) return;
db = p->db;
if( p->pPrev ){
p->pPrev->pNext = p->pNext;
@@ -1988,9 +2028,17 @@ void sqlite3VdbeDelete(Vdbe *p){
}
/*
** Make sure the cursor p is ready to read or write the row to which it
** was last positioned. Return an error code if an OOM fault or I/O error
** prevents us from positioning the cursor to its correct position.
**
** If a MoveTo operation is pending on the given cursor, then do that
** MoveTo now. Return an error code. If no MoveTo is pending, this
** routine does nothing and returns SQLITE_OK.
** MoveTo now. If no move is pending, check to see if the row has been
** deleted out from under the cursor and if it has, mark the row as
** a NULL row.
**
** If the cursor is already pointing to the correct row and that row has
** not been deleted out from under the cursor, then this routine is a no-op.
*/
int sqlite3VdbeCursorMoveto(VdbeCursor *p){
if( p->deferredMoveto ){
@@ -2001,7 +2049,7 @@ int sqlite3VdbeCursorMoveto(VdbeCursor *p){
assert( p->isTable );
rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res);
if( rc ) return rc;
p->lastRowid = keyToInt(p->movetoTarget);
p->lastRowid = p->movetoTarget;
p->rowidIsValid = ALWAYS(res==0) ?1:0;
if( NEVER(res<0) ){
rc = sqlite3BtreeNext(p->pCursor, &res);
@@ -2012,7 +2060,7 @@ int sqlite3VdbeCursorMoveto(VdbeCursor *p){
#endif
p->deferredMoveto = 0;
p->cacheStatus = CACHE_STALE;
}else if( p->pCursor ){
}else if( ALWAYS(p->pCursor) ){
int hasMoved;
int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved);
if( rc ) return rc;
@@ -2107,7 +2155,7 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
/*
** Return the length of the data corresponding to the supplied serial-type.
*/
int sqlite3VdbeSerialTypeLen(u32 serial_type){
u32 sqlite3VdbeSerialTypeLen(u32 serial_type){
if( serial_type>=12 ){
return (serial_type-12)/2;
}else{
@@ -2187,14 +2235,14 @@ static u64 floatSwap(u64 in){
** of bytes in the zero-filled tail is included in the return value only
** if those bytes were zeroed in buf[].
*/
int sqlite3VdbeSerialPut(u8 *buf, int nBuf, Mem *pMem, int file_format){
u32 sqlite3VdbeSerialPut(u8 *buf, int nBuf, Mem *pMem, int file_format){
u32 serial_type = sqlite3VdbeSerialType(pMem, file_format);
int len;
u32 len;
/* Integer and Real */
if( serial_type<=7 && serial_type>0 ){
u64 v;
int i;
u32 i;
if( serial_type==7 ){
assert( sizeof(v)==sizeof(pMem->r) );
memcpy(&v, &pMem->r, sizeof(v));
@@ -2203,7 +2251,7 @@ int sqlite3VdbeSerialPut(u8 *buf, int nBuf, Mem *pMem, int file_format){
v = pMem->u.i;
}
len = i = sqlite3VdbeSerialTypeLen(serial_type);
assert( len<=nBuf );
assert( len<=(u32)nBuf );
while( i-- ){
buf[i] = (u8)(v&0xFF);
v >>= 8;
@@ -2214,14 +2262,15 @@ int sqlite3VdbeSerialPut(u8 *buf, int nBuf, Mem *pMem, int file_format){
/* String or blob */
if( serial_type>=12 ){
assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.nZero:0)
== sqlite3VdbeSerialTypeLen(serial_type) );
== (int)sqlite3VdbeSerialTypeLen(serial_type) );
assert( pMem->n<=nBuf );
len = pMem->n;
memcpy(buf, pMem->z, len);
if( pMem->flags & MEM_Zero ){
len += pMem->u.nZero;
if( len>nBuf ){
len = nBuf;
assert( nBuf>=0 );
if( len > (u32)nBuf ){
len = (u32)nBuf;
}
memset(&buf[pMem->n], 0, len-pMem->n);
}
@@ -2236,7 +2285,7 @@ int sqlite3VdbeSerialPut(u8 *buf, int nBuf, Mem *pMem, int file_format){
** Deserialize the data blob pointed to by buf as serial type serial_type
** and store the result in pMem. Return the number of bytes read.
*/
int sqlite3VdbeSerialGet(
u32 sqlite3VdbeSerialGet(
const unsigned char *buf, /* Buffer to deserialize from */
u32 serial_type, /* Serial type to deserialize */
Mem *pMem /* Memory cell to write value into */
@@ -2314,7 +2363,7 @@ int sqlite3VdbeSerialGet(
return 0;
}
default: {
int len = (serial_type-12)/2;
u32 len = (serial_type-12)/2;
pMem->z = (char *)buf;
pMem->n = len;
pMem->xDel = 0;
@@ -2384,11 +2433,10 @@ UnpackedRecord *sqlite3VdbeRecordUnpack(
idx = getVarint32(aKey, szHdr);
d = szHdr;
u = 0;
while( idx<szHdr && u<p->nField ){
while( idx<szHdr && u<p->nField && d<=nKey ){
u32 serial_type;
idx += getVarint32(&aKey[idx], serial_type);
if( d>=nKey && sqlite3VdbeSerialTypeLen(serial_type)>0 ) break;
pMem->enc = pKeyInfo->enc;
pMem->db = pKeyInfo->db;
pMem->flags = 0;
@@ -2403,22 +2451,24 @@ UnpackedRecord *sqlite3VdbeRecordUnpack(
}
/*
** This routine destroys a UnpackedRecord object
** This routine destroys a UnpackedRecord object.
*/
void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){
if( p ){
if( p->flags & UNPACKED_NEED_DESTROY ){
int i;
Mem *pMem;
for(i=0, pMem=p->aMem; i<p->nField; i++, pMem++){
if( pMem->zMalloc ){
sqlite3VdbeMemRelease(pMem);
}
}
}
if( p->flags & UNPACKED_NEED_FREE ){
sqlite3DbFree(p->pKeyInfo->db, p);
}
int i;
Mem *pMem;
assert( p!=0 );
assert( p->flags & UNPACKED_NEED_DESTROY );
for(i=0, pMem=p->aMem; i<p->nField; i++, pMem++){
/* The unpacked record is always constructed by the
** sqlite3VdbeUnpackRecord() function above, which makes all
** strings and blobs static. And none of the elements are
** ever transformed, so there is never anything to delete.
*/
if( NEVER(pMem->zMalloc) ) sqlite3VdbeMemRelease(pMem);
}
if( p->flags & UNPACKED_NEED_FREE ){
sqlite3DbFree(p->pKeyInfo->db, p);
}
}
@@ -2495,7 +2545,9 @@ int sqlite3VdbeRecordCompare(
}
i++;
}
if( mem1.zMalloc ) sqlite3VdbeMemRelease(&mem1);
/* No memory allocation is ever used on mem1. */
if( NEVER(mem1.zMalloc) ) sqlite3VdbeMemRelease(&mem1);
/* If the PREFIX_SEARCH flag is set and all fields except the final
** rowid field were equal, then clear the PREFIX_SEARCH flag and set
@@ -2542,7 +2594,7 @@ int sqlite3VdbeRecordCompare(
** pCur might be pointing to text obtained from a corrupt database file.
** So the content cannot be trusted. Do appropriate checks on the content.
*/
int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
i64 nCellKey = 0;
int rc;
u32 szHdr; /* Size of the header */
@@ -2551,15 +2603,18 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
Mem m, v;
/* Get the size of the index entry. Only indices entries of less
** than 2GiB are support - anything large must be database corruption */
sqlite3BtreeKeySize(pCur, &nCellKey);
if( unlikely(nCellKey<=0 || nCellKey>0x7fffffff) ){
return SQLITE_CORRUPT_BKPT;
}
** than 2GiB are support - anything large must be database corruption.
** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so
** this code can safely assume that nCellKey is 32-bits
*/
assert( sqlite3BtreeCursorIsValid(pCur) );
rc = sqlite3BtreeKeySize(pCur, &nCellKey);
assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */
assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey );
/* Read in the complete content of the index entry */
m.flags = 0;
m.db = 0;
m.db = db;
m.zMalloc = 0;
rc = sqlite3VdbeMemFromBtree(pCur, 0, (int)nCellKey, 1, &m);
if( rc ){
@@ -2568,9 +2623,9 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
/* The index entry must begin with a header size */
(void)getVarint32((u8*)m.z, szHdr);
testcase( szHdr==2 );
testcase( szHdr==3 );
testcase( szHdr==m.n );
if( unlikely(szHdr<2 || (int)szHdr>m.n) ){
if( unlikely(szHdr<3 || (int)szHdr>m.n) ){
goto idx_rowid_corruption;
}
@@ -2589,8 +2644,8 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
goto idx_rowid_corruption;
}
lenRowid = sqlite3VdbeSerialTypeLen(typeRowid);
testcase( m.n-lenRowid==szHdr );
if( unlikely(m.n-lenRowid<szHdr) ){
testcase( (u32)m.n==szHdr+lenRowid );
if( unlikely((u32)m.n<szHdr+lenRowid) ){
goto idx_rowid_corruption;
}
@@ -2609,22 +2664,19 @@ idx_rowid_corruption:
}
/*
** Compare the key of the index entry that cursor pC is point to against
** the key string in pKey (of length nKey). Write into *pRes a number
** Compare the key of the index entry that cursor pC is pointing to against
** the key string in pUnpacked. Write into *pRes a number
** that is negative, zero, or positive if pC is less than, equal to,
** or greater than pKey. Return SQLITE_OK on success.
** or greater than pUnpacked. Return SQLITE_OK on success.
**
** pKey is either created without a rowid or is truncated so that it
** pUnpacked is either created without a rowid or is truncated so that it
** omits the rowid at the end. The rowid at the end of the index entry
** is ignored as well. Hence, this routine only compares the prefixes
** of the keys prior to the final rowid, not the entire key.
**
** pUnpacked may be an unpacked version of pKey,nKey. If pUnpacked is
** supplied it is used in place of pKey,nKey.
*/
int sqlite3VdbeIdxKeyCompare(
VdbeCursor *pC, /* The cursor to compare against */
UnpackedRecord *pUnpacked, /* Unpacked version of pKey and nKey */
UnpackedRecord *pUnpacked, /* Unpacked version of key to compare against */
int *res /* Write the comparison result here */
){
i64 nCellKey = 0;
@@ -2632,10 +2684,14 @@ int sqlite3VdbeIdxKeyCompare(
BtCursor *pCur = pC->pCursor;
Mem m;
sqlite3BtreeKeySize(pCur, &nCellKey);
assert( sqlite3BtreeCursorIsValid(pCur) );
rc = sqlite3BtreeKeySize(pCur, &nCellKey);
assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */
/* nCellKey will always be between 0 and 0xffffffff because of the say
** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */
if( nCellKey<=0 || nCellKey>0x7fffffff ){
*res = 0;
return SQLITE_OK;
return SQLITE_CORRUPT;
}
m.db = 0;
m.flags = 0;
+72 -48
View File
@@ -12,7 +12,7 @@
**
** This file contains code used to implement incremental BLOB I/O.
**
** $Id: vdbeblob.c,v 1.31 2009/03/24 15:08:10 drh Exp $
** $Id: vdbeblob.c,v 1.35 2009/07/02 07:47:33 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -66,56 +66,62 @@ int sqlite3_blob_open(
static const VdbeOpList openBlob[] = {
{OP_Transaction, 0, 0, 0}, /* 0: Start a transaction */
{OP_VerifyCookie, 0, 0, 0}, /* 1: Check the schema cookie */
{OP_TableLock, 0, 0, 0}, /* 2: Acquire a read or write lock */
/* One of the following two instructions is replaced by an
** OP_Noop before exection.
*/
{OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */
{OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */
/* One of the following two instructions is replaced by an OP_Noop. */
{OP_OpenRead, 0, 0, 0}, /* 3: Open cursor 0 for reading */
{OP_OpenWrite, 0, 0, 0}, /* 4: Open cursor 0 for read/write */
{OP_Variable, 1, 1, 1}, /* 4: Push the rowid to the stack */
{OP_NotExists, 0, 8, 1}, /* 5: Seek the cursor */
{OP_Column, 0, 0, 1}, /* 6 */
{OP_ResultRow, 1, 0, 0}, /* 7 */
{OP_Close, 0, 0, 0}, /* 8 */
{OP_Halt, 0, 0, 0}, /* 9 */
{OP_Variable, 1, 1, 1}, /* 5: Push the rowid to the stack */
{OP_NotExists, 0, 9, 1}, /* 6: Seek the cursor */
{OP_Column, 0, 0, 1}, /* 7 */
{OP_ResultRow, 1, 0, 0}, /* 8 */
{OP_Close, 0, 0, 0}, /* 9 */
{OP_Halt, 0, 0, 0}, /* 10 */
};
Vdbe *v = 0;
int rc = SQLITE_OK;
char zErr[128];
char *zErr = 0;
Table *pTab;
Parse *pParse;
zErr[0] = 0;
*ppBlob = 0;
sqlite3_mutex_enter(db->mutex);
pParse = sqlite3StackAllocRaw(db, sizeof(*pParse));
if( pParse==0 ){
rc = SQLITE_NOMEM;
goto blob_open_out;
}
do {
Parse sParse;
Table *pTab;
memset(&sParse, 0, sizeof(Parse));
sParse.db = db;
memset(pParse, 0, sizeof(Parse));
pParse->db = db;
if( sqlite3SafetyOn(db) ){
sqlite3DbFree(db, zErr);
sqlite3StackFree(db, pParse);
sqlite3_mutex_leave(db->mutex);
return SQLITE_MISUSE;
}
sqlite3BtreeEnterAll(db);
pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb);
pTab = sqlite3LocateTable(pParse, 0, zTable, zDb);
if( pTab && IsVirtual(pTab) ){
pTab = 0;
sqlite3ErrorMsg(&sParse, "cannot open virtual table: %s", zTable);
sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable);
}
#ifndef SQLITE_OMIT_VIEW
if( pTab && pTab->pSelect ){
pTab = 0;
sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable);
}
#endif
if( !pTab ){
if( sParse.zErrMsg ){
sqlite3_snprintf(sizeof(zErr), zErr, "%s", sParse.zErrMsg);
if( pParse->zErrMsg ){
sqlite3DbFree(db, zErr);
zErr = pParse->zErrMsg;
pParse->zErrMsg = 0;
}
sqlite3DbFree(db, sParse.zErrMsg);
rc = SQLITE_ERROR;
(void)sqlite3SafetyOff(db);
sqlite3BtreeLeaveAll(db);
@@ -129,7 +135,8 @@ int sqlite3_blob_open(
}
}
if( iCol==pTab->nCol ){
sqlite3_snprintf(sizeof(zErr), zErr, "no such column: \"%s\"", zColumn);
sqlite3DbFree(db, zErr);
zErr = sqlite3MPrintf(db, "no such column: \"%s\"", zColumn);
rc = SQLITE_ERROR;
(void)sqlite3SafetyOff(db);
sqlite3BtreeLeaveAll(db);
@@ -146,7 +153,8 @@ int sqlite3_blob_open(
int j;
for(j=0; j<pIdx->nColumn; j++){
if( pIdx->aiColumn[j]==iCol ){
sqlite3_snprintf(sizeof(zErr), zErr,
sqlite3DbFree(db, zErr);
zErr = sqlite3MPrintf(db,
"cannot open indexed column for writing");
rc = SQLITE_ERROR;
(void)sqlite3SafetyOff(db);
@@ -161,10 +169,11 @@ int sqlite3_blob_open(
if( v ){
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob);
flags = !!flags; /* flags = (flags ? 1 : 0); */
/* Configure the OP_Transaction */
sqlite3VdbeChangeP1(v, 0, iDb);
sqlite3VdbeChangeP2(v, 0, (flags ? 1 : 0));
sqlite3VdbeChangeP2(v, 0, flags);
/* Configure the OP_VerifyCookie */
sqlite3VdbeChangeP1(v, 1, iDb);
@@ -173,12 +182,17 @@ int sqlite3_blob_open(
/* Make sure a mutex is held on the table to be accessed */
sqlite3VdbeUsesBtree(v, iDb);
/* Configure the OP_TableLock instruction */
sqlite3VdbeChangeP1(v, 2, iDb);
sqlite3VdbeChangeP2(v, 2, pTab->tnum);
sqlite3VdbeChangeP3(v, 2, flags);
sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
** parameter of the other to pTab->tnum.
*/
sqlite3VdbeChangeToNoop(v, (flags ? 2 : 3), 1);
sqlite3VdbeChangeP2(v, (flags ? 3 : 2), pTab->tnum);
sqlite3VdbeChangeP3(v, (flags ? 3 : 2), iDb);
** parameter of the other to pTab->tnum. */
sqlite3VdbeChangeToNoop(v, 4 - flags, 1);
sqlite3VdbeChangeP2(v, 3 + flags, pTab->tnum);
sqlite3VdbeChangeP3(v, 3 + flags, iDb);
/* Configure the number of columns. Configure the cursor to
** think that the table has one more column than it really
@@ -187,8 +201,8 @@ int sqlite3_blob_open(
** we can invoke OP_Column to fill in the vdbe cursors type
** and offset cache without causing any IO.
*/
sqlite3VdbeChangeP4(v, flags ? 3 : 2, SQLITE_INT_TO_PTR(pTab->nCol+1), P4_INT32);
sqlite3VdbeChangeP2(v, 6, pTab->nCol);
sqlite3VdbeChangeP4(v, 3+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
sqlite3VdbeChangeP2(v, 7, pTab->nCol);
if( !db->mallocFailed ){
sqlite3VdbeMakeReady(v, 1, 1, 1, 0);
}
@@ -196,7 +210,7 @@ int sqlite3_blob_open(
sqlite3BtreeLeaveAll(db);
rc = sqlite3SafetyOff(db);
if( rc!=SQLITE_OK || db->mallocFailed ){
if( NEVER(rc!=SQLITE_OK) || db->mallocFailed ){
goto blob_open_out;
}
@@ -205,7 +219,8 @@ int sqlite3_blob_open(
if( rc!=SQLITE_ROW ){
nAttempt++;
rc = sqlite3_finalize((sqlite3_stmt *)v);
sqlite3_snprintf(sizeof(zErr), zErr, sqlite3_errmsg(db));
sqlite3DbFree(db, zErr);
zErr = sqlite3MPrintf(db, sqlite3_errmsg(db));
v = 0;
}
} while( nAttempt<5 && rc==SQLITE_SCHEMA );
@@ -219,7 +234,8 @@ int sqlite3_blob_open(
u32 type = v->apCsr[0]->aType[iCol];
if( type<12 ){
sqlite3_snprintf(sizeof(zErr), zErr, "cannot open value of type %s",
sqlite3DbFree(db, zErr);
zErr = sqlite3MPrintf(db, "cannot open value of type %s",
type==0?"null": type==7?"real": "integer"
);
rc = SQLITE_ERROR;
@@ -242,16 +258,18 @@ int sqlite3_blob_open(
*ppBlob = (sqlite3_blob *)pBlob;
rc = SQLITE_OK;
}else if( rc==SQLITE_OK ){
sqlite3_snprintf(sizeof(zErr), zErr, "no such rowid: %lld", iRow);
sqlite3DbFree(db, zErr);
zErr = sqlite3MPrintf(db, "no such rowid: %lld", iRow);
rc = SQLITE_ERROR;
}
blob_open_out:
zErr[sizeof(zErr)-1] = '\0';
if( v && (rc!=SQLITE_OK || db->mallocFailed) ){
sqlite3VdbeFinalize(v);
}
sqlite3Error(db, rc, (rc==SQLITE_OK?0:zErr));
sqlite3Error(db, rc, zErr);
sqlite3DbFree(db, zErr);
sqlite3StackFree(db, pParse);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
@@ -266,11 +284,15 @@ int sqlite3_blob_close(sqlite3_blob *pBlob){
int rc;
sqlite3 *db;
db = p->db;
sqlite3_mutex_enter(db->mutex);
rc = sqlite3_finalize(p->pStmt);
sqlite3DbFree(db, p);
sqlite3_mutex_leave(db->mutex);
if( p ){
db = p->db;
sqlite3_mutex_enter(db->mutex);
rc = sqlite3_finalize(p->pStmt);
sqlite3DbFree(db, p);
sqlite3_mutex_leave(db->mutex);
}else{
rc = SQLITE_OK;
}
return rc;
}
@@ -287,8 +309,10 @@ static int blobReadWrite(
int rc;
Incrblob *p = (Incrblob *)pBlob;
Vdbe *v;
sqlite3 *db = p->db;
sqlite3 *db;
if( p==0 ) return SQLITE_MISUSE;
db = p->db;
sqlite3_mutex_enter(db->mutex);
v = (Vdbe*)p->pStmt;
@@ -344,7 +368,7 @@ int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
*/
int sqlite3_blob_bytes(sqlite3_blob *pBlob){
Incrblob *p = (Incrblob *)pBlob;
return p->nByte;
return p ? p->nByte : 0;
}
#endif /* #ifndef SQLITE_OMIT_INCRBLOB */
+58 -30
View File
@@ -15,7 +15,7 @@
** only within the VDBE. Interface routines refer to a Mem using the
** name sqlite_value
**
** $Id: vdbemem.c,v 1.144 2009/05/05 12:54:50 drh Exp $
** $Id: vdbemem.c,v 1.152 2009/07/22 18:07:41 drh Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@@ -96,7 +96,7 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){
}
}
if( preserve && pMem->z && pMem->zMalloc && pMem->z!=pMem->zMalloc ){
if( pMem->z && preserve && pMem->zMalloc && pMem->z!=pMem->zMalloc ){
memcpy(pMem->zMalloc, pMem->z, pMem->n);
}
if( pMem->flags&MEM_Dyn && pMem->xDel ){
@@ -245,7 +245,7 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
*/
int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
int rc = SQLITE_OK;
if( pFunc && pFunc->xFinalize ){
if( ALWAYS(pFunc && pFunc->xFinalize) ){
sqlite3_context ctx;
assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
@@ -258,7 +258,7 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
assert( 0==(pMem->flags&MEM_Dyn) && !pMem->xDel );
sqlite3DbFree(pMem->db, pMem->zMalloc);
memcpy(pMem, &ctx.s, sizeof(ctx.s));
rc = (ctx.isError?SQLITE_ERROR:SQLITE_OK);
rc = ctx.isError;
}
return rc;
}
@@ -411,7 +411,18 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
pMem->u.i = doubleToInt64(pMem->r);
if( pMem->r==(double)pMem->u.i ){
/* Only mark the value as an integer if
**
** (1) the round-trip conversion real->int->real is a no-op, and
** (2) The integer is neither the largest nor the smallest
** possible integer (ticket #3922)
**
** The second term in the following conditional enforces the second
** condition under the assumption that additional overflow causes
** values to wrap around.
*/
if( pMem->r==(double)pMem->u.i && (pMem->u.i-1) < (pMem->u.i+1) ){
pMem->flags |= MEM_Int;
}
}
@@ -487,6 +498,14 @@ void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){
if( n<0 ) n = 0;
pMem->u.nZero = n;
pMem->enc = SQLITE_UTF8;
#ifdef SQLITE_OMIT_INCRBLOB
sqlite3VdbeMemGrow(pMem, n, 0);
if( pMem->z ){
pMem->n = n;
memset(pMem->z, 0, n);
}
#endif
}
/*
@@ -522,12 +541,9 @@ void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
void sqlite3VdbeMemSetRowSet(Mem *pMem){
sqlite3 *db = pMem->db;
assert( db!=0 );
if( pMem->flags & MEM_RowSet ){
sqlite3RowSetClear(pMem->u.pRowSet);
}else{
sqlite3VdbeMemRelease(pMem);
pMem->zMalloc = sqlite3DbMallocRaw(db, 64);
}
assert( (pMem->flags & MEM_RowSet)==0 );
sqlite3VdbeMemRelease(pMem);
pMem->zMalloc = sqlite3DbMallocRaw(db, 64);
if( db->mallocFailed ){
pMem->flags = MEM_Null;
}else{
@@ -626,6 +642,12 @@ void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){
** string is copied into a (possibly existing) buffer managed by the
** Mem structure. Otherwise, any existing buffer is freed and the
** pointer copied.
**
** If the string is too large (if it exceeds the SQLITE_LIMIT_LENGTH
** size limit) then no memory allocation occurs. If the string can be
** stored without allocating memory, then it is. If a memory allocation
** is required to store the string, then value of pMem is unchanged. In
** either case, SQLITE_TOOBIG is returned.
*/
int sqlite3VdbeMemSetStr(
Mem *pMem, /* Memory cell to set to string value */
@@ -689,9 +711,6 @@ int sqlite3VdbeMemSetStr(
pMem->xDel = xDel;
flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn);
}
if( nByte>iLimit ){
return SQLITE_TOOBIG;
}
pMem->n = nByte;
pMem->flags = flags;
@@ -704,6 +723,10 @@ int sqlite3VdbeMemSetStr(
}
#endif
if( nByte>iLimit ){
return SQLITE_TOOBIG;
}
return SQLITE_OK;
}
@@ -848,13 +871,14 @@ int sqlite3VdbeMemFromBtree(
int key, /* If true, retrieve from the btree key, not data. */
Mem *pMem /* OUT: Return data in this Mem structure. */
){
char *zData; /* Data from the btree layer */
int available = 0; /* Number of bytes available on the local btree page */
sqlite3 *db; /* Database connection */
int rc = SQLITE_OK;
char *zData; /* Data from the btree layer */
int available = 0; /* Number of bytes available on the local btree page */
int rc = SQLITE_OK; /* Return code */
db = sqlite3BtreeCursorDb(pCur);
assert( sqlite3_mutex_held(db->mutex) );
assert( sqlite3BtreeCursorIsValid(pCur) );
/* Note: the calls to BtreeKeyFetch() and DataFetch() below assert()
** that both the BtShared and database handle mutexes are held. */
assert( (pMem->flags & MEM_RowSet)==0 );
if( key ){
zData = (char *)sqlite3BtreeKeyFetch(pCur, &available);
@@ -863,7 +887,7 @@ int sqlite3VdbeMemFromBtree(
}
assert( zData!=0 );
if( offset+amt<=available && ((pMem->flags&MEM_Dyn)==0 || pMem->xDel) ){
if( offset+amt<=available && (pMem->flags&MEM_Dyn)==0 ){
sqlite3VdbeMemRelease(pMem);
pMem->z = &zData[offset];
pMem->flags = MEM_Blob|MEM_Ephem;
@@ -974,10 +998,15 @@ int sqlite3ValueFromExpr(
op = pExpr->op;
if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
zVal = sqlite3DbStrNDup(db, (char*)pExpr->token.z, pExpr->token.n);
pVal = sqlite3ValueNew(db);
if( !zVal || !pVal ) goto no_mem;
sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
if( pVal==0 ) goto no_mem;
if( ExprHasProperty(pExpr, EP_IntValue) ){
sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue);
}else{
zVal = sqlite3DbStrDup(db, pExpr->u.zToken);
if( zVal==0 ) goto no_mem;
sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
}
if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){
sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8);
}else{
@@ -996,14 +1025,13 @@ int sqlite3ValueFromExpr(
#ifndef SQLITE_OMIT_BLOB_LITERAL
else if( op==TK_BLOB ){
int nVal;
assert( pExpr->token.n>=3 );
assert( pExpr->token.z[0]=='x' || pExpr->token.z[0]=='X' );
assert( pExpr->token.z[1]=='\'' );
assert( pExpr->token.z[pExpr->token.n-1]=='\'' );
assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' );
assert( pExpr->u.zToken[1]=='\'' );
pVal = sqlite3ValueNew(db);
if( !pVal ) goto no_mem;
nVal = pExpr->token.n - 3;
zVal = (char*)pExpr->token.z + 2;
zVal = &pExpr->u.zToken[2];
nVal = sqlite3Strlen30(zVal)-1;
assert( zVal[nVal]=='\'' );
sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(db, zVal, nVal), nVal/2,
0, SQLITE_DYNAMIC);
}
+303 -194
View File
@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to help implement virtual tables.
**
** $Id: vtab.c,v 1.86 2009/04/28 13:01:09 drh Exp $
** $Id: vtab.c,v 1.94 2009/08/08 18:01:08 drh Exp $
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"
@@ -27,7 +27,7 @@ static int createModule(
const sqlite3_module *pModule, /* The definition of the module */
void *pAux, /* Context pointer for xCreate/xConnect */
void (*xDestroy)(void *) /* Module destructor function */
) {
){
int rc, nName;
Module *pMod;
@@ -93,27 +93,128 @@ int sqlite3_create_module_v2(
** If a disconnect is attempted while a virtual table is locked,
** the disconnect is deferred until all locks have been removed.
*/
void sqlite3VtabLock(sqlite3_vtab *pVtab){
pVtab->nRef++;
void sqlite3VtabLock(VTable *pVTab){
pVTab->nRef++;
}
/*
** pTab is a pointer to a Table structure representing a virtual-table.
** Return a pointer to the VTable object used by connection db to access
** this virtual-table, if one has been created, or NULL otherwise.
*/
VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){
VTable *pVtab;
assert( IsVirtual(pTab) );
for(pVtab=pTab->pVTable; pVtab && pVtab->db!=db; pVtab=pVtab->pNext);
return pVtab;
}
/*
** Unlock a virtual table. When the last lock is removed,
** disconnect the virtual table.
** Decrement the ref-count on a virtual table object. When the ref-count
** reaches zero, call the xDisconnect() method to delete the object.
*/
void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){
assert( pVtab->nRef>0 );
pVtab->nRef--;
assert(db);
void sqlite3VtabUnlock(VTable *pVTab){
sqlite3 *db = pVTab->db;
assert( db );
assert( pVTab->nRef>0 );
assert( sqlite3SafetyCheckOk(db) );
if( pVtab->nRef==0 ){
if( db->magic==SQLITE_MAGIC_BUSY ){
(void)sqlite3SafetyOff(db);
pVtab->pModule->xDisconnect(pVtab);
(void)sqlite3SafetyOn(db);
} else {
pVtab->pModule->xDisconnect(pVtab);
pVTab->nRef--;
if( pVTab->nRef==0 ){
sqlite3_vtab *p = pVTab->pVtab;
if( p ){
#ifdef SQLITE_DEBUG
if( pVTab->db->magic==SQLITE_MAGIC_BUSY ){
(void)sqlite3SafetyOff(db);
p->pModule->xDisconnect(p);
(void)sqlite3SafetyOn(db);
} else
#endif
{
p->pModule->xDisconnect(p);
}
}
sqlite3DbFree(db, pVTab);
}
}
/*
** Table p is a virtual table. This function moves all elements in the
** p->pVTable list to the sqlite3.pDisconnect lists of their associated
** database connections to be disconnected at the next opportunity.
** Except, if argument db is not NULL, then the entry associated with
** connection db is left in the p->pVTable list.
*/
static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){
VTable *pRet = 0;
VTable *pVTable = p->pVTable;
p->pVTable = 0;
/* Assert that the mutex (if any) associated with the BtShared database
** that contains table p is held by the caller. See header comments
** above function sqlite3VtabUnlockList() for an explanation of why
** this makes it safe to access the sqlite3.pDisconnect list of any
** database connection that may have an entry in the p->pVTable list. */
assert( db==0 ||
sqlite3BtreeHoldsMutex(db->aDb[sqlite3SchemaToIndex(db, p->pSchema)].pBt)
);
while( pVTable ){
sqlite3 *db2 = pVTable->db;
VTable *pNext = pVTable->pNext;
assert( db2 );
if( db2==db ){
pRet = pVTable;
p->pVTable = pRet;
pRet->pNext = 0;
}else{
pVTable->pNext = db2->pDisconnect;
db2->pDisconnect = pVTable;
}
pVTable = pNext;
}
assert( !db || pRet );
return pRet;
}
/*
** Disconnect all the virtual table objects in the sqlite3.pDisconnect list.
**
** This function may only be called when the mutexes associated with all
** shared b-tree databases opened using connection db are held by the
** caller. This is done to protect the sqlite3.pDisconnect list. The
** sqlite3.pDisconnect list is accessed only as follows:
**
** 1) By this function. In this case, all BtShared mutexes and the mutex
** associated with the database handle itself must be held.
**
** 2) By function vtabDisconnectAll(), when it adds a VTable entry to
** the sqlite3.pDisconnect list. In this case either the BtShared mutex
** associated with the database the virtual table is stored in is held
** or, if the virtual table is stored in a non-sharable database, then
** the database handle mutex is held.
**
** As a result, a sqlite3.pDisconnect cannot be accessed simultaneously
** by multiple threads. It is thread-safe.
*/
void sqlite3VtabUnlockList(sqlite3 *db){
VTable *p = db->pDisconnect;
db->pDisconnect = 0;
assert( sqlite3BtreeHoldsAllMutexes(db) );
assert( sqlite3_mutex_held(db->mutex) );
if( p ){
sqlite3ExpirePreparedStatements(db);
do {
VTable *pNext = p->pNext;
sqlite3VtabUnlock(p);
p = pNext;
}while( p );
}
}
@@ -121,22 +222,24 @@ void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){
** Clear any and all virtual-table information from the Table record.
** This routine is called, for example, just before deleting the Table
** record.
**
** Since it is a virtual-table, the Table structure contains a pointer
** to the head of a linked list of VTable structures. Each VTable
** structure is associated with a single sqlite3* user of the schema.
** The reference count of the VTable structure associated with database
** connection db is decremented immediately (which may lead to the
** structure being xDisconnected and free). Any other VTable structures
** in the list are moved to the sqlite3.pDisconnect list of the associated
** database connection.
*/
void sqlite3VtabClear(Table *p){
sqlite3_vtab *pVtab = p->pVtab;
Schema *pSchema = p->pSchema;
sqlite3 *db = pSchema ? pSchema->db : 0;
if( pVtab ){
assert( p->pMod && p->pMod->pModule );
sqlite3VtabUnlock(db, pVtab);
p->pVtab = 0;
}
vtabDisconnectAll(0, p);
if( p->azModuleArg ){
int i;
for(i=0; i<p->nModuleArg; i++){
sqlite3DbFree(db, p->azModuleArg[i]);
sqlite3DbFree(p->dbMem, p->azModuleArg[i]);
}
sqlite3DbFree(db, p->azModuleArg);
sqlite3DbFree(p->dbMem, p->azModuleArg);
}
}
@@ -181,14 +284,9 @@ void sqlite3VtabBeginParse(
Table *pTable; /* The new virtual table */
sqlite3 *db; /* Database connection */
if( pParse->db->flags & SQLITE_SharedCache ){
sqlite3ErrorMsg(pParse, "Cannot use virtual tables in shared-cache mode");
return;
}
sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0);
pTable = pParse->pNewTable;
if( pTable==0 || pParse->nErr ) return;
if( pTable==0 ) return;
assert( 0==pTable->pIndex );
db = pParse->db;
@@ -221,7 +319,7 @@ void sqlite3VtabBeginParse(
** virtual table currently under construction in pParse->pTable.
*/
static void addArgumentToVtab(Parse *pParse){
if( pParse->sArg.z && pParse->pNewTable ){
if( pParse->sArg.z && ALWAYS(pParse->pNewTable) ){
const char *z = (const char*)pParse->sArg.z;
int n = pParse->sArg.n;
sqlite3 *db = pParse->db;
@@ -234,23 +332,13 @@ static void addArgumentToVtab(Parse *pParse){
** has been completely parsed.
*/
void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
Table *pTab; /* The table being constructed */
sqlite3 *db; /* The database connection */
char *zModule; /* The module name of the table: USING modulename */
Module *pMod = 0;
Table *pTab = pParse->pNewTable; /* The table being constructed */
sqlite3 *db = pParse->db; /* The database connection */
if( pTab==0 ) return;
addArgumentToVtab(pParse);
pParse->sArg.z = 0;
/* Lookup the module name. */
pTab = pParse->pNewTable;
if( pTab==0 ) return;
db = pParse->db;
if( pTab->nModuleArg<1 ) return;
zModule = pTab->azModuleArg[0];
pMod = (Module*)sqlite3HashFind(&db->aModule, zModule,
sqlite3Strlen30(zModule));
pTab->pMod = pMod;
/* If the CREATE VIRTUAL TABLE statement is being entered for the
** first time (in other words if the virtual table is actually being
@@ -301,9 +389,10 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
}
/* If we are rereading the sqlite_master table create the in-memory
** record of the table. If the module has already been registered,
** also call the xConnect method here.
*/
** record of the table. The xConnect() method is not called until
** the first time the virtual table is used in an SQL statement. This
** allows a schema that contains virtual tables to be loaded before
** the required virtual table implementations are registered. */
else {
Table *pOld;
Schema *pSchema = pTab->pSchema;
@@ -357,9 +446,8 @@ static int vtabCallConstructor(
int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
char **pzErr
){
VTable *pVTable;
int rc;
int rc2;
sqlite3_vtab *pVtab = 0;
const char *const*azArg = (const char *const*)pTab->azModuleArg;
int nArg = pTab->nModuleArg;
char *zErr = 0;
@@ -369,19 +457,23 @@ static int vtabCallConstructor(
return SQLITE_NOMEM;
}
pVTable = sqlite3DbMallocZero(db, sizeof(VTable));
if( !pVTable ){
sqlite3DbFree(db, zModuleName);
return SQLITE_NOMEM;
}
pVTable->db = db;
pVTable->pMod = pMod;
assert( !db->pVTab );
assert( xConstruct );
db->pVTab = pTab;
rc = sqlite3SafetyOff(db);
assert( rc==SQLITE_OK );
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVtab, &zErr);
rc2 = sqlite3SafetyOn(db);
if( rc==SQLITE_OK && pVtab ){
pVtab->pModule = pMod->pModule;
pVtab->nRef = 1;
pTab->pVtab = pVtab;
}
/* Invoke the virtual table constructor */
(void)sqlite3SafetyOff(db);
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
(void)sqlite3SafetyOn(db);
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
if( SQLITE_OK!=rc ){
if( zErr==0 ){
@@ -390,54 +482,61 @@ static int vtabCallConstructor(
*pzErr = sqlite3MPrintf(db, "%s", zErr);
sqlite3DbFree(db, zErr);
}
}else if( db->pVTab ){
const char *zFormat = "vtable constructor did not declare schema: %s";
*pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
rc = SQLITE_ERROR;
}
if( rc==SQLITE_OK ){
rc = rc2;
}
db->pVTab = 0;
sqlite3DbFree(db, zModuleName);
sqlite3DbFree(db, pVTable);
}else if( ALWAYS(pVTable->pVtab) ){
/* Justification of ALWAYS(): A correct vtab constructor must allocate
** the sqlite3_vtab object if successful. */
pVTable->pVtab->pModule = pMod->pModule;
pVTable->nRef = 1;
if( db->pVTab ){
const char *zFormat = "vtable constructor did not declare schema: %s";
*pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
sqlite3VtabUnlock(pVTable);
rc = SQLITE_ERROR;
}else{
int iCol;
/* If everything went according to plan, link the new VTable structure
** into the linked list headed by pTab->pVTable. Then loop through the
** columns of the table to see if any of them contain the token "hidden".
** If so, set the Column.isHidden flag and remove the token from
** the type string. */
pVTable->pNext = pTab->pVTable;
pTab->pVTable = pVTable;
/* If everything went according to plan, loop through the columns
** of the table to see if any of them contain the token "hidden".
** If so, set the Column.isHidden flag and remove the token from
** the type string.
*/
if( rc==SQLITE_OK ){
int iCol;
for(iCol=0; iCol<pTab->nCol; iCol++){
char *zType = pTab->aCol[iCol].zType;
int nType;
int i = 0;
if( !zType ) continue;
nType = sqlite3Strlen30(zType);
if( sqlite3StrNICmp("hidden", zType, 6) || (zType[6] && zType[6]!=' ') ){
for(i=0; i<nType; i++){
if( (0==sqlite3StrNICmp(" hidden", &zType[i], 7))
&& (zType[i+7]=='\0' || zType[i+7]==' ')
){
i++;
break;
for(iCol=0; iCol<pTab->nCol; iCol++){
char *zType = pTab->aCol[iCol].zType;
int nType;
int i = 0;
if( !zType ) continue;
nType = sqlite3Strlen30(zType);
if( sqlite3StrNICmp("hidden", zType, 6)||(zType[6] && zType[6]!=' ') ){
for(i=0; i<nType; i++){
if( (0==sqlite3StrNICmp(" hidden", &zType[i], 7))
&& (zType[i+7]=='\0' || zType[i+7]==' ')
){
i++;
break;
}
}
}
}
if( i<nType ){
int j;
int nDel = 6 + (zType[i+6] ? 1 : 0);
for(j=i; (j+nDel)<=nType; j++){
zType[j] = zType[j+nDel];
if( i<nType ){
int j;
int nDel = 6 + (zType[i+6] ? 1 : 0);
for(j=i; (j+nDel)<=nType; j++){
zType[j] = zType[j+nDel];
}
if( zType[i]=='\0' && i>0 ){
assert(zType[i-1]==' ');
zType[i-1] = '\0';
}
pTab->aCol[iCol].isHidden = 1;
}
if( zType[i]=='\0' && i>0 ){
assert(zType[i-1]==' ');
zType[i-1] = '\0';
}
pTab->aCol[iCol].isHidden = 1;
}
}
}
sqlite3DbFree(db, zModuleName);
db->pVTab = 0;
return rc;
}
@@ -449,21 +548,26 @@ static int vtabCallConstructor(
** This call is a no-op if table pTab is not a virtual table.
*/
int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
sqlite3 *db = pParse->db;
const char *zMod;
Module *pMod;
int rc = SQLITE_OK;
int rc;
if( !pTab || (pTab->tabFlags & TF_Virtual)==0 || pTab->pVtab ){
assert( pTab );
if( (pTab->tabFlags & TF_Virtual)==0 || sqlite3GetVTable(db, pTab) ){
return SQLITE_OK;
}
pMod = pTab->pMod;
/* Locate the required virtual table module */
zMod = pTab->azModuleArg[0];
pMod = (Module*)sqlite3HashFind(&db->aModule, zMod, sqlite3Strlen30(zMod));
if( !pMod ){
const char *zModule = pTab->azModuleArg[0];
sqlite3ErrorMsg(pParse, "no such module: %s", zModule);
rc = SQLITE_ERROR;
} else {
}else{
char *zErr = 0;
sqlite3 *db = pParse->db;
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr);
if( rc!=SQLITE_OK ){
sqlite3ErrorMsg(pParse, "%s", zErr);
@@ -475,14 +579,14 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
}
/*
** Add the virtual table pVtab to the array sqlite3.aVTrans[].
** Add the virtual table pVTab to the array sqlite3.aVTrans[].
*/
static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
static int addToVTrans(sqlite3 *db, VTable *pVTab){
const int ARRAY_INCR = 5;
/* Grow the sqlite3.aVTrans array if required */
if( (db->nVTrans%ARRAY_INCR)==0 ){
sqlite3_vtab **aVTrans;
VTable **aVTrans;
int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR);
aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes);
if( !aVTrans ){
@@ -493,8 +597,8 @@ static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
}
/* Add pVtab to the end of sqlite3.aVTrans */
db->aVTrans[db->nVTrans++] = pVtab;
sqlite3VtabLock(pVtab);
db->aVTrans[db->nVTrans++] = pVTab;
sqlite3VtabLock(pVTab);
return SQLITE_OK;
}
@@ -510,26 +614,30 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
int rc = SQLITE_OK;
Table *pTab;
Module *pMod;
const char *zModule;
const char *zMod;
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
assert(pTab && (pTab->tabFlags & TF_Virtual)!=0 && !pTab->pVtab);
pMod = pTab->pMod;
zModule = pTab->azModuleArg[0];
assert( pTab && (pTab->tabFlags & TF_Virtual)!=0 && !pTab->pVTable );
/* Locate the required virtual table module */
zMod = pTab->azModuleArg[0];
pMod = (Module*)sqlite3HashFind(&db->aModule, zMod, sqlite3Strlen30(zMod));
/* If the module has been registered and includes a Create method,
** invoke it now. If the module has not been registered, return an
** error. Otherwise, do nothing.
*/
if( !pMod ){
*pzErr = sqlite3MPrintf(db, "no such module: %s", zModule);
*pzErr = sqlite3MPrintf(db, "no such module: %s", zMod);
rc = SQLITE_ERROR;
}else{
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr);
}
if( rc==SQLITE_OK && pTab->pVtab ){
rc = addToVTrans(db, pTab->pVtab);
/* Justification of ALWAYS(): The xConstructor method is required to
** create a valid sqlite3_vtab if it returns SQLITE_OK. */
if( rc==SQLITE_OK && ALWAYS(sqlite3GetVTable(db, pTab)) ){
rc = addToVTrans(db, sqlite3GetVTable(db, pTab));
}
return rc;
@@ -541,7 +649,7 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
** virtual table module.
*/
int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
Parse sParse;
Parse *pParse;
int rc = SQLITE_OK;
Table *pTab;
@@ -554,35 +662,41 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
sqlite3_mutex_leave(db->mutex);
return SQLITE_MISUSE;
}
assert((pTab->tabFlags & TF_Virtual)!=0 && pTab->nCol==0 && pTab->aCol==0);
assert( (pTab->tabFlags & TF_Virtual)!=0 );
memset(&sParse, 0, sizeof(Parse));
sParse.declareVtab = 1;
sParse.db = db;
if(
SQLITE_OK == sqlite3RunParser(&sParse, zCreateTable, &zErr) &&
sParse.pNewTable &&
!sParse.pNewTable->pSelect &&
(sParse.pNewTable->tabFlags & TF_Virtual)==0
){
pTab->aCol = sParse.pNewTable->aCol;
pTab->nCol = sParse.pNewTable->nCol;
sParse.pNewTable->nCol = 0;
sParse.pNewTable->aCol = 0;
db->pVTab = 0;
} else {
sqlite3Error(db, SQLITE_ERROR, zErr);
sqlite3DbFree(db, zErr);
rc = SQLITE_ERROR;
pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
if( pParse==0 ){
rc = SQLITE_NOMEM;
}else{
pParse->declareVtab = 1;
pParse->db = db;
if(
SQLITE_OK == sqlite3RunParser(pParse, zCreateTable, &zErr) &&
pParse->pNewTable &&
!pParse->pNewTable->pSelect &&
(pParse->pNewTable->tabFlags & TF_Virtual)==0
){
if( !pTab->aCol ){
pTab->aCol = pParse->pNewTable->aCol;
pTab->nCol = pParse->pNewTable->nCol;
pParse->pNewTable->nCol = 0;
pParse->pNewTable->aCol = 0;
}
db->pVTab = 0;
} else {
sqlite3Error(db, SQLITE_ERROR, zErr);
sqlite3DbFree(db, zErr);
rc = SQLITE_ERROR;
}
pParse->declareVtab = 0;
if( pParse->pVdbe ){
sqlite3VdbeFinalize(pParse->pVdbe);
}
sqlite3DeleteTable(pParse->pNewTable);
sqlite3StackFree(db, pParse);
}
sParse.declareVtab = 0;
if( sParse.pVdbe ){
sqlite3VdbeFinalize(sParse.pVdbe);
}
sqlite3DeleteTable(sParse.pNewTable);
sParse.pNewTable = 0;
assert( (rc&0xff)==rc );
rc = sqlite3ApiExit(db, rc);
@@ -597,30 +711,25 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
**
** This call is a no-op if zTab is not a virtual table.
*/
int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab)
{
int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){
int rc = SQLITE_OK;
Table *pTab;
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
assert(pTab);
if( pTab->pVtab ){
int (*xDestroy)(sqlite3_vtab *pVTab) = pTab->pMod->pModule->xDestroy;
if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){
VTable *p = vtabDisconnectAll(db, pTab);
rc = sqlite3SafetyOff(db);
assert( rc==SQLITE_OK );
if( xDestroy ){
rc = xDestroy(pTab->pVtab);
}
rc = p->pMod->pModule->xDestroy(p->pVtab);
(void)sqlite3SafetyOn(db);
/* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
if( rc==SQLITE_OK ){
int i;
for(i=0; i<db->nVTrans; i++){
if( db->aVTrans[i]==pTab->pVtab ){
db->aVTrans[i] = db->aVTrans[--db->nVTrans];
break;
}
}
pTab->pVtab = 0;
assert( pTab->pVTable==p && p->pNext==0 );
p->pVtab = 0;
pTab->pVTable = 0;
sqlite3VtabUnlock(p);
}
}
@@ -638,12 +747,15 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab)
static void callFinaliser(sqlite3 *db, int offset){
int i;
if( db->aVTrans ){
for(i=0; i<db->nVTrans && db->aVTrans[i]; i++){
sqlite3_vtab *pVtab = db->aVTrans[i];
int (*x)(sqlite3_vtab *);
x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset);
if( x ) x(pVtab);
sqlite3VtabUnlock(db, pVtab);
for(i=0; i<db->nVTrans; i++){
VTable *pVTab = db->aVTrans[i];
sqlite3_vtab *p = pVTab->pVtab;
if( p ){
int (*x)(sqlite3_vtab *);
x = *(int (**)(sqlite3_vtab *))((char *)p->pModule + offset);
if( x ) x(p);
}
sqlite3VtabUnlock(pVTab);
}
sqlite3DbFree(db, db->aVTrans);
db->nVTrans = 0;
@@ -663,15 +775,14 @@ int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){
int i;
int rc = SQLITE_OK;
int rcsafety;
sqlite3_vtab **aVTrans = db->aVTrans;
VTable **aVTrans = db->aVTrans;
rc = sqlite3SafetyOff(db);
db->aVTrans = 0;
for(i=0; rc==SQLITE_OK && i<db->nVTrans && aVTrans[i]; i++){
sqlite3_vtab *pVtab = aVTrans[i];
for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){
int (*x)(sqlite3_vtab *);
x = pVtab->pModule->xSync;
if( x ){
sqlite3_vtab *pVtab = aVTrans[i]->pVtab;
if( pVtab && (x = pVtab->pModule->xSync)!=0 ){
rc = x(pVtab);
sqlite3DbFree(db, *pzErrmsg);
*pzErrmsg = pVtab->zErrMsg;
@@ -713,38 +824,38 @@ int sqlite3VtabCommit(sqlite3 *db){
** If the xBegin call is successful, place the sqlite3_vtab pointer
** in the sqlite3.aVTrans array.
*/
int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
int rc = SQLITE_OK;
const sqlite3_module *pModule;
/* Special case: If db->aVTrans is NULL and db->nVTrans is greater
** than zero, then this function is being called from within a
** virtual module xSync() callback. It is illegal to write to
** virtual module tables in this case, so return SQLITE_MISUSE.
** virtual module tables in this case, so return SQLITE_LOCKED.
*/
if( sqlite3VtabInSync(db) ){
return SQLITE_LOCKED;
}
if( !pVtab ){
if( !pVTab ){
return SQLITE_OK;
}
pModule = pVtab->pModule;
pModule = pVTab->pVtab->pModule;
if( pModule->xBegin ){
int i;
/* If pVtab is already in the aVTrans array, return early */
for(i=0; (i<db->nVTrans) && 0!=db->aVTrans[i]; i++){
if( db->aVTrans[i]==pVtab ){
for(i=0; i<db->nVTrans; i++){
if( db->aVTrans[i]==pVTab ){
return SQLITE_OK;
}
}
/* Invoke the xBegin method */
rc = pModule->xBegin(pVtab);
rc = pModule->xBegin(pVTab->pVtab);
if( rc==SQLITE_OK ){
rc = addToVTrans(db, pVtab);
rc = addToVTrans(db, pVTab);
}
}
return rc;
@@ -781,12 +892,12 @@ FuncDef *sqlite3VtabOverloadFunction(
/* Check to see the left operand is a column in a virtual table */
if( pExpr==0 ) return pDef;
if( NEVER(pExpr==0) ) return pDef;
if( pExpr->op!=TK_COLUMN ) return pDef;
pTab = pExpr->pTab;
if( pTab==0 ) return pDef;
if( NEVER(pTab==0) ) return pDef;
if( (pTab->tabFlags & TF_Virtual)==0 ) return pDef;
pVtab = pTab->pVtab;
pVtab = sqlite3GetVTable(db, pTab)->pVtab;
assert( pVtab!=0 );
assert( pVtab->pModule!=0 );
pMod = (sqlite3_module *)pVtab->pModule;
@@ -802,11 +913,6 @@ FuncDef *sqlite3VtabOverloadFunction(
}
rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg);
sqlite3DbFree(db, zLowerName);
if( pVtab->zErrMsg ){
sqlite3Error(db, rc, "%s", pVtab->zErrMsg);
sqlite3DbFree(db, pVtab->zErrMsg);
pVtab->zErrMsg = 0;
}
}
if( rc==0 ){
return pDef;
@@ -815,7 +921,7 @@ FuncDef *sqlite3VtabOverloadFunction(
/* Create a new ephemeral function definition for the overloaded
** function */
pNew = sqlite3DbMallocZero(db, sizeof(*pNew)
+ sqlite3Strlen30(pDef->zName) );
+ sqlite3Strlen30(pDef->zName) + 1);
if( pNew==0 ){
return pDef;
}
@@ -836,13 +942,16 @@ FuncDef *sqlite3VtabOverloadFunction(
*/
void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
int i, n;
Table **apVtabLock;
assert( IsVirtual(pTab) );
for(i=0; i<pParse->nVtabLock; i++){
if( pTab==pParse->apVtabLock[i] ) return;
}
n = (pParse->nVtabLock+1)*sizeof(pParse->apVtabLock[0]);
pParse->apVtabLock = sqlite3_realloc(pParse->apVtabLock, n);
if( pParse->apVtabLock ){
apVtabLock = sqlite3_realloc(pParse->apVtabLock, n);
if( apVtabLock ){
pParse->apVtabLock = apVtabLock;
pParse->apVtabLock[pParse->nVtabLock++] = pTab;
}else{
pParse->db->mallocFailed = 1;
+5 -6
View File
@@ -12,7 +12,7 @@
** This file contains routines used for walking the parser tree for
** an SQL statement.
**
** $Id: walker.c,v 1.4 2009/04/08 13:51:52 drh Exp $
** $Id: walker.c,v 1.7 2009/06/15 23:15:59 drh Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@@ -42,11 +42,10 @@ int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
int rc;
if( pExpr==0 ) return WRC_Continue;
testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
testcase( ExprHasProperty(pExpr, EP_SpanToken) );
testcase( ExprHasProperty(pExpr, EP_Reduced) );
rc = pWalker->xExprCallback(pWalker, pExpr);
if( rc==WRC_Continue
&& !ExprHasAnyProperty(pExpr,EP_TokenOnly|EP_SpanToken) ){
&& !ExprHasAnyProperty(pExpr,EP_TokenOnly) ){
if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
@@ -63,14 +62,14 @@ int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
** an abort request is seen.
*/
int sqlite3WalkExprList(Walker *pWalker, ExprList *p){
int i, rc = WRC_Continue;
int i;
struct ExprList_item *pItem;
if( p ){
for(i=p->nExpr, pItem=p->a; i>0; i--, pItem++){
if( sqlite3WalkExpr(pWalker, pItem->pExpr) ) return WRC_Abort;
}
}
return rc & WRC_Continue;
return WRC_Continue;
}
/*
@@ -103,7 +102,7 @@ int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
struct SrcList_item *pItem;
pSrc = p->pSrc;
if( pSrc ){
if( ALWAYS(pSrc) ){
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
if( sqlite3WalkSelect(pWalker, pItem->pSelect) ){
return WRC_Abort;
+108 -52
View File
@@ -16,7 +16,7 @@
** so is applicable. Because this module is responsible for selecting
** indices, you might also think of this module as the "query optimizer".
**
** $Id: where.c,v 1.396 2009/05/06 19:03:14 drh Exp $
** $Id: where.c,v 1.411 2009/07/31 06:14:52 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -127,11 +127,16 @@ struct WhereTerm {
struct WhereClause {
Parse *pParse; /* The parser context */
WhereMaskSet *pMaskSet; /* Mapping of table cursor numbers to bitmasks */
Bitmask vmask; /* Bitmask identifying virtual table cursors */
u8 op; /* Split operator. TK_AND or TK_OR */
int nTerm; /* Number of terms */
int nSlot; /* Number of entries in a[] */
WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */
WhereTerm aStatic[4]; /* Initial static space for a[] */
#if defined(SQLITE_SMALL_STACK)
WhereTerm aStatic[1]; /* Initial static space for a[] */
#else
WhereTerm aStatic[8]; /* Initial static space for a[] */
#endif
};
/*
@@ -254,6 +259,7 @@ static void whereClauseInit(
pWC->nTerm = 0;
pWC->nSlot = ArraySize(pWC->aStatic);
pWC->a = pWC->aStatic;
pWC->vmask = 0;
}
/* Forward reference */
@@ -626,7 +632,6 @@ static int isLikeOrGlob(
Expr *pRight, *pLeft; /* Right and left size of LIKE operator */
ExprList *pList; /* List of operands to the LIKE operator */
int c; /* One character in z[] */
int n; /* Length of string z[] */
int cnt; /* Number of non-wildcard prefix characters */
char wc[3]; /* Wildcard characters */
CollSeq *pColl; /* Collating sequence for LHS */
@@ -649,28 +654,25 @@ static int isLikeOrGlob(
}
pColl = sqlite3ExprCollSeq(pParse, pLeft);
assert( pColl!=0 || pLeft->iColumn==-1 );
if( pColl==0 ){
/* No collation is defined for the ROWID. Use the default. */
pColl = db->pDfltColl;
}
if( pColl==0 ) return 0;
if( (pColl->type!=SQLITE_COLL_BINARY || *pnoCase) &&
(pColl->type!=SQLITE_COLL_NOCASE || !*pnoCase) ){
return 0;
}
z = (const char*)pRight->token.z;
cnt = 0;
if( z ){
n = pRight->token.n;
while( cnt<n && (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
if( sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT ) return 0;
z = pRight->u.zToken;
if( ALWAYS(z) ){
cnt = 0;
while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
cnt++;
}
if( cnt!=0 && c!=0 && 255!=(u8)z[cnt-1] ){
*pisComplete = z[cnt]==wc[0] && z[cnt+1]==0;
*pnPattern = cnt;
return 1;
}
}
if( cnt==0 || 255==(u8)z[cnt-1] ){
return 0;
}
*pisComplete = z[cnt]==wc[0] && z[cnt+1]==0;
*pnPattern = cnt;
return 1;
return 0;
}
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
@@ -691,8 +693,7 @@ static int isMatchOfColumn(
if( pExpr->op!=TK_FUNCTION ){
return 0;
}
if( pExpr->token.n!=5 ||
sqlite3StrNICmp((const char*)pExpr->token.z,"match",5)!=0 ){
if( sqlite3StrICmp(pExpr->u.zToken,"match")!=0 ){
return 0;
}
pList = pExpr->x.pList;
@@ -829,7 +830,8 @@ static void exprAnalyzeOrTerm(
/*
** Compute the set of tables that might satisfy cases 1 or 2.
*/
indexable = chngToIN = ~(Bitmask)0;
indexable = ~(Bitmask)0;
chngToIN = ~(pWC->vmask);
for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){
if( (pOrTerm->eOperator & WO_SINGLE)==0 ){
WhereAndInfo *pAndInfo;
@@ -890,6 +892,22 @@ static void exprAnalyzeOrTerm(
** chngToIN holds a set of tables that *might* satisfy case 1. But
** we have to do some additional checking to see if case 1 really
** is satisfied.
**
** chngToIN will hold either 0, 1, or 2 bits. The 0-bit case means
** that there is no possibility of transforming the OR clause into an
** IN operator because one or more terms in the OR clause contain
** something other than == on a column in the single table. The 1-bit
** case means that every term of the OR clause is of the form
** "table.column=expr" for some single table. The one bit that is set
** will correspond to the common table. We still need to check to make
** sure the same column is used on all terms. The 2-bit case is when
** the all terms are of the form "table1.column=table2.column". It
** might be possible to form an IN operator with either table1.column
** or table2.column as the LHS if either is common to every term of
** the OR clause.
**
** Note that terms of the form "table.column1=table.column2" (the
** same table on both sizes of the ==) cannot be optimized.
*/
if( chngToIN ){
int okToChngToIN = 0; /* True if the conversion to IN is valid */
@@ -908,18 +926,38 @@ static void exprAnalyzeOrTerm(
for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){
assert( pOrTerm->eOperator==WO_EQ );
pOrTerm->wtFlags &= ~TERM_OR_OK;
if( pOrTerm->leftCursor==iColumn ) continue;
if( (chngToIN & getMask(pMaskSet, pOrTerm->leftCursor))==0 ) continue;
if( pOrTerm->leftCursor==iCursor ){
/* This is the 2-bit case and we are on the second iteration and
** current term is from the first iteration. So skip this term. */
assert( j==1 );
continue;
}
if( (chngToIN & getMask(pMaskSet, pOrTerm->leftCursor))==0 ){
/* This term must be of the form t1.a==t2.b where t2 is in the
** chngToIN set but t1 is not. This term will be either preceeded
** or follwed by an inverted copy (t2.b==t1.a). Skip this term
** and use its inversion. */
testcase( pOrTerm->wtFlags & TERM_COPIED );
testcase( pOrTerm->wtFlags & TERM_VIRTUAL );
assert( pOrTerm->wtFlags & (TERM_COPIED|TERM_VIRTUAL) );
continue;
}
iColumn = pOrTerm->u.leftColumn;
iCursor = pOrTerm->leftCursor;
break;
}
if( i<0 ){
/* No candidate table+column was found. This can only occur
** on the second iteration */
assert( j==1 );
assert( (chngToIN&(chngToIN-1))==0 );
assert( chngToIN==getMask(pMaskSet, iColumn) );
assert( chngToIN==getMask(pMaskSet, iCursor) );
break;
}
testcase( j==1 );
/* We have found a candidate table and column. Check to see if that
** table and column is common to every term in the OR clause */
okToChngToIN = 1;
for(; i>=0 && okToChngToIN; i--, pOrTerm++){
assert( pOrTerm->eOperator==WO_EQ );
@@ -960,12 +998,12 @@ static void exprAnalyzeOrTerm(
assert( pOrTerm->leftCursor==iCursor );
assert( pOrTerm->u.leftColumn==iColumn );
pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0);
pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup, 0);
pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup);
pLeft = pOrTerm->pExpr->pLeft;
}
assert( pLeft!=0 );
pDup = sqlite3ExprDup(db, pLeft, 0);
pNew = sqlite3Expr(db, TK_IN, pDup, 0, 0);
pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0, 0);
if( pNew ){
int idxNew;
transferJoinMarkings(pNew, pExpr);
@@ -1118,7 +1156,8 @@ static void exprAnalyze(
for(i=0; i<2; i++){
Expr *pNewExpr;
int idxNew;
pNewExpr = sqlite3Expr(db, ops[i], sqlite3ExprDup(db, pExpr->pLeft, 0),
pNewExpr = sqlite3PExpr(pParse, ops[i],
sqlite3ExprDup(db, pExpr->pLeft, 0),
sqlite3ExprDup(db, pList->a[i].pExpr, 0), 0);
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
@@ -1137,6 +1176,7 @@ static void exprAnalyze(
else if( pExpr->op==TK_OR ){
assert( pWC->op==TK_AND );
exprAnalyzeOrTerm(pSrc, pWC, idxTerm);
pTerm = &pWC->a[idxTerm];
}
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
@@ -1160,19 +1200,22 @@ static void exprAnalyze(
pLeft = pExpr->x.pList->a[1].pExpr;
pRight = pExpr->x.pList->a[0].pExpr;
pStr1 = sqlite3PExpr(pParse, TK_STRING, 0, 0, 0);
if( pStr1 ){
sqlite3TokenCopy(db, &pStr1->token, &pRight->token);
pStr1->token.n = nPattern;
}
pStr1 = sqlite3Expr(db, TK_STRING, pRight->u.zToken);
if( pStr1 ) pStr1->u.zToken[nPattern] = 0;
pStr2 = sqlite3ExprDup(db, pStr1, 0);
if( !db->mallocFailed ){
u8 c, *pC;
/* assert( pStr2->token.dyn ); */
pC = (u8*)&pStr2->token.z[nPattern-1];
u8 c, *pC; /* Last character before the first wildcard */
pC = (u8*)&pStr2->u.zToken[nPattern-1];
c = *pC;
if( noCase ){
if( c=='@' ) isComplete = 0;
/* The point is to increment the last character before the first
** wildcard. But if we increment '@', that will push it into the
** alphabetic range where case conversions will mess up the
** inequality. To avoid this, make sure to also run the full
** LIKE on all candidate expressions by clearing the isComplete flag
*/
if( c=='A'-1 ) isComplete = 0;
c = sqlite3UpperToLower[c];
}
*pC = c + 1;
@@ -1213,7 +1256,8 @@ static void exprAnalyze(
prereqColumn = exprTableUsage(pMaskSet, pLeft);
if( (prereqExpr & prereqColumn)==0 ){
Expr *pNewExpr;
pNewExpr = sqlite3Expr(db, TK_MATCH, 0, sqlite3ExprDup(db, pRight, 0), 0);
pNewExpr = sqlite3PExpr(pParse, TK_MATCH,
0, sqlite3ExprDup(db, pRight, 0), 0);
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
pNewTerm = &pWC->a[idxNew];
@@ -1683,7 +1727,7 @@ static sqlite3_index_info *allocateIndexInfo(
** that this is required.
*/
static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
sqlite3_vtab *pVtab = pTab->pVtab;
sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
int i;
int rc;
@@ -1780,7 +1824,7 @@ static void bestVirtualIndex(
** sqlite3ViewGetColumnNames() would have picked up the error.
*/
assert( pTab->azModuleArg && pTab->azModuleArg[0] );
assert( pTab->pVtab );
assert( sqlite3GetVTable(pParse->db, pTab) );
/* Set the aConstraint[].usable fields and initialize all
** output variables to zero.
@@ -1841,7 +1885,7 @@ static void bestVirtualIndex(
pCost->rCost = pIdxInfo->estimatedCost;
}
pCost->plan.u.pVtabIdx = pIdxInfo;
if( pIdxInfo && pIdxInfo->orderByConsumed ){
if( pIdxInfo->orderByConsumed ){
pCost->plan.wsFlags |= WHERE_ORDERBY;
}
pCost->plan.nEq = 0;
@@ -2127,7 +2171,7 @@ static void bestBtreeIndex(
cost += cost*estLog(cost);
WHERETRACE(("...... orderby increases cost to %.9g\n", cost));
}
}else if( pParse->db->flags & SQLITE_ReverseOrder ){
}else if( wsFlags!=0 && (pParse->db->flags & SQLITE_ReverseOrder)!=0 ){
/* For application testing, randomly reverse the output order for
** SELECT statements that omit the ORDER BY clause. This will help
** to find cases where
@@ -2170,7 +2214,7 @@ static void bestBtreeIndex(
/* Report the best result
*/
pCost->plan.wsFlags |= eqTermMask;
WHERETRACE(("best index is %s, cost=%.9g, nrow=%.9g, wsFlags=%x, nEq=%d\n",
WHERETRACE(("best index is %s, nrow=%.9g, cost=%.9g, wsFlags=%x, nEq=%d\n",
(pCost->plan.wsFlags & WHERE_INDEXED)!=0 ?
pCost->plan.u.pIdx->zName : "(none)", pCost->nRow,
pCost->rCost, pCost->plan.wsFlags, pCost->plan.nEq));
@@ -2190,6 +2234,7 @@ static void bestIndex(
ExprList *pOrderBy, /* The ORDER BY clause */
WhereCost *pCost /* Lowest cost query plan */
){
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pSrc->pTab) ){
sqlite3_index_info *p = 0;
bestVirtualIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost, &p);
@@ -2197,7 +2242,9 @@ static void bestIndex(
sqlite3_free(p->idxStr);
}
sqlite3DbFree(pParse->db, p);
}else{
}else
#endif
{
bestBtreeIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
}
}
@@ -2293,7 +2340,6 @@ static int codeEqualityTerm(
eType = sqlite3FindInIndex(pParse, pX, 0);
iTab = pX->iTable;
sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
VdbeComment((v, "%.*s", pX->span.n, pX->span.z));
assert( pLevel->plan.wsFlags & WHERE_IN_ABLE );
if( pLevel->u.in.nIn==0 ){
pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
@@ -2834,8 +2880,8 @@ static Bitmask codeOneLoopStart(
SrcList oneTab; /* Shortened table list */
int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */
int regRowset; /* Register for RowSet object */
int regRowid; /* Register holding rowid */
int regRowset = 0; /* Register for RowSet object */
int regRowid = 0; /* Register holding rowid */
int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */
int iRetInit; /* Address of regReturn init */
int ii;
@@ -2874,7 +2920,6 @@ static Bitmask codeOneLoopStart(
WhereTerm *pOrTerm = &pOrWc->a[ii];
if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){
WhereInfo *pSubWInfo; /* Info for single OR-term scan */
/* Loop through table entries that match term pOrTerm. */
pSubWInfo = sqlite3WhereBegin(pParse, &oneTab, pOrTerm->pExpr, 0,
WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE | WHERE_FORCE_TABLE);
@@ -2884,7 +2929,7 @@ static Bitmask codeOneLoopStart(
int r;
r = sqlite3ExprCodeGetColumn(pParse, pTabItem->pTab, -1, iCur,
regRowid, 0);
sqlite3VdbeAddOp4(v, OP_RowSetTest, regRowset,
sqlite3VdbeAddOp4(v, OP_RowSetTest, regRowset,
sqlite3VdbeCurrentAddr(v)+2,
r, SQLITE_INT_TO_PTR(iSet), P4_INT32);
}
@@ -3166,9 +3211,20 @@ WhereInfo *sqlite3WhereBegin(
** of the join. Subtracting one from the right table bitmask gives a
** bitmask for all tables to the left of the join. Knowing the bitmask
** for all tables to the left of a left join is important. Ticket #3015.
**
** Configure the WhereClause.vmask variable so that bits that correspond
** to virtual table cursors are set. This is used to selectively disable
** the OR-to-IN transformation in exprAnalyzeOrTerm(). It is not helpful
** with virtual tables.
*/
assert( pWC->vmask==0 && pMaskSet->n==0 );
for(i=0; i<pTabList->nSrc; i++){
createMask(pMaskSet, pTabList->a[i].iCursor);
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( ALWAYS(pTabList->a[i].pTab) && IsVirtual(pTabList->a[i].pTab) ){
pWC->vmask |= ((Bitmask)1 << i);
}
#endif
}
#ifndef NDEBUG
{
@@ -3349,13 +3405,13 @@ WhereInfo *sqlite3WhereBegin(
#endif /* SQLITE_OMIT_EXPLAIN */
pTabItem = &pTabList->a[pLevel->iFrom];
pTab = pTabItem->pTab;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue;
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
int iCur = pTabItem->iCursor;
sqlite3VdbeAddOp4(v, OP_VOpen, iCur, 0, 0,
(const char*)pTab->pVtab, P4_VTAB);
sqlite3VdbeAddOp4(v, OP_VOpen, iCur, 0, 0, pVTab, P4_VTAB);
}else
#endif
if( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0
@@ -3541,7 +3597,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
** that reference the table and converts them into opcodes that
** reference the index.
*/
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 && !db->mallocFailed){
int k, j, last;
VdbeOp *pOp;
Index *pIdx = pLevel->plan.u.pIdx;
+1 -2
View File
@@ -6,7 +6,7 @@
#***********************************************************************
# This file runs all tests.
#
# $Id: async.test,v 1.20 2009/04/25 08:39:15 danielk1977 Exp $
# $Id: async.test,v 1.21 2009/06/05 17:09:12 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -85,4 +85,3 @@ rename async_really_finish_test finish_test
if {[info exists ASYNC_SAVE_ISQUICK]} { set ISQUICK $ASYNC_SAVE_ISQUICK }
finish_test
+15 -2
View File
@@ -9,10 +9,21 @@
#
#***********************************************************************
#
# $Id: async4.test,v 1.1 2009/04/25 08:39:15 danielk1977 Exp $
# $Id: async4.test,v 1.4 2009/06/05 17:09:12 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# These tests only work for Tcl version 8.5 and later on Windows (for now)
#
if {$tcl_platform(platform)=="windows"} {
scan $::tcl_version %f vx
if {$vx<8.5} {
finish_test
return
}
}
if {[info commands sqlite3async_initialize] eq ""} {
# The async logic is not built into this system
finish_test
@@ -92,6 +103,9 @@ do_test async4.1.16 {
sqlite3async_start
sqlite3async_wait
} {}
do_test async4.1.17 {
sqlite3async_control lockfiles true
} {1}
do_test async4.2.1 {
sqlite3async_control delay
@@ -146,4 +160,3 @@ do_test async4.2.8 {
} {}
finish_test
+69
View File
@@ -0,0 +1,69 @@
# 2009 July 19
#
# 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 tests that asynchronous IO is compatible with multi-file
# transactions.
#
# $Id: async5.test,v 1.1 2009/07/18 11:52:04 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
if {[info commands sqlite3async_initialize] eq ""} {
# The async logic is not built into this system
finish_test
return
}
db close
file delete -force test2.db
sqlite3async_initialize "" 1
sqlite3async_control halt never
sqlite3 db test.db
do_test async5-1.1 {
execsql {
ATTACH 'test2.db' AS next;
CREATE TABLE main.t1(a, b);
CREATE TABLE next.t2(a, b);
BEGIN;
INSERT INTO t1 VALUES(1, 2);
INSERT INTO t2 VALUES(3, 4);
COMMIT;
}
} {}
do_test async5-1.2 {
execsql { SELECT * FROM t1 }
} {1 2}
do_test async5-1.3 {
execsql { SELECT * FROM t2 }
} {3 4}
do_test async5-1.4 {
execsql {
BEGIN;
INSERT INTO t1 VALUES('a', 'b');
INSERT INTO t2 VALUES('c', 'd');
COMMIT;
}
} {}
do_test async5-1.5 {
execsql { SELECT * FROM t1 }
} {1 2 a b}
do_test async5-1.6 {
execsql { SELECT * FROM t2 }
} {3 4 c d}
db close
sqlite3async_control halt idle
sqlite3async_start
sqlite3async_wait
sqlite3async_control halt never
sqlite3async_shutdown
set sqlite3async_trace 0
finish_test
+2 -3
View File
@@ -12,7 +12,7 @@
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: attach.test,v 1.49 2008/07/12 14:52:20 drh Exp $
# $Id: attach.test,v 1.52 2009/05/29 14:39:08 drh Exp $
#
set testdir [file dirname $argv0]
@@ -756,8 +756,7 @@ ifcapable subquery {
DETACH RAISE ( IGNORE ) IN ( SELECT "AAAAAA" . * ORDER BY
REGISTER LIMIT "AAAAAA" . "AAAAAA" OFFSET RAISE ( IGNORE ) NOT NULL )
}
} {1 {invalid name: "RAISE ( IGNORE ) IN ( SELECT "AAAAAA" . * ORDER BY
REGISTER LIMIT "AAAAAA" . "AAAAAA" OFFSET RAISE ( IGNORE ) NOT NULL )"}}
} {1 {no such table: AAAAAA}}
}
# Create a malformed file (a file that is not a valid database)
+29 -1
View File
@@ -12,7 +12,7 @@
# focus of this script is testing the sqlite3_set_authorizer() API
# and related functionality.
#
# $Id: auth.test,v 1.45 2009/05/04 01:58:31 drh Exp $
# $Id: auth.test,v 1.46 2009/07/02 18:40:35 danielk1977 Exp $
#
set testdir [file dirname $argv0]
@@ -2319,6 +2319,34 @@ ifcapable compound&&subquery {
} {sqlite_stat1 t1 t2 t3 t4}
}
# Ticket #3944
#
ifcapable trigger {
do_test auth-5.3.1 {
execsql {
CREATE TABLE t5 ( x );
CREATE TRIGGER t5_tr1 AFTER INSERT ON t5 BEGIN
UPDATE t5 SET x = 1 WHERE NEW.x = 0;
END;
}
} {}
set ::authargs [list]
proc auth {args} {
eval lappend ::authargs $args
return SQLITE_OK
}
do_test auth-5.3.2 {
execsql { INSERT INTO t5 (x) values(0) }
set ::authargs
} [list SQLITE_INSERT t5 {} main {} \
SQLITE_UPDATE t5 x main t5_tr1 \
SQLITE_READ t5 x main t5_tr1 \
]
do_test auth-5.3.2 {
execsql { SELECT * FROM t5 }
} {1}
}
rename proc {}
rename proc_real proc
+78 -1
View File
@@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this script is testing the AUTOINCREMENT features.
#
# $Id: autoinc.test,v 1.13 2008/08/11 18:44:58 drh Exp $
# $Id: autoinc.test,v 1.14 2009/06/23 20:28:54 drh Exp $
#
set testdir [file dirname $argv0]
@@ -556,5 +556,82 @@ do_test autoinc-9.1 {
}
} {t3 0}
# Ticket #3928. Make sure that triggers to not make extra slots in
# the SQLITE_SEQUENCE table.
#
do_test autoinc-3928.1 {
db eval {
CREATE TABLE t3928(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
CREATE TRIGGER t3928r1 BEFORE INSERT ON t3928 BEGIN
INSERT INTO t3928(b) VALUES('before1');
INSERT INTO t3928(b) VALUES('before2');
END;
CREATE TRIGGER t3928r2 AFTER INSERT ON t3928 BEGIN
INSERT INTO t3928(b) VALUES('after1');
INSERT INTO t3928(b) VALUES('after2');
END;
INSERT INTO t3928(b) VALUES('test');
SELECT * FROM t3928 ORDER BY a;
}
} {1 before1 2 after1 3 after2 4 before2 5 after1 6 after2 7 test 8 before1 9 before2 10 after1 11 before1 12 before2 13 after2}
do_test autoinc-3928.2 {
db eval {
SELECT * FROM sqlite_sequence WHERE name='t3928'
}
} {t3928 13}
do_test autoinc-3928.3 {
db eval {
DROP TRIGGER t3928r1;
DROP TRIGGER t3928r2;
CREATE TRIGGER t3928r3 BEFORE UPDATE ON t3928
WHEN typeof(new.b)=='integer' BEGIN
INSERT INTO t3928(b) VALUES('before-int-' || new.b);
END;
CREATE TRIGGER t3928r4 AFTER UPDATE ON t3928
WHEN typeof(new.b)=='integer' BEGIN
INSERT INTO t3928(b) VALUES('after-int-' || new.b);
END;
DELETE FROM t3928 WHERE a!=1;
UPDATE t3928 SET b=456 WHERE a=1;
SELECT * FROM t3928 ORDER BY a;
}
} {1 456 14 before-int-456 15 after-int-456}
do_test autoinc-3928.4 {
db eval {
SELECT * FROM sqlite_sequence WHERE name='t3928'
}
} {t3928 15}
do_test autoinc-3928.5 {
db eval {
CREATE TABLE t3928b(x);
INSERT INTO t3928b VALUES(100);
INSERT INTO t3928b VALUES(200);
INSERT INTO t3928b VALUES(300);
DELETE FROM t3928;
CREATE TABLE t3928c(y INTEGER PRIMARY KEY AUTOINCREMENT, z);
CREATE TRIGGER t3928br1 BEFORE DELETE ON t3928b BEGIN
INSERT INTO t3928(b) VALUES('before-del-'||old.x);
INSERT INTO t3928c(z) VALUES('before-del-'||old.x);
END;
CREATE TRIGGER t3928br2 AFTER DELETE ON t3928b BEGIN
INSERT INTO t3928(b) VALUES('after-del-'||old.x);
INSERT INTO t3928c(z) VALUES('after-del-'||old.x);
END;
DELETE FROM t3928b;
SELECT * FROM t3928 ORDER BY a;
}
} {16 before-del-100 17 after-del-100 18 before-del-200 19 after-del-200 20 before-del-300 21 after-del-300}
do_test autoinc-3928.6 {
db eval {
SELECT * FROM t3928c ORDER BY y;
}
} {1 before-del-100 2 after-del-100 3 before-del-200 4 after-del-200 5 before-del-300 6 after-del-300}
do_test autoinc-3928.7 {
db eval {
SELECT * FROM sqlite_sequence WHERE name LIKE 't3928%' ORDER BY name;
}
} {t3928 21 t3928c 6}
finish_test
+47 -3
View File
@@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this file is testing the sqlite3_backup_XXX API.
#
# $Id: backup.test,v 1.9 2009/03/16 13:19:36 danielk1977 Exp $
# $Id: backup.test,v 1.11 2009/06/05 17:09:12 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -404,7 +404,6 @@ do_test backup-4.2.2 {
catchsql { DETACH aux2 } db2
} {1 {database aux2 is locked}}
do_test backup-4.2.3 {
breakpoint
B step 50
} {SQLITE_DONE}
do_test backup-4.2.4 {
@@ -859,5 +858,50 @@ do_test backup-9.2.3 {
} {SQLITE_OK}
catch {db2 close}
finish_test
ifcapable memorymanage {
db close
file delete -force test.db
file delete -force bak.db
sqlite3 db test.db
sqlite3 db2 test.db
sqlite3 db3 bak.db
do_test backup-10.1.1 {
execsql {
BEGIN;
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, randstr(1000,1000));
INSERT INTO t1 VALUES(2, randstr(1000,1000));
INSERT INTO t1 VALUES(3, randstr(1000,1000));
INSERT INTO t1 VALUES(4, randstr(1000,1000));
INSERT INTO t1 VALUES(5, randstr(1000,1000));
CREATE INDEX i1 ON t1(a, b);
COMMIT;
}
} {}
do_test backup-10.1.2 {
sqlite3_backup B db3 main db2 main
B step 5
} {SQLITE_OK}
do_test backup-10.1.3 {
execsql {
UPDATE t1 SET b = randstr(500,500);
}
} {}
sqlite3_release_memory [expr 1024*1024]
do_test backup-10.1.3 {
B step 50
} {SQLITE_DONE}
do_test backup-10.1.4 {
B finish
} {SQLITE_OK}
do_test backup-10.1.5 {
execsql { PRAGMA integrity_check } db3
} {ok}
db2 close
db3 close
}
finish_test
+2 -2
View File
@@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this script testing the sqlite_bind API.
#
# $Id: bind.test,v 1.47 2009/02/20 03:55:05 drh Exp $
# $Id: bind.test,v 1.48 2009/07/22 07:27:57 danielk1977 Exp $
#
set testdir [file dirname $argv0]
@@ -291,7 +291,7 @@ do_test bind-6.4 {
execsql {SELECT * FROM t1}
} {hello hello hello}
set enc [db eval {PRAGMA encoding}]
if {$enc=="UTF-8"} {
if {$enc=="UTF-8" || $enc==""} {
do_test bind-6.5 {
execsql {SELECT hex(a), hex(b), hex(c) FROM t1}
} {68656C6C6F00746865726500 68656C6C6F007468657265 68656C6C6F}
+29 -27
View File
@@ -13,7 +13,7 @@
# This is a copy of the capi3.test file that has been adapted to
# test the new sqlite3_prepare_v2 interface.
#
# $Id: capi3c.test,v 1.22 2008/11/05 16:37:35 drh Exp $
# $Id: capi3c.test,v 1.23 2009/07/22 07:27:57 danielk1977 Exp $
#
set testdir [file dirname $argv0]
@@ -1292,31 +1292,33 @@ sqlite3_finalize $STMT
# conversion (or vice versa) on one column does not change the value of
# the second.
#
do_test capi3c-23.1 {
set STMT [sqlite3_prepare_v2 db {SELECT b,b,b,b FROM t1} -1 TAIL]
sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3c-23.2 {
sqlite3_column_text16 $STMT 0
sqlite3_column_text $STMT 1
} {one}
do_test capi3c-23.3 {
sqlite3_column_text16 $STMT 2
sqlite3_column_text $STMT 3
} {one}
sqlite3_finalize $STMT
do_test capi3c-23.4 {
set STMT [sqlite3_prepare_v2 db {SELECT b||'x',b,b,b FROM t1} -1 TAIL]
sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3c-23.5 {
sqlite3_column_text16 $STMT 0
sqlite3_column_text $STMT 1
} {one}
do_test capi3c-23.6 {
sqlite3_column_text16 $STMT 2
sqlite3_column_text $STMT 3
} {one}
sqlite3_finalize $STMT
ifcapable utf16 {
do_test capi3c-23.1 {
set STMT [sqlite3_prepare_v2 db {SELECT b,b,b,b FROM t1} -1 TAIL]
sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3c-23.2 {
sqlite3_column_text16 $STMT 0
sqlite3_column_text $STMT 1
} {one}
do_test capi3c-23.3 {
sqlite3_column_text16 $STMT 2
sqlite3_column_text $STMT 3
} {one}
sqlite3_finalize $STMT
do_test capi3c-23.4 {
set STMT [sqlite3_prepare_v2 db {SELECT b||'x',b,b,b FROM t1} -1 TAIL]
sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3c-23.5 {
sqlite3_column_text16 $STMT 0
sqlite3_column_text $STMT 1
} {one}
do_test capi3c-23.6 {
sqlite3_column_text16 $STMT 2
sqlite3_column_text $STMT 3
} {one}
sqlite3_finalize $STMT
}
finish_test
+1 -2
View File
@@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this file is testing CHECK constraints
#
# $Id: check.test,v 1.12 2009/03/24 15:08:10 drh Exp $
# $Id: check.test,v 1.13 2009/06/05 17:09:12 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -115,7 +115,6 @@ do_test check-1.17 {
} {4 11.0}
do_test check-2.1 {
breakpoint
execsql {
CREATE TABLE t2(
x INTEGER CHECK( typeof(coalesce(x,0))=="integer" ),
+11 -1
View File
@@ -13,7 +13,7 @@
# The focus of this file is testing how SQLite generates the names
# of columns in a result set.
#
# $Id: colname.test,v 1.6 2008/10/09 15:56:46 drh Exp $
# $Id: colname.test,v 1.7 2009/06/02 15:47:38 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -316,4 +316,14 @@ do_test colname-7.1 {
execsql2 {SELECT rowid, * FROM t7}
} {x 1 x 1 y 2}
# Tickets #3893 and #3984. (Same problem; independently reported)
#
do_test colname-8.1 {
db eval {
CREATE TABLE "t3893"("x");
INSERT INTO t3893 VALUES(123);
SELECT "y"."x" FROM (SELECT "x" FROM "t3893") AS "y";
}
} {123}
finish_test
+53 -1
View File
@@ -13,7 +13,7 @@
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file.
#
# $Id: corrupt.test,v 1.10 2008/08/25 12:14:09 drh Exp $
# $Id: corrupt.test,v 1.12 2009/07/13 09:41:45 danielk1977 Exp $
catch {file delete -force test.db test.db-journal test.bu}
@@ -174,4 +174,56 @@ do_test corrupt-3.6 {
}
} {1 {database disk image is malformed}}
do_test corrupt-4.1 {
db close
file delete -force test.db test.db-journal
sqlite3 db test.db
execsql {
PRAGMA page_size = 1024;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);
}
for {set i 0} {$i < 10} {incr i} {
set text [string repeat $i 220]
execsql { INSERT INTO t1 VALUES($i, $text) }
}
execsql { CREATE INDEX i1 ON t1(b) }
} {}
do_test corrupt-4.2 {
set iRoot [db one {SELECT rootpage FROM sqlite_master WHERE name = 'i1'}]
set iOffset [hexio_get_int [hexio_read test.db [expr 12+($iRoot-1)*1024] 2]]
set data [hexio_render_int32 [expr $iRoot - 1]]
hexio_write test.db [expr ($iRoot-1)*1024 + $iOffset] $data
db close
sqlite3 db test.db
# The following DELETE statement attempts to delete a cell stored on the
# root page of index i1. After this cell is deleted it must be replaced
# by a cell retrieved from the child page (a leaf) of the deleted cell.
# This will fail, as the block modified the database image so that the
# child page of the deleted cell is from a table (intkey) b-tree, not an
# index b-tree as expected. At one point this was causing an assert()
# to fail.
catchsql { DELETE FROM t1 WHERE rowid = 3 }
} {1 {database disk image is malformed}}
do_test corrupt-5.1 {
db close
file delete -force test.db test.db-journal
sqlite3 db test.db
execsql { PRAGMA page_size = 1024 }
set ct "CREATE TABLE t1(c0 "
set i 0
while {[string length $ct] < 950} { append ct ", c[incr i]" }
append ct ")"
execsql $ct
} {}
do_test corrupt-5.2 {
db close
hexio_write test.db 108 00000000
sqlite3 db test.db
catchsql { SELECT * FROM sqlite_master }
} {1 {database disk image is malformed}}
finish_test
+3 -2
View File
@@ -11,9 +11,10 @@
# This file implements regression tests for SQLite library.
#
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file.
# segfault if it sees a corrupt database file. Checks for
# malformed schema.
#
# $Id: corrupt5.test,v 1.2 2008/03/19 13:03:34 drh Exp $
# $Id: corrupt5.test,v 1.3 2009/06/04 02:47:04 shane Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
+34 -14
View File
@@ -14,7 +14,7 @@
# segfault if it sees a corrupt database file. It specifically focuses
# on corrupt cell offsets in a btree page.
#
# $Id: corrupt7.test,v 1.5 2008/08/13 14:07:41 drh Exp $
# $Id: corrupt7.test,v 1.8 2009/08/10 10:18:08 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -57,21 +57,41 @@ integrity_check corrupt7-1.4
# Deliberately corrupt some of the cell offsets in the btree page
# on page 2 of the database.
#
do_test corrupt7-2.1 {
db close
hexio_write test.db 1062 FF
sqlite3 db test.db
db eval {PRAGMA integrity_check(1)}
} {{*** in database main ***
# The error message is different depending on whether or not the
# SQLITE_ENABLE_OVERSIZE_CELL_CHECK compile-time option is engaged.
#
ifcapable oversize_cell_check {
do_test corrupt7-2.1 {
db close
hexio_write test.db 1062 FF
sqlite3 db test.db
db eval {PRAGMA integrity_check(1)}
} {{*** in database main ***
Page 2: btreeInitPage() returns error code 11}}
do_test corrupt7-2.2 {
db close
hexio_write test.db 1062 04
sqlite3 db test.db
db eval {PRAGMA integrity_check(1)}
} {{*** in database main ***
Page 2: btreeInitPage() returns error code 11}}
} else {
do_test corrupt7-2.1 {
db close
hexio_write test.db 1062 FF
sqlite3 db test.db
db eval {PRAGMA integrity_check(1)}
} {{*** in database main ***
Corruption detected in cell 15 on page 2}}
do_test corrupt7-2.2 {
db close
hexio_write test.db 1062 04
sqlite3 db test.db
db eval {PRAGMA integrity_check(1)}
} {{*** in database main ***
do_test corrupt7-2.2 {
db close
hexio_write test.db 1062 04
sqlite3 db test.db
db eval {PRAGMA integrity_check(1)}
} {{*** in database main ***
Corruption detected in cell 15 on page 2}}
}
# The code path that was causing the buffer overrun that this test
# case was checking for was removed.
#
+2 -2
View File
@@ -12,9 +12,9 @@
#
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file. It specifically focuses
# on corruption in the form of duplicate entries no the freelist.
# on corruption in the form of duplicate entries on the freelist.
#
# $Id: corrupt9.test,v 1.2 2008/07/16 12:25:32 drh Exp $
# $Id: corrupt9.test,v 1.3 2009/06/04 02:47:04 shane Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
+2 -3
View File
@@ -20,7 +20,7 @@
# contains a (corrupt) reference to a page greater than the configured
# maximum page number.
#
# $Id: corruptB.test,v 1.2 2008/09/10 17:53:36 danielk1977 Exp $
# $Id: corruptB.test,v 1.4 2009/07/21 19:25:24 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -154,7 +154,7 @@ do_test corruptB-2.1.1 {
do_test corruptB-2.1.2 {
sqlite3 db test.db
catchsql { SELECT * FROM t1 }
} {1 {database disk image is malformed}}
} {1 {database or disk is full}}
#---------------------------------------------------------------------------
@@ -182,4 +182,3 @@ do_test corruptB-3.1.2 {
} {1 {database disk image is malformed}}
finish_test
+21 -10
View File
@@ -15,7 +15,7 @@
# data base file, then tests that single byte corruptions in
# increasingly larger quantities are handled gracefully.
#
# $Id: corruptC.test,v 1.11 2009/04/11 16:06:15 danielk1977 Exp $
# $Id: corruptC.test,v 1.14 2009/07/11 06:55:34 danielk1977 Exp $
catch {file delete -force test.db test.db-journal test.bu}
@@ -94,8 +94,7 @@ do_test corruptC-2.1 {
sqlite3 db test.db
catchsql {PRAGMA integrity_check}
} {0 {{*** in database main ***
Corruption detected in header on page 3}}}
} {1 {database disk image is malformed}}
# test that a corrupt content offset size is handled (seed 5649)
do_test corruptC-2.2 {
@@ -155,9 +154,12 @@ do_test corruptC-2.5 {
catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;}
catchsql {PRAGMA integrity_check}
} {0 {{*** in database main ***
Corruption detected in cell 710 on page 4
Multiple uses for byte 661 of page 4
Fragmented space is 249 byte reported as 21 on page 4}}}
Page 4: btreeInitPage() returns error code 11}}}
# {0 {{*** in database main ***
# Corruption detected in cell 710 on page 4
# Multiple uses for byte 661 of page 4
# Fragmented space is 249 byte reported as 21 on page 4}}}
# test that a corrupt free cell size is handled (seed 169595)
do_test corruptC-2.6 {
@@ -275,8 +277,10 @@ do_test corruptC-2.14 {
} {1 {database disk image is malformed}}
#
# now test for a series of quasi-random seeds
for {set tn 0} {$tn<1024} {incr tn 1} {
# Now test for a series of quasi-random seeds.
# We loop over the entire file size and touch
# each byte at least once.
for {set tn 0} {$tn<$fsize} {incr tn 1} {
# setup for test
db close
@@ -290,9 +294,16 @@ for {set tn 0} {$tn<1024} {incr tn 1} {
set last 0
for {set i 1} {$i<=512 && !$last} {incr i 1} {
# insert random byte at random location
db close
set roffset [random $fsize]
if {$i==1} {
# on the first corrupt value, use location $tn
# this ensures that we touch each location in the
# file at least once.
set roffset $tn
} else {
# insert random byte at random location
set roffset [random $fsize]
}
set rbyte [format %02x [random 255]]
# You can uncomment the following to have it trace

Some files were not shown because too many files have changed in this diff Show More