upgrade bundled sqlite to sqlite 3.1.3

This commit is contained in:
Wez Furlong 2005-02-27 05:20:19 +00:00
parent 58f61a16ee
commit ae5649598d
62 changed files with 11169 additions and 5661 deletions

View File

@ -72,23 +72,27 @@ if test "$PHP_PDO_SQLITE" != "no"; then
sqlite/src/table.c sqlite/src/tokenize.c \
sqlite/src/trigger.c sqlite/src/update.c sqlite/src/utf.c sqlite/src/util.c \
sqlite/src/vacuum.c sqlite/src/vdbeapi.c sqlite/src/vdbeaux.c sqlite/src/vdbe.c \
sqlite/src/vdbemem.c sqlite/src/where.c sqlite/src/parse.c sqlite/src/opcodes.c"
sqlite/src/vdbemem.c sqlite/src/where.c sqlite/src/parse.c sqlite/src/opcodes.c \
sqlite/src/alter.c sqlite/src/experimental.c"
PHP_NEW_EXTENSION(pdo_sqlite,
$php_pdo_sqlite_sources_core $pdo_sqlite_sources,
$ext_shared,,-I@ext_srcdir@/sqlite/src -DPDO_SQLITE_BUNDLED=1 -I$pdo_inc_path)
$ext_shared,,-I@ext_srcdir@/sqlite/src -DPDO_SQLITE_BUNDLED=1 -DSQLITE_OMIT_CURSOR -I$pdo_inc_path)
PHP_ADD_BUILD_DIR($ext_builddir/sqlite)
PHP_ADD_BUILD_DIR($ext_builddir/sqlite/src)
AC_CHECK_SIZEOF(char *,4)
AC_DEFINE(SQLITE_PTR_SZ, SIZEOF_CHAR_P, [Size of a pointer])
PDO_SQLITE_VERSION=`cat $ext_srcdir/sqlite/VERSION`
sed -e s/--VERS--/$PDO_SQLITE_VERSION/ $ext_srcdir/sqlite/src/sqlite.h.in > $ext_srcdir/sqlite3.h
PDO_SQLITE_VERSION_NUMBER=`echo $PDO_SQLITE_VERSION | awk -F. '{printf("%d%03d%03d", $1, $2, $3)}'`
sed -e s/--VERS--/$PDO_SQLITE_VERSION/ -e s/--VERSION-NUMBER--/$PDO_SQLITE_VERSION_NUMBER/ $ext_srcdir/sqlite/src/sqlite.h.in > $ext_srcdir/sqlite3.h
if ! test -f $ext_srcdir/sqlite/src/parse.h ; then
$CC -o $ext_srcdir/sqlite/tool/lemon $ext_srcdir/sqlite/tool/lemon.c
$ext_srcdir/sqlite/tool/lemon $ext_srcdir/sqlite/src/parse.y
cat $ext_srcdir/sqlite/src/parse.h $ext_srcdir/sqlite/src/vdbe.c | awk -f $ext_srcdir/sqlite/mkopcodeh.awk > $ext_srcdir/sqlite/src/opcodes.h
sort -n +2 $ext_srcdir/sqlite/src/opcodes.h | awk -f $ext_srcdir/sqlite/mkopcodec.awk > $ext_srcdir/sqlite/src/opcodes.c
$CC -o $ext_srcdir/sqlite/tool/mkkeywordhash $ext_srcdir/sqlite/tool/mkkeywordhash.c
$ext_srcdir/sqlite/tool/mkkeywordhash > $ext_srcdir/keywordhash.h
fi
if test "$ext_shared" = "no" -o "$ext_srcdir" != "$abs_srcdir"; then

View File

@ -72,8 +72,10 @@
<file role="src" name="sqlite3.pc.in"/>
<file role="src" name="sqlite.pc.in"/>
<file role="src" name="VERSION"/>
<file role="src" name="keywordhash.h"/>
<dir name="src">
<file role="src" name="attach.c"/>
<file role="src" name="alter.c"/>
<file role="src" name="auth.c"/>
<file role="src" name="btree.c"/>
<file role="src" name="btree.h"/>
@ -81,6 +83,7 @@
<file role="src" name="date.c"/>
<file role="src" name="delete.c"/>
<file role="src" name="expr.c"/>
<file role="src" name="experimental.c"/>
<file role="src" name="func.c"/>
<file role="src" name="hash.c"/>
<file role="src" name="hash.h"/>

View File

@ -26,29 +26,21 @@ BCC = @BUILD_CC@ @BUILD_CFLAGS@
# will run on the target platform. (BCC and TCC are usually the
# same unless your are cross-compiling.)
#
TCC = @TARGET_CC@ @TARGET_CFLAGS@ -I. -I${TOP}/src -DNDEBUG
TCC = @TARGET_CC@ @TARGET_CFLAGS@ -I. -I${TOP}/src
# Some standard variables and programs
# Define -DNDEBUG to compile without debugging (i.e., for production usage)
# Omitting the define will cause extra debugging code to be inserted and
# includes extra comments when "EXPLAIN stmt" is used.
#
prefix = @prefix@
exec_prefix = @exec_prefix@
libdir = @libdir@
INSTALL = @INSTALL@
LIBTOOL = ./libtool
RELEASE = @ALLOWRELEASE@
# libtool compile/link/install
LTCOMPILE = $(LIBTOOL) --mode=compile $(TCC)
LTLINK = $(LIBTOOL) --mode=link $(TCC)
LTINSTALL = $(LIBTOOL) --mode=install $(INSTALL)
TCC += @TARGET_DEBUG@
# Compiler options needed for programs that use the TCL library.
#
TCL_FLAGS = @TARGET_TCL_INC@
TCC += @TCL_INCLUDE_SPEC@
# The library that programs using TCL must link against.
#
LIBTCL = @TARGET_TCL_LIBS@
LIBTCL = @TCL_LIB_SPEC@ @TCL_LIBS@
# Compiler options needed for programs that use the readline() library.
#
@ -74,22 +66,64 @@ LIBPTHREAD=@TARGET_THREAD_LIB@
#
TEMP_STORE = -DTEMP_STORE=@TEMP_STORE@
# Version numbers and release number for the SQLite being compiled.
#
VERSION = @VERSION@
VERSION_NUMBER = @VERSION_NUMBER@
RELEASE = @RELEASE@
# Filename extensions
#
BEXE = @BUILD_EXEEXT@
TEXE = @TARGET_EXEEXT@
# The following variable is "1" if the configure script was able to locate
# the tclConfig.sh file. It is an empty string otherwise. When this
# variable is "1", the TCL extension library (libtclsqlite3.so) is built
# and installed.
#
HAVE_TCL = @HAVE_TCL@
# The suffix used on shared libraries. Ex: ".dll", ".so", ".dylib"
#
SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@
# The directory into which to store package information for
# Some standard variables and programs
#
prefix = @prefix@
exec_prefix = @exec_prefix@
libdir = @libdir@
INSTALL = @INSTALL@
LIBTOOL = ./libtool
ALLOWRELEASE = @ALLOWRELEASE@
# libtool compile/link/install
LTCOMPILE = $(LIBTOOL) --mode=compile $(TCC)
LTLINK = $(LIBTOOL) --mode=link $(TCC)
LTINSTALL = $(LIBTOOL) --mode=install $(INSTALL)
# You should not have to change anything below this line
###############################################################################
OPTS += -DSQLITE_OMIT_CURSOR # Cursors do not work at this time
TCC += -DSQLITE_OMIT_CURSOR
# Object files for the SQLite library.
#
LIBOBJ = attach.lo auth.lo btree.lo build.lo date.lo delete.lo \
expr.lo func.lo hash.lo insert.lo \
main.lo opcodes.lo os_mac.lo os_unix.lo os_win.lo \
LIBOBJ = alter.lo attach.lo auth.lo btree.lo build.lo date.lo \
delete.lo expr.lo func.lo hash.lo insert.lo \
main.lo opcodes.lo os_unix.lo os_win.lo \
pager.lo parse.lo pragma.lo printf.lo random.lo \
select.lo table.lo tokenize.lo trigger.lo update.lo util.lo vacuum.lo \
vdbe.lo vdbeapi.lo vdbeaux.lo vdbemem.lo \
select.lo table.lo tokenize.lo trigger.lo update.lo \
util.lo vacuum.lo vdbe.lo vdbeapi.lo vdbeaux.lo vdbemem.lo \
where.lo utf.lo legacy.lo
# All of the source code files.
#
SRC = \
$(TOP)/src/alter.c \
$(TOP)/src/attach.c \
$(TOP)/src/auth.c \
$(TOP)/src/btree.c \
@ -104,7 +138,6 @@ SRC = \
$(TOP)/src/insert.c \
$(TOP)/src/legacy.c \
$(TOP)/src/main.c \
$(TOP)/src/os_mac.c \
$(TOP)/src/os_unix.c \
$(TOP)/src/os_win.c \
$(TOP)/src/pager.c \
@ -137,8 +170,8 @@ SRC = \
#
TESTSRC = \
$(TOP)/src/btree.c \
$(TOP)/src/date.c \
$(TOP)/src/func.c \
$(TOP)/src/os_mac.c \
$(TOP)/src/os_unix.c \
$(TOP)/src/os_win.c \
$(TOP)/src/pager.c \
@ -164,7 +197,6 @@ HDR = \
opcodes.h \
$(TOP)/src/os.h \
$(TOP)/src/os_common.h \
$(TOP)/src/os_mac.h \
$(TOP)/src/os_unix.h \
$(TOP)/src/os_win.h \
$(TOP)/src/sqliteInt.h \
@ -180,7 +212,7 @@ VDBEHDR = \
# This is the default Makefile target. The objects listed here
# are what get build when you type just "make" with no arguments.
#
all: sqlite3.h libsqlite3.la sqlite3@TARGET_EXEEXT@
all: sqlite3.h libsqlite3.la sqlite3$(TEXE) $(HAVE_TCL:1=libtclsqlite3.la)
Makefile: $(TOP)/Makefile.in
./config.status
@ -194,14 +226,15 @@ last_change: $(SRC)
libsqlite3.la: $(LIBOBJ)
$(LTLINK) -o libsqlite3.la $(LIBOBJ) $(LIBPTHREAD) \
${RELEASE} -rpath $(libdir) -version-info "8:6:8"
${ALLOWRELEASE} -rpath $(libdir) -version-info "8:6:8"
libtclsqlite3.la: tclsqlite.lo libsqlite3.la
$(LTLINK) -o libtclsqlite3.la tclsqlite.lo \
libsqlite3.la $(LIBTCL) $(LIBPTHREAD) -rpath $(libdir)/sqlite \
$(LIBOBJ) @TCL_STUB_LIB_SPEC@ $(LIBPTHREAD) \
-rpath $(libdir)/sqlite \
-version-info "8:6:8"
sqlite3@TARGET_EXEEXT@: $(TOP)/src/shell.c libsqlite3.la sqlite3.h
sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h
$(LTLINK) $(READLINE_FLAGS) $(LIBPTHREAD) \
-o sqlite3 $(TOP)/src/shell.c libsqlite3.la $(LIBREADLINE)
@ -211,23 +244,26 @@ sqlite3@TARGET_EXEEXT@: $(TOP)/src/shell.c libsqlite3.la sqlite3.h
# files are automatically generated. This target takes care of
# all that automatic generation.
#
target_source: $(SRC) $(VDBEHDR)
target_source: $(SRC) parse.c opcodes.c keywordhash.h $(VDBEHDR)
rm -rf tsrc
mkdir -p tsrc
cp $(SRC) $(VDBEHDR) tsrc
rm tsrc/sqlite.h.in tsrc/parse.y
cp parse.c opcodes.c tsrc
cp parse.c opcodes.c keywordhash.h tsrc
cp $(TOP)/sqlite3.def tsrc
# Rules to build the LEMON compiler generator
#
lemon@BUILD_EXEEXT@: $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
lemon$(BEXE): $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
$(BCC) -o lemon $(TOP)/tool/lemon.c
cp $(TOP)/tool/lempar.c .
# Rules to build individual files
#
alter.lo: $(TOP)/src/alter.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/alter.c
attach.lo: $(TOP)/src/attach.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/attach.c
@ -287,14 +323,11 @@ opcodes.lo: opcodes.c
$(LTCOMPILE) -c opcodes.c
opcodes.c: opcodes.h $(TOP)/mkopcodec.awk
sort -n +2 opcodes.h | awk -f $(TOP)/mkopcodec.awk >opcodes.c
sort -n -b +2 opcodes.h | awk -f $(TOP)/mkopcodec.awk >opcodes.c
opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/mkopcodeh.awk
cat parse.h $(TOP)/src/vdbe.c | awk -f $(TOP)/mkopcodeh.awk >opcodes.h
os_mac.lo: $(TOP)/src/os_mac.c $(HDR)
$(LTCOMPILE) $(THREADSAFE) -c $(TOP)/src/os_mac.c
os_unix.lo: $(TOP)/src/os_unix.c $(HDR)
$(LTCOMPILE) $(THREADSAFE) -c $(TOP)/src/os_unix.c
@ -306,15 +339,15 @@ parse.lo: parse.c $(HDR)
parse.h: parse.c
parse.c: $(TOP)/src/parse.y lemon@BUILD_EXEEXT@
parse.c: $(TOP)/src/parse.y lemon$(BEXE)
cp $(TOP)/src/parse.y .
./lemon parse.y
./lemon $(OPTS) parse.y
pragma.lo: $(TOP)/src/pragma.c $(HDR)
$(LTCOMPILE) $(TCL_FLAGS) -c $(TOP)/src/pragma.c
$(LTCOMPILE) -c $(TOP)/src/pragma.c
printf.lo: $(TOP)/src/printf.c $(HDR)
$(LTCOMPILE) $(TCL_FLAGS) -c $(TOP)/src/printf.c
$(LTCOMPILE) -c $(TOP)/src/printf.c
random.lo: $(TOP)/src/random.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/random.c
@ -323,18 +356,22 @@ select.lo: $(TOP)/src/select.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/select.c
sqlite3.h: $(TOP)/src/sqlite.h.in
sed -e s/--VERS--/`cat ${TOP}/VERSION`/ \
$(TOP)/src/sqlite.h.in >sqlite3.h
sed -e s/--VERS--/$(RELEASE)/ $(TOP)/src/sqlite.h.in | \
sed -e s/--VERSION-NUMBER--/$(VERSION_NUMBER)/ >sqlite3.h
table.lo: $(TOP)/src/table.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/table.c
tclsqlite.lo: $(TOP)/src/tclsqlite.c $(HDR)
$(LTCOMPILE) $(TCL_FLAGS) -c $(TOP)/src/tclsqlite.c
$(LTCOMPILE) -c $(TOP)/src/tclsqlite.c
tokenize.lo: $(TOP)/src/tokenize.c $(HDR)
tokenize.lo: $(TOP)/src/tokenize.c keywordhash.h $(HDR)
$(LTCOMPILE) -c $(TOP)/src/tokenize.c
keywordhash.h: $(TOP)/tool/mkkeywordhash.c
$(BCC) -o mkkeywordhash$(BEXE) $(OPTS) $(TOP)/tool/mkkeywordhash.c
./mkkeywordhash$(BEXE) >keywordhash.h
trigger.lo: $(TOP)/src/trigger.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/trigger.c
@ -365,33 +402,49 @@ vdbemem.lo: $(TOP)/src/vdbemem.c $(VDBEHDR)
where.lo: $(TOP)/src/where.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/where.c
tclsqlite-sh.lo: $(TOP)/src/tclsqlite.c $(HDR)
$(LTCOMPILE) $(TCL_FLAGS) -DTCLSH=1 -o $@ -c $(TOP)/src/tclsqlite.c
tclsqlite-shell.lo: $(TOP)/src/tclsqlite.c $(HDR)
$(LTCOMPILE) -DTCLSH=1 -o $@ -c $(TOP)/src/tclsqlite.c
tclsqlite3: tclsqlite-sh.lo libsqlite3.la
$(LTLINK) $(TCL_FLAGS) -o tclsqlite3 tclsqlite-sh.lo \
tclsqlite-stubs.lo: $(TOP)/src/tclsqlite.c $(HDR)
$(LTCOMPILE) -DTCL_USE_STUBS=1 -o $@ -c $(TOP)/src/tclsqlite.c
tclsqlite3: tclsqlite-shell.lo libsqlite3.la
$(LTLINK) -o tclsqlite3 tclsqlite-shell.lo \
libsqlite3.la $(LIBTCL)
testfixture@TARGET_EXEEXT@: $(TOP)/src/tclsqlite.c libtclsqlite3.la libsqlite3.la $(TESTSRC)
$(LTLINK) $(TCL_FLAGS) -DTCLSH=1 -DSQLITE_TEST=1\
testfixture$(TEXE): $(TOP)/src/tclsqlite.c libtclsqlite3.la libsqlite3.la $(TESTSRC)
$(LTLINK) -DTCLSH=1 -DSQLITE_TEST=1\
$(THREADSAFE) $(TEMP_STORE)\
-o testfixture $(TESTSRC) $(TOP)/src/tclsqlite.c \
libtclsqlite3.la libsqlite3.la $(LIBTCL)
libtclsqlite3.la $(LIBTCL)
crashtest@TARGET_EXEEXT@: $(TOP)/src/tclsqlite.c libsqlite3.la $(TESTSRC) $(TOP)/src/os_test.c
$(LTLINK) $(TCL_FLAGS) -DOS_TEST=1 -DTCLSH=1 -DSQLITE_TEST=1 \
crashtest$(TEXE): $(TOP)/src/tclsqlite.c libsqlite3.la $(TESTSRC) $(TOP)/src/os_test.c
$(LTLINK) -DOS_TEST=1 -DTCLSH=1 -DSQLITE_TEST=1 \
-o crashtest \
$(TESTSRC) $(TOP)/src/os_test.c $(TOP)/src/tclsqlite.c \
libsqlite3.la $(LIBTCL) $(THREADLIB)
fulltest: testfixture@TARGET_EXEEXT@ sqlite3@TARGET_EXEEXT@ crashtest@TARGET_EXEEXT@
fulltest: testfixture$(TEXE) sqlite3$(TEXE) crashtest$(TEXE)
./testfixture $(TOP)/test/all.test
test: testfixture@TARGET_EXEEXT@ sqlite3@TARGET_EXEEXT@
test: testfixture$(TEXE) sqlite3$(TEXE)
./testfixture $(TOP)/test/quick.test
sqlite3_analyzer$(TEXE): $(TOP)/src/tclsqlite.c libtclsqlite3.la \
$(TESTSRC) $(TOP)/tool/spaceanal.tcl
sed \
-e '/^#/d' \
-e 's,\\,\\\\,g' \
-e 's,",\\",g' \
-e 's,^,",' \
-e 's,$$,\\n",' \
$(TOP)/tool/spaceanal.tcl >spaceanal_tcl.h
$(LTLINK) -DTCLSH=2 -DSQLITE_TEST=1\
$(THREADSAFE) $(TEMP_STORE)\
-o sqlite3_analyzer$(EXE) $(TESTSRC) $(TOP)/src/tclsqlite.c \
libtclsqlite3.la $(LIBTCL)
# Rules used to build documentation
#
@ -401,6 +454,9 @@ arch.html: $(TOP)/www/arch.tcl
arch2.gif: $(TOP)/www/arch2.gif
cp $(TOP)/www/arch2.gif .
autoinc.html: $(TOP)/www/autoinc.tcl
tclsh $(TOP)/www/autoinc.tcl >autoinc.html
c_interface.html: $(TOP)/www/c_interface.tcl
tclsh $(TOP)/www/c_interface.tcl >c_interface.html
@ -413,6 +469,9 @@ capi3ref.html: $(TOP)/www/capi3ref.tcl
changes.html: $(TOP)/www/changes.tcl
tclsh $(TOP)/www/changes.tcl >changes.html
compile.html: $(TOP)/www/compile.tcl
tclsh $(TOP)/www/compile.tcl >compile.html
copyright.html: $(TOP)/www/copyright.tcl
tclsh $(TOP)/www/copyright.tcl >copyright.html
@ -456,6 +515,9 @@ index.html: $(TOP)/www/index.tcl last_change
lang.html: $(TOP)/www/lang.tcl
tclsh $(TOP)/www/lang.tcl >lang.html
pragma.html: $(TOP)/www/pragma.tcl
tclsh $(TOP)/www/pragma.tcl >pragma.html
lockingv3.html: $(TOP)/www/lockingv3.tcl
tclsh $(TOP)/www/lockingv3.tcl >lockingv3.html
@ -503,11 +565,13 @@ version3.html: $(TOP)/www/version3.tcl
#
DOC = \
arch.html \
arch2.gif \
arch.png \
autoinc.html \
c_interface.html \
capi3.html \
capi3ref.html \
changes.html \
compile.html \
copyright.html \
copyright-release.html \
copyright-release.pdf \
@ -527,6 +591,7 @@ DOC = \
oldnews.html \
omitted.html \
opcode.html \
pragma.html \
quickstart.html \
speed.html \
sqlite.gif \
@ -534,13 +599,13 @@ DOC = \
support.html \
tclsqlite.html \
vdbe.html \
version3.html
version3.html
doc: common.tcl $(DOC)
mkdir -p doc
mv $(DOC) doc
install: sqlite3 libsqlite3.la sqlite3.h
install: sqlite3 libsqlite3.la sqlite3.h ${HAVE_TCL:1=tcl_install}
$(INSTALL) -d $(DESTDIR)$(libdir)
$(LTINSTALL) libsqlite3.la $(DESTDIR)$(libdir)
$(INSTALL) -d $(DESTDIR)$(exec_prefix)/bin
@ -550,14 +615,18 @@ install: sqlite3 libsqlite3.la sqlite3.h
$(INSTALL) -d $(DESTDIR)$(libdir)/pkgconfig;
$(INSTALL) -m 0644 sqlite3.pc $(DESTDIR)$(libdir)/pkgconfig;
tcl_install: libtclsqlite3.la
tclsh $(TOP)/tclinstaller.tcl $(VERSION)
clean:
rm -f *.lo *.la *.o sqlite3@TARGET_EXEEXT@ libsqlite3.la
rm -f *.lo *.la *.o sqlite3$(TEXE) libsqlite3.la
rm -f sqlite3.h opcodes.*
rm -rf .libs .deps
rm -f lemon@BUILD_EXEEXT@ lempar.c parse.* sqlite*.tar.gz
rm -f lemon$(BEXE) lempar.c parse.* sqlite*.tar.gz
rm -f mkkeywordhash$(BEXE) keywordhash.h
rm -f $(PUBLISH)
rm -f *.da *.bb *.bbg gmon.out
rm -f testfixture@TARGET_EXEEXT@ test.db
rm -f testfixture$(TEXE) test.db
rm -rf doc
rm -f common.tcl
rm -f sqlite3.dll sqlite3.lib

View File

@ -1 +1 @@
3.0.8
3.1.3

View File

@ -463,7 +463,7 @@ ac_includes_default="\
# include <unistd.h>
#endif"
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB STRIP ac_ct_STRIP CPP CXX CXXFLAGS ac_ct_CXX CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA program_prefix VERSION BUILD_CC BUILD_CFLAGS BUILD_LIBS TARGET_CC TARGET_CFLAGS TARGET_LINK TARGET_LFLAGS TARGET_RANLIB TARGET_AR THREADSAFE TARGET_THREAD_LIB ALLOWRELEASE TEMP_STORE BUILD_EXEEXT OS_UNIX OS_WIN TARGET_EXEEXT TARGET_LIBS TARGET_TCL_LIBS TARGET_TCL_INC TARGET_READLINE_LIBS TARGET_READLINE_INC TARGET_HAVE_READLINE LIBOBJS LTLIBOBJS'
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB STRIP ac_ct_STRIP CPP CXX CXXFLAGS ac_ct_CXX CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA program_prefix VERSION VERSION_NUMBER RELEASE BUILD_CC BUILD_CFLAGS BUILD_LIBS TARGET_CC TARGET_CFLAGS TARGET_LINK TARGET_LFLAGS TARGET_RANLIB TARGET_AR THREADSAFE TARGET_THREAD_LIB ALLOWRELEASE TEMP_STORE BUILD_EXEEXT OS_UNIX OS_WIN TARGET_EXEEXT TARGET_LIBS TCL_VERSION TCL_BIN_DIR TCL_SRC_DIR TCL_LIBS TCL_INCLUDE_SPEC TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC HAVE_TCL TARGET_READLINE_LIBS TARGET_READLINE_INC TARGET_HAVE_READLINE TARGET_DEBUG LIBOBJS LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@ -1028,6 +1028,8 @@ Optional Features:
--enable-threadsafe Support threadsafe operation
--enable-releasemode Support libtool link to release mode
--enable-tempstore Use an in-ram database for temporary tables (never,no,yes,always)
--disable-tcl do not build TCL extension
--enable-debug enable debugging & verbose explain
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
@ -1038,6 +1040,7 @@ Optional Packages:
--with-tags[=TAGS]
include additional configurations [automatic]
--with-hints=FILE Read configuration options from FILE
--with-tcl=DIR directory containing tcl configuration (tclConfig.sh)
Some influential environment variables:
CC C compiler command
@ -3052,7 +3055,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
echo '#line 3055 "configure"' > conftest.$ac_ext
echo '#line 3058 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
@ -4515,7 +4518,7 @@ fi
# Provide some information about the compiler.
echo "$as_me:4518:" \
echo "$as_me:4521:" \
"checking for Fortran 77 compiler version" >&5
ac_compiler=`set X $ac_compile; echo $2`
{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
@ -5549,11 +5552,11 @@ else
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:5552: $lt_compile\"" >&5)
(eval echo "\"\$as_me:5555: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:5556: \$? = $ac_status" >&5
echo "$as_me:5559: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
@ -5782,11 +5785,11 @@ else
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:5785: $lt_compile\"" >&5)
(eval echo "\"\$as_me:5788: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:5789: \$? = $ac_status" >&5
echo "$as_me:5792: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
@ -5842,11 +5845,11 @@ else
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:5845: $lt_compile\"" >&5)
(eval echo "\"\$as_me:5848: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:5849: \$? = $ac_status" >&5
echo "$as_me:5852: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@ -8026,7 +8029,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
#line 8029 "configure"
#line 8032 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -8124,7 +8127,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
#line 8127 "configure"
#line 8130 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -10303,11 +10306,11 @@ else
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:10306: $lt_compile\"" >&5)
(eval echo "\"\$as_me:10309: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:10310: \$? = $ac_status" >&5
echo "$as_me:10313: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
@ -10363,11 +10366,11 @@ else
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:10366: $lt_compile\"" >&5)
(eval echo "\"\$as_me:10369: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:10370: \$? = $ac_status" >&5
echo "$as_me:10373: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@ -11724,7 +11727,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
#line 11727 "configure"
#line 11730 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -11822,7 +11825,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
#line 11825 "configure"
#line 11828 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -12649,11 +12652,11 @@ else
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:12652: $lt_compile\"" >&5)
(eval echo "\"\$as_me:12655: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:12656: \$? = $ac_status" >&5
echo "$as_me:12659: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
@ -12709,11 +12712,11 @@ else
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:12712: $lt_compile\"" >&5)
(eval echo "\"\$as_me:12715: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:12716: \$? = $ac_status" >&5
echo "$as_me:12719: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@ -14743,11 +14746,11 @@ else
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:14746: $lt_compile\"" >&5)
(eval echo "\"\$as_me:14749: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:14750: \$? = $ac_status" >&5
echo "$as_me:14753: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
@ -14976,11 +14979,11 @@ else
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:14979: $lt_compile\"" >&5)
(eval echo "\"\$as_me:14982: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:14983: \$? = $ac_status" >&5
echo "$as_me:14986: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
@ -15036,11 +15039,11 @@ else
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:15039: $lt_compile\"" >&5)
(eval echo "\"\$as_me:15042: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:15043: \$? = $ac_status" >&5
echo "$as_me:15046: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@ -17220,7 +17223,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
#line 17223 "configure"
#line 17226 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -17318,7 +17321,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
#line 17321 "configure"
#line 17324 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -18420,11 +18423,17 @@ if test "$program_prefix" = "NONE"; then
fi
if test -f VERSION; then
VERSION=`cat VERSION`
echo "Version set to $VERSION"
fi
VERSION=`cat $srcdir/VERSION | sed 's/^\([0-9]*\.*[0-9]*\).*/\1/'`
echo "Version set to $VERSION"
RELEASE=`cat $srcdir/VERSION`
echo "Release set to $RELEASE"
VERSION_NUMBER=`cat $srcdir/VERSION \
| sed 's/[^0-9]/ /g' \
| awk '{printf "%d%03d%03d",$1,$2,$3}'`
echo "Version number set to $VERSION_NUMBER"
#########
# Check to see if the --with-hints=FILE option is used. If there is none,
@ -19611,520 +19620,169 @@ fi
##########
# Figure out what C libraries are required to compile Tcl programs.
# Figure out all the parameters needed to compile against Tcl.
#
if test "$config_TARGET_TCL_LIBS" != ""; then
TARGET_TCL_LIBS="$config_TARGET_TCL_LIBS"
else
if test "$with_tcl" != ""; then
extra=`echo $with_tcl/$tclsubdir/libtcl8*.a`
fi
CC=$TARGET_CC
echo "$as_me:$LINENO: checking for sin" >&5
echo $ECHO_N "checking for sin... $ECHO_C" >&6
if test "${ac_cv_func_sin+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Define sin to an innocuous variant, in case <limits.h> declares sin.
For example, HP-UX 11i <limits.h> declares gettimeofday. */
#define sin innocuous_sin
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char sin (); below.
Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
<limits.h> exists even on freestanding compilers. */
#ifdef __STDC__
# include <limits.h>
#else
# include <assert.h>
#endif
#undef sin
/* Override any gcc2 internal prototype to avoid an error. */
#ifdef __cplusplus
extern "C"
{
#endif
/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
char sin ();
/* The GNU C library defines this for functions which it implements
to always fail with ENOSYS. Some functions are actually named
something starting with __ and the normal name is an alias. */
#if defined (__stub_sin) || defined (__stub___sin)
choke me
#else
char (*f) () = sin;
#endif
#ifdef __cplusplus
}
#endif
int
main ()
{
return f != sin;
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
(eval $ac_link) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } &&
{ ac_try='test -z "$ac_c_werror_flag"
|| test ! -s conftest.err'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; } &&
{ ac_try='test -s conftest$ac_exeext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
ac_cv_func_sin=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_cv_func_sin=no
fi
rm -f conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
fi
echo "$as_me:$LINENO: result: $ac_cv_func_sin" >&5
echo "${ECHO_T}$ac_cv_func_sin" >&6
if test $ac_cv_func_sin = yes; then
LIBS=""
else
LIBS="-lm"
fi
echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
if test "${ac_cv_lib_dl_dlopen+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-ldl $LIBS"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Override any gcc2 internal prototype to avoid an error. */
#ifdef __cplusplus
extern "C"
#endif
/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
char dlopen ();
int
main ()
{
dlopen ();
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
(eval $ac_link) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } &&
{ ac_try='test -z "$ac_c_werror_flag"
|| test ! -s conftest.err'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; } &&
{ ac_try='test -s conftest$ac_exeext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
ac_cv_lib_dl_dlopen=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_cv_lib_dl_dlopen=no
fi
rm -f conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
if test $ac_cv_lib_dl_dlopen = yes; then
cat >>confdefs.h <<_ACEOF
#define HAVE_LIBDL 1
_ACEOF
LIBS="-ldl $LIBS"
fi
otherlibs=$LIBS
if test "$extra" != ""; then
LIBS=$extra
else
LIBS=""
echo "$as_me:$LINENO: checking for library containing Tcl_Init" >&5
echo $ECHO_N "checking for library containing Tcl_Init... $ECHO_C" >&6
if test "${ac_cv_search_Tcl_Init+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ac_func_search_save_LIBS=$LIBS
ac_cv_search_Tcl_Init=no
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Override any gcc2 internal prototype to avoid an error. */
#ifdef __cplusplus
extern "C"
#endif
/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
char Tcl_Init ();
int
main ()
{
Tcl_Init ();
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
(eval $ac_link) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } &&
{ ac_try='test -z "$ac_c_werror_flag"
|| test ! -s conftest.err'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; } &&
{ ac_try='test -s conftest$ac_exeext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
ac_cv_search_Tcl_Init="none required"
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
fi
rm -f conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
if test "$ac_cv_search_Tcl_Init" = no; then
for ac_lib in tcl8.4 tcl8.3 tcl84 tcl83 tcl; do
LIBS="-l$ac_lib $otherlibs $ac_func_search_save_LIBS"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Override any gcc2 internal prototype to avoid an error. */
#ifdef __cplusplus
extern "C"
#endif
/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
char Tcl_Init ();
int
main ()
{
Tcl_Init ();
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
(eval $ac_link) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } &&
{ ac_try='test -z "$ac_c_werror_flag"
|| test ! -s conftest.err'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; } &&
{ ac_try='test -s conftest$ac_exeext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
ac_cv_search_Tcl_Init="-l$ac_lib"
break
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
fi
rm -f conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
done
fi
LIBS=$ac_func_search_save_LIBS
fi
echo "$as_me:$LINENO: result: $ac_cv_search_Tcl_Init" >&5
echo "${ECHO_T}$ac_cv_search_Tcl_Init" >&6
if test "$ac_cv_search_Tcl_Init" != no; then
test "$ac_cv_search_Tcl_Init" = "none required" || LIBS="$ac_cv_search_Tcl_Init $LIBS"
fi
fi
TARGET_TCL_LIBS="$LIBS $otherlibs"
fi
##########
# Figure out where to get the TCL header files.
# This code is derived from the SC_PATH_TCLCONFIG and SC_LOAD_TCLCONFIG
# macros in the in the tcl.m4 file of the standard TCL distribution.
# Those macros could not be used directly since we have to make some
# minor changes to accomodate systems that do not have TCL installed.
#
echo "$as_me:$LINENO: checking TCL header files" >&5
echo $ECHO_N "checking TCL header files... $ECHO_C" >&6
found=no
if test "$config_TARGET_TCL_INC" != ""; then
TARGET_TCL_INC=$config_TARGET_TCL_INC
found=yes
# Check whether --enable-tcl or --disable-tcl was given.
if test "${enable_tcl+set}" = set; then
enableval="$enable_tcl"
use_tcl=$enableval
else
if test "$with_tcl" != ""; then
TARGET_TCL_INC="-I$with_tcl/generic -I$with_tcl/$tclsubdir"
found=yes
else
TARGET_TCL_INC=""
found=no
fi
fi
if test "$found" = "yes"; then
echo "$as_me:$LINENO: result: $TARGET_TCL_INC" >&5
echo "${ECHO_T}$TARGET_TCL_INC" >&6
else
echo "$as_me:$LINENO: result: not specified: still searching..." >&5
echo "${ECHO_T}not specified: still searching..." >&6
if test "${ac_cv_header_tcl_h+set}" = set; then
echo "$as_me:$LINENO: checking for tcl.h" >&5
echo $ECHO_N "checking for tcl.h... $ECHO_C" >&6
if test "${ac_cv_header_tcl_h+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
fi
echo "$as_me:$LINENO: result: $ac_cv_header_tcl_h" >&5
echo "${ECHO_T}$ac_cv_header_tcl_h" >&6
else
# Is the header compilable?
echo "$as_me:$LINENO: checking tcl.h usability" >&5
echo $ECHO_N "checking tcl.h usability... $ECHO_C" >&6
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
$ac_includes_default
#include <tcl.h>
_ACEOF
rm -f conftest.$ac_objext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } &&
{ ac_try='test -z "$ac_c_werror_flag"
|| test ! -s conftest.err'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; } &&
{ ac_try='test -s conftest.$ac_objext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
ac_header_compiler=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
use_tcl=yes
fi;
if test "${use_tcl}" = "yes" ; then
ac_header_compiler=no
fi
rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
echo "${ECHO_T}$ac_header_compiler" >&6
# Is the header present?
echo "$as_me:$LINENO: checking tcl.h presence" >&5
echo $ECHO_N "checking tcl.h presence... $ECHO_C" >&6
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#include <tcl.h>
_ACEOF
if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
(eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } >/dev/null; then
if test -s conftest.err; then
ac_cpp_err=$ac_c_preproc_warn_flag
ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
else
ac_cpp_err=
fi
else
ac_cpp_err=yes
fi
if test -z "$ac_cpp_err"; then
ac_header_preproc=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_header_preproc=no
fi
rm -f conftest.err conftest.$ac_ext
echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
echo "${ECHO_T}$ac_header_preproc" >&6
# So? What about this header?
case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
yes:no: )
{ echo "$as_me:$LINENO: WARNING: tcl.h: accepted by the compiler, rejected by the preprocessor!" >&5
echo "$as_me: WARNING: tcl.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
{ echo "$as_me:$LINENO: WARNING: tcl.h: proceeding with the compiler's result" >&5
echo "$as_me: WARNING: tcl.h: proceeding with the compiler's result" >&2;}
ac_header_preproc=yes
;;
no:yes:* )
{ echo "$as_me:$LINENO: WARNING: tcl.h: present but cannot be compiled" >&5
echo "$as_me: WARNING: tcl.h: present but cannot be compiled" >&2;}
{ echo "$as_me:$LINENO: WARNING: tcl.h: check for missing prerequisite headers?" >&5
echo "$as_me: WARNING: tcl.h: check for missing prerequisite headers?" >&2;}
{ echo "$as_me:$LINENO: WARNING: tcl.h: see the Autoconf documentation" >&5
echo "$as_me: WARNING: tcl.h: see the Autoconf documentation" >&2;}
{ echo "$as_me:$LINENO: WARNING: tcl.h: section \"Present But Cannot Be Compiled\"" >&5
echo "$as_me: WARNING: tcl.h: section \"Present But Cannot Be Compiled\"" >&2;}
{ echo "$as_me:$LINENO: WARNING: tcl.h: proceeding with the preprocessor's result" >&5
echo "$as_me: WARNING: tcl.h: proceeding with the preprocessor's result" >&2;}
{ echo "$as_me:$LINENO: WARNING: tcl.h: in the future, the compiler will take precedence" >&5
echo "$as_me: WARNING: tcl.h: in the future, the compiler will take precedence" >&2;}
(
cat <<\_ASBOX
## ------------------------------------------ ##
## Report this to the AC_PACKAGE_NAME lists. ##
## ------------------------------------------ ##
_ASBOX
) |
sed "s/^/$as_me: WARNING: /" >&2
;;
esac
echo "$as_me:$LINENO: checking for tcl.h" >&5
echo $ECHO_N "checking for tcl.h... $ECHO_C" >&6
if test "${ac_cv_header_tcl_h+set}" = set; then
# Check whether --with-tcl or --without-tcl was given.
if test "${with_tcl+set}" = set; then
withval="$with_tcl"
with_tclconfig=${withval}
fi;
echo "$as_me:$LINENO: checking for Tcl configuration" >&5
echo $ECHO_N "checking for Tcl configuration... $ECHO_C" >&6
if test "${ac_cv_c_tclconfig+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ac_cv_header_tcl_h=$ac_header_preproc
fi
echo "$as_me:$LINENO: result: $ac_cv_header_tcl_h" >&5
echo "${ECHO_T}$ac_cv_header_tcl_h" >&6
fi
if test $ac_cv_header_tcl_h = yes; then
found=yes
fi
fi
if test "$found" = "no"; then
for dir in /usr/local /usr/X11 /usr/X11R6 /usr/pkg /usr/contrib /usr; do
as_ac_File=`echo "ac_cv_file_$dir/include/tcl.h" | $as_tr_sh`
echo "$as_me:$LINENO: checking for $dir/include/tcl.h" >&5
echo $ECHO_N "checking for $dir/include/tcl.h... $ECHO_C" >&6
if eval "test \"\${$as_ac_File+set}\" = set"; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
test "$cross_compiling" = yes &&
{ { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
# First check to see if --with-tcl was specified.
if test x"${with_tclconfig}" != x ; then
if test -f "${with_tclconfig}/tclConfig.sh" ; then
ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)`
else
{ { echo "$as_me:$LINENO: error: ${with_tclconfig} directory doesn't contain tclConfig.sh" >&5
echo "$as_me: error: ${with_tclconfig} directory doesn't contain tclConfig.sh" >&2;}
{ (exit 1); exit 1; }; }
if test -r "$dir/include/tcl.h"; then
eval "$as_ac_File=yes"
else
eval "$as_ac_File=no"
fi
fi
echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_File'}'`" >&5
echo "${ECHO_T}`eval echo '${'$as_ac_File'}'`" >&6
if test `eval echo '${'$as_ac_File'}'` = yes; then
found=yes
fi
fi
# then check for a private Tcl installation
if test x"${ac_cv_c_tclconfig}" = x ; then
for i in \
../tcl \
`ls -dr ../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
`ls -dr ../tcl[8-9].[0-9] 2>/dev/null` \
`ls -dr ../tcl[8-9].[0-9]* 2>/dev/null` \
../../tcl \
`ls -dr ../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
`ls -dr ../../tcl[8-9].[0-9] 2>/dev/null` \
`ls -dr ../../tcl[8-9].[0-9]* 2>/dev/null` \
../../../tcl \
`ls -dr ../../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
`ls -dr ../../../tcl[8-9].[0-9] 2>/dev/null` \
`ls -dr ../../../tcl[8-9].[0-9]* 2>/dev/null`
do
if test -f "$i/unix/tclConfig.sh" ; then
ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
break
fi
done
fi
# check in a few common install locations
if test x"${ac_cv_c_tclconfig}" = x ; then
for i in \
`ls -d ${libdir} 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null`
do
if test -f "$i/tclConfig.sh" ; then
ac_cv_c_tclconfig=`(cd $i; pwd)`
break
fi
done
fi
# check in a few other private locations
if test x"${ac_cv_c_tclconfig}" = x ; then
for i in \
${srcdir}/../tcl \
`ls -dr ${srcdir}/../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
`ls -dr ${srcdir}/../tcl[8-9].[0-9] 2>/dev/null` \
`ls -dr ${srcdir}/../tcl[8-9].[0-9]* 2>/dev/null`
do
if test -f "$i/unix/tclConfig.sh" ; then
ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
break
fi
done
fi
fi
if test "$found" = "yes"; then
TARGET_TCL_INC="-I$dir/include"
break
if test x"${ac_cv_c_tclconfig}" = x ; then
use_tcl=no
{ echo "$as_me:$LINENO: WARNING: Can't find Tcl configuration definitions" >&5
echo "$as_me: WARNING: Can't find Tcl configuration definitions" >&2;}
{ echo "$as_me:$LINENO: WARNING: *** Without Tcl the regression tests cannot be executed ***" >&5
echo "$as_me: WARNING: *** Without Tcl the regression tests cannot be executed ***" >&2;}
{ echo "$as_me:$LINENO: WARNING: *** Consider using --with-tcl=... to define location of Tcl ***" >&5
echo "$as_me: WARNING: *** Consider using --with-tcl=... to define location of Tcl ***" >&2;}
else
TCL_BIN_DIR=${ac_cv_c_tclconfig}
echo "$as_me:$LINENO: result: found $TCL_BIN_DIR/tclConfig.sh" >&5
echo "${ECHO_T}found $TCL_BIN_DIR/tclConfig.sh" >&6
echo "$as_me:$LINENO: checking for existence of $TCL_BIN_DIR/tclConfig.sh" >&5
echo $ECHO_N "checking for existence of $TCL_BIN_DIR/tclConfig.sh... $ECHO_C" >&6
if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then
echo "$as_me:$LINENO: result: loading" >&5
echo "${ECHO_T}loading" >&6
. $TCL_BIN_DIR/tclConfig.sh
else
echo "$as_me:$LINENO: result: file not found" >&5
echo "${ECHO_T}file not found" >&6
fi
done
#
# If the TCL_BIN_DIR is the build directory (not the install directory),
# then set the common variable name to the value of the build variables.
# For example, the variable TCL_LIB_SPEC will be set to the value
# of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC
# instead of TCL_BUILD_LIB_SPEC since it will work with both an
# installed and uninstalled version of Tcl.
#
if test -f $TCL_BIN_DIR/Makefile ; then
TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC}
TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC}
TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH}
fi
#
# eval is required to do the TCL_DBGX substitution
#
eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\""
eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\""
eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\""
eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\""
eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\""
eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\""
fi
fi
if test "$found" = "no"; then
TARGET_TCL_INC="-DNO_TCL=1"
if test "${use_tcl}" = "no" ; then
HAVE_TCL=""
else
HAVE_TCL=1
fi
@ -20568,6 +20226,22 @@ fi
#########
# check for debug enabled
# Check whether --enable-debug or --disable-debug was given.
if test "${enable_debug+set}" = set; then
enableval="$enable_debug"
use_debug=$enableval
else
use_debug=no
fi;
if test "${use_debug}" = "yes" ; then
TARGET_DEBUG=""
else
TARGET_DEBUG="-DNDEBUG"
fi
#########
# Figure out whether or not we have a "usleep()" function.
#
@ -21344,6 +21018,8 @@ s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
s,@INSTALL_DATA@,$INSTALL_DATA,;t t
s,@program_prefix@,$program_prefix,;t t
s,@VERSION@,$VERSION,;t t
s,@VERSION_NUMBER@,$VERSION_NUMBER,;t t
s,@RELEASE@,$RELEASE,;t t
s,@BUILD_CC@,$BUILD_CC,;t t
s,@BUILD_CFLAGS@,$BUILD_CFLAGS,;t t
s,@BUILD_LIBS@,$BUILD_LIBS,;t t
@ -21362,11 +21038,22 @@ s,@OS_UNIX@,$OS_UNIX,;t t
s,@OS_WIN@,$OS_WIN,;t t
s,@TARGET_EXEEXT@,$TARGET_EXEEXT,;t t
s,@TARGET_LIBS@,$TARGET_LIBS,;t t
s,@TARGET_TCL_LIBS@,$TARGET_TCL_LIBS,;t t
s,@TARGET_TCL_INC@,$TARGET_TCL_INC,;t t
s,@TCL_VERSION@,$TCL_VERSION,;t t
s,@TCL_BIN_DIR@,$TCL_BIN_DIR,;t t
s,@TCL_SRC_DIR@,$TCL_SRC_DIR,;t t
s,@TCL_LIBS@,$TCL_LIBS,;t t
s,@TCL_INCLUDE_SPEC@,$TCL_INCLUDE_SPEC,;t t
s,@TCL_LIB_FILE@,$TCL_LIB_FILE,;t t
s,@TCL_LIB_FLAG@,$TCL_LIB_FLAG,;t t
s,@TCL_LIB_SPEC@,$TCL_LIB_SPEC,;t t
s,@TCL_STUB_LIB_FILE@,$TCL_STUB_LIB_FILE,;t t
s,@TCL_STUB_LIB_FLAG@,$TCL_STUB_LIB_FLAG,;t t
s,@TCL_STUB_LIB_SPEC@,$TCL_STUB_LIB_SPEC,;t t
s,@HAVE_TCL@,$HAVE_TCL,;t t
s,@TARGET_READLINE_LIBS@,$TARGET_READLINE_LIBS,;t t
s,@TARGET_READLINE_INC@,$TARGET_READLINE_INC,;t t
s,@TARGET_HAVE_READLINE@,$TARGET_HAVE_READLINE,;t t
s,@TARGET_DEBUG@,$TARGET_DEBUG,;t t
s,@LIBOBJS@,$LIBOBJS,;t t
s,@LTLIBOBJS@,$LTLIBOBJS,;t t
CEOF

View File

@ -1,9 +1,4 @@
#
# This file describes a "configure" script that is used to build
# makefiles for a particular platform. Process this file using
# Autoconf version 1.13 in order to generate that script. All
# lines of this file up to the AC_INIT macro are ignored.
#
# The build process allows for using a cross-compiler. But the default
# action is to target the same platform that we are running on. The
# configure script needs to discover the following properties of the
@ -62,18 +57,11 @@
# into *.o files. Do not include TARGET_TCL_INC in this list.
# Makefiles might add additional switches such as "-I.".
#
# TARGET_TCL_LIBS
# TCL_*
#
# This is the library directives passed to the target linker
# that cause the executable to link against Tcl. This might
# be a switch like "-ltcl8.0" or pathnames of library file
# like "../../src/libtcl8.0.a".
#
# TARGET_TCL_INC
#
# This variables define the directory that contain header
# files for Tcl. If the compiler is able to find <tcl.h>
# on its own, then this can be blank.
# Lots of values are read in from the tclConfig.sh script,
# if that script is available. This values are used for
# constructing and installing the TCL extension.
#
# TARGET_READLINE_LIBS
#
@ -118,16 +106,6 @@
# where FILE is the name of the file that sets the environment
# variables. FILE should be an absolute pathname.
#
# If you have a Tcl/Tk/BLT source distribution available, then the
# files in that distribution will be used instead of any other
# Tcl/Tk/BLT files the script might discover if you tell the configure
# script about the source tree. Use commandline options:
#
# --with-tcl=PATH --with-tk=PATH --with-blt=PATH
#
# Or set environment variables config_WITH_TCL, config_WITH_TK, or
# config_WITH_BLT.
#
# This configure.in file is easy to reuse on other projects. Just
# change the argument to AC_INIT(). And disable any features that
# you don't need (for example BLT) by erasing or commenting out
@ -154,11 +132,17 @@ if test "$program_prefix" = "NONE"; then
fi
AC_SUBST(program_prefix)
if test -f VERSION; then
VERSION=`cat VERSION`
echo "Version set to $VERSION"
fi
VERSION=[`cat $srcdir/VERSION | sed 's/^\([0-9]*\.*[0-9]*\).*/\1/'`]
echo "Version set to $VERSION"
AC_SUBST(VERSION)
RELEASE=`cat $srcdir/VERSION`
echo "Release set to $RELEASE"
AC_SUBST(RELEASE)
VERSION_NUMBER=`cat $srcdir/VERSION \
| sed 's/[^0-9]/ /g' \
| awk '{printf "%d%03d%03d",$1,$2,$3}'`
echo "Version number set to $VERSION_NUMBER"
AC_SUBST(VERSION_NUMBER)
#########
# Check to see if the --with-hints=FILE option is used. If there is none,
@ -410,65 +394,146 @@ fi
AC_SUBST(TARGET_LIBS)
##########
# Figure out what C libraries are required to compile Tcl programs.
# Figure out all the parameters needed to compile against Tcl.
#
if test "$config_TARGET_TCL_LIBS" != ""; then
TARGET_TCL_LIBS="$config_TARGET_TCL_LIBS"
else
if test "$with_tcl" != ""; then
extra=`echo $with_tcl/$tclsubdir/libtcl8*.a`
fi
CC=$TARGET_CC
AC_CHECK_FUNC(sin, LIBS="", LIBS="-lm")
AC_CHECK_LIB(dl, dlopen)
otherlibs=$LIBS
if test "$extra" != ""; then
LIBS=$extra
else
LIBS=""
AC_SEARCH_LIBS(Tcl_Init, dnl
tcl8.4 tcl8.3 tcl84 tcl83 tcl,,,$otherlibs)
fi
TARGET_TCL_LIBS="$LIBS $otherlibs"
fi
AC_SUBST(TARGET_TCL_LIBS)
##########
# Figure out where to get the TCL header files.
# This code is derived from the SC_PATH_TCLCONFIG and SC_LOAD_TCLCONFIG
# macros in the in the tcl.m4 file of the standard TCL distribution.
# Those macros could not be used directly since we have to make some
# minor changes to accomodate systems that do not have TCL installed.
#
AC_MSG_CHECKING([TCL header files])
found=no
if test "$config_TARGET_TCL_INC" != ""; then
TARGET_TCL_INC=$config_TARGET_TCL_INC
found=yes
else
if test "$with_tcl" != ""; then
TARGET_TCL_INC="-I$with_tcl/generic -I$with_tcl/$tclsubdir"
found=yes
else
TARGET_TCL_INC=""
found=no
fi
fi
if test "$found" = "yes"; then
AC_MSG_RESULT($TARGET_TCL_INC)
else
AC_MSG_RESULT(not specified: still searching...)
AC_CHECK_HEADER(tcl.h, [found=yes])
fi
if test "$found" = "no"; then
for dir in /usr/local /usr/X11 /usr/X11R6 /usr/pkg /usr/contrib /usr; do
AC_CHECK_FILE($dir/include/tcl.h, found=yes)
if test "$found" = "yes"; then
TARGET_TCL_INC="-I$dir/include"
break
AC_ARG_ENABLE(tcl, [ --disable-tcl do not build TCL extension],
[use_tcl=$enableval],[use_tcl=yes])
if test "${use_tcl}" = "yes" ; then
AC_ARG_WITH(tcl, [ --with-tcl=DIR directory containing tcl configuration (tclConfig.sh)], with_tclconfig=${withval})
AC_MSG_CHECKING([for Tcl configuration])
AC_CACHE_VAL(ac_cv_c_tclconfig,[
# First check to see if --with-tcl was specified.
if test x"${with_tclconfig}" != x ; then
if test -f "${with_tclconfig}/tclConfig.sh" ; then
ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)`
else
AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh])
fi
fi
done
# then check for a private Tcl installation
if test x"${ac_cv_c_tclconfig}" = x ; then
for i in \
../tcl \
`ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
`ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \
`ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \
../../tcl \
`ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
`ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \
`ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \
../../../tcl \
`ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
`ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \
`ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null`
do
if test -f "$i/unix/tclConfig.sh" ; then
ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
break
fi
done
fi
# check in a few common install locations
if test x"${ac_cv_c_tclconfig}" = x ; then
for i in \
`ls -d ${libdir} 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null`
do
if test -f "$i/tclConfig.sh" ; then
ac_cv_c_tclconfig=`(cd $i; pwd)`
break
fi
done
fi
# check in a few other private locations
if test x"${ac_cv_c_tclconfig}" = x ; then
for i in \
${srcdir}/../tcl \
`ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
`ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \
`ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null`
do
if test -f "$i/unix/tclConfig.sh" ; then
ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
break
fi
done
fi
])
if test x"${ac_cv_c_tclconfig}" = x ; then
use_tcl=no
AC_MSG_WARN(Can't find Tcl configuration definitions)
AC_MSG_WARN(*** Without Tcl the regression tests cannot be executed ***)
AC_MSG_WARN(*** Consider using --with-tcl=... to define location of Tcl ***)
else
TCL_BIN_DIR=${ac_cv_c_tclconfig}
AC_MSG_RESULT(found $TCL_BIN_DIR/tclConfig.sh)
AC_MSG_CHECKING([for existence of $TCL_BIN_DIR/tclConfig.sh])
if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then
AC_MSG_RESULT([loading])
. $TCL_BIN_DIR/tclConfig.sh
else
AC_MSG_RESULT([file not found])
fi
#
# If the TCL_BIN_DIR is the build directory (not the install directory),
# then set the common variable name to the value of the build variables.
# For example, the variable TCL_LIB_SPEC will be set to the value
# of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC
# instead of TCL_BUILD_LIB_SPEC since it will work with both an
# installed and uninstalled version of Tcl.
#
if test -f $TCL_BIN_DIR/Makefile ; then
TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC}
TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC}
TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH}
fi
#
# eval is required to do the TCL_DBGX substitution
#
eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\""
eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\""
eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\""
eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\""
eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\""
eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\""
AC_SUBST(TCL_VERSION)
AC_SUBST(TCL_BIN_DIR)
AC_SUBST(TCL_SRC_DIR)
AC_SUBST(TCL_LIBS)
AC_SUBST(TCL_INCLUDE_SPEC)
AC_SUBST(TCL_LIB_FILE)
AC_SUBST(TCL_LIB_FLAG)
AC_SUBST(TCL_LIB_SPEC)
AC_SUBST(TCL_STUB_LIB_FILE)
AC_SUBST(TCL_STUB_LIB_FLAG)
AC_SUBST(TCL_STUB_LIB_SPEC)
fi
fi
if test "$found" = "no"; then
TARGET_TCL_INC="-DNO_TCL=1"
if test "${use_tcl}" = "no" ; then
HAVE_TCL=""
else
HAVE_TCL=1
fi
AC_SUBST(TARGET_TCL_INC)
AC_SUBST(HAVE_TCL)
##########
# Figure out what C libraries are required to compile programs
@ -526,6 +591,17 @@ fi
AC_SUBST(TARGET_READLINE_INC)
AC_SUBST(TARGET_HAVE_READLINE)
#########
# check for debug enabled
AC_ARG_ENABLE(debug, [ --enable-debug enable debugging & verbose explain],
[use_debug=$enableval],[use_debug=no])
if test "${use_debug}" = "yes" ; then
TARGET_DEBUG=""
else
TARGET_DEBUG="-DNDEBUG"
fi
AC_SUBST(TARGET_DEBUG)
#########
# Figure out whether or not we have a "usleep()" function.
#

View File

@ -54,9 +54,9 @@ TCCX = $(TCC) $(OPTS) $(THREADSAFE) $(USLEEP) -I. -I$(TOP)/src
# Object files for the SQLite library.
#
LIBOBJ+= attach.o auth.o btree.o build.o date.o delete.o \
LIBOBJ+= alter.o attach.o auth.o btree.o build.o date.o delete.o \
expr.o func.o hash.o insert.o \
main.o opcodes.o os_mac.o os_unix.o os_win.o \
main.o opcodes.o os_unix.o os_win.o \
pager.o parse.o pragma.o printf.o random.o \
select.o table.o tclsqlite.o tokenize.o trigger.o \
update.o util.o vacuum.o \
@ -66,6 +66,7 @@ LIBOBJ+= attach.o auth.o btree.o build.o date.o delete.o \
# All of the source code files.
#
SRC = \
$(TOP)/src/alter.c \
$(TOP)/src/attach.c \
$(TOP)/src/auth.c \
$(TOP)/src/btree.c \
@ -80,7 +81,6 @@ SRC = \
$(TOP)/src/insert.c \
$(TOP)/src/legacy.c \
$(TOP)/src/main.c \
$(TOP)/src/os_mac.c \
$(TOP)/src/os_unix.c \
$(TOP)/src/os_win.c \
$(TOP)/src/pager.c \
@ -113,8 +113,8 @@ SRC = \
#
TESTSRC = \
$(TOP)/src/btree.c \
$(TOP)/src/date.c \
$(TOP)/src/func.c \
$(TOP)/src/os_mac.c \
$(TOP)/src/os_unix.c \
$(TOP)/src/os_win.c \
$(TOP)/src/pager.c \
@ -140,7 +140,6 @@ HDR = \
opcodes.h \
$(TOP)/src/os.h \
$(TOP)/src/os_common.h \
$(TOP)/src/os_mac.h \
$(TOP)/src/os_unix.h \
$(TOP)/src/os_win.h \
$(TOP)/src/sqliteInt.h \
@ -181,12 +180,12 @@ objects: $(LIBOBJ_ORIG)
# files are automatically generated. This target takes care of
# all that automatic generation.
#
target_source: $(SRC) $(VDBEHDR) opcodes.c
target_source: $(SRC) $(VDBEHDR) opcodes.c keywordhash.h
rm -rf tsrc
mkdir tsrc
cp $(SRC) $(VDBEHDR) tsrc
rm tsrc/sqlite.h.in tsrc/parse.y
cp parse.c opcodes.c tsrc
cp parse.c opcodes.c keywordhash.h tsrc
cp $(TOP)/sqlite3.def tsrc
# Rules to build the LEMON compiler generator
@ -197,6 +196,9 @@ lemon: $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
# Rules to build individual files
#
alter.o: $(TOP)/src/alter.c $(HDR)
$(TCCX) -c $(TOP)/src/alter.c
attach.o: $(TOP)/src/attach.c $(HDR)
$(TCCX) -c $(TOP)/src/attach.c
@ -256,14 +258,11 @@ opcodes.o: opcodes.c
$(TCCX) -c opcodes.c
opcodes.c: opcodes.h $(TOP)/mkopcodec.awk
sort -n +2 opcodes.h | awk -f $(TOP)/mkopcodec.awk >opcodes.c
sort -n -b +2 opcodes.h | awk -f $(TOP)/mkopcodec.awk >opcodes.c
opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/mkopcodeh.awk
cat parse.h $(TOP)/src/vdbe.c | awk -f $(TOP)/mkopcodeh.awk >opcodes.h
os_mac.o: $(TOP)/src/os_mac.c $(HDR)
$(TCCX) -c $(TOP)/src/os_mac.c
os_unix.o: $(TOP)/src/os_unix.c $(HDR)
$(TCCX) -c $(TOP)/src/os_unix.c
@ -277,7 +276,7 @@ parse.h: parse.c
parse.c: $(TOP)/src/parse.y lemon
cp $(TOP)/src/parse.y .
./lemon parse.y
./lemon $(OPTS) parse.y
pragma.o: $(TOP)/src/pragma.c $(HDR)
$(TCCX) $(TCL_FLAGS) -c $(TOP)/src/pragma.c
@ -293,7 +292,7 @@ select.o: $(TOP)/src/select.c $(HDR)
sqlite3.h: $(TOP)/src/sqlite.h.in
sed -e s/--VERS--/`cat ${TOP}/VERSION`/ \
-e s/--ENCODING--/$(ENCODING)/ \
-e s/--VERSION-NUMBER--/`cat ${TOP}/VERSION | sed 's/[^0-9]/ /g' | awk '{printf "%d%03d%03d",$$1,$$2,$$3}'`/ \
$(TOP)/src/sqlite.h.in >sqlite3.h
table.o: $(TOP)/src/table.c $(HDR)
@ -302,9 +301,13 @@ table.o: $(TOP)/src/table.c $(HDR)
tclsqlite.o: $(TOP)/src/tclsqlite.c $(HDR)
$(TCCX) $(TCL_FLAGS) -c $(TOP)/src/tclsqlite.c
tokenize.o: $(TOP)/src/tokenize.c $(HDR)
tokenize.o: $(TOP)/src/tokenize.c keywordhash.h $(HDR)
$(TCCX) -c $(TOP)/src/tokenize.c
keywordhash.h: $(TOP)/tool/mkkeywordhash.c
$(BCC) -o mkkeywordhash $(OPTS) $(TOP)/tool/mkkeywordhash.c
./mkkeywordhash >keywordhash.h
trigger.o: $(TOP)/src/trigger.c $(HDR)
$(TCCX) -c $(TOP)/src/trigger.c
@ -367,7 +370,7 @@ sqlite3_analyzer$(EXE): $(TOP)/src/tclsqlite.c libsqlite3.a $(TESTSRC) \
-e 's,^,",' \
-e 's,$$,\\n",' \
$(TOP)/tool/spaceanal.tcl >spaceanal_tcl.h
$(TCCX) $(TCL_FLAGS) -DTCLSH=2 -DSQLITE_TEST=1 -static -o \
$(TCCX) $(TCL_FLAGS) -DTCLSH=2 -DSQLITE_TEST=1 -o \
sqlite3_analyzer$(EXE) $(TESTSRC) $(TOP)/src/tclsqlite.c \
libsqlite3.a $(LIBTCL) $(THREADLIB)
@ -379,6 +382,9 @@ arch.html: $(TOP)/www/arch.tcl
arch.png: $(TOP)/www/arch.png
cp $(TOP)/www/arch.png .
autoinc.html: $(TOP)/www/autoinc.tcl
tclsh $(TOP)/www/autoinc.tcl >autoinc.html
c_interface.html: $(TOP)/www/c_interface.tcl
tclsh $(TOP)/www/c_interface.tcl >c_interface.html
@ -391,6 +397,9 @@ capi3ref.html: $(TOP)/www/capi3ref.tcl
changes.html: $(TOP)/www/changes.tcl
tclsh $(TOP)/www/changes.tcl >changes.html
compile.html: $(TOP)/www/compile.tcl
tclsh $(TOP)/www/compile.tcl >compile.html
copyright.html: $(TOP)/www/copyright.tcl
tclsh $(TOP)/www/copyright.tcl >copyright.html
@ -432,7 +441,10 @@ index.html: $(TOP)/www/index.tcl last_change
tclsh $(TOP)/www/index.tcl >index.html
lang.html: $(TOP)/www/lang.tcl
tclsh $(TOP)/www/lang.tcl >lang.html
tclsh $(TOP)/www/lang.tcl doc >lang.html
pragma.html: $(TOP)/www/pragma.tcl
tclsh $(TOP)/www/pragma.tcl >pragma.html
lockingv3.html: $(TOP)/www/lockingv3.tcl
tclsh $(TOP)/www/lockingv3.tcl >lockingv3.html
@ -476,16 +488,21 @@ vdbe.html: $(TOP)/www/vdbe.tcl
version3.html: $(TOP)/www/version3.tcl
tclsh $(TOP)/www/version3.tcl >version3.html
whentouse.html: $(TOP)/www/whentouse.tcl
tclsh $(TOP)/www/whentouse.tcl >whentouse.html
# Files to be published on the website.
#
DOC = \
arch.html \
arch.png \
autoinc.html \
c_interface.html \
capi3.html \
capi3ref.html \
changes.html \
compile.html \
copyright.html \
copyright-release.html \
copyright-release.pdf \
@ -505,6 +522,7 @@ DOC = \
oldnews.html \
omitted.html \
opcode.html \
pragma.html \
quickstart.html \
speed.html \
sqlite.gif \
@ -512,7 +530,8 @@ DOC = \
support.html \
tclsqlite.html \
vdbe.html \
version3.html
version3.html \
whentouse.html
doc: common.tcl $(DOC)
mkdir -p doc
@ -527,7 +546,7 @@ install: sqlite3 libsqlite3.a sqlite3.h
clean:
rm -f *.o sqlite3 libsqlite3.a sqlite3.h opcodes.*
rm -f lemon lempar.c parse.* sqlite*.tar.gz
rm -f lemon lempar.c parse.* sqlite*.tar.gz mkkeywordhash keywordhash.h
rm -f $(PUBLISH)
rm -f *.da *.bb *.bbg gmon.out
rm -rf tsrc

View File

@ -10,13 +10,19 @@
#
BEGIN {
print "/* Automatically generated. Do not edit */"
print "/* See the mkopcodec.h script for details. */"
print "/* See the mkopcodec.awk script for details. */"
printf "#if !defined(SQLITE_OMIT_EXPLAIN)"
printf " || !defined(NDEBUG)"
printf " || defined(VDBE_PROFILE)"
print " || defined(SQLITE_DEBUG)"
print "const char *const sqlite3OpcodeNames[] = { \"?\","
}
/^#define OP_/ {
/define OP_/ {
sub("OP_","",$2)
print " \"" $2 "\","
i++
printf " /* %3d */ \"%s\",\n", $3, $2
}
END {
print "};"
print "#endif"
}

View File

@ -1,5 +1,7 @@
#!/usr/bin/awk -f
#
# Generate the file opcodes.h.
#
# This AWK script scans a concatenation of the parse.h output file from the
# parser and the vdbe.c source file in order to generate the opcodes numbers
# for all opcodes.
@ -12,6 +14,15 @@
# the OP_ is the same as the TK_ value. If missing, the OP_ value is assigned
# a small integer that is different from every other OP_ value.
#
# We go to the trouble of making some OP_ value the same as TK_ values
# as an optimization. During parsing, things like expression operators
# are coded with TK_ values such as TK_ADD, TK_DIVIDE, and so forth. Later
# during code generation, we need to generate corresponding opcodes like
# OP_Add and OP_Divide. By making TK_ADD==OP_Add and TK_DIVIDE==OP_Divide,
# code to translation from one to the other is avoided. This makes the
# code generator run (infinitesimally) faster and more importantly it makes
# the total library smaller.
#
# Remember the TK_ values from the parse.h file
/^#define TK_/ {
@ -28,6 +39,7 @@
if($i=="same" && $(i+1)=="as"){
op[name] = tk[$(i+2)]
used[op[name]] = 1
sameas[op[name]] = $(i+2)
}
}
}
@ -35,6 +47,7 @@
# Assign numbers to all opcodes and output the result.
END {
cnt = 0
max = 0
print "/* Automatically generated. Do not edit */"
print "/* See the mkopcodeh.awk script for details */"
for(name in op){
@ -43,6 +56,23 @@ END {
while( used[cnt] ) cnt++
op[name] = cnt
}
printf "#define %-30s %d\n", name, op[name]
used[op[name]] = 1;
if( op[name]>max ) max = op[name]
printf "#define %-25s %15d", name, op[name]
if( sameas[op[name]] ) {
printf " /* same as %-12s*/", sameas[op[name]]
}
printf "\n"
}
seenUnused = 0;
for(i=1; i<max; i++){
if( !used[i] ){
if( !seenUnused ){
printf "\n/* The following opcode values are never used */\n"
seenUnused = 1
}
printf "#define %-25s %15d\n", sprintf( "OP_NotUsed_%-3d", i ), i
}
}
}

View File

@ -13,9 +13,11 @@ TCLDIR=/home/drh/tcltk/846/linux/846linux
TCLSTUBLIB=$TCLDIR/libtclstub8.4g.a
OPTS='-DUSE_TCL_STUBS=1 -DNDEBUG=1'
for i in *.c; do
CMD="cc -fPIC $OPTS -O2 -I. -I$TCLDIR -c $i"
echo $CMD
$CMD
if test $i != 'keywordhash.c'; then
CMD="cc -fPIC $OPTS -O2 -I. -I$TCLDIR -c $i"
echo $CMD
$CMD
fi
done
echo gcc -shared *.o $TCLSTUBLIB -o tclsqlite3.so
gcc -shared *.o $TCLSTUBLIB -o tclsqlite3.so

View File

@ -75,8 +75,10 @@ cd ..
ORIGIN=`pwd`
cd $srcdir
cd ..
EXCLUDE=`find sqlite -print | grep CVS | sed 's,^, --exclude ,'`
tar czf $ORIGIN/doc/sqlite-$VERS.tar.gz $EXCLUDE sqlite
mv sqlite sqlite-$VERS
EXCLUDE=`find sqlite-$VERS -print | grep CVS | sed 's,^, --exclude ,'`
tar czf $ORIGIN/doc/sqlite-$VERS.tar.gz $EXCLUDE sqlite-$VERS
mv sqlite-$VERS sqlite
cd $ORIGIN
#

View File

@ -0,0 +1,334 @@
/*
** 2005 February 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that used to generate VDBE code
** that implements the ALTER TABLE command.
**
** $Id$
*/
#include "sqliteInt.h"
/*
** The code in this file only exists if we are not omitting the
** ALTER TABLE logic from the build.
*/
#ifndef SQLITE_OMIT_ALTERTABLE
/*
** This function is used by SQL generated to implement the
** ALTER TABLE command. The first argument is the text of a CREATE TABLE or
** CREATE INDEX command. The second is a table name. The table name in
** the CREATE TABLE or CREATE INDEX statement is replaced with the second
** argument and the result returned. Examples:
**
** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def')
** -> 'CREATE TABLE def(a, b, c)'
**
** sqlite_rename_table('CREATE INDEX i ON abc(a)', 'def')
** -> 'CREATE INDEX i ON def(a, b, c)'
*/
static void renameTableFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
unsigned char const *zSql = sqlite3_value_text(argv[0]);
unsigned char const *zTableName = sqlite3_value_text(argv[1]);
int token;
Token tname;
char const *zCsr = zSql;
int len = 0;
char *zRet;
/* The principle used to locate the table name in the CREATE TABLE
** statement is that the table name is the first token that is immediatedly
** followed by a left parenthesis - TK_LP.
*/
if( zSql ){
do {
/* Store the token that zCsr points to in tname. */
tname.z = zCsr;
tname.n = len;
/* Advance zCsr to the next token. Store that token type in 'token',
** and it's length in 'len' (to be used next iteration of this loop).
*/
do {
zCsr += len;
len = sqlite3GetToken(zCsr, &token);
} while( token==TK_SPACE );
assert( len>0 );
} while( token!=TK_LP );
zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql,
zTableName, tname.z+tname.n);
sqlite3_result_text(context, zRet, -1, sqlite3FreeX);
}
}
#ifndef SQLITE_OMIT_TRIGGER
/* This function is used by SQL generated to implement the ALTER TABLE
** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER
** statement. The second is a table name. The table name in the CREATE
** TRIGGER statement is replaced with the second argument and the result
** returned. This is analagous to renameTableFunc() above, except for CREATE
** TRIGGER, not CREATE INDEX and CREATE TABLE.
*/
static void renameTriggerFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
unsigned char const *zSql = sqlite3_value_text(argv[0]);
unsigned char const *zTableName = sqlite3_value_text(argv[1]);
int token;
Token tname;
int dist = 3;
char const *zCsr = zSql;
int len = 0;
char *zRet;
/* The principle used to locate the table name in the CREATE TRIGGER
** statement is that the table name is the first token that is immediatedly
** preceded by either TK_ON or TK_DOT and immediatedly followed by one
** of TK_WHEN, TK_BEGIN or TK_FOR.
*/
if( zSql ){
do {
/* Store the token that zCsr points to in tname. */
tname.z = zCsr;
tname.n = len;
/* Advance zCsr to the next token. Store that token type in 'token',
** and it's length in 'len' (to be used next iteration of this loop).
*/
do {
zCsr += len;
len = sqlite3GetToken(zCsr, &token);
}while( token==TK_SPACE );
assert( len>0 );
/* Variable 'dist' stores the number of tokens read since the most
** recent TK_DOT or TK_ON. This means that when a WHEN, FOR or BEGIN
** token is read and 'dist' equals 2, the condition stated above
** to be met.
**
** Note that ON cannot be a database, table or column name, so
** there is no need to worry about syntax like
** "CREATE TRIGGER ... ON ON.ON BEGIN ..." etc.
*/
dist++;
if( token==TK_DOT || token==TK_ON ){
dist = 0;
}
} while( dist!=2 || (token!=TK_WHEN && token!=TK_FOR && token!=TK_BEGIN) );
/* Variable tname now contains the token that is the old table-name
** in the CREATE TRIGGER statement.
*/
zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql,
zTableName, tname.z+tname.n);
sqlite3_result_text(context, zRet, -1, sqlite3FreeX);
}
}
#endif /* !SQLITE_OMIT_TRIGGER */
/*
** Register built-in functions used to help implement ALTER TABLE
*/
void sqlite3AlterFunctions(sqlite3 *db){
static const struct {
char *zName;
signed char nArg;
void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
} aFuncs[] = {
{ "sqlite_rename_table", 2, renameTableFunc},
#ifndef SQLITE_OMIT_TRIGGER
{ "sqlite_rename_trigger", 2, renameTriggerFunc},
#endif
};
int i;
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
}
}
/*
** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy"
** command.
*/
void sqlite3AlterRenameTable(
Parse *pParse, /* Parser context. */
SrcList *pSrc, /* The table to rename. */
Token *pName /* The new table name. */
){
int iDb; /* Database that contains the table */
char *zDb; /* Name of database iDb */
Table *pTab; /* Table being renamed */
char *zName = 0; /* NULL-terminated version of pName */
char *zWhere = 0; /* Where clause of schema elements to reparse */
sqlite3 *db = pParse->db; /* Database connection */
Vdbe *v;
#ifndef SQLITE_OMIT_TRIGGER
char *zTempTrig = 0; /* Where clause to locate temp triggers */
#endif
assert( pSrc->nSrc==1 );
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
if( !pTab ) goto exit_rename_table;
iDb = pTab->iDb;
zDb = db->aDb[iDb].zName;
/* Get a NULL terminated version of the new table name. */
zName = sqlite3NameFromToken(pName);
if( !zName ) goto exit_rename_table;
/* Check that a table or index named 'zName' does not already exist
** in database iDb. If so, this is an error.
*/
if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){
sqlite3ErrorMsg(pParse,
"there is already another table or index with this name: %s", zName);
goto exit_rename_table;
}
/* Make sure it is not a system table being altered, or a reserved name
** that the table is being renamed to.
*/
if( strlen(pTab->zName)>6 && 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) ){
sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName);
goto exit_rename_table;
}
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
goto exit_rename_table;
}
#ifndef SQLITE_OMIT_AUTHORIZATION
/* Invoke the authorization callback. */
if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){
goto exit_rename_table;
}
#endif
/* Begin a transaction and code the VerifyCookie for database iDb.
** Then modify the schema cookie (since the ALTER TABLE modifies the
** schema).
*/
v = sqlite3GetVdbe(pParse);
if( v==0 ){
goto exit_rename_table;
}
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3ChangeCookie(db, v, iDb);
/* Modify the sqlite_master table to use the new table name. */
sqlite3NestedParse(pParse,
"UPDATE %Q.%s SET "
#ifdef SQLITE_OMIT_TRIGGER
"sql = sqlite_rename_table(sql, %Q), "
#else
"sql = CASE "
"WHEN type = 'trigger' THEN sqlite_rename_trigger(sql, %Q)"
"ELSE sqlite_rename_table(sql, %Q) END, "
#endif
"tbl_name = %Q, "
"name = CASE "
"WHEN type='table' THEN %Q "
"WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN "
"'sqlite_autoindex_' || %Q || substr(name, %d+18,10) "
"ELSE name END "
"WHERE tbl_name=%Q AND "
"(type='table' OR type='index' OR type='trigger');",
zDb, SCHEMA_TABLE(iDb), zName, zName, zName,
#ifndef SQLITE_OMIT_TRIGGER
zName,
#endif
zName, strlen(pTab->zName), pTab->zName
);
#ifndef SQLITE_OMIT_AUTOINCREMENT
/* If the sqlite_sequence table exists in this database, then update
** it with the new table name.
*/
if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){
sqlite3NestedParse(pParse,
"UPDATE %Q.sqlite_sequence set name = %Q WHERE name = %Q",
zDb, zName, pTab->zName);
}
#endif
#ifndef SQLITE_OMIT_TRIGGER
/* If there are TEMP triggers on this table, modify the sqlite_temp_master
** table. Don't do this if the table being ALTERed is itself located in
** the temp database.
*/
if( iDb!=1 ){
Trigger *pTrig;
char *tmp = 0;
for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
if( pTrig->iDb==1 ){
if( !zTempTrig ){
zTempTrig =
sqlite3MPrintf("type = 'trigger' AND (name=%Q", pTrig->name);
}else{
tmp = zTempTrig;
zTempTrig = sqlite3MPrintf("%s OR name=%Q", zTempTrig, pTrig->name);
sqliteFree(tmp);
}
}
}
if( zTempTrig ){
tmp = zTempTrig;
zTempTrig = sqlite3MPrintf("%s)", zTempTrig);
sqliteFree(tmp);
sqlite3NestedParse(pParse,
"UPDATE sqlite_temp_master SET "
"sql = sqlite_rename_trigger(sql, %Q), "
"tbl_name = %Q "
"WHERE %s;", zName, zName, zTempTrig);
}
}
#endif
/* Drop the elements of the in-memory schema that refered to the table
** renamed and load the new versions from the database.
*/
if( pParse->nErr==0 ){
#ifndef SQLITE_OMIT_TRIGGER
Trigger *pTrig;
for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
assert( pTrig->iDb==iDb || pTrig->iDb==1 );
sqlite3VdbeOp3(v, OP_DropTrigger, pTrig->iDb, 0, pTrig->name, 0);
}
#endif
sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0);
zWhere = sqlite3MPrintf("tbl_name=%Q", zName);
sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC);
#ifndef SQLITE_OMIT_TRIGGER
if( zTempTrig ){
sqlite3VdbeOp3(v, OP_ParseSchema, 1, 0, zTempTrig, P3_DYNAMIC);
}
}else{
sqliteFree(zTempTrig);
#endif
}
exit_rename_table:
sqlite3SrcListDelete(pSrc);
sqliteFree(zName);
}
#endif /* SQLITE_ALTER_TABLE */

View File

@ -38,6 +38,7 @@ void sqlite3Attach(
v = sqlite3GetVdbe(pParse);
if( !v ) return;
sqlite3VdbeAddOp(v, OP_Expire, 1, 0);
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
if( pParse->explain ) return;
db = pParse->db;
@ -160,6 +161,7 @@ void sqlite3Detach(Parse *pParse, Token *pDbname){
v = sqlite3GetVdbe(pParse);
if( !v ) return;
sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
if( pParse->explain ) return;
db = pParse->db;
@ -251,11 +253,14 @@ int sqlite3FixSrcList(
pFix->zType, pFix->pName, pItem->zDatabase);
return 1;
}
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
#endif
}
return 0;
}
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
int sqlite3FixSelect(
DbFixer *pFix, /* Context of the fixation */
Select *pSelect /* The SELECT statement to be fixed to one database */
@ -309,6 +314,9 @@ int sqlite3FixExprList(
}
return 0;
}
#endif
#ifndef SQLITE_OMIT_TRIGGER
int sqlite3FixTriggerStep(
DbFixer *pFix, /* Context of the fixation */
TriggerStep *pStep /* The trigger step be fixed to one database */
@ -327,3 +335,4 @@ int sqlite3FixTriggerStep(
}
return 0;
}
#endif

View File

@ -76,6 +76,7 @@ int sqlite3_set_authorizer(
){
db->xAuth = xAuth;
db->pAuthArg = pArg;
sqlite3ExpirePreparedStatements(db);
return SQLITE_OK;
}
@ -114,10 +115,10 @@ void sqlite3AuthRead(
if( db->xAuth==0 ) return;
assert( pExpr->op==TK_COLUMN );
for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
for(iSrc=0; pTabList && iSrc<pTabList->nSrc; iSrc++){
if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break;
}
if( iSrc>=0 && iSrc<pTabList->nSrc ){
if( iSrc>=0 && pTabList && iSrc<pTabList->nSrc ){
pTab = pTabList->a[iSrc].pTab;
}else if( (pStack = pParse->trigStack)!=0 ){
/* This must be an attempt to read the NEW or OLD pseudo-tables

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,14 @@
*/
#define SQLITE_N_BTREE_META 10
/*
** If defined as non-zero, auto-vacuum is enabled by default. Otherwise
** it must be turned on for each database using "PRAGMA auto_vacuum = 1".
*/
#ifndef SQLITE_DEFAULT_AUTOVACUUM
#define SQLITE_DEFAULT_AUTOVACUUM 0
#endif
/*
** Forward declarations of structure
*/
@ -38,9 +46,13 @@ int sqlite3BtreeOpen(
/* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the
** following values.
**
** NOTE: These values must match the corresponding PAGER_ values in
** pager.h.
*/
#define BTREE_OMIT_JOURNAL 1 /* Do not use journal. No argument */
#define BTREE_MEMORY 2 /* In-memory DB. No argument */
#define BTREE_NO_READLOCK 2 /* Omit readlocks on readonly files */
#define BTREE_MEMORY 4 /* In-memory DB. No argument */
int sqlite3BtreeClose(Btree*);
int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*);
@ -49,6 +61,8 @@ int sqlite3BtreeSetSafetyLevel(Btree*,int);
int sqlite3BtreeSetPageSize(Btree*,int,int);
int sqlite3BtreeGetPageSize(Btree*);
int sqlite3BtreeGetReserve(Btree*);
int sqlite3BtreeSetAutoVacuum(Btree *, int);
int sqlite3BtreeGetAutoVacuum(Btree *);
int sqlite3BtreeBeginTrans(Btree*,int);
int sqlite3BtreeCommit(Btree*);
int sqlite3BtreeRollback(Btree*);
@ -72,7 +86,7 @@ int sqlite3BtreeCopyFile(Btree *, Btree *);
#define BTREE_ZERODATA 2 /* Table has keys only - no data */
#define BTREE_LEAFDATA 4 /* Data stored in leaves only. Implies INTKEY */
int sqlite3BtreeDropTable(Btree*, int);
int sqlite3BtreeDropTable(Btree*, int, int*);
int sqlite3BtreeClearTable(Btree*, int);
int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue);
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
@ -117,8 +131,12 @@ struct Pager *sqlite3BtreePager(Btree*);
#ifdef SQLITE_TEST
int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
void sqlite3BtreeCursorList(Btree*);
int sqlite3BtreePageDump(Btree*, int, int recursive);
#endif
#ifdef SQLITE_DEBUG
int sqlite3BtreePageDump(Btree*, int, int recursive);
#else
#define sqlite3BtreePageDump(X,Y,Z) SQLITE_OK
#endif
#endif /* _BTREE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -315,12 +315,10 @@ static int parseDateOrTime(const char *zDate, DateTime *p){
return 0;
}else if( sqlite3StrICmp(zDate,"now")==0){
double r;
if( sqlite3OsCurrentTime(&r)==0 ){
p->rJD = r;
p->validJD = 1;
return 0;
}
return 1;
sqlite3OsCurrentTime(&r);
p->rJD = r;
p->validJD = 1;
return 0;
}else if( sqlite3IsNumber(zDate, 0, SQLITE_UTF8) ){
p->rJD = sqlite3AtoF(zDate, 0);
p->validJD = 1;
@ -862,9 +860,100 @@ static void strftimeFunc(
}
}
/*
** current_time()
**
** This function returns the same value as time('now').
*/
static void ctimeFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
sqlite3_value *pVal = sqlite3ValueNew();
if( pVal ){
sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC);
timeFunc(context, 1, &pVal);
sqlite3ValueFree(pVal);
}
}
/*
** current_date()
**
** This function returns the same value as date('now').
*/
static void cdateFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
sqlite3_value *pVal = sqlite3ValueNew();
if( pVal ){
sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC);
dateFunc(context, 1, &pVal);
sqlite3ValueFree(pVal);
}
}
/*
** current_timestamp()
**
** This function returns the same value as datetime('now').
*/
static void ctimestampFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
sqlite3_value *pVal = sqlite3ValueNew();
if( pVal ){
sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC);
datetimeFunc(context, 1, &pVal);
sqlite3ValueFree(pVal);
}
}
#endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */
#ifdef SQLITE_OMIT_DATETIME_FUNCS
/*
** If the library is compiled to omit the full-scale date and time
** handling (to get a smaller binary), the following minimal version
** of the functions current_time(), current_date() and current_timestamp()
** are included instead. This is to support column declarations that
** include "DEFAULT CURRENT_TIME" etc.
**
** This function uses the C-library functions time(), gmtime()
** and strftime(). The format string to pass to strftime() is supplied
** as the user-data for the function.
*/
static void currentTimeFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
time_t t;
char *zFormat = (char *)sqlite3_user_data(context);
char zBuf[20];
time(&t);
#ifdef SQLITE_TEST
{
extern int sqlite3_current_time; /* See os_XXX.c */
if( sqlite3_current_time ){
t = sqlite3_current_time;
}
}
#endif
sqlite3OsEnterMutex();
strftime(zBuf, 20, zFormat, gmtime(&t));
sqlite3OsLeaveMutex();
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}
#endif
/*
** This function registered all of the above C functions as SQL
** functions. This should be the only routine in this file with
@ -882,6 +971,9 @@ void sqlite3RegisterDateTimeFunctions(sqlite3 *db){
{ "time", -1, timeFunc },
{ "datetime", -1, datetimeFunc },
{ "strftime", -1, strftimeFunc },
{ "current_time", 0, ctimeFunc },
{ "current_timestamp", 0, ctimestampFunc },
{ "current_date", 0, cdateFunc },
};
int i;
@ -889,5 +981,20 @@ void sqlite3RegisterDateTimeFunctions(sqlite3 *db){
sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
}
#else
static const struct {
char *zName;
char *zFormat;
} aFuncs[] = {
{ "current_time", "%H:%M:%S" },
{ "current_date", "%Y-%m-%d" },
{ "current_timestamp", "%Y-%m-%d %H:%M:%S" }
};
int i;
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
sqlite3_create_function(db, aFuncs[i].zName, 0, SQLITE_UTF8,
aFuncs[i].zFormat, currentTimeFunc, 0, 0);
}
#endif
}

View File

@ -10,7 +10,7 @@
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
** in order to generate code for DELETE FROM statements.
**
** $Id$
*/
@ -38,14 +38,17 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
** writable return 0;
*/
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
if( pTab->readOnly ){
if( pTab->readOnly && (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);
return 1;
}
#endif
return 0;
}
@ -65,7 +68,11 @@ void sqlite3OpenTableForReading(
/*
** Process a DELETE FROM statement.
** Generate code for a DELETE FROM statement.
**
** DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL;
** \________/ \________________/
** pTabList pWhere
*/
void sqlite3DeleteFrom(
Parse *pParse, /* The parser context */
@ -81,13 +88,14 @@ void sqlite3DeleteFrom(
Index *pIdx; /* For looping over indices of the table */
int iCur; /* VDBE Cursor number for pTab */
sqlite3 *db; /* Main database structure */
int isView; /* True if attempting to delete from a view */
AuthContext sContext; /* Authorization context */
int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */
NameContext sNC; /* Name context to resolve expressions in */
int row_triggers_exist = 0; /* True if any triggers exist */
int before_triggers; /* True if there are BEFORE triggers */
int after_triggers; /* True if there are AFTER triggers */
int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to delete from a view */
int triggers_exist = 0; /* True if any triggers exist */
#endif
sContext.pParse = 0;
if( pParse->nErr || sqlite3_malloc_failed ){
@ -104,13 +112,23 @@ void sqlite3DeleteFrom(
*/
pTab = sqlite3SrcListLookup(pParse, pTabList);
if( pTab==0 ) goto delete_from_cleanup;
before_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
TK_DELETE, TK_BEFORE, TK_ROW, 0);
after_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
TK_DELETE, TK_AFTER, TK_ROW, 0);
row_triggers_exist = before_triggers || after_triggers;
/* Figure out if we have any triggers and if the table being
** deleted from is a view
*/
#ifndef SQLITE_OMIT_TRIGGER
triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0);
isView = pTab->pSelect!=0;
if( sqlite3IsReadOnly(pParse, pTab, before_triggers) ){
#else
# define triggers_exist 0
# define isView 0
#endif
#ifdef SQLITE_OMIT_VIEW
# undef isView
# define isView 0
#endif
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
goto delete_from_cleanup;
}
assert( pTab->iDb<db->nDb );
@ -127,15 +145,18 @@ void sqlite3DeleteFrom(
/* Allocate a cursor used to store the old.* data for a trigger.
*/
if( row_triggers_exist ){
if( triggers_exist ){
oldIdx = pParse->nTab++;
}
/* Resolve the column names in all the expressions.
/* Resolve the column names in the WHERE clause.
*/
assert( pTabList->nSrc==1 );
iCur = pTabList->a[0].iCursor = pParse->nTab++;
if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
if( sqlite3ExprResolveNames(&sNC, pWhere) ){
goto delete_from_cleanup;
}
@ -151,8 +172,8 @@ void sqlite3DeleteFrom(
if( v==0 ){
goto delete_from_cleanup;
}
sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, row_triggers_exist, pTab->iDb);
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, triggers_exist, pTab->iDb);
/* If we are trying to delete from a view, construct that view into
** a temporary table.
@ -174,7 +195,7 @@ void sqlite3DeleteFrom(
** It is easier just to erase the whole table. Note, however, that
** this means that the row change count will be incorrect.
*/
if( pWhere==0 && !row_triggers_exist ){
if( pWhere==0 && !triggers_exist ){
if( db->flags & SQLITE_CountRows ){
/* If counting rows deleted, just count the total number of
** entries in the table. */
@ -210,11 +231,12 @@ void sqlite3DeleteFrom(
/* Begin the database scan
*/
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0);
if( pWInfo==0 ) goto delete_from_cleanup;
/* Remember the key of every item to be deleted.
/* Remember the rowid of every item to be deleted.
*/
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
@ -226,7 +248,7 @@ void sqlite3DeleteFrom(
/* Open the pseudo-table used to store OLD if there are triggers.
*/
if( row_triggers_exist ){
if( triggers_exist ){
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
}
@ -241,7 +263,7 @@ void sqlite3DeleteFrom(
/* This is the beginning of the delete loop when there are
** row triggers.
*/
if( row_triggers_exist ){
if( triggers_exist ){
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
if( !isView ){
@ -255,8 +277,8 @@ void sqlite3DeleteFrom(
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1,
oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_BEFORE, pTab,
-1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
addr);
}
@ -271,25 +293,25 @@ void sqlite3DeleteFrom(
/* This is the beginning of the delete loop when there are no
** row triggers */
if( !row_triggers_exist ){
if( !triggers_exist ){
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
}
/* Delete the row */
sqlite3GenerateRowDelete(db, v, pTab, iCur, 1);
sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0);
}
/* If there are row triggers, close all cursors then invoke
** the AFTER triggers
*/
if( row_triggers_exist ){
if( triggers_exist ){
if( !isView ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
}
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1,
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1,
oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
addr);
}
@ -300,7 +322,7 @@ void sqlite3DeleteFrom(
sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
/* Close the cursors after the loop if there are no row triggers */
if( !row_triggers_exist ){
if( !triggers_exist ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
}
@ -309,9 +331,11 @@ void sqlite3DeleteFrom(
}
/*
** Return the number of rows that were deleted.
** Return the number of rows that were deleted. If this routine is
** generating code because of a call to sqlite3NestedParse(), do not
** invoke the callback function.
*/
if( db->flags & SQLITE_CountRows ){
if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, "rows deleted", P3_STATIC);

View File

@ -0,0 +1,38 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
** $Id$
*/
#include "sqliteInt.h"
/*
** Set all the parameters in the compiled SQL statement to NULL.
*/
int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
int i;
int rc = SQLITE_OK;
for(i=1; rc==SQLITE_OK && i<=sqlite3_bind_parameter_count(pStmt); i++){
rc = sqlite3_bind_null(pStmt, i);
}
return rc;
}
/*
** Sleep for a little while. Return the amount of time slept.
*/
int sqlite3_sleep(int ms){
return sqlite3OsSleep(ms);
}

File diff suppressed because it is too large Load Diff

View File

@ -18,11 +18,11 @@
**
** $Id$
*/
#include "sqliteInt.h"
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include "sqliteInt.h"
#include "vdbeInt.h"
#include "os.h"
@ -347,10 +347,11 @@ static const struct compareInfo likeInfo = { '%', '_', 0, 1 };
**
** abc[*]xyz Matches "abc*xyz" only
*/
int patternCompare(
static int patternCompare(
const u8 *zPattern, /* The glob pattern */
const u8 *zString, /* The string to compare against the glob */
const struct compareInfo *pInfo /* Information about how to do the compare */
const struct compareInfo *pInfo, /* Information about how to do the compare */
const int esc /* The escape character */
){
register int c;
int invert;
@ -360,9 +361,10 @@ int patternCompare(
u8 matchAll = pInfo->matchAll;
u8 matchSet = pInfo->matchSet;
u8 noCase = pInfo->noCase;
int prevEscape = 0; /* True if the previous character was 'escape' */
while( (c = *zPattern)!=0 ){
if( c==matchAll ){
if( !prevEscape && c==matchAll ){
while( (c=zPattern[1]) == matchAll || c == matchOne ){
if( c==matchOne ){
if( *zString==0 ) return 0;
@ -370,9 +372,15 @@ int patternCompare(
}
zPattern++;
}
if( c && esc && sqlite3ReadUtf8(&zPattern[1])==esc ){
u8 const *zTemp = &zPattern[1];
sqliteNextChar(zTemp);
c = *zTemp;
}
if( c==0 ) return 1;
if( c==matchSet ){
while( *zString && patternCompare(&zPattern[1],zString,pInfo)==0 ){
assert( esc==0 ); /* This is GLOB, not LIKE */
while( *zString && patternCompare(&zPattern[1],zString,pInfo,esc)==0 ){
sqliteNextChar(zString);
}
return *zString!=0;
@ -386,17 +394,18 @@ int patternCompare(
while( c2 != 0 && c2 != c ){ c2 = *++zString; }
}
if( c2==0 ) return 0;
if( patternCompare(&zPattern[1],zString,pInfo) ) return 1;
if( patternCompare(&zPattern[1],zString,pInfo,esc) ) return 1;
sqliteNextChar(zString);
}
return 0;
}
}else if( c==matchOne ){
}else if( !prevEscape && c==matchOne ){
if( *zString==0 ) return 0;
sqliteNextChar(zString);
zPattern++;
}else if( c==matchSet ){
int prior_c = 0;
assert( esc==0 ); /* This only occurs for GLOB, not LIKE */
seen = 0;
invert = 0;
c = sqliteCharVal(zString);
@ -424,6 +433,9 @@ int patternCompare(
if( c2==0 || (seen ^ invert)==0 ) return 0;
sqliteNextChar(zString);
zPattern++;
}else if( esc && !prevEscape && sqlite3ReadUtf8(zPattern)==esc){
prevEscape = 1;
sqliteNextChar(zPattern);
}else{
if( noCase ){
if( sqlite3UpperToLower[c] != sqlite3UpperToLower[*zString] ) return 0;
@ -432,6 +444,7 @@ int patternCompare(
}
zPattern++;
zString++;
prevEscape = 0;
}
}
return *zString==0;
@ -457,8 +470,21 @@ static void likeFunc(
){
const unsigned char *zA = sqlite3_value_text(argv[0]);
const unsigned char *zB = sqlite3_value_text(argv[1]);
int escape = 0;
if( argc==3 ){
/* The escape character string must consist of a single UTF-8 character.
** Otherwise, return an error.
*/
const unsigned char *zEsc = sqlite3_value_text(argv[2]);
if( sqlite3utf8CharLen(zEsc, -1)!=1 ){
sqlite3_result_error(context,
"ESCAPE expression must be a single character", -1);
return;
}
escape = sqlite3ReadUtf8(zEsc);
}
if( zA && zB ){
sqlite3_result_int(context, patternCompare(zA, zB, &likeInfo));
sqlite3_result_int(context, patternCompare(zA, zB, &likeInfo, escape));
}
}
@ -469,13 +495,13 @@ static void likeFunc(
**
** A GLOB B
**
** is implemented as glob(A,B).
** is implemented as glob(B,A).
*/
static void globFunc(sqlite3_context *context, int arg, sqlite3_value **argv){
const unsigned char *zA = sqlite3_value_text(argv[0]);
const unsigned char *zB = sqlite3_value_text(argv[1]);
if( zA && zB ){
sqlite3_result_int(context, patternCompare(zA, zB, &globInfo));
sqlite3_result_int(context, patternCompare(zA, zB, &globInfo, 0));
}
}
@ -507,6 +533,7 @@ static void versionFunc(
sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
}
/*
** EXPERIMENTAL - This is not an official function. The interface may
** change. This function may disappear. Do not write code that depends
@ -704,10 +731,12 @@ static void test_destructor(
memcpy(zVal, sqlite3ValueText(argv[0], db->enc), len);
if( db->enc==SQLITE_UTF8 ){
sqlite3_result_text(pCtx, zVal, -1, destructor);
#ifndef SQLITE_OMIT_UTF16
}else if( db->enc==SQLITE_UTF16LE ){
sqlite3_result_text16le(pCtx, zVal, -1, destructor);
}else{
sqlite3_result_text16be(pCtx, zVal, -1, destructor);
#endif /* SQLITE_OMIT_UTF16 */
}
}
static void test_destructor_count(
@ -762,6 +791,20 @@ static void test_auxdata(
}
#endif /* SQLITE_TEST */
#ifdef SQLITE_TEST
/*
** A function to test error reporting from user functions. This function
** returns a copy of it's first argument as an error.
*/
static void test_error(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **argv
){
sqlite3_result_error(pCtx, sqlite3_value_text(argv[0]), 0);
}
#endif /* SQLITE_TEST */
/*
** An instance of the following structure holds the context of a
** sum() or avg() aggregate computation.
@ -808,33 +851,6 @@ struct StdDevCtx {
int cnt; /* Number of terms counted */
};
#if 0 /* Omit because math library is required */
/*
** Routines used to compute the standard deviation as an aggregate.
*/
static void stdDevStep(sqlite3_context *context, int argc, const char **argv){
StdDevCtx *p;
double x;
if( argc<1 ) return;
p = sqlite3_aggregate_context(context, sizeof(*p));
if( p && argv[0] ){
x = sqlite3AtoF(argv[0], 0);
p->sum += x;
p->sum2 += x*x;
p->cnt++;
}
}
static void stdDevFinalize(sqlite3_context *context){
double rN = sqlite3_aggregate_count(context);
StdDevCtx *p = sqlite3_aggregate_context(context, sizeof(*p));
if( p && p->cnt>1 ){
double rCnt = cnt;
sqlite3_set_result_double(context,
sqrt((p->sum2 - p->sum*p->sum/rCnt)/(rCnt-1.0)));
}
}
#endif
/*
** The following structure keeps track of state information for the
** count() aggregate function.
@ -933,7 +949,9 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
{ "typeof", 1, 0, SQLITE_UTF8, 0, typeofFunc },
{ "length", 1, 0, SQLITE_UTF8, 0, lengthFunc },
{ "substr", 3, 0, SQLITE_UTF8, 0, substrFunc },
#ifndef SQLITE_OMIT_UTF16
{ "substr", 3, 0, SQLITE_UTF16LE, 0, sqlite3utf16Substr },
#endif
{ "abs", 1, 0, SQLITE_UTF8, 0, absFunc },
{ "round", 1, 0, SQLITE_UTF8, 0, roundFunc },
{ "round", 2, 0, SQLITE_UTF8, 0, roundFunc },
@ -945,6 +963,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
{ "ifnull", 2, 0, SQLITE_UTF8, 1, ifnullFunc },
{ "random", -1, 0, SQLITE_UTF8, 0, randomFunc },
{ "like", 2, 0, SQLITE_UTF8, 0, likeFunc },
{ "like", 3, 0, SQLITE_UTF8, 0, likeFunc },
{ "glob", 2, 0, SQLITE_UTF8, 0, globFunc },
{ "nullif", 2, 0, SQLITE_UTF8, 1, nullifFunc },
{ "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc},
@ -960,6 +979,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
{ "test_destructor", 1, 1, SQLITE_UTF8, 0, test_destructor},
{ "test_destructor_count", 0, 0, SQLITE_UTF8, 0, test_destructor_count},
{ "test_auxdata", -1, 0, SQLITE_UTF8, 0, test_auxdata},
{ "test_error", 1, 0, SQLITE_UTF8, 0, test_error},
#endif
};
static const struct {
@ -976,9 +996,6 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
{ "avg", 1, 0, 0, sumStep, avgFinalize },
{ "count", 0, 0, 0, countStep, countFinalize },
{ "count", 1, 0, 0, countStep, countFinalize },
#if 0
{ "stddev", 1, 0, stdDevStep, stdDevFinalize },
#endif
};
int i;
@ -998,6 +1015,9 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
}
}
}
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions(db);
#endif
for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
void *pArg = 0;
switch( aAggs[i].argType ){

View File

@ -98,7 +98,14 @@ static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){
** Hash and comparison functions when the mode is SQLITE_HASH_STRING
*/
static int strHash(const void *pKey, int nKey){
return sqlite3HashNoCase((const char*)pKey, nKey);
const char *z = (const char *)pKey;
int h = 0;
if( nKey<=0 ) nKey = strlen(z);
while( nKey > 0 ){
h = (h<<3) ^ h ^ sqlite3UpperToLower[(unsigned char)*z++];
nKey--;
}
return h & 0x7fffffff;
}
static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){
if( n1!=n2 ) return 1;

View File

@ -94,6 +94,27 @@ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
sqlite3VdbeChangeP3(v, -1, pTab->zColAff, 0);
}
/*
** Return non-zero if SELECT statement p opens the table with rootpage
** iTab in database iDb. This is used to see if a statement of the form
** "INSERT INTO <iDb, iTab> SELECT ..." can run without using temporary
** table for the results of the SELECT.
**
** No checking is done for sub-selects that are part of expressions.
*/
static int selectReadsTable(Select *p, int iDb, int iTab){
int i;
struct SrcList_item *pItem;
if( p->pSrc==0 ) return 0;
for(i=0, pItem=p->pSrc->a; i<p->pSrc->nSrc; i++, pItem++){
if( pItem->pSelect ){
if( selectReadsTable(p, iDb, iTab) ) return 1;
}else{
if( pItem->pTab->iDb==iDb && pItem->pTab->tnum==iTab ) return 1;
}
}
return 0;
}
/*
** This routine is call to handle SQL of the following forms:
@ -182,18 +203,24 @@ void sqlite3Insert(
sqlite3 *db; /* The main database structure */
int keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */
int endOfLoop; /* Label for the end of the insertion loop */
int useTempTable; /* Store SELECT results in intermediate table */
int useTempTable = 0; /* Store SELECT results in intermediate table */
int srcTab = 0; /* Data comes from this temporary cursor if >=0 */
int iSelectLoop = 0; /* Address of code that implements the SELECT */
int iCleanup = 0; /* Address of the cleanup code */
int iInsertBlock = 0; /* Address of the subroutine used to insert data */
int iCntMem = 0; /* Memory cell used for the row counter */
int isView; /* True if attempting to insert into a view */
int newIdx = -1; /* Cursor for the NEW table */
Db *pDb; /* The database containing table being inserted into */
int counterMem = 0; /* Memory cell holding AUTOINCREMENT counter */
int row_triggers_exist = 0; /* True if there are FOR EACH ROW triggers */
int before_triggers; /* True if there are BEFORE triggers */
int after_triggers; /* True if there are AFTER triggers */
int newIdx = -1; /* Cursor for the NEW table */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to insert into a view */
int triggers_exist = 0; /* True if there are FOR EACH ROW triggers */
#endif
#ifndef SQLITE_OMIT_AUTOINCREMENT
int counterRowid; /* Memory cell holding rowid of autoinc counter */
#endif
if( pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup;
db = pParse->db;
@ -208,22 +235,32 @@ void sqlite3Insert(
goto insert_cleanup;
}
assert( pTab->iDb<db->nDb );
zDb = db->aDb[pTab->iDb].zName;
pDb = &db->aDb[pTab->iDb];
zDb = pDb->zName;
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){
goto insert_cleanup;
}
/* Figure out if we have any triggers and if the table being
** inserted into is a view
*/
#ifndef SQLITE_OMIT_TRIGGER
triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0);
isView = pTab->pSelect!=0;
#else
# define triggers_exist 0
# define isView 0
#endif
#ifdef SQLITE_OMIT_VIEW
# undef isView
# define isView 0
#endif
/* Ensure that:
* (a) the table is not read-only,
* (b) that if it is a view then ON INSERT triggers exist
*/
before_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger, TK_INSERT,
TK_BEFORE, TK_ROW, 0);
after_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger, TK_INSERT,
TK_AFTER, TK_ROW, 0);
row_triggers_exist = before_triggers || after_triggers;
isView = pTab->pSelect!=0;
if( sqlite3IsReadOnly(pParse, pTab, before_triggers) ){
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
goto insert_cleanup;
}
if( pTab==0 ) goto insert_cleanup;
@ -245,14 +282,42 @@ void sqlite3Insert(
*/
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto insert_cleanup;
sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, pSelect || row_triggers_exist, pTab->iDb);
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, pSelect || triggers_exist, pTab->iDb);
/* if there are row triggers, allocate a temp table for new.* references. */
if( row_triggers_exist ){
if( triggers_exist ){
newIdx = pParse->nTab++;
}
#ifndef SQLITE_OMIT_AUTOINCREMENT
/* If this is an AUTOINCREMENT table, look up the sequence number in the
** sqlite_sequence table and store it in memory cell counterMem. Also
** remember the rowid of the sqlite_sequence table entry in memory cell
** counterRowid.
*/
if( pTab->autoInc ){
int iCur = pParse->nTab;
int base = sqlite3VdbeCurrentAddr(v);
counterRowid = pParse->nMem++;
counterMem = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pDb->pSeqTab->tnum);
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, 2);
sqlite3VdbeAddOp(v, OP_Rewind, iCur, base+13);
sqlite3VdbeAddOp(v, OP_Column, iCur, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
sqlite3VdbeAddOp(v, OP_Ne, 28417, base+12);
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
sqlite3VdbeAddOp(v, OP_MemStore, counterRowid, 1);
sqlite3VdbeAddOp(v, OP_Column, iCur, 1);
sqlite3VdbeAddOp(v, OP_MemStore, counterMem, 1);
sqlite3VdbeAddOp(v, OP_Goto, 0, base+13);
sqlite3VdbeAddOp(v, OP_Next, iCur, base+4);
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
#endif /* SQLITE_OMIT_AUTOINCREMENT */
/* Figure out how many columns of data are supplied. If the data
** is coming from a SELECT statement, then this step also generates
** all the code to implement the SELECT statement and invoke a subroutine
@ -268,8 +333,11 @@ void sqlite3Insert(
iInitCode = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
iSelectLoop = sqlite3VdbeCurrentAddr(v);
iInsertBlock = sqlite3VdbeMakeLabel(v);
rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock, 0,0,0,0);
/* Resolve the expressions in the SELECT statement and execute it. */
rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock,0,0,0,0);
if( rc || pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup;
iCleanup = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup);
assert( pSelect->pEList );
@ -283,20 +351,8 @@ void sqlite3Insert(
** of the tables being read by the SELECT statement. Also use a
** temp table in the case of row triggers.
*/
if( row_triggers_exist ){
if( triggers_exist || selectReadsTable(pSelect, pTab->iDb, pTab->tnum) ){
useTempTable = 1;
}else{
int addr = 0;
useTempTable = 0;
while( useTempTable==0 ){
VdbeOp *pOp;
addr = sqlite3VdbeFindOp(v, addr, OP_OpenRead, pTab->tnum);
if( addr==0 ) break;
pOp = sqlite3VdbeGetOp(v, addr-2);
if( pOp->opcode==OP_Integer && pOp->p1==pTab->iDb ){
useTempTable = 1;
}
}
}
if( useTempTable ){
@ -328,15 +384,16 @@ void sqlite3Insert(
/* This is the case if the data for the INSERT is coming from a VALUES
** clause
*/
SrcList dummy;
NameContext sNC;
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
assert( pList!=0 );
srcTab = -1;
useTempTable = 0;
assert( pList );
nColumn = pList->nExpr;
dummy.nSrc = 0;
for(i=0; i<nColumn; i++){
if( sqlite3ExprResolveAndCheck(pParse,&dummy,0,pList->a[i].pExpr,0,0) ){
if( sqlite3ExprResolveNames(&sNC, pList->a[i].pExpr) ){
goto insert_cleanup;
}
}
@ -404,7 +461,7 @@ void sqlite3Insert(
/* Open the temp table for FOR EACH ROW triggers
*/
if( row_triggers_exist ){
if( triggers_exist ){
sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
}
@ -418,7 +475,7 @@ void sqlite3Insert(
}
/* Open tables and indices if there are no row triggers */
if( !row_triggers_exist ){
if( !triggers_exist ){
base = pParse->nTab;
sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite);
}
@ -440,7 +497,7 @@ void sqlite3Insert(
/* Run the BEFORE and INSTEAD OF triggers, if there are any
*/
endOfLoop = sqlite3VdbeMakeLabel(v);
if( before_triggers ){
if( triggers_exist & TRIGGER_BEFORE ){
/* build the NEW.* reference row. Note that if there is an INTEGER
** PRIMARY KEY into which a NULL is being inserted, that NULL will be
@ -452,9 +509,8 @@ void sqlite3Insert(
sqlite3VdbeAddOp(v, OP_Integer, -1, 0);
}else if( useTempTable ){
sqlite3VdbeAddOp(v, OP_Column, srcTab, keyColumn);
}else if( pSelect ){
sqlite3VdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1);
}else{
assert( pSelect==0 ); /* Otherwise useTempTable is true */
sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr);
sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
@ -473,13 +529,12 @@ void sqlite3Insert(
}
}
if( pColumn && j>=pColumn->nId ){
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);
}else if( useTempTable ){
sqlite3VdbeAddOp(v, OP_Column, srcTab, j);
}else if( pSelect ){
sqlite3VdbeAddOp(v, OP_Dup, nColumn-j-1, 1);
}else{
sqlite3ExprCode(pParse, pList->a[j].pExpr);
assert( pSelect==0 ); /* Otherwise useTempTable is true */
sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr);
}
}
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
@ -495,7 +550,7 @@ void sqlite3Insert(
sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
/* Fire BEFORE or INSTEAD OF triggers */
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TK_BEFORE, pTab,
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_BEFORE, pTab,
newIdx, -1, onError, endOfLoop) ){
goto insert_cleanup;
}
@ -504,7 +559,7 @@ void sqlite3Insert(
/* If any triggers exists, the opening of tables and indices is deferred
** until now.
*/
if( row_triggers_exist && !isView ){
if( triggers_exist && !isView ){
base = pParse->nTab;
sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite);
}
@ -528,11 +583,16 @@ void sqlite3Insert(
*/
sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
sqlite3VdbeAddOp(v, OP_NewRecno, base, 0);
sqlite3VdbeAddOp(v, OP_NewRecno, base, counterMem);
sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
}else{
sqlite3VdbeAddOp(v, OP_NewRecno, base, 0);
sqlite3VdbeAddOp(v, OP_NewRecno, base, counterMem);
}
#ifndef SQLITE_OMIT_AUTOINCREMENT
if( pTab->autoInc ){
sqlite3VdbeAddOp(v, OP_MemMax, counterMem, 0);
}
#endif /* SQLITE_OMIT_AUTOINCREMENT */
/* Push onto the stack, data for all columns of the new entry, beginning
** with the first column.
@ -554,7 +614,7 @@ void sqlite3Insert(
}
}
if( pColumn && j>=pColumn->nId ){
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);
}else if( useTempTable ){
sqlite3VdbeAddOp(v, OP_Column, srcTab, j);
}else if( pSelect ){
@ -570,7 +630,7 @@ void sqlite3Insert(
sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0,
0, onError, endOfLoop);
sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0,
after_triggers ? newIdx : -1);
(triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1);
}
/* Update the count of rows that are inserted
@ -579,7 +639,7 @@ void sqlite3Insert(
sqlite3VdbeAddOp(v, OP_MemIncr, iCntMem, 0);
}
if( row_triggers_exist ){
if( triggers_exist ){
/* Close all tables opened */
if( !isView ){
sqlite3VdbeAddOp(v, OP_Close, base, 0);
@ -589,8 +649,8 @@ void sqlite3Insert(
}
/* Code AFTER triggers */
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TK_AFTER, pTab, newIdx, -1,
onError, endOfLoop) ){
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_AFTER, pTab,
newIdx, -1, onError, endOfLoop) ){
goto insert_cleanup;
}
}
@ -608,7 +668,7 @@ void sqlite3Insert(
sqlite3VdbeResolveLabel(v, iCleanup);
}
if( !row_triggers_exist ){
if( !triggers_exist ){
/* Close all tables opened */
sqlite3VdbeAddOp(v, OP_Close, base, 0);
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
@ -616,10 +676,35 @@ void sqlite3Insert(
}
}
/*
** Return the number of rows inserted.
#ifndef SQLITE_OMIT_AUTOINCREMENT
/* Update the sqlite_sequence table by storing the content of the
** counter value in memory counterMem back into the sqlite_sequence
** table.
*/
if( db->flags & SQLITE_CountRows ){
if( pTab->autoInc ){
int iCur = pParse->nTab;
int base = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqlite3VdbeAddOp(v, OP_OpenWrite, iCur, pDb->pSeqTab->tnum);
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, 2);
sqlite3VdbeAddOp(v, OP_MemLoad, counterRowid, 0);
sqlite3VdbeAddOp(v, OP_NotNull, -1, base+7);
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
sqlite3VdbeAddOp(v, OP_NewRecno, iCur, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
sqlite3VdbeAddOp(v, OP_MemLoad, counterMem, 0);
sqlite3VdbeAddOp(v, OP_MakeRecord, 2, 0);
sqlite3VdbeAddOp(v, OP_PutIntKey, iCur, 0);
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
#endif
/*
** Return the number of rows inserted. If this routine is
** generating code because of a call to sqlite3NestedParse(), do not
** invoke the callback function.
*/
if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
sqlite3VdbeAddOp(v, OP_MemLoad, iCntMem, 0);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeSetNumCols(v, 1);
@ -753,11 +838,13 @@ void sqlite3GenerateConstraintChecks(
}else if( onError==OE_Default ){
onError = OE_Abort;
}
if( onError==OE_Replace && pTab->aCol[i].zDflt==0 ){
if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){
onError = OE_Abort;
}
sqlite3VdbeAddOp(v, OP_Dup, nCol-1-i, 1);
addr = sqlite3VdbeAddOp(v, OP_NotNull, 1, 0);
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|| onError==OE_Ignore || onError==OE_Replace );
switch( onError ){
case OE_Rollback:
case OE_Abort:
@ -775,11 +862,10 @@ void sqlite3GenerateConstraintChecks(
break;
}
case OE_Replace: {
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);
sqlite3VdbeAddOp(v, OP_Push, nCol-i, 0);
break;
}
default: assert(0);
}
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
}
@ -885,6 +971,8 @@ void sqlite3GenerateConstraintChecks(
jumpInst2 = sqlite3VdbeAddOp(v, OP_IsUnique, base+iCur+1, 0);
/* Generate code that executes if the new index entry is not unique */
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|| onError==OE_Ignore || onError==OE_Replace );
switch( onError ){
case OE_Rollback:
case OE_Abort:
@ -929,7 +1017,6 @@ void sqlite3GenerateConstraintChecks(
seenReplace = 1;
break;
}
default: assert(0);
}
contAddr = sqlite3VdbeCurrentAddr(v);
assert( contAddr<(1<<24) );
@ -975,12 +1062,18 @@ void sqlite3CompleteInsertion(
}
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
sqlite3TableAffinityStr(v, pTab);
#ifndef SQLITE_OMIT_TRIGGER
if( newIdx>=0 ){
sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
}
pik_flags = (OPFLAG_NCHANGE|(isUpdate?0:OPFLAG_LASTROWID));
#endif
if( pParse->nested ){
pik_flags = 0;
}else{
pik_flags = (OPFLAG_NCHANGE|(isUpdate?0:OPFLAG_LASTROWID));
}
sqlite3VdbeAddOp(v, OP_PutIntKey, base, pik_flags);
if( isUpdate && recnoChng ){

View File

@ -202,7 +202,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
** meta[2] Size of the page cache.
** meta[3] Use freelist if 0. Autovacuum if greater than zero.
** meta[4] Db text encoding. 1:UTF-8 3:UTF-16 LE 4:UTF-16 BE
** meta[5]
** meta[5] The user cookie. Used by the application.
** meta[6]
** meta[7]
** meta[8]
@ -257,12 +257,23 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
/* This happens if the database was initially empty */
db->file_format = 1;
}
if( db->file_format==2 ){
/* File format 2 is treated exactly as file format 1. New
** databases are created with file format 1.
*/
db->file_format = 1;
}
}
/*
** file_format==1 Version 3.0.0.
** file_format==1 Version 3.0.0.
** file_format==2 Version 3.1.3.
**
** Version 3.0 can only use files with file_format==1. Version 3.1.3
** can read and write files with file_format==1 or file_format==2.
*/
if( meta[1]>1 ){
if( meta[1]>2 ){
sqlite3BtreeCloseCursor(curMain);
sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0);
return SQLITE_ERROR;
@ -279,7 +290,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
}else{
char *zSql;
zSql = sqlite3MPrintf(
"SELECT name, rootpage, sql, %s FROM '%q'.%s",
"SELECT name, rootpage, sql, '%s' FROM '%q'.%s",
zDbNum, db->aDb[iDb].zName, zMasterName);
sqlite3SafetyOff(db);
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
@ -373,12 +384,13 @@ int sqlite3ReadSchema(Parse *pParse){
const char rcsid3[] = "@(#) \044Id: SQLite version " SQLITE_VERSION " $";
const char sqlite3_version[] = SQLITE_VERSION;
const char *sqlite3_libversion(void){ return sqlite3_version; }
int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
/*
** This is the default collating function named "BINARY" which is always
** available.
*/
static int binaryCollatingFunc(
static int binCollFunc(
void *NotUsed,
int nKey1, const void *pKey1,
int nKey2, const void *pKey2
@ -553,7 +565,7 @@ const char *sqlite3ErrStr(int rc){
case SQLITE_NOLFS: z = "kernel lacks large file support"; break;
case SQLITE_AUTH: z = "authorization denied"; break;
case SQLITE_FORMAT: z = "auxiliary database format error"; break;
case SQLITE_RANGE: z = "bind index out of range"; break;
case SQLITE_RANGE: z = "bind or column index out of range"; break;
case SQLITE_NOTADB: z = "file is encrypted or is not a database";break;
default: z = "unknown error"; break;
}
@ -706,6 +718,7 @@ int sqlite3_create_function(
return SQLITE_ERROR;
}
#ifndef SQLITE_OMIT_UTF16
/* If SQLITE_UTF16 is specified as the encoding type, transform this
** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally.
@ -725,6 +738,25 @@ int sqlite3_create_function(
if( rc!=SQLITE_OK ) return rc;
enc = SQLITE_UTF16BE;
}
#else
enc = SQLITE_UTF8;
#endif
/* Check if an existing function is being overridden or deleted. If so,
** and there are active VMs, then return SQLITE_BUSY. If a function
** is being overridden/deleted but there are no active VMs, allow the
** operation to continue but invalidate all precompiled statements.
*/
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 0);
if( p && p->iPrefEnc==enc && p->nArg==nArg ){
if( db->activeVdbeCnt ){
sqlite3Error(db, SQLITE_BUSY,
"Unable to delete/modify user-function due to active statements");
return SQLITE_BUSY;
}else{
sqlite3ExpirePreparedStatements(db);
}
}
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 1);
if( p==0 ) return SQLITE_NOMEM;
@ -734,6 +766,7 @@ int sqlite3_create_function(
p->pUserData = pUserData;
return SQLITE_OK;
}
#ifndef SQLITE_OMIT_UTF16
int sqlite3_create_function16(
sqlite3 *db,
const void *zFunctionName,
@ -762,6 +795,7 @@ int sqlite3_create_function16(
pUserData, xFunc, xStep, xFinal);
return rc;
}
#endif
/*
** Register a trace function. The pArg from the previously registered trace
@ -835,13 +869,14 @@ int sqlite3BtreeFactory(
if( omitJournal ){
btree_flags |= BTREE_OMIT_JOURNAL;
}
if( db->flags & SQLITE_NoReadlock ){
btree_flags |= BTREE_NO_READLOCK;
}
if( zFilename==0 ){
#ifndef TEMP_STORE
# define TEMP_STORE 1
#endif
#if TEMP_STORE==0
/* Do nothing */
#endif
#ifndef SQLITE_OMIT_MEMORYDB
#if TEMP_STORE==1
if( db->temp_store==2 ) zFilename = ":memory:";
#endif
@ -851,6 +886,7 @@ int sqlite3BtreeFactory(
#if TEMP_STORE==3
zFilename = ":memory:";
#endif
#endif /* SQLITE_OMIT_MEMORYDB */
}
rc = sqlite3BtreeOpen(zFilename, ppBtree, btree_flags);
@ -880,6 +916,7 @@ const char *sqlite3_errmsg(sqlite3 *db){
return z;
}
#ifndef SQLITE_OMIT_UTF16
/*
** Return UTF-16 encoded English language explanation of the most recent
** error.
@ -919,6 +956,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){
}
return z;
}
#endif /* SQLITE_OMIT_UTF16 */
/*
** Return the most recent error code generated by an SQLite routine.
@ -1005,6 +1043,7 @@ int sqlite3_prepare(
if( pzTail ) *pzTail = sParse.zTail;
rc = sParse.rc;
#ifndef SQLITE_OMIT_EXPLAIN
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
sqlite3VdbeSetNumCols(sParse.pVdbe, 5);
sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC);
@ -1013,6 +1052,7 @@ int sqlite3_prepare(
sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC);
}
#endif
prepare_out:
if( sqlite3SafetyOff(db) ){
@ -1033,6 +1073,7 @@ prepare_out:
return rc;
}
#ifndef SQLITE_OMIT_UTF16
/*
** Compile the UTF-16 encoded SQL statement zSql into a statement handle.
*/
@ -1076,6 +1117,7 @@ int sqlite3_prepare16(
return rc;
}
#endif /* SQLITE_OMIT_UTF16 */
/*
** This routine does the work of opening a database on behalf of
@ -1091,7 +1133,6 @@ static int openDatabase(
){
sqlite3 *db;
int rc, i;
char *zErrMsg = 0;
/* Allocate the sqlite data structure */
db = sqliteMalloc( sizeof(sqlite3) );
@ -1102,7 +1143,7 @@ static int openDatabase(
db->aDb = db->aDbStatic;
db->enc = SQLITE_UTF8;
db->autoCommit = 1;
/* db->flags |= SQLITE_ShortColNames; */
db->flags |= SQLITE_ShortColNames;
sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0);
for(i=0; i<db->nDb; i++){
@ -1116,11 +1157,9 @@ static int openDatabase(
** and UTF-16, so add a version for each to avoid any unnecessary
** conversions. The only error that can occur here is a malloc() failure.
*/
sqlite3_create_collation(db, "BINARY", SQLITE_UTF8, 0,binaryCollatingFunc);
sqlite3_create_collation(db, "BINARY", SQLITE_UTF16LE, 0,binaryCollatingFunc);
sqlite3_create_collation(db, "BINARY", SQLITE_UTF16BE, 0,binaryCollatingFunc);
db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0);
if( !db->pDfltColl ){
if( sqlite3_create_collation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc) ||
sqlite3_create_collation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) ||
!(db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0)) ){
rc = db->errCode;
assert( rc!=SQLITE_OK );
db->magic = SQLITE_MAGIC_CLOSED;
@ -1150,14 +1189,8 @@ static int openDatabase(
** is accessed.
*/
sqlite3RegisterBuiltinFunctions(db);
if( rc==SQLITE_OK ){
sqlite3Error(db, SQLITE_OK, 0);
db->magic = SQLITE_MAGIC_OPEN;
}else{
sqlite3Error(db, rc, "%s", zErrMsg, 0);
if( zErrMsg ) sqliteFree(zErrMsg);
db->magic = SQLITE_MAGIC_CLOSED;
}
sqlite3Error(db, SQLITE_OK, 0);
db->magic = SQLITE_MAGIC_OPEN;
opendb_out:
if( sqlite3_errcode(db)==SQLITE_OK && sqlite3_malloc_failed ){
@ -1177,6 +1210,7 @@ int sqlite3_open(
return openDatabase(zFilename, ppDb);
}
#ifndef SQLITE_OMIT_UTF16
/*
** Open a new database handle.
*/
@ -1205,6 +1239,7 @@ int sqlite3_open16(
return rc;
}
#endif /* SQLITE_OMIT_UTF16 */
/*
** The following routine destroys a virtual machine that is created by
@ -1239,7 +1274,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
rc = SQLITE_OK;
}else{
rc = sqlite3VdbeReset((Vdbe*)pStmt);
sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0);
sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0, 0);
}
return rc;
}
@ -1276,6 +1311,21 @@ int sqlite3_create_collation(
);
return SQLITE_ERROR;
}
/* Check if this call is removing or replacing an existing collation
** sequence. If so, and there are active VMs, return busy. If there
** are no active VMs, invalidate any pre-compiled statements.
*/
pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 0);
if( pColl && pColl->xCmp ){
if( db->activeVdbeCnt ){
sqlite3Error(db, SQLITE_BUSY,
"Unable to delete/modify collation sequence due to active statements");
return SQLITE_BUSY;
}
sqlite3ExpirePreparedStatements(db);
}
pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 1);
if( 0==pColl ){
rc = SQLITE_NOMEM;
@ -1288,6 +1338,7 @@ int sqlite3_create_collation(
return rc;
}
#ifndef SQLITE_OMIT_UTF16
/*
** Register a new collation sequence with the database handle db.
*/
@ -1308,6 +1359,7 @@ int sqlite3_create_collation16(
zName8 = sqlite3ValueText(pTmp, SQLITE_UTF8);
return sqlite3_create_collation(db, zName8, enc, pCtx, xCompare);
}
#endif /* SQLITE_OMIT_UTF16 */
/*
** Register a collation sequence factory callback with the database handle
@ -1327,6 +1379,7 @@ int sqlite3_collation_needed(
return SQLITE_OK;
}
#ifndef SQLITE_OMIT_UTF16
/*
** Register a collation sequence factory callback with the database handle
** db. Replace any previously installed collation sequence factory.
@ -1344,3 +1397,4 @@ int sqlite3_collation_needed16(
db->pCollNeededArg = pCollNeededArg;
return SQLITE_OK;
}
#endif /* SQLITE_OMIT_UTF16 */

View File

@ -1,128 +1,137 @@
/* Automatically generated. Do not edit */
/* See the mkopcodec.h script for details. */
/* See the mkopcodec.awk script for details. */
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
const char *const sqlite3OpcodeNames[] = { "?",
"ContextPop",
"IntegrityCk",
"DropTrigger",
"DropIndex",
"Recno",
"KeyAsData",
"Delete",
"MoveGt",
"VerifyCookie",
"Push",
"Dup",
"Blob",
"IdxGT",
"IdxRecno",
"RowKey",
"PutStrKey",
"IsUnique",
"SetNumColumns",
"IdxIsNull",
"NullRow",
"OpenPseudo",
"OpenWrite",
"OpenRead",
"Transaction",
"AutoCommit",
"Pop",
"Halt",
"Vacuum",
"ListRead",
"RowData",
"NotExists",
"MoveLe",
"SetCookie",
"Variable",
"AggNext",
"AggReset",
"Sort",
"IdxDelete",
"ResetCount",
"OpenTemp",
"IdxColumn",
"Integer",
"AggSet",
"CreateIndex",
"IdxPut",
"MoveLt",
"Return",
"MemLoad",
"SortNext",
"IdxLT",
"Rewind",
"AddImm",
"AggFunc",
"AggInit",
"MemIncr",
"ListReset",
"Clear",
"Or",
"And",
"Not",
"PutIntKey",
"If",
"Callback",
"IsNull",
"NotNull",
"Ne",
"Eq",
"Gt",
"Le",
"Lt",
"Ge",
"BitAnd",
"BitOr",
"ShiftLeft",
"ShiftRight",
"Add",
"Subtract",
"Multiply",
"Divide",
"Remainder",
"Concat",
"Negative",
"SortReset",
"BitNot",
"String8",
"SortPut",
"Last",
"NotFound",
"MakeRecord",
"String",
"Goto",
"AggFocus",
"DropTable",
"Column",
"Noop",
"AggGet",
"CreateTable",
"NewRecno",
"Found",
"Distinct",
"Close",
"Statement",
"IfNot",
"Pull",
"MemStore",
"Next",
"Prev",
"MoveGe",
"MustBeInt",
"ForceInt",
"CollSeq",
"Gosub",
"ContextPush",
"ListRewind",
"ListWrite",
"ParseSchema",
"Destroy",
"IdxGE",
"FullKey",
"ReadCookie",
"AbsValue",
"Real",
"HexBlob",
"Function",
/* 1 */ "MemLoad",
/* 2 */ "Column",
/* 3 */ "SetCookie",
/* 4 */ "IfMemPos",
/* 5 */ "MoveGt",
/* 6 */ "AggFocus",
/* 7 */ "RowKey",
/* 8 */ "IdxRecno",
/* 9 */ "AggNext",
/* 10 */ "OpenWrite",
/* 11 */ "If",
/* 12 */ "PutStrKey",
/* 13 */ "Pop",
/* 14 */ "SortPut",
/* 15 */ "AggContextPush",
/* 16 */ "CollSeq",
/* 17 */ "OpenRead",
/* 18 */ "Expire",
/* 19 */ "SortReset",
/* 20 */ "AutoCommit",
/* 21 */ "Sort",
/* 22 */ "ListRewind",
/* 23 */ "IntegrityCk",
/* 24 */ "Function",
/* 25 */ "Noop",
/* 26 */ "Return",
/* 27 */ "Variable",
/* 28 */ "String",
/* 29 */ "ParseSchema",
/* 30 */ "PutIntKey",
/* 31 */ "AggFunc",
/* 32 */ "Close",
/* 33 */ "ListWrite",
/* 34 */ "CreateIndex",
/* 35 */ "IsUnique",
/* 36 */ "IdxIsNull",
/* 37 */ "NotFound",
/* 38 */ "MustBeInt",
/* 39 */ "Halt",
/* 40 */ "IdxLT",
/* 41 */ "AddImm",
/* 42 */ "Statement",
/* 43 */ "RowData",
/* 44 */ "MemMax",
/* 45 */ "Push",
/* 46 */ "KeyAsData",
/* 47 */ "NotExists",
/* 48 */ "OpenTemp",
/* 49 */ "MemIncr",
/* 50 */ "Gosub",
/* 51 */ "AggSet",
/* 52 */ "Integer",
/* 53 */ "SortNext",
/* 54 */ "Prev",
/* 55 */ "CreateTable",
/* 56 */ "Last",
/* 57 */ "ResetCount",
/* 58 */ "Callback",
/* 59 */ "ContextPush",
/* 60 */ "DropTrigger",
/* 61 */ "DropIndex",
/* 62 */ "FullKey",
/* 63 */ "IdxGE",
/* 64 */ "Or",
/* 65 */ "And",
/* 66 */ "Not",
/* 67 */ "IdxDelete",
/* 68 */ "Vacuum",
/* 69 */ "MoveLe",
/* 70 */ "IsNull",
/* 71 */ "NotNull",
/* 72 */ "Ne",
/* 73 */ "Eq",
/* 74 */ "Gt",
/* 75 */ "Le",
/* 76 */ "Lt",
/* 77 */ "Ge",
/* 78 */ "IfNot",
/* 79 */ "BitAnd",
/* 80 */ "BitOr",
/* 81 */ "ShiftLeft",
/* 82 */ "ShiftRight",
/* 83 */ "Add",
/* 84 */ "Subtract",
/* 85 */ "Multiply",
/* 86 */ "Divide",
/* 87 */ "Remainder",
/* 88 */ "Concat",
/* 89 */ "Negative",
/* 90 */ "DropTable",
/* 91 */ "BitNot",
/* 92 */ "String8",
/* 93 */ "MakeRecord",
/* 94 */ "Delete",
/* 95 */ "AggContextPop",
/* 96 */ "ListRead",
/* 97 */ "ListReset",
/* 98 */ "Dup",
/* 99 */ "Goto",
/* 100 */ "Clear",
/* 101 */ "IdxGT",
/* 102 */ "MoveLt",
/* 103 */ "VerifyCookie",
/* 104 */ "Pull",
/* 105 */ "SetNumColumns",
/* 106 */ "AbsValue",
/* 107 */ "Transaction",
/* 108 */ "AggGet",
/* 109 */ "ContextPop",
/* 110 */ "Next",
/* 111 */ "AggInit",
/* 112 */ "Distinct",
/* 113 */ "NewRecno",
/* 114 */ "AggReset",
/* 115 */ "Destroy",
/* 116 */ "ReadCookie",
/* 117 */ "ForceInt",
/* 118 */ "Recno",
/* 119 */ "OpenPseudo",
/* 120 */ "Blob",
/* 121 */ "MemStore",
/* 122 */ "Rewind",
/* 123 */ "MoveGe",
/* 124 */ "IdxPut",
/* 125 */ "Found",
/* 126 */ "NullRow",
/* 127 */ "NotUsed_127",
/* 128 */ "NotUsed_128",
/* 129 */ "NotUsed_129",
/* 130 */ "Real",
/* 131 */ "HexBlob",
};
#endif

View File

@ -1,126 +1,135 @@
/* Automatically generated. Do not edit */
/* See the mkopcodeh.awk script for details */
#define OP_ContextPop 1
#define OP_IntegrityCk 2
#define OP_DropTrigger 3
#define OP_DropIndex 4
#define OP_Recno 5
#define OP_KeyAsData 6
#define OP_Delete 7
#define OP_MoveGt 8
#define OP_VerifyCookie 9
#define OP_Push 10
#define OP_Dup 11
#define OP_Blob 12
#define OP_IdxGT 13
#define OP_IdxRecno 14
#define OP_RowKey 15
#define OP_PutStrKey 16
#define OP_IsUnique 17
#define OP_SetNumColumns 18
#define OP_Eq 67
#define OP_IdxIsNull 19
#define OP_NullRow 20
#define OP_OpenPseudo 21
#define OP_OpenWrite 22
#define OP_OpenRead 23
#define OP_Transaction 24
#define OP_AutoCommit 25
#define OP_Negative 82
#define OP_Pop 26
#define OP_Halt 27
#define OP_Vacuum 28
#define OP_ListRead 29
#define OP_RowData 30
#define OP_NotExists 31
#define OP_MoveLe 32
#define OP_SetCookie 33
#define OP_Variable 34
#define OP_AggNext 35
#define OP_AggReset 36
#define OP_Sort 37
#define OP_IdxDelete 38
#define OP_ResetCount 39
#define OP_OpenTemp 40
#define OP_IdxColumn 41
#define OP_NotNull 65
#define OP_Ge 71
#define OP_Remainder 80
#define OP_Divide 79
#define OP_Integer 42
#define OP_AggSet 43
#define OP_CreateIndex 44
#define OP_IdxPut 45
#define OP_MoveLt 46
#define OP_And 59
#define OP_ShiftLeft 74
#define OP_Real 122
#define OP_Return 47
#define OP_MemLoad 48
#define OP_SortNext 49
#define OP_IdxLT 50
#define OP_Rewind 51
#define OP_Gt 68
#define OP_AddImm 52
#define OP_Subtract 77
#define OP_AggFunc 53
#define OP_AggInit 54
#define OP_MemIncr 55
#define OP_ListReset 56
#define OP_Clear 57
#define OP_PutIntKey 61
#define OP_IsNull 64
#define OP_If 62
#define OP_Callback 63
#define OP_SortReset 83
#define OP_SortPut 86
#define OP_Last 87
#define OP_NotFound 88
#define OP_MakeRecord 89
#define OP_BitAnd 72
#define OP_Add 76
#define OP_HexBlob 123
#define OP_String 90
#define OP_Goto 91
#define OP_AggFocus 92
#define OP_DropTable 93
#define OP_Column 94
#define OP_Noop 95
#define OP_Not 60
#define OP_Le 69
#define OP_BitOr 73
#define OP_Multiply 78
#define OP_String8 85
#define OP_AggGet 96
#define OP_CreateTable 97
#define OP_NewRecno 98
#define OP_Found 99
#define OP_Distinct 100
#define OP_Close 101
#define OP_Statement 102
#define OP_IfNot 103
#define OP_Pull 104
#define OP_MemStore 105
#define OP_Next 106
#define OP_Prev 107
#define OP_MoveGe 108
#define OP_Lt 70
#define OP_Ne 66
#define OP_MustBeInt 109
#define OP_ForceInt 110
#define OP_ShiftRight 75
#define OP_CollSeq 111
#define OP_Gosub 112
#define OP_ContextPush 113
#define OP_ListRewind 114
#define OP_ListWrite 115
#define OP_ParseSchema 116
#define OP_Destroy 117
#define OP_IdxGE 118
#define OP_FullKey 119
#define OP_ReadCookie 120
#define OP_BitNot 84
#define OP_AbsValue 121
#define OP_Or 58
#define OP_Function 124
#define OP_Concat 81
#define OP_MemLoad 1
#define OP_HexBlob 131 /* same as TK_BLOB */
#define OP_Column 2
#define OP_SetCookie 3
#define OP_IfMemPos 4
#define OP_Real 130 /* same as TK_FLOAT */
#define OP_MoveGt 5
#define OP_Ge 77 /* same as TK_GE */
#define OP_AggFocus 6
#define OP_RowKey 7
#define OP_IdxRecno 8
#define OP_AggNext 9
#define OP_Eq 73 /* same as TK_EQ */
#define OP_OpenWrite 10
#define OP_NotNull 71 /* same as TK_NOTNULL */
#define OP_If 11
#define OP_PutStrKey 12
#define OP_String8 92 /* same as TK_STRING */
#define OP_Pop 13
#define OP_SortPut 14
#define OP_AggContextPush 15
#define OP_CollSeq 16
#define OP_OpenRead 17
#define OP_Expire 18
#define OP_SortReset 19
#define OP_AutoCommit 20
#define OP_Gt 74 /* same as TK_GT */
#define OP_Sort 21
#define OP_ListRewind 22
#define OP_IntegrityCk 23
#define OP_Function 24
#define OP_Subtract 84 /* same as TK_MINUS */
#define OP_And 65 /* same as TK_AND */
#define OP_Noop 25
#define OP_Return 26
#define OP_Remainder 87 /* same as TK_REM */
#define OP_Multiply 85 /* same as TK_STAR */
#define OP_Variable 27
#define OP_String 28
#define OP_ParseSchema 29
#define OP_PutIntKey 30
#define OP_AggFunc 31
#define OP_Close 32
#define OP_ListWrite 33
#define OP_CreateIndex 34
#define OP_IsUnique 35
#define OP_IdxIsNull 36
#define OP_NotFound 37
#define OP_MustBeInt 38
#define OP_Halt 39
#define OP_IdxLT 40
#define OP_AddImm 41
#define OP_Statement 42
#define OP_RowData 43
#define OP_MemMax 44
#define OP_Push 45
#define OP_Or 64 /* same as TK_OR */
#define OP_KeyAsData 46
#define OP_NotExists 47
#define OP_OpenTemp 48
#define OP_MemIncr 49
#define OP_Gosub 50
#define OP_Divide 86 /* same as TK_SLASH */
#define OP_AggSet 51
#define OP_Integer 52
#define OP_SortNext 53
#define OP_Prev 54
#define OP_Concat 88 /* same as TK_CONCAT */
#define OP_BitAnd 79 /* same as TK_BITAND */
#define OP_CreateTable 55
#define OP_Last 56
#define OP_IsNull 70 /* same as TK_ISNULL */
#define OP_ShiftRight 82 /* same as TK_RSHIFT */
#define OP_ResetCount 57
#define OP_Callback 58
#define OP_ContextPush 59
#define OP_DropTrigger 60
#define OP_DropIndex 61
#define OP_FullKey 62
#define OP_IdxGE 63
#define OP_IdxDelete 67
#define OP_Vacuum 68
#define OP_MoveLe 69
#define OP_IfNot 78
#define OP_DropTable 90
#define OP_MakeRecord 93
#define OP_Delete 94
#define OP_AggContextPop 95
#define OP_ListRead 96
#define OP_ListReset 97
#define OP_ShiftLeft 81 /* same as TK_LSHIFT */
#define OP_Dup 98
#define OP_Goto 99
#define OP_Clear 100
#define OP_IdxGT 101
#define OP_MoveLt 102
#define OP_Le 75 /* same as TK_LE */
#define OP_VerifyCookie 103
#define OP_Pull 104
#define OP_Not 66 /* same as TK_NOT */
#define OP_SetNumColumns 105
#define OP_AbsValue 106
#define OP_Transaction 107
#define OP_Negative 89 /* same as TK_UMINUS */
#define OP_Ne 72 /* same as TK_NE */
#define OP_AggGet 108
#define OP_ContextPop 109
#define OP_BitOr 80 /* same as TK_BITOR */
#define OP_Next 110
#define OP_AggInit 111
#define OP_Distinct 112
#define OP_NewRecno 113
#define OP_Lt 76 /* same as TK_LT */
#define OP_AggReset 114
#define OP_Destroy 115
#define OP_ReadCookie 116
#define OP_ForceInt 117
#define OP_Recno 118
#define OP_OpenPseudo 119
#define OP_Blob 120
#define OP_Add 83 /* same as TK_PLUS */
#define OP_MemStore 121
#define OP_Rewind 122
#define OP_MoveGe 123
#define OP_IdxPut 124
#define OP_BitNot 91 /* same as TK_BITNOT */
#define OP_Found 125
#define OP_NullRow 126
/* The following opcode values are never used */
#define OP_NotUsed_127 127
#define OP_NotUsed_128 128
#define OP_NotUsed_129 129

View File

@ -25,30 +25,17 @@
*/
#if !defined(OS_UNIX) && !defined(OS_TEST)
# ifndef OS_WIN
# ifndef OS_MAC
# if defined(__MACOS__)
# define OS_MAC 1
# define OS_WIN 0
# define OS_UNIX 0
# elif defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
# define OS_MAC 0
# define OS_WIN 1
# define OS_UNIX 0
# else
# define OS_MAC 0
# define OS_WIN 0
# define OS_UNIX 1
# endif
# else
# define OS_WIN 0
# define OS_UNIX 0
# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
# define OS_WIN 1
# define OS_UNIX 0
# else
# define OS_WIN 0
# define OS_UNIX 1
# endif
# else
# define OS_MAC 0
# define OS_UNIX 0
# endif
#else
# define OS_MAC 0
# ifndef OS_WIN
# define OS_WIN 0
# endif
@ -66,9 +53,6 @@
#if OS_WIN
# include "os_win.h"
#endif
#if OS_MAC
# include "os_mac.h"
#endif
/*
** Temporary files are named starting with this prefix followed by 16 random
@ -162,7 +146,7 @@
**
*/
#define PENDING_BYTE 0x40000000 /* First byte past the 1GB boundary */
/* #define PENDING_BYTE 0x5400 // Page 20 - for testing */
/* #define PENDING_BYTE 0x5400 // Page 22 - for testing */
#define RESERVED_BYTE (PENDING_BYTE+1)
#define SHARED_FIRST (PENDING_BYTE+2)
#define SHARED_SIZE 510
@ -176,6 +160,7 @@ int sqlite3OsOpenReadOnly(const char*, OsFile*);
int sqlite3OsOpenDirectory(const char*, OsFile*);
int sqlite3OsSyncDirectory(const char*);
int sqlite3OsTempFileName(char*);
int sqlite3OsIsDirWritable(char*);
int sqlite3OsClose(OsFile*);
int sqlite3OsRead(OsFile*, void*, int amt);
int sqlite3OsWrite(OsFile*, const void*, int amt);

View File

@ -239,10 +239,12 @@ printf("Writing block %d of %s\n", i, pFile->zName);
if( BLOCK_OFFSET(i+1)>nMax ){
len = nMax-BLOCK_OFFSET(i);
}
if( trash ){
sqlite3Randomness(len, p);
if( len>0 ){
if( trash ){
sqlite3Randomness(len, p);
}
rc = sqlite3RealWrite(&pFile->fd, p, len);
}
rc = sqlite3RealWrite(&pFile->fd, p, len);
}
sqliteFree(p);
}

View File

@ -574,7 +574,7 @@ int sqlite3OsOpenDirectory(
** name of a directory, then that directory will be used to store
** temporary files.
*/
const char *sqlite3_temp_directory = 0;
char *sqlite3_temp_directory = 0;
/*
** Create a temporary file name in zBuf. zBuf must be big enough to
@ -616,6 +616,22 @@ int sqlite3OsTempFileName(char *zBuf){
return SQLITE_OK;
}
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** Check that a given pathname is a directory and is writable
**
*/
int sqlite3OsIsDirWritable(char *zBuf){
struct stat buf;
if( zBuf==0 ) return 0;
if( zBuf[0]==0 ) return 0;
if( stat(zBuf, &buf) ) return 0;
if( !S_ISDIR(buf.st_mode) ) return 0;
if( access(zBuf, 07) ) return 0;
return 1;
}
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
/*
** Read data from a file into a buffer. Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
@ -645,6 +661,7 @@ int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
int wrote = 0;
assert( id->isOpen );
assert( amt>0 );
SimulateIOError(SQLITE_IOERR);
SimulateDiskfullError;
TIMER_START;
@ -675,8 +692,17 @@ int sqlite3OsSeek(OsFile *id, i64 offset){
** The fsync() system call does not work as advertised on many
** unix systems. The following procedure is an attempt to make
** it work better.
**
** The SQLITE_NO_SYNC macro disables all fsync()s. This is useful
** for testing when we want to run through the test suite quickly.
** You are strongly advised *not* to deploy with SQLITE_NO_SYNC
** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
** or power failure will likely corrupt the database file.
*/
static int full_fsync(int fd){
#ifdef SQLITE_NO_SYNC
return SQLITE_OK;
#else
int rc;
#ifdef F_FULLFSYNC
rc = fcntl(fd, F_FULLFSYNC, 0);
@ -685,6 +711,7 @@ static int full_fsync(int fd){
rc = fsync(fd);
#endif
return rc;
#endif
}
/*
@ -1157,10 +1184,16 @@ int sqlite3OsRandomSeed(char *zBuf){
memset(zBuf, 0, 256);
#if !defined(SQLITE_TEST)
{
int pid;
time((time_t*)zBuf);
pid = getpid();
memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid));
int pid, fd;
fd = open("/dev/urandom", O_RDONLY);
if( fd<0 ){
time((time_t*)zBuf);
pid = getpid();
memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid));
}else{
read(fd, zBuf, 256);
close(fd);
}
}
#endif
return SQLITE_OK;

View File

@ -202,7 +202,7 @@ int sqlite3OsOpenDirectory(
** name of a directory, then that directory will be used to store
** temporary files.
*/
const char *sqlite3_temp_directory = 0;
char *sqlite3_temp_directory = 0;
/*
** Create a temporary file name in zBuf. zBuf must be big enough to
@ -275,12 +275,13 @@ int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
** or some other error code on failure.
*/
int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
int rc;
int rc = 0;
DWORD wrote;
assert( id->isOpen );
SimulateIOError(SQLITE_IOERR);
SimulateDiskfullError;
TRACE3("WRITE %d lock=%d\n", id->h, id->locktype);
assert( amt>0 );
while( amt>0 && (rc = WriteFile(id->h, pBuf, amt, &wrote, 0))!=0 && wrote>0 ){
amt -= wrote;
pBuf = &((char*)pBuf)[wrote];
@ -409,6 +410,24 @@ static int unlockReadLock(OsFile *id){
return res;
}
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** Check that a given pathname is a directory and is writable
**
*/
int sqlite3OsIsDirWritable(char *zBuf){
int fileAttr;
if(! zBuf ) return 0;
if(! isNT() && strlen(zBuf) > MAX_PATH ) return 0;
fileAttr = GetFileAttributesA(zBuf);
if( fileAttr == 0xffffffff ) return 0;
if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){
return 0;
}
return 1;
}
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
/*
** Lock the file with the lock specified by parameter locktype - one
** of the following:

File diff suppressed because it is too large Load Diff

View File

@ -50,13 +50,21 @@ typedef unsigned int Pgno;
*/
typedef struct Pager Pager;
/*
** Allowed values for the flags parameter to sqlite3pager_open().
**
** NOTE: This values must match the corresponding BTREE_ values in btree.h.
*/
#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
#define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */
/*
** See source code comments for a detailed description of the following
** routines:
*/
int sqlite3pager_open(Pager **ppPager, const char *zFilename,
int nExtra, int useJournal);
int nExtra, int flags);
void sqlite3pager_set_busyhandler(Pager*, BusyHandler *pBusyHandler);
void sqlite3pager_set_destructor(Pager*, void(*)(void*,int));
void sqlite3pager_set_reiniter(Pager*, void(*)(void*,int));
@ -76,7 +84,7 @@ int sqlite3pager_pagecount(Pager*);
int sqlite3pager_truncate(Pager*,Pgno);
int sqlite3pager_begin(void*, int exFlag);
int sqlite3pager_commit(Pager*);
int sqlite3pager_sync(Pager*,const char *zMaster);
int sqlite3pager_sync(Pager*,const char *zMaster, Pgno);
int sqlite3pager_rollback(Pager*);
int sqlite3pager_isreadonly(Pager*);
int sqlite3pager_stmt_begin(Pager*);
@ -91,6 +99,7 @@ const char *sqlite3pager_dirname(Pager*);
const char *sqlite3pager_journalname(Pager*);
int sqlite3pager_rename(Pager*, const char *zNewName);
void sqlite3pager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*);
int sqlite3pager_movepage(Pager*,void*,Pgno);
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
int sqlite3pager_lockstate(Pager*);

File diff suppressed because it is too large Load Diff

View File

@ -55,75 +55,86 @@
#define TK_TRIGGER 55
#define TK_VACUUM 56
#define TK_VIEW 57
#define TK_OR 58
#define TK_AND 59
#define TK_NOT 60
#define TK_IS 61
#define TK_BETWEEN 62
#define TK_IN 63
#define TK_ISNULL 64
#define TK_NOTNULL 65
#define TK_NE 66
#define TK_EQ 67
#define TK_GT 68
#define TK_LE 69
#define TK_LT 70
#define TK_GE 71
#define TK_BITAND 72
#define TK_BITOR 73
#define TK_LSHIFT 74
#define TK_RSHIFT 75
#define TK_PLUS 76
#define TK_MINUS 77
#define TK_STAR 78
#define TK_SLASH 79
#define TK_REM 80
#define TK_CONCAT 81
#define TK_UMINUS 82
#define TK_UPLUS 83
#define TK_BITNOT 84
#define TK_STRING 85
#define TK_JOIN_KW 86
#define TK_CONSTRAINT 87
#define TK_DEFAULT 88
#define TK_NULL 89
#define TK_PRIMARY 90
#define TK_UNIQUE 91
#define TK_CHECK 92
#define TK_REFERENCES 93
#define TK_COLLATE 94
#define TK_ON 95
#define TK_DELETE 96
#define TK_UPDATE 97
#define TK_INSERT 98
#define TK_SET 99
#define TK_DEFERRABLE 100
#define TK_FOREIGN 101
#define TK_DROP 102
#define TK_UNION 103
#define TK_ALL 104
#define TK_INTERSECT 105
#define TK_EXCEPT 106
#define TK_SELECT 107
#define TK_DISTINCT 108
#define TK_DOT 109
#define TK_FROM 110
#define TK_JOIN 111
#define TK_USING 112
#define TK_ORDER 113
#define TK_BY 114
#define TK_GROUP 115
#define TK_HAVING 116
#define TK_LIMIT 117
#define TK_WHERE 118
#define TK_INTO 119
#define TK_VALUES 120
#define TK_INTEGER 121
#define TK_FLOAT 122
#define TK_BLOB 123
#define TK_VARIABLE 124
#define TK_CASE 125
#define TK_WHEN 126
#define TK_THEN 127
#define TK_ELSE 128
#define TK_INDEX 129
#define TK_REINDEX 58
#define TK_RENAME 59
#define TK_CDATE 60
#define TK_CTIME 61
#define TK_CTIMESTAMP 62
#define TK_ALTER 63
#define TK_OR 64
#define TK_AND 65
#define TK_NOT 66
#define TK_IS 67
#define TK_BETWEEN 68
#define TK_IN 69
#define TK_ISNULL 70
#define TK_NOTNULL 71
#define TK_NE 72
#define TK_EQ 73
#define TK_GT 74
#define TK_LE 75
#define TK_LT 76
#define TK_GE 77
#define TK_ESCAPE 78
#define TK_BITAND 79
#define TK_BITOR 80
#define TK_LSHIFT 81
#define TK_RSHIFT 82
#define TK_PLUS 83
#define TK_MINUS 84
#define TK_STAR 85
#define TK_SLASH 86
#define TK_REM 87
#define TK_CONCAT 88
#define TK_UMINUS 89
#define TK_UPLUS 90
#define TK_BITNOT 91
#define TK_STRING 92
#define TK_JOIN_KW 93
#define TK_CONSTRAINT 94
#define TK_DEFAULT 95
#define TK_NULL 96
#define TK_PRIMARY 97
#define TK_UNIQUE 98
#define TK_CHECK 99
#define TK_REFERENCES 100
#define TK_COLLATE 101
#define TK_AUTOINCR 102
#define TK_ON 103
#define TK_DELETE 104
#define TK_UPDATE 105
#define TK_INSERT 106
#define TK_SET 107
#define TK_DEFERRABLE 108
#define TK_FOREIGN 109
#define TK_DROP 110
#define TK_UNION 111
#define TK_ALL 112
#define TK_INTERSECT 113
#define TK_EXCEPT 114
#define TK_SELECT 115
#define TK_DISTINCT 116
#define TK_DOT 117
#define TK_FROM 118
#define TK_JOIN 119
#define TK_USING 120
#define TK_ORDER 121
#define TK_BY 122
#define TK_GROUP 123
#define TK_HAVING 124
#define TK_LIMIT 125
#define TK_WHERE 126
#define TK_INTO 127
#define TK_VALUES 128
#define TK_INTEGER 129
#define TK_FLOAT 130
#define TK_BLOB 131
#define TK_REGISTER 132
#define TK_VARIABLE 133
#define TK_EXISTS 134
#define TK_CASE 135
#define TK_WHEN 136
#define TK_THEN 137
#define TK_ELSE 138
#define TK_INDEX 139
#define TK_TO 140

View File

@ -39,8 +39,8 @@
** LIMIT clause of a SELECT statement.
*/
struct LimitVal {
int limit; /* The LIMIT value. -1 if there is no limit */
int offset; /* The OFFSET. 0 if there is none */
Expr *pLimit; /* The LIMIT expression. NULL if there is no limit */
Expr *pOffset; /* The OFFSET expression. NULL if there is none */
};
/*
@ -81,11 +81,13 @@ struct AttachKey { int type; Token key; };
input ::= cmdlist.
cmdlist ::= cmdlist ecmd.
cmdlist ::= ecmd.
ecmd ::= explain cmdx SEMI.
ecmd ::= SEMI.
cmdx ::= cmd. { sqlite3FinishCoding(pParse); }
explain ::= EXPLAIN. { sqlite3BeginParse(pParse, 1); }
ecmd ::= SEMI.
ecmd ::= explain cmdx SEMI.
explain ::= . { sqlite3BeginParse(pParse, 0); }
%ifndef SQLITE_OMIT_EXPLAIN
explain ::= EXPLAIN. { sqlite3BeginParse(pParse, 1); }
%endif
///////////////////// Begin and end transactions. ////////////////////////////
//
@ -144,7 +146,12 @@ id(A) ::= ID(X). {A = X;}
DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
GLOB IGNORE IMMEDIATE INITIALLY INSTEAD LIKE MATCH KEY
OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
TEMP TRIGGER VACUUM VIEW.
TEMP TRIGGER VACUUM VIEW
%ifdef SQLITE_OMIT_COMPOUND_SELECT
EXCEPT INTERSECT UNION
%endif
REINDEX RENAME CDATE CTIME CTIMESTAMP ALTER
.
// Define operator precedence early so that this is the first occurance
// of the operator tokens in the grammer. Keeping the operators together
@ -162,6 +169,7 @@ id(A) ::= ID(X). {A = X;}
%right NOT.
%left IS LIKE GLOB BETWEEN IN ISNULL NOTNULL NE EQ.
%left GT LE LT GE.
%right ESCAPE.
%left BITAND BITOR LSHIFT RSHIFT.
%left PLUS MINUS.
%left STAR SLASH REM.
@ -196,17 +204,24 @@ carglist ::= carglist carg.
carglist ::= .
carg ::= CONSTRAINT nm ccons.
carg ::= ccons.
carg ::= DEFAULT ids(X). {sqlite3AddDefaultValue(pParse,&X,0);}
carg ::= DEFAULT plus_num(X). {sqlite3AddDefaultValue(pParse,&X,0);}
carg ::= DEFAULT minus_num(X). {sqlite3AddDefaultValue(pParse,&X,1);}
carg ::= DEFAULT NULL.
carg ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,X);}
carg ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,X);}
carg ::= DEFAULT MINUS term(X). {
Expr *p = sqlite3Expr(TK_UMINUS, X, 0, 0);
sqlite3AddDefaultValue(pParse,p);
}
carg ::= DEFAULT id(X). {
Expr *p = sqlite3Expr(TK_STRING, 0, 0, &X);
sqlite3AddDefaultValue(pParse,p);
}
// 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 ::= PRIMARY KEY sortorder onconf(R). {sqlite3AddPrimaryKey(pParse,0,R);}
ccons ::= PRIMARY KEY sortorder onconf(R) autoinc(I).
{sqlite3AddPrimaryKey(pParse,0,R,I);}
ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0);}
ccons ::= CHECK LP expr RP onconf.
ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
@ -214,6 +229,11 @@ ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);}
ccons ::= COLLATE id(C). {sqlite3AddCollateType(pParse, C.z, C.n);}
// The optional AUTOINCREMENT keyword
%type autoinc {int}
autoinc(X) ::= . {X = 0;}
autoinc(X) ::= AUTOINCR. {X = 1;}
// The next group of rules parses the arguments to a REFERENCES clause
// that determine if the referential integrity checking is deferred or
// or immediate and which determine what action to take if a ref-integ
@ -249,8 +269,8 @@ conslist ::= conslist COMMA tcons.
conslist ::= conslist tcons.
conslist ::= tcons.
tcons ::= CONSTRAINT nm.
tcons ::= PRIMARY KEY LP idxlist(X) RP onconf(R).
{sqlite3AddPrimaryKey(pParse,X,R);}
tcons ::= PRIMARY KEY LP idxlist(X) autoinc(I) RP onconf(R).
{sqlite3AddPrimaryKey(pParse,X,R,I);}
tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
{sqlite3CreateIndex(pParse,0,0,0,X,R,0,0);}
tcons ::= CHECK expr onconf.
@ -285,12 +305,14 @@ cmd ::= DROP TABLE fullname(X). {
///////////////////// The CREATE VIEW statement /////////////////////////////
//
%ifndef SQLITE_OMIT_VIEW
cmd ::= CREATE(X) temp(T) VIEW nm(Y) dbnm(Z) AS select(S). {
sqlite3CreateView(pParse, &X, &Y, &Z, S, T);
}
cmd ::= DROP VIEW fullname(X). {
sqlite3DropTable(pParse, X, 1);
}
%endif // SQLITE_OMIT_VIEW
//////////////////////// The SELECT statement /////////////////////////////////
//
@ -305,6 +327,7 @@ cmd ::= select(X). {
%destructor oneselect {sqlite3SelectDelete($$);}
select(A) ::= oneselect(X). {A = X;}
%ifndef SQLITE_OMIT_COMPOUND_SELECT
select(A) ::= select(X) multiselect_op(Y) oneselect(Z). {
if( Z ){
Z->op = Y;
@ -317,9 +340,10 @@ multiselect_op(A) ::= UNION(OP). {A = @OP;}
multiselect_op(A) ::= UNION ALL. {A = TK_ALL;}
multiselect_op(A) ::= INTERSECT(OP). {A = @OP;}
multiselect_op(A) ::= EXCEPT(OP). {A = @OP;}
%endif // SQLITE_OMIT_COMPOUND_SELECT
oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
A = sqlite3SelectNew(W,X,Y,P,Q,Z,D,L.limit,L.offset);
A = sqlite3SelectNew(W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset);
}
// The "distinct" nonterminal is true (1) if the DISTINCT keyword is
@ -394,31 +418,33 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
else { sqlite3IdListDelete(U); }
}
}
seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP
as(Z) on_opt(N) using_opt(U). {
A = sqlite3SrcListAppend(X,0,0);
A->a[A->nSrc-1].pSelect = S;
if( Z.n ) sqlite3SrcListAddAlias(A,&Z);
if( N ){
if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; }
else { sqlite3ExprDelete(N); }
%ifndef SQLITE_OMIT_SUBQUERY
seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP
as(Z) on_opt(N) using_opt(U). {
A = sqlite3SrcListAppend(X,0,0);
A->a[A->nSrc-1].pSelect = S;
if( Z.n ) sqlite3SrcListAddAlias(A,&Z);
if( N ){
if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; }
else { sqlite3ExprDelete(N); }
}
if( U ){
if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; }
else { sqlite3IdListDelete(U); }
}
}
if( U ){
if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; }
else { sqlite3IdListDelete(U); }
// A seltablist_paren nonterminal represents anything in a FROM that
// is contained inside parentheses. This can be either a subquery or
// a grouping of table and subqueries.
//
%type seltablist_paren {Select*}
%destructor seltablist_paren {sqlite3SelectDelete($$);}
seltablist_paren(A) ::= select(S). {A = S;}
seltablist_paren(A) ::= seltablist(F). {
A = sqlite3SelectNew(0,F,0,0,0,0,0,0,0);
}
}
// A seltablist_paren nonterminal represents anything in a FROM that
// is contained inside parentheses. This can be either a subquery or
// a grouping of table and subqueries.
//
%type seltablist_paren {Select*}
%destructor seltablist_paren {sqlite3SelectDelete($$);}
seltablist_paren(A) ::= select(S). {A = S;}
seltablist_paren(A) ::= seltablist(F). {
A = sqlite3SelectNew(0,F,0,0,0,0,0,-1,0);
}
%endif // SQLITE_OMIT_SUBQUERY
%type dbnm {Token}
dbnm(A) ::= . {A.z=0; A.n=0;}
@ -487,12 +513,16 @@ having_opt(A) ::= . {A = 0;}
having_opt(A) ::= HAVING expr(X). {A = X;}
%type limit_opt {struct LimitVal}
limit_opt(A) ::= . {A.limit = -1; A.offset = 0;}
limit_opt(A) ::= LIMIT signed(X). {A.limit = X; A.offset = 0;}
limit_opt(A) ::= LIMIT signed(X) OFFSET signed(Y).
{A.limit = X; A.offset = Y;}
limit_opt(A) ::= LIMIT signed(X) COMMA signed(Y).
{A.limit = Y; A.offset = X;}
%destructor limit_opt {
sqlite3ExprDelete($$.pLimit);
sqlite3ExprDelete($$.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) ::= LIMIT expr(X) OFFSET expr(Y).
{A.pLimit = X; A.pOffset = Y;}
limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y).
{A.pOffset = X; A.pLimit = Y;}
/////////////////////////// The DELETE statement /////////////////////////////
//
@ -550,9 +580,12 @@ inscollist(A) ::= nm(Y). {A = sqlite3IdListAppend(0,&Y);}
%type expr {Expr*}
%destructor expr {sqlite3ExprDelete($$);}
%type term {Expr*}
%destructor term {sqlite3ExprDelete($$);}
expr(A) ::= term(X). {A = X;}
expr(A) ::= LP(B) expr(X) RP(E). {A = X; sqlite3ExprSpan(A,&B,&E); }
expr(A) ::= NULL(X). {A = sqlite3Expr(@X, 0, 0, &X);}
term(A) ::= NULL(X). {A = sqlite3Expr(@X, 0, 0, &X);}
expr(A) ::= ID(X). {A = sqlite3Expr(TK_ID, 0, 0, &X);}
expr(A) ::= JOIN_KW(X). {A = sqlite3Expr(TK_ID, 0, 0, &X);}
expr(A) ::= nm(X) DOT nm(Y). {
@ -567,10 +600,11 @@ expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
Expr *temp4 = sqlite3Expr(TK_DOT, temp2, temp3, 0);
A = sqlite3Expr(TK_DOT, temp1, temp4, 0);
}
expr(A) ::= INTEGER(X). {A = sqlite3Expr(@X, 0, 0, &X);}
expr(A) ::= FLOAT(X). {A = sqlite3Expr(@X, 0, 0, &X);}
expr(A) ::= STRING(X). {A = sqlite3Expr(@X, 0, 0, &X);}
term(A) ::= INTEGER(X). {A = sqlite3Expr(@X, 0, 0, &X);}
term(A) ::= FLOAT(X). {A = sqlite3Expr(@X, 0, 0, &X);}
term(A) ::= STRING(X). {A = sqlite3Expr(@X, 0, 0, &X);}
expr(A) ::= BLOB(X). {A = sqlite3Expr(@X, 0, 0, &X);}
expr(A) ::= REGISTER(X). {A = sqlite3RegisterExpr(pParse, &X);}
expr(A) ::= VARIABLE(X). {
Token *pToken = &X;
Expr *pExpr = A = sqlite3Expr(TK_VARIABLE, 0, 0, pToken);
@ -584,6 +618,9 @@ expr(A) ::= ID(X) LP STAR RP(E). {
A = sqlite3ExprFunction(0, &X);
sqlite3ExprSpan(A,&X,&E);
}
term(A) ::= CTIME(OP). {A = sqlite3Expr(@OP,0,0,0);}
term(A) ::= CDATE(OP). {A = sqlite3Expr(@OP,0,0,0);}
term(A) ::= CTIMESTAMP(OP). {A = sqlite3Expr(@OP,0,0,0);}
expr(A) ::= expr(X) AND(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) OR(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) LT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
@ -607,14 +644,21 @@ likeop(A) ::= LIKE. {A.opcode = TK_LIKE; A.not = 0;}
likeop(A) ::= GLOB. {A.opcode = TK_GLOB; A.not = 0;}
likeop(A) ::= NOT LIKE. {A.opcode = TK_LIKE; A.not = 1;}
likeop(A) ::= NOT GLOB. {A.opcode = TK_GLOB; A.not = 1;}
expr(A) ::= expr(X) likeop(OP) expr(Y). [LIKE] {
%type escape {Expr*}
escape(X) ::= ESCAPE expr(A). [ESCAPE] {X = A;}
escape(X) ::= . [ESCAPE] {X = 0;}
expr(A) ::= expr(X) likeop(OP) expr(Y) escape(E). [LIKE] {
ExprList *pList = sqlite3ExprListAppend(0, Y, 0);
pList = sqlite3ExprListAppend(pList, X, 0);
if( E ){
pList = sqlite3ExprListAppend(pList, E, 0);
}
A = sqlite3ExprFunction(pList, 0);
if( A ) A->op = OP.opcode;
if( OP.not ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A, &X->span, &Y->span);
}
expr(A) ::= expr(X) ISNULL(E). {
A = sqlite3Expr(TK_ISNULL, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
@ -651,11 +695,6 @@ expr(A) ::= PLUS(B) expr(X). [UPLUS] {
A = sqlite3Expr(TK_UPLUS, X, 0, 0);
sqlite3ExprSpan(A,&B,&X->span);
}
expr(A) ::= LP(B) select(X) RP(E). {
A = sqlite3Expr(TK_SELECT, 0, 0, 0);
if( A ) A->pSelect = X;
sqlite3ExprSpan(A,&B,&E);
}
%type between_op {int}
between_op(A) ::= BETWEEN. {A = 0;}
between_op(A) ::= NOT BETWEEN. {A = 1;}
@ -667,29 +706,42 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&W->span,&Y->span);
}
%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 = sqlite3Expr(TK_IN, X, 0, 0);
if( A ) A->pList = Y;
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] {
A = sqlite3Expr(TK_IN, X, 0, 0);
if( A ) A->pSelect = Y;
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] {
SrcList *pSrc = sqlite3SrcListAppend(0,&Y,&Z);
A = sqlite3Expr(TK_IN, X, 0, 0);
if( A ) A->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,-1,0);
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,Z.z?&Z:&Y);
}
%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 = sqlite3Expr(TK_IN, X, 0, 0);
if( A ) A->pList = Y;
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= LP(B) select(X) RP(E). {
A = sqlite3Expr(TK_SELECT, 0, 0, 0);
if( A ) A->pSelect = X;
sqlite3ExprSpan(A,&B,&E);
}
expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] {
A = sqlite3Expr(TK_IN, X, 0, 0);
if( A ) A->pSelect = Y;
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] {
SrcList *pSrc = sqlite3SrcListAppend(0,&Y,&Z);
A = sqlite3Expr(TK_IN, X, 0, 0);
if( A ) A->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0);
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,Z.z?&Z:&Y);
}
expr(A) ::= EXISTS(B) LP select(Y) RP(E). {
Expr *p = A = sqlite3Expr(TK_EXISTS, 0, 0, 0);
if( p ){
p->pSelect = Y;
sqlite3ExprSpan(p,&B,&E);
}
}
%endif // SQLITE_OMIT_SUBQUERY
/* CASE expressions */
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
@ -728,10 +780,10 @@ expritem(A) ::= . {A = 0;}
///////////////////////////// The CREATE INDEX command ///////////////////////
//
cmd ::= CREATE(S) uniqueflag(U) INDEX nm(X) dbnm(D)
ON fullname(Y) LP idxlist(Z) RP(E) onconf(R). {
ON nm(Y) LP idxlist(Z) RP(E) onconf(R). {
if( U!=OE_None ) U = R;
if( U==OE_Default) U = OE_Abort;
sqlite3CreateIndex(pParse, &X, &D, Y, Z, U, &S, &E);
sqlite3CreateIndex(pParse, &X, &D, sqlite3SrcListAppend(0,&Y,0),Z,U, &S, &E);
}
%type uniqueflag {int}
@ -776,6 +828,7 @@ cmd ::= VACUUM nm. {sqlite3Vacuum(pParse,0);}
///////////////////////////// The PRAGMA command /////////////////////////////
//
%ifndef SQLITE_OMIT_PRAGMA
cmd ::= PRAGMA nm(X) dbnm(Z) EQ nm(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ ON(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ plus_num(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
@ -784,6 +837,7 @@ cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y). {
}
cmd ::= PRAGMA nm(X) dbnm(Z) LP nm(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);}
%endif // SQLITE_OMIT_PRAGMA
plus_num(A) ::= plus_opt number(X). {A = X;}
minus_num(A) ::= MINUS number(X). {A = X;}
number(A) ::= INTEGER(X). {A = X;}
@ -793,6 +847,8 @@ plus_opt ::= .
//////////////////////////// The CREATE TRIGGER command /////////////////////
%ifndef SQLITE_OMIT_TRIGGER
cmd ::= CREATE trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). {
Token all;
all.z = A.z;
@ -869,6 +925,8 @@ expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
A->iColumn = T;
sqlite3ExprSpan(A, &X, &Y);
}
%endif // !SQLITE_OMIT_TRIGGER
%type raisetype {int}
raisetype(A) ::= ROLLBACK. {A = OE_Rollback;}
raisetype(A) ::= ABORT. {A = OE_Abort;}
@ -876,9 +934,11 @@ raisetype(A) ::= FAIL. {A = OE_Fail;}
//////////////////////// DROP TRIGGER statement //////////////////////////////
%ifndef SQLITE_OMIT_TRIGGER
cmd ::= DROP TRIGGER fullname(X). {
sqlite3DropTrigger(pParse,X);
}
%endif // !SQLITE_OMIT_TRIGGER
//////////////////////// ATTACH DATABASE file AS name /////////////////////////
cmd ::= ATTACH database_kw_opt ids(F) AS nm(D) key_opt(K). {
@ -896,3 +956,16 @@ database_kw_opt ::= .
cmd ::= DETACH database_kw_opt nm(D). {
sqlite3Detach(pParse, &D);
}
////////////////////////// REINDEX collation //////////////////////////////////
%ifndef SQLITE_OMIT_REINDEX
cmd ::= REINDEX. {sqlite3Reindex(pParse, 0, 0);}
cmd ::= REINDEX nm(X) dbnm(Y). {sqlite3Reindex(pParse, &X, &Y);}
%endif
//////////////////////// ALTER TABLE table ... ////////////////////////////////
%ifndef SQLITE_OMIT_ALTERTABLE
cmd ::= ALTER TABLE fullname(X) RENAME TO nm(Z). {
sqlite3AlterRenameTable(pParse,X,&Z);
}
%endif

View File

@ -14,29 +14,18 @@
** $Id$
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
/* Ignore this whole file if pragmas are disabled
*/
#ifndef SQLITE_OMIT_PRAGMA
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
# include "pager.h"
# include "btree.h"
#endif
/*
** Interpret the given string as a boolean value.
*/
static int getBoolean(const u8 *z){
static const u8 *azTrue[] = { "yes", "on", "true" };
int i;
if( z[0]==0 ) return 0;
if( sqlite3IsNumber(z, 0, SQLITE_UTF8) ){
return atoi(z);
}
for(i=0; i<sizeof(azTrue)/sizeof(azTrue[0]); i++){
if( sqlite3StrICmp(z,azTrue[i])==0 ) return 1;
}
return 0;
}
/*
** Interpret the given string as a safety level. Return 0 for OFF,
** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or
@ -47,30 +36,33 @@ static int getBoolean(const u8 *z){
** to support legacy SQL code. The safety level used to be boolean
** and older scripts may have used numbers 0 for OFF and 1 for ON.
*/
static int getSafetyLevel(u8 *z){
static const struct {
const u8 *zWord;
int val;
} aKey[] = {
{ "no", 0 },
{ "off", 0 },
{ "false", 0 },
{ "yes", 1 },
{ "on", 1 },
{ "true", 1 },
{ "full", 2 },
};
int i;
if( z[0]==0 ) return 1;
if( sqlite3IsNumber(z, 0, SQLITE_UTF8) ){
static int getSafetyLevel(const u8 *z){
/* 123456789 123456789 */
static const char zText[] = "onoffalseyestruefull";
static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16};
static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4};
static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 2};
int i, n;
if( isdigit(*z) ){
return atoi(z);
}
for(i=0; i<sizeof(aKey)/sizeof(aKey[0]); i++){
if( sqlite3StrICmp(z,aKey[i].zWord)==0 ) return aKey[i].val;
n = strlen(z);
for(i=0; i<sizeof(iLength); i++){
if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0 ){
return iValue[i];
}
}
return 1;
}
/*
** Interpret the given string as a boolean value.
*/
static int getBoolean(const u8 *z){
return getSafetyLevel(z)&1;
}
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** Interpret the given string as a temp db location. Return 1 for file
** backed temporary databases, 2 for the Red-Black tree in memory database
@ -89,14 +81,11 @@ static int getTempStore(const char *z){
}
/*
** If the TEMP database is open, close it and mark the database schema
** as needing reloading. This must be done when using the TEMP_STORE
** or DEFAULT_TEMP_STORE pragmas.
** Invalidate temp storage, either when the temp storage is changed
** from default, or when 'file' and the temp_store_directory has changed
*/
static int changeTempStorage(Parse *pParse, const char *zStorageType){
int ts = getTempStore(zStorageType);
static int invalidateTempStorage(Parse *pParse){
sqlite3 *db = pParse->db;
if( db->temp_store==ts ) return SQLITE_OK;
if( db->aDb[1].pBt!=0 ){
if( db->flags & SQLITE_InTrans ){
sqlite3ErrorMsg(pParse, "temporary storage cannot be changed "
@ -107,9 +96,25 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){
db->aDb[1].pBt = 0;
sqlite3ResetInternalSchema(db, 0);
}
return SQLITE_OK;
}
/*
** If the TEMP database is open, close it and mark the database schema
** as needing reloading. This must be done when using the TEMP_STORE
** or DEFAULT_TEMP_STORE pragmas.
*/
static int changeTempStorage(Parse *pParse, const char *zStorageType){
int ts = getTempStore(zStorageType);
sqlite3 *db = pParse->db;
if( db->temp_store==ts ) return SQLITE_OK;
if( invalidateTempStorage( pParse ) != SQLITE_OK ){
return SQLITE_ERROR;
}
db->temp_store = ts;
return SQLITE_OK;
}
#endif
/*
** Generate code to return a single integer value.
@ -130,35 +135,42 @@ static void returnSingleInt(Parse *pParse, const char *zLabel, int value){
** Also, implement the pragma.
*/
static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
static const struct {
static const struct sPragmaType {
const char *zName; /* Name of the pragma */
int mask; /* Mask for the db->flags value */
} aPragma[] = {
{ "vdbe_trace", SQLITE_VdbeTrace },
{ "sql_trace", SQLITE_SqlTrace },
{ "vdbe_listing", SQLITE_VdbeListing },
#if 1 /* FIX ME: Remove the following pragmas */
{ "full_column_names", SQLITE_FullColNames },
{ "short_column_names", SQLITE_ShortColNames },
{ "count_changes", SQLITE_CountRows },
{ "empty_result_callbacks", SQLITE_NullCallback },
#endif
/* The following is VERY experimental */
{ "writable_schema", SQLITE_WriteSchema },
{ "omit_readlock", SQLITE_NoReadlock },
};
int i;
for(i=0; i<sizeof(aPragma)/sizeof(aPragma[0]); i++){
if( sqlite3StrICmp(zLeft, aPragma[i].zName)==0 ){
const struct sPragmaType *p;
for(i=0, p=aPragma; i<sizeof(aPragma)/sizeof(aPragma[0]); i++, p++){
if( sqlite3StrICmp(zLeft, p->zName)==0 ){
sqlite3 *db = pParse->db;
Vdbe *v;
if( zRight==0 ){
v = sqlite3GetVdbe(pParse);
if( v ){
returnSingleInt(pParse,
aPragma[i].zName, (db->flags&aPragma[i].mask)!=0);
v = sqlite3GetVdbe(pParse);
if( v ){
if( zRight==0 ){
returnSingleInt(pParse, p->zName, (db->flags & p->mask)!=0 );
}else{
if( getBoolean(zRight) ){
db->flags |= p->mask;
}else{
db->flags &= ~p->mask;
}
}
}else if( getBoolean(zRight) ){
db->flags |= aPragma[i].mask;
}else{
db->flags &= ~aPragma[i].mask;
/* If one of these pragmas is executed, any prepared statements
** need to be recompiled.
*/
sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
}
return 1;
}
@ -217,6 +229,7 @@ void sqlite3Pragma(
goto pragma_out;
}
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** PRAGMA [database.]default_cache_size
** PRAGMA [database.]default_cache_size=N
@ -281,10 +294,31 @@ void sqlite3Pragma(
int size = pBt ? sqlite3BtreeGetPageSize(pBt) : 0;
returnSingleInt(pParse, "page_size", size);
}else{
sqlite3BtreeSetPageSize(pBt, atoi(zRight), sqlite3BtreeGetReserve(pBt));
sqlite3BtreeSetPageSize(pBt, atoi(zRight), -1);
}
}else
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
/*
** PRAGMA [database.]auto_vacuum
** PRAGMA [database.]auto_vacuum=N
**
** Get or set the (boolean) value of the database 'auto-vacuum' parameter.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
if( sqlite3StrICmp(zLeft,"auto_vacuum")==0 ){
Btree *pBt = pDb->pBt;
if( !zRight ){
int auto_vacuum =
pBt ? sqlite3BtreeGetAutoVacuum(pBt) : SQLITE_DEFAULT_AUTOVACUUM;
returnSingleInt(pParse, "auto_vacuum", auto_vacuum);
}else{
sqlite3BtreeSetAutoVacuum(pBt, getBoolean(zRight));
}
}else
#endif
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** PRAGMA [database.]cache_size
** PRAGMA [database.]cache_size=N
@ -330,6 +364,45 @@ void sqlite3Pragma(
}
}else
/*
** PRAGMA temp_store_directory
** PRAGMA temp_store_directory = ""|"directory_name"
**
** Return or set the local value of the temp_store_directory flag. Changing
** the value sets a specific directory to be used for temporary files.
** Setting to a null string reverts to the default temporary directory search.
** If temporary directory is changed, then invalidateTempStorage.
**
*/
if( sqlite3StrICmp(zLeft, "temp_store_directory")==0 ){
if( !zRight ){
if( sqlite3_temp_directory ){
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, "temp_store_directory", P3_STATIC);
sqlite3VdbeOp3(v, OP_String8, 0, 0, sqlite3_temp_directory, 0);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
}
}else{
if( zRight[0] && !sqlite3OsIsDirWritable(zRight) ){
sqlite3ErrorMsg(pParse, "not a writable directory");
goto pragma_out;
}
if( TEMP_STORE==0
|| (TEMP_STORE==1 && db->temp_store<=1)
|| (TEMP_STORE==2 && db->temp_store==1)
){
invalidateTempStorage(pParse);
}
sqliteFree(sqlite3_temp_directory);
if( zRight[0] ){
sqlite3_temp_directory = zRight;
zRight = 0;
}else{
sqlite3_temp_directory = 0;
}
}
}else
/*
** PRAGMA [database.]synchronous
** PRAGMA [database.]synchronous=OFF|ON|NORMAL|FULL
@ -353,22 +426,14 @@ void sqlite3Pragma(
}
}
}else
#if 0 /* Used once during development. No longer needed */
if( sqlite3StrICmp(zLeft, "trigger_overhead_test")==0 ){
if( getBoolean(zRight) ){
sqlite3_always_code_trigger_setup = 1;
}else{
sqlite3_always_code_trigger_setup = 0;
}
}else
#endif
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
if( flagPragma(pParse, zLeft, zRight) ){
/* The flagPragma() subroutine also generates any necessary code
** there is nothing more to do here */
}else
#ifndef SQLITE_OMIT_SCHEMA_PRAGMAS
/*
** PRAGMA table_info(<table>)
**
@ -401,8 +466,7 @@ void sqlite3Pragma(
sqlite3VdbeOp3(v, OP_String8, 0, 0,
pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", 0);
sqlite3VdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
pTab->aCol[i].zDflt, P3_STATIC);
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);
sqlite3VdbeAddOp(v, OP_Integer, pTab->aCol[i].isPrimKey, 0);
sqlite3VdbeAddOp(v, OP_Callback, 6, 0);
}
@ -458,6 +522,40 @@ void sqlite3Pragma(
}
}else
if( sqlite3StrICmp(zLeft, "database_list")==0 ){
int i;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 3);
sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
sqlite3VdbeSetColName(v, 2, "file", P3_STATIC);
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt==0 ) continue;
assert( db->aDb[i].zName!=0 );
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
sqlite3BtreeGetFilename(db->aDb[i].pBt), 0);
sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
}
}else
if( sqlite3StrICmp(zLeft, "collation_list")==0 ){
int i = 0;
HashElem *p;
sqlite3VdbeSetNumCols(v, 2);
sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){
CollSeq *pColl = (CollSeq *)sqliteHashData(p);
sqlite3VdbeAddOp(v, OP_Integer, i++, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pColl->zName, 0);
sqlite3VdbeAddOp(v, OP_Callback, 2, 0);
}
}else
#endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */
#ifndef SQLITE_OMIT_FOREIGN_KEY
if( sqlite3StrICmp(zLeft, "foreign_key_list")==0 && zRight ){
FKey *pFK;
Table *pTab;
@ -491,24 +589,7 @@ void sqlite3Pragma(
}
}
}else
if( sqlite3StrICmp(zLeft, "database_list")==0 ){
int i;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 3);
sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
sqlite3VdbeSetColName(v, 2, "file", P3_STATIC);
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt==0 ) continue;
assert( db->aDb[i].zName!=0 );
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
sqlite3BtreeGetFilename(db->aDb[i].pBt), 0);
sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
}
}else
#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
#ifndef NDEBUG
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
@ -521,6 +602,7 @@ void sqlite3Pragma(
}else
#endif
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
int i, j, addr;
@ -645,6 +727,9 @@ void sqlite3Pragma(
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
sqlite3VdbeChangeP2(v, addr+2, addr+ArraySize(endCode));
}else
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
#ifndef SQLITE_OMIT_UTF16
/*
** PRAGMA encoding
** PRAGMA encoding = "utf-8"|"utf-16"|"utf-16le"|"utf-16be"
@ -715,6 +800,69 @@ void sqlite3Pragma(
}
}
}else
#endif /* SQLITE_OMIT_UTF16 */
#ifndef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
/*
** PRAGMA [database.]schema_version
** PRAGMA [database.]schema_version = <integer>
**
** PRAGMA [database.]user_version
** PRAGMA [database.]user_version = <integer>
**
** The pragma's schema_version and user_version are used to set or get
** the value of the schema-version and user-version, respectively. Both
** the schema-version and the user-version are 32-bit signed integers
** stored in the database header.
**
** The schema-cookie is usually only manipulated internally by SQLite. It
** is incremented by SQLite whenever the database schema is modified (by
** creating or dropping a table or index). The schema version is used by
** SQLite each time a query is executed to ensure that the internal cache
** of the schema used when compiling the SQL query matches the schema of
** the database against which the compiled query is actually executed.
** Subverting this mechanism by using "PRAGMA schema_version" to modify
** the schema-version is potentially dangerous and may lead to program
** crashes or database corruption. Use with caution!
**
** The user-version is not used internally by SQLite. It may be used by
** applications for any purpose.
*/
if( sqlite3StrICmp(zLeft, "schema_version")==0 ||
sqlite3StrICmp(zLeft, "user_version")==0 ){
int iCookie; /* Cookie index. 0 for schema-cookie, 6 for user-cookie. */
if( zLeft[0]=='s' || zLeft[0]=='S' ){
iCookie = 0;
}else{
iCookie = 5;
}
if( zRight ){
/* Write the specified cookie value */
static const VdbeOpList setCookie[] = {
{ OP_Transaction, 0, 1, 0}, /* 0 */
{ OP_Integer, 0, 0, 0}, /* 1 */
{ OP_SetCookie, 0, 0, 0}, /* 2 */
};
int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie);
sqlite3VdbeChangeP1(v, addr, iDb);
sqlite3VdbeChangeP1(v, addr+1, atoi(zRight));
sqlite3VdbeChangeP1(v, addr+2, iDb);
sqlite3VdbeChangeP2(v, addr+2, iCookie);
}else{
/* Read the specified cookie value */
static const VdbeOpList readCookie[] = {
{ OP_ReadCookie, 0, 0, 0}, /* 0 */
{ OP_Callback, 1, 0, 0}
};
int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie);
sqlite3VdbeChangeP1(v, addr, iDb);
sqlite3VdbeChangeP2(v, addr, iCookie);
sqlite3VdbeSetNumCols(v, 1);
}
}
#endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/*
@ -748,7 +896,17 @@ void sqlite3Pragma(
#endif
{}
if( v ){
/* Code an OP_Expire at the end of each PRAGMA program to cause
** the VDBE implementing the pragma to expire. Most (all?) pragmas
** are only valid for a single execution.
*/
sqlite3VdbeAddOp(v, OP_Expire, 1, 0);
}
pragma_out:
sqliteFree(zLeft);
sqliteFree(zRight);
}
#endif /* SQLITE_OMIT_PRAGMA */

View File

@ -99,6 +99,7 @@ typedef struct et_info { /* Information about each format field */
*/
#define FLAG_SIGNED 1 /* True if the value to convert is signed */
#define FLAG_INTERN 2 /* True if for internal use only */
#define FLAG_STRING 4 /* Allow infinity precision */
/*
@ -109,10 +110,10 @@ static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
static const char aPrefix[] = "-x0\000X0";
static const et_info fmtinfo[] = {
{ 'd', 10, 1, etRADIX, 0, 0 },
{ 's', 0, 0, etSTRING, 0, 0 },
{ 'z', 0, 2, etDYNSTRING, 0, 0 },
{ 'q', 0, 0, etSQLESCAPE, 0, 0 },
{ 'Q', 0, 0, etSQLESCAPE2, 0, 0 },
{ 's', 0, 4, etSTRING, 0, 0 },
{ 'z', 0, 6, etDYNSTRING, 0, 0 },
{ 'q', 0, 4, etSQLESCAPE, 0, 0 },
{ 'Q', 0, 4, etSQLESCAPE2, 0, 0 },
{ 'c', 0, 0, etCHARX, 0, 0 },
{ 'o', 8, 0, etRADIX, 0, 2 },
{ 'u', 10, 0, etRADIX, 0, 0 },
@ -296,8 +297,6 @@ static int vxprintf(
c = *++fmt;
}
}
/* Limit the precision to prevent overflowing buf[] during conversion */
if( precision>etBUFSIZE-40 ) precision = etBUFSIZE-40;
}else{
precision = -1;
}
@ -328,6 +327,11 @@ static int vxprintf(
}
zExtra = 0;
/* Limit the precision to prevent overflowing buf[] during conversion */
if( precision>etBUFSIZE-40 && (infop->flags & FLAG_STRING)==0 ){
precision = etBUFSIZE-40;
}
/*
** At this point, variables are initialized as follows:
**
@ -563,13 +567,15 @@ static int vxprintf(
case etSQLESCAPE2:
{
int i, j, n, c, isnull;
int needQuote;
char *arg = va_arg(ap,char*);
isnull = arg==0;
if( isnull ) arg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
for(i=n=0; (c=arg[i])!=0; i++){
if( c=='\'' ) n++;
}
n += i + 1 + ((!isnull && xtype==etSQLESCAPE2) ? 2 : 0);
needQuote = !isnull && xtype==etSQLESCAPE2;
n += i + 1 + needQuote*2;
if( n>etBUFSIZE ){
bufpt = zExtra = sqliteMalloc( n );
if( bufpt==0 ) return -1;
@ -577,12 +583,12 @@ static int vxprintf(
bufpt = buf;
}
j = 0;
if( !isnull && xtype==etSQLESCAPE2 ) bufpt[j++] = '\'';
if( needQuote ) bufpt[j++] = '\'';
for(i=0; (c=arg[i])!=0; i++){
bufpt[j++] = c;
if( c=='\'' ) bufpt[j++] = c;
}
if( !isnull && xtype==etSQLESCAPE2 ) bufpt[j++] = '\'';
if( needQuote ) bufpt[j++] = '\'';
bufpt[j] = 0;
length = j;
if( precision>=0 && precision<length ) length = precision;

File diff suppressed because it is too large Load Diff

View File

@ -196,7 +196,9 @@ static char *one_input_line(const char *zPrior, FILE *in){
zPrompt = mainPrompt;
}
zResult = readline(zPrompt);
#if defined(HAVE_READLINE) && HAVE_READLINE==1
if( zResult ) add_history(zResult);
#endif
return zResult;
}
@ -360,6 +362,7 @@ static void output_csv(struct callback_data *p, const char *z, int bSep){
}
}
#ifdef SIGINT
/*
** This routine runs when the user presses Ctrl-C
*/
@ -367,6 +370,7 @@ static void interrupt_handler(int NotUsed){
seenInterrupt = 1;
if( db ) sqlite3_interrupt(db);
}
#endif
/*
** This is the callback routine that the SQLite library
@ -652,7 +656,11 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
zType = azArg[1];
zSql = azArg[2];
fprintf(p->out, "%s;\n", zSql);
if( strcasecmp(zTable,"sqlite_sequence")!=0 ){
fprintf(p->out, "%s;\n", zSql);
}else{
fprintf(p->out, "DELETE FROM sqlite_sequence;\n");
}
if( strcmp(zType, "table")==0 ){
sqlite3_stmt *pTableInfo = 0;
@ -746,7 +754,7 @@ static char zHelp[] =
".help Show this message\n"
".import FILE TABLE Import data from FILE into TABLE\n"
".indices TABLE Show names of all indices on TABLE\n"
".mode MODE ?TABLE? Set output mode where MODE is on of:\n"
".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
" csv Comma-separated values\n"
" column Left-aligned columns. (See .width)\n"
" html HTML <table> code\n"
@ -882,6 +890,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
data.colWidth[0] = 3;
data.colWidth[1] = 15;
data.colWidth[2] = 58;
data.cnt = 0;
sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
if( zErrMsg ){
fprintf(stderr,"Error: %s\n", zErrMsg);
@ -1677,7 +1686,11 @@ int main(int argc, char **argv){
if( i<argc ){
data.zDbFilename = argv[i++];
}else{
#ifndef SQLITE_OMIT_MEMORYDB
data.zDbFilename = ":memory:";
#else
data.zDbFilename = 0;
#endif
}
if( i<argc ){
zFirstCmd = argv[i++];
@ -1770,7 +1783,9 @@ int main(int argc, char **argv){
if( zHome && (zHistory = malloc(strlen(zHome)+20))!=0 ){
sprintf(zHistory,"%s/.sqlite_history", zHome);
}
#if defined(HAVE_READLINE) && HAVE_READLINE==1
if( zHistory ) read_history(zHistory);
#endif
process_input(&data, 0);
if( zHistory ){
stifle_history(100);

View File

@ -30,9 +30,25 @@ extern "C" {
*/
#ifdef SQLITE_VERSION
# undef SQLITE_VERSION
#else
# define SQLITE_VERSION "--VERS--"
#endif
#define SQLITE_VERSION "--VERS--"
/*
** The format of the version string is "X.Y.Z<trailing string>", where
** X is the major version number, Y is the minor version number and Z
** is the release number. The trailing string is often "alpha" or "beta".
** For example "3.1.1beta".
**
** The SQLITE_VERSION_NUMBER is an integer with the value
** (X*100000 + Y*1000 + Z). For example, for version "3.1.1beta",
** SQLITE_VERSION_NUMBER is set to 3001001. To detect if they are using
** version 3.1.1 or greater at compile time, programs may use the test
** (SQLITE_VERSION_NUMBER>=3001001).
*/
#ifdef SQLITE_VERSION_NUMBER
# undef SQLITE_VERSION_NUMBER
#endif
#define SQLITE_VERSION_NUMBER --VERSION-NUMBER--
/*
** The version string is also compiled into the library so that a program
@ -44,6 +60,12 @@ extern "C" {
extern const char sqlite3_version[];
const char *sqlite3_libversion(void);
/*
** Return the value of the SQLITE_VERSION_NUMBER macro when the
** library was compiled.
*/
int sqlite3_libversion_number(void);
/*
** Each open sqlite database is represented by an instance of the
** following opaque structure.
@ -309,7 +331,7 @@ int sqlite3_busy_timeout(sqlite3*, int ms);
** pass the result data pointer to sqlite3_free_table() in order to
** release the memory that was malloc-ed. Because of the way the
** malloc() happens, the calling function must not try to call
** malloc() directly. Only sqlite3_free_table() is able to release
** free() directly. Only sqlite3_free_table() is able to release
** the memory properly and safely.
**
** The return value of this routine is the same as from sqlite3_exec().
@ -428,6 +450,8 @@ int sqlite3_set_authorizer(
#define SQLITE_UPDATE 23 /* Table Name Column Name */
#define SQLITE_ATTACH 24 /* Filename NULL */
#define SQLITE_DETACH 25 /* Database Name NULL */
#define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */
#define SQLITE_REINDEX 27 /* Index Name NULL */
/*
@ -448,8 +472,8 @@ void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
/*
** This routine configures a callback function - the progress callback - that
** is invoked periodically during long running calls to sqlite3_exec(),
** sqlite3_step() and sqlite3_get_table(). An example use for this API is to keep
** a GUI updated during a large query.
** sqlite3_step() and sqlite3_get_table(). An example use for this API is to
** keep a GUI updated during a large query.
**
** The progress callback is invoked once for every N virtual machine opcodes,
** where N is the second argument to this function. The progress callback
@ -606,14 +630,19 @@ typedef struct Mem sqlite3_value;
/*
** In the SQL strings input to sqlite3_prepare() and sqlite3_prepare16(),
** one or more literals can be replace by a wildcard "?" or ":N:" where
** N is an integer. These value of these wildcard literals can be set
** using the routines listed below.
** one or more literals can be replace by parameters "?" or ":AAA" or
** "$VVV" where AAA is an identifer and VVV is a variable name according
** to the syntax rules of the TCL programming language.
** The value of these parameters (also called "host parameter names") can
** be set using the routines listed below.
**
** In every case, the first parameter is a pointer to the sqlite3_stmt
** structure returned from sqlite3_prepare(). The second parameter is the
** index of the wildcard. The first "?" has an index of 1. ":N:" wildcards
** use the index N.
** index of the parameter. The first parameter as an index of 1. For
** named parameters (":AAA" or "$VVV") you can use
** sqlite3_bind_parameter_index() to get the correct index value given
** the parameters name. If the same named parameter occurs more than
** once, it is assigned the same index each time.
**
** The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and
** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
@ -624,8 +653,8 @@ typedef struct Mem sqlite3_value;
** own private copy of the data.
**
** The sqlite3_bind_* routine must be called before sqlite3_step() after
** an sqlite3_prepare() or sqlite3_reset(). Unbound wildcards are interpreted
** as NULL.
** an sqlite3_prepare() or sqlite3_reset(). Unbound parameterss are
** interpreted as NULL.
*/
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
int sqlite3_bind_double(sqlite3_stmt*, int, double);
@ -637,16 +666,16 @@ int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
/*
** Return the number of wildcards in a compiled SQL statement. This
** Return the number of parameters in a compiled SQL statement. This
** routine was added to support DBD::SQLite.
*/
int sqlite3_bind_parameter_count(sqlite3_stmt*);
/*
** Return the name of the i-th parameter. Ordinary wildcards "?" are
** nameless and a NULL is returned. For wildcards of the form :N or
** $vvvv the complete text of the wildcard is returned.
** NULL is returned if the index is out of range.
** Return the name of the i-th parameter. Ordinary parameters "?" are
** nameless and a NULL is returned. For parameters of the form :AAA or
** $VVV the complete text of the parameter name is returned, including
** the initial ":" or "$". NULL is returned if the index is out of range.
*/
const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
@ -657,6 +686,13 @@ const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
*/
int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
/*
** Set all the parameters in the compiled SQL statement to NULL.
**
******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
*/
int sqlite3_clear_bindings(sqlite3_stmt*);
/*
** Return the number of columns in the result set returned by the compiled
** SQL statement. This routine returns 0 if pStmt is an SQL statement
@ -1148,17 +1184,41 @@ int sqlite3_rekey(
);
/*
** If the following global variable is made to point to a constant
** Sleep for a little while. The second parameter is the number of
** miliseconds to sleep for.
**
** If the operating system does not support sleep requests with
** milisecond time resolution, then the time will be rounded up to
** the nearest second. The number of miliseconds of sleep actually
** requested from the operating system is returned.
**
******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
*/
int sqlite3_sleep(int);
/*
** Return TRUE (non-zero) of the statement supplied as an argument needs
** to be recompiled. A statement needs to be recompiled whenever the
** execution environment changes in a way that would alter the program
** that sqlite3_prepare() generates. For example, if new functions or
** collating sequences are registered or if an authorizer function is
** added or changed.
**
******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
*/
int sqlite3_expired(sqlite3_stmt*);
/*
** If the following global variable is made to point to a
** string which is the name of a directory, then all temporary files
** created by SQLite will be placed in that directory. If this variable
** is NULL pointer, then SQLite does a search for an appropriate temporary
** file directory.
**
** This variable should only be changed when there are no open databases.
** Once sqlite3_open() has been called, this variable should not be changed
** until all database connections are closed.
** Once sqlite3_open() has been called, changing this variable will invalidate the
** current temporary database, if any.
*/
extern const char *sqlite3_temp_directory;
extern char *sqlite3_temp_directory;
#ifdef __cplusplus
} /* End of the 'extern "C"' block */

View File

@ -47,13 +47,25 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stddef.h>
/*
** The maximum number of in-memory pages to use for the main database
** table and for temporary tables.
** table and for temporary tables. Internally, the MAX_PAGES and
** TEMP_PAGES macros are used. To override the default values at
** compilation time, the SQLITE_DEFAULT_CACHE_SIZE and
** SQLITE_DEFAULT_TEMP_CACHE_SIZE macros should be set.
*/
#define MAX_PAGES 2000
#define TEMP_PAGES 500
#ifdef SQLITE_DEFAULT_CACHE_SIZE
# define MAX_PAGES SQLITE_DEFAULT_CACHE_SIZE
#else
# define MAX_PAGES 2000
#endif
#ifdef SQLITE_DEFAULT_TEMP_CACHE_SIZE
# define TEMP_PAGES SQLITE_DEFAULT_TEMP_CACHE_SIZE
#else
# define TEMP_PAGES 500
#endif
/*
** If the following macro is set to 1, then NULL values are considered
@ -102,10 +114,28 @@
** a minimum.
*/
/* #define SQLITE_OMIT_AUTHORIZATION 1 */
/* #define SQLITE_OMIT_INMEMORYDB 1 */
/* #define SQLITE_OMIT_MEMORYDB 1 */
/* #define SQLITE_OMIT_VACUUM 1 */
/* #define SQLITE_OMIT_DATETIME_FUNCS 1 */
/* #define SQLITE_OMIT_PROGRESS_CALLBACK 1 */
/* #define SQLITE_OMIT_AUTOVACUUM */
/* #define SQLITE_OMIT_ALTERTABLE */
/*
** Provide a default value for TEMP_STORE in case it is not specified
** on the command-line
*/
#ifndef TEMP_STORE
# define TEMP_STORE 1
#endif
/*
** GCC does not define the offsetof() macro so we'll have to do it
** ourselves.
*/
#ifndef offsetof
#define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD))
#endif
/*
** Integers of known sizes. These typedefs might change for architectures
@ -213,7 +243,7 @@ struct BusyHandler {
** each malloc() and free(). This output can be analyzed
** by an AWK script to determine if there are any leaks.
*/
#ifdef SQLITE_DEBUG
#ifdef SQLITE_MEMDEBUG
# define sqliteMalloc(X) sqlite3Malloc_(X,1,__FILE__,__LINE__)
# define sqliteMallocRaw(X) sqlite3Malloc_(X,0,__FILE__,__LINE__)
# define sqliteFree(X) sqlite3Free_(X,__FILE__,__LINE__)
@ -239,10 +269,11 @@ extern int sqlite3_malloc_failed;
** The following global variables are used for testing and debugging
** only. They only work if SQLITE_DEBUG is defined.
*/
#ifdef SQLITE_DEBUG
extern int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */
extern int sqlite3_nFree; /* Number of sqliteFree() calls */
extern int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */
#ifdef SQLITE_MEMDEBUG
extern int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */
extern int sqlite3_nFree; /* Number of sqliteFree() calls */
extern int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */
extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */
#endif
/*
@ -296,6 +327,8 @@ typedef struct AuthContext AuthContext;
typedef struct KeyClass KeyClass;
typedef struct CollSeq CollSeq;
typedef struct KeyInfo KeyInfo;
typedef struct NameContext NameContext;
typedef struct Fetch Fetch;
/*
** Each database file to be accessed by the system is an instance
@ -316,7 +349,8 @@ struct Db {
u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */
u8 safety_level; /* How aggressive at synching data to disk */
int cache_size; /* Number of pages to use in the cache */
void *pAux; /* Auxiliary data. Usually NULL */
Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */
void *pAux; /* Auxiliary data. Usually NULL */
void (*xFreeAux)(void*); /* Routine to free pAux */
};
@ -408,7 +442,6 @@ struct sqlite3 {
void *pProgressArg; /* Argument to the progress callback */
int nProgressOps; /* Number of opcodes for progress callback */
#endif
int errCode; /* Most recent error code (SQLITE_*) */
u8 enc; /* Text encoding for this database. */
u8 autoCommit; /* The auto-commit flag. */
@ -417,9 +450,8 @@ struct sqlite3 {
void *pCollNeededArg;
sqlite3_value *pValue; /* Value used for transient conversions */
sqlite3_value *pErr; /* Most recent error message */
char *zErrMsg; /* Most recent error message (UTF-8 encoded) */
char *zErrMsg16; /* Most recent error message (UTF-8 encoded) */
char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */
};
/*
@ -443,6 +475,9 @@ struct sqlite3 {
/* result set is empty */
#define SQLITE_SqlTrace 0x00000200 /* Debug print SQL as it executes */
#define SQLITE_VdbeListing 0x00000400 /* Debug listings of VDBE programs */
#define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */
#define SQLITE_NoReadlock 0x00001000 /* Readlocks are omitted when
** accessing read-only databases */
/*
** Possible values for the sqlite.magic field.
@ -478,7 +513,7 @@ struct FuncDef {
*/
struct Column {
char *zName; /* Name of this column */
char *zDflt; /* Default value of this column */
Expr *pDflt; /* Default value of this column */
char *zType; /* Data type for this column */
CollSeq *pColl; /* Collating sequence. If NULL, use the default */
u8 notNull; /* True if there is a NOT NULL constraint */
@ -572,6 +607,7 @@ struct Table {
u8 isTransient; /* True if automatically deleted when VDBE finishes */
u8 hasPrimKey; /* True if there exists a primary key */
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
u8 autoInc; /* True if the integer primary key is autoincrement */
Trigger *pTrigger; /* List of SQL triggers on this table */
FKey *pFKey; /* Linked list of all foreign keys in this table */
char *zColAff; /* String defining the affinity of each column */
@ -759,6 +795,12 @@ struct Token {
** marker (a question mark character '?' in the original SQL) then the
** Expr.iTable holds the index number for that variable.
**
** If the expression is a subquery then Expr.iColumn holds an integer
** register number containing the result of the subquery. If the
** subquery gives a constant result, then iTable is -1. If the subquery
** gives a different answer at different times during statement processing
** then iTable is the address of a subroutine that computes the subquery.
**
** The Expr.pSelect field points to a SELECT statement. The SELECT might
** be the right operand of an IN operator. Or, if a scalar SELECT appears
** in an expression the opcode is TK_SELECT and Expr.pSelect is the only
@ -777,8 +819,9 @@ struct Expr {
Token span; /* Complete text of the expression */
int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
** iColumn-th field of the iTable-th table. */
int iAgg; /* When op==TK_COLUMN and pParse->useAgg==TRUE, pull
int iAgg; /* When op==TK_COLUMN and pParse->fillAgg==FALSE, pull
** result from the iAgg-th element of the aggregator */
int iAggCtx; /* The value to pass as P1 of OP_AggGet. */
Select *pSelect; /* When the expression is a sub-select. Also the
** right side of "<expr> IN (<select>)" */
};
@ -787,6 +830,11 @@ struct Expr {
** The following are the meanings of bits in the Expr.flags field.
*/
#define EP_FromJoin 0x0001 /* Originated in ON or USING clause of a join */
#define EP_Agg 0x0002 /* Contains one or more aggregate functions */
#define EP_Resolved 0x0004 /* IDs have been resolved to COLUMNs */
#define EP_Error 0x0008 /* Expression contains one or more errors */
#define EP_Not 0x0010 /* Operator preceeded by NOT */
#define EP_VarSelect 0x0020 /* pSelect is correlated, not constant */
/*
** These macros can be used to test, set, or clear bits in the
@ -841,6 +889,11 @@ struct IdList {
} *a;
};
/*
** The bitmask datatype defined below is used for various optimizations.
*/
typedef unsigned int Bitmask;
/*
** The following structure describes the FROM clause of a SELECT statement.
** Each table or subquery in the FROM clause is a separate element of
@ -865,6 +918,7 @@ struct SrcList {
int iCursor; /* The VDBE cursor number used to access this table */
Expr *pOn; /* The ON clause of a join */
IdList *pUsing; /* The USING clause of a join */
Bitmask colUsed; /* Bit N (1<<N) set if column N or pTab is used */
} a[1]; /* One entry for each identifier on the list */
};
@ -886,9 +940,10 @@ struct SrcList {
*/
struct WhereLevel {
int iMem; /* Memory cell used by this level */
Index *pIdx; /* Index used */
int iCur; /* Cursor number used for this index */
int score; /* How well this indexed scored */
Index *pIdx; /* Index used. NULL if no index */
int iTabCur; /* The VDBE cursor used to access the table */
int iIdxCur; /* The VDBE cursor used to acesss pIdx */
int score; /* How well this index scored */
int brk; /* Jump here to break out of the loop */
int cont; /* Jump here to continue with the next loop cycle */
int op, p1, p2; /* Opcode used to terminate the loop */
@ -908,24 +963,50 @@ struct WhereLevel {
struct WhereInfo {
Parse *pParse;
SrcList *pTabList; /* List of tables in the join */
int iTop; /* The very beginning of the WHERE loop */
int iContinue; /* Jump here to continue with next record */
int iBreak; /* Jump here to break out of the loop */
int nLevel; /* Number of nested loop */
WhereLevel a[1]; /* Information about each nest loop in the WHERE */
};
/*
** A NameContext defines a context in which to resolve table and column
** names. The context consists of a list of tables (the pSrcList) field and
** a list of named expression (pEList). The named expression list may
** be NULL. The pSrc corresponds to the FROM clause of a SELECT or
** to the table being operated on by INSERT, UPDATE, or DELETE. The
** pEList corresponds to the result set of a SELECT and is NULL for
** other statements.
**
** NameContexts can be nested. When resolving names, the inner-most
** context is searched first. If no match is found, the next outer
** context is checked. If there is still no match, the next context
** is checked. This process continues until either a match is found
** or all contexts are check. When a match is found, the nRef member of
** the context containing the match is incremented.
**
** Each subquery gets a new NameContext. The pNext field points to the
** NameContext in the parent query. Thus the process of scanning the
** NameContext list corresponds to searching through successively outer
** subqueries looking for a match.
*/
struct NameContext {
Parse *pParse; /* The parser */
SrcList *pSrcList; /* One or more tables used to resolve names */
ExprList *pEList; /* Optional list of named expressions */
int nRef; /* Number of names resolved by this context */
int nErr; /* Number of errors encountered while resolving names */
u8 allowAgg; /* Aggregate functions allowed here */
u8 hasAgg;
int nDepth; /* Depth of subquery recursion. 1 for no recursion */
NameContext *pNext; /* Next outer name context. NULL for outermost */
};
/*
** An instance of the following structure contains all information
** needed to generate code for a single SELECT statement.
**
** The zSelect field is used when the Select structure must be persistent.
** Normally, the expression tree points to tokens in the original input
** string that encodes the select. But if the Select structure must live
** longer than its input string (for example when it is used to describe
** a VIEW) we have to make a copy of the input string so that the nodes
** of the expression tree will have something to point to. zSelect is used
** to hold that copy.
**
** nLimit is set to -1 if there is no LIMIT clause. nOffset is set to 0.
** If there is a LIMIT clause, the parser sets nLimit to the value of the
** limit and nOffset to the value of the offset (or 0 if there is not
@ -942,10 +1023,13 @@ struct Select {
Expr *pHaving; /* The HAVING clause */
ExprList *pOrderBy; /* The ORDER BY clause */
Select *pPrior; /* Prior select in a compound select statement */
int nLimit, nOffset; /* LIMIT and OFFSET values. -1 means not used */
Expr *pLimit; /* LIMIT expression. NULL means not used. */
Expr *pOffset; /* OFFSET expression. NULL means not used. */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
char *zSelect; /* Complete text of the SELECT command */
IdList **ppOpenTemp; /* OP_OpenTemp addresses used by multi-selects */
Fetch *pFetch; /* If this stmt is part of a FETCH command */
u8 isResolved; /* True once sqlite3SelectResolve() has run. */
u8 isAgg; /* True if this is an aggregate query */
};
/*
@ -961,6 +1045,7 @@ struct Select {
#define SRT_Discard 9 /* Do not save the results anywhere */
#define SRT_Sorter 10 /* Store results in the sorter */
#define SRT_Subroutine 11 /* Call a subroutine to handle results */
#define SRT_Exists 12 /* Put 0 or 1 in a memory cell */
/*
** When a SELECT uses aggregate functions (like "count(*)" or "avg(f1)")
@ -991,41 +1076,51 @@ struct AggExpr {
** An SQL parser context. A copy of this structure is passed through
** the parser and down into all the parser action routine in order to
** carry around information that is global to the entire parse.
**
** The structure is divided into two parts. When the parser and code
** generate call themselves recursively, the first part of the structure
** is constant but the second part is reset at the beginning and end of
** each recursion.
*/
struct Parse {
sqlite3 *db; /* The main database structure */
int rc; /* Return code from execution */
char *zErrMsg; /* An error message */
Vdbe *pVdbe; /* An engine for executing database bytecode */
u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
u8 nameClash; /* A permanent table name clashes with temp table name */
u8 checkSchema; /* Causes schema cookie check after an error */
u8 nested; /* Number of nested calls to the parser/code generator */
int nErr; /* Number of errors seen */
int nTab; /* Number of previously allocated VDBE cursors */
int nMem; /* Number of memory cells used so far */
int nSet; /* Number of sets used so far */
u32 cookieMask; /* Bitmask of schema verified databases */
int cookieValue[MAX_ATTACHED+2]; /* Values of cookies to verify */
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
u32 writeMask; /* Start a write transaction on these databases */
u8 fillAgg; /* If true, ignore the Expr.iAgg field. Normally false */
/* Above is constant between recursions. Below is reset before and after
** each recursion */
int nVar; /* Number of '?' variables seen in the SQL so far */
int nVarExpr; /* Number of used slots in apVarExpr[] */
int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */
Expr **apVarExpr; /* Pointers to :aaa and $aaaa wildcard expressions */
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 */
Vdbe *pVdbe; /* An engine for executing database bytecode */
u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
u8 explain; /* True if the EXPLAIN flag is found on the query */
u8 nameClash; /* A permanent table name clashes with temp table name */
u8 useAgg; /* If true, extract field values from the aggregator
** while generating expressions. Normally false */
u8 checkSchema; /* Causes schema cookie check after an error */
int nErr; /* Number of errors seen */
int nTab; /* Number of previously allocated VDBE cursors */
int nMem; /* Number of memory cells used so far */
int nSet; /* Number of sets used so far */
int nAgg; /* Number of aggregate expressions */
int nVar; /* Number of '?' variables seen in the SQL so far */
int nVarExpr; /* Number of used slots in apVarExpr[] */
int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */
Expr **apVarExpr; /* Pointers to :aaa and $aaaa wildcard expressions */
AggExpr *aAgg; /* An array of aggregate expressions */
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
TriggerStack *trigStack; /* Trigger actions being coded */
u32 cookieMask; /* Bitmask of schema verified databases */
int cookieValue[MAX_ATTACHED+2]; /* Values of cookies to verify */
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
u32 writeMask; /* Start a write transaction on these databases */
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
int nAgg; /* Number of aggregate expressions */
AggExpr *aAgg; /* An array of aggregate expressions */
int nMaxDepth; /* Maximum depth of subquery recursion */
};
/*
@ -1064,7 +1159,7 @@ struct Trigger {
u8 iDb; /* Database containing this trigger */
u8 iTabDb; /* Database containing Trigger.table */
u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */
u8 tr_tm; /* One of TK_BEFORE, TK_AFTER */
u8 tr_tm; /* One of TRIGGER_BEFORE, TRIGGER_AFTER */
Expr *pWhen; /* The WHEN clause of the expresion (may be NULL) */
IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger,
the <column-list> is stored here */
@ -1075,6 +1170,16 @@ struct Trigger {
Trigger *pNext; /* Next trigger associated with the table */
};
/*
** A trigger is either a BEFORE or an AFTER trigger. The following constants
** determine which.
**
** If there are multiple triggers, you might of some BEFORE and some AFTER.
** In that cases, the constants below can be ORed together.
*/
#define TRIGGER_BEFORE 1
#define TRIGGER_AFTER 2
/*
* An instance of struct TriggerStep is used to store a single SQL statement
* that is a part of a trigger-program.
@ -1188,7 +1293,6 @@ typedef struct {
char **pzErrMsg; /* Error message stored here */
} InitData;
/*
* This global flag is set for performance testing of triggers. When it is set
* SQLite will perform the overhead of building new and old trigger references
@ -1206,7 +1310,7 @@ int sqlite3IsNumber(const char*, int*, u8);
int sqlite3Compare(const char *, const char *);
int sqlite3SortCompare(const char *, const char *);
void sqlite3RealToSortable(double r, char *);
#ifdef SQLITE_DEBUG
#ifdef SQLITE_MEMDEBUG
void *sqlite3Malloc_(int,int,char*,int);
void sqlite3Free_(void*,char*,int);
void *sqlite3Realloc_(void*,int,char*,int);
@ -1233,7 +1337,8 @@ void sqlite3Dequote(char*);
int sqlite3KeywordCode(const char*, int);
int sqlite3RunParser(Parse*, const char*, char **);
void sqlite3FinishCoding(Parse*);
Expr *sqlite3Expr(int, Expr*, Expr*, Token*);
Expr *sqlite3Expr(int, Expr*, Expr*, const Token*);
Expr *sqlite3RegisterExpr(Parse*,Token*);
Expr *sqlite3ExprAnd(Expr*, Expr*);
void sqlite3ExprSpan(Expr*,Token*,Token*);
Expr *sqlite3ExprFunction(ExprList*, Token*);
@ -1253,13 +1358,19 @@ void sqlite3OpenMasterTable(Vdbe *v, int);
void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int);
void sqlite3AddColumn(Parse*,Token*);
void sqlite3AddNotNull(Parse*, int);
void sqlite3AddPrimaryKey(Parse*, ExprList*, int);
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int);
void sqlite3AddColumnType(Parse*,Token*,Token*);
void sqlite3AddDefaultValue(Parse*,Token*,int);
void sqlite3AddDefaultValue(Parse*,Expr*);
void sqlite3AddCollateType(Parse*, const char*, int);
void sqlite3EndTable(Parse*,Token*,Select*);
void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int);
int sqlite3ViewGetColumnNames(Parse*,Table*);
#ifndef SQLITE_OMIT_VIEW
void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int);
int sqlite3ViewGetColumnNames(Parse*,Table*);
#else
# define sqlite3ViewGetColumnNames(A,B) 0
#endif
void sqlite3DropTable(Parse*, SrcList*, int);
void sqlite3DeleteTable(sqlite3*, Table*);
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
@ -1277,35 +1388,36 @@ void sqlite3AddKeyType(Vdbe*, ExprList*);
void sqlite3AddIdxKeyType(Vdbe*, Index*);
int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*, char *aff);
Select *sqlite3SelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*,
int,int,int);
int,Expr*,Expr*);
void sqlite3SelectDelete(Select*);
void sqlite3SelectUnbind(Select*);
Table *sqlite3SrcListLookup(Parse*, SrcList*);
int sqlite3IsReadOnly(Parse*, Table*, int);
void sqlite3OpenTableForReading(Vdbe*, int iCur, Table*);
void sqlite3OpenTable(Vdbe*, int iCur, Table*, int);
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, int, ExprList**);
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, Fetch*);
void sqlite3WhereEnd(WhereInfo*);
void sqlite3ExprCode(Parse*, Expr*);
void sqlite3ExprCodeAndCache(Parse*, Expr*);
int sqlite3ExprCodeExprList(Parse*, ExprList*);
void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
void sqlite3NextedParse(Parse*, const char*, ...);
Table *sqlite3FindTable(sqlite3*,const char*, const char*);
Table *sqlite3LocateTable(Parse*,const char*, const char*);
Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
void sqlite3Vacuum(Parse*, Token*);
int sqlite3RunVacuum(char**, sqlite3*);
char *sqlite3NameFromToken(Token*);
int sqlite3ExprCheck(Parse*, Expr*, int, int*);
int sqlite3ExprCompare(Expr*, Expr*);
int sqliteFuncId(Token*);
int sqlite3ExprResolveIds(Parse*, SrcList*, ExprList*, Expr*);
int sqlite3ExprResolveAndCheck(Parse*,SrcList*,ExprList*,Expr*,int,int*);
int sqlite3ExprAnalyzeAggregates(Parse*, Expr*);
int sqlite3ExprResolveNames(NameContext *, Expr *);
int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
Vdbe *sqlite3GetVdbe(Parse*);
void sqlite3Randomness(int, void*);
void sqlite3RollbackAll(sqlite3*);
@ -1336,21 +1448,32 @@ int sqlite3SafetyOn(sqlite3*);
int sqlite3SafetyOff(sqlite3*);
int sqlite3SafetyCheck(sqlite3*);
void sqlite3ChangeCookie(sqlite3*, Vdbe*, int);
void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*,
int,Expr*,int);
void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
void sqlite3DropTrigger(Parse*, SrcList*);
void sqlite3DropTriggerPtr(Parse*, Trigger*, int);
int sqlite3TriggersExist(Parse* , Trigger* , int , int , int, ExprList*);
int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
int, int);
void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
void sqlite3DeleteTriggerStep(TriggerStep*);
TriggerStep *sqlite3TriggerSelectStep(Select*);
TriggerStep *sqlite3TriggerInsertStep(Token*, IdList*, ExprList*, Select*, int);
TriggerStep *sqlite3TriggerUpdateStep(Token*, ExprList*, Expr*, int);
TriggerStep *sqlite3TriggerDeleteStep(Token*, Expr*);
void sqlite3DeleteTrigger(Trigger*);
#ifndef SQLITE_OMIT_TRIGGER
void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*,
int,Expr*,int);
void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
void sqlite3DropTrigger(Parse*, SrcList*);
void sqlite3DropTriggerPtr(Parse*, Trigger*, int);
int sqlite3TriggersExist(Parse*, Table*, int, ExprList*);
int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
int, int);
void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
void sqlite3DeleteTriggerStep(TriggerStep*);
TriggerStep *sqlite3TriggerSelectStep(Select*);
TriggerStep *sqlite3TriggerInsertStep(Token*, IdList*, ExprList*,Select*,int);
TriggerStep *sqlite3TriggerUpdateStep(Token*, ExprList*, Expr*, int);
TriggerStep *sqlite3TriggerDeleteStep(Token*, Expr*);
void sqlite3DeleteTrigger(Trigger*);
void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
#else
# define sqlite3TriggersExist(A,B,C,D,E,F) 0
# define sqlite3DeleteTrigger(A)
# define sqlite3DropTriggerPtr(A,B,C)
# define sqlite3UnlinkAndDeleteTrigger(A,B,C)
# define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I) 0
#endif
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int);
void sqlite3DeferForeignKey(Parse*, int);
@ -1386,7 +1509,6 @@ int sqlite3PutVarint(unsigned char *, u64);
int sqlite3GetVarint(const unsigned char *, u64 *);
int sqlite3GetVarint32(const unsigned char *, u32 *);
int sqlite3VarintLen(u64 v);
char sqlite3AffinityType(const char *, int);
void sqlite3IndexAffinityStr(Vdbe *, Index *);
void sqlite3TableAffinityStr(Vdbe *, Table *);
char sqlite3CompareAffinity(Expr *pExpr, char aff2);
@ -1415,5 +1537,14 @@ void sqlite3ValueFree(sqlite3_value*);
sqlite3_value *sqlite3ValueNew();
sqlite3_value *sqlite3GetTransientValue(sqlite3*db);
extern const unsigned char sqlite3UpperToLower[];
void sqlite3RootPageMoved(Db*, int, int);
void sqlite3Reindex(Parse*, Token*, Token*);
void sqlite3AlterFunctions(sqlite3*);
void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
int sqlite3GetToken(const unsigned char *, int *);
void sqlite3NestedParse(Parse*, const char*, ...);
void sqlite3ExpirePreparedStatements(sqlite3*);
void sqlite3CodeSubselect(Parse *, Expr *);
int sqlite3SelectResolve(Parse *, Select *, NameContext *);
#endif

View File

@ -22,6 +22,9 @@
#include <string.h>
#include <assert.h>
#define NUM_PREPARED_STMTS 10
#define MAX_PREPARED_STMTS 100
/*
** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we
** have to do a translation when going between the two. Set the
@ -54,6 +57,19 @@ struct SqlCollate {
SqlCollate *pNext; /* Next function on the list of them all */
};
/*
** Prepared statements are cached for faster execution. Each prepared
** statement is described by an instance of the following structure.
*/
typedef struct SqlPreparedStmt SqlPreparedStmt;
struct SqlPreparedStmt {
SqlPreparedStmt *pNext; /* Next in linked list */
SqlPreparedStmt *pPrev; /* Previous on the list */
sqlite3_stmt *pStmt; /* The prepared statement */
int nSql; /* chars in zSql[] */
char zSql[1]; /* Text of the SQL statement */
};
/*
** There is one instance of this structure for each SQLite database
** that has been opened by the SQLite TCL interface.
@ -71,14 +87,35 @@ struct SqliteDb {
SqlCollate *pCollate; /* List of SQL collation functions */
int rc; /* Return code of most recent sqlite3_exec() */
Tcl_Obj *pCollateNeeded; /* Collation needed script */
SqlPreparedStmt *stmtList; /* List of prepared statements*/
SqlPreparedStmt *stmtLast; /* Last statement in the list */
int maxStmt; /* The next maximum number of stmtList */
int nStmt; /* Number of statements in stmtList */
};
/*
** Finalize and free a list of prepared statements
*/
static void flushStmtCache( SqliteDb *pDb ){
SqlPreparedStmt *pPreStmt;
while( pDb->stmtList ){
sqlite3_finalize( pDb->stmtList->pStmt );
pPreStmt = pDb->stmtList;
pDb->stmtList = pDb->stmtList->pNext;
Tcl_Free( (char*)pPreStmt );
}
pDb->nStmt = 0;
pDb->stmtLast = 0;
}
/*
** TCL calls this procedure when an sqlite3 database command is
** deleted.
*/
static void DbDeleteCmd(void *db){
SqliteDb *pDb = (SqliteDb*)db;
flushStmtCache(pDb);
sqlite3_close(pDb->db);
while( pDb->pFunc ){
SqlFunc *pFunc = pDb->pFunc;
@ -215,7 +252,7 @@ static int tclSqlCollate(
** This routine is called to evaluate an SQL function implemented
** using TCL script.
*/
static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
SqlFunc *p = sqlite3_user_data(context);
Tcl_DString cmd;
int i;
@ -287,6 +324,8 @@ static int auth_callback(
case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break;
case SQLITE_ATTACH : zCode="SQLITE_ATTACH"; break;
case SQLITE_DETACH : zCode="SQLITE_DETACH"; break;
case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break;
case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break;
default : zCode="????"; break;
}
Tcl_DStringInit(&str);
@ -332,6 +371,54 @@ static Tcl_Obj *dbTextToObj(char const *zText){
return pVal;
}
/*
** This routine reads a line of text from FILE in, stores
** the text in memory obtained from malloc() and returns a pointer
** to the text. NULL is returned at end of file, or if malloc()
** fails.
**
** The interface is like "readline" but no command-line editing
** is done.
**
** copied from shell.c from '.import' command
*/
static char *local_getline(char *zPrompt, FILE *in){
char *zLine;
int nLine;
int n;
int eol;
nLine = 100;
zLine = malloc( nLine );
if( zLine==0 ) return 0;
n = 0;
eol = 0;
while( !eol ){
if( n+100>nLine ){
nLine = nLine*2 + 100;
zLine = realloc(zLine, nLine);
if( zLine==0 ) return 0;
}
if( fgets(&zLine[n], nLine - n, in)==0 ){
if( n==0 ){
free(zLine);
return 0;
}
zLine[n] = 0;
eol = 1;
break;
}
while( zLine[n] ){ n++; }
if( n>0 && zLine[n-1]=='\n' ){
n--;
zLine[n] = 0;
eol = 1;
}
}
zLine = realloc( zLine, n+1 );
return zLine;
}
/*
** The "sqlite" command below creates a new Tcl command for each
** connection it opens to an SQLite database. This routine is invoked
@ -350,22 +437,25 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
int choice;
int rc = TCL_OK;
static const char *DB_strs[] = {
"authorizer", "busy", "changes",
"close", "collate", "collation_needed",
"commit_hook", "complete", "errorcode",
"eval", "function", "last_insert_rowid",
"onecolumn", "progress", "rekey",
"timeout", "total_changes", "trace",
"authorizer", "busy", "cache",
"changes", "close", "collate",
"collation_needed", "commit_hook", "complete",
"copy", "errorcode", "eval",
"function", "last_insert_rowid", "onecolumn",
"progress", "rekey", "timeout",
"total_changes", "trace", "version",
0
};
enum DB_enum {
DB_AUTHORIZER, DB_BUSY, DB_CHANGES,
DB_CLOSE, DB_COLLATE, DB_COLLATION_NEEDED,
DB_COMMIT_HOOK, DB_COMPLETE, DB_ERRORCODE,
DB_EVAL, DB_FUNCTION, DB_LAST_INSERT_ROWID,
DB_ONECOLUMN, DB_PROGRESS, DB_REKEY,
DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE,
DB_AUTHORIZER, DB_BUSY, DB_CACHE,
DB_CHANGES, DB_CLOSE, DB_COLLATE,
DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE,
DB_COPY, DB_ERRORCODE, DB_EVAL,
DB_FUNCTION, DB_LAST_INSERT_ROWID,DB_ONECOLUMN,
DB_PROGRESS, DB_REKEY, DB_TIMEOUT,
DB_TOTAL_CHANGES, DB_TRACE, DB_VERSION
};
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
if( objc<2 ){
Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
@ -467,6 +557,55 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break;
}
/* $db cache flush
** $db cache size n
**
** Flush the prepared statement cache, or set the maximum number of
** cached statements.
*/
case DB_CACHE: {
char *subCmd;
int n;
if( objc<=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "cache option ?arg?");
return TCL_ERROR;
}
subCmd = Tcl_GetStringFromObj( objv[2], 0 );
if( *subCmd=='f' && strcmp(subCmd,"flush")==0 ){
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "flush");
return TCL_ERROR;
}else{
flushStmtCache( pDb );
}
}else if( *subCmd=='s' && strcmp(subCmd,"size")==0 ){
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 2, objv, "size n");
return TCL_ERROR;
}else{
if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){
Tcl_AppendResult( interp, "cannot convert \"",
Tcl_GetStringFromObj(objv[3],0), "\" to integer", 0);
return TCL_ERROR;
}else{
if( n<0 ){
flushStmtCache( pDb );
n = 0;
}else if( n>MAX_PREPARED_STMTS ){
n = MAX_PREPARED_STMTS;
}
pDb->maxStmt = n;
}
}
}else{
Tcl_AppendResult( interp, "bad option \"",
Tcl_GetStringFromObj(objv[0],0), "\": must be flush or size", 0);
return TCL_ERROR;
}
break;
}
/* $db changes
**
** Return the number of rows that were modified, inserted, or deleted by
@ -557,6 +696,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
strcpy(pCollate->zScript, zScript);
if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8,
pCollate, tclSqlCollate) ){
Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
return TCL_ERROR;
}
break;
@ -636,6 +776,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
int nParm; /* Number of entries used in apParm[] */
Tcl_Obj *aParm[10]; /* Static space for apParm[] in the common case */
Tcl_Obj *pRet; /* Value to be returned */
SqlPreparedStmt *pPreStmt; /* Pointer to a prepared statement */
int rc2;
if( choice==DB_ONECOLUMN ){
if( objc!=3 ){
@ -665,29 +807,78 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_IncrRefCount(objv[2]);
zSql = Tcl_GetStringFromObj(objv[2], 0);
while( rc==TCL_OK && zSql[0] ){
int i; /* Loop counter */
int nVar; /* Number of wildcards in the SQL */
int nCol; /* Number of columns in the result set */
int i; /* Loop counter */
int nVar; /* Number of bind parameters in the pStmt */
int nCol; /* Number of columns in the result set */
Tcl_Obj **apColName = 0; /* Array of column names */
int len; /* String length of zSql */
/* Compile a single SQL statement */
if( SQLITE_OK!=sqlite3_prepare(pDb->db, zSql, -1, &pStmt, &zLeft) ){
Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
rc = TCL_ERROR;
break;
/* Try to find a SQL statement that has already been compiled and
** which matches the next sequence of SQL.
*/
pStmt = 0;
pPreStmt = pDb->stmtList;
len = strlen(zSql);
if( pPreStmt && sqlite3_expired(pPreStmt->pStmt) ){
flushStmtCache(pDb);
pPreStmt = 0;
}
for(; pPreStmt; pPreStmt=pPreStmt->pNext){
int n = pPreStmt->nSql;
if( len>=n
&& memcmp(pPreStmt->zSql, zSql, n)==0
&& (zSql[n]==0 || zSql[n-1]==';')
){
pStmt = pPreStmt->pStmt;
zLeft = &zSql[pPreStmt->nSql];
/* When a prepared statement is found, unlink it from the
** cache list. It will later be added back to the beginning
** of the cache list in order to implement LRU replacement.
*/
if( pPreStmt->pPrev ){
pPreStmt->pPrev->pNext = pPreStmt->pNext;
}else{
pDb->stmtList = pPreStmt->pNext;
}
if( pPreStmt->pNext ){
pPreStmt->pNext->pPrev = pPreStmt->pPrev;
}else{
pDb->stmtLast = pPreStmt->pPrev;
}
pDb->nStmt--;
break;
}
}
/* If no prepared statement was found. Compile the SQL text
*/
if( pStmt==0 ){
if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){
if( SQLITE_OK!=sqlite3_prepare(pDb->db, zSql, -1, &pStmt, &zLeft) ){
Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
rc = TCL_ERROR;
break;
}else{
zSql = zLeft;
continue;
}
if( pStmt==0 ){
if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){
/* A compile-time error in the statement
*/
Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
rc = TCL_ERROR;
break;
}else{
/* The statement was a no-op. Continue to the next statement
** in the SQL string.
*/
zSql = zLeft;
continue;
}
}
assert( pPreStmt==0 );
}
/* Bind values to wildcards that begin with $ or : */
/* Bind values to parameters that begin with $ or :
*/
nVar = sqlite3_bind_parameter_count(pStmt);
nParm = 0;
if( nVar>sizeof(aParm)/sizeof(aParm[0]) ){
@ -697,7 +888,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
for(i=1; i<=nVar; i++){
const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
if( zVar[0]=='$' || zVar[0]==':' ){
if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':') ){
Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0);
if( pVar ){
int n;
@ -723,6 +914,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_IncrRefCount(pVar);
apParm[nParm++] = pVar;
}
}else{
sqlite3_bind_null( pStmt, i );
}
}
}
@ -827,19 +1020,75 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_Free((char*)apParm);
}
/* Finalize the statement. If the result code is SQLITE_SCHEMA, then
** try again to execute the same statement
/* Reset the statement. If the result code is SQLITE_SCHEMA, then
** flush the statement cache and try the statement again.
*/
if( SQLITE_SCHEMA==sqlite3_finalize(pStmt) ){
rc2 = sqlite3_reset(pStmt);
if( SQLITE_SCHEMA==rc2 ){
/* After a schema change, flush the cache and try to run the
** statement again
*/
flushStmtCache( pDb );
sqlite3_finalize(pStmt);
if( pPreStmt ) Tcl_Free((char*)pPreStmt);
continue;
}
if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){
}else if( SQLITE_OK!=rc2 ){
/* If a run-time error occurs, report the error and stop reading
** the SQL
*/
Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
sqlite3_finalize(pStmt);
rc = TCL_ERROR;
if( pPreStmt ) Tcl_Free((char*)pPreStmt);
break;
}else if( pDb->maxStmt<=0 ){
/* If the cache is turned off, deallocated the statement */
if( pPreStmt ) Tcl_Free((char*)pPreStmt);
sqlite3_finalize(pStmt);
}else{
/* Everything worked and the cache is operational.
** Create a new SqlPreparedStmt structure if we need one.
** (If we already have one we can just reuse it.)
*/
if( pPreStmt==0 ){
len = zLeft - zSql;
pPreStmt = (SqlPreparedStmt*)Tcl_Alloc( sizeof(*pPreStmt) + len );
if( pPreStmt==0 ) return TCL_ERROR;
pPreStmt->pStmt = pStmt;
pPreStmt->nSql = len;
memcpy(pPreStmt->zSql, zSql, len);
pPreStmt->zSql[len] = 0;
}
/* Add the prepared statement to the beginning of the cache list
*/
pPreStmt->pNext = pDb->stmtList;
pPreStmt->pPrev = 0;
if( pDb->stmtList ){
pDb->stmtList->pPrev = pPreStmt;
}
pDb->stmtList = pPreStmt;
if( pDb->stmtLast==0 ){
assert( pDb->nStmt==0 );
pDb->stmtLast = pPreStmt;
}else{
assert( pDb->nStmt>0 );
}
pDb->nStmt++;
/* If we have too many statement in cache, remove the surplus from the
** end of the cache list.
*/
while( pDb->nStmt>pDb->maxStmt ){
sqlite3_finalize(pDb->stmtLast->pStmt);
pDb->stmtLast = pDb->stmtLast->pPrev;
Tcl_Free((char*)pDb->stmtLast->pNext);
pDb->stmtLast->pNext = 0;
pDb->nStmt--;
}
}
/* Proceed to the next statement */
zSql = zLeft;
}
Tcl_DecrRefCount(objv[2]);
@ -879,7 +1128,13 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
strcpy(pFunc->zScript, zScript);
rc = sqlite3_create_function(pDb->db, zName, -1, SQLITE_UTF8,
pFunc, tclSqlFunc, 0, 0);
if( rc!=SQLITE_OK ) rc = TCL_ERROR;
if( rc!=SQLITE_OK ){
rc = TCL_ERROR;
Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
}else{
/* Must flush any cached statements */
flushStmtCache( pDb );
}
break;
}
@ -1040,6 +1295,202 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break;
}
/* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR?
**
** Copy data into table from filename, optionally using SEPARATOR
** as column separators. If a column contains a null string, or the
** value of NULLINDICATOR, a NULL is inserted for the column.
** conflict-algorithm is one of the sqlite conflict algorithms:
** rollback, abort, fail, ignore, replace
** On success, return the number of lines processed, not necessarily same
** as 'db changes' due to conflict-algorithm selected.
**
** This code is basically an implementation/enhancement of
** the sqlite3 shell.c ".import" command.
**
** This command usage is equivalent to the sqlite2.x COPY statement,
** which imports file data into a table using the PostgreSQL COPY file format:
** $db copy $conflit_algo $table_name $filename \t \\N
*/
case DB_COPY: {
char *zTable; /* Insert data into this table */
char *zFile; /* The file from which to extract data */
char *zConflict; /* The conflict algorithm to use */
sqlite3_stmt *pStmt; /* A statement */
int rc; /* Result code */
int nCol; /* Number of columns in the table */
int nByte; /* Number of bytes in an SQL string */
int i, j; /* Loop counters */
int nSep; /* Number of bytes in zSep[] */
int nNull; /* Number of bytes in zNull[] */
char *zSql; /* An SQL statement */
char *zLine; /* A single line of input from the file */
char **azCol; /* zLine[] broken up into columns */
char *zCommit; /* How to commit changes */
FILE *in; /* The input file */
int lineno = 0; /* Line number of input file */
char zLineNum[80]; /* Line number print buffer */
Tcl_Obj *pResult; /* interp result */
char *zSep;
char *zNull;
if( objc<5 || objc>7 ){
Tcl_WrongNumArgs(interp, 2, objv,
"CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?");
return TCL_ERROR;
}
if( objc>=6 ){
zSep = Tcl_GetStringFromObj(objv[5], 0);
}else{
zSep = "\t";
}
if( objc>=7 ){
zNull = Tcl_GetStringFromObj(objv[6], 0);
}else{
zNull = "";
}
zConflict = Tcl_GetStringFromObj(objv[2], 0);
zTable = Tcl_GetStringFromObj(objv[3], 0);
zFile = Tcl_GetStringFromObj(objv[4], 0);
nSep = strlen(zSep);
nNull = strlen(zNull);
if( nSep==0 ){
Tcl_AppendResult(interp, "Error: non-null separator required for copy", 0);
return TCL_ERROR;
}
if(sqlite3StrICmp(zConflict, "rollback") != 0 &&
sqlite3StrICmp(zConflict, "abort" ) != 0 &&
sqlite3StrICmp(zConflict, "fail" ) != 0 &&
sqlite3StrICmp(zConflict, "ignore" ) != 0 &&
sqlite3StrICmp(zConflict, "replace" ) != 0 ) {
Tcl_AppendResult(interp, "Error: \"", zConflict,
"\", conflict-algorithm must be one of: rollback, "
"abort, fail, ignore, or replace", 0);
return TCL_ERROR;
}
zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
if( zSql==0 ){
Tcl_AppendResult(interp, "Error: no such table: ", zTable, 0);
return TCL_ERROR;
}
nByte = strlen(zSql);
rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
sqlite3_free(zSql);
if( rc ){
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
nCol = 0;
}else{
nCol = sqlite3_column_count(pStmt);
}
sqlite3_finalize(pStmt);
if( nCol==0 ) {
return TCL_ERROR;
}
zSql = malloc( nByte + 50 + nCol*2 );
if( zSql==0 ) {
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
return TCL_ERROR;
}
sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?",
zConflict, zTable);
j = strlen(zSql);
for(i=1; i<nCol; i++){
zSql[j++] = ',';
zSql[j++] = '?';
}
zSql[j++] = ')';
zSql[j] = 0;
rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
free(zSql);
if( rc ){
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
sqlite3_finalize(pStmt);
return TCL_ERROR;
}
in = fopen(zFile, "rb");
if( in==0 ){
Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, NULL);
sqlite3_finalize(pStmt);
return TCL_ERROR;
}
azCol = malloc( sizeof(azCol[0])*(nCol+1) );
if( azCol==0 ) {
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
return TCL_ERROR;
}
sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0);
zCommit = "COMMIT";
while( (zLine = local_getline(0, in))!=0 ){
char *z;
i = 0;
lineno++;
azCol[0] = zLine;
for(i=0, z=zLine; *z; z++){
if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){
*z = 0;
i++;
if( i<nCol ){
azCol[i] = &z[nSep];
z += nSep-1;
}
}
}
if( i+1!=nCol ){
char *zErr;
zErr = malloc(200 + strlen(zFile));
sprintf(zErr,"Error: %s line %d: expected %d columns of data but found %d",
zFile, lineno, nCol, i+1);
Tcl_AppendResult(interp, zErr, 0);
free(zErr);
zCommit = "ROLLBACK";
break;
}
for(i=0; i<nCol; i++){
/* check for null data, if so, bind as null */
if ((nNull>0 && strcmp(azCol[i], zNull)==0) || strlen(azCol[i])==0) {
sqlite3_bind_null(pStmt, i+1);
}else{
sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
}
}
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
free(zLine);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), 0);
zCommit = "ROLLBACK";
break;
}
}
free(azCol);
fclose(in);
sqlite3_finalize(pStmt);
sqlite3_exec(pDb->db, zCommit, 0, 0, 0);
if( zCommit[0] == 'C' ){
/* success, set result as number of lines processed */
pResult = Tcl_GetObjResult(interp);
Tcl_SetIntObj(pResult, lineno);
rc = TCL_OK;
}else{
/* failure, append lineno where failed */
sprintf(zLineNum,"%d",lineno);
Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,0);
rc = TCL_ERROR;
}
break;
}
/* $db version
**
** Return the version string for this database.
*/
case DB_VERSION: {
Tcl_SetResult(interp, (char *)sqlite3_libversion(), TCL_STATIC);
break;
}
} /* End of the SWITCH statement */
return rc;
}
@ -1146,6 +1597,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
free(zErrMsg);
return TCL_ERROR;
}
p->maxStmt = NUM_PREPARED_STMTS;
zArg = Tcl_GetStringFromObj(objv[1], 0);
Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
@ -1163,12 +1615,12 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
#ifdef SQLITE_TEST
{
extern void Md5_Register(sqlite3*);
#ifdef SQLITE_DEBUG
#ifdef SQLITE_MEMDEBUG
int mallocfail = sqlite3_iMallocFail;
sqlite3_iMallocFail = 0;
#endif
Md5_Register(p->db);
#ifdef SQLITE_DEBUG
#ifdef SQLITE_MEMDEBUG
sqlite3_iMallocFail = mallocfail;
#endif
}
@ -1199,20 +1651,20 @@ int Sqlite3_Init(Tcl_Interp *interp){
Tcl_InitStubs(interp, "8.4", 0);
Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0);
Tcl_PkgProvide(interp, "sqlite3", "3.0");
Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
Tcl_PkgProvide(interp, "sqlite", "3.0");
return TCL_OK;
}
int Tclsqlite3_Init(Tcl_Interp *interp){
Tcl_InitStubs(interp, "8.4", 0);
Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0);
Tcl_PkgProvide(interp, "sqlite3", "3.0");
return TCL_OK;
}
int Sqlite3_SafeInit(Tcl_Interp *interp){
return TCL_OK;
}
int Tclsqlite3_SafeInit(Tcl_Interp *interp){
return TCL_OK;
}
int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
#ifndef SQLITE_3_SUFFIX_ONLY
int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
#endif
#ifdef TCLSH
/*****************************************************************************
@ -1285,7 +1737,7 @@ int TCLSH_MAIN(int argc, char **argv){
int i;
Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
for(i=2; i<argc; i++){
for(i=3-TCLSH; i<argc; i++){
Tcl_SetVar(interp, "argv", argv[i],
TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
}

View File

@ -478,21 +478,22 @@ static int test_create_function(
){
int rc;
sqlite3 *db;
sqlite3_value *pVal;
extern void Md5_Register(sqlite3*);
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" FILENAME\"", 0);
" DB\"", 0);
return TCL_ERROR;
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_ANY, 0,
ifnullFunc, 0, 0);
#ifndef SQLITE_OMIT_UTF16
/* Use the sqlite3_create_function16() API here. Mainly for fun, but also
** because it is not tested anywhere else. */
if( rc==SQLITE_OK ){
sqlite3_value *pVal;
pVal = sqlite3ValueNew();
sqlite3ValueSetStr(pVal, -1, "x_sqlite_exec", SQLITE_UTF8, SQLITE_STATIC);
rc = sqlite3_create_function16(db,
@ -500,7 +501,10 @@ static int test_create_function(
1, SQLITE_UTF16, db, sqlite3ExecFunc, 0, 0);
sqlite3ValueFree(pVal);
}
#endif
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
Tcl_SetResult(interp, (char *)errorName(rc), 0);
return TCL_OK;
}
@ -743,12 +747,17 @@ static int sqlite3_mprintf_stronly(
}
/*
** Usage: sqlite_malloc_fail N
** Usage: sqlite_malloc_fail N ?REPEAT-INTERVAL?
**
** Rig sqliteMalloc() to fail on the N-th call. Turn off this mechanism
** and reset the sqlite3_malloc_failed variable is N==0.
** Rig sqliteMalloc() to fail on the N-th call and every REPEAT-INTERVAL call
** after that. If REPEAT-INTERVAL is 0 or is omitted, then only a single
** malloc will fail. If REPEAT-INTERVAL is 1 then all mallocs after the
** first failure will continue to fail on every call. If REPEAT-INTERVAL is
** 2 then every other malloc will fail. And so forth.
**
** Turn off this mechanism and reset the sqlite3_malloc_failed variable is N==0.
*/
#ifdef SQLITE_DEBUG
#ifdef SQLITE_MEMDEBUG
static int sqlite_malloc_fail(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
@ -756,12 +765,19 @@ static int sqlite_malloc_fail(
char **argv /* Text of each argument */
){
int n;
if( argc!=2 ){
int rep;
if( argc!=2 && argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
return TCL_ERROR;
}
if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
if( argc==3 ){
if( Tcl_GetInt(interp, argv[2], &rep) ) return TCL_ERROR;
}else{
rep = 0;
}
sqlite3_iMallocFail = n;
sqlite3_iMallocReset = rep;
sqlite3_malloc_failed = 0;
return TCL_OK;
}
@ -772,7 +788,7 @@ static int sqlite_malloc_fail(
**
** Return the number of prior calls to sqliteMalloc() and sqliteFree().
*/
#ifdef SQLITE_DEBUG
#ifdef SQLITE_MEMDEBUG
static int sqlite_malloc_stat(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
@ -892,10 +908,12 @@ static int test_finalize(
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
db = StmtToDb(pStmt);
if( pStmt ){
db = StmtToDb(pStmt);
}
rc = sqlite3_finalize(pStmt);
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
if( db && sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
return TCL_OK;
}
@ -922,13 +940,37 @@ static int test_reset(
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
rc = sqlite3_reset(pStmt);
if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
if( pStmt &&
sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
if( rc ){
return TCL_ERROR;
}
return TCL_OK;
}
/*
** Usage: sqlite3_expired STMT
**
** Return TRUE if a recompilation of the statement is recommended.
*/
static int test_expired(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3_stmt *pStmt;
if( objc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
return TCL_ERROR;
}
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(sqlite3_expired(pStmt)));
return TCL_OK;
}
/*
** Usage: sqlite3_changes DB
**
@ -1005,7 +1047,7 @@ static int test_bind(
return TCL_OK;
}
#ifndef SQLITE_OMIT_UTF16
/*
** Usage: add_test_collate <db ptr> <utf8> <utf16le> <utf16be>
**
@ -1148,6 +1190,7 @@ bad_args:
Tcl_WrongNumArgs(interp, 1, objv, "DB");
return TCL_ERROR;
}
#endif /* SQLITE_OMIT_UTF16 */
/*
** Usage: add_test_function <db ptr> <utf8> <utf16le> <utf16be>
@ -1174,6 +1217,7 @@ bad_args:
** for a UTF-16LE test_function(), and UTF-16LE for an implementation that
** prefers UTF-16BE.
*/
#ifndef SQLITE_OMIT_UTF16
static void test_function_utf8(
sqlite3_context *pCtx,
int nArg,
@ -1243,12 +1287,14 @@ static void test_function_utf16be(
-1, SQLITE_TRANSIENT);
sqlite3ValueFree(pVal);
}
#endif /* SQLITE_OMIT_UTF16 */
static int test_function(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
#ifndef SQLITE_OMIT_UTF16
sqlite3 *db;
int val;
@ -1275,6 +1321,7 @@ static int test_function(
bad_args:
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0);
#endif /* SQLITE_OMIT_UTF16 */
return TCL_ERROR;
}
@ -1553,6 +1600,7 @@ static int test_bind_text16(
int objc,
Tcl_Obj *CONST objv[]
){
#ifndef SQLITE_OMIT_UTF16
sqlite3_stmt *pStmt;
int idx;
int bytes;
@ -1576,6 +1624,7 @@ static int test_bind_text16(
return TCL_ERROR;
}
#endif /* SQLITE_OMIT_UTF16 */
return TCL_OK;
}
@ -1695,6 +1744,29 @@ static int test_bind_parameter_index(
return TCL_OK;
}
/*
** Usage: sqlite3_clear_bindings STMT
**
*/
#if 0
static int test_clear_bindings(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3_stmt *pStmt;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "STMT");
return TCL_ERROR;
}
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_clear_bindings(pStmt)));
return TCL_OK;
}
#endif
/*
** Usage: sqlite3_errcode DB
**
@ -1760,6 +1832,7 @@ static int test_errmsg16(
int objc,
Tcl_Obj *CONST objv[]
){
#ifndef SQLITE_OMIT_UTF16
sqlite3 *db;
const void *zErr;
int bytes;
@ -1774,6 +1847,7 @@ static int test_errmsg16(
zErr = sqlite3_errmsg16(db);
bytes = sqlite3utf16ByteLen(zErr, -1);
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes));
#endif /* SQLITE_OMIT_UTF16 */
return TCL_OK;
}
@ -1844,6 +1918,7 @@ static int test_prepare16(
int objc,
Tcl_Obj *CONST objv[]
){
#ifndef SQLITE_OMIT_UTF16
sqlite3 *db;
const void *zSql;
const void *zTail = 0;
@ -1883,6 +1958,7 @@ static int test_prepare16(
if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
}
Tcl_AppendResult(interp, zBuf, 0);
#endif /* SQLITE_OMIT_UTF16 */
return TCL_OK;
}
@ -1923,6 +1999,7 @@ static int test_open16(
int objc,
Tcl_Obj *CONST objv[]
){
#ifndef SQLITE_OMIT_UTF16
const void *zFilename;
sqlite3 *db;
int rc;
@ -1939,6 +2016,7 @@ static int test_open16(
if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
Tcl_AppendResult(interp, zBuf, 0);
#endif /* SQLITE_OMIT_UTF16 */
return TCL_OK;
}
@ -1954,6 +2032,7 @@ static int test_complete16(
int objc,
Tcl_Obj *CONST objv[]
){
#ifndef SQLITE_OMIT_UTF16
char *zBuf;
if( objc!=2 ){
@ -1963,6 +2042,7 @@ static int test_complete16(
zBuf = Tcl_GetByteArrayFromObj(objv[1], 0);
Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_complete16(zBuf)));
#endif /* SQLITE_OMIT_UTF16 */
return TCL_OK;
}
@ -2227,6 +2307,7 @@ static int test_stmt_utf16(
int objc,
Tcl_Obj *CONST objv[]
){
#ifndef SQLITE_OMIT_UTF16
sqlite3_stmt *pStmt;
int col;
Tcl_Obj *pRet;
@ -2247,6 +2328,7 @@ static int test_stmt_utf16(
pRet = Tcl_NewByteArrayObj(zName16, sqlite3utf16ByteLen(zName16, -1)+2);
Tcl_SetObjResult(interp, pRet);
}
#endif /* SQLITE_OMIT_UTF16 */
return TCL_OK;
}
@ -2442,6 +2524,133 @@ static int test_sqlite3OsTempFileName(
return TCL_OK;
}
/*
** Usage: sqlite_set_magic DB MAGIC-NUMBER
**
** Set the db->magic value. This is used to test error recovery logic.
*/
static int sqlite_set_magic(
void * clientData,
Tcl_Interp *interp,
int argc,
char **argv
){
sqlite3 *db;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" DB MAGIC", 0);
return TCL_ERROR;
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
if( strcmp(argv[2], "SQLITE_MAGIC_OPEN")==0 ){
db->magic = SQLITE_MAGIC_OPEN;
}else if( strcmp(argv[2], "SQLITE_MAGIC_CLOSED")==0 ){
db->magic = SQLITE_MAGIC_CLOSED;
}else if( strcmp(argv[2], "SQLITE_MAGIC_BUSY")==0 ){
db->magic = SQLITE_MAGIC_BUSY;
}else if( strcmp(argv[2], "SQLITE_MAGIC_ERROR")==0 ){
db->magic = SQLITE_MAGIC_ERROR;
}else if( Tcl_GetInt(interp, argv[2], &db->magic) ){
return TCL_ERROR;
}
return TCL_OK;
}
/*
** Usage: sqlite3_interrupt DB
**
** Trigger an interrupt on DB
*/
static int test_interrupt(
void * clientData,
Tcl_Interp *interp,
int argc,
char **argv
){
sqlite3 *db;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB", 0);
return TCL_ERROR;
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
sqlite3_interrupt(db);
return TCL_OK;
}
/*
** Usage: sqlite3_sleep ms
**
** Sleep for the specified number of ms.
*/
#if 0
static int test_sleep(
void * clientData,
Tcl_Interp *interp,
int argc,
char **argv
){
sqlite3 *db;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ms", 0);
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_sleep(atoi(argv[1]))));
return TCL_OK;
}
#endif
/*
** Usage: sqlite_delete_function DB function-name
**
** Delete the user function 'function-name' from database handle DB. It
** is assumed that the user function was created as UTF8, any number of
** arguments (the way the TCL interface does it).
*/
static int delete_function(
void * clientData,
Tcl_Interp *interp,
int argc,
char **argv
){
int rc;
sqlite3 *db;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" DB function-name", 0);
return TCL_ERROR;
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0, 0, 0, 0);
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
return TCL_OK;
}
/*
** Usage: sqlite_delete_collation DB collation-name
**
** Delete the collation sequence 'collation-name' from database handle
** DB. It is assumed that the collation sequence was created as UTF8 (the
** way the TCL interface does it).
*/
static int delete_collation(
void * clientData,
Tcl_Interp *interp,
int argc,
char **argv
){
int rc;
sqlite3 *db;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" DB function-name", 0);
return TCL_ERROR;
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
rc = sqlite3_create_collation(db, argv[2], SQLITE_UTF8, 0, 0);
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
return TCL_OK;
}
/*
** Usage: tcl_variable_type VARIABLENAME
**
@ -2467,6 +2676,181 @@ static int tcl_variable_type(
return TCL_OK;
}
/*
** This routine sets entries in the global ::sqlite_options() array variable
** according to the compile-time configuration of the database. Test
** procedures use this to determine when tests should be omitted.
*/
static void set_options(Tcl_Interp *interp){
#ifdef SQLITE_32BIT_ROWID
Tcl_SetVar2(interp, "sqlite_options", "rowid32", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "rowid32", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_ALTERTABLE
Tcl_SetVar2(interp, "sqlite_options", "altertable", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "altertable", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_AUTHORIZATION
Tcl_SetVar2(interp, "sqlite_options", "auth", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "auth", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_AUTOINCREMENT
Tcl_SetVar2(interp, "sqlite_options", "autoinc", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "autoinc", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_AUTOVACUUM
Tcl_SetVar2(interp, "sqlite_options", "autovacuum", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "autovacuum", "1", TCL_GLOBAL_ONLY);
#endif /* SQLITE_OMIT_AUTOVACUUM */
#if !defined(SQLITE_DEFAULT_AUTOVACUUM) || SQLITE_DEFAULT_AUTOVACUUM==0
Tcl_SetVar2(interp,"sqlite_options","default_autovacuum","0",TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp,"sqlite_options","default_autovacuum","1",TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_BLOB_LITERAL
Tcl_SetVar2(interp, "sqlite_options", "bloblit", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "bloblit", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_COMPOUND_SELECT
Tcl_SetVar2(interp, "sqlite_options", "compound", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "compound", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_CONFLICT_CLAUSE
Tcl_SetVar2(interp, "sqlite_options", "conflict", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "conflict", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_DATETIME_FUNCS
Tcl_SetVar2(interp, "sqlite_options", "datetime", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "datetime", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_EXPLAIN
Tcl_SetVar2(interp, "sqlite_options", "explain", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "explain", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_FLOATING_POINT
Tcl_SetVar2(interp, "sqlite_options", "floatingpoint", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "floatingpoint", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_FOREIGN_KEY
Tcl_SetVar2(interp, "sqlite_options", "foreignkey", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "foreignkey", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_INTEGRITY_CHECK
Tcl_SetVar2(interp, "sqlite_options", "integrityck", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "integrityck", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_MEMORYDB
Tcl_SetVar2(interp, "sqlite_options", "memorydb", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "memorydb", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_PAGER_PRAGMAS
Tcl_SetVar2(interp, "sqlite_options", "pager_pragmas", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "pager_pragmas", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_PRAGMA
Tcl_SetVar2(interp, "sqlite_options", "pragma", "0", TCL_GLOBAL_ONLY);
Tcl_SetVar2(interp, "sqlite_options", "integrityck", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "pragma", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_PROGRESS_CALLBACK
Tcl_SetVar2(interp, "sqlite_options", "progress", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "progress", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_REINDEX
Tcl_SetVar2(interp, "sqlite_options", "reindex", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "reindex", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
Tcl_SetVar2(interp, "sqlite_options", "schema_pragmas", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "schema_pragmas", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
Tcl_SetVar2(interp, "sqlite_options", "schema_version", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "schema_version", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_SUBQUERY
Tcl_SetVar2(interp, "sqlite_options", "subquery", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "subquery", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_TCL_VARIABLE
Tcl_SetVar2(interp, "sqlite_options", "tclvar", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "tclvar", "1", TCL_GLOBAL_ONLY);
#endif
#if defined(THREADSAFE) && THREADSAFE
Tcl_SetVar2(interp, "sqlite_options", "threadsafe", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "threadsafe", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_TRIGGER
Tcl_SetVar2(interp, "sqlite_options", "trigger", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "trigger", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_UTF16
Tcl_SetVar2(interp, "sqlite_options", "utf16", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "utf16", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_VACUUM
Tcl_SetVar2(interp, "sqlite_options", "vacuum", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "vacuum", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_VIEW
Tcl_SetVar2(interp, "sqlite_options", "view", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "view", "1", TCL_GLOBAL_ONLY);
#endif
}
/*
** Register commands with the TCL interpreter.
*/
@ -2474,6 +2858,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
extern int sqlite3_search_count;
extern int sqlite3_interrupt_count;
extern int sqlite3_open_file_count;
extern int sqlite3_sort_count;
extern int sqlite3_current_time;
static struct {
char *zName;
@ -2494,7 +2879,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate },
{ "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func },
{ "sqlite_abort", (Tcl_CmdProc*)sqlite_abort },
#ifdef SQLITE_DEBUG
#ifdef SQLITE_MEMDEBUG
{ "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail },
{ "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat },
#endif
@ -2502,6 +2887,13 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "breakpoint", (Tcl_CmdProc*)test_breakpoint },
{ "sqlite3_key", (Tcl_CmdProc*)test_key },
{ "sqlite3_rekey", (Tcl_CmdProc*)test_rekey },
{ "sqlite_set_magic", (Tcl_CmdProc*)sqlite_set_magic },
{ "sqlite3_interrupt", (Tcl_CmdProc*)test_interrupt },
#if 0
{ "sqlite3_sleep", (Tcl_CmdProc*)test_sleep },
#endif
{ "sqlite_delete_function", (Tcl_CmdProc*)delete_function },
{ "sqlite_delete_collation", (Tcl_CmdProc*)delete_collation }
};
static struct {
char *zName;
@ -2518,6 +2910,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_bind_parameter_count", test_bind_parameter_count, 0},
{ "sqlite3_bind_parameter_name", test_bind_parameter_name, 0},
{ "sqlite3_bind_parameter_index", test_bind_parameter_index, 0},
#if 0
{ "sqlite3_clear_bindings", test_clear_bindings, 0},
#endif
{ "sqlite3_errcode", test_errcode ,0 },
{ "sqlite3_errmsg", test_errmsg ,0 },
{ "sqlite3_errmsg16", test_errmsg16 ,0 },
@ -2529,6 +2924,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_prepare16", test_prepare16 ,0 },
{ "sqlite3_finalize", test_finalize ,0 },
{ "sqlite3_reset", test_reset ,0 },
{ "sqlite3_expired", test_expired ,0 },
{ "sqlite3_changes", test_changes ,0 },
{ "sqlite3_step", test_step ,0 },
@ -2539,15 +2935,17 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_column_blob", test_column_blob ,0 },
{ "sqlite3_column_double", test_column_double ,0 },
{ "sqlite3_column_int64", test_column_int64 ,0 },
{ "sqlite3_column_int", test_stmt_int, sqlite3_column_int },
{ "sqlite3_column_bytes", test_stmt_int, sqlite3_column_bytes },
{ "sqlite3_column_bytes16", test_stmt_int, sqlite3_column_bytes16 },
{ "sqlite3_column_text", test_stmt_utf8, sqlite3_column_text },
{ "sqlite3_column_decltype", test_stmt_utf8, sqlite3_column_decltype },
{ "sqlite3_column_name", test_stmt_utf8, sqlite3_column_name },
{ "sqlite3_column_int", test_stmt_int, sqlite3_column_int },
{ "sqlite3_column_bytes", test_stmt_int, sqlite3_column_bytes },
#ifndef SQLITE_OMIT_UTF16
{ "sqlite3_column_bytes16", test_stmt_int, sqlite3_column_bytes16 },
{ "sqlite3_column_text16", test_stmt_utf16, sqlite3_column_text16 },
{ "sqlite3_column_decltype16", test_stmt_utf16, sqlite3_column_decltype16},
{ "sqlite3_column_name16", test_stmt_utf16, sqlite3_column_name16 },
#endif
/* Functions from os.h */
{ "sqlite3OsOpenReadWrite",test_sqlite3OsOpenReadWrite, 0 },
@ -2557,16 +2955,19 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
/* Custom test interfaces */
{ "sqlite3OsUnlock", test_sqlite3OsUnlock, 0 },
#ifndef SQLITE_OMIT_UTF16
{ "add_test_collate", test_collate, 0 },
{ "add_test_collate_needed", test_collate_needed, 0 },
{ "add_test_function", test_function, 0 },
#endif
{ "sqlite3_crashparams", sqlite3_crashparams, 0 },
{ "sqlite3_test_errstr", test_errstr, 0 },
{ "tcl_variable_type", tcl_variable_type, 0 },
};
static int bitmask_size = sizeof(Bitmask)*8;
int i;
extern int sqlite3_os_trace;
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
@ -2577,6 +2978,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
}
Tcl_LinkVar(interp, "sqlite_search_count",
(char*)&sqlite3_search_count, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_sort_count",
(char*)&sqlite3_sort_count, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_interrupt_count",
(char*)&sqlite3_interrupt_count, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_open_file_count",
@ -2589,5 +2992,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
(char*)&sqlite_static_bind_value, TCL_LINK_STRING);
Tcl_LinkVar(interp, "sqlite_temp_directory",
(char*)&sqlite3_temp_directory, TCL_LINK_STRING);
Tcl_LinkVar(interp, "bitmask_size",
(char*)&bitmask_size, TCL_LINK_INT|TCL_LINK_READ_ONLY);
set_options(interp);
return TCL_OK;
}

View File

@ -81,7 +81,7 @@ static int pager_open(
return TCL_ERROR;
}
if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR;
rc = sqlite3pager_open(&pPager, argv[1], 0, 1);
rc = sqlite3pager_open(&pPager, argv[1], 0, 0);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@ -376,6 +376,34 @@ static int page_lookup(
return TCL_OK;
}
/*
** Usage: pager_truncate ID PGNO
*/
static int pager_truncate(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
Pager *pPager;
int rc;
int pgno;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID PGNO\"", 0);
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
rc = sqlite3pager_truncate(pPager, pgno);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** Usage: page_unref PAGE
**
@ -553,6 +581,7 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
{ "page_read", (Tcl_CmdProc*)page_read },
{ "page_write", (Tcl_CmdProc*)page_write },
{ "page_number", (Tcl_CmdProc*)page_number },
{ "pager_truncate", (Tcl_CmdProc*)pager_truncate },
{ "fake_big_file", (Tcl_CmdProc*)fake_big_file },
};
int i;

View File

@ -44,6 +44,7 @@ static char *errorName(int rc){
case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break;
default: zName = "SQLITE_Unknown"; break;
}
return zName;
@ -315,6 +316,7 @@ static int btree_drop_table(
Btree *pBt;
int iTable;
int rc;
int notUsed1;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID TABLENUM\"", 0);
@ -322,7 +324,7 @@ static int btree_drop_table(
}
pBt = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
rc = sqlite3BtreeDropTable(pBt, iTable);
rc = sqlite3BtreeDropTable(pBt, iTable, &notUsed1);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@ -512,10 +514,10 @@ static int btree_pager_stats(
}
pBt = sqlite3TextToPtr(argv[1]);
a = sqlite3pager_stats(sqlite3BtreePager(pBt));
for(i=0; i<9; i++){
for(i=0; i<11; i++){
static char *zName[] = {
"ref", "page", "max", "size", "state", "err",
"hit", "miss", "ovfl",
"hit", "miss", "ovfl", "read", "write"
};
char zBuf[100];
Tcl_AppendElement(interp, zName[i]);
@ -544,7 +546,9 @@ static int btree_pager_ref_dump(
return TCL_ERROR;
}
pBt = sqlite3TextToPtr(argv[1]);
#ifdef SQLITE_DEBUG
sqlite3pager_refdump(sqlite3BtreePager(pBt));
#endif
return TCL_OK;
}
@ -562,10 +566,10 @@ static int btree_integrity_check(
const char **argv /* Text of each argument */
){
Btree *pBt;
char *zResult;
int nRoot;
int *aRoot;
int i;
char *zResult;
if( argc<3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
@ -578,7 +582,11 @@ static int btree_integrity_check(
for(i=0; i<argc-2; i++){
if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
}
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot);
#else
zResult = 0;
#endif
if( zResult ){
Tcl_AppendResult(interp, zResult, 0);
sqliteFree(zResult);
@ -1014,7 +1022,7 @@ static int btree_key(
}
/*
** Usage: btree_data ID
** Usage: btree_data ID ?N?
**
** Return the data for the entry at which the cursor is pointing.
*/
@ -1029,13 +1037,17 @@ static int btree_data(
u32 n;
char *zBuf;
if( argc!=2 ){
if( argc!=2 && argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID\"", 0);
return TCL_ERROR;
}
pCur = sqlite3TextToPtr(argv[1]);
sqlite3BtreeDataSize(pCur, &n);
if( argc==2 ){
sqlite3BtreeDataSize(pCur, &n);
}else{
n = atoi(argv[2]);
}
zBuf = malloc( n+1 );
rc = sqlite3BtreeData(pCur, 0, n, zBuf);
if( rc ){
@ -1314,6 +1326,72 @@ static int btree_varint_test(
return TCL_OK;
}
/*
** usage: btree_from_db DB-HANDLE
**
** This command returns the btree handle for the main database associated
** with the database-handle passed as the argument. Example usage:
**
** sqlite3 db test.db
** set bt [btree_from_db db]
*/
static int btree_from_db(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
char zBuf[100];
Tcl_CmdInfo info;
sqlite3 *db;
Btree *pBt;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" DB-HANDLE\"", 0);
return TCL_ERROR;
}
if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){
Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
return TCL_ERROR;
}
db = *((sqlite3 **)info.objClientData);
assert( db );
pBt = db->aDb[0].pBt;
sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
return TCL_OK;
}
/*
** usage: btree_set_cache_size ID NCACHE
**
** Set the size of the cache used by btree $ID.
*/
static int btree_set_cache_size(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
int nCache;
Btree *pBt;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" BT NCACHE\"", 0);
return TCL_ERROR;
}
pBt = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
sqlite3BtreeSetCacheSize(pBt, nCache);
return TCL_OK;
}
/*
** Register commands with the TCL interpreter.
*/
@ -1360,6 +1438,8 @@ int Sqlitetest3_Init(Tcl_Interp *interp){
{ "btree_begin_statement", (Tcl_CmdProc*)btree_begin_statement },
{ "btree_commit_statement", (Tcl_CmdProc*)btree_commit_statement },
{ "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement },
{ "btree_from_db", (Tcl_CmdProc*)btree_from_db },
{ "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size },
};
int i;

View File

@ -190,7 +190,9 @@ static int test_translate_selftest(
int objc,
Tcl_Obj *CONST objv[]
){
#ifndef SQLITE_OMIT_UTF16
sqlite3utfSelfTest();
#endif
return SQLITE_OK;
}
@ -214,4 +216,3 @@ int Sqlitetest5_Init(Tcl_Interp *interp){
}
return SQLITE_OK;
}

View File

@ -23,106 +23,18 @@
#include <stdlib.h>
/*
** This function looks up an identifier to determine if it is a
** keyword. If it is a keyword, the token code of that keyword is
** The sqlite3KeywordCode function looks up an identifier to determine if
** it is a keyword. If it is a keyword, the token code of that keyword is
** returned. If the input is not a keyword, TK_ID is returned.
**
** The implementation of this routine was generated by a program,
** mkkeywordhash.c, located in the tool subdirectory of the distribution.
** The output of the mkkeywordhash.c program was manually cut and pasted
** into this file. When the set of keywords for SQLite changes, you
** must modify the mkkeywordhash.c program (to add or remove keywords from
** the data tables) then rerun that program to regenerate this function.
** mkkeywordhash.h, located in the tool subdirectory of the distribution.
** The output of the mkkeywordhash.c program is written into a file
** named keywordhash.h and then included into this source file by
** the #include below.
*/
int sqlite3KeywordCode(const char *z, int n){
static const char zText[519] =
"ABORTAFTERALLANDASCATTACHBEFOREBEGINBETWEENBYCASCADECASECHECK"
"COLLATECOMMITCONFLICTCONSTRAINTCREATECROSSDATABASEDEFAULTDEFERRABLE"
"DEFERREDDELETEDESCDETACHDISTINCTDROPEACHELSEENDEXCEPTEXCLUSIVE"
"EXPLAINFAILFOREIGNFROMFULLGLOBGROUPHAVINGIGNOREIMMEDIATEINDEX"
"INITIALLYINNERINSERTINSTEADINTERSECTINTOISNULLJOINKEYLEFTLIKE"
"LIMITMATCHNATURALNOTNULLNULLOFFSETONORDEROUTERPRAGMAPRIMARYRAISE"
"REFERENCESREPLACERESTRICTRIGHTROLLBACKROWSELECTSETSTATEMENTTABLE"
"TEMPORARYTHENTRANSACTIONTRIGGERUNIONUNIQUEUPDATEUSINGVACUUMVALUES"
"VIEWWHENWHERE";
static const unsigned char aHash[154] = {
0, 75, 82, 0, 0, 97, 80, 0, 83, 0, 0, 0, 0,
0, 0, 6, 0, 95, 4, 0, 0, 0, 0, 0, 0, 0,
0, 96, 86, 8, 0, 26, 13, 7, 19, 15, 0, 0, 32,
25, 0, 21, 31, 41, 0, 0, 0, 34, 27, 0, 0, 30,
0, 0, 0, 9, 0, 10, 0, 0, 0, 0, 51, 0, 44,
43, 0, 45, 40, 0, 29, 39, 35, 0, 0, 20, 0, 59,
0, 16, 0, 17, 0, 18, 0, 55, 42, 72, 0, 33, 0,
0, 61, 66, 56, 0, 0, 0, 0, 0, 0, 0, 54, 0,
0, 0, 0, 0, 74, 50, 76, 64, 52, 0, 0, 0, 0,
68, 84, 0, 47, 0, 58, 60, 92, 0, 0, 48, 0, 93,
0, 63, 71, 98, 0, 0, 0, 0, 0, 67, 0, 0, 0,
0, 87, 0, 0, 0, 0, 0, 90, 88, 0, 94,
};
static const unsigned char aNext[98] = {
0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
0, 12, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0,
0, 0, 0, 14, 3, 24, 0, 0, 0, 1, 22, 0, 0,
36, 23, 28, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0,
0, 49, 37, 0, 0, 0, 38, 0, 53, 0, 57, 62, 0,
0, 0, 0, 0, 0, 70, 46, 0, 65, 0, 0, 0, 0,
69, 73, 0, 77, 0, 0, 0, 0, 0, 0, 81, 85, 0,
91, 79, 78, 0, 0, 89, 0,
};
static const unsigned char aLen[98] = {
5, 5, 3, 3, 2, 3, 6, 6, 5, 7, 2, 7, 4,
5, 7, 6, 8, 10, 6, 5, 8, 7, 10, 8, 6, 4,
6, 8, 4, 4, 4, 3, 6, 9, 7, 4, 3, 7, 4,
4, 4, 5, 6, 6, 9, 2, 5, 9, 5, 6, 7, 9,
4, 2, 6, 4, 3, 4, 4, 5, 5, 7, 3, 7, 4,
2, 6, 2, 2, 5, 5, 6, 7, 5, 10, 7, 8, 5,
8, 3, 6, 3, 9, 5, 4, 9, 4, 11, 7, 5, 6,
6, 5, 6, 6, 4, 4, 5,
};
static const unsigned short int aOffset[98] = {
0, 5, 10, 13, 16, 16, 19, 25, 31, 36, 43, 45, 52,
56, 61, 68, 74, 82, 92, 98, 103, 111, 118, 128, 136, 142,
146, 152, 160, 164, 168, 172, 175, 181, 190, 197, 201, 201, 208,
212, 216, 220, 225, 231, 237, 246, 246, 251, 260, 265, 271, 278,
287, 291, 291, 297, 301, 304, 308, 312, 317, 322, 329, 329, 336,
340, 340, 346, 348, 348, 353, 358, 364, 371, 376, 386, 393, 401,
406, 414, 417, 423, 426, 435, 440, 440, 449, 453, 464, 471, 476,
482, 488, 493, 499, 505, 509, 513,
};
static const unsigned char aCode[98] = {
TK_ABORT, TK_AFTER, TK_ALL, TK_AND, TK_AS,
TK_ASC, TK_ATTACH, TK_BEFORE, TK_BEGIN, TK_BETWEEN,
TK_BY, TK_CASCADE, TK_CASE, TK_CHECK, TK_COLLATE,
TK_COMMIT, TK_CONFLICT, TK_CONSTRAINT, TK_CREATE, TK_JOIN_KW,
TK_DATABASE, TK_DEFAULT, TK_DEFERRABLE, TK_DEFERRED, TK_DELETE,
TK_DESC, TK_DETACH, TK_DISTINCT, TK_DROP, TK_EACH,
TK_ELSE, TK_END, TK_EXCEPT, TK_EXCLUSIVE, TK_EXPLAIN,
TK_FAIL, TK_FOR, TK_FOREIGN, TK_FROM, TK_JOIN_KW,
TK_GLOB, TK_GROUP, TK_HAVING, TK_IGNORE, TK_IMMEDIATE,
TK_IN, TK_INDEX, TK_INITIALLY, TK_JOIN_KW, TK_INSERT,
TK_INSTEAD, TK_INTERSECT, TK_INTO, TK_IS, TK_ISNULL,
TK_JOIN, TK_KEY, TK_JOIN_KW, TK_LIKE, TK_LIMIT,
TK_MATCH, TK_JOIN_KW, TK_NOT, TK_NOTNULL, TK_NULL,
TK_OF, TK_OFFSET, TK_ON, TK_OR, TK_ORDER,
TK_JOIN_KW, TK_PRAGMA, TK_PRIMARY, TK_RAISE, TK_REFERENCES,
TK_REPLACE, TK_RESTRICT, TK_JOIN_KW, TK_ROLLBACK, TK_ROW,
TK_SELECT, TK_SET, TK_STATEMENT, TK_TABLE, TK_TEMP,
TK_TEMP, TK_THEN, TK_TRANSACTION,TK_TRIGGER, TK_UNION,
TK_UNIQUE, TK_UPDATE, TK_USING, TK_VACUUM, TK_VALUES,
TK_VIEW, TK_WHEN, TK_WHERE,
};
int h, i;
if( n<2 ) return TK_ID;
h = (sqlite3UpperToLower[((unsigned char*)z)[0]]*5 +
sqlite3UpperToLower[((unsigned char*)z)[n-1]]*3 +
n) % 154;
for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){
if( aLen[i]==n && sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){
return aCode[i];
}
}
return TK_ID;
}
#include "keywordhash.h"
/*
** If X is a character that can be used in an identifier and
@ -137,9 +49,15 @@ int sqlite3KeywordCode(const char *z, int n){
** with the high-order bit set. The latter rule means that
** any sequence of UTF-8 characters or characters taken from
** an extended ISO8859 character set can form an identifier.
**
** Ticket #1066. the SQL standard does not allow '$' in the
** middle of identfiers. But many SQL implementations do.
** SQLite will allow '$' in identifiers for compatibility.
** But the feature is undocumented.
*/
static const char isIdChar[] = {
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */
@ -147,13 +65,13 @@ static const char isIdChar[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */
};
#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x2f && isIdChar[c-0x30]))
#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && isIdChar[c-0x20]))
/*
** Return the length of the token that begins at z[0].
** Store the token type in *tokenType before returning.
*/
static int sqliteGetToken(const unsigned char *z, int *tokenType){
static int getToken(const unsigned char *z, int *tokenType){
int i, c;
switch( *z ){
case ' ': case '\t': case '\n': case '\f': case '\r': {
@ -265,6 +183,11 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){
*tokenType = TK_BITNOT;
return 1;
}
case '#': {
for(i=1; isdigit(z[i]) || (i==1 && z[1]=='-'); i++){}
*tokenType = TK_REGISTER;
return i;
}
case '\'': case '"': {
int delim = z[0];
for(i=1; (c=z[i])!=0; i++){
@ -288,6 +211,7 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){
case '5': case '6': case '7': case '8': case '9': {
*tokenType = TK_INTEGER;
for(i=1; isdigit(z[i]); i++){}
#ifndef SQLITE_OMIT_FLOATING_POINT
if( z[i]=='.' && isdigit(z[i+1]) ){
i += 2;
while( isdigit(z[i]) ){ i++; }
@ -302,6 +226,7 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){
while( isdigit(z[i]) ){ i++; }
*tokenType = TK_FLOAT;
}
#endif
return i;
}
case '[': {
@ -319,6 +244,7 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){
*tokenType = i>1 ? TK_VARIABLE : TK_ILLEGAL;
return i;
}
#ifndef SQLITE_OMIT_TCL_VARIABLE
case '$': {
*tokenType = TK_VARIABLE;
if( z[1]=='{' ){
@ -355,7 +281,9 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){
if( n==0 ) *tokenType = TK_ILLEGAL;
}
return i;
}
}
#endif
#ifndef SQLITE_OMIT_BLOB_LITERAL
case 'x': case 'X': {
if( (c=z[1])=='\'' || c=='"' ){
int delim = c;
@ -375,18 +303,22 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){
}
/* Otherwise fall through to the next case */
}
#endif
default: {
if( !IdChar(*z) ){
break;
}
for(i=1; IdChar(z[i]); i++){}
*tokenType = sqlite3KeywordCode((char*)z, i);
*tokenType = keywordCode((char*)z, i);
return i;
}
}
*tokenType = TK_ILLEGAL;
return 1;
}
int sqlite3GetToken(const unsigned char *z, int *tokenType){
return getToken(z, tokenType);
}
/*
** Run the parser on the given SQL string. The parser structure is
@ -426,7 +358,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
assert( i>=0 );
pParse->sLastToken.z = &zSql[i];
assert( pParse->sLastToken.dyn==0 );
pParse->sLastToken.n = sqliteGetToken((unsigned char*)&zSql[i], &tokenType);
pParse->sLastToken.n = getToken((unsigned char*)&zSql[i],&tokenType);
i += pParse->sLastToken.n;
switch( tokenType ){
case TK_SPACE:
@ -486,7 +418,7 @@ abort_parse:
pParse->zErrMsg = 0;
if( !nErr ) nErr++;
}
if( pParse->pVdbe && pParse->nErr>0 ){
if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){
sqlite3VdbeDelete(pParse->pVdbe);
pParse->pVdbe = 0;
}
@ -503,14 +435,14 @@ abort_parse:
** Token types used by the sqlite3_complete() routine. See the header
** comments on that procedure for additional information.
*/
#define tkEXPLAIN 0
#define tkCREATE 1
#define tkTEMP 2
#define tkTRIGGER 3
#define tkEND 4
#define tkSEMI 5
#define tkWS 6
#define tkOTHER 7
#define tkSEMI 0
#define tkWS 1
#define tkOTHER 2
#define tkEXPLAIN 3
#define tkCREATE 4
#define tkTEMP 5
#define tkTRIGGER 6
#define tkEND 7
/*
** Return TRUE if the given SQL string ends in a semicolon.
@ -525,16 +457,16 @@ abort_parse:
** returns 1 if it ends in the START state and 0 if it ends
** in any other state.
**
** (1) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
** (1) NORMAL We are in the middle of statement which ends with a single
** semicolon.
**
** (2) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
** a statement.
**
** (2) CREATE The keyword CREATE has been seen at the beginning of a
** (3) CREATE The keyword CREATE has been seen at the beginning of a
** statement, possibly preceeded by EXPLAIN and/or followed by
** TEMP or TEMPORARY
**
** (3) NORMAL We are in the middle of statement which ends with a single
** semicolon.
**
** (4) TRIGGER We are in the middle of a trigger definition that must be
** ended by a semicolon, the keyword END, and another semicolon.
**
@ -547,36 +479,51 @@ abort_parse:
** Transitions between states above are determined by tokens extracted
** from the input. The following tokens are significant:
**
** (0) tkEXPLAIN The "explain" keyword.
** (1) tkCREATE The "create" keyword.
** (2) tkTEMP The "temp" or "temporary" keyword.
** (3) tkTRIGGER The "trigger" keyword.
** (4) tkEND The "end" keyword.
** (5) tkSEMI A semicolon.
** (6) tkWS Whitespace
** (7) tkOTHER Any other SQL token.
** (0) tkSEMI A semicolon.
** (1) tkWS Whitespace
** (2) tkOTHER Any other SQL token.
** (3) tkEXPLAIN The "explain" keyword.
** (4) tkCREATE The "create" keyword.
** (5) tkTEMP The "temp" or "temporary" keyword.
** (6) tkTRIGGER The "trigger" keyword.
** (7) tkEND The "end" keyword.
**
** Whitespace never causes a state transition and is always ignored.
**
** If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed
** to recognize the end of a trigger can be omitted. All we have to do
** is look for a semicolon that is not part of an string or comment.
*/
int sqlite3_complete(const char *zSql){
u8 state = 0; /* Current state, using numbers defined in header comment */
u8 token; /* Value of the next token */
/* The following matrix defines the transition from one state to another
** according to what token is seen. trans[state][token] returns the
** next state.
#ifndef SQLITE_OMIT_TRIGGER
/* A complex statement machine used to detect the end of a CREATE TRIGGER
** statement. This is the normal case.
*/
static const u8 trans[7][8] = {
/* Token: */
/* State: ** EXPLAIN CREATE TEMP TRIGGER END SEMI WS OTHER */
/* 0 START: */ { 1, 2, 3, 3, 3, 0, 0, 3, },
/* 1 EXPLAIN: */ { 3, 2, 3, 3, 3, 0, 1, 3, },
/* 2 CREATE: */ { 3, 3, 2, 4, 3, 0, 2, 3, },
/* 3 NORMAL: */ { 3, 3, 3, 3, 3, 0, 3, 3, },
/* 4 TRIGGER: */ { 4, 4, 4, 4, 4, 5, 4, 4, },
/* 5 SEMI: */ { 4, 4, 4, 4, 6, 5, 5, 4, },
/* 6 END: */ { 4, 4, 4, 4, 4, 0, 6, 4, },
/* State: ** SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END */
/* 0 START: */ { 0, 0, 1, 2, 3, 1, 1, 1, },
/* 1 NORMAL: */ { 0, 1, 1, 1, 1, 1, 1, 1, },
/* 2 EXPLAIN: */ { 0, 2, 1, 1, 3, 1, 1, 1, },
/* 3 CREATE: */ { 0, 3, 1, 1, 1, 3, 4, 1, },
/* 4 TRIGGER: */ { 5, 4, 4, 4, 4, 4, 4, 4, },
/* 5 SEMI: */ { 5, 5, 4, 4, 4, 4, 4, 6, },
/* 6 END: */ { 0, 6, 4, 4, 4, 4, 4, 4, },
};
#else
/* If triggers are not suppored by this compile then the statement machine
** used to detect the end of a statement is much simplier
*/
static const u8 trans[2][3] = {
/* Token: */
/* State: ** SEMI WS OTHER */
/* 0 START: */ { 0, 0, 1, },
/* 1 NORMAL: */ { 0, 1, 1, },
};
#endif /* SQLITE_OMIT_TRIGGER */
while( *zSql ){
switch( *zSql ){
@ -636,6 +583,9 @@ int sqlite3_complete(const char *zSql){
/* Keywords and unquoted identifiers */
int nId;
for(nId=1; IdChar(zSql[nId]); nId++){}
#ifdef SQLITE_OMIT_TRIGGER
token = tkOTHER;
#else
switch( *zSql ){
case 'c': case 'C': {
if( nId==6 && sqlite3StrNICmp(zSql, "create", 6)==0 ){
@ -660,9 +610,13 @@ int sqlite3_complete(const char *zSql){
case 'e': case 'E': {
if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){
token = tkEND;
}else if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){
}else
#ifndef SQLITE_OMIT_EXPLAIN
if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){
token = tkEXPLAIN;
}else{
}else
#endif
{
token = tkOTHER;
}
break;
@ -672,6 +626,7 @@ int sqlite3_complete(const char *zSql){
break;
}
}
#endif /* SQLITE_OMIT_TRIGGER */
zSql += nId-1;
}else{
/* Operators and special symbols */
@ -686,6 +641,7 @@ int sqlite3_complete(const char *zSql){
return state==0;
}
#ifndef SQLITE_OMIT_UTF16
/*
** This routine is the same as the sqlite3_complete() routine described
** above, except that the parameter is required to be UTF-16 encoded, not
@ -705,3 +661,4 @@ int sqlite3_complete16(const void *zSql){
sqlite3ValueFree(pVal);
return rc;
}
#endif /* SQLITE_OMIT_UTF16 */

View File

@ -12,6 +12,7 @@
*/
#include "sqliteInt.h"
#ifndef SQLITE_OMIT_TRIGGER
/*
** Delete a linked list of TriggerStep structures.
*/
@ -110,9 +111,7 @@ void sqlite3BeginTrigger(
}
/* Do not create a trigger on a system table */
if( (iDb!=1 && sqlite3StrICmp(pTab->zName, MASTER_NAME)==0) ||
(iDb==1 && sqlite3StrICmp(pTab->zName, TEMP_MASTER_NAME)==0)
){
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){
sqlite3ErrorMsg(pParse, "cannot create trigger on system table");
pParse->nErr++;
goto trigger_cleanup;
@ -166,7 +165,7 @@ void sqlite3BeginTrigger(
pTrigger->iDb = iDb;
pTrigger->iTabDb = pTab->iDb;
pTrigger->op = op;
pTrigger->tr_tm = tr_tm;
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
pTrigger->pWhen = sqlite3ExprDup(pWhen);
pTrigger->pColumns = sqlite3IdListDup(pColumns);
pTrigger->foreach = foreach;
@ -190,20 +189,20 @@ void sqlite3FinishTrigger(
TriggerStep *pStepList, /* The triggered program */
Token *pAll /* Token that describes the complete CREATE TRIGGER */
){
Trigger *nt = 0; /* The trigger whose construction is finishing up */
Trigger *pTrig = 0; /* The trigger whose construction is finishing up */
sqlite3 *db = pParse->db; /* The database */
DbFixer sFix;
if( pParse->nErr || pParse->pNewTrigger==0 ) goto triggerfinish_cleanup;
nt = pParse->pNewTrigger;
pTrig = pParse->pNewTrigger;
pParse->pNewTrigger = 0;
nt->step_list = pStepList;
pTrig->step_list = pStepList;
while( pStepList ){
pStepList->pTrig = nt;
pStepList->pTrig = pTrig;
pStepList = pStepList->pNext;
}
if( sqlite3FixInit(&sFix, pParse, nt->iDb, "trigger", &nt->nameToken)
&& sqlite3FixTriggerStep(&sFix, nt->step_list) ){
if( sqlite3FixInit(&sFix, pParse, pTrig->iDb, "trigger", &pTrig->nameToken)
&& sqlite3FixTriggerStep(&sFix, pTrig->step_list) ){
goto triggerfinish_cleanup;
}
@ -229,35 +228,32 @@ void sqlite3FinishTrigger(
/* Make an entry in the sqlite_master table */
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto triggerfinish_cleanup;
sqlite3BeginWriteOperation(pParse, 0, nt->iDb);
sqlite3OpenMasterTable(v, nt->iDb);
sqlite3BeginWriteOperation(pParse, 0, pTrig->iDb);
sqlite3OpenMasterTable(v, pTrig->iDb);
addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
sqlite3VdbeChangeP3(v, addr+2, nt->name, 0);
sqlite3VdbeChangeP3(v, addr+3, nt->table, 0);
sqlite3VdbeChangeP3(v, addr+2, pTrig->name, 0);
sqlite3VdbeChangeP3(v, addr+3, pTrig->table, 0);
sqlite3VdbeChangeP3(v, addr+6, pAll->z, pAll->n);
if( nt->iDb!=0 ){
sqlite3ChangeCookie(db, v, nt->iDb);
}
sqlite3ChangeCookie(db, v, pTrig->iDb);
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
sqlite3VdbeOp3(v, OP_ParseSchema, nt->iDb, 0,
sqlite3MPrintf("type='trigger' AND name='%q'", nt->name), P3_DYNAMIC);
sqlite3VdbeOp3(v, OP_ParseSchema, pTrig->iDb, 0,
sqlite3MPrintf("type='trigger' AND name='%q'", pTrig->name), P3_DYNAMIC);
}
if( db->init.busy ){
Table *pTab;
sqlite3HashInsert(&db->aDb[nt->iDb].trigHash,
nt->name, strlen(nt->name)+1, nt);
pTab = sqlite3LocateTable(pParse, nt->table, db->aDb[nt->iTabDb].zName);
sqlite3HashInsert(&db->aDb[pTrig->iDb].trigHash,
pTrig->name, strlen(pTrig->name)+1, pTrig);
pTab = sqlite3LocateTable(pParse,pTrig->table,db->aDb[pTrig->iTabDb].zName);
assert( pTab!=0 );
nt->pNext = pTab->pTrigger;
pTab->pTrigger = nt;
nt = 0;
pTrig->pNext = pTab->pTrigger;
pTab->pTrigger = pTrig;
pTrig = 0;
}
triggerfinish_cleanup:
sqlite3DeleteTrigger(nt);
sqlite3DeleteTrigger(pParse->pNewTrigger);
pParse->pNewTrigger = 0;
sqlite3DeleteTrigger(pTrig);
assert( !pParse->pNewTrigger );
sqlite3DeleteTriggerStep(pStepList);
}
@ -555,52 +551,38 @@ static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
return 0;
}
/* A global variable that is TRUE if we should always set up temp tables for
* for triggers, even if there are no triggers to code. This is used to test
* how much overhead the triggers algorithm is causing.
*
* This flag can be set or cleared using the "trigger_overhead_test" pragma.
* The pragma is not documented since it is not really part of the interface
* to SQLite, just the test procedure.
*/
int sqlite3_always_code_trigger_setup = 0;
/*
* Returns true if a trigger matching op, tr_tm and foreach that is NOT already
* on the Parse objects trigger-stack (to prevent recursive trigger firing) is
* found in the list specified as pTrigger.
*/
** Return a bit vector to indicate what kind of triggers exist for operation
** "op" on table pTab. If pChanges is not NULL then it is a list of columns
** that are being updated. Triggers only match if the ON clause of the
** trigger definition overlaps the set of columns being updated.
**
** The returned bit vector is some combination of TRIGGER_BEFORE and
** TRIGGER_AFTER.
*/
int sqlite3TriggersExist(
Parse *pParse, /* Used to check for recursive triggers */
Trigger *pTrigger, /* A list of triggers associated with a table */
Table *pTab, /* The table the contains the triggers */
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
int tr_tm, /* one of TK_BEFORE, TK_AFTER */
int foreach, /* one of TK_ROW or TK_STATEMENT */
ExprList *pChanges /* Columns that change in an UPDATE statement */
){
Trigger * pTriggerCursor;
Trigger *pTrigger = pTab->pTrigger;
int mask = 0;
if( sqlite3_always_code_trigger_setup ){
return 1;
}
pTriggerCursor = pTrigger;
while( pTriggerCursor ){
if( pTriggerCursor->op == op &&
pTriggerCursor->tr_tm == tr_tm &&
pTriggerCursor->foreach == foreach &&
checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){
TriggerStack * ss;
while( pTrigger ){
if( pTrigger->op==op && checkColumnOverLap(pTrigger->pColumns, pChanges) ){
TriggerStack *ss;
ss = pParse->trigStack;
while( ss && ss->pTrigger != pTrigger ){
while( ss && ss->pTrigger!=pTab->pTrigger ){
ss = ss->pNext;
}
if( !ss )return 1;
if( ss==0 ){
mask |= pTrigger->tr_tm;
}
}
pTriggerCursor = pTriggerCursor->pNext;
pTrigger = pTrigger->pNext;
}
return 0;
return mask;
}
/*
@ -658,6 +640,7 @@ static int codeTriggerProgram(
Select * ss = sqlite3SelectDup(pTriggerStep->pSelect);
assert(ss);
assert(ss->pSrc);
sqlite3SelectResolve(pParse, ss, 0);
sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
sqlite3SelectDelete(ss);
break;
@ -726,7 +709,7 @@ int sqlite3CodeRowTrigger(
Parse *pParse, /* Parse context */
int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
int tr_tm, /* One of TK_BEFORE, TK_AFTER */
int tr_tm, /* One of TRIGGER_BEFORE, TRIGGER_AFTER */
Table *pTab, /* The table to code triggers from */
int newIdx, /* The indice of the "new" row to access */
int oldIdx, /* The indice of the "old" row to access */
@ -738,7 +721,7 @@ int sqlite3CodeRowTrigger(
TriggerStack trigStackEntry;
assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER );
assert(tr_tm == TRIGGER_BEFORE || tr_tm == TRIGGER_AFTER );
assert(newIdx != -1 || oldIdx != -1);
@ -747,8 +730,7 @@ int sqlite3CodeRowTrigger(
int fire_this = 0;
/* determine whether we should code this trigger */
if( pTrigger->op == op && pTrigger->tr_tm == tr_tm &&
pTrigger->foreach == TK_ROW ){
if( pTrigger->op == op && pTrigger->tr_tm == tr_tm ){
fire_this = 1;
for(pStack=pParse->trigStack; pStack; pStack=pStack->pNext){
if( pStack->pTrigger==pTrigger ){
@ -763,11 +745,12 @@ int sqlite3CodeRowTrigger(
if( fire_this ){
int endTrigger;
SrcList dummyTablist;
Expr * whenExpr;
AuthContext sContext;
NameContext sNC;
dummyTablist.nSrc = 0;
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
/* Push an entry on to the trigger stack */
trigStackEntry.pTrigger = pTrigger;
@ -782,7 +765,7 @@ int sqlite3CodeRowTrigger(
/* code the WHEN clause */
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
whenExpr = sqlite3ExprDup(pTrigger->pWhen);
if( sqlite3ExprResolveIds(pParse, &dummyTablist, 0, whenExpr) ){
if( sqlite3ExprResolveNames(&sNC, whenExpr) ){
pParse->trigStack = trigStackEntry.pNext;
sqlite3ExprDelete(whenExpr);
return 1;
@ -802,3 +785,4 @@ int sqlite3CodeRowTrigger(
}
return 0;
}
#endif /* !defined(SQLITE_OMIT_TRIGGER) */

View File

@ -48,12 +48,13 @@ void sqlite3Update(
int chngRecno; /* True if the record number is being changed */
Expr *pRecnoExpr = 0; /* Expression defining the new record number */
int openAll = 0; /* True if all indices need to be opened */
int isView; /* Trying to update a view */
AuthContext sContext; /* The authorization context */
NameContext sNC; /* The name-context to resolve expressions in */
int before_triggers; /* True if there are any BEFORE triggers */
int after_triggers; /* True if there are any AFTER triggers */
int row_triggers_exist = 0; /* True if any row triggers exist */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* Trying to update a view */
int triggers_exist = 0; /* True if any row triggers exist */
#endif
int newIdx = -1; /* index of trigger "new" temp table */
int oldIdx = -1; /* index of trigger "old" temp table */
@ -67,13 +68,23 @@ void sqlite3Update(
*/
pTab = sqlite3SrcListLookup(pParse, pTabList);
if( pTab==0 ) goto update_cleanup;
before_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
TK_UPDATE, TK_BEFORE, TK_ROW, pChanges);
after_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
TK_UPDATE, TK_AFTER, TK_ROW, pChanges);
row_triggers_exist = before_triggers || after_triggers;
/* Figure out if we have any triggers and if the table being
** updated is a view
*/
#ifndef SQLITE_OMIT_TRIGGER
triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges);
isView = pTab->pSelect!=0;
if( sqlite3IsReadOnly(pParse, pTab, before_triggers) ){
#else
# define triggers_exist 0
# define isView 0
#endif
#ifdef SQLITE_OMIT_VIEW
# undef isView
# define isView 0
#endif
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
goto update_cleanup;
}
if( isView ){
@ -88,7 +99,7 @@ void sqlite3Update(
/* If there are FOR EACH ROW triggers, allocate cursors for the
** special OLD and NEW tables
*/
if( row_triggers_exist ){
if( triggers_exist ){
newIdx = pParse->nTab++;
oldIdx = pParse->nTab++;
}
@ -103,6 +114,11 @@ void sqlite3Update(
pParse->nTab++;
}
/* Initialize the name-context */
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
/* Resolve the column names in all the expressions of the
** of the UPDATE statement. Also find the column index
** for each column to be updated in the pChanges array. For each
@ -111,8 +127,7 @@ void sqlite3Update(
*/
chngRecno = 0;
for(i=0; i<pChanges->nExpr; i++){
if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0,
pChanges->a[i].pExpr, 0, 0) ){
if( sqlite3ExprResolveNames(&sNC, pChanges->a[i].pExpr) ){
goto update_cleanup;
}
for(j=0; j<pTab->nCol; j++){
@ -188,7 +203,7 @@ void sqlite3Update(
/* Resolve the column names in all the expressions in the
** WHERE clause.
*/
if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){
if( sqlite3ExprResolveNames(&sNC, pWhere) ){
goto update_cleanup;
}
@ -202,7 +217,7 @@ void sqlite3Update(
*/
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto update_cleanup;
sqlite3VdbeCountChanges(v);
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, 1, pTab->iDb);
/* If we are trying to update a view, construct that view into
@ -217,11 +232,12 @@ void sqlite3Update(
/* Begin the database scan
*/
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0);
if( pWInfo==0 ) goto update_cleanup;
/* Remember the index of every item to be updated.
*/
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
/* End the database scan loop.
@ -234,7 +250,7 @@ void sqlite3Update(
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
}
if( row_triggers_exist ){
if( triggers_exist ){
/* Create pseudo-tables for NEW and OLD
*/
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
@ -266,11 +282,11 @@ void sqlite3Update(
/* Generate the NEW table
*/
if( chngRecno ){
sqlite3ExprCode(pParse, pRecnoExpr);
sqlite3ExprCodeAndCache(pParse, pRecnoExpr);
}else{
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
}
for(i=0; i<pTab->nCol; i++){ /* TODO: Factor out this loop as common code */
for(i=0; i<pTab->nCol; i++){
if( i==pTab->iPKey ){
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
continue;
@ -279,7 +295,7 @@ void sqlite3Update(
if( j<0 ){
sqlite3VdbeAddOp(v, OP_Column, iCur, i);
}else{
sqlite3ExprCode(pParse, pChanges->a[j].pExpr);
sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr);
}
}
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
@ -294,7 +310,7 @@ void sqlite3Update(
/* Fire the BEFORE and INSTEAD OF triggers
*/
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, pTab,
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab,
newIdx, oldIdx, onError, addr) ){
goto update_cleanup;
}
@ -336,7 +352,7 @@ void sqlite3Update(
** Also, the old data is needed to delete the old index entires.
** So make the cursor point at the old record.
*/
if( !row_triggers_exist ){
if( !triggers_exist ){
sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, 0);
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
@ -396,7 +412,7 @@ void sqlite3Update(
/* If there are triggers, close all the cursors after each iteration
** through the loop. The fire the after triggers.
*/
if( row_triggers_exist ){
if( triggers_exist ){
if( !isView ){
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
if( openAll || aIdxUsed[i] )
@ -404,7 +420,7 @@ void sqlite3Update(
}
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, pTab,
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab,
newIdx, oldIdx, onError, addr) ){
goto update_cleanup;
}
@ -418,7 +434,7 @@ void sqlite3Update(
sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
/* Close all tables if there were no FOR EACH ROW triggers */
if( !row_triggers_exist ){
if( !triggers_exist ){
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
if( openAll || aIdxUsed[i] ){
sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
@ -431,9 +447,11 @@ void sqlite3Update(
}
/*
** Return the number of rows that were changed.
** Return the number of rows that were changed. If this routine is
** generating code because of a call to sqlite3NestedParse(), do not
** invoke the callback function.
*/
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, "rows updated", P3_STATIC);

View File

@ -58,8 +58,8 @@
** sqlite3utf8LikeCompare() - Do a LIKE match given two UTF8 char* strings.
**
*/
#include <assert.h>
#include "sqliteInt.h"
#include <assert.h>
#include "vdbeInt.h"
/*
@ -232,6 +232,7 @@ int sqlite3ReadUtf8(const unsigned char *z){
*/
/* #define TRANSLATE_TRACE 1 */
#ifndef SQLITE_OMIT_UTF16
/*
** This routine transforms the internal text encoding used by pMem to
** desiredEnc. It is an error if the string is already of the desired
@ -251,7 +252,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
assert( pMem->enc!=0 );
assert( pMem->n>=0 );
#ifdef TRANSLATE_TRACE
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
{
char zBuf[100];
sqlite3VdbeMemPrettyPrint(pMem, zBuf, 100);
@ -367,7 +368,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
pMem->z = zOut;
translate_out:
#ifdef TRANSLATE_TRACE
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
{
char zBuf[100];
sqlite3VdbeMemPrettyPrint(pMem, zBuf, 100);
@ -423,6 +424,7 @@ int sqlite3VdbeMemHandleBom(Mem *pMem){
}
return rc;
}
#endif /* SQLITE_OMIT_UTF16 */
/*
** pZ is a UTF-8 encoded unicode string. If nByte is less than zero,
@ -447,6 +449,7 @@ int sqlite3utf8CharLen(const char *z, int nByte){
return r;
}
#ifndef SQLITE_OMIT_UTF16
/*
** pZ is a UTF-16 encoded unicode string. If nChar is less than zero,
** return the number of bytes up to (but not including), the first pair
@ -563,4 +566,5 @@ void sqlite3utfSelfTest(){
assert( (z-zBuf)==n );
}
}
#endif
#endif /* SQLITE_TEST */
#endif /* SQLITE_OMIT_UTF16 */

View File

@ -20,18 +20,18 @@
#include <stdarg.h>
#include <ctype.h>
#if SQLITE_DEBUG>2 && defined(__GLIBC__)
#if SQLITE_MEMDEBUG>2 && defined(__GLIBC__)
#include <execinfo.h>
void print_stack_trace(){
void *bt[30];
int i;
int n = backtrace(bt, 30);
sqlite3DebugPrintf("STACK: ");
fprintf(stderr, "STACK: ");
for(i=0; i<n;i++){
sqlite3DebugPrintf("%p ", bt[i]);
fprintf(stderr, "%p ", bt[i]);
}
sqlite3DebugPrintf("\n");
fprintf(stderr, "\n");
}
#else
#define print_stack_trace()
@ -44,19 +44,23 @@ void print_stack_trace(){
int sqlite3_malloc_failed = 0;
/*
** If SQLITE_DEBUG is defined, then use versions of malloc() and
** If SQLITE_MEMDEBUG is defined, then use versions of malloc() and
** free() that track memory usage and check for buffer overruns.
*/
#ifdef SQLITE_DEBUG
#ifdef SQLITE_MEMDEBUG
/*
** For keeping track of the number of mallocs and frees. This
** is used to check for memory leaks.
** is used to check for memory leaks. The iMallocFail and iMallocReset
** values are used to simulate malloc() failures during testing in
** order to verify that the library correctly handles an out-of-memory
** condition.
*/
int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */
int sqlite3_nFree; /* Number of sqliteFree() calls */
int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */
#if SQLITE_DEBUG>1
int sqlite3_iMallocReset = -1; /* When iMallocFail reaches 0, set to this */
#if SQLITE_MEMDEBUG>1
static int memcnt = 0;
#endif
@ -77,11 +81,11 @@ void *sqlite3Malloc_(int n, int bZero, char *zFile, int line){
sqlite3_iMallocFail--;
if( sqlite3_iMallocFail==0 ){
sqlite3_malloc_failed++;
#if SQLITE_DEBUG>1
#if SQLITE_MEMDEBUG>1
fprintf(stderr,"**** failed to allocate %d bytes at %s:%d\n",
n, zFile,line);
#endif
sqlite3_iMallocFail--;
sqlite3_iMallocFail = sqlite3_iMallocReset;
return 0;
}
}
@ -89,7 +93,7 @@ void *sqlite3Malloc_(int n, int bZero, char *zFile, int line){
k = (n+sizeof(int)-1)/sizeof(int);
pi = malloc( (N_GUARD*2+1+k)*sizeof(int));
if( pi==0 ){
sqlite3_malloc_failed++;
if( n>0 ) sqlite3_malloc_failed++;
return 0;
}
sqlite3_nMalloc++;
@ -98,7 +102,7 @@ void *sqlite3Malloc_(int n, int bZero, char *zFile, int line){
for(i=0; i<N_GUARD; i++) pi[k+1+N_GUARD+i] = 0xdead3344;
p = &pi[N_GUARD+1];
memset(p, bZero==0, n);
#if SQLITE_DEBUG>1
#if SQLITE_MEMDEBUG>1
print_stack_trace();
fprintf(stderr,"%06d malloc %d bytes at 0x%x from %s:%d\n",
++memcnt, n, (int)p, zFile,line);
@ -152,7 +156,7 @@ void sqlite3Free_(void *p, char *zFile, int line){
}
}
memset(pi, 0xff, (k+N_GUARD*2+1)*sizeof(int));
#if SQLITE_DEBUG>1
#if SQLITE_MEMDEBUG>1
fprintf(stderr,"%06d free %d bytes at 0x%x from %s:%d\n",
++memcnt, n, (int)p, zFile,line);
#endif
@ -193,7 +197,7 @@ void *sqlite3Realloc_(void *oldP, int n, char *zFile, int line){
k = (n + sizeof(int) - 1)/sizeof(int);
pi = malloc( (k+N_GUARD*2+1)*sizeof(int) );
if( pi==0 ){
sqlite3_malloc_failed++;
if( n>0 ) sqlite3_malloc_failed++;
return 0;
}
for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122;
@ -206,7 +210,7 @@ void *sqlite3Realloc_(void *oldP, int n, char *zFile, int line){
}
memset(oldPi, 0xab, (oldK+N_GUARD+2)*sizeof(int));
free(oldPi);
#if SQLITE_DEBUG>1
#if SQLITE_MEMDEBUG>1
print_stack_trace();
fprintf(stderr,"%06d realloc %d to %d bytes at 0x%x to 0x%x at %s:%d\n",
++memcnt, oldN, n, (int)oldP, (int)p, zFile, line);
@ -241,13 +245,13 @@ char *sqlite3StrNDup_(const char *z, int n, char *zFile, int line){
void sqlite3FreeX(void *p){
sqliteFree(p);
}
#endif /* SQLITE_DEBUG */
#endif /* SQLITE_MEMDEBUG */
/*
** The following versions of malloc() and free() are for use in a
** normal build.
*/
#if !defined(SQLITE_DEBUG)
#if !defined(SQLITE_MEMDEBUG)
/*
** Allocate new memory and set it to zero. Return NULL if
@ -300,7 +304,7 @@ void *sqlite3Realloc(void *p, int n){
}
p2 = realloc(p, n);
if( p2==0 ){
sqlite3_malloc_failed++;
if( n>0 ) sqlite3_malloc_failed++;
}
return p2;
}
@ -325,7 +329,7 @@ char *sqlite3StrNDup(const char *z, int n){
}
return zNew;
}
#endif /* !defined(SQLITE_DEBUG) */
#endif /* !defined(SQLITE_MEMDEBUG) */
/*
** Create a string from the 2nd and subsequent arguments (up to the
@ -488,20 +492,6 @@ const unsigned char sqlite3UpperToLower[] = {
};
#define UpperToLower sqlite3UpperToLower
/*
** This function computes a hash on the name of a keyword.
** Case is not significant.
*/
int sqlite3HashNoCase(const char *z, int n){
int h = 0;
if( n<=0 ) n = strlen(z);
while( n > 0 ){
h = (h<<3) ^ h ^ UpperToLower[(unsigned char)*z++];
n--;
}
return h & 0x7fffffff;
}
/*
** Some systems have stricmp(). Others have strcasecmp(). Because
** there is no consistency, we will define our own.
@ -796,7 +786,7 @@ int sqlite3SafetyCheck(sqlite3 *db){
int sqlite3PutVarint(unsigned char *p, u64 v){
int i, j, n;
u8 buf[10];
if( v & 0xff00000000000000 ){
if( v & (((u64)0xff000000)<<32) ){
p[8] = v;
v >>= 8;
for(i=7; i>=0; i--){
@ -868,6 +858,7 @@ int sqlite3GetVarint32(const unsigned char *p, u32 *v){
u32 x;
int n;
unsigned char c;
#if 0
if( ((c = p[0]) & 0x80)==0 ){
*v = c;
return 1;
@ -878,6 +869,18 @@ int sqlite3GetVarint32(const unsigned char *p, u32 *v){
return 2;
}
x = (x<<7) | (c & 0x7f);
#else
if( ((signed char*)p)[0]>=0 ){
*v = p[0];
return 1;
}
x = p[0] & 0x7f;
if( ((signed char*)p)[1]>=0 ){
*v = (x<<7) | p[1];
return 2;
}
x = (x<<7) | (p[1] & 0x7f);
#endif
n = 2;
do{
x = (x<<7) | ((c = p[n++])&0x7f);
@ -899,6 +902,8 @@ int sqlite3VarintLen(u64 v){
return i;
}
#if (!defined(SQLITE_OMIT_BLOB_LITERAL) && !defined(SQLITE_HAS_CODEC)) \
|| defined(SQLITE_TEST)
/*
** Translate a single byte of Hex into an integer.
*/
@ -907,13 +912,14 @@ static int hexToInt(int h){
return h - '0';
}else if( h>='a' && h<='f' ){
return h - 'a' + 10;
}else if( h>='A' && h<='F' ){
return h - 'A' + 10;
}else{
return 0;
assert( h>='A' && h<='F' );
return h - 'A' + 10;
}
}
#endif /* (!SQLITE_OMIT_BLOB_LITERAL && !SQLITE_HAS_CODEC) || SQLITE_TEST */
#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
/*
** Convert a BLOB literal of the form "x'hhhhhh'" into its binary
** value. Return a pointer to its binary value. Space to hold the
@ -932,6 +938,7 @@ void *sqlite3HexToBlob(const char *z){
}
return zBlob;
}
#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
#if defined(SQLITE_TEST)
/*

View File

@ -19,7 +19,7 @@
#include "sqliteInt.h"
#include "os.h"
#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
#ifndef SQLITE_OMIT_VACUUM
/*
** Generate a random name of 20 character in length.
*/
@ -93,11 +93,10 @@ void sqlite3Vacuum(Parse *pParse, Token *pTableName){
*/
int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
int rc = SQLITE_OK; /* Return code from service routines */
#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
#ifndef SQLITE_OMIT_VACUUM
const char *zFilename; /* full pathname of the database file */
int nFilename; /* number of characters in zFilename[] */
char *zTemp = 0; /* a temporary file in same directory as zFilename */
int i; /* Loop counter */
Btree *pMain; /* The database being vacuumed */
Btree *pTemp;
char *zSql = 0;
@ -129,11 +128,19 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
goto end_of_vacuum;
}
strcpy(zTemp, zFilename);
i = 0;
/* The randomName() procedure in the following loop uses an excellent
** source of randomness to generate a name from a space of 1.3e+31
** possibilities. So unless the directory already contains on the order
** of 1.3e+31 files, the probability that the following loop will
** run more than once or twice is vanishingly small. We are certain
** enough that this loop will always terminate (and terminate quickly)
** that we don't even bother to set a maximum loop count.
*/
do {
zTemp[nFilename] = '-';
randomName((unsigned char*)&zTemp[nFilename+1]);
} while( i<10 && sqlite3OsFileExists(zTemp) );
} while( sqlite3OsFileExists(zTemp) );
/* 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
@ -159,6 +166,10 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
assert( sqlite3BtreeGetPageSize(pTemp)==sqlite3BtreeGetPageSize(pMain) );
execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
#ifndef SQLITE_OMIT_AUTOVACUUM
sqlite3BtreeSetAutoVacuum(pTemp, sqlite3BtreeGetAutoVacuum(pMain));
#endif
/* Begin a transaction */
rc = execSql(db, "BEGIN;");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
@ -168,14 +179,17 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
*/
rc = execExecSql(db,
"SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14,100000000) "
" FROM sqlite_master WHERE type='table' "
"UNION ALL "
"SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14,100000000) "
" FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' "
"UNION ALL "
" FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execExecSql(db,
"SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14,100000000)"
" FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' ");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execExecSql(db,
"SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21,100000000) "
" FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'"
"UNION ALL "
" FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execExecSql(db,
"SELECT 'CREATE VIEW vacuum_db.' || substr(sql,13,100000000) "
" FROM sqlite_master WHERE type='view'"
);
@ -189,10 +203,25 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
"|| ' SELECT * FROM ' || quote(name) || ';'"
"FROM sqlite_master "
"WHERE type = 'table';"
"WHERE type = 'table' AND name!='sqlite_sequence';"
);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Copy over the sequence table
*/
rc = execExecSql(db,
"SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' "
"FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' "
);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execExecSql(db,
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
"|| ' SELECT * FROM ' || quote(name) || ';' "
"FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';"
);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Copy the triggers from the main database to the temporary database.
** This was deferred before in case the triggers interfered with copying
** the data. It's possible the indices should be deferred until this
@ -215,22 +244,31 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
*/
if( sqlite3BtreeIsInTrans(pTemp) ){
u32 meta;
int i;
/* This array determines which meta meta values are preserved in the
** vacuum. Even entries are the meta value number and odd entries
** are an increment to apply to the meta value after the vacuum.
** The increment is used to increase the schema cookie so that other
** 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 */
};
assert( 0==sqlite3BtreeIsInTrans(pMain) );
rc = sqlite3BtreeBeginTrans(pMain, 1);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Copy Btree meta values 3 and 4. These correspond to SQL layer meta
** values 2 and 3, the default values of a couple of pragmas.
*/
rc = sqlite3BtreeGetMeta(pMain, 3, &meta);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = sqlite3BtreeUpdateMeta(pTemp, 3, meta);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = sqlite3BtreeGetMeta(pMain, 4, &meta);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = sqlite3BtreeUpdateMeta(pTemp, 4, meta);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Copy Btree meta values */
for(i=0; i<sizeof(aCopy)/sizeof(aCopy[0]); i+=2){
rc = sqlite3BtreeGetMeta(pMain, aCopy[i], &meta);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], meta+aCopy[i+1]);
}
rc = sqlite3BtreeCopyFile(pMain, pTemp);
if( rc!=SQLITE_OK ) goto end_of_vacuum;

View File

@ -69,6 +69,15 @@ int sqlite3_search_count = 0;
*/
int sqlite3_interrupt_count = 0;
/*
** The next global variable is incremented each type the OP_Sort opcode
** is executed. The test procedures use this information to make sure that
** sorting is occurring or not occuring at appropriate times. This variable
** has no function other than to help verify the correct operation of the
** library.
*/
int sqlite3_sort_count = 0;
/*
** Release the memory associated with the given stack level. This
** leaves the Mem.flags field in an inconsistent state.
@ -294,7 +303,7 @@ static void applyAffinity(Mem *pRec, char affinity, u8 enc){
}
}
#ifndef NDEBUG
#ifdef SQLITE_DEBUG
/*
** Write a nice string representation of the contents of cell pMem
** into buffer zBuf, length nBuf.
@ -371,7 +380,7 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf, int nBuf){
#ifdef VDBE_PROFILE
/*
** The following routine only works on pentium-class processors.
** It uses the RDTSC opcode to read cycle count value out of the
** It uses the RDTSC opcode to read the cycle count value out of the
** processor and returns that value. This can be used for high-res
** profiling.
*/
@ -468,9 +477,9 @@ int sqlite3VdbeExec(
#endif
pOp = &p->aOp[pc];
/* Only allow tracing if NDEBUG is not defined.
/* Only allow tracing if SQLITE_DEBUG is defined.
*/
#ifndef NDEBUG
#ifdef SQLITE_DEBUG
if( p->trace ){
if( pc==0 ){
printf("VDBE Execution Trace:\n");
@ -478,8 +487,6 @@ int sqlite3VdbeExec(
}
sqlite3VdbePrintOp(p->trace, pc, pOp);
}
#endif
#ifdef SQLITE_TEST
if( p->trace==0 && pc==0 && sqlite3OsFileExists("vdbe_sqltrace") ){
sqlite3VdbePrintSql(p);
}
@ -618,11 +625,10 @@ case OP_Halt: {
sqlite3SetString(&p->zErrMsg, pOp->p3, (char*)0);
}
rc = sqlite3VdbeHalt(p);
assert( rc==SQLITE_BUSY || rc==SQLITE_OK );
if( rc==SQLITE_BUSY ){
p->rc = SQLITE_BUSY;
return SQLITE_BUSY;
}else if( rc!=SQLITE_OK ){
p->rc = rc;
}
return p->rc ? SQLITE_ERROR : SQLITE_DONE;
}
@ -632,6 +638,9 @@ case OP_Halt: {
** The integer value P1 is pushed onto the stack. If P3 is not zero
** then it is assumed to be a string representation of the same integer.
** If P1 is zero and P3 is not zero, then the value is derived from P3.
**
** If the value cannot be represented as a 32-bits then its value
** will be in P3.
*/
case OP_Integer: {
pTos++;
@ -671,6 +680,7 @@ case OP_Real: { /* same as TK_FLOAT */
** into an OP_String before it is executed for the first time.
*/
case OP_String8: { /* same as TK_STRING */
#ifndef SQLITE_OMIT_UTF16
pOp->opcode = OP_String;
if( db->enc!=SQLITE_UTF8 && pOp->p3 ){
@ -687,6 +697,7 @@ case OP_String8: { /* same as TK_STRING */
pOp->p3 = pTos->z;
break;
}
#endif
/* Otherwise fall through to the next case, OP_String */
}
@ -701,11 +712,16 @@ case OP_String: {
if( pOp->p3 ){
pTos->flags = MEM_Str|MEM_Static|MEM_Term;
pTos->z = pOp->p3;
#ifndef SQLITE_OMIT_UTF16
if( db->enc==SQLITE_UTF8 ){
pTos->n = strlen(pTos->z);
}else{
pTos->n = sqlite3utf16ByteLen(pTos->z, -1);
}
#else
assert( db->enc==SQLITE_UTF8 );
pTos->n = strlen(pTos->z);
#endif
pTos->enc = db->enc;
}else{
pTos->flags = MEM_Null;
@ -713,6 +729,7 @@ case OP_String: {
break;
}
#ifndef SQLITE_OMIT_BLOB_LITERAL
/* Opcode: HexBlob * * P3
**
** P3 is an UTF-8 SQL hex encoding of a blob. The blob is pushed onto the
@ -750,13 +767,14 @@ case OP_HexBlob: { /* same as TK_BLOB */
** by the compiler. Instead, the compiler layer specifies
** an OP_HexBlob opcode, with the hex string representation of
** the blob as P3. This opcode is transformed to an OP_Blob
** before execution (within the sqlite3_prepare() function).
** the first time it is executed.
*/
case OP_Blob: {
pTos++;
sqlite3VdbeMemSetStr(pTos, pOp->p3, pOp->p1, 0, 0);
break;
}
#endif /* SQLITE_OMIT_BLOB_LITERAL */
/* Opcode: Variable P1 * *
**
@ -1084,7 +1102,7 @@ divide_by_zero:
** P3 is a pointer to a CollSeq struct. If the next call to a user function
** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will
** be returned. This is used by the built-in min(), max() and nullif()
** built-in functions.
** functions.
**
** The interface used by the implementation of the aforementioned functions
** to retrieve the collation sequence set by this opcode is not available
@ -1140,7 +1158,6 @@ case OP_Function: {
ctx.s.z = 0;
ctx.s.xDel = 0;
ctx.isError = 0;
ctx.isStep = 0;
if( ctx.pFunc->needCollSeq ){
assert( pOp>p->aOp );
assert( pOp[-1].p3type==P3_COLLSEQ );
@ -1643,25 +1660,30 @@ case OP_NotNull: { /* same as TK_NOTNULL */
** opcode must be called to set the number of fields in the table.
**
** This opcode sets the number of columns for cursor P1 to P2.
**
** If OP_KeyAsData is to be applied to cursor P1, it must be executed
** before this op-code.
*/
case OP_SetNumColumns: {
Cursor *pC;
assert( (pOp->p1)<p->nCursor );
assert( p->apCsr[pOp->p1]!=0 );
p->apCsr[pOp->p1]->nField = pOp->p2;
pC = p->apCsr[pOp->p1];
pC->nField = pOp->p2;
if( (!pC->keyAsData && pC->zeroData) || (pC->keyAsData && pC->intKey) ){
rc = SQLITE_CORRUPT;
goto abort_due_to_error;
}
break;
}
/* Opcode: IdxColumn P1 * *
**
** P1 is a cursor opened on an index. Push the first field from the
** current index key onto the stack.
*/
/* Opcode: Column P1 P2 *
**
** Interpret the data that cursor P1 points to as a structure built using
** the MakeRecord instruction. (See the MakeRecord opcode for additional
** information about the format of the data.) Push onto the stack the value
** of the P2-th column contained in the data.
** of the P2-th column contained in the data. If there are less that (P2+1)
** values in the record, push a NULL onto the stack.
**
** If the KeyAsData opcode has previously executed on this cursor, then the
** field might be extracted from the key rather than the data.
@ -1673,7 +1695,6 @@ case OP_SetNumColumns: {
** stack. The column value is not copied. The number of columns in the
** record is stored on the stack just above the record itself.
*/
case OP_IdxColumn:
case OP_Column: {
u32 payloadSize; /* Number of bytes in the record */
int p1 = pOp->p1; /* P1 value of the opcode */
@ -1727,7 +1748,8 @@ case OP_Column: {
pCrsr = 0;
}else if( (pC = p->apCsr[p1])->pCursor!=0 ){
/* The record is stored in a B-Tree */
sqlite3VdbeCursorMoveto(pC);
rc = sqlite3VdbeCursorMoveto(pC);
if( rc ) goto abort_due_to_error;
zRec = 0;
pCrsr = pC->pCursor;
if( pC->nullRow ){
@ -1743,6 +1765,7 @@ case OP_Column: {
sqlite3BtreeDataSize(pCrsr, &payloadSize);
}
nField = pC->nField;
#ifndef SQLITE_OMIT_TRIGGER
}else if( pC->pseudoTable ){
/* The record is the sole entry of a pseudo-table */
payloadSize = pC->nData;
@ -1751,6 +1774,7 @@ case OP_Column: {
assert( payloadSize==0 || zRec!=0 );
nField = pC->nField;
pCrsr = 0;
#endif
}else{
zRec = 0;
payloadSize = 0;
@ -1816,7 +1840,7 @@ case OP_Column: {
if( !zRec && avail<szHdr ){
rc = sqlite3VdbeMemFromBtree(pCrsr, 0, szHdr, pC->keyAsData, &sMem);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
goto op_column_out;
}
zData = sMem.z;
}
@ -1827,6 +1851,7 @@ case OP_Column: {
** of the record to the start of the data for the i-th column
*/
offset = szHdr;
assert( offset>0 );
i = 0;
while( idx<szHdr && i<nField && offset<=payloadSize ){
aOffset[i] = offset;
@ -1837,15 +1862,23 @@ case OP_Column: {
Release(&sMem);
sMem.flags = MEM_Null;
/* If i is less that nField, then there are less fields in this
** record than SetNumColumns indicated there are columns in the
** table. Set the offset for any extra columns not present in
** the record to 0. This tells code below to push a NULL onto the
** stack instead of deserializing a value from the record.
*/
while( i<nField ){
aOffset[i++] = 0;
}
/* The header should end at the start of data and the data should
** end at last byte of the record. If this is not the case then
** we are dealing with a malformed record.
*/
if( idx!=szHdr || offset!=payloadSize ){
sqliteFree(aType);
if( pC ) pC->aType = 0;
rc = SQLITE_CORRUPT;
break;
goto op_column_out;
}
/* Remember all aType and aColumn information if we have a cursor
@ -1858,20 +1891,28 @@ case OP_Column: {
}
}
/* Get the column information.
/* Get the column information. If aOffset[p2] is non-zero, then
** deserialize the value from the record. If aOffset[p2] is zero,
** then there are not enough fields in the record to satisfy the
** request. The value is NULL in this case.
*/
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
if( zRec ){
zData = &zRec[aOffset[p2]];
if( aOffset[p2] ){
assert( rc==SQLITE_OK );
if( zRec ){
zData = &zRec[aOffset[p2]];
}else{
len = sqlite3VdbeSerialTypeLen(aType[p2]);
rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len,pC->keyAsData,&sMem);
if( rc!=SQLITE_OK ){
goto op_column_out;
}
zData = sMem.z;
}
sqlite3VdbeSerialGet(zData, aType[p2], pTos);
pTos->enc = db->enc;
}else{
len = sqlite3VdbeSerialTypeLen(aType[p2]);
sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->keyAsData, &sMem);
zData = sMem.z;
pTos->flags = MEM_Null;
}
sqlite3VdbeSerialGet(zData, aType[p2], pTos);
pTos->enc = db->enc;
/* If we dynamically allocated space to hold the data (in the
** sqlite3VdbeMemFromBtree() call above) then transfer control of that
@ -1891,14 +1932,15 @@ case OP_Column: {
** can abandon sMem */
rc = sqlite3VdbeMemMakeWriteable(pTos);
op_column_out:
/* Release the aType[] memory if we are not dealing with cursor */
if( !pC ){
if( !pC || !pC->aType ){
sqliteFree(aType);
}
break;
}
/* Opcode MakeRecord P1 P2 P3
/* Opcode: MakeRecord P1 P2 P3
**
** Convert the top abs(P1) entries of the stack into a single entry
** suitable for use as a data record in a database table or as a key
@ -1923,12 +1965,11 @@ case OP_Column: {
** field of the index key (i.e. the first character of P3 corresponds to the
** lowest element on the stack).
**
** Character Column affinity
** ------------------------------
** 'n' NUMERIC
** 'i' INTEGER
** 't' TEXT
** 'o' NONE
** The mapping from character to affinity is as follows:
** 'n' = NUMERIC.
** 'i' = INTEGER.
** 't' = TEXT.
** 'o' = NONE.
**
** If P3 is NULL then all index fields have the affinity NONE.
*/
@ -2034,15 +2075,7 @@ case OP_MakeRecord: {
if( addRowid ){
zCsr += sqlite3VdbeSerialPut(zCsr, pRowid);
}
/* If zCsr has not been advanced exactly nByte bytes, then one
** of the sqlite3PutVarint() or sqlite3VdbeSerialPut() calls above
** failed. This indicates a corrupted memory cell or code bug.
*/
if( zCsr!=(zNewRecord+nByte) ){
rc = SQLITE_INTERNAL;
goto abort_due_to_error;
}
assert( zCsr==(zNewRecord+nByte) );
/* Pop entries off the stack if required. Push the new record on. */
if( !leaveOnStack ){
@ -2448,6 +2481,7 @@ case OP_OpenTemp: {
break;
}
#ifndef SQLITE_OMIT_TRIGGER
/* Opcode: OpenPseudo P1 * *
**
** Open a new cursor that points to a fake table that contains a single
@ -2469,6 +2503,7 @@ case OP_OpenPseudo: {
pCx->pIncrKey = &pCx->bogusIncrKey;
break;
}
#endif
/* Opcode: Close P1 * *
**
@ -2542,7 +2577,6 @@ case OP_MoveGt: {
*pC->pIncrKey = oc==OP_MoveGt || oc==OP_MoveLe;
if( pC->intKey ){
i64 iKey;
assert( !pOp->p3 );
Integerify(pTos);
iKey = intToKey(pTos->i);
if( pOp->p2==0 && pOp->opcode==OP_MoveGe ){
@ -2552,12 +2586,18 @@ case OP_MoveGt: {
pTos--;
break;
}
sqlite3BtreeMoveto(pC->pCursor, 0, (u64)iKey, &res);
rc = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)iKey, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
pC->lastRecno = pTos->i;
pC->recnoIsValid = res==0;
}else{
Stringify(pTos, db->enc);
sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
rc = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
pC->recnoIsValid = 0;
}
pC->deferredMoveto = 0;
@ -2566,7 +2606,8 @@ case OP_MoveGt: {
sqlite3_search_count++;
if( oc==OP_MoveGe || oc==OP_MoveGt ){
if( res<0 ){
sqlite3BtreeNext(pC->pCursor, &res);
rc = sqlite3BtreeNext(pC->pCursor, &res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
pC->recnoIsValid = 0;
}else{
res = 0;
@ -2574,7 +2615,8 @@ case OP_MoveGt: {
}else{
assert( oc==OP_MoveLt || oc==OP_MoveLe );
if( res>=0 ){
sqlite3BtreePrevious(pC->pCursor, &res);
rc = sqlite3BtreePrevious(pC->pCursor, &res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
pC->recnoIsValid = 0;
}else{
/* res might be negative because the table is empty. Check to
@ -2782,17 +2824,17 @@ case OP_NotExists: {
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
int res, rx;
int res;
u64 iKey;
assert( pTos->flags & MEM_Int );
assert( p->apCsr[i]->intKey );
iKey = intToKey(pTos->i);
rx = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res);
rc = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res);
pC->lastRecno = pTos->i;
pC->recnoIsValid = res==0;
pC->nullRow = 0;
pC->cacheValid = 0;
if( rx!=SQLITE_OK || res!=0 ){
if( res!=0 ){
pc = pOp->p2 - 1;
pC->recnoIsValid = 0;
}
@ -2802,12 +2844,19 @@ case OP_NotExists: {
break;
}
/* Opcode: NewRecno P1 * *
/* Opcode: NewRecno P1 P2 *
**
** Get a new integer record number used as the key to a table.
** The record number is not previously used as a key in the database
** table that cursor P1 points to. The new record number is pushed
** onto the stack.
**
** If P2>0 then P2 is a memory cell that holds the largest previously
** generated record number. No new record numbers are allowed to be less
** than this value. When this value reaches its maximum, a SQLITE_FULL
** error is generated. The P2 memory cell is updated with the generated
** record number. This P2 mechanism is used to help implement the
** AUTOINCREMENT feature.
*/
case OP_NewRecno: {
int i = pOp->p1;
@ -2852,8 +2901,24 @@ case OP_NewRecno: {
int res, rx=SQLITE_OK, cnt;
i64 x;
cnt = 0;
if( (sqlite3BtreeFlags(pC->pCursor)&(BTREE_INTKEY|BTREE_ZERODATA)) !=
BTREE_INTKEY ){
rc = SQLITE_CORRUPT;
goto abort_due_to_error;
}
assert( (sqlite3BtreeFlags(pC->pCursor) & BTREE_INTKEY)!=0 );
assert( (sqlite3BtreeFlags(pC->pCursor) & BTREE_ZERODATA)==0 );
#ifdef SQLITE_32BIT_ROWID
# define MAX_ROWID 0x7fffffff
#else
/* Some compilers complain about constants of the form 0x7fffffffffffffff.
** Others complain about 0x7ffffffffffffffffLL. The following macro seems
** to provide the constant while making all compilers happy.
*/
# define MAX_ROWID ( (((u64)0x7fffffff)<<32) | (u64)0xffffffff )
#endif
if( !pC->useRandomRowid ){
if( pC->nextRowidValid ){
v = pC->nextRowid;
@ -2864,14 +2929,33 @@ case OP_NewRecno: {
}else{
sqlite3BtreeKeySize(pC->pCursor, &v);
v = keyToInt(v);
if( v==0x7fffffffffffffff ){
if( v==MAX_ROWID ){
pC->useRandomRowid = 1;
}else{
v++;
}
}
}
if( v<0x7fffffffffffffff ){
#ifndef SQLITE_OMIT_AUTOINCREMENT
if( pOp->p2 ){
Mem *pMem;
assert( pOp->p2>0 && pOp->p2<p->nMem ); /* P2 is a valid memory cell */
pMem = &p->aMem[pOp->p2];
Integerify(pMem);
assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P2) holds an integer */
if( pMem->i==MAX_ROWID || pC->useRandomRowid ){
rc = SQLITE_FULL;
goto abort_due_to_error;
}
if( v<pMem->i+1 ){
v = pMem->i + 1;
}
pMem->i = v;
}
#endif
if( v<MAX_ROWID ){
pC->nextRowidValid = 1;
pC->nextRowid = v+1;
}else{
@ -2879,6 +2963,7 @@ case OP_NewRecno: {
}
}
if( pC->useRandomRowid ){
assert( pOp->p2==0 ); /* SQLITE_FULL must have occurred prior to this */
v = db->priorNewRowid;
cnt = 0;
do{
@ -2979,6 +3064,7 @@ case OP_PutStrKey: {
}else{
assert( pTos->flags & (MEM_Blob|MEM_Str) );
}
#ifndef SQLITE_OMIT_TRIGGER
if( pC->pseudoTable ){
/* PutStrKey does not work for pseudo-tables.
** The following assert makes sure we are not trying to use
@ -3000,8 +3086,12 @@ case OP_PutStrKey: {
}
pC->nullRow = 0;
}else{
#endif
rc = sqlite3BtreeInsert(pC->pCursor, zKey, nKey, pTos->z, pTos->n);
#ifndef SQLITE_OMIT_TRIGGER
}
#endif
pC->recnoIsValid = 0;
pC->deferredMoveto = 0;
pC->cacheValid = 0;
@ -3031,7 +3121,8 @@ case OP_Delete: {
pC = p->apCsr[i];
assert( pC!=0 );
if( pC->pCursor!=0 ){
sqlite3VdbeCursorMoveto(pC);
rc = sqlite3VdbeCursorMoveto(pC);
if( rc ) goto abort_due_to_error;
rc = sqlite3BtreeDelete(pC->pCursor);
pC->nextRowidValid = 0;
pC->cacheValid = 0;
@ -3104,7 +3195,8 @@ case OP_RowData: {
pTos->flags = MEM_Null;
}else if( pC->pCursor!=0 ){
BtCursor *pCrsr = pC->pCursor;
sqlite3VdbeCursorMoveto(pC);
rc = sqlite3VdbeCursorMoveto(pC);
if( rc ) goto abort_due_to_error;
if( pC->nullRow ){
pTos->flags = MEM_Null;
break;
@ -3132,10 +3224,12 @@ case OP_RowData: {
}else{
sqlite3BtreeData(pCrsr, 0, n, pTos->z);
}
#ifndef SQLITE_OMIT_TRIGGER
}else if( pC->pseudoTable ){
pTos->n = pC->nData;
pTos->z = pC->pData;
pTos->flags = MEM_Blob|MEM_Ephem;
#endif
}else{
pTos->flags = MEM_Null;
}
@ -3157,7 +3251,8 @@ case OP_Recno: {
assert( i>=0 && i<p->nCursor );
pC = p->apCsr[i];
assert( pC!=0 );
sqlite3VdbeCursorMoveto(pC);
rc = sqlite3VdbeCursorMoveto(pC);
if( rc ) goto abort_due_to_error;
pTos++;
if( pC->recnoIsValid ){
v = pC->lastRecno;
@ -3176,6 +3271,7 @@ case OP_Recno: {
break;
}
#ifndef SQLITE_OMIT_COMPOUND_SELECT
/* Opcode: FullKey P1 * *
**
** Extract the complete key from the record that cursor P1 is currently
@ -3202,7 +3298,8 @@ case OP_FullKey: {
i64 amt;
char *z;
sqlite3VdbeCursorMoveto(pC);
rc = sqlite3VdbeCursorMoveto(pC);
if( rc ) goto abort_due_to_error;
assert( pC->intKey==0 );
sqlite3BtreeKeySize(pCrsr, &amt);
if( amt<=0 ){
@ -3224,6 +3321,7 @@ case OP_FullKey: {
}
break;
}
#endif
/* Opcode: NullRow P1 * *
**
@ -3441,7 +3539,7 @@ case OP_IdxDelete: {
/* Opcode: IdxRecno P1 * *
**
** Push onto the stack an integer which is the varint located at the
** end of the index key pointed to by cursor P1. These integer should be
** end of the index key pointed to by cursor P1. This integer should be
** the record number of the table entry to which this index entry points.
**
** See also: Recno, MakeIdxKey.
@ -3596,10 +3694,33 @@ case OP_IdxIsNull: {
** P2==1 then the table to be clear is in the auxiliary database file
** that is used to store tables create using CREATE TEMPORARY TABLE.
**
** If AUTOVACUUM is enabled then it is possible that another root page
** might be moved into the newly deleted root page in order to keep all
** root pages contiguous at the beginning of the database. The former
** value of the root page that moved - its value before the move occurred -
** is pushed onto the stack. If no page movement was required (because
** the table being dropped was already the last one in the database) then
** a zero is pushed onto the stack. If AUTOVACUUM is disabled
** then a zero is pushed onto the stack.
**
** See also: Clear
*/
case OP_Destroy: {
rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
int iMoved;
if( db->activeVdbeCnt>1 ){
rc = SQLITE_LOCKED;
}else{
assert( db->activeVdbeCnt==1 );
rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1, &iMoved);
pTos++;
pTos->flags = MEM_Int;
pTos->i = iMoved;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( rc==SQLITE_OK && iMoved!=0 ){
sqlite3RootPageMoved(&db->aDb[pOp->p2], iMoved, pOp->p1);
}
#endif
}
break;
}
@ -3735,6 +3856,7 @@ case OP_DropTrigger: {
}
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
/* Opcode: IntegrityCk * P2 *
**
** Do an analysis of the currently open database. Push onto the
@ -3786,6 +3908,7 @@ case OP_IntegrityCk: {
sqliteFree(aRoot);
break;
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
/* Opcode: ListWrite * * *
**
@ -3871,6 +3994,32 @@ case OP_ListReset: {
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
/* Opcode: AggContextPush * * *
**
** Save the state of the current aggregator. It is restored an
** AggContextPop opcode.
**
*/
case OP_AggContextPush: {
p->pAgg++;
assert( p->pAgg<&p->apAgg[p->nAgg] );
break;
}
/* Opcode: AggContextPop * * *
**
** Restore the aggregator to the state it was in when AggContextPush
** was last called. Any data in the current aggregator is deleted.
*/
case OP_AggContextPop: {
p->pAgg--;
assert( p->pAgg>=p->apAgg );
break;
}
#endif
#ifndef SQLITE_OMIT_TRIGGER
/* Opcode: ContextPush * * *
**
** Save the current Vdbe context such that it can be restored by a ContextPop
@ -3911,12 +4060,13 @@ case OP_ContextPop: {
p->pList = pContext->pList;
break;
}
#endif /* #ifndef SQLITE_OMIT_TRIGGER */
/* Opcode: SortPut * * *
**
** The TOS is the key and the NOS is the data. Pop both from the stack
** and put them on the sorter. The key and data should have been
** made using SortMakeKey and SortMakeRec, respectively.
** made using the MakeRecord opcode.
*/
case OP_SortPut: {
Mem *pNos = &pTos[-1];
@ -3947,6 +4097,7 @@ case OP_Sort: {
KeyInfo *pKeyInfo = (KeyInfo*)pOp->p3;
Sorter *pElem;
Sorter *apSorter[NSORT];
sqlite3_sort_count++;
pKeyInfo->enc = p->db->enc;
for(i=0; i<NSORT; i++){
apSorter[i] = 0;
@ -4048,10 +4199,34 @@ case OP_MemLoad: {
break;
}
#ifndef SQLITE_OMIT_AUTOINCREMENT
/* Opcode: MemMax P1 * *
**
** Set the value of memory cell P1 to the maximum of its current value
** and the value on the top of the stack. The stack is unchanged.
**
** This instruction throws an error if the memory cell is not initially
** an integer.
*/
case OP_MemMax: {
int i = pOp->p1;
Mem *pMem;
assert( pTos>=p->aStack );
assert( i>=0 && i<p->nMem );
pMem = &p->aMem[i];
Integerify(pMem);
Integerify(pTos);
if( pMem->i<pTos->i){
pMem->i = pTos->i;
}
break;
}
#endif /* SQLITE_OMIT_AUTOINCREMENT */
/* Opcode: MemIncr P1 P2 *
**
** Increment the integer valued memory cell P1 by 1. If P2 is not zero
** and the result after the increment is greater than zero, then jump
** and the result after the increment is exactly 1, then jump
** to P2.
**
** This instruction throws an error if the memory cell is not initially
@ -4064,7 +4239,24 @@ case OP_MemIncr: {
pMem = &p->aMem[i];
assert( pMem->flags==MEM_Int );
pMem->i++;
if( pOp->p2>0 && pMem->i>0 ){
if( pOp->p2>0 && pMem->i==1 ){
pc = pOp->p2 - 1;
}
break;
}
/* Opcode: IfMemPos P1 P2 *
**
** If the value of memory cell P1 is 1 or greater, jump to P2. This
** opcode assumes that memory cell P1 holds an integer value.
*/
case OP_IfMemPos: {
int i = pOp->p1;
Mem *pMem;
assert( i>=0 && i<p->nMem );
pMem = &p->aMem[i];
assert( pMem->flags==MEM_Int );
if( pMem->i>0 ){
pc = pOp->p2 - 1;
}
break;
@ -4072,8 +4264,8 @@ case OP_MemIncr: {
/* Opcode: AggReset P1 P2 P3
**
** Reset the aggregator so that it no longer contains any data.
** Future aggregator elements will contain P2 values each and be sorted
** Reset the current aggregator context so that it no longer contains any
** data. Future aggregator elements will contain P2 values each and be sorted
** using the KeyInfo structure pointed to by P3.
**
** If P1 is non-zero, then only a single aggregator row is available (i.e.
@ -4083,18 +4275,18 @@ case OP_MemIncr: {
case OP_AggReset: {
assert( !pOp->p3 || pOp->p3type==P3_KEYINFO );
if( pOp->p1 ){
rc = sqlite3VdbeAggReset(0, &p->agg, (KeyInfo *)pOp->p3);
p->agg.nMem = pOp->p2; /* Agg.nMem is used by AggInsert() */
rc = AggInsert(&p->agg, 0, 0);
rc = sqlite3VdbeAggReset(0, p->pAgg, (KeyInfo *)pOp->p3);
p->pAgg->nMem = pOp->p2; /* Agg.nMem is used by AggInsert() */
rc = AggInsert(p->pAgg, 0, 0);
}else{
rc = sqlite3VdbeAggReset(db, &p->agg, (KeyInfo *)pOp->p3);
p->agg.nMem = pOp->p2;
rc = sqlite3VdbeAggReset(db, p->pAgg, (KeyInfo *)pOp->p3);
p->pAgg->nMem = pOp->p2;
}
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
p->agg.apFunc = sqliteMalloc( p->agg.nMem*sizeof(p->agg.apFunc[0]) );
if( p->agg.apFunc==0 ) goto no_mem;
p->pAgg->apFunc = sqliteMalloc( p->pAgg->nMem*sizeof(p->pAgg->apFunc[0]) );
if( p->pAgg->apFunc==0 ) goto no_mem;
break;
}
@ -4106,8 +4298,8 @@ case OP_AggReset: {
*/
case OP_AggInit: {
int i = pOp->p2;
assert( i>=0 && i<p->agg.nMem );
p->agg.apFunc[i] = (FuncDef*)pOp->p3;
assert( i>=0 && i<p->pAgg->nMem );
p->pAgg->apFunc[i] = (FuncDef*)pOp->p3;
break;
}
@ -4142,14 +4334,13 @@ case OP_AggFunc: {
storeTypeInfo(pRec, db->enc);
}
i = pTos->i;
assert( i>=0 && i<p->agg.nMem );
assert( i>=0 && i<p->pAgg->nMem );
ctx.pFunc = (FuncDef*)pOp->p3;
pMem = &p->agg.pCurrent->aMem[i];
pMem = &p->pAgg->pCurrent->aMem[i];
ctx.s.z = pMem->zShort; /* Space used for small aggregate contexts */
ctx.pAgg = pMem->z;
ctx.cnt = ++pMem->i;
ctx.isError = 0;
ctx.isStep = 1;
ctx.pColl = 0;
if( ctx.pFunc->needCollSeq ){
assert( pOp>p->aOp );
@ -4189,18 +4380,18 @@ case OP_AggFocus: {
Stringify(pTos, db->enc);
zKey = pTos->z;
nKey = pTos->n;
assert( p->agg.pBtree );
assert( p->agg.pCsr );
rc = sqlite3BtreeMoveto(p->agg.pCsr, zKey, nKey, &res);
assert( p->pAgg->pBtree );
assert( p->pAgg->pCsr );
rc = sqlite3BtreeMoveto(p->pAgg->pCsr, zKey, nKey, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
if( res==0 ){
rc = sqlite3BtreeData(p->agg.pCsr, 0, sizeof(AggElem*),
(char *)&p->agg.pCurrent);
rc = sqlite3BtreeData(p->pAgg->pCsr, 0, sizeof(AggElem*),
(char *)&p->pAgg->pCurrent);
pc = pOp->p2 - 1;
}else{
rc = AggInsert(&p->agg, zKey, nKey);
rc = AggInsert(p->pAgg, zKey, nKey);
}
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
@ -4218,27 +4409,48 @@ case OP_AggFocus: {
case OP_AggSet: {
AggElem *pFocus;
int i = pOp->p2;
pFocus = p->agg.pCurrent;
pFocus = p->pAgg->pCurrent;
assert( pTos>=p->aStack );
if( pFocus==0 ) goto no_mem;
assert( i>=0 && i<p->agg.nMem );
assert( i>=0 && i<p->pAgg->nMem );
rc = sqlite3VdbeMemMove(&pFocus->aMem[i], pTos);
pTos--;
break;
}
/* Opcode: AggGet * P2 *
/* Opcode: AggGet P1 P2 *
**
** Push a new entry onto the stack which is a copy of the P2-th field
** of the current aggregate. Strings are not duplicated so
** string values will be ephemeral.
**
** If P1 is zero, then the value is pulled out of the current aggregate
** in the current aggregate context. If P1 is greater than zero, then
** the value is taken from the P1th outer aggregate context. (i.e. if
** P1==1 then read from the aggregate context that will be restored
** by the next OP_AggContextPop opcode).
*/
case OP_AggGet: {
AggElem *pFocus;
int i = pOp->p2;
pFocus = p->agg.pCurrent;
if( pFocus==0 ) goto no_mem;
assert( i>=0 && i<p->agg.nMem );
Agg *pAgg = &p->pAgg[-pOp->p1];
assert( pAgg>=p->apAgg );
pFocus = pAgg->pCurrent;
if( pFocus==0 ){
int res;
if( sqlite3_malloc_failed ) goto no_mem;
rc = sqlite3BtreeFirst(pAgg->pCsr, &res);
if( rc!=SQLITE_OK ){
return rc;
}
if( res!=0 ){
rc = AggInsert(pAgg, "", 1);
pFocus = pAgg->pCurrent;
}else{
rc = sqlite3BtreeData(pAgg->pCsr, 0, 4, (char *)&pFocus);
}
}
assert( i>=0 && i<pAgg->nMem );
pTos++;
sqlite3VdbeMemShallowCopy(pTos, &pFocus->aMem[i], MEM_Ephem);
if( pTos->flags&MEM_Str ){
@ -4263,16 +4475,16 @@ case OP_AggNext: {
int res;
assert( rc==SQLITE_OK );
CHECK_FOR_INTERRUPT;
if( p->agg.searching==0 ){
p->agg.searching = 1;
if( p->agg.pCsr ){
rc = sqlite3BtreeFirst(p->agg.pCsr, &res);
if( p->pAgg->searching==0 ){
p->pAgg->searching = 1;
if( p->pAgg->pCsr ){
rc = sqlite3BtreeFirst(p->pAgg->pCsr, &res);
}else{
res = 0;
}
}else{
if( p->agg.pCsr ){
rc = sqlite3BtreeNext(p->agg.pCsr, &res);
if( p->pAgg->pCsr ){
rc = sqlite3BtreeNext(p->pAgg->pCsr, &res);
}else{
res = 1;
}
@ -4285,21 +4497,20 @@ case OP_AggNext: {
sqlite3_context ctx;
Mem *aMem;
if( p->agg.pCsr ){
rc = sqlite3BtreeData(p->agg.pCsr, 0, sizeof(AggElem*),
(char *)&p->agg.pCurrent);
if( p->pAgg->pCsr ){
rc = sqlite3BtreeData(p->pAgg->pCsr, 0, sizeof(AggElem*),
(char *)&p->pAgg->pCurrent);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
aMem = p->agg.pCurrent->aMem;
for(i=0; i<p->agg.nMem; i++){
FuncDef *pFunc = p->agg.apFunc[i];
aMem = p->pAgg->pCurrent->aMem;
for(i=0; i<p->pAgg->nMem; i++){
FuncDef *pFunc = p->pAgg->apFunc[i];
Mem *pMem = &aMem[i];
if( pFunc==0 || pFunc->xFinalize==0 ) continue;
ctx.s.flags = MEM_Null;
ctx.s.z = pMem->zShort;
ctx.pAgg = (void*)pMem->z;
ctx.cnt = pMem->i;
ctx.isStep = 0;
ctx.pFunc = pFunc;
pFunc->xFinalize(&ctx);
pMem->z = ctx.pAgg;
@ -4328,6 +4539,25 @@ case OP_Vacuum: {
break;
}
/* Opcode: Expire P1 * *
**
** Cause precompiled statements to become expired. An expired statement
** fails with an error code of SQLITE_SCHEMA if it is ever executed
** (via sqlite3_step()).
**
** If P1 is 0, then all SQL statements become expired. If P1 is non-zero,
** then only the currently executing statement is affected.
*/
case OP_Expire: {
if( !pOp->p1 ){
sqlite3ExpirePreparedStatements(db);
}else{
p->expired = 1;
}
break;
}
/* An other opcode is illegal...
*/
default: {
@ -4371,6 +4601,8 @@ default: {
sqlite3SetString(&p->zErrMsg, "jump destination out of range", (char*)0);
rc = SQLITE_INTERNAL;
}
#ifdef SQLITE_DEBUG
/* Code for tracing the vdbe stack. */
if( p->trace && pTos>=p->aStack ){
int i;
fprintf(p->trace, "Stack:");
@ -4393,7 +4625,8 @@ default: {
if( rc!=0 ) fprintf(p->trace," rc=%d",rc);
fprintf(p->trace,"\n");
}
#endif
#endif /* SQLITE_DEBUG */
#endif /* NDEBUG */
} /* The end of the for(;;) loop the loops through opcodes */
/* If we reach this point, it means that execution is finished.

View File

@ -110,7 +110,7 @@ int sqlite3VdbeFindOp(Vdbe*, int, int, int);
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
int sqlite3VdbeMakeLabel(Vdbe*);
void sqlite3VdbeDelete(Vdbe*);
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int);
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int);
int sqlite3VdbeFinalize(Vdbe*);
void sqlite3VdbeResolveLabel(Vdbe*, int);
int sqlite3VdbeCurrentAddr(Vdbe*);

View File

@ -220,7 +220,6 @@ struct sqlite3_context {
Mem s; /* The return value is stored here */
void *pAgg; /* Aggregate context */
u8 isError; /* Set to true for an error */
u8 isStep; /* Current in the step function */
int cnt; /* Number of times that the step function has been called */
CollSeq *pColl;
};
@ -322,7 +321,9 @@ struct Vdbe {
int magic; /* Magic number for sanity checking */
int nMem; /* Number of memory locations currently allocated */
Mem *aMem; /* The memory locations */
Agg agg; /* Aggregate information */
int nAgg; /* Number of elements in apAgg */
Agg *apAgg; /* Array of aggregate contexts */
Agg *pAgg; /* Current aggregate context */
int nCallback; /* Number of callbacks invoked so far */
Keylist *pList; /* A list of ROWIDs */
int contextStackTop; /* Index of top element in the context stack */
@ -343,6 +344,7 @@ struct Vdbe {
u8 explain; /* True if EXPLAIN present on SQL command */
u8 changeCntOn; /* True to update the change-counter */
u8 aborted; /* True if ROLLBACK in another VM causes an abort */
u8 expired; /* True if the VM needs to be recompiled */
int nChange; /* Number of db changes made since last reset */
};
@ -363,10 +365,12 @@ int sqlite3VdbeAggReset(sqlite3*, Agg *, KeyInfo *);
void sqlite3VdbeKeylistFree(Keylist*);
void sqliteVdbePopStack(Vdbe*,int);
int sqlite3VdbeCursorMoveto(Cursor*);
#if !defined(NDEBUG) || defined(VDBE_PROFILE)
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
void sqlite3VdbePrintOp(FILE*, int, Op*);
#endif
#ifdef SQLITE_DEBUG
void sqlite3VdbePrintSql(Vdbe*);
#endif
int sqlite3VdbeSerialTypeLen(u32);
u32 sqlite3VdbeSerialType(Mem*);
int sqlite3VdbeSerialPut(unsigned char*, Mem*);

View File

@ -16,6 +16,21 @@
#include "sqliteInt.h"
#include "vdbeInt.h"
/*
** Return TRUE (non-zero) of the statement supplied as an argument needs
** to be recompiled. A statement needs to be recompiled whenever the
** execution environment changes in a way that would alter the program
** that sqlite3_prepare() generates. For example, if new functions or
** collating sequences are registered or if an authorizer function is
** added or changed.
**
***** EXPERIMENTAL ******
*/
int sqlite3_expired(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe*)pStmt;
return p==0 || p->expired;
}
/**************************** sqlite3_value_ *******************************
** The following routines extract information from a Mem or sqlite3_value
** structure.
@ -46,6 +61,7 @@ sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){
const unsigned char *sqlite3_value_text(sqlite3_value *pVal){
return (const char *)sqlite3ValueText(pVal, SQLITE_UTF8);
}
#ifndef SQLITE_OMIT_UTF16
const void *sqlite3_value_text16(sqlite3_value* pVal){
return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE);
}
@ -55,6 +71,7 @@ const void *sqlite3_value_text16be(sqlite3_value *pVal){
const void *sqlite3_value_text16le(sqlite3_value *pVal){
return sqlite3ValueText(pVal, SQLITE_UTF16LE);
}
#endif /* SQLITE_OMIT_UTF16 */
int sqlite3_value_type(sqlite3_value* pVal){
return pVal->type;
}
@ -100,6 +117,7 @@ void sqlite3_result_text(
){
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, xDel);
}
#ifndef SQLITE_OMIT_UTF16
void sqlite3_result_text16(
sqlite3_context *pCtx,
const void *z,
@ -124,6 +142,7 @@ void sqlite3_result_text16le(
){
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16LE, xDel);
}
#endif /* SQLITE_OMIT_UTF16 */
void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
sqlite3VdbeMemCopy(&pCtx->s, pValue);
}
@ -144,6 +163,12 @@ int sqlite3_step(sqlite3_stmt *pStmt){
if( p->aborted ){
return SQLITE_ABORT;
}
if( p->pc<=0 && p->expired ){
if( p->rc==SQLITE_OK ){
p->rc = SQLITE_SCHEMA;
}
return SQLITE_ERROR;
}
db = p->db;
if( sqlite3SafetyOn(db) ){
p->rc = SQLITE_MISUSE;
@ -177,9 +202,12 @@ int sqlite3_step(sqlite3_stmt *pStmt){
db->activeVdbeCnt++;
p->pc = 0;
}
#ifndef SQLITE_OMIT_EXPLAIN
if( p->explain ){
rc = sqlite3VdbeList(p);
}else{
}else
#endif /* SQLITE_OMIT_EXPLAIN */
{
rc = sqlite3VdbeExec(p);
}
@ -343,9 +371,11 @@ sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
return sqlite3_value_text( columnMem(pStmt,i) );
}
#ifndef SQLITE_OMIT_UTF16
const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
return sqlite3_value_text16( columnMem(pStmt,i) );
}
#endif /* SQLITE_OMIT_UTF16 */
int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
return sqlite3_value_type( columnMem(pStmt,i) );
}
@ -383,6 +413,15 @@ const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 0);
}
/*
** Return the column declaration type (if applicable) of the 'i'th column
** of the result set of SQL statement pStmt, encoded as UTF-8.
*/
const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 1);
}
#ifndef SQLITE_OMIT_UTF16
/*
** Return the name of the 'i'th column of the result set of SQL statement
** pStmt, encoded as UTF-16.
@ -391,14 +430,6 @@ const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 0);
}
/*
** Return the column declaration type (if applicable) of the 'i'th column
** of the result set of SQL statement pStmt, encoded as UTF-8.
*/
const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 1);
}
/*
** Return the column declaration type (if applicable) of the 'i'th column
** of the result set of SQL statement pStmt, encoded as UTF-16.
@ -406,6 +437,7 @@ const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 1);
}
#endif /* SQLITE_OMIT_UTF16 */
/******************************* sqlite3_bind_ ***************************
**
@ -513,6 +545,7 @@ int sqlite3_bind_text(
){
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8);
}
#ifndef SQLITE_OMIT_UTF16
int sqlite3_bind_text16(
sqlite3_stmt *pStmt,
int i,
@ -522,6 +555,7 @@ int sqlite3_bind_text16(
){
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
}
#endif /* SQLITE_OMIT_UTF16 */
/*
** Return the number of wildcards that can be potentially bound to.
@ -578,10 +612,12 @@ int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
return 0;
}
createVarMap(p);
for(i=0; i<p->nVar; i++){
const char *z = p->azVar[i];
if( z && strcmp(z,zName)==0 ){
return i+1;
if( zName ){
for(i=0; i<p->nVar; i++){
const char *z = p->azVar[i];
if( z && strcmp(z,zName)==0 ){
return i+1;
}
}
}
return 0;

View File

@ -103,7 +103,7 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
pOp->p2 = p2;
pOp->p3 = 0;
pOp->p3type = P3_NOTUSED;
#ifndef NDEBUG
#ifdef SQLITE_DEBUG
if( sqlite3_vdbe_addop_trace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
#endif
return i;
@ -212,7 +212,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
pOut->p2 = p2<0 ? addr + ADDR(p2) : p2;
pOut->p3 = pIn->p3;
pOut->p3type = pIn->p3 ? P3_STATIC : P3_NOTUSED;
#ifndef NDEBUG
#ifdef SQLITE_DEBUG
if( sqlite3_vdbe_addop_trace ){
sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
}
@ -375,6 +375,8 @@ VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
return &p->aOp[addr];
}
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
|| defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
/*
** Compute a string that describes the P3 parameter for an opcode.
** Use zTemp for any required temporary buffer space.
@ -444,9 +446,10 @@ static char *displayP3(Op *pOp, char *zTemp, int nTemp){
}
return zP3;
}
#endif
#if !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
/*
** Print a single opcode. This routine is used for debugging only.
*/
@ -473,6 +476,7 @@ static void releaseMemArray(Mem *p, int N){
}
}
#ifndef SQLITE_OMIT_EXPLAIN
/*
** Give a listing of the program in the virtual machine.
**
@ -488,6 +492,9 @@ int sqlite3VdbeList(
int rc = SQLITE_OK;
assert( p->explain );
if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
assert( db->magic==SQLITE_MAGIC_BUSY );
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY );
/* Even though this opcode does not put dynamic strings onto the
** the stack, they may become dynamic if the user calls
@ -498,17 +505,14 @@ int sqlite3VdbeList(
}
p->resOnStack = 0;
i = p->pc++;
if( i>=p->nOp ){
p->rc = SQLITE_OK;
rc = SQLITE_DONE;
}else if( db->flags & SQLITE_Interrupt ){
db->flags &= ~SQLITE_Interrupt;
if( db->magic!=SQLITE_MAGIC_BUSY ){
p->rc = SQLITE_MISUSE;
}else{
p->rc = SQLITE_INTERRUPT;
}
p->rc = SQLITE_INTERRUPT;
rc = SQLITE_ERROR;
sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(p->rc), (char*)0);
}else{
@ -549,6 +553,7 @@ int sqlite3VdbeList(
}
return rc;
}
#endif /* SQLITE_OMIT_EXPLAIN */
/*
** Print the SQL that was used to generate a VDBE program.
@ -581,6 +586,7 @@ void sqlite3VdbeMakeReady(
int nVar, /* Number of '?' see in the SQL statement */
int nMem, /* Number of memory cells to allocate */
int nCursor, /* Number of cursors to allocate */
int nAgg, /* Number of aggregate contexts required */
int isExplain /* True if the EXPLAIN keywords is present */
){
int n;
@ -610,6 +616,7 @@ void sqlite3VdbeMakeReady(
+ nVar*sizeof(char*) /* azVar */
+ nMem*sizeof(Mem) /* aMem */
+ nCursor*sizeof(Cursor*) /* apCsr */
+ nAgg*sizeof(Agg) /* Aggregate contexts */
);
if( !sqlite3_malloc_failed ){
p->aMem = &p->aStack[n];
@ -620,15 +627,20 @@ void sqlite3VdbeMakeReady(
p->apArg = (Mem**)&p->aVar[nVar];
p->azVar = (char**)&p->apArg[n];
p->apCsr = (Cursor**)&p->azVar[nVar];
if( nAgg>0 ){
p->nAgg = nAgg;
p->apAgg = (Agg*)&p->apCsr[nCursor];
}
p->nCursor = nCursor;
for(n=0; n<nVar; n++){
p->aVar[n].flags = MEM_Null;
}
for(n=0; n<nMem; n++){
p->aMem[n].flags = MEM_Null;
}
}
}
p->pAgg = p->apAgg;
for(n=0; n<p->nMem; n++){
p->aMem[n].flags = MEM_Null;
}
#ifdef SQLITE_DEBUG
if( (p->db->flags & SQLITE_VdbeListing)!=0
@ -684,7 +696,7 @@ void sqlite3VdbeSorterReset(Vdbe *p){
** Free all resources allociated with AggElem pElem, an element of
** aggregate pAgg.
*/
void freeAggElem(AggElem *pElem, Agg *pAgg){
static void freeAggElem(AggElem *pElem, Agg *pAgg){
int i;
for(i=0; i<pAgg->nMem; i++){
Mem *pMem = &pElem->aMem[i];
@ -694,9 +706,8 @@ void freeAggElem(AggElem *pElem, Agg *pAgg){
ctx.s.flags = MEM_Null;
ctx.pAgg = pMem->z;
ctx.cnt = pMem->i;
ctx.isStep = 0;
ctx.isError = 0;
(*pAgg->apFunc[i]->xFinalize)(&ctx);
(*ctx.pFunc->xFinalize)(&ctx);
pMem->z = ctx.pAgg;
if( pMem->z!=0 && pMem->z!=pMem->zShort ){
sqliteFree(pMem->z);
@ -729,8 +740,10 @@ void freeAggElem(AggElem *pElem, Agg *pAgg){
*/
int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){
int rc = 0;
BtCursor *pCsr = pAgg->pCsr;
BtCursor *pCsr;
if( !pAgg ) return SQLITE_OK;
pCsr = pAgg->pCsr;
assert( (pCsr && pAgg->nTab>0) || (!pCsr && pAgg->nTab==0)
|| sqlite3_malloc_failed );
@ -748,7 +761,7 @@ int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){
while( res==0 && rc==SQLITE_OK ){
AggElem *pElem;
rc = sqlite3BtreeData(pCsr, 0, sizeof(AggElem*), (char *)&pElem);
if( res!=SQLITE_OK ){
if( rc!=SQLITE_OK ){
return rc;
}
assert( pAgg->apFunc!=0 );
@ -779,7 +792,11 @@ int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){
if( db ){
if( !pAgg->pBtree ){
assert( pAgg->nTab==0 );
#ifndef SQLITE_OMIT_MEMORYDB
rc = sqlite3BtreeFactory(db, ":memory:", 0, TEMP_PAGES, &pAgg->pBtree);
#else
rc = sqlite3BtreeFactory(db, 0, 0, TEMP_PAGES, &pAgg->pBtree);
#endif
if( rc!=SQLITE_OK ) return rc;
sqlite3BtreeBeginTrans(pAgg->pBtree, 1);
rc = sqlite3BtreeCreateTable(pAgg->pBtree, &pAgg->nTab, 0);
@ -878,7 +895,9 @@ static void Cleanup(Vdbe *p){
sqliteFree(p->contextStack);
}
sqlite3VdbeSorterReset(p);
sqlite3VdbeAggReset(0, &p->agg, 0);
for(i=0; i<p->nAgg; i++){
sqlite3VdbeAggReset(0, &p->apAgg[i], 0);
}
p->contextStack = 0;
p->contextStackDepth = 0;
p->contextStackTop = 0;
@ -1026,7 +1045,7 @@ static int vdbeCommit(sqlite3 *db){
** master journal file. If an error occurs at this point close
** and delete the master journal file. All the individual journal files
** still have 'null' as the master journal pointer, so they will roll
** back independantly if a failure occurs.
** back independently if a failure occurs.
*/
for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
@ -1050,18 +1069,12 @@ static int vdbeCommit(sqlite3 *db){
*/
zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
rc = sqlite3OsOpenDirectory(zMainFile, &master);
if( rc!=SQLITE_OK ){
if( rc!=SQLITE_OK || (rc = sqlite3OsSync(&master))!=SQLITE_OK ){
sqlite3OsClose(&master);
sqlite3OsDelete(zMaster);
sqliteFree(zMaster);
return rc;
}
rc = sqlite3OsSync(&master);
if( rc!=SQLITE_OK ){
sqlite3OsClose(&master);
sqliteFree(zMaster);
return rc;
}
/* Sync all the db files involved in the transaction. The same call
** sets the master journal pointer in each individual journal. If
@ -1103,8 +1116,6 @@ static int vdbeCommit(sqlite3 *db){
** master journal exists now or if it will exist after the operating
** system crash that may follow the fsync() failure.
*/
assert(0);
sqliteFree(zMaster);
return rc;
}
@ -1193,7 +1204,9 @@ int sqlite3VdbeHalt(Vdbe *p){
}
closeAllCursors(p);
checkActiveVdbeCnt(db);
if( db->autoCommit && db->activeVdbeCnt==1 ){
if( p->pc<0 ){
/* No commit or rollback needed if the program never started */
}else if( db->autoCommit && db->activeVdbeCnt==1 ){
if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
/* The auto-commit flag is true, there are no other active queries
** using this handle and the vdbe program was successful or hit an
@ -1236,7 +1249,7 @@ int sqlite3VdbeHalt(Vdbe *p){
}
/* If this was an INSERT, UPDATE or DELETE, set the change counter. */
if( p->changeCntOn ){
if( p->changeCntOn && p->pc>=0 ){
if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){
sqlite3VdbeSetChanges(db, p->nChange);
}else{
@ -1285,17 +1298,27 @@ int sqlite3VdbeReset(Vdbe *p){
*/
sqlite3VdbeHalt(p);
/* Transfer the error code and error message from the VDBE into the
** main database structure.
/* If the VDBE has be run even partially, then transfer the error code
** and error message from the VDBE into the main database structure. But
** if the VDBE has just been set to run but has not actually executed any
** instructions yet, leave the main database error information unchanged.
*/
if( p->zErrMsg ){
sqlite3Error(p->db, p->rc, "%s", p->zErrMsg);
sqliteFree(p->zErrMsg);
p->zErrMsg = 0;
}else if( p->rc ){
if( p->pc>=0 ){
if( p->zErrMsg ){
sqlite3Error(p->db, p->rc, "%s", p->zErrMsg);
sqliteFree(p->zErrMsg);
p->zErrMsg = 0;
}else if( p->rc ){
sqlite3Error(p->db, p->rc, 0);
}else{
sqlite3Error(p->db, SQLITE_OK, 0);
}
}else if( p->rc && p->expired ){
/* The expired flag was set on the VDBE before the first call
** to sqlite3_step(). For consistency (since sqlite3_step() was
** called), set the database error in this case as well.
*/
sqlite3Error(p->db, p->rc, 0);
}else{
sqlite3Error(p->db, SQLITE_OK, 0);
}
/* Reclaim all memory used by the VDBE
@ -1329,6 +1352,9 @@ int sqlite3VdbeReset(Vdbe *p){
#endif
p->magic = VDBE_MAGIC_INIT;
p->aborted = 0;
if( p->rc==SQLITE_SCHEMA ){
sqlite3ResetInternalSchema(p->db, 0);
}
return p->rc;
}
@ -1338,18 +1364,13 @@ int sqlite3VdbeReset(Vdbe *p){
*/
int sqlite3VdbeFinalize(Vdbe *p){
int rc = SQLITE_OK;
sqlite3 *db = p->db;
if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){
rc = sqlite3VdbeReset(p);
}else if( p->magic!=VDBE_MAGIC_INIT ){
/* sqlite3Error(p->db, SQLITE_MISUSE, 0); */
return SQLITE_MISUSE;
}
sqlite3VdbeDelete(p);
if( rc==SQLITE_SCHEMA ){
sqlite3ResetInternalSchema(db, 0);
}
return rc;
}
@ -1418,19 +1439,22 @@ void sqlite3VdbeDelete(Vdbe *p){
*/
int sqlite3VdbeCursorMoveto(Cursor *p){
if( p->deferredMoveto ){
int res;
int res, rc;
extern int sqlite3_search_count;
assert( p->intKey );
if( p->intKey ){
sqlite3BtreeMoveto(p->pCursor, 0, p->movetoTarget, &res);
rc = sqlite3BtreeMoveto(p->pCursor, 0, p->movetoTarget, &res);
}else{
sqlite3BtreeMoveto(p->pCursor,(char*)&p->movetoTarget,sizeof(i64),&res);
rc = sqlite3BtreeMoveto(p->pCursor,(char*)&p->movetoTarget,
sizeof(i64),&res);
}
if( rc ) return rc;
*p->pIncrKey = 0;
p->lastRecno = keyToInt(p->movetoTarget);
p->recnoIsValid = res==0;
if( res<0 ){
sqlite3BtreeNext(p->pCursor, &res);
rc = sqlite3BtreeNext(p->pCursor, &res);
if( rc ) return rc;
}
sqlite3_search_count++;
p->deferredMoveto = 0;
@ -1487,13 +1511,15 @@ u32 sqlite3VdbeSerialType(Mem *pMem){
return 0;
}
if( flags&MEM_Int ){
/* Figure out whether to use 1, 2, 4 or 8 bytes. */
/* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
# define MAX_6BYTE ((((i64)0x00010000)<<32)-1)
i64 i = pMem->i;
if( i>=-127 && i<=127 ) return 1;
if( i>=-32767 && i<=32767 ) return 2;
if( i>=-8388607 && i<=8388607 ) return 3;
if( i>=-2147483647 && i<=2147483647 ) return 4;
if( i>=-140737488355328L && i<=140737488355328L ) return 5;
u64 u = i<0 ? -i : i;
if( u<=127 ) return 1;
if( u<=32767 ) return 2;
if( u<=8388607 ) return 3;
if( u<=2147483647 ) return 4;
if( u<=MAX_6BYTE ) return 5;
return 6;
}
if( flags&MEM_Real ){
@ -1801,6 +1827,23 @@ void sqlite3VdbeSetChanges(sqlite3 *db, int nChange){
** Set a flag in the vdbe to update the change counter when it is finalised
** or reset.
*/
void sqlite3VdbeCountChanges(Vdbe *p){
p->changeCntOn = 1;
void sqlite3VdbeCountChanges(Vdbe *v){
v->changeCntOn = 1;
}
/*
** Mark every prepared statement associated with a database connection
** as expired.
**
** An expired statement means that recompilation of the statement is
** recommend. Statements expire when things happen that make their
** programs obsolete. Removing user-defined functions or collating
** sequences, or changing an authorization function are the types of
** things that make prepared statements obsolete.
*/
void sqlite3ExpirePreparedStatements(sqlite3 *db){
Vdbe *p;
for(p = db->pVdbe; p; p=p->pNext){
p->expired = 1;
}
}

View File

@ -34,10 +34,21 @@
** between formats.
*/
int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
int rc;
if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
return SQLITE_OK;
}
return sqlite3VdbeMemTranslate(pMem, desiredEnc);
#ifdef SQLITE_OMIT_UTF16
return SQLITE_ERROR;
#else
rc = sqlite3VdbeMemTranslate(pMem, desiredEnc);
if( rc==SQLITE_NOMEM ){
sqlite3VdbeMemRelease(pMem);
pMem->flags = MEM_Null;
pMem->z = 0;
}
return rc;
#endif
}
/*
@ -390,6 +401,8 @@ int sqlite3VdbeMemSetStr(
pMem->type = enc==0 ? SQLITE_BLOB : SQLITE_TEXT;
pMem->n = n;
assert( enc==0 || enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE
|| enc==SQLITE_UTF16BE );
switch( enc ){
case 0:
pMem->flags |= MEM_Blob;
@ -403,6 +416,7 @@ int sqlite3VdbeMemSetStr(
}
break;
#ifndef SQLITE_OMIT_UTF16
case SQLITE_UTF16LE:
case SQLITE_UTF16BE:
pMem->flags |= MEM_Str;
@ -413,10 +427,7 @@ int sqlite3VdbeMemSetStr(
if( sqlite3VdbeMemHandleBom(pMem) ){
return SQLITE_NOMEM;
}
break;
default:
assert(0);
#endif /* SQLITE_OMIT_UTF16 */
}
if( pMem->flags&MEM_Ephem ){
return sqlite3VdbeMemMakeWriteable(pMem);

File diff suppressed because it is too large Load Diff

View File

@ -15,118 +15,204 @@ typedef struct Keyword Keyword;
struct Keyword {
char *zName; /* The keyword name */
char *zTokenType; /* Token value for this keyword */
int mask; /* Code this keyword if non-zero */
int id; /* Unique ID for this record */
int hash; /* Hash on the keyword */
int offset; /* Offset to start of name string */
int len; /* Length of this keyword, not counting final \000 */
int prefix; /* Number of characters in prefix */
int iNext; /* Index in aKeywordTable[] of next with same hash */
int substrId; /* Id to another keyword this keyword is embedded in */
int substrOffset; /* Offset into substrId for start of this keyword */
};
/*
** Define masks used to determine which keywords are allowed
*/
#ifdef SQLITE_OMIT_ALTERTABLE
# define ALTER 0
#else
# define ALTER 1
#endif
#define ALWAYS 2
#ifdef SQLITE_OMIT_ATTACH
# define ATTACH 0
#else
# define ATTACH 4
#endif
#ifdef SQLITE_OMIT_AUTOINCREMENT
# define AUTOINCR 0
#else
# define AUTOINCR 8
#endif
#ifdef SQLITE_OMIT_COMPOUND_SELECT
# define COMPOUND 0
#else
# define COMPOUND 16
#endif
#ifdef SQLITE_OMIT_CONFLICT_CLAUSE
# define CONFLICT 0
#else
# define CONFLICT 32
#endif
#ifdef SQLITE_OMIT_EXPLAIN
# define EXPLAIN 0
#else
# define EXPLAIN 128
#endif
#ifdef SQLITE_OMIT_FOREIGN_KEY
# define FKEY 0
#else
# define FKEY 256
#endif
#ifdef SQLITE_OMIT_PRAGMA
# define PRAGMA 0
#else
# define PRAGMA 512
#endif
#ifdef SQLITE_OMIT_REINDEX
# define REINDEX 0
#else
# define REINDEX 1024
#endif
#ifdef SQLITE_OMIT_SUBQUERY
# define SUBQUERY 0
#else
# define SUBQUERY 2048
#endif
#ifdef SQLITE_OMIT_TRIGGER
# define TRIGGER 0
#else
# define TRIGGER 4096
#endif
#ifdef SQLITE_OMIT_VACUUM
# define VACUUM 0
#else
# define VACUUM 8192
#endif
#ifdef SQLITE_OMIT_VIEW
# define VIEW 0
#else
# define VIEW 16384
#endif
/*
** These are the keywords
*/
static Keyword aKeywordTable[] = {
{ "ABORT", "TK_ABORT", },
{ "AFTER", "TK_AFTER", },
{ "ALL", "TK_ALL", },
{ "AND", "TK_AND", },
{ "AS", "TK_AS", },
{ "ASC", "TK_ASC", },
{ "ATTACH", "TK_ATTACH", },
{ "BEFORE", "TK_BEFORE", },
{ "BEGIN", "TK_BEGIN", },
{ "BETWEEN", "TK_BETWEEN", },
{ "BY", "TK_BY", },
{ "CASCADE", "TK_CASCADE", },
{ "CASE", "TK_CASE", },
{ "CHECK", "TK_CHECK", },
{ "COLLATE", "TK_COLLATE", },
{ "COMMIT", "TK_COMMIT", },
{ "CONFLICT", "TK_CONFLICT", },
{ "CONSTRAINT", "TK_CONSTRAINT", },
{ "CREATE", "TK_CREATE", },
{ "CROSS", "TK_JOIN_KW", },
{ "DATABASE", "TK_DATABASE", },
{ "DEFAULT", "TK_DEFAULT", },
{ "DEFERRED", "TK_DEFERRED", },
{ "DEFERRABLE", "TK_DEFERRABLE", },
{ "DELETE", "TK_DELETE", },
{ "DESC", "TK_DESC", },
{ "DETACH", "TK_DETACH", },
{ "DISTINCT", "TK_DISTINCT", },
{ "DROP", "TK_DROP", },
{ "END", "TK_END", },
{ "EACH", "TK_EACH", },
{ "ELSE", "TK_ELSE", },
{ "EXCEPT", "TK_EXCEPT", },
{ "EXCLUSIVE", "TK_EXCLUSIVE", },
{ "EXPLAIN", "TK_EXPLAIN", },
{ "FAIL", "TK_FAIL", },
{ "FOR", "TK_FOR", },
{ "FOREIGN", "TK_FOREIGN", },
{ "FROM", "TK_FROM", },
{ "FULL", "TK_JOIN_KW", },
{ "GLOB", "TK_GLOB", },
{ "GROUP", "TK_GROUP", },
{ "HAVING", "TK_HAVING", },
{ "IGNORE", "TK_IGNORE", },
{ "IMMEDIATE", "TK_IMMEDIATE", },
{ "IN", "TK_IN", },
{ "INDEX", "TK_INDEX", },
{ "INITIALLY", "TK_INITIALLY", },
{ "INNER", "TK_JOIN_KW", },
{ "INSERT", "TK_INSERT", },
{ "INSTEAD", "TK_INSTEAD", },
{ "INTERSECT", "TK_INTERSECT", },
{ "INTO", "TK_INTO", },
{ "IS", "TK_IS", },
{ "ISNULL", "TK_ISNULL", },
{ "JOIN", "TK_JOIN", },
{ "KEY", "TK_KEY", },
{ "LEFT", "TK_JOIN_KW", },
{ "LIKE", "TK_LIKE", },
{ "LIMIT", "TK_LIMIT", },
{ "MATCH", "TK_MATCH", },
{ "NATURAL", "TK_JOIN_KW", },
{ "NOT", "TK_NOT", },
{ "NOTNULL", "TK_NOTNULL", },
{ "NULL", "TK_NULL", },
{ "OF", "TK_OF", },
{ "OFFSET", "TK_OFFSET", },
{ "ON", "TK_ON", },
{ "OR", "TK_OR", },
{ "ORDER", "TK_ORDER", },
{ "OUTER", "TK_JOIN_KW", },
{ "PRAGMA", "TK_PRAGMA", },
{ "PRIMARY", "TK_PRIMARY", },
{ "RAISE", "TK_RAISE", },
{ "REFERENCES", "TK_REFERENCES", },
{ "REPLACE", "TK_REPLACE", },
{ "RESTRICT", "TK_RESTRICT", },
{ "RIGHT", "TK_JOIN_KW", },
{ "ROLLBACK", "TK_ROLLBACK", },
{ "ROW", "TK_ROW", },
{ "SELECT", "TK_SELECT", },
{ "SET", "TK_SET", },
{ "STATEMENT", "TK_STATEMENT", },
{ "TABLE", "TK_TABLE", },
{ "TEMP", "TK_TEMP", },
{ "TEMPORARY", "TK_TEMP", },
{ "THEN", "TK_THEN", },
{ "TRANSACTION", "TK_TRANSACTION", },
{ "TRIGGER", "TK_TRIGGER", },
{ "UNION", "TK_UNION", },
{ "UNIQUE", "TK_UNIQUE", },
{ "UPDATE", "TK_UPDATE", },
{ "USING", "TK_USING", },
{ "VACUUM", "TK_VACUUM", },
{ "VALUES", "TK_VALUES", },
{ "VIEW", "TK_VIEW", },
{ "WHEN", "TK_WHEN", },
{ "WHERE", "TK_WHERE", },
{ "ABORT", "TK_ABORT", CONFLICT|TRIGGER },
{ "AFTER", "TK_AFTER", TRIGGER },
{ "ALL", "TK_ALL", ALWAYS },
{ "ALTER", "TK_ALTER", ALTER },
{ "AND", "TK_AND", ALWAYS },
{ "AS", "TK_AS", ALWAYS },
{ "ASC", "TK_ASC", ALWAYS },
{ "ATTACH", "TK_ATTACH", ATTACH },
{ "AUTOINCREMENT", "TK_AUTOINCR", AUTOINCR },
{ "BEFORE", "TK_BEFORE", TRIGGER },
{ "BEGIN", "TK_BEGIN", ALWAYS },
{ "BETWEEN", "TK_BETWEEN", ALWAYS },
{ "BY", "TK_BY", ALWAYS },
{ "CASCADE", "TK_CASCADE", FKEY },
{ "CASE", "TK_CASE", ALWAYS },
{ "CHECK", "TK_CHECK", ALWAYS },
{ "COLLATE", "TK_COLLATE", ALWAYS },
{ "COMMIT", "TK_COMMIT", ALWAYS },
{ "CONFLICT", "TK_CONFLICT", CONFLICT },
{ "CONSTRAINT", "TK_CONSTRAINT", ALWAYS },
{ "CREATE", "TK_CREATE", ALWAYS },
{ "CROSS", "TK_JOIN_KW", ALWAYS },
{ "CURRENT_DATE", "TK_CDATE", ALWAYS },
{ "CURRENT_TIME", "TK_CTIME", ALWAYS },
{ "CURRENT_TIMESTAMP","TK_CTIMESTAMP", ALWAYS },
{ "DATABASE", "TK_DATABASE", ATTACH },
{ "DEFAULT", "TK_DEFAULT", ALWAYS },
{ "DEFERRED", "TK_DEFERRED", ALWAYS },
{ "DEFERRABLE", "TK_DEFERRABLE", FKEY },
{ "DELETE", "TK_DELETE", ALWAYS },
{ "DESC", "TK_DESC", ALWAYS },
{ "DETACH", "TK_DETACH", ATTACH },
{ "DISTINCT", "TK_DISTINCT", ALWAYS },
{ "DROP", "TK_DROP", ALWAYS },
{ "END", "TK_END", ALWAYS },
{ "EACH", "TK_EACH", TRIGGER },
{ "ELSE", "TK_ELSE", ALWAYS },
{ "ESCAPE", "TK_ESCAPE", ALWAYS },
{ "EXCEPT", "TK_EXCEPT", COMPOUND },
{ "EXCLUSIVE", "TK_EXCLUSIVE", ALWAYS },
{ "EXISTS", "TK_EXISTS", SUBQUERY },
{ "EXPLAIN", "TK_EXPLAIN", EXPLAIN },
{ "FAIL", "TK_FAIL", CONFLICT|TRIGGER },
{ "FOR", "TK_FOR", TRIGGER },
{ "FOREIGN", "TK_FOREIGN", FKEY },
{ "FROM", "TK_FROM", ALWAYS },
{ "FULL", "TK_JOIN_KW", ALWAYS },
{ "GLOB", "TK_GLOB", ALWAYS },
{ "GROUP", "TK_GROUP", ALWAYS },
{ "HAVING", "TK_HAVING", ALWAYS },
{ "IGNORE", "TK_IGNORE", CONFLICT|TRIGGER },
{ "IMMEDIATE", "TK_IMMEDIATE", ALWAYS },
{ "IN", "TK_IN", ALWAYS },
{ "INDEX", "TK_INDEX", ALWAYS },
{ "INITIALLY", "TK_INITIALLY", FKEY },
{ "INNER", "TK_JOIN_KW", ALWAYS },
{ "INSERT", "TK_INSERT", ALWAYS },
{ "INSTEAD", "TK_INSTEAD", TRIGGER },
{ "INTERSECT", "TK_INTERSECT", COMPOUND },
{ "INTO", "TK_INTO", ALWAYS },
{ "IS", "TK_IS", ALWAYS },
{ "ISNULL", "TK_ISNULL", ALWAYS },
{ "JOIN", "TK_JOIN", ALWAYS },
{ "KEY", "TK_KEY", ALWAYS },
{ "LEFT", "TK_JOIN_KW", ALWAYS },
{ "LIKE", "TK_LIKE", ALWAYS },
{ "LIMIT", "TK_LIMIT", ALWAYS },
{ "MATCH", "TK_MATCH", ALWAYS },
{ "NATURAL", "TK_JOIN_KW", ALWAYS },
{ "NOT", "TK_NOT", ALWAYS },
{ "NOTNULL", "TK_NOTNULL", ALWAYS },
{ "NULL", "TK_NULL", ALWAYS },
{ "OF", "TK_OF", ALWAYS },
{ "OFFSET", "TK_OFFSET", ALWAYS },
{ "ON", "TK_ON", ALWAYS },
{ "OR", "TK_OR", ALWAYS },
{ "ORDER", "TK_ORDER", ALWAYS },
{ "OUTER", "TK_JOIN_KW", ALWAYS },
{ "PRAGMA", "TK_PRAGMA", PRAGMA },
{ "PRIMARY", "TK_PRIMARY", ALWAYS },
{ "RAISE", "TK_RAISE", TRIGGER },
{ "REFERENCES", "TK_REFERENCES", FKEY },
{ "REINDEX", "TK_REINDEX", REINDEX },
{ "RENAME", "TK_RENAME", ALTER },
{ "REPLACE", "TK_REPLACE", CONFLICT },
{ "RESTRICT", "TK_RESTRICT", FKEY },
{ "RIGHT", "TK_JOIN_KW", ALWAYS },
{ "ROLLBACK", "TK_ROLLBACK", ALWAYS },
{ "ROW", "TK_ROW", TRIGGER },
{ "SELECT", "TK_SELECT", ALWAYS },
{ "SET", "TK_SET", ALWAYS },
{ "STATEMENT", "TK_STATEMENT", TRIGGER },
{ "TABLE", "TK_TABLE", ALWAYS },
{ "TEMP", "TK_TEMP", ALWAYS },
{ "TEMPORARY", "TK_TEMP", ALWAYS },
{ "THEN", "TK_THEN", ALWAYS },
{ "TO", "TK_TO", ALTER },
{ "TRANSACTION", "TK_TRANSACTION", ALWAYS },
{ "TRIGGER", "TK_TRIGGER", TRIGGER },
{ "UNION", "TK_UNION", COMPOUND },
{ "UNIQUE", "TK_UNIQUE", ALWAYS },
{ "UPDATE", "TK_UPDATE", ALWAYS },
{ "USING", "TK_USING", ALWAYS },
{ "VACUUM", "TK_VACUUM", VACUUM },
{ "VALUES", "TK_VALUES", ALWAYS },
{ "VIEW", "TK_VIEW", VIEW },
{ "WHEN", "TK_WHEN", ALWAYS },
{ "WHERE", "TK_WHERE", ALWAYS },
};
/* Number of keywords */
#define NKEYWORD (sizeof(aKeywordTable)/sizeof(aKeywordTable[0]))
static int NKEYWORD = (sizeof(aKeywordTable)/sizeof(aKeywordTable[0]));
/* An array to map all upper-case characters into their corresponding
** lower-case character.
@ -153,10 +239,37 @@ const unsigned char sqlite3UpperToLower[] = {
/*
** Comparision function for two Keyword records
*/
static int keywordCompare(const void *a, const void *b){
static int keywordCompare1(const void *a, const void *b){
const Keyword *pA = (Keyword*)a;
const Keyword *pB = (Keyword*)b;
return strcmp(pA->zName, pB->zName);
int n = pA->len - pB->len;
if( n==0 ){
n = strcmp(pA->zName, pB->zName);
}
return n;
}
static int keywordCompare2(const void *a, const void *b){
const Keyword *pA = (Keyword*)a;
const Keyword *pB = (Keyword*)b;
int n = strcmp(pA->zName, pB->zName);
return n;
}
static int keywordCompare3(const void *a, const void *b){
const Keyword *pA = (Keyword*)a;
const Keyword *pB = (Keyword*)b;
int n = pA->offset - pB->offset;
return n;
}
/*
** Return a KeywordTable entry with the given id
*/
static Keyword *findById(int id){
int i;
for(i=0; i<NKEYWORD; i++){
if( aKeywordTable[i].id==id ) break;
}
return &aKeywordTable[i];
}
/*
@ -164,32 +277,89 @@ static int keywordCompare(const void *a, const void *b){
** output.
*/
int main(int argc, char **argv){
int i, j, h;
int i, j, k, h;
int bestSize, bestCount;
int count;
int nChar;
int aHash[1000]; /* 1000 is much bigger than NKEYWORD */
/* Make sure the table is sorted */
qsort(aKeywordTable, NKEYWORD, sizeof(aKeywordTable[0]), keywordCompare);
/* Remove entries from the list of keywords that have mask==0 */
for(i=j=0; i<NKEYWORD; i++){
if( aKeywordTable[i].mask==0 ) continue;
if( j<i ){
aKeywordTable[j] = aKeywordTable[i];
}
j++;
}
NKEYWORD = j;
/* Fill in the hash value, length, and offset for all entries */
nChar = 0;
/* Fill in the lengths of strings and hashes for all entries. */
for(i=0; i<NKEYWORD; i++){
Keyword *p = &aKeywordTable[i];
p->len = strlen(p->zName);
/* p->hash = sqlite3HashNoCase(p->zName, p->len); */
p->hash = UpperToLower[p->zName[0]]*5 +
UpperToLower[p->zName[p->len-1]]*3 + p->len;
p->offset = nChar;
if( i<NKEYWORD-1 && strncmp(p->zName, aKeywordTable[i+1].zName,p->len)==0 ){
/* This entry is a prefix of the one that follows. Do not advance
** the offset */
}else{
nChar += p->len;
p->hash = (UpperToLower[p->zName[0]]*4) ^
(UpperToLower[p->zName[p->len-1]]*3) ^ p->len;
p->id = i+1;
}
/* Sort the table from shortest to longest keyword */
qsort(aKeywordTable, NKEYWORD, sizeof(aKeywordTable[0]), keywordCompare1);
/* Look for short keywords embedded in longer keywords */
for(i=NKEYWORD-2; i>=0; i--){
Keyword *p = &aKeywordTable[i];
for(j=NKEYWORD-1; j>i && p->substrId==0; j--){
Keyword *pOther = &aKeywordTable[j];
if( pOther->substrId ) continue;
if( pOther->len<=p->len ) continue;
for(k=0; k<=pOther->len-p->len; k++){
if( memcmp(p->zName, &pOther->zName[k], p->len)==0 ){
p->substrId = pOther->id;
p->substrOffset = k;
break;
}
}
}
}
/* Sort the table into alphabetical order */
qsort(aKeywordTable, NKEYWORD, sizeof(aKeywordTable[0]), keywordCompare2);
/* Fill in the offset for all entries */
nChar = 0;
for(i=0; i<NKEYWORD; i++){
Keyword *p = &aKeywordTable[i];
if( p->offset>0 || p->substrId ) continue;
p->offset = nChar;
nChar += p->len;
for(k=p->len-1; k>=1; k--){
for(j=i+1; j<NKEYWORD; j++){
Keyword *pOther = &aKeywordTable[j];
if( pOther->offset>0 || pOther->substrId ) continue;
if( pOther->len<=k ) continue;
if( memcmp(&p->zName[p->len-k], pOther->zName, k)==0 ){
p = pOther;
p->offset = nChar - k;
nChar = p->offset + p->len;
p->zName += k;
p->len -= k;
p->prefix = k;
j = i;
k = p->len;
}
}
}
}
for(i=0; i<NKEYWORD; i++){
Keyword *p = &aKeywordTable[i];
if( p->substrId ){
p->offset = findById(p->substrId)->offset + p->substrOffset;
}
}
/* Sort the table by offset */
qsort(aKeywordTable, NKEYWORD, sizeof(aKeywordTable[0]), keywordCompare3);
/* Figure out how big to make the hash table in order to minimize the
** number of collisions */
bestSize = NKEYWORD;
@ -217,12 +387,13 @@ int main(int argc, char **argv){
}
/* Begin generating code */
printf("int sqlite3KeywordCode(const char *z, int n){\n");
printf("/* Hash score: %d */\n", bestCount);
printf("static int keywordCode(const char *z, int n){\n");
printf(" static const char zText[%d] =\n", nChar+1);
for(i=j=0; i<NKEYWORD; i++){
Keyword *p = &aKeywordTable[i];
if( i<NKEYWORD-1 && p->offset==aKeywordTable[i+1].offset ) continue;
if( p->substrId ) continue;
if( j==0 ) printf(" \"");
printf("%s", p->zName);
j += p->len;
@ -260,7 +431,7 @@ int main(int argc, char **argv){
printf(" static const unsigned char aLen[%d] = {\n", NKEYWORD);
for(i=j=0; i<NKEYWORD; i++){
if( j==0 ) printf(" ");
printf(" %3d,", aKeywordTable[i].len);
printf(" %3d,", aKeywordTable[i].len+aKeywordTable[i].prefix);
j++;
if( j>12 ){
printf("\n");
@ -296,8 +467,8 @@ int main(int argc, char **argv){
printf(" int h, i;\n");
printf(" if( n<2 ) return TK_ID;\n");
printf(" h = (sqlite3UpperToLower[((unsigned char*)z)[0]]*5 + \n"
" sqlite3UpperToLower[((unsigned char*)z)[n-1]]*3 +\n"
printf(" h = ((sqlite3UpperToLower[((unsigned char*)z)[0]]*4) ^\n"
" (sqlite3UpperToLower[((unsigned char*)z)[n-1]]*3) ^\n"
" n) %% %d;\n", bestSize);
printf(" for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){\n");
printf(" if( aLen[i]==n &&"
@ -307,6 +478,9 @@ int main(int argc, char **argv){
printf(" }\n");
printf(" return TK_ID;\n");
printf("}\n");
printf("int sqlite3KeywordCode(const char *z, int n){\n");
printf(" return keywordCode(z, n);\n");
printf("}\n");
return 0;
}

View File

@ -176,15 +176,16 @@ static int pdo_sqlite_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
stmt->columns[colno].namelen = strlen(stmt->columns[colno].name);
stmt->columns[colno].maxlen = 0xffffffff;
stmt->columns[colno].precision = 0;
switch (sqlite3_column_type(S->stmt, colno)) {
case SQLITE_INTEGER:
case SQLITE_FLOAT:
case SQLITE_TEXT:
case SQLITE3_TEXT:
case SQLITE_BLOB:
stmt->columns[colno].param_type = PDO_PARAM_STR;
break;
case SQLITE_NULL:
default:
stmt->columns[colno].param_type = PDO_PARAM_NULL;
break;
}
@ -214,10 +215,20 @@ static int pdo_sqlite_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsi
*ptr = (char*)sqlite3_column_blob(S->stmt, colno);
*len = sqlite3_column_bytes(S->stmt, colno);
return 1;
case SQLITE3_TEXT:
*ptr = (char*)sqlite3_column_text(S->stmt, colno);
*len = sqlite3_column_bytes(S->stmt, colno);
if (*len) {
/* sqlite3.h says "the NUL terminator is included in the byte count
* for TEXT values" */
*len--;
}
return 1;
default:
*ptr = (char*)sqlite3_column_text(S->stmt, colno);
*len = strlen(*ptr);
*len = sqlite3_column_bytes(S->stmt, colno);
return 1;
}
}