mirror of
https://github.com/php/php-src.git
synced 2025-01-20 10:43:40 +08:00
upgrade bundled sqlite to sqlite 3.1.3
This commit is contained in:
parent
58f61a16ee
commit
ae5649598d
@ -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
|
||||
|
@ -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"/>
|
||||
|
@ -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
|
||||
|
@ -1 +1 @@
|
||||
3.0.8
|
||||
3.1.3
|
||||
|
761
ext/pdo_sqlite/sqlite/configure
vendored
761
ext/pdo_sqlite/sqlite/configure
vendored
@ -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
|
||||
|
@ -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.
|
||||
#
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
#
|
||||
|
334
ext/pdo_sqlite/sqlite/src/alter.c
Normal file
334
ext/pdo_sqlite/sqlite/src/alter.c
Normal 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 */
|
@ -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
|
||||
|
@ -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
@ -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
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
38
ext/pdo_sqlite/sqlite/src/experimental.c
Normal file
38
ext/pdo_sqlite/sqlite/src/experimental.c
Normal 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
@ -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 ){
|
||||
|
@ -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;
|
||||
|
@ -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 ){
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
@ -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
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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, ¬Used1);
|
||||
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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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) */
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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*);
|
||||
|
@ -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*);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user