summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlia Alshanetsky <iliaa@php.net>2006-08-14 16:15:29 +0000
committerIlia Alshanetsky <iliaa@php.net>2006-08-14 16:15:29 +0000
commite8f30d450255baa92c1f2abe5d4a2696b6e4ebf0 (patch)
tree1ededffa0df99ad1b61a3e476febad54b6a15991
parent0091c7e1b337de1252824ec33c87b4bed9ca2a5c (diff)
downloadphp-git-e8f30d450255baa92c1f2abe5d4a2696b6e4ebf0.tar.gz
Upgraded bunbled SQLite lib to 3.3.7
-rw-r--r--ext/pdo_sqlite/config.m46
-rw-r--r--ext/pdo_sqlite/config.w326
-rw-r--r--ext/pdo_sqlite/package2.xml7
-rw-r--r--ext/pdo_sqlite/sqlite/Makefile.in78
-rw-r--r--ext/pdo_sqlite/sqlite/Makefile.linux-gcc18
-rw-r--r--ext/pdo_sqlite/sqlite/VERSION2
-rw-r--r--ext/pdo_sqlite/sqlite/aclocal.m42
-rwxr-xr-xext/pdo_sqlite/sqlite/configure444
-rw-r--r--ext/pdo_sqlite/sqlite/configure.ac101
-rw-r--r--ext/pdo_sqlite/sqlite/main.mk81
-rw-r--r--ext/pdo_sqlite/sqlite/mkdll.sh6
-rw-r--r--ext/pdo_sqlite/sqlite/mkopcodeh.awk25
-rw-r--r--ext/pdo_sqlite/sqlite/publish.sh2
-rw-r--r--ext/pdo_sqlite/sqlite/sqlite3.def4
-rw-r--r--ext/pdo_sqlite/sqlite/src/alter.c80
-rw-r--r--ext/pdo_sqlite/sqlite/src/analyze.c37
-rw-r--r--ext/pdo_sqlite/sqlite/src/attach.c396
-rw-r--r--ext/pdo_sqlite/sqlite/src/auth.c19
-rw-r--r--ext/pdo_sqlite/sqlite/src/btree.c1452
-rw-r--r--ext/pdo_sqlite/sqlite/src/btree.h9
-rw-r--r--ext/pdo_sqlite/sqlite/src/build.c868
-rw-r--r--ext/pdo_sqlite/sqlite/src/callback.c85
-rw-r--r--ext/pdo_sqlite/sqlite/src/complete.c263
-rw-r--r--ext/pdo_sqlite/sqlite/src/date.c26
-rw-r--r--ext/pdo_sqlite/sqlite/src/delete.c91
-rw-r--r--ext/pdo_sqlite/sqlite/src/experimental.c37
-rw-r--r--ext/pdo_sqlite/sqlite/src/expr.c310
-rw-r--r--ext/pdo_sqlite/sqlite/src/func.c179
-rw-r--r--ext/pdo_sqlite/sqlite/src/hash.c29
-rw-r--r--ext/pdo_sqlite/sqlite/src/hash.h2
-rw-r--r--ext/pdo_sqlite/sqlite/src/insert.c155
-rw-r--r--ext/pdo_sqlite/sqlite/src/keywordhash.h87
-rw-r--r--ext/pdo_sqlite/sqlite/src/legacy.c13
-rw-r--r--ext/pdo_sqlite/sqlite/src/loadext.c355
-rw-r--r--ext/pdo_sqlite/sqlite/src/main.c641
-rw-r--r--ext/pdo_sqlite/sqlite/src/opcodes.h296
-rw-r--r--ext/pdo_sqlite/sqlite/src/os.c92
-rw-r--r--ext/pdo_sqlite/sqlite/src/os.h355
-rw-r--r--ext/pdo_sqlite/sqlite/src/os_common.h67
-rw-r--r--ext/pdo_sqlite/sqlite/src/os_mac.c738
-rw-r--r--ext/pdo_sqlite/sqlite/src/os_mac.h41
-rw-r--r--ext/pdo_sqlite/sqlite/src/os_unix.c1010
-rw-r--r--ext/pdo_sqlite/sqlite/src/os_win.c936
-rw-r--r--ext/pdo_sqlite/sqlite/src/pager.c1225
-rw-r--r--ext/pdo_sqlite/sqlite/src/pager.h11
-rw-r--r--ext/pdo_sqlite/sqlite/src/parse.c4155
-rw-r--r--ext/pdo_sqlite/sqlite/src/parse.h298
-rw-r--r--ext/pdo_sqlite/sqlite/src/parse.y229
-rw-r--r--ext/pdo_sqlite/sqlite/src/pragma.c160
-rw-r--r--ext/pdo_sqlite/sqlite/src/prepare.c233
-rw-r--r--ext/pdo_sqlite/sqlite/src/printf.c97
-rw-r--r--ext/pdo_sqlite/sqlite/src/select.c772
-rw-r--r--ext/pdo_sqlite/sqlite/src/shell.c110
-rw-r--r--ext/pdo_sqlite/sqlite/src/sqlite.h.in475
-rw-r--r--ext/pdo_sqlite/sqlite/src/sqlite3ext.h280
-rw-r--r--ext/pdo_sqlite/sqlite/src/sqliteInt.h529
-rw-r--r--ext/pdo_sqlite/sqlite/src/table.c27
-rw-r--r--ext/pdo_sqlite/sqlite/src/tclsqlite.c272
-rw-r--r--ext/pdo_sqlite/sqlite/src/test1.c880
-rw-r--r--ext/pdo_sqlite/sqlite/src/test2.c10
-rw-r--r--ext/pdo_sqlite/sqlite/src/test3.c23
-rw-r--r--ext/pdo_sqlite/sqlite/src/test4.c72
-rw-r--r--ext/pdo_sqlite/sqlite/src/test5.c8
-rw-r--r--ext/pdo_sqlite/sqlite/src/tokenize.c122
-rw-r--r--ext/pdo_sqlite/sqlite/src/trigger.c161
-rw-r--r--ext/pdo_sqlite/sqlite/src/update.c176
-rw-r--r--ext/pdo_sqlite/sqlite/src/utf.c44
-rw-r--r--ext/pdo_sqlite/sqlite/src/util.c968
-rw-r--r--ext/pdo_sqlite/sqlite/src/vacuum.c59
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbe.c1311
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbe.h17
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbeInt.h48
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbeapi.c170
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbeaux.c567
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbemem.c149
-rw-r--r--ext/pdo_sqlite/sqlite/src/vtab.c659
-rw-r--r--ext/pdo_sqlite/sqlite/src/where.c681
-rw-r--r--ext/pdo_sqlite/sqlite/tool/lemon.c298
-rw-r--r--ext/pdo_sqlite/sqlite/tool/lempar.c52
-rw-r--r--ext/pdo_sqlite/sqlite/tool/memleak3.tcl1
-rw-r--r--ext/pdo_sqlite/sqlite/tool/mkkeywordhash.c18
-rw-r--r--ext/pdo_sqlite/sqlite/tool/showdb.c7
-rw-r--r--ext/pdo_sqlite/sqlite/tool/spaceanal.tcl51
83 files changed, 17126 insertions, 7750 deletions
diff --git a/ext/pdo_sqlite/config.m4 b/ext/pdo_sqlite/config.m4
index cacd0de083..4907e8c947 100644
--- a/ext/pdo_sqlite/config.m4
+++ b/ext/pdo_sqlite/config.m4
@@ -75,14 +75,14 @@ if test "$PHP_PDO_SQLITE" != "no"; then
pdo_sqlite_sources="sqlite/src/attach.c sqlite/src/auth.c sqlite/src/btree.c \
sqlite/src/build.c sqlite/src/callback.c sqlite/src/date.c sqlite/src/delete.c sqlite/src/expr.c \
sqlite/src/func.c sqlite/src/hash.c sqlite/src/insert.c sqlite/src/legacy.c \
- sqlite/src/main.c sqlite/src/os_mac.c sqlite/src/os_unix.c sqlite/src/os_win.c \
+ sqlite/src/main.c sqlite/src/os_unix.c sqlite/src/os_win.c sqlite/src/os.c \
sqlite/src/pager.c sqlite/src/pragma.c sqlite/src/prepare.c \
sqlite/src/printf.c sqlite/src/random.c sqlite/src/select.c \
- sqlite/src/table.c sqlite/src/tokenize.c sqlite/src/analyze.c \
+ sqlite/src/table.c sqlite/src/tokenize.c sqlite/src/analyze.c sqlite/src/complete.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/alter.c sqlite/src/vdbefifo.c sqlite/src/experimental.c"
+ sqlite/src/alter.c sqlite/src/vdbefifo.c sqlite/src/vtab.c sqlite/src/loadext.c"
PHP_NEW_EXTENSION(pdo_sqlite,
$php_pdo_sqlite_sources_core $pdo_sqlite_sources,
diff --git a/ext/pdo_sqlite/config.w32 b/ext/pdo_sqlite/config.w32
index 11f09e3507..f9d663f17f 100644
--- a/ext/pdo_sqlite/config.w32
+++ b/ext/pdo_sqlite/config.w32
@@ -22,9 +22,9 @@ if (PHP_PDO_SQLITE != "no") {
EXTENSION("pdo_sqlite", "pdo_sqlite.c sqlite_driver.c sqlite_statement.c", null, "/DSQLITE_OMIT_CURSOR /I" + configure_module_dirname + "/sqlite/src /I" + configure_module_dirname);
ADD_SOURCES(configure_module_dirname + "/sqlite/src",
"attach.c auth.c btree.c build.c callback.c date.c delete.c expr.c func.c hash.c insert.c \
- legacy.c main.c os_mac.c os_unix.c os_win.c pager.c pragma.c prepare.c printf.c random.c \
- select.c table.c tokenize.c trigger.c update.c utf.c util.c vacuum.c vdbeapi.c analyze.c \
- vdbeaux.c vdbe.c vdbemem.c vdbefifo.c where.c parse.c opcodes.c alter.c experimental.c", "pdo_sqlite");
+ legacy.c main.c os.c os_unix.c os_win.c pager.c pragma.c prepare.c printf.c random.c \
+ select.c table.c tokenize.c trigger.c update.c utf.c util.c vacuum.c vdbeapi.c analyze.c complete.c \
+ vdbeaux.c vdbe.c vdbemem.c vdbefifo.c where.c parse.c opcodes.c alter.c vtab.c loadext.c", "pdo_sqlite");
ADD_EXTENSION_DEP('pdo_sqlite', 'pdo');
}
diff --git a/ext/pdo_sqlite/package2.xml b/ext/pdo_sqlite/package2.xml
index 7ccec31cb0..23a4afa7c7 100644
--- a/ext/pdo_sqlite/package2.xml
+++ b/ext/pdo_sqlite/package2.xml
@@ -57,7 +57,6 @@ http://pecl4win.php.net/ext.php/php_pdo_sqlite.dll
<file name="callback.c" role="src" />
<file name="date.c" role="src" />
<file name="delete.c" role="src" />
- <file name="experimental.c" role="src" />
<file name="expr.c" role="src" />
<file name="func.c" role="src" />
<file name="hash.c" role="src" />
@@ -70,9 +69,8 @@ http://pecl4win.php.net/ext.php/php_pdo_sqlite.dll
<file name="opcodes.c" role="src" />
<file name="opcodes.h" role="src" />
<file name="os.h" role="src" />
+ <file name="os.c" role="src" />
<file name="os_common.h" role="src" />
- <file name="os_mac.c" role="src" />
- <file name="os_mac.h" role="src" />
<file name="os_test.c" role="src" />
<file name="os_test.h" role="src" />
<file name="os_unix.c" role="src" />
@@ -113,6 +111,9 @@ http://pecl4win.php.net/ext.php/php_pdo_sqlite.dll
<file name="vdbeInt.h" role="src" />
<file name="vdbemem.c" role="src" />
<file name="where.c" role="src" />
+ <file name="vtab.c" role="src" />
+ <file name="loadext.c" role="src" />
+ <file name="complete.c" role="src" />
</dir> <!-- //sqlite/src -->
<dir name="tool">
<file name="diffdb.c" role="src" />
diff --git a/ext/pdo_sqlite/sqlite/Makefile.in b/ext/pdo_sqlite/sqlite/Makefile.in
index db47144225..712823e5f6 100644
--- a/ext/pdo_sqlite/sqlite/Makefile.in
+++ b/ext/pdo_sqlite/sqlite/Makefile.in
@@ -32,7 +32,7 @@ TCC = @TARGET_CC@ @TARGET_CFLAGS@ -I. -I${TOP}/src
# Omitting the define will cause extra debugging code to be inserted and
# includes extra comments when "EXPLAIN stmt" is used.
#
-TCC += @TARGET_DEBUG@
+TCC += @TARGET_DEBUG@ @XTHREADCONNECT@
# Compiler options needed for programs that use the TCL library.
#
@@ -58,6 +58,13 @@ TCC += -DTHREADSAFE=@THREADSAFE@
#
LIBPTHREAD=@TARGET_THREAD_LIB@
+# Do threads override each others locks by default (1), or do we test (-1)
+#
+TCC += -DSQLITE_THREAD_OVERRIDE_LOCK=@THREADSOVERRIDELOCKS@
+
+# The fdatasync library
+TLIBS = @TARGET_LIBS@
+
# Flags controlling use of the in memory btree implementation
#
# TEMP_STORE is 0 to force temporary tables to be in a file, 1 to
@@ -104,9 +111,12 @@ LTCOMPILE = $(LIBTOOL) --mode=compile $(TCC)
LTLINK = $(LIBTOOL) --mode=link $(TCC)
LTINSTALL = $(LIBTOOL) --mode=install $(INSTALL)
+# nawk compatible awk.
+NAWK = @AWK@
+
# You should not have to change anything below this line
###############################################################################
-
+OPTS =
OPTS += -DSQLITE_OMIT_CURSOR # Cursors do not work at this time
TCC += -DSQLITE_OMIT_CURSOR
@@ -114,13 +124,13 @@ TCC += -DSQLITE_OMIT_CURSOR
#
LIBOBJ = alter.lo analyze.lo attach.lo auth.lo btree.lo build.lo \
callback.lo complete.lo date.lo \
- delete.lo expr.lo func.lo hash.lo insert.lo \
- main.lo opcodes.lo os_unix.lo os_win.lo \
+ delete.lo expr.lo func.lo hash.lo insert.lo loadext.lo \
+ main.lo opcodes.lo os.lo os_unix.lo os_win.lo os_os2.lo \
pager.lo parse.lo pragma.lo prepare.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 vdbefifo.lo vdbemem.lo \
- where.lo utf.lo legacy.lo
+ where.lo utf.lo legacy.lo vtab.lo
# All of the source code files.
#
@@ -142,9 +152,12 @@ SRC = \
$(TOP)/src/hash.h \
$(TOP)/src/insert.c \
$(TOP)/src/legacy.c \
+ $(TOP)/src/loadext.c \
$(TOP)/src/main.c \
+ $(TOP)/src/os.c \
$(TOP)/src/os_unix.c \
$(TOP)/src/os_win.c \
+ $(TOP)/src/os_os2.c \
$(TOP)/src/pager.c \
$(TOP)/src/pager.h \
$(TOP)/src/parse.y \
@@ -171,6 +184,7 @@ SRC = \
$(TOP)/src/vdbefifo.c \
$(TOP)/src/vdbemem.c \
$(TOP)/src/vdbeInt.h \
+ $(TOP)/src/vtab.c \
$(TOP)/src/where.c
# Source code to the test files.
@@ -179,8 +193,10 @@ TESTSRC = \
$(TOP)/src/btree.c \
$(TOP)/src/date.c \
$(TOP)/src/func.c \
+ $(TOP)/src/os.c \
$(TOP)/src/os_unix.c \
$(TOP)/src/os_win.c \
+ $(TOP)/src/os_os2.c \
$(TOP)/src/pager.c \
$(TOP)/src/pragma.c \
$(TOP)/src/printf.c \
@@ -189,10 +205,17 @@ TESTSRC = \
$(TOP)/src/test3.c \
$(TOP)/src/test4.c \
$(TOP)/src/test5.c \
+ $(TOP)/src/test6.c \
+ $(TOP)/src/test7.c \
+ $(TOP)/src/test8.c \
+ $(TOP)/src/test_async.c \
+ $(TOP)/src/test_md5.c \
+ $(TOP)/src/test_schema.c \
+ $(TOP)/src/test_server.c \
+ $(TOP)/src/test_tclvar.c \
$(TOP)/src/utf.c \
$(TOP)/src/util.c \
$(TOP)/src/vdbe.c \
- $(TOP)/src/md5.c \
$(TOP)/src/where.c
# Header files used by all library source files.
@@ -204,8 +227,7 @@ HDR = \
opcodes.h \
$(TOP)/src/os.h \
$(TOP)/src/os_common.h \
- $(TOP)/src/os_unix.h \
- $(TOP)/src/os_win.h \
+ $(TOP)/src/sqlite3ext.h \
$(TOP)/src/sqliteInt.h \
$(TOP)/src/vdbe.h \
parse.h
@@ -228,8 +250,8 @@ Makefile: $(TOP)/Makefile.in
# of the most recently modified source code file
#
last_change: $(SRC)
- cat $(SRC) | grep '$$Id: ' | sort +4 | tail -1 \
- | awk '{print $$5,$$6}' >last_change
+ cat $(SRC) | grep '$$Id: ' | sort -k 5 | tail -1 \
+ | $(NAWK) '{print $$5,$$6}' >last_change
libsqlite3.la: $(LIBOBJ)
$(LTLINK) -o libsqlite3.la $(LIBOBJ) $(LIBPTHREAD) \
@@ -243,7 +265,8 @@ libtclsqlite3.la: tclsqlite.lo libsqlite3.la
sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h
$(LTLINK) $(READLINE_FLAGS) $(LIBPTHREAD) \
- -o sqlite3 $(TOP)/src/shell.c libsqlite3.la $(LIBREADLINE)
+ -o $@ $(TOP)/src/shell.c libsqlite3.la \
+ $(LIBREADLINE) $(TLIBS)
# This target creates a directory named "tsrc" and fills it with
# copies of all of the C source code and header files needed to
@@ -313,6 +336,9 @@ insert.lo: $(TOP)/src/insert.c $(HDR)
legacy.lo: $(TOP)/src/legacy.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/legacy.c
+loadext.lo: $(TOP)/src/loadext.c $(HDR)
+ $(LTCOMPILE) -c $(TOP)/src/loadext.c
+
main.lo: $(TOP)/src/main.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/main.c
@@ -323,10 +349,13 @@ opcodes.lo: opcodes.c
$(LTCOMPILE) -c opcodes.c
opcodes.c: opcodes.h $(TOP)/mkopcodec.awk
- sort -n -b +2 opcodes.h | awk -f $(TOP)/mkopcodec.awk >opcodes.c
+ sort -n -b -k 3 opcodes.h | $(NAWK) -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
+ cat parse.h $(TOP)/src/vdbe.c | $(NAWK) -f $(TOP)/mkopcodeh.awk >opcodes.h
+
+os.lo: $(TOP)/src/os.c $(HDR)
+ $(LTCOMPILE) -c $(TOP)/src/os.c
os_unix.lo: $(TOP)/src/os_unix.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/os_unix.c
@@ -334,14 +363,19 @@ os_unix.lo: $(TOP)/src/os_unix.c $(HDR)
os_win.lo: $(TOP)/src/os_win.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/os_win.c
+os_os2.lo: $(TOP)/src/os_os2.c $(HDR)
+ $(LTCOMPILE) -c $(TOP)/src/os_os2.c
+
parse.lo: parse.c $(HDR)
$(LTCOMPILE) -c parse.c
parse.h: parse.c
-parse.c: $(TOP)/src/parse.y lemon$(BEXE)
+parse.c: $(TOP)/src/parse.y lemon$(BEXE) $(TOP)/addopcodes.awk
cp $(TOP)/src/parse.y .
./lemon $(OPTS) parse.y
+ mv parse.h parse.h.temp
+ awk -f $(TOP)/addopcodes.awk parse.h.temp >parse.h
pragma.lo: $(TOP)/src/pragma.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/pragma.c
@@ -405,6 +439,9 @@ vdbefifo.lo: $(TOP)/src/vdbefifo.c $(VDBEHDR)
vdbemem.lo: $(TOP)/src/vdbemem.c $(VDBEHDR)
$(LTCOMPILE) -c $(TOP)/src/vdbemem.c
+vtab.lo: $(TOP)/src/vtab.c $(VDBEHDR)
+ $(LTCOMPILE) -c $(TOP)/src/vtab.c
+
where.lo: $(TOP)/src/where.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/where.c
@@ -419,19 +456,12 @@ tclsqlite3: tclsqlite-shell.lo libsqlite3.la
libsqlite3.la $(LIBTCL)
testfixture$(TEXE): $(TOP)/src/tclsqlite.c libsqlite3.la $(TESTSRC)
- $(LTLINK) -DTCLSH=1 -DSQLITE_TEST=1 $(TEMP_STORE) \
- -o testfixture $(TESTSRC) $(TOP)/src/tclsqlite.c \
+ $(LTLINK) -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 \
+ $(TEMP_STORE) -o testfixture $(TESTSRC) $(TOP)/src/tclsqlite.c \
libsqlite3.la $(LIBTCL)
-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)
-
-
-fulltest: testfixture$(TEXE) sqlite3$(TEXE) crashtest$(TEXE)
+fulltest: testfixture$(TEXE) sqlite3$(TEXE)
./testfixture $(TOP)/test/all.test
test: testfixture$(TEXE) sqlite3$(TEXE)
diff --git a/ext/pdo_sqlite/sqlite/Makefile.linux-gcc b/ext/pdo_sqlite/sqlite/Makefile.linux-gcc
index 202f4a1ee2..c865024b44 100644
--- a/ext/pdo_sqlite/sqlite/Makefile.linux-gcc
+++ b/ext/pdo_sqlite/sqlite/Makefile.linux-gcc
@@ -41,6 +41,11 @@ THREADSAFE = -DTHREADSAFE=0
#THREADLIB = -lpthread
THREADLIB =
+#### Specify any extra libraries needed to access required functions.
+#
+#TLIBS = -lrt # fdatasync on Solaris 8
+TLIBS =
+
#### Leave SQLITE_DEBUG undefined for maximum speed. Use SQLITE_DEBUG=1
# to check for memory leaks. Use SQLITE_DEBUG=2 to print a log of all
# malloc()s and free()s in order to track down memory leaks.
@@ -53,6 +58,7 @@ THREADLIB =
#OPTS = -DSQLITE_DEBUG=1
#OPTS =
OPTS = -DNDEBUG=1
+OPTS += -DHAVE_FDATASYNC=1
#### The suffix to add to executable files. ".exe" for windows.
# Nothing for unix.
@@ -77,6 +83,12 @@ AR = ar cr
RANLIB = ranlib
#RANLIB = /opt/mingw/bin/i386-mingw32-ranlib
+MKSHLIB = gcc -shared
+SO = so
+SHPREFIX = lib
+# SO = dll
+# SHPREFIX =
+
#### Extra compiler options needed for programs that use the TCL library.
#
#TCL_FLAGS =
@@ -107,6 +119,12 @@ LIBREADLINE =
# ENCODING = UTF8
ENCODING = ISO8859
+
+#### Which "awk" program provides nawk compatibilty
+#
+# NAWK = nawk
+NAWK = awk
+
# You should not have to change anything below this line
###############################################################################
include $(TOP)/main.mk
diff --git a/ext/pdo_sqlite/sqlite/VERSION b/ext/pdo_sqlite/sqlite/VERSION
index f092941a75..86fb650440 100644
--- a/ext/pdo_sqlite/sqlite/VERSION
+++ b/ext/pdo_sqlite/sqlite/VERSION
@@ -1 +1 @@
-3.2.8
+3.3.7
diff --git a/ext/pdo_sqlite/sqlite/aclocal.m4 b/ext/pdo_sqlite/sqlite/aclocal.m4
index 852eb3134b..b50b61e56a 100644
--- a/ext/pdo_sqlite/sqlite/aclocal.m4
+++ b/ext/pdo_sqlite/sqlite/aclocal.m4
@@ -151,7 +151,7 @@ ltmain="$ac_aux_dir/ltmain.sh"
ofile="$default_ofile"
with_gnu_ld="$lt_cv_prog_gnu_ld"
-AC_CHECK_TOOL(AR, ar, false)
+AC_CHECK_TOOL(AR, ar, AC_CHECK_TOOL(AR, emxomfar, false))
AC_CHECK_TOOL(RANLIB, ranlib, :)
AC_CHECK_TOOL(STRIP, strip, :)
diff --git a/ext/pdo_sqlite/sqlite/configure b/ext/pdo_sqlite/sqlite/configure
index 11e3c9c51b..666f18668e 100755
--- a/ext/pdo_sqlite/sqlite/configure
+++ b/ext/pdo_sqlite/sqlite/configure
@@ -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 RELEASE VERSION_NUMBER 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_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 AWK program_prefix VERSION RELEASE VERSION_NUMBER BUILD_CC BUILD_CFLAGS BUILD_LIBS TARGET_CC TARGET_CFLAGS TARGET_LINK TARGET_LFLAGS TARGET_RANLIB TARGET_AR THREADSAFE TARGET_THREAD_LIB XTHREADCONNECT THREADSOVERRIDELOCKS ALLOWRELEASE TEMP_STORE BUILD_EXEEXT OS_UNIX OS_WIN OS_OS2 TARGET_EXEEXT 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 TARGET_LIBS LIBOBJS LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@@ -1025,11 +1025,16 @@ Optional Features:
--enable-fast-install[=PKGS]
optimize for fast installation [default=yes]
--disable-libtool-lock avoid locking (might break parallel builds)
- --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
+ --enable-threadsafe Support threadsafe operation
+ --enable-cross-thread-connections
+ Allow connection sharing across threads
+ --enable-threads-override-locks
+ Threads can override each others locks
+ --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]
@@ -1040,7 +1045,8 @@ 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)
+ --with-tcl=DIR directory containing tcl configuration
+ (tclConfig.sh)
Some influential environment variables:
CC C compiler command
@@ -3055,7 +3061,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 3058 "configure"' > conftest.$ac_ext
+ echo '#line 3064 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -4518,7 +4524,7 @@ fi
# Provide some information about the compiler.
-echo "$as_me:4521:" \
+echo "$as_me:4527:" \
"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
@@ -5552,11 +5558,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:5555: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:5561: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:5559: \$? = $ac_status" >&5
+ echo "$as_me:5565: \$? = $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
@@ -5785,11 +5791,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:5788: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:5794: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:5792: \$? = $ac_status" >&5
+ echo "$as_me:5798: \$? = $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
@@ -5845,11 +5851,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:5848: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:5854: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:5852: \$? = $ac_status" >&5
+ echo "$as_me:5858: \$? = $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
@@ -8029,7 +8035,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 8032 "configure"
+#line 8038 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -8127,7 +8133,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 8130 "configure"
+#line 8136 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -10306,11 +10312,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:10309: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:10315: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:10313: \$? = $ac_status" >&5
+ echo "$as_me:10319: \$? = $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
@@ -10366,11 +10372,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:10369: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:10375: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:10373: \$? = $ac_status" >&5
+ echo "$as_me:10379: \$? = $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
@@ -11727,7 +11733,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 11730 "configure"
+#line 11736 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11825,7 +11831,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 11828 "configure"
+#line 11834 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -12652,11 +12658,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:12655: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:12661: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:12659: \$? = $ac_status" >&5
+ echo "$as_me:12665: \$? = $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
@@ -12712,11 +12718,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:12715: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:12721: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:12719: \$? = $ac_status" >&5
+ echo "$as_me:12725: \$? = $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
@@ -14746,11 +14752,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:14749: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:14755: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:14753: \$? = $ac_status" >&5
+ echo "$as_me:14759: \$? = $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
@@ -14979,11 +14985,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:14982: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:14988: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:14986: \$? = $ac_status" >&5
+ echo "$as_me:14992: \$? = $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
@@ -15039,11 +15045,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:15042: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:15048: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:15046: \$? = $ac_status" >&5
+ echo "$as_me:15052: \$? = $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
@@ -17223,7 +17229,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 17226 "configure"
+#line 17232 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -17321,7 +17327,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 17324 "configure"
+#line 17330 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -18414,6 +18420,46 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AWK+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AWK="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ echo "$as_me:$LINENO: result: $AWK" >&5
+echo "${ECHO_T}$AWK" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$AWK" && break
+done
+
#########
# Set up an appropriate program prefix
@@ -19500,6 +19546,57 @@ fi
##########
+# Do we want to allow a connection created in one thread to be used
+# in another thread. This does not work on many Linux systems (ex: RedHat 9)
+# due to bugs in the threading implementations. This is thus off by default.
+#
+# Check whether --enable-cross-thread-connections or --disable-cross-thread-connections was given.
+if test "${enable_cross_thread_connections+set}" = set; then
+ enableval="$enable_cross_thread_connections"
+
+else
+ enable_xthreadconnect=no
+fi;
+echo "$as_me:$LINENO: checking whether to allow connections to be shared across threads" >&5
+echo $ECHO_N "checking whether to allow connections to be shared across threads... $ECHO_C" >&6
+if test "$enable_xthreadconnect" = "no"; then
+ XTHREADCONNECT=''
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+else
+ XTHREADCONNECT='-DSQLITE_ALLOW_XTHREAD_CONNECT=1'
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+fi
+
+
+##########
+# Do we want to set threadsOverrideEachOthersLocks variable to be 1 (true) by
+# default. Normally, a test at runtime is performed to determine the
+# appropriate value of this variable. Use this option only if you're sure that
+# threads can safely override each others locks in all runtime situations.
+#
+# Check whether --enable-threads-override-locks or --disable-threads-override-locks was given.
+if test "${enable_threads_override_locks+set}" = set; then
+ enableval="$enable_threads_override_locks"
+
+else
+ enable_threads_override_locks=no
+fi;
+echo "$as_me:$LINENO: checking whether threads can override each others locks" >&5
+echo $ECHO_N "checking whether threads can override each others locks... $ECHO_C" >&6
+if test "$enable_threads_override_locks" = "no"; then
+ THREADSOVERRIDELOCKS='-1'
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+else
+ THREADSOVERRIDELOCKS='1'
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+fi
+
+
+##########
# Do we want to support release
#
# Check whether --enable-releasemode or --disable-releasemode was given.
@@ -19530,7 +19627,7 @@ if test "${enable_tempstore+set}" = set; then
enableval="$enable_tempstore"
else
- enable_tempstore=yes
+ enable_tempstore=no
fi;
echo "$as_me:$LINENO: checking whether to use an in-ram database for temporary tables" >&5
echo $ECHO_N "checking whether to use an in-ram database for temporary tables... $ECHO_C" >&6
@@ -19550,8 +19647,13 @@ echo "${ECHO_T}no" >&6
echo "$as_me:$LINENO: result: always" >&5
echo "${ECHO_T}always" >&6
;;
+ yes )
+ TEMP_STORE=3
+ echo "$as_me:$LINENO: result: always" >&5
+echo "${ECHO_T}always" >&6
+ ;;
* )
- TEMP_STORE=2
+ TEMP_STORE=1
echo "$as_me:$LINENO: result: yes" >&5
echo "${ECHO_T}yes" >&6
;;
@@ -19593,13 +19695,26 @@ else
TARGET_EXEEXT=$config_TARGET_EXEEXT
fi
if test "$TARGET_EXEEXT" = ".exe"; then
- OS_UNIX=0
- OS_WIN=1
- tclsubdir=win
- TARGET_CFLAGS="$TARGET_CFLAGS -DOS_WIN=1"
+ if test $OS2_SHELL ; then
+ OS_UNIX=0
+ OS_WIN=0
+ OS_OS2=1
+ TARGET_CFLAGS="$TARGET_CFLAGS -DOS_OS2=1"
+ if test "$ac_compiler_gnu" == "yes" ; then
+ TARGET_CFLAGS="$TARGET_CFLAGS -Zomf -Zexe -Zmap"
+ BUILD_CFLAGS="$BUILD_CFLAGS -Zomf -Zexe"
+ fi
+ else
+ OS_UNIX=0
+ OS_WIN=1
+ OS_OS2=0
+ tclsubdir=win
+ TARGET_CFLAGS="$TARGET_CFLAGS -DOS_WIN=1"
+ fi
else
OS_UNIX=1
OS_WIN=0
+ OS_OS2=0
tclsubdir=unix
TARGET_CFLAGS="$TARGET_CFLAGS -DOS_UNIX=1"
fi
@@ -19618,7 +19733,6 @@ else
TARGET_LIBS=""
fi
-
##########
# Figure out all the parameters needed to compile against Tcl.
#
@@ -20000,6 +20114,140 @@ fi
##########
+# Figure out what C libraries are required to compile programs
+# that use "fdatasync()" function.
+#
+CC=$TARGET_CC
+LIBS=$TARGET_LIBS
+echo "$as_me:$LINENO: checking for library containing fdatasync" >&5
+echo $ECHO_N "checking for library containing fdatasync... $ECHO_C" >&6
+if test "${ac_cv_search_fdatasync+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_fdatasync=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 fdatasync ();
+int
+main ()
+{
+fdatasync ();
+ ;
+ 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_fdatasync="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_fdatasync" = no; then
+ for ac_lib in rt; do
+ LIBS="-l$ac_lib $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 fdatasync ();
+int
+main ()
+{
+fdatasync ();
+ ;
+ 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_fdatasync="-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_fdatasync" >&5
+echo "${ECHO_T}$ac_cv_search_fdatasync" >&6
+if test "$ac_cv_search_fdatasync" != no; then
+ test "$ac_cv_search_fdatasync" = "none required" || LIBS="$ac_cv_search_fdatasync $LIBS"
+
+fi
+
+TARGET_LIBS="$LIBS"
+
+##########
# Figure out where to get the READLINE header files.
#
echo "$as_me:$LINENO: checking readline header files" >&5
@@ -20236,7 +20484,7 @@ else
use_debug=no
fi;
if test "${use_debug}" = "yes" ; then
- TARGET_DEBUG=""
+ TARGET_DEBUG="-DSQLITE_DEBUG=1"
else
TARGET_DEBUG="-DNDEBUG"
fi
@@ -20340,6 +20588,110 @@ if test $ac_cv_func_usleep = yes; then
fi
+#--------------------------------------------------------------------
+# Redefine fdatasync as fsync on systems that lack fdatasync
+#--------------------------------------------------------------------
+
+echo "$as_me:$LINENO: checking for fdatasync" >&5
+echo $ECHO_N "checking for fdatasync... $ECHO_C" >&6
+if test "${ac_cv_func_fdatasync+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 fdatasync to an innocuous variant, in case <limits.h> declares fdatasync.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define fdatasync innocuous_fdatasync
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char fdatasync (); 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 fdatasync
+
+/* 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 fdatasync ();
+/* 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_fdatasync) || defined (__stub___fdatasync)
+choke me
+#else
+char (*f) () = fdatasync;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != fdatasync;
+ ;
+ 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_fdatasync=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_fdatasync=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_fdatasync" >&5
+echo "${ECHO_T}$ac_cv_func_fdatasync" >&6
+if test $ac_cv_func_fdatasync = yes; then
+ TARGET_CFLAGS="$TARGET_CFLAGS -DHAVE_FDATASYNC=1"
+fi
+
+
+#########
+# Put out accumulated miscellaneous LIBRARIES
+#
+
+
#########
# Generate the output files.
#
@@ -21016,6 +21368,7 @@ s,@LIBTOOL@,$LIBTOOL,;t t
s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@AWK@,$AWK,;t t
s,@program_prefix@,$program_prefix,;t t
s,@VERSION@,$VERSION,;t t
s,@RELEASE@,$RELEASE,;t t
@@ -21031,13 +21384,15 @@ s,@TARGET_RANLIB@,$TARGET_RANLIB,;t t
s,@TARGET_AR@,$TARGET_AR,;t t
s,@THREADSAFE@,$THREADSAFE,;t t
s,@TARGET_THREAD_LIB@,$TARGET_THREAD_LIB,;t t
+s,@XTHREADCONNECT@,$XTHREADCONNECT,;t t
+s,@THREADSOVERRIDELOCKS@,$THREADSOVERRIDELOCKS,;t t
s,@ALLOWRELEASE@,$ALLOWRELEASE,;t t
s,@TEMP_STORE@,$TEMP_STORE,;t t
s,@BUILD_EXEEXT@,$BUILD_EXEEXT,;t t
s,@OS_UNIX@,$OS_UNIX,;t t
s,@OS_WIN@,$OS_WIN,;t t
+s,@OS_OS2@,$OS_OS2,;t t
s,@TARGET_EXEEXT@,$TARGET_EXEEXT,;t t
-s,@TARGET_LIBS@,$TARGET_LIBS,;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
@@ -21054,6 +21409,7 @@ 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,@TARGET_LIBS@,$TARGET_LIBS,;t t
s,@LIBOBJS@,$LIBOBJS,;t t
s,@LTLIBOBJS@,$LTLIBOBJS,;t t
CEOF
diff --git a/ext/pdo_sqlite/sqlite/configure.ac b/ext/pdo_sqlite/sqlite/configure.ac
index 3682bf8210..cfec34ab36 100644
--- a/ext/pdo_sqlite/sqlite/configure.ac
+++ b/ext/pdo_sqlite/sqlite/configure.ac
@@ -123,6 +123,7 @@ dnl show in in configure.
#
AC_PROG_LIBTOOL
AC_PROG_INSTALL
+AC_PROG_AWK
#########
# Set up an appropriate program prefix
@@ -152,7 +153,7 @@ AC_SUBST(VERSION_NUMBER)
# $system is the result of uname -s.
#
AC_ARG_WITH(hints,
- [ --with-hints=FILE Read configuration options from FILE],
+ AC_HELP_STRING([--with-hints=FILE],[Read configuration options from FILE]),
hints=$withval)
if test "$hints" = ""; then
host=`hostname | sed 's/\..*//'`
@@ -278,7 +279,7 @@ fi
# Do we want to support multithreaded use of sqlite
#
AC_ARG_ENABLE(threadsafe,
-[ --enable-threadsafe Support threadsafe operation],,enable_threadsafe=no)
+AC_HELP_STRING([--enable-threadsafe],[Support threadsafe operation]),,enable_threadsafe=no)
AC_MSG_CHECKING([whether to support threadsafe operation])
if test "$enable_threadsafe" = "no"; then
THREADSAFE=0
@@ -300,10 +301,45 @@ fi
AC_SUBST(TARGET_THREAD_LIB)
##########
+# Do we want to allow a connection created in one thread to be used
+# in another thread. This does not work on many Linux systems (ex: RedHat 9)
+# due to bugs in the threading implementations. This is thus off by default.
+#
+AC_ARG_ENABLE(cross-thread-connections,
+AC_HELP_STRING([--enable-cross-thread-connections],[Allow connection sharing across threads]),,enable_xthreadconnect=no)
+AC_MSG_CHECKING([whether to allow connections to be shared across threads])
+if test "$enable_xthreadconnect" = "no"; then
+ XTHREADCONNECT=''
+ AC_MSG_RESULT([no])
+else
+ XTHREADCONNECT='-DSQLITE_ALLOW_XTHREAD_CONNECT=1'
+ AC_MSG_RESULT([yes])
+fi
+AC_SUBST(XTHREADCONNECT)
+
+##########
+# Do we want to set threadsOverrideEachOthersLocks variable to be 1 (true) by
+# default. Normally, a test at runtime is performed to determine the
+# appropriate value of this variable. Use this option only if you're sure that
+# threads can safely override each others locks in all runtime situations.
+#
+AC_ARG_ENABLE(threads-override-locks,
+AC_HELP_STRING([--enable-threads-override-locks],[Threads can override each others locks]),,enable_threads_override_locks=no)
+AC_MSG_CHECKING([whether threads can override each others locks])
+if test "$enable_threads_override_locks" = "no"; then
+ THREADSOVERRIDELOCKS='-1'
+ AC_MSG_RESULT([no])
+else
+ THREADSOVERRIDELOCKS='1'
+ AC_MSG_RESULT([yes])
+fi
+AC_SUBST(THREADSOVERRIDELOCKS)
+
+##########
# Do we want to support release
#
AC_ARG_ENABLE(releasemode,
-[ --enable-releasemode Support libtool link to release mode],,enable_releasemode=no)
+AC_HELP_STRING([--enable-releasemode],[Support libtool link to release mode]),,enable_releasemode=no)
AC_MSG_CHECKING([whether to support shared library linked as release mode or not])
if test "$enable_releasemode" = "no"; then
ALLOWRELEASE=""
@@ -318,7 +354,7 @@ AC_SUBST(ALLOWRELEASE)
# Do we want temporary databases in memory
#
AC_ARG_ENABLE(tempstore,
-[ --enable-tempstore Use an in-ram database for temporary tables (never,no,yes,always)],,enable_tempstore=yes)
+AC_HELP_STRING([--enable-tempstore],[Use an in-ram database for temporary tables (never,no,yes,always)]),,enable_tempstore=no)
AC_MSG_CHECKING([whether to use an in-ram database for temporary tables])
case "$enable_tempstore" in
never )
@@ -333,8 +369,12 @@ case "$enable_tempstore" in
TEMP_STORE=3
AC_MSG_RESULT([always])
;;
+ yes )
+ TEMP_STORE=3
+ AC_MSG_RESULT([always])
+ ;;
* )
- TEMP_STORE=2
+ TEMP_STORE=1
AC_MSG_RESULT([yes])
;;
esac
@@ -367,13 +407,26 @@ else
TARGET_EXEEXT=$config_TARGET_EXEEXT
fi
if test "$TARGET_EXEEXT" = ".exe"; then
- OS_UNIX=0
- OS_WIN=1
- tclsubdir=win
- TARGET_CFLAGS="$TARGET_CFLAGS -DOS_WIN=1"
+ if test $OS2_SHELL ; then
+ OS_UNIX=0
+ OS_WIN=0
+ OS_OS2=1
+ TARGET_CFLAGS="$TARGET_CFLAGS -DOS_OS2=1"
+ if test "$ac_compiler_gnu" == "yes" ; then
+ TARGET_CFLAGS="$TARGET_CFLAGS -Zomf -Zexe -Zmap"
+ BUILD_CFLAGS="$BUILD_CFLAGS -Zomf -Zexe"
+ fi
+ else
+ OS_UNIX=0
+ OS_WIN=1
+ OS_OS2=0
+ tclsubdir=win
+ TARGET_CFLAGS="$TARGET_CFLAGS -DOS_WIN=1"
+ fi
else
OS_UNIX=1
OS_WIN=0
+ OS_OS2=0
tclsubdir=unix
TARGET_CFLAGS="$TARGET_CFLAGS -DOS_UNIX=1"
fi
@@ -381,6 +434,7 @@ fi
AC_SUBST(BUILD_EXEEXT)
AC_SUBST(OS_UNIX)
AC_SUBST(OS_WIN)
+AC_SUBST(OS_OS2)
AC_SUBST(TARGET_EXEEXT)
##########
@@ -391,7 +445,6 @@ if test "$config_TARGET_LIBS" != ""; then
else
TARGET_LIBS=""
fi
-AC_SUBST(TARGET_LIBS)
##########
# Figure out all the parameters needed to compile against Tcl.
@@ -401,10 +454,10 @@ AC_SUBST(TARGET_LIBS)
# 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_ARG_ENABLE(tcl, [ --disable-tcl do not build TCL extension],
+AC_ARG_ENABLE(tcl, AC_HELP_STRING([--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_ARG_WITH(tcl, AC_HELP_STRING([--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.
@@ -551,6 +604,15 @@ fi
AC_SUBST(TARGET_READLINE_LIBS)
##########
+# Figure out what C libraries are required to compile programs
+# that use "fdatasync()" function.
+#
+CC=$TARGET_CC
+LIBS=$TARGET_LIBS
+AC_SEARCH_LIBS(fdatasync, [rt])
+TARGET_LIBS="$LIBS"
+
+##########
# Figure out where to get the READLINE header files.
#
AC_MSG_CHECKING([readline header files])
@@ -593,10 +655,10 @@ AC_SUBST(TARGET_HAVE_READLINE)
#########
# check for debug enabled
-AC_ARG_ENABLE(debug, [ --enable-debug enable debugging & verbose explain],
+AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],[enable debugging & verbose explain]),
[use_debug=$enableval],[use_debug=no])
if test "${use_debug}" = "yes" ; then
- TARGET_DEBUG=""
+ TARGET_DEBUG="-DSQLITE_DEBUG=1"
else
TARGET_DEBUG="-DNDEBUG"
fi
@@ -607,6 +669,17 @@ AC_SUBST(TARGET_DEBUG)
#
AC_CHECK_FUNC(usleep, [TARGET_CFLAGS="$TARGET_CFLAGS -DHAVE_USLEEP=1"])
+#--------------------------------------------------------------------
+# Redefine fdatasync as fsync on systems that lack fdatasync
+#--------------------------------------------------------------------
+
+AC_CHECK_FUNC(fdatasync, [TARGET_CFLAGS="$TARGET_CFLAGS -DHAVE_FDATASYNC=1"])
+
+#########
+# Put out accumulated miscellaneous LIBRARIES
+#
+AC_SUBST(TARGET_LIBS)
+
#########
# Generate the output files.
#
diff --git a/ext/pdo_sqlite/sqlite/main.mk b/ext/pdo_sqlite/sqlite/main.mk
index d931e281ae..2653815457 100644
--- a/ext/pdo_sqlite/sqlite/main.mk
+++ b/ext/pdo_sqlite/sqlite/main.mk
@@ -42,7 +42,8 @@
# LIBREADLINE Linker options needed by programs using readline() must
# link against.
#
-# ENCODING "UTF8" or "ISO8859"
+# NAWK Nawk compatible awk program. Older (obsolete?) solaris
+# systems need this to avoid using the original AT&T AWK.
#
# Once the macros above are defined, the rest of this make script will
# build the SQLite library and testing tools.
@@ -56,13 +57,13 @@ TCCX = $(TCC) $(OPTS) $(THREADSAFE) $(USLEEP) -I. -I$(TOP)/src
#
LIBOBJ+= alter.o analyze.o attach.o auth.o btree.o build.o \
callback.o complete.o date.o delete.o \
- expr.o func.o hash.o insert.o \
- main.o opcodes.o os_unix.o os_win.o \
+ expr.o func.o hash.o insert.o loadext.o \
+ main.o opcodes.o os.o os_os2.o os_unix.o os_win.o \
pager.o parse.o pragma.o prepare.o printf.o random.o \
select.o table.o tclsqlite.o tokenize.o trigger.o \
update.o util.o vacuum.o \
vdbe.o vdbeapi.o vdbeaux.o vdbefifo.o vdbemem.o \
- where.o utf.o legacy.o
+ where.o utf.o legacy.o vtab.o
# All of the source code files.
#
@@ -84,7 +85,10 @@ SRC = \
$(TOP)/src/hash.h \
$(TOP)/src/insert.c \
$(TOP)/src/legacy.c \
+ $(TOP)/src/loadext.c \
$(TOP)/src/main.c \
+ $(TOP)/src/os.c \
+ $(TOP)/src/os_os2.c \
$(TOP)/src/os_unix.c \
$(TOP)/src/os_win.c \
$(TOP)/src/pager.c \
@@ -113,6 +117,7 @@ SRC = \
$(TOP)/src/vdbefifo.c \
$(TOP)/src/vdbemem.c \
$(TOP)/src/vdbeInt.h \
+ $(TOP)/src/vtab.c \
$(TOP)/src/where.c
# Source code to the test files.
@@ -121,6 +126,8 @@ TESTSRC = \
$(TOP)/src/btree.c \
$(TOP)/src/date.c \
$(TOP)/src/func.c \
+ $(TOP)/src/os.c \
+ $(TOP)/src/os_os2.c \
$(TOP)/src/os_unix.c \
$(TOP)/src/os_win.c \
$(TOP)/src/pager.c \
@@ -131,10 +138,17 @@ TESTSRC = \
$(TOP)/src/test3.c \
$(TOP)/src/test4.c \
$(TOP)/src/test5.c \
+ $(TOP)/src/test6.c \
+ $(TOP)/src/test7.c \
+ $(TOP)/src/test8.c \
+ $(TOP)/src/test_async.c \
+ $(TOP)/src/test_md5.c \
+ $(TOP)/src/test_schema.c \
+ $(TOP)/src/test_server.c \
+ $(TOP)/src/test_tclvar.c \
$(TOP)/src/utf.c \
$(TOP)/src/util.c \
$(TOP)/src/vdbe.c \
- $(TOP)/src/md5.c \
$(TOP)/src/where.c
# Header files used by all library source files.
@@ -146,8 +160,7 @@ HDR = \
opcodes.h \
$(TOP)/src/os.h \
$(TOP)/src/os_common.h \
- $(TOP)/src/os_unix.h \
- $(TOP)/src/os_win.h \
+ $(TOP)/src/sqlite3ext.h \
$(TOP)/src/sqliteInt.h \
$(TOP)/src/vdbe.h \
parse.h
@@ -167,8 +180,8 @@ all: sqlite3.h libsqlite3.a sqlite3$(EXE)
# of the most recently modified source code file
#
last_change: $(SRC)
- cat $(SRC) | grep '$$Id: ' | sort +4 | tail -1 \
- | awk '{print $$5,$$6}' >last_change
+ cat $(SRC) | grep '$$Id: ' | sort -k 5 | tail -1 \
+ | $(NAWK) '{print $$5,$$6}' >last_change
libsqlite3.a: $(LIBOBJ)
$(AR) libsqlite3.a $(LIBOBJ)
@@ -176,7 +189,7 @@ libsqlite3.a: $(LIBOBJ)
sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h
$(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) $(TOP)/src/shell.c \
- libsqlite3.a $(LIBREADLINE) $(THREADLIB)
+ libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
objects: $(LIBOBJ_ORIG)
@@ -247,6 +260,9 @@ insert.o: $(TOP)/src/insert.c $(HDR)
legacy.o: $(TOP)/src/legacy.c $(HDR)
$(TCCX) -c $(TOP)/src/legacy.c
+loadext.o: $(TOP)/src/loadext.c $(HDR)
+ $(TCCX) -c $(TOP)/src/loadext.c
+
main.o: $(TOP)/src/main.c $(HDR)
$(TCCX) -c $(TOP)/src/main.c
@@ -257,10 +273,16 @@ opcodes.o: opcodes.c
$(TCCX) -c opcodes.c
opcodes.c: opcodes.h $(TOP)/mkopcodec.awk
- sort -n -b +2 opcodes.h | awk -f $(TOP)/mkopcodec.awk >opcodes.c
+ sort -n -b -k 3 opcodes.h | $(NAWK) -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
+ cat parse.h $(TOP)/src/vdbe.c | $(NAWK) -f $(TOP)/mkopcodeh.awk >opcodes.h
+
+os.o: $(TOP)/src/os.c $(HDR)
+ $(TCCX) -c $(TOP)/src/os.c
+
+os_os2.o: $(TOP)/src/os_os2.c $(HDR)
+ $(TCCX) -c $(TOP)/src/os_os2.c
os_unix.o: $(TOP)/src/os_unix.c $(HDR)
$(TCCX) -c $(TOP)/src/os_unix.c
@@ -273,9 +295,11 @@ parse.o: parse.c $(HDR)
parse.h: parse.c
-parse.c: $(TOP)/src/parse.y lemon
+parse.c: $(TOP)/src/parse.y lemon $(TOP)/addopcodes.awk
cp $(TOP)/src/parse.y .
./lemon $(OPTS) parse.y
+ mv parse.h parse.h.temp
+ awk -f $(TOP)/addopcodes.awk parse.h.temp >parse.h
pragma.o: $(TOP)/src/pragma.c $(HDR)
$(TCCX) $(TCL_FLAGS) -c $(TOP)/src/pragma.c
@@ -294,7 +318,7 @@ select.o: $(TOP)/src/select.c $(HDR)
sqlite3.h: $(TOP)/src/sqlite.h.in
sed -e s/--VERS--/`cat ${TOP}/VERSION`/ \
- -e s/--VERSION-NUMBER--/`cat ${TOP}/VERSION | sed 's/[^0-9]/ /g' | awk '{printf "%d%03d%03d",$$1,$$2,$$3}'`/ \
+ -e s/--VERSION-NUMBER--/`cat ${TOP}/VERSION | sed 's/[^0-9]/ /g' | $(NAWK) '{printf "%d%03d%03d",$$1,$$2,$$3}'`/ \
$(TOP)/src/sqlite.h.in >sqlite3.h
table.o: $(TOP)/src/table.c $(HDR)
@@ -340,6 +364,9 @@ vdbefifo.o: $(TOP)/src/vdbefifo.c $(VDBEHDR)
vdbemem.o: $(TOP)/src/vdbemem.c $(VDBEHDR)
$(TCCX) -c $(TOP)/src/vdbemem.c
+vtab.o: $(TOP)/src/vtab.c $(VDBEHDR)
+ $(TCCX) -c $(TOP)/src/vtab.c
+
where.o: $(TOP)/src/where.c $(HDR)
$(TCCX) -c $(TOP)/src/where.c
@@ -350,17 +377,12 @@ tclsqlite3: $(TOP)/src/tclsqlite.c libsqlite3.a
$(TOP)/src/tclsqlite.c libsqlite3.a $(LIBTCL) $(THREADLIB)
testfixture$(EXE): $(TOP)/src/tclsqlite.c libsqlite3.a $(TESTSRC)
- $(TCCX) $(TCL_FLAGS) -DTCLSH=1 -DSQLITE_TEST=1 -o testfixture$(EXE) \
+ $(TCCX) $(TCL_FLAGS) -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 \
+ -DSQLITE_SERVER=1 -o testfixture$(EXE) \
$(TESTSRC) $(TOP)/src/tclsqlite.c \
libsqlite3.a $(LIBTCL) $(THREADLIB)
-crashtest: $(TOP)/src/tclsqlite.c libsqlite3.a $(TESTSRC) $(TOP)/src/os_test.c
- $(TCCX) $(TCL_FLAGS) -DOS_TEST=1 -DTCLSH=1 -DSQLITE_TEST=1 \
- -o crashtest \
- $(TESTSRC) $(TOP)/src/os_test.c $(TOP)/src/tclsqlite.c \
- libsqlite3.a $(LIBTCL) $(THREADLIB)
-
-fulltest: testfixture$(EXE) sqlite3$(EXE) crashtest
+fulltest: testfixture$(EXE) sqlite3$(EXE)
./testfixture$(EXE) $(TOP)/test/all.test
test: testfixture$(EXE) sqlite3$(EXE)
@@ -375,10 +397,17 @@ 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 -o \
+ $(TCCX) $(TCL_FLAGS) -DTCLSH=2 -DSQLITE_TEST=1 -DSQLITE_DEBUG=1 -o \
sqlite3_analyzer$(EXE) $(TESTSRC) $(TOP)/src/tclsqlite.c \
libsqlite3.a $(LIBTCL) $(THREADLIB)
+TEST_EXTENSION = $(SHPREFIX)testloadext.$(SO)
+$(TEST_EXTENSION): $(TOP)/src/test_loadext.c
+ $(MKSHLIB) $(TOP)/src/test_loadext.c -o $(TEST_EXTENSION)
+
+extensiontest: testfixture$(EXE) $(TEST_EXTENSION)
+ ./testfixture$(EXE) $(TOP)/test/loadext.test
+
# Rules used to build documentation
#
arch.html: $(TOP)/www/arch.tcl
@@ -469,6 +498,9 @@ omitted.html: $(TOP)/www/omitted.tcl
opcode.html: $(TOP)/www/opcode.tcl $(TOP)/src/vdbe.c
tclsh $(TOP)/www/opcode.tcl $(TOP)/src/vdbe.c >opcode.html
+sharedcache.html: $(TOP)/www/sharedcache.tcl
+ tclsh $(TOP)/www/sharedcache.tcl >sharedcache.html
+
mingw.html: $(TOP)/www/mingw.tcl
tclsh $(TOP)/www/mingw.tcl >mingw.html
@@ -537,6 +569,7 @@ DOC = \
opcode.html \
pragma.html \
quickstart.html \
+ sharedcache.html \
speed.html \
sqlite.gif \
sqlite.html \
@@ -558,7 +591,7 @@ install: sqlite3 libsqlite3.a sqlite3.h
mv sqlite3.h /usr/include
clean:
- rm -f *.o sqlite3 libsqlite3.a sqlite3.h opcodes.* crashtest
+ rm -f *.o sqlite3 libsqlite3.a sqlite3.h opcodes.*
rm -f lemon lempar.c parse.* sqlite*.tar.gz mkkeywordhash keywordhash.h
rm -f $(PUBLISH)
rm -f *.da *.bb *.bbg gmon.out
diff --git a/ext/pdo_sqlite/sqlite/mkdll.sh b/ext/pdo_sqlite/sqlite/mkdll.sh
index 1ad5f83326..50dd60b711 100644
--- a/ext/pdo_sqlite/sqlite/mkdll.sh
+++ b/ext/pdo_sqlite/sqlite/mkdll.sh
@@ -11,7 +11,7 @@ cd tsrc
PATH=$PATH:/opt/mingw/bin
TCLDIR=/home/drh/tcltk/846/win/846win
TCLSTUBLIB=$TCLDIR/libtcl84stub.a
-OPTS='-DUSE_TCL_STUBS=1 -DNDEBUG=1 -DTHREADSAFE=1'
+OPTS='-DUSE_TCL_STUBS=1 -DNDEBUG=1 -DTHREADSAFE=1 -DBUILD_sqlite=1'
CC="i386-mingw32msvc-gcc -O2 $OPTS -I. -I$TCLDIR"
rm shell.c
for i in *.c; do
@@ -31,7 +31,7 @@ i386-mingw32msvc-dllwrap \
--as i386-mingw32msvc-as \
--target i386-mingw32 \
-dllname tclsqlite3.dll -lmsvcrt *.o $TCLSTUBLIB
-i386-mingw32msvc-strip tclsqlite3.dll
+#i386-mingw32msvc-strip tclsqlite3.dll
rm tclsqlite.o
i386-mingw32msvc-dllwrap \
--def sqlite3.def -v --export-all \
@@ -40,5 +40,5 @@ i386-mingw32msvc-dllwrap \
--as i386-mingw32msvc-as \
--target i386-mingw32 \
-dllname sqlite3.dll -lmsvcrt *.o
-i386-mingw32msvc-strip sqlite3.dll
+#i386-mingw32msvc-strip sqlite3.dll
cd ..
diff --git a/ext/pdo_sqlite/sqlite/mkopcodeh.awk b/ext/pdo_sqlite/sqlite/mkopcodeh.awk
index a258194ca8..0fa50ead09 100644
--- a/ext/pdo_sqlite/sqlite/mkopcodeh.awk
+++ b/ext/pdo_sqlite/sqlite/mkopcodeh.awk
@@ -14,14 +14,28 @@
# 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
+# We go to the trouble of making some OP_ values 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 to translate from one to the other is avoided. This makes the
# code generator run (infinitesimally) faster and more importantly it makes
-# the total library smaller.
+# the library footprint smaller.
+#
+# This script also scans for lines of the form:
+#
+# case OP_aaaa: /* no-push */
+#
+# When the no-push comment is found on an opcode, it means that that
+# opcode does not leave a result on the stack. By identifying which
+# opcodes leave results on the stack it is possible to determine a
+# much smaller upper bound on the size of the stack. This allows
+# a smaller stack to be allocated, which is important to embedded
+# systems with limited memory space. This script generates a series
+# of "NOPUSH_MASK" defines that contain bitmaps of opcodes that leave
+# results on the stack. The NOPUSH_MASK defines are used in vdbeaux.c
+# to help determine the maximum stack size.
#
@@ -104,7 +118,10 @@ END {
}
}
printf "\n"
+ print "/* Opcodes that are guaranteed to never push a value onto the stack"
+ print "** contain a 1 their corresponding position of the following mask"
+ print "** set. See the opcodeNoPush() function in vdbeaux.c */"
for(i=0; i<10; i++){
- printf "#define NOPUSH_MASK_%d %d\n", i, nopush[i]
+ printf "#define NOPUSH_MASK_%d 0x%04x\n", i, nopush[i]
}
}
diff --git a/ext/pdo_sqlite/sqlite/publish.sh b/ext/pdo_sqlite/sqlite/publish.sh
index 0a61d90ed2..043c89a039 100644
--- a/ext/pdo_sqlite/sqlite/publish.sh
+++ b/ext/pdo_sqlite/sqlite/publish.sh
@@ -113,3 +113,5 @@ mv $HOME/rpm/SRPMS/sqlite-$vers*.rpm doc
#
#cp $srcdir/../historical/* doc
make doc
+cd doc
+chmod 644 *.gz
diff --git a/ext/pdo_sqlite/sqlite/sqlite3.def b/ext/pdo_sqlite/sqlite/sqlite3.def
index c57ca68973..e42a0cd3d6 100644
--- a/ext/pdo_sqlite/sqlite/sqlite3.def
+++ b/ext/pdo_sqlite/sqlite/sqlite3.def
@@ -40,6 +40,7 @@ sqlite3_create_function
sqlite3_create_function16
sqlite3_data_count
sqlite3_db_handle
+sqlite3_enable_shared_cache
sqlite3_errcode
sqlite3_errmsg
sqlite3_errmsg16
@@ -75,13 +76,16 @@ sqlite3_result_text16
sqlite3_result_text16be
sqlite3_result_text16le
sqlite3_result_value
+sqlite3_rollback_hook
sqlite3_set_authorizer
sqlite3_set_auxdata
sqlite3_snprintf
sqlite3_step
+sqlite3_thread_cleanup
sqlite3_total_changes
sqlite3_trace
sqlite3_transfer_bindings
+sqlite3_update_hook
sqlite3_user_data
sqlite3_value_blob
sqlite3_value_bytes
diff --git a/ext/pdo_sqlite/sqlite/src/alter.c b/ext/pdo_sqlite/sqlite/src/alter.c
index ada0769b5d..0d6bfbf9dc 100644
--- a/ext/pdo_sqlite/sqlite/src/alter.c
+++ b/ext/pdo_sqlite/sqlite/src/alter.c
@@ -47,7 +47,7 @@ static void renameTableFunc(
int token;
Token tname;
- char const *zCsr = zSql;
+ unsigned char const *zCsr = zSql;
int len = 0;
char *zRet;
@@ -96,7 +96,7 @@ static void renameTriggerFunc(
int token;
Token tname;
int dist = 3;
- char const *zCsr = zSql;
+ unsigned char const *zCsr = zSql;
int len = 0;
char *zRet;
@@ -162,7 +162,7 @@ void sqlite3AlterFunctions(sqlite3 *db){
int i;
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
- sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
+ sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
}
}
@@ -177,9 +177,16 @@ static char *whereTempTriggers(Parse *pParse, Table *pTab){
Trigger *pTrig;
char *zWhere = 0;
char *tmp = 0;
- if( pTab->iDb!=1 ){
+ const Schema *pTempSchema = pParse->db->aDb[1].pSchema; /* Temp db schema */
+
+ /* If the table is not located in the temp-db (in which case NULL is
+ ** returned, loop through the tables list of triggers. For each trigger
+ ** that is not part of the temp-db schema, add a clause to the WHERE
+ ** expression being built up in zWhere.
+ */
+ if( pTab->pSchema!=pTempSchema ){
for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
- if( pTrig->iDb==1 ){
+ if( pTrig->pSchema==pTempSchema ){
if( !zWhere ){
zWhere = sqlite3MPrintf("name=%Q", pTrig->name);
}else{
@@ -204,20 +211,22 @@ static char *whereTempTriggers(Parse *pParse, Table *pTab){
static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
Vdbe *v;
char *zWhere;
- int iDb;
+ int iDb; /* Index of database containing pTab */
#ifndef SQLITE_OMIT_TRIGGER
Trigger *pTrig;
#endif
v = sqlite3GetVdbe(pParse);
if( !v ) return;
- iDb = pTab->iDb;
+ iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ assert( iDb>=0 );
#ifndef SQLITE_OMIT_TRIGGER
/* Drop any table triggers from the internal schema. */
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);
+ int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
+ assert( iTrigDb==iDb || iTrigDb==1 );
+ sqlite3VdbeOp3(v, OP_DropTrigger, iTrigDb, 0, pTrig->name, 0);
}
#endif
@@ -233,7 +242,7 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
/* Now, if the table is not stored in the temp database, reload any temp
** triggers. Don't use IN(...) in case SQLITE_OMIT_SUBQUERY is defined.
*/
- if( (zWhere=whereTempTriggers(pParse, pTab)) ){
+ if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){
sqlite3VdbeOp3(v, OP_ParseSchema, 1, 0, zWhere, P3_DYNAMIC);
}
#endif
@@ -258,12 +267,18 @@ void sqlite3AlterRenameTable(
char *zWhere = 0; /* Where clause to locate temp triggers */
#endif
- if( sqlite3_malloc_failed ) goto exit_rename_table;
+ if( sqlite3MallocFailed() ) goto exit_rename_table;
assert( pSrc->nSrc==1 );
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
if( !pTab ) goto exit_rename_table;
- iDb = pTab->iDb;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTab) ){
+ sqlite3ErrorMsg(pParse, "virtual tables may not be altered");
+ goto exit_rename_table;
+ }
+#endif
+ iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
zDb = db->aDb[iDb].zName;
/* Get a NULL terminated version of the new table name. */
@@ -349,7 +364,7 @@ void sqlite3AlterRenameTable(
** table. Don't do this if the table being ALTERed is itself located in
** the temp database.
*/
- if( (zWhere=whereTempTriggers(pParse, pTab)) ){
+ if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){
sqlite3NestedParse(pParse,
"UPDATE sqlite_temp_master SET "
"sql = sqlite_rename_trigger(sql, %Q), "
@@ -385,13 +400,12 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
char *zCol; /* Null-terminated column definition */
Column *pCol; /* The new column */
Expr *pDflt; /* Default value for the new column */
- Vdbe *v;
if( pParse->nErr ) return;
pNew = pParse->pNewTable;
assert( pNew );
- iDb = pNew->iDb;
+ iDb = sqlite3SchemaToIndex(pParse->db, pNew->pSchema);
zDb = pParse->db->aDb[iDb].zName;
zTab = pNew->zName;
pCol = &pNew->aCol[pNew->nCol-1];
@@ -399,6 +413,13 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
pTab = sqlite3FindTable(pParse->db, zTab, zDb);
assert( pTab );
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ /* Invoke the authorization callback. */
+ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){
+ return;
+ }
+#endif
+
/* If the default value for the new column was specified with a
** literal NULL, then set pDflt to 0. This simplifies checking
** for an SQL NULL default below.
@@ -442,7 +463,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
}
/* Modify the CREATE TABLE statement. */
- zCol = sqliteStrNDup(pColDef->z, pColDef->n);
+ zCol = sqliteStrNDup((char*)pColDef->z, pColDef->n);
if( zCol ){
char *zEnd = &zCol[pColDef->n-1];
while( (zEnd>zCol && *zEnd==';') || isspace(*(unsigned char *)zEnd) ){
@@ -462,22 +483,12 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
** format to 2. If the default value of the new column is not NULL,
** the file format becomes 3.
*/
- if( (v=sqlite3GetVdbe(pParse)) ){
- int f = (pDflt?3:2);
-
- /* Only set the file format to $f if it is currently less than $f. */
- sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1);
- sqlite3VdbeAddOp(v, OP_Integer, f, 0);
- sqlite3VdbeAddOp(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Integer, f, 0);
- sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
- }
+ sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2);
/* Reload the schema of the modified table. */
reloadTableSchema(pParse, pTab, pTab->zName);
}
-
/*
** This function is called by the parser after the table-name in
** an "ALTER TABLE <table-name> ADD" statement is parsed. Argument
@@ -501,13 +512,19 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
int i;
int nAlloc;
-
/* Look up the table being altered. */
assert( pParse->pNewTable==0 );
- if( sqlite3_malloc_failed ) goto exit_begin_add_column;
+ if( sqlite3MallocFailed() ) goto exit_begin_add_column;
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
if( !pTab ) goto exit_begin_add_column;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTab) ){
+ sqlite3ErrorMsg(pParse, "virtual tables may not be altered");
+ goto exit_begin_add_column;
+ }
+#endif
+
/* Make sure this is not an attempt to ALTER a view. */
if( pTab->pSelect ){
sqlite3ErrorMsg(pParse, "Cannot add a column to a view");
@@ -515,7 +532,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
}
assert( pTab->addColOffset>0 );
- iDb = pTab->iDb;
+ iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
/* Put a copy of the Table struct in Parse.pNewTable for the
** sqlite3AddColumn() function and friends to modify.
@@ -537,10 +554,11 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
for(i=0; i<pNew->nCol; i++){
Column *pCol = &pNew->aCol[i];
pCol->zName = sqliteStrDup(pCol->zName);
+ pCol->zColl = 0;
pCol->zType = 0;
pCol->pDflt = 0;
}
- pNew->iDb = iDb;
+ pNew->pSchema = pParse->db->aDb[iDb].pSchema;
pNew->addColOffset = pTab->addColOffset;
pNew->nRef = 1;
diff --git a/ext/pdo_sqlite/sqlite/src/analyze.c b/ext/pdo_sqlite/sqlite/src/analyze.c
index a6c92e9f6f..dc1f33286d 100644
--- a/ext/pdo_sqlite/sqlite/src/analyze.c
+++ b/ext/pdo_sqlite/sqlite/src/analyze.c
@@ -61,8 +61,14 @@ static void openStatTable(
sqlite3VdbeAddOp(v, OP_Clear, pStat->tnum, iDb);
}
- /* Open the sqlite_stat1 table for writing.
+ /* Open the sqlite_stat1 table for writing. Unless it was created
+ ** by this vdbe program, lock it for writing at the shared-cache level.
+ ** If this vdbe did create the sqlite_stat1 table, then it must have
+ ** already obtained a schema-lock, making the write-lock redundant.
*/
+ if( iRootPage>0 ){
+ sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1");
+ }
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
sqlite3VdbeAddOp(v, OP_OpenWrite, iStatCur, iRootPage);
sqlite3VdbeAddOp(v, OP_SetNumColumns, iStatCur, 3);
@@ -86,6 +92,7 @@ static void analyzeOneTable(
int topOfLoop; /* The top of the loop */
int endOfLoop; /* The end of the loop */
int addr; /* The address of an instruction */
+ int iDb; /* Index of database containing pTab */
v = sqlite3GetVdbe(pParse);
if( pTab==0 || pTab->pIndex==0 ){
@@ -93,21 +100,29 @@ static void analyzeOneTable(
return;
}
+ iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ assert( iDb>=0 );
#ifndef SQLITE_OMIT_AUTHORIZATION
if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0,
- pParse->db->aDb[pTab->iDb].zName ) ){
+ pParse->db->aDb[iDb].zName ) ){
return;
}
#endif
+ /* Establish a read-lock on the table at the shared-cache level. */
+ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
+
iIdxCur = pParse->nTab;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
+
/* Open a cursor to the index to be analyzed
*/
- sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
+ assert( iDb==sqlite3SchemaToIndex(pParse->db, pIdx->pSchema) );
+ sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
VdbeComment((v, "# %s", pIdx->zName));
sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum,
- (char*)&pIdx->keyInfo, P3_KEYINFO);
+ (char *)pKey, P3_KEYINFO_HANDOFF);
nCol = pIdx->nColumn;
if( iMem+nCol*2>=pParse->nMem ){
pParse->nMem = iMem+nCol*2+1;
@@ -139,7 +154,7 @@ static void analyzeOneTable(
endOfLoop = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp(v, OP_Rewind, iIdxCur, endOfLoop);
topOfLoop = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeAddOp(v, OP_MemIncr, iMem, 0);
+ sqlite3VdbeAddOp(v, OP_MemIncr, 1, iMem);
for(i=0; i<nCol; i++){
sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i);
sqlite3VdbeAddOp(v, OP_MemLoad, iMem+nCol+i+1, 0);
@@ -147,7 +162,7 @@ static void analyzeOneTable(
}
sqlite3VdbeAddOp(v, OP_Goto, 0, endOfLoop);
for(i=0; i<nCol; i++){
- addr = sqlite3VdbeAddOp(v, OP_MemIncr, iMem+i+1, 0);
+ addr = sqlite3VdbeAddOp(v, OP_MemIncr, 1, iMem+i+1);
sqlite3VdbeChangeP2(v, topOfLoop + 3*i + 3, addr);
sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i);
sqlite3VdbeAddOp(v, OP_MemStore, iMem+nCol+i+1, 1);
@@ -188,13 +203,14 @@ static void analyzeOneTable(
sqlite3VdbeAddOp(v, OP_AddImm, -1, 0);
sqlite3VdbeAddOp(v, OP_MemLoad, iMem+i+1, 0);
sqlite3VdbeAddOp(v, OP_Divide, 0, 0);
+ sqlite3VdbeAddOp(v, OP_ToInt, 0, 0);
if( i==nCol-1 ){
sqlite3VdbeAddOp(v, OP_Concat, nCol*2-1, 0);
}else{
sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
}
}
- sqlite3VdbeOp3(v, OP_MakeRecord, 3, 0, "ttt", 0);
+ sqlite3VdbeOp3(v, OP_MakeRecord, 3, 0, "aaa", 0);
sqlite3VdbeAddOp(v, OP_Insert, iStatCur, 0);
sqlite3VdbeJumpHere(v, addr);
}
@@ -214,6 +230,7 @@ static void loadAnalysis(Parse *pParse, int iDb){
*/
static void analyzeDatabase(Parse *pParse, int iDb){
sqlite3 *db = pParse->db;
+ Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */
HashElem *k;
int iStatCur;
int iMem;
@@ -222,7 +239,7 @@ static void analyzeDatabase(Parse *pParse, int iDb){
iStatCur = pParse->nTab++;
openStatTable(pParse, iDb, iStatCur, 0);
iMem = pParse->nMem;
- for(k=sqliteHashFirst(&db->aDb[iDb].tblHash); k; k=sqliteHashNext(k)){
+ for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
Table *pTab = (Table*)sqliteHashData(k);
analyzeOneTable(pParse, pTab, iStatCur, iMem);
}
@@ -238,7 +255,7 @@ static void analyzeTable(Parse *pParse, Table *pTab){
int iStatCur;
assert( pTab!=0 );
- iDb = pTab->iDb;
+ iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
sqlite3BeginWriteOperation(pParse, 0, iDb);
iStatCur = pParse->nTab++;
openStatTable(pParse, iDb, iStatCur, pTab->zName);
@@ -360,7 +377,7 @@ void sqlite3AnalysisLoad(sqlite3 *db, int iDb){
char *zSql;
/* Clear any prior statistics */
- for(i=sqliteHashFirst(&db->aDb[iDb].idxHash); i; i=sqliteHashNext(i)){
+ for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i);
sqlite3DefaultRowEst(pIdx);
}
diff --git a/ext/pdo_sqlite/sqlite/src/attach.c b/ext/pdo_sqlite/sqlite/src/attach.c
index 46b653e975..10abc49014 100644
--- a/ext/pdo_sqlite/sqlite/src/attach.c
+++ b/ext/pdo_sqlite/sqlite/src/attach.c
@@ -16,196 +16,348 @@
#include "sqliteInt.h"
/*
-** This routine is called by the parser to process an ATTACH statement:
+** Resolve an expression that was part of an ATTACH or DETACH statement. This
+** is slightly different from resolving a normal SQL expression, because simple
+** identifiers are treated as strings, not possible column names or aliases.
**
-** ATTACH DATABASE filename AS dbname
+** i.e. if the parser sees:
**
-** The pFilename and pDbname arguments are the tokens that define the
-** filename and dbname in the ATTACH statement.
+** ATTACH DATABASE abc AS def
+**
+** it treats the two expressions as literal strings 'abc' and 'def' instead of
+** looking for columns of the same name.
+**
+** This only applies to the root node of pExpr, so the statement:
+**
+** ATTACH DATABASE abc||def AS 'db2'
+**
+** will fail because neither abc or def can be resolved.
*/
-void sqlite3Attach(
- Parse *pParse, /* The parser context */
- Token *pFilename, /* Name of database file */
- Token *pDbname, /* Name of the database to use internally */
- int keyType, /* 0: no key. 1: TEXT, 2: BLOB */
- Token *pKey /* Text of the key for keytype 1 and 2 */
+static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
+{
+ int rc = SQLITE_OK;
+ if( pExpr ){
+ if( pExpr->op!=TK_ID ){
+ rc = sqlite3ExprResolveNames(pName, pExpr);
+ }else{
+ pExpr->op = TK_STRING;
+ }
+ }
+ return rc;
+}
+
+/*
+** An SQL user-function registered to do the work of an ATTACH statement. The
+** three arguments to the function come directly from an attach statement:
+**
+** ATTACH DATABASE x AS y KEY z
+**
+** SELECT sqlite_attach(x, y, z)
+**
+** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the
+** third argument.
+*/
+static void attachFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
){
+ int i;
+ int rc = 0;
+ sqlite3 *db = sqlite3_user_data(context);
+ const char *zName;
+ const char *zFile;
Db *aNew;
- int rc, i;
- char *zFile = 0;
- char *zName = 0;
- sqlite3 *db;
- Vdbe *v;
+ char zErr[128];
+ char *zErrDyn = 0;
- 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;
+ zFile = (const char *)sqlite3_value_text(argv[0]);
+ zName = (const char *)sqlite3_value_text(argv[1]);
+ if( zFile==0 ) zFile = "";
+ if( zName==0 ) zName = "";
+
+ /* Check for the following errors:
+ **
+ ** * Too many attached databases,
+ ** * Transaction currently open
+ ** * Specified database name already being used.
+ */
if( db->nDb>=MAX_ATTACHED+2 ){
- sqlite3ErrorMsg(pParse, "too many attached databases - max %d",
- MAX_ATTACHED);
- pParse->rc = SQLITE_ERROR;
- return;
+ sqlite3_snprintf(
+ sizeof(zErr), zErr, "too many attached databases - max %d", MAX_ATTACHED
+ );
+ goto attach_error;
}
-
if( !db->autoCommit ){
- sqlite3ErrorMsg(pParse, "cannot ATTACH database within transaction");
- pParse->rc = SQLITE_ERROR;
- return;
- }
-
- zFile = sqlite3NameFromToken(pFilename);
- if( zFile==0 ){
- goto attach_end;
- }
-#ifndef SQLITE_OMIT_AUTHORIZATION
- if( sqlite3AuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){
- goto attach_end;
- }
-#endif /* SQLITE_OMIT_AUTHORIZATION */
-
- zName = sqlite3NameFromToken(pDbname);
- if( zName==0 ){
- goto attach_end;
+ strcpy(zErr, "cannot ATTACH database within transaction");
+ goto attach_error;
}
for(i=0; i<db->nDb; i++){
char *z = db->aDb[i].zName;
- if( z && sqlite3StrICmp(z, zName)==0 ){
- sqlite3ErrorMsg(pParse, "database %s is already in use", zName);
- pParse->rc = SQLITE_ERROR;
- goto attach_end;
+ if( z && zName && sqlite3StrICmp(z, zName)==0 ){
+ sqlite3_snprintf(sizeof(zErr), zErr, "database %s is already in use", zName);
+ goto attach_error;
}
}
+ /* Allocate the new entry in the db->aDb[] array and initialise the schema
+ ** hash tables.
+ */
if( db->aDb==db->aDbStatic ){
aNew = sqliteMalloc( sizeof(db->aDb[0])*3 );
if( aNew==0 ){
- goto attach_end;
+ return;
}
memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
}else{
aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
if( aNew==0 ){
- goto attach_end;
+ return;
}
}
db->aDb = aNew;
aNew = &db->aDb[db->nDb++];
memset(aNew, 0, sizeof(*aNew));
- sqlite3HashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0);
- sqlite3HashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0);
- sqlite3HashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0);
- sqlite3HashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1);
- aNew->zName = zName;
- zName = 0;
- aNew->safety_level = 3;
+
+ /* Open the database file. If the btree is successfully opened, use
+ ** it to obtain the database schema. At this point the schema may
+ ** or may not be initialised.
+ */
rc = sqlite3BtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt);
- if( rc ){
- sqlite3ErrorMsg(pParse, "unable to open database: %s", zFile);
+ if( rc==SQLITE_OK ){
+ aNew->pSchema = sqlite3SchemaGet(aNew->pBt);
+ if( !aNew->pSchema ){
+ rc = SQLITE_NOMEM;
+ }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
+ strcpy(zErr,
+ "attached databases must use the same text encoding as main database");
+ goto attach_error;
+ }
}
+ aNew->zName = sqliteStrDup(zName);
+ aNew->safety_level = 3;
+
#if SQLITE_HAS_CODEC
{
extern int sqlite3CodecAttach(sqlite3*, int, void*, int);
- char *zKey;
+ extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
int nKey;
- if( keyType==0 ){
- /* No key specified. Use the key from the main database */
- extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
- sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
- }else if( keyType==1 ){
- /* Key specified as text */
- zKey = sqlite3NameFromToken(pKey);
- nKey = strlen(zKey);
- }else{
- /* Key specified as a BLOB */
- char *zTemp;
- assert( keyType==2 );
- pKey->z++;
- pKey->n--;
- zTemp = sqlite3NameFromToken(pKey);
- zKey = sqlite3HexToBlob(zTemp);
- sqliteFree(zTemp);
- }
- sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
- if( keyType ){
- sqliteFree(zKey);
+ char *zKey;
+ int t = sqlite3_value_type(argv[2]);
+ switch( t ){
+ case SQLITE_INTEGER:
+ case SQLITE_FLOAT:
+ zErrDyn = sqliteStrDup("Invalid key value");
+ rc = SQLITE_ERROR;
+ break;
+
+ case SQLITE_TEXT:
+ case SQLITE_BLOB:
+ nKey = sqlite3_value_bytes(argv[2]);
+ zKey = (char *)sqlite3_value_blob(argv[2]);
+ sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
+ break;
+
+ case SQLITE_NULL:
+ /* No key specified. Use the key from the main database */
+ sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
+ sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
+ break;
}
}
#endif
- db->flags &= ~SQLITE_Initialized;
- if( pParse->nErr==0 && rc==SQLITE_OK ){
- rc = sqlite3ReadSchema(pParse);
+
+ /* If the file was opened successfully, read the schema for the new database.
+ ** If this fails, or if opening the file failed, then close the file and
+ ** remove the entry from the db->aDb[] array. i.e. put everything back the way
+ ** we found it.
+ */
+ if( rc==SQLITE_OK ){
+ sqlite3SafetyOn(db);
+ rc = sqlite3Init(db, &zErrDyn);
+ sqlite3SafetyOff(db);
}
if( rc ){
- int i = db->nDb - 1;
- assert( i>=2 );
- if( db->aDb[i].pBt ){
- sqlite3BtreeClose(db->aDb[i].pBt);
- db->aDb[i].pBt = 0;
+ int iDb = db->nDb - 1;
+ assert( iDb>=2 );
+ if( db->aDb[iDb].pBt ){
+ sqlite3BtreeClose(db->aDb[iDb].pBt);
+ db->aDb[iDb].pBt = 0;
+ db->aDb[iDb].pSchema = 0;
}
sqlite3ResetInternalSchema(db, 0);
- assert( pParse->nErr>0 ); /* Always set by sqlite3ReadSchema() */
- if( pParse->rc==SQLITE_OK ){
- pParse->rc = SQLITE_ERROR;
+ db->nDb = iDb;
+ if( rc==SQLITE_NOMEM ){
+ if( !sqlite3MallocFailed() ) sqlite3FailedMalloc();
+ sqlite3_snprintf(sizeof(zErr),zErr, "out of memory");
+ }else{
+ sqlite3_snprintf(sizeof(zErr),zErr, "unable to open database: %s", zFile);
}
+ goto attach_error;
}
+
+ return;
-attach_end:
- sqliteFree(zFile);
- sqliteFree(zName);
+attach_error:
+ /* Return an error if we get here */
+ if( zErrDyn ){
+ sqlite3_result_error(context, zErrDyn, -1);
+ sqliteFree(zErrDyn);
+ }else{
+ zErr[sizeof(zErr)-1] = 0;
+ sqlite3_result_error(context, zErr, -1);
+ }
}
/*
-** This routine is called by the parser to process a DETACH statement:
+** An SQL user-function registered to do the work of an DETACH statement. The
+** three arguments to the function come directly from a detach statement:
**
-** DETACH DATABASE dbname
+** DETACH DATABASE x
**
-** The pDbname argument is the name of the database in the DETACH statement.
+** SELECT sqlite_detach(x)
*/
-void sqlite3Detach(Parse *pParse, Token *pDbname){
+static void detachFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zName = (const char *)sqlite3_value_text(argv[0]);
+ sqlite3 *db = sqlite3_user_data(context);
int i;
- sqlite3 *db;
- Vdbe *v;
Db *pDb = 0;
- char *zName;
+ char zErr[128];
- 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;
- zName = sqlite3NameFromToken(pDbname);
- if( zName==0 ) return;
+ if( zName==0 ) zName = "";
for(i=0; i<db->nDb; i++){
pDb = &db->aDb[i];
if( pDb->pBt==0 ) continue;
if( sqlite3StrICmp(pDb->zName, zName)==0 ) break;
}
+
if( i>=db->nDb ){
- sqlite3ErrorMsg(pParse, "no such database: %z", zName);
- return;
+ sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s", zName);
+ goto detach_error;
}
if( i<2 ){
- sqlite3ErrorMsg(pParse, "cannot detach database %z", zName);
- return;
+ sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName);
+ goto detach_error;
}
- sqliteFree(zName);
if( !db->autoCommit ){
- sqlite3ErrorMsg(pParse, "cannot DETACH database within transaction");
- pParse->rc = SQLITE_ERROR;
- return;
+ strcpy(zErr, "cannot DETACH database within transaction");
+ goto detach_error;
}
-#ifndef SQLITE_OMIT_AUTHORIZATION
- if( sqlite3AuthCheck(pParse,SQLITE_DETACH,db->aDb[i].zName,0,0)!=SQLITE_OK ){
- return;
+ if( sqlite3BtreeIsInReadTrans(pDb->pBt) ){
+ sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName);
+ goto detach_error;
}
-#endif /* SQLITE_OMIT_AUTHORIZATION */
+
sqlite3BtreeClose(pDb->pBt);
pDb->pBt = 0;
+ pDb->pSchema = 0;
sqlite3ResetInternalSchema(db, 0);
+ return;
+
+detach_error:
+ sqlite3_result_error(context, zErr, -1);
+}
+
+/*
+** This procedure generates VDBE code for a single invocation of either the
+** sqlite_detach() or sqlite_attach() SQL user functions.
+*/
+static void codeAttach(
+ Parse *pParse, /* The parser context */
+ int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */
+ const char *zFunc, /* Either "sqlite_attach" or "sqlite_detach */
+ int nFunc, /* Number of args to pass to zFunc */
+ Expr *pAuthArg, /* Expression to pass to authorization callback */
+ Expr *pFilename, /* Name of database file */
+ Expr *pDbname, /* Name of the database to use internally */
+ Expr *pKey /* Database key for encryption extension */
+){
+ int rc;
+ NameContext sName;
+ Vdbe *v;
+ FuncDef *pFunc;
+ sqlite3* db = pParse->db;
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ assert( sqlite3MallocFailed() || pAuthArg );
+ if( pAuthArg ){
+ char *zAuthArg = sqlite3NameFromToken(&pAuthArg->span);
+ if( !zAuthArg ){
+ goto attach_end;
+ }
+ rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0);
+ sqliteFree(zAuthArg);
+ if(rc!=SQLITE_OK ){
+ goto attach_end;
+ }
+ }
+#endif /* SQLITE_OMIT_AUTHORIZATION */
+
+ memset(&sName, 0, sizeof(NameContext));
+ sName.pParse = pParse;
+
+ if(
+ SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) ||
+ SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) ||
+ SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey))
+ ){
+ pParse->nErr++;
+ goto attach_end;
+ }
+
+ v = sqlite3GetVdbe(pParse);
+ sqlite3ExprCode(pParse, pFilename);
+ sqlite3ExprCode(pParse, pDbname);
+ sqlite3ExprCode(pParse, pKey);
+
+ assert( v || sqlite3MallocFailed() );
+ if( v ){
+ sqlite3VdbeAddOp(v, OP_Function, 0, nFunc);
+ pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0);
+ sqlite3VdbeChangeP3(v, -1, (char *)pFunc, P3_FUNCDEF);
+
+ /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
+ ** statement only). For DETACH, set it to false (expire all existing
+ ** statements).
+ */
+ sqlite3VdbeAddOp(v, OP_Expire, (type==SQLITE_ATTACH), 0);
+ }
+
+attach_end:
+ sqlite3ExprDelete(pFilename);
+ sqlite3ExprDelete(pDbname);
+ sqlite3ExprDelete(pKey);
+}
+
+/*
+** Called by the parser to compile a DETACH statement.
+**
+** DETACH pDbname
+*/
+void sqlite3Detach(Parse *pParse, Expr *pDbname){
+ codeAttach(pParse, SQLITE_DETACH, "sqlite_detach", 1, pDbname, 0, 0, pDbname);
+}
+
+/*
+** Called by the parser to compile an ATTACH statement.
+**
+** ATTACH p AS pDbname KEY pKey
+*/
+void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
+ codeAttach(pParse, SQLITE_ATTACH, "sqlite_attach", 3, p, p, pDbname, pKey);
+}
+
+/*
+** Register the functions sqlite_attach and sqlite_detach.
+*/
+void sqlite3AttachFunctions(sqlite3 *db){
+ static const int enc = SQLITE_UTF8;
+ sqlite3CreateFunc(db, "sqlite_attach", 3, enc, db, attachFunc, 0, 0);
+ sqlite3CreateFunc(db, "sqlite_detach", 1, enc, db, detachFunc, 0, 0);
}
/*
diff --git a/ext/pdo_sqlite/sqlite/src/auth.c b/ext/pdo_sqlite/sqlite/src/auth.c
index 693baa2c89..3983c1bc69 100644
--- a/ext/pdo_sqlite/sqlite/src/auth.c
+++ b/ext/pdo_sqlite/sqlite/src/auth.c
@@ -112,10 +112,17 @@ void sqlite3AuthRead(
int iSrc; /* Index in pTabList->a[] of table being read */
const char *zDBase; /* Name of database being accessed */
TriggerStack *pStack; /* The stack of current triggers */
+ int iDb; /* The index of the database the expression refers to */
if( db->xAuth==0 ) return;
if( pExpr->op==TK_AS ) return;
assert( pExpr->op==TK_COLUMN );
+ iDb = sqlite3SchemaToIndex(pParse->db, pExpr->pSchema);
+ if( iDb<0 ){
+ /* An attempt to read a column out of a subquery or other
+ ** temporary table. */
+ return;
+ }
for(iSrc=0; pTabList && iSrc<pTabList->nSrc; iSrc++){
if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break;
}
@@ -140,14 +147,14 @@ void sqlite3AuthRead(
}else{
zCol = "ROWID";
}
- assert( pExpr->iDb<db->nDb );
- zDBase = db->aDb[pExpr->iDb].zName;
+ assert( iDb>=0 && iDb<db->nDb );
+ zDBase = db->aDb[iDb].zName;
rc = db->xAuth(db->pAuthArg, SQLITE_READ, pTab->zName, zCol, zDBase,
pParse->zAuthContext);
if( rc==SQLITE_IGNORE ){
pExpr->op = TK_NULL;
}else if( rc==SQLITE_DENY ){
- if( db->nDb>2 || pExpr->iDb!=0 ){
+ if( db->nDb>2 || iDb!=0 ){
sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",
zDBase, pTab->zName, zCol);
}else{
@@ -175,8 +182,10 @@ int sqlite3AuthCheck(
sqlite3 *db = pParse->db;
int rc;
- /* Don't do any authorization checks if the database is initialising. */
- if( db->init.busy ){
+ /* Don't do any authorization checks if the database is initialising
+ ** or if the parser is being invoked from within sqlite3_declare_vtab.
+ */
+ if( db->init.busy || IN_DECLARE_VTAB ){
return SQLITE_OK;
}
diff --git a/ext/pdo_sqlite/sqlite/src/btree.c b/ext/pdo_sqlite/sqlite/src/btree.c
index f1ef6a2a4c..52bc749a32 100644
--- a/ext/pdo_sqlite/sqlite/src/btree.c
+++ b/ext/pdo_sqlite/sqlite/src/btree.c
@@ -230,6 +230,7 @@
/* Forward declarations */
typedef struct MemPage MemPage;
+typedef struct BtLock BtLock;
/*
** This is a magic string that appears at the beginning of every
@@ -285,10 +286,10 @@ struct MemPage {
u16 nFree; /* Number of free bytes on the page */
u16 nCell; /* Number of cells on this page, local and ovfl */
struct _OvflCell { /* Cells that will not fit on aData[] */
- u8 *pCell; /* Pointers to the body of the overflow cell */
- u16 idx; /* Insert this cell before idx-th non-overflow cell */
+ u8 *pCell; /* Pointers to the body of the overflow cell */
+ u16 idx; /* Insert this cell before idx-th non-overflow cell */
} aOvfl[5];
- struct Btree *pBt; /* Pointer back to BTree structure */
+ BtShared *pBt; /* Pointer back to BTree structure */
u8 *aData; /* Pointer back to the start of the page */
Pgno pgno; /* Page number for this page */
MemPage *pParent; /* The parent of this page. NULL for root */
@@ -301,14 +302,32 @@ struct MemPage {
*/
#define EXTRA_SIZE sizeof(MemPage)
+/* Btree handle */
+struct Btree {
+ sqlite3 *pSqlite;
+ BtShared *pBt;
+ u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
+};
+
+/*
+** Btree.inTrans may take one of the following values.
+**
+** If the shared-data extension is enabled, there may be multiple users
+** of the Btree structure. At most one of these may open a write transaction,
+** but any number may have active read transactions. Variable Btree.pDb
+** points to the handle that owns any current write-transaction.
+*/
+#define TRANS_NONE 0
+#define TRANS_READ 1
+#define TRANS_WRITE 2
+
/*
** Everything we need to know about an open database
*/
-struct Btree {
+struct BtShared {
Pager *pPager; /* The page cache */
BtCursor *pCursor; /* A list of all open cursors */
MemPage *pPage1; /* First page of the database */
- u8 inTrans; /* True if a transaction is in progress */
u8 inStmt; /* True if we are in a statement subtransaction */
u8 readOnly; /* True if the underlying file is readonly */
u8 maxEmbedFrac; /* Maximum payload as % of total page size */
@@ -325,15 +344,16 @@ struct Btree {
int maxLeaf; /* Maximum local payload in a LEAFDATA table */
int minLeaf; /* Minimum local payload in a LEAFDATA table */
BusyHandler *pBusyHandler; /* Callback for when there is lock contention */
+ u8 inTransaction; /* Transaction state */
+ int nRef; /* Number of references to this structure */
+ int nTransaction; /* Number of open transactions (read + write) */
+ void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */
+ void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ BtLock *pLock; /* List of locks held on this shared-btree struct */
+ BtShared *pNext; /* Next in ThreadData.pBtree linked list */
+#endif
};
-typedef Btree Bt;
-
-/*
-** Btree.inTrans may take one of the following values.
-*/
-#define TRANS_NONE 0
-#define TRANS_READ 1
-#define TRANS_WRITE 2
/*
** An instance of the following structure is used to hold information
@@ -357,7 +377,7 @@ struct CellInfo {
** MemPage.aCell[] of the entry.
*/
struct BtCursor {
- Btree *pBt; /* The Btree to which this cursor belongs */
+ Btree *pBtree; /* The Btree to which this cursor belongs */
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */
void *pArg; /* First arg to xCompare() */
@@ -366,10 +386,39 @@ struct BtCursor {
int idx; /* Index of the entry in pPage->aCell[] */
CellInfo info; /* A parse of the cell we are pointing at */
u8 wrFlag; /* True if writable */
- u8 isValid; /* TRUE if points to a valid entry */
+ u8 eState; /* One of the CURSOR_XXX constants (see below) */
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ void *pKey; /* Saved key that was cursor's last known position */
+ i64 nKey; /* Size of pKey, or last integer key */
+ int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */
+#endif
};
/*
+** Potential values for BtCursor.eState. The first two values (VALID and
+** INVALID) may occur in any build. The third (REQUIRESEEK) may only occur
+** if sqlite was compiled without the OMIT_SHARED_CACHE symbol defined.
+**
+** CURSOR_VALID:
+** Cursor points to a valid entry. getPayload() etc. may be called.
+**
+** CURSOR_INVALID:
+** Cursor does not point to a valid entry. This can happen (for example)
+** because the table is empty or because BtreeCursorFirst() has not been
+** called.
+**
+** CURSOR_REQUIRESEEK:
+** The table that this cursor was opened on still exists, but has been
+** modified since the cursor was last used. The cursor position is saved
+** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
+** this state, restoreOrClearCursorPosition() can be called to attempt to
+** seek the cursor to the saved position.
+*/
+#define CURSOR_INVALID 0
+#define CURSOR_VALID 1
+#define CURSOR_REQUIRESEEK 2
+
+/*
** The TRACE macro will print high-level status information about the
** btree operation when the global variable sqlite3_btree_trace is
** enabled.
@@ -377,15 +426,15 @@ struct BtCursor {
#if SQLITE_TEST
# define TRACE(X) if( sqlite3_btree_trace )\
{ sqlite3DebugPrintf X; fflush(stdout); }
+int sqlite3_btree_trace=0; /* True to enable tracing */
#else
# define TRACE(X)
#endif
-int sqlite3_btree_trace=0; /* True to enable tracing */
/*
** Forward declaration
*/
-static int checkReadLocks(Btree*,Pgno,BtCursor*);
+static int checkReadLocks(BtShared*,Pgno,BtCursor*);
/*
** Read or write a two- and four-byte big-endian integer values.
@@ -413,14 +462,290 @@ static void put4byte(unsigned char *p, u32 v){
** file.
*/
#define getVarint sqlite3GetVarint
-#define getVarint32 sqlite3GetVarint32
+/* #define getVarint32 sqlite3GetVarint32 */
+#define getVarint32(A,B) ((*B=*(A))<=0x7f?1:sqlite3GetVarint32(A,B))
#define putVarint sqlite3PutVarint
/* The database page the PENDING_BYTE occupies. This page is never used.
** TODO: This macro is very similary to PAGER_MJ_PGNO() in pager.c. They
** should possibly be consolidated (presumably in pager.h).
+**
+** If disk I/O is omitted (meaning that the database is stored purely
+** in memory) then there is no pending byte.
+*/
+#ifdef SQLITE_OMIT_DISKIO
+# define PENDING_BYTE_PAGE(pBt) 0x7fffffff
+#else
+# define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1)
+#endif
+
+/*
+** A linked list of the following structures is stored at BtShared.pLock.
+** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor
+** is opened on the table with root page BtShared.iTable. Locks are removed
+** from this list when a transaction is committed or rolled back, or when
+** a btree handle is closed.
+*/
+struct BtLock {
+ Btree *pBtree; /* Btree handle holding this lock */
+ Pgno iTable; /* Root page of table */
+ u8 eLock; /* READ_LOCK or WRITE_LOCK */
+ BtLock *pNext; /* Next in BtShared.pLock list */
+};
+
+/* Candidate values for BtLock.eLock */
+#define READ_LOCK 1
+#define WRITE_LOCK 2
+
+#ifdef SQLITE_OMIT_SHARED_CACHE
+ /*
+ ** The functions queryTableLock(), lockTable() and unlockAllTables()
+ ** manipulate entries in the BtShared.pLock linked list used to store
+ ** shared-cache table level locks. If the library is compiled with the
+ ** shared-cache feature disabled, then there is only ever one user
+ ** of each BtShared structure and so this locking is not necessary.
+ ** So define the lock related functions as no-ops.
+ */
+ #define queryTableLock(a,b,c) SQLITE_OK
+ #define lockTable(a,b,c) SQLITE_OK
+ #define unlockAllTables(a)
+ #define restoreOrClearCursorPosition(a,b) SQLITE_OK
+ #define saveAllCursors(a,b,c) SQLITE_OK
+
+#else
+
+static void releasePage(MemPage *pPage);
+
+/*
+** Save the current cursor position in the variables BtCursor.nKey
+** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
+*/
+static int saveCursorPosition(BtCursor *pCur){
+ int rc;
+
+ assert( CURSOR_VALID==pCur->eState );
+ assert( 0==pCur->pKey );
+
+ rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
+
+ /* If this is an intKey table, then the above call to BtreeKeySize()
+ ** stores the integer key in pCur->nKey. In this case this value is
+ ** all that is required. Otherwise, if pCur is not open on an intKey
+ ** table, then malloc space for and store the pCur->nKey bytes of key
+ ** data.
+ */
+ if( rc==SQLITE_OK && 0==pCur->pPage->intKey){
+ void *pKey = sqliteMalloc(pCur->nKey);
+ if( pKey ){
+ rc = sqlite3BtreeKey(pCur, 0, pCur->nKey, pKey);
+ if( rc==SQLITE_OK ){
+ pCur->pKey = pKey;
+ }else{
+ sqliteFree(pKey);
+ }
+ }else{
+ rc = SQLITE_NOMEM;
+ }
+ }
+ assert( !pCur->pPage->intKey || !pCur->pKey );
+
+ if( rc==SQLITE_OK ){
+ releasePage(pCur->pPage);
+ pCur->pPage = 0;
+ pCur->eState = CURSOR_REQUIRESEEK;
+ }
+
+ return rc;
+}
+
+/*
+** Save the positions of all cursors except pExcept open on the table
+** with root-page iRoot. Usually, this is called just before cursor
+** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()).
+*/
+static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
+ BtCursor *p;
+ if( sqlite3ThreadDataReadOnly()->useSharedData ){
+ for(p=pBt->pCursor; p; p=p->pNext){
+ if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) &&
+ p->eState==CURSOR_VALID ){
+ int rc = saveCursorPosition(p);
+ if( SQLITE_OK!=rc ){
+ return rc;
+ }
+ }
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Restore the cursor to the position it was in (or as close to as possible)
+** when saveCursorPosition() was called. Note that this call deletes the
+** saved position info stored by saveCursorPosition(), so there can be
+** at most one effective restoreOrClearCursorPosition() call after each
+** saveCursorPosition().
+**
+** If the second argument argument - doSeek - is false, then instead of
+** returning the cursor to it's saved position, any saved position is deleted
+** and the cursor state set to CURSOR_INVALID.
+*/
+static int restoreOrClearCursorPositionX(BtCursor *pCur, int doSeek){
+ int rc = SQLITE_OK;
+ assert( sqlite3ThreadDataReadOnly()->useSharedData );
+ assert( pCur->eState==CURSOR_REQUIRESEEK );
+ pCur->eState = CURSOR_INVALID;
+ if( doSeek ){
+ rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, &pCur->skip);
+ }
+ if( rc==SQLITE_OK ){
+ sqliteFree(pCur->pKey);
+ pCur->pKey = 0;
+ assert( CURSOR_VALID==pCur->eState || CURSOR_INVALID==pCur->eState );
+ }
+ return rc;
+}
+
+#define restoreOrClearCursorPosition(p,x) \
+ (p->eState==CURSOR_REQUIRESEEK?restoreOrClearCursorPositionX(p,x):SQLITE_OK)
+
+/*
+** Query to see if btree handle p may obtain a lock of type eLock
+** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return
+** SQLITE_OK if the lock may be obtained (by calling lockTable()), or
+** SQLITE_LOCKED if not.
+*/
+static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){
+ BtShared *pBt = p->pBt;
+ BtLock *pIter;
+
+ /* This is a no-op if the shared-cache is not enabled */
+ if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){
+ return SQLITE_OK;
+ }
+
+ /* This (along with lockTable()) is where the ReadUncommitted flag is
+ ** dealt with. If the caller is querying for a read-lock and the flag is
+ ** set, it is unconditionally granted - even if there are write-locks
+ ** on the table. If a write-lock is requested, the ReadUncommitted flag
+ ** is not considered.
+ **
+ ** In function lockTable(), if a read-lock is demanded and the
+ ** ReadUncommitted flag is set, no entry is added to the locks list
+ ** (BtShared.pLock).
+ **
+ ** To summarize: If the ReadUncommitted flag is set, then read cursors do
+ ** not create or respect table locks. The locking procedure for a
+ ** write-cursor does not change.
+ */
+ if(
+ !p->pSqlite ||
+ 0==(p->pSqlite->flags&SQLITE_ReadUncommitted) ||
+ eLock==WRITE_LOCK ||
+ iTab==MASTER_ROOT
+ ){
+ for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
+ if( pIter->pBtree!=p && pIter->iTable==iTab &&
+ (pIter->eLock!=eLock || eLock!=READ_LOCK) ){
+ return SQLITE_LOCKED;
+ }
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Add a lock on the table with root-page iTable to the shared-btree used
+** by Btree handle p. Parameter eLock must be either READ_LOCK or
+** WRITE_LOCK.
+**
+** SQLITE_OK is returned if the lock is added successfully. SQLITE_BUSY and
+** SQLITE_NOMEM may also be returned.
*/
-#define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1)
+static int lockTable(Btree *p, Pgno iTable, u8 eLock){
+ BtShared *pBt = p->pBt;
+ BtLock *pLock = 0;
+ BtLock *pIter;
+
+ /* This is a no-op if the shared-cache is not enabled */
+ if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){
+ return SQLITE_OK;
+ }
+
+ assert( SQLITE_OK==queryTableLock(p, iTable, eLock) );
+
+ /* If the read-uncommitted flag is set and a read-lock is requested,
+ ** return early without adding an entry to the BtShared.pLock list. See
+ ** comment in function queryTableLock() for more info on handling
+ ** the ReadUncommitted flag.
+ */
+ if(
+ (p->pSqlite) &&
+ (p->pSqlite->flags&SQLITE_ReadUncommitted) &&
+ (eLock==READ_LOCK) &&
+ iTable!=MASTER_ROOT
+ ){
+ return SQLITE_OK;
+ }
+
+ /* First search the list for an existing lock on this table. */
+ for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
+ if( pIter->iTable==iTable && pIter->pBtree==p ){
+ pLock = pIter;
+ break;
+ }
+ }
+
+ /* If the above search did not find a BtLock struct associating Btree p
+ ** with table iTable, allocate one and link it into the list.
+ */
+ if( !pLock ){
+ pLock = (BtLock *)sqliteMalloc(sizeof(BtLock));
+ if( !pLock ){
+ return SQLITE_NOMEM;
+ }
+ pLock->iTable = iTable;
+ pLock->pBtree = p;
+ pLock->pNext = pBt->pLock;
+ pBt->pLock = pLock;
+ }
+
+ /* Set the BtLock.eLock variable to the maximum of the current lock
+ ** and the requested lock. This means if a write-lock was already held
+ ** and a read-lock requested, we don't incorrectly downgrade the lock.
+ */
+ assert( WRITE_LOCK>READ_LOCK );
+ if( eLock>pLock->eLock ){
+ pLock->eLock = eLock;
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Release all the table locks (locks obtained via calls to the lockTable()
+** procedure) held by Btree handle p.
+*/
+static void unlockAllTables(Btree *p){
+ BtLock **ppIter = &p->pBt->pLock;
+
+ /* If the shared-cache extension is not enabled, there should be no
+ ** locks in the BtShared.pLock list, making this procedure a no-op. Assert
+ ** that this is the case.
+ */
+ assert( sqlite3ThreadDataReadOnly()->useSharedData || 0==*ppIter );
+
+ while( *ppIter ){
+ BtLock *pLock = *ppIter;
+ if( pLock->pBtree==p ){
+ *ppIter = pLock->pNext;
+ sqliteFree(pLock);
+ }else{
+ ppIter = &pLock->pNext;
+ }
+ }
+}
+#endif /* SQLITE_OMIT_SHARED_CACHE */
#ifndef SQLITE_OMIT_AUTOVACUUM
/*
@@ -438,9 +763,19 @@ static void put4byte(unsigned char *p, u32 v){
** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
** this test.
*/
-#define PTRMAP_PAGENO(pgsz, pgno) (((pgno-2)/(pgsz/5+1))*(pgsz/5+1)+2)
-#define PTRMAP_PTROFFSET(pgsz, pgno) (((pgno-2)%(pgsz/5+1)-1)*5)
-#define PTRMAP_ISPAGE(pgsz, pgno) (PTRMAP_PAGENO(pgsz,pgno)==pgno)
+#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
+#define PTRMAP_PTROFFSET(pBt, pgno) (5*(pgno-ptrmapPageno(pBt, pgno)-1))
+#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
+
+static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){
+ int nPagesPerMapPage = (pBt->usableSize/5)+1;
+ int iPtrMap = (pgno-2)/nPagesPerMapPage;
+ int ret = (iPtrMap*nPagesPerMapPage) + 2;
+ if( ret==PENDING_BYTE_PAGE(pBt) ){
+ ret++;
+ }
+ return ret;
+}
/*
** The pointer map is a lookup table that identifies the parent page for
@@ -486,22 +821,25 @@ static void put4byte(unsigned char *p, u32 v){
** so that it maps to type 'eType' and parent page number 'pgno'.
** An error code is returned if something goes wrong, otherwise SQLITE_OK.
*/
-static int ptrmapPut(Btree *pBt, Pgno key, u8 eType, Pgno parent){
+static int ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent){
u8 *pPtrmap; /* The pointer map page */
Pgno iPtrmap; /* The pointer map page number */
int offset; /* Offset in pointer map page */
int rc;
+ /* The master-journal page number must never be used as a pointer map page */
+ assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) );
+
assert( pBt->autoVacuum );
if( key==0 ){
return SQLITE_CORRUPT_BKPT;
}
- iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key);
+ iPtrmap = PTRMAP_PAGENO(pBt, key);
rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
if( rc!=SQLITE_OK ){
return rc;
}
- offset = PTRMAP_PTROFFSET(pBt->usableSize, key);
+ offset = PTRMAP_PTROFFSET(pBt, key);
if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));
@@ -523,20 +861,21 @@ static int ptrmapPut(Btree *pBt, Pgno key, u8 eType, Pgno parent){
** the type and parent page number to *pEType and *pPgno respectively.
** An error code is returned if something goes wrong, otherwise SQLITE_OK.
*/
-static int ptrmapGet(Btree *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
+static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
int iPtrmap; /* Pointer map page index */
u8 *pPtrmap; /* Pointer map page data */
int offset; /* Offset of entry in pointer map */
int rc;
- iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key);
+ iPtrmap = PTRMAP_PAGENO(pBt, key);
rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
if( rc!=0 ){
return rc;
}
- offset = PTRMAP_PTROFFSET(pBt->usableSize, key);
- if( pEType ) *pEType = pPtrmap[offset];
+ offset = PTRMAP_PTROFFSET(pBt, key);
+ assert( pEType!=0 );
+ *pEType = pPtrmap[offset];
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
sqlite3pager_unref(pPtrmap);
@@ -604,12 +943,16 @@ static void parseCellPtr(
}else{
nPayload = 0;
}
- n += getVarint(&pCell[n], (u64 *)&pInfo->nKey);
- pInfo->nHeader = n;
pInfo->nData = nPayload;
- if( !pPage->intKey ){
- nPayload += pInfo->nKey;
+ if( pPage->intKey ){
+ n += getVarint(&pCell[n], (u64 *)&pInfo->nKey);
+ }else{
+ u32 x;
+ n += getVarint32(&pCell[n], &x);
+ pInfo->nKey = x;
+ nPayload += x;
}
+ pInfo->nHeader = n;
if( nPayload<=pPage->maxLocal ){
/* This is the (easy) common case where the entire payload fits
** on the local page. No overflow is required.
@@ -790,10 +1133,20 @@ static void _pageIntegrity(MemPage *pPage){
# define pageIntegrity(X)
#endif
+/* A bunch of assert() statements to check the transaction state variables
+** of handle p (type Btree*) are internally consistent.
+*/
+#define btreeIntegrity(p) \
+ assert( p->inTrans!=TRANS_NONE || p->pBt->nTransaction<p->pBt->nRef ); \
+ assert( p->pBt->nTransaction<=p->pBt->nRef ); \
+ assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
+ assert( p->pBt->inTransaction>=p->inTrans );
+
/*
** Defragment the page given. All Cells are moved to the
-** beginning of the page and all free space is collected
-** into one big FreeBlk at the end of the page.
+** end of the page and all free space is collected into one
+** big FreeBlk that occurs in between the header and cell
+** pointer array and the cell content area.
*/
static int defragmentPage(MemPage *pPage){
int i; /* Loop counter */
@@ -928,6 +1281,12 @@ static void freeSpace(MemPage *pPage, int start, int size){
assert( (start + size)<=pPage->pBt->usableSize );
if( size<4 ) size = 4;
+#ifdef SQLITE_SECURE_DELETE
+ /* Overwrite deleted information with zeros when the SECURE_DELETE
+ ** option is enabled at compile-time */
+ memset(&data[start], 0, size);
+#endif
+
/* Add the space back into the linked list of freeblocks */
hdr = pPage->hdrOffset;
addr = hdr + 1;
@@ -977,7 +1336,7 @@ static void freeSpace(MemPage *pPage, int start, int size){
** and initialize fields of the MemPage structure accordingly.
*/
static void decodeFlags(MemPage *pPage, int flagByte){
- Btree *pBt; /* A copy of pPage->pBt */
+ BtShared *pBt; /* A copy of pPage->pBt */
assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) );
pPage->intKey = (flagByte & (PTF_INTKEY|PTF_LEAFDATA))!=0;
@@ -1017,7 +1376,7 @@ static int initPage(
int pc; /* Address of a freeblock within pPage->aData[] */
int hdr; /* Offset to beginning of page header */
u8 *data; /* Equal to pPage->aData */
- Btree *pBt; /* The main btree structure */
+ BtShared *pBt; /* The main btree structure */
int usableSize; /* Amount of usable space on each page */
int cellOffset; /* Offset from start of page to first cell pointer */
int nFree; /* Number of unused bytes on the page */
@@ -1090,7 +1449,7 @@ static int initPage(
*/
static void zeroPage(MemPage *pPage, int flags){
unsigned char *data = pPage->aData;
- Btree *pBt = pPage->pBt;
+ BtShared *pBt = pPage->pBt;
int hdr = pPage->hdrOffset;
int first;
@@ -1118,7 +1477,7 @@ static void zeroPage(MemPage *pPage, int flags){
** Get a page from the pager. Initialize the MemPage.pBt and
** MemPage.aData elements if needed.
*/
-static int getPage(Btree *pBt, Pgno pgno, MemPage **ppPage){
+static int getPage(BtShared *pBt, Pgno pgno, MemPage **ppPage){
int rc;
unsigned char *aData;
MemPage *pPage;
@@ -1139,7 +1498,7 @@ static int getPage(Btree *pBt, Pgno pgno, MemPage **ppPage){
** getPage() and initPage().
*/
static int getAndInitPage(
- Btree *pBt, /* The database file */
+ BtShared *pBt, /* The database file */
Pgno pgno, /* Number of the page to get */
MemPage **ppPage, /* Write the page pointer here */
MemPage *pParent /* Parent of the page */
@@ -1212,21 +1571,69 @@ static void pageReinit(void *pData, int pageSize){
*/
int sqlite3BtreeOpen(
const char *zFilename, /* Name of the file containing the BTree database */
+ sqlite3 *pSqlite, /* Associated database handle */
Btree **ppBtree, /* Pointer to new Btree object written here */
int flags /* Options */
){
- Btree *pBt;
+ BtShared *pBt; /* Shared part of btree structure */
+ Btree *p; /* Handle to return */
int rc;
int nReserve;
unsigned char zDbHeader[100];
+#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
+ const ThreadData *pTsdro;
+#endif
+
+ /* Set the variable isMemdb to true for an in-memory database, or
+ ** false for a file-based database. This symbol is only required if
+ ** either of the shared-data or autovacuum features are compiled
+ ** into the library.
+ */
+#if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM)
+ #ifdef SQLITE_OMIT_MEMORYDB
+ const int isMemdb = !zFilename;
+ #else
+ const int isMemdb = !zFilename || (strcmp(zFilename, ":memory:")?0:1);
+ #endif
+#endif
+
+ p = sqliteMalloc(sizeof(Btree));
+ if( !p ){
+ return SQLITE_NOMEM;
+ }
+ p->inTrans = TRANS_NONE;
+ p->pSqlite = pSqlite;
+
+ /* Try to find an existing Btree structure opened on zFilename. */
+#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
+ pTsdro = sqlite3ThreadDataReadOnly();
+ if( pTsdro->useSharedData && zFilename && !isMemdb ){
+ char *zFullPathname = sqlite3OsFullPathname(zFilename);
+ if( !zFullPathname ){
+ sqliteFree(p);
+ return SQLITE_NOMEM;
+ }
+ for(pBt=pTsdro->pBtree; pBt; pBt=pBt->pNext){
+ assert( pBt->nRef>0 );
+ if( 0==strcmp(zFullPathname, sqlite3pager_filename(pBt->pPager)) ){
+ p->pBt = pBt;
+ *ppBtree = p;
+ pBt->nRef++;
+ sqliteFree(zFullPathname);
+ return SQLITE_OK;
+ }
+ }
+ sqliteFree(zFullPathname);
+ }
+#endif
/*
** The following asserts make sure that structures used by the btree are
** the right size. This is to guard against size changes that result
** when compiling on a different architecture.
*/
- assert( sizeof(i64)==8 );
- assert( sizeof(u64)==8 );
+ assert( sizeof(i64)==8 || sizeof(i64)==4 );
+ assert( sizeof(u64)==8 || sizeof(u64)==4 );
assert( sizeof(u32)==4 );
assert( sizeof(u16)==2 );
assert( sizeof(Pgno)==4 );
@@ -1234,15 +1641,19 @@ int sqlite3BtreeOpen(
pBt = sqliteMalloc( sizeof(*pBt) );
if( pBt==0 ){
*ppBtree = 0;
+ sqliteFree(p);
return SQLITE_NOMEM;
}
rc = sqlite3pager_open(&pBt->pPager, zFilename, EXTRA_SIZE, flags);
if( rc!=SQLITE_OK ){
if( pBt->pPager ) sqlite3pager_close(pBt->pPager);
sqliteFree(pBt);
+ sqliteFree(p);
*ppBtree = 0;
return rc;
}
+ p->pBt = pBt;
+
sqlite3pager_set_destructor(pBt->pPager, pageDestructor);
sqlite3pager_set_reiniter(pBt->pPager, pageReinit);
pBt->pCursor = 0;
@@ -1263,11 +1674,7 @@ int sqlite3BtreeOpen(
** then ":memory:" is just a regular file-name. Respect the auto-vacuum
** default in this case.
*/
-#ifndef SQLITE_OMIT_MEMORYDB
- if( zFilename && strcmp(zFilename,":memory:") ){
-#else
- if( zFilename ){
-#endif
+ if( zFilename && !isMemdb ){
pBt->autoVacuum = SQLITE_DEFAULT_AUTOVACUUM;
}
#endif
@@ -1285,18 +1692,87 @@ int sqlite3BtreeOpen(
pBt->usableSize = pBt->pageSize - nReserve;
assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */
sqlite3pager_set_pagesize(pBt->pPager, pBt->pageSize);
- *ppBtree = pBt;
+
+#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
+ /* Add the new btree to the linked list starting at ThreadData.pBtree.
+ ** There is no chance that a malloc() may fail inside of the
+ ** sqlite3ThreadData() call, as the ThreadData structure must have already
+ ** been allocated for pTsdro->useSharedData to be non-zero.
+ */
+ if( pTsdro->useSharedData && zFilename && !isMemdb ){
+ pBt->pNext = pTsdro->pBtree;
+ sqlite3ThreadData()->pBtree = pBt;
+ }
+#endif
+ pBt->nRef = 1;
+ *ppBtree = p;
return SQLITE_OK;
}
/*
** Close an open database and invalidate all cursors.
*/
-int sqlite3BtreeClose(Btree *pBt){
- while( pBt->pCursor ){
- sqlite3BtreeCloseCursor(pBt->pCursor);
+int sqlite3BtreeClose(Btree *p){
+ BtShared *pBt = p->pBt;
+ BtCursor *pCur;
+
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ ThreadData *pTsd;
+#endif
+
+ /* Close all cursors opened via this handle. */
+ pCur = pBt->pCursor;
+ while( pCur ){
+ BtCursor *pTmp = pCur;
+ pCur = pCur->pNext;
+ if( pTmp->pBtree==p ){
+ sqlite3BtreeCloseCursor(pTmp);
+ }
+ }
+
+ /* Rollback any active transaction and free the handle structure.
+ ** The call to sqlite3BtreeRollback() drops any table-locks held by
+ ** this handle.
+ */
+ sqlite3BtreeRollback(p);
+ sqliteFree(p);
+
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ /* If there are still other outstanding references to the shared-btree
+ ** structure, return now. The remainder of this procedure cleans
+ ** up the shared-btree.
+ */
+ assert( pBt->nRef>0 );
+ pBt->nRef--;
+ if( pBt->nRef ){
+ return SQLITE_OK;
}
+
+ /* Remove the shared-btree from the thread wide list. Call
+ ** ThreadDataReadOnly() and then cast away the const property of the
+ ** pointer to avoid allocating thread data if it is not really required.
+ */
+ pTsd = (ThreadData *)sqlite3ThreadDataReadOnly();
+ if( pTsd->pBtree==pBt ){
+ assert( pTsd==sqlite3ThreadData() );
+ pTsd->pBtree = pBt->pNext;
+ }else{
+ BtShared *pPrev;
+ for(pPrev=pTsd->pBtree; pPrev && pPrev->pNext!=pBt; pPrev=pPrev->pNext){}
+ if( pPrev ){
+ assert( pTsd==sqlite3ThreadData() );
+ pPrev->pNext = pBt->pNext;
+ }
+ }
+#endif
+
+ /* Close the pager and free the shared-btree structure */
+ assert( !pBt->pCursor );
sqlite3pager_close(pBt->pPager);
+ if( pBt->xFreeSchema && pBt->pSchema ){
+ pBt->xFreeSchema(pBt->pSchema);
+ }
+ sqliteFree(pBt->pSchema);
sqliteFree(pBt);
return SQLITE_OK;
}
@@ -1304,7 +1780,8 @@ int sqlite3BtreeClose(Btree *pBt){
/*
** Change the busy handler callback function.
*/
-int sqlite3BtreeSetBusyHandler(Btree *pBt, BusyHandler *pHandler){
+int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){
+ BtShared *pBt = p->pBt;
pBt->pBusyHandler = pHandler;
sqlite3pager_set_busyhandler(pBt->pPager, pHandler);
return SQLITE_OK;
@@ -1325,7 +1802,8 @@ int sqlite3BtreeSetBusyHandler(Btree *pBt, BusyHandler *pHandler){
** Synchronous is on by default so database corruption is not
** normally a worry.
*/
-int sqlite3BtreeSetCacheSize(Btree *pBt, int mxPage){
+int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
+ BtShared *pBt = p->pBt;
sqlite3pager_set_cachesize(pBt->pPager, mxPage);
return SQLITE_OK;
}
@@ -1339,8 +1817,9 @@ int sqlite3BtreeSetCacheSize(Btree *pBt, int mxPage){
** probability of damage to near zero but with a write performance reduction.
*/
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
-int sqlite3BtreeSetSafetyLevel(Btree *pBt, int level){
- sqlite3pager_set_safety_level(pBt->pPager, level);
+int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){
+ BtShared *pBt = p->pBt;
+ sqlite3pager_set_safety_level(pBt->pPager, level, fullSync);
return SQLITE_OK;
}
#endif
@@ -1349,7 +1828,8 @@ int sqlite3BtreeSetSafetyLevel(Btree *pBt, int level){
** Return TRUE if the given btree is set to safety level 1. In other
** words, return TRUE if no sync() occurs on the disk files.
*/
-int sqlite3BtreeSyncDisabled(Btree *pBt){
+int sqlite3BtreeSyncDisabled(Btree *p){
+ BtShared *pBt = p->pBt;
assert( pBt && pBt->pPager );
return sqlite3pager_nosync(pBt->pPager);
}
@@ -1370,7 +1850,8 @@ int sqlite3BtreeSyncDisabled(Btree *pBt){
** If parameter nReserve is less than zero, then the number of reserved
** bytes per page is left unchanged.
*/
-int sqlite3BtreeSetPageSize(Btree *pBt, int pageSize, int nReserve){
+int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve){
+ BtShared *pBt = p->pBt;
if( pBt->pageSizeFixed ){
return SQLITE_READONLY;
}
@@ -1380,6 +1861,7 @@ int sqlite3BtreeSetPageSize(Btree *pBt, int pageSize, int nReserve){
if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE &&
((pageSize-1)&pageSize)==0 ){
assert( (pageSize & 7)==0 );
+ assert( !pBt->pPage1 && !pBt->pCursor );
pBt->pageSize = sqlite3pager_set_pagesize(pBt->pPager, pageSize);
}
pBt->usableSize = pBt->pageSize - nReserve;
@@ -1389,11 +1871,11 @@ int sqlite3BtreeSetPageSize(Btree *pBt, int pageSize, int nReserve){
/*
** Return the currently defined page size
*/
-int sqlite3BtreeGetPageSize(Btree *pBt){
- return pBt->pageSize;
+int sqlite3BtreeGetPageSize(Btree *p){
+ return p->pBt->pageSize;
}
-int sqlite3BtreeGetReserve(Btree *pBt){
- return pBt->pageSize - pBt->usableSize;
+int sqlite3BtreeGetReserve(Btree *p){
+ return p->pBt->pageSize - p->pBt->usableSize;
}
#endif /* !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) */
@@ -1403,7 +1885,8 @@ int sqlite3BtreeGetReserve(Btree *pBt){
** is disabled. The default value for the auto-vacuum property is
** determined by the SQLITE_DEFAULT_AUTOVACUUM macro.
*/
-int sqlite3BtreeSetAutoVacuum(Btree *pBt, int autoVacuum){
+int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){
+ BtShared *pBt = p->pBt;;
#ifdef SQLITE_OMIT_AUTOVACUUM
return SQLITE_READONLY;
#else
@@ -1419,11 +1902,11 @@ int sqlite3BtreeSetAutoVacuum(Btree *pBt, int autoVacuum){
** Return the value of the 'auto-vacuum' property. If auto-vacuum is
** enabled 1 is returned. Otherwise 0.
*/
-int sqlite3BtreeGetAutoVacuum(Btree *pBt){
+int sqlite3BtreeGetAutoVacuum(Btree *p){
#ifdef SQLITE_OMIT_AUTOVACUUM
return 0;
#else
- return pBt->autoVacuum;
+ return p->pBt->autoVacuum;
#endif
}
@@ -1438,7 +1921,7 @@ int sqlite3BtreeGetAutoVacuum(Btree *pBt){
** is returned if we run out of memory. SQLITE_PROTOCOL is returned
** if there is a locking protocol violation.
*/
-static int lockBtree(Btree *pBt){
+static int lockBtree(BtShared *pBt){
int rc, pageSize;
MemPage *pPage1;
if( pBt->pPage1 ) return SQLITE_OK;
@@ -1510,11 +1993,18 @@ page1_init_failed:
** This routine works like lockBtree() except that it also invokes the
** busy callback if there is lock contention.
*/
-static int lockBtreeWithRetry(Btree *pBt){
+static int lockBtreeWithRetry(Btree *pRef){
int rc = SQLITE_OK;
- if( pBt->inTrans==TRANS_NONE ){
- rc = sqlite3BtreeBeginTrans(pBt, 0);
- pBt->inTrans = TRANS_NONE;
+ if( pRef->inTrans==TRANS_NONE ){
+ u8 inTransaction = pRef->pBt->inTransaction;
+ btreeIntegrity(pRef);
+ rc = sqlite3BtreeBeginTrans(pRef, 0);
+ pRef->pBt->inTransaction = inTransaction;
+ pRef->inTrans = TRANS_NONE;
+ if( rc==SQLITE_OK ){
+ pRef->pBt->nTransaction--;
+ }
+ btreeIntegrity(pRef);
}
return rc;
}
@@ -1530,11 +2020,11 @@ static int lockBtreeWithRetry(Btree *pBt){
**
** If there is a transaction in progress, this routine is a no-op.
*/
-static void unlockBtreeIfUnused(Btree *pBt){
- if( pBt->inTrans==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){
+static void unlockBtreeIfUnused(BtShared *pBt){
+ if( pBt->inTransaction==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){
if( pBt->pPage1->aData==0 ){
MemPage *pPage = pBt->pPage1;
- pPage->aData = &((char*)pPage)[-pBt->pageSize];
+ pPage->aData = &((u8*)pPage)[-pBt->pageSize];
pPage->pBt = pBt;
pPage->pgno = 1;
}
@@ -1548,7 +2038,7 @@ static void unlockBtreeIfUnused(Btree *pBt){
** Create a new database by initializing the first page of the
** file.
*/
-static int newDatabase(Btree *pBt){
+static int newDatabase(BtShared *pBt){
MemPage *pP1;
unsigned char *data;
int rc;
@@ -1613,14 +2103,17 @@ static int newDatabase(Btree *pBt){
** when A already has a read lock, we encourage A to give up and let B
** proceed.
*/
-int sqlite3BtreeBeginTrans(Btree *pBt, int wrflag){
+int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
+ BtShared *pBt = p->pBt;
int rc = SQLITE_OK;
+ btreeIntegrity(p);
+
/* If the btree is already in a write-transaction, or it
** is already in a read-transaction and a read-transaction
** is requested, this is a no-op.
*/
- if( pBt->inTrans==TRANS_WRITE || (pBt->inTrans==TRANS_READ && !wrflag) ){
+ if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
return SQLITE_OK;
}
@@ -1629,6 +2122,14 @@ int sqlite3BtreeBeginTrans(Btree *pBt, int wrflag){
return SQLITE_READONLY;
}
+ /* If another database handle has already opened a write transaction
+ ** on this shared-btree structure and a second write transaction is
+ ** requested, return SQLITE_BUSY.
+ */
+ if( pBt->inTransaction==TRANS_WRITE && wrflag ){
+ return SQLITE_BUSY;
+ }
+
do {
if( pBt->pPage1==0 ){
rc = lockBtree(pBt);
@@ -1642,13 +2143,24 @@ int sqlite3BtreeBeginTrans(Btree *pBt, int wrflag){
}
if( rc==SQLITE_OK ){
- pBt->inTrans = (wrflag?TRANS_WRITE:TRANS_READ);
if( wrflag ) pBt->inStmt = 0;
}else{
unlockBtreeIfUnused(pBt);
}
- }while( rc==SQLITE_BUSY && pBt->inTrans==TRANS_NONE &&
+ }while( rc==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
sqlite3InvokeBusyHandler(pBt->pBusyHandler) );
+
+ if( rc==SQLITE_OK ){
+ if( p->inTrans==TRANS_NONE ){
+ pBt->nTransaction++;
+ }
+ p->inTrans = (wrflag?TRANS_WRITE:TRANS_READ);
+ if( p->inTrans>pBt->inTransaction ){
+ pBt->inTransaction = p->inTrans;
+ }
+ }
+
+ btreeIntegrity(p);
return rc;
}
@@ -1663,7 +2175,7 @@ static int setChildPtrmaps(MemPage *pPage){
int i; /* Counter variable */
int nCell; /* Number of cells in page pPage */
int rc = SQLITE_OK; /* Return code */
- Btree *pBt = pPage->pBt;
+ BtShared *pBt = pPage->pBt;
int isInitOrig = pPage->isInit;
Pgno pgno = pPage->pgno;
@@ -1763,7 +2275,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
** database. The pDbPage reference remains valid.
*/
static int relocatePage(
- Btree *pBt, /* Btree */
+ BtShared *pBt, /* Btree */
MemPage *pDbPage, /* Open page to move */
u8 eType, /* Pointer map 'type' entry for pDbPage */
Pgno iPtrPage, /* Pointer map 'page-no' entry for pDbPage */
@@ -1833,19 +2345,19 @@ static int relocatePage(
}
/* Forward declaration required by autoVacuumCommit(). */
-static int allocatePage(Btree *, MemPage **, Pgno *, Pgno, u8);
+static int allocatePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
/*
** This routine is called prior to sqlite3pager_commit when a transaction
** is commited for an auto-vacuum database.
*/
-static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){
+static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
Pager *pPager = pBt->pPager;
- Pgno nFreeList; /* Number of pages remaining on the free-list. */
- int nPtrMap; /* Number of pointer-map pages deallocated */
- Pgno origSize; /* Pages in the database file */
- Pgno finSize; /* Pages in the database file after truncation */
- int rc; /* Return code */
+ Pgno nFreeList; /* Number of pages remaining on the free-list. */
+ int nPtrMap; /* Number of pointer-map pages deallocated */
+ Pgno origSize; /* Pages in the database file */
+ Pgno finSize; /* Pages in the database file after truncation */
+ int rc; /* Return code */
u8 eType;
int pgsz = pBt->pageSize; /* Page size for this database */
Pgno iDbPage; /* The database page to move */
@@ -1855,11 +2367,11 @@ static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){
MemPage *pFreeMemPage = 0; /* "" */
#ifndef NDEBUG
- int nRef = *sqlite3pager_stats(pPager);
+ int nRef = sqlite3pager_refcount(pPager);
#endif
assert( pBt->autoVacuum );
- if( PTRMAP_ISPAGE(pgsz, sqlite3pager_pagecount(pPager)) ){
+ if( PTRMAP_ISPAGE(pBt, sqlite3pager_pagecount(pPager)) ){
return SQLITE_CORRUPT_BKPT;
}
@@ -1872,14 +2384,26 @@ static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){
return SQLITE_OK;
}
+ /* This block figures out how many pages there are in the database
+ ** now (variable origSize), and how many there will be after the
+ ** truncation (variable finSize).
+ **
+ ** The final size is the original size, less the number of free pages
+ ** in the database, less any pointer-map pages that will no longer
+ ** be required, less 1 if the pending-byte page was part of the database
+ ** but is not after the truncation.
+ **/
origSize = sqlite3pager_pagecount(pPager);
- nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pgsz, origSize)+pgsz/5)/(pgsz/5);
+ if( origSize==PENDING_BYTE_PAGE(pBt) ){
+ origSize--;
+ }
+ nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pBt, origSize)+pgsz/5)/(pgsz/5);
finSize = origSize - nFreeList - nPtrMap;
- if( origSize>=PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){
+ if( origSize>PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){
+ finSize--;
+ }
+ while( PTRMAP_ISPAGE(pBt, finSize) || finSize==PENDING_BYTE_PAGE(pBt) ){
finSize--;
- if( PTRMAP_ISPAGE(pBt->usableSize, finSize) ){
- finSize--;
- }
}
TRACE(("AUTOVACUUM: Begin (db size %d->%d)\n", origSize, finSize));
@@ -1891,7 +2415,7 @@ static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){
*/
for( iDbPage=finSize+1; iDbPage<=origSize; iDbPage++ ){
/* If iDbPage is a pointer map page, or the pending-byte page, skip it. */
- if( PTRMAP_ISPAGE(pgsz, iDbPage) || iDbPage==PENDING_BYTE_PAGE(pBt) ){
+ if( PTRMAP_ISPAGE(pBt, iDbPage) || iDbPage==PENDING_BYTE_PAGE(pBt) ){
continue;
}
@@ -1928,6 +2452,12 @@ static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){
releasePage(pFreeMemPage);
pFreeMemPage = 0;
+ /* Relocate the page into the body of the file. Note that although the
+ ** page has moved within the database file, the pDbMemPage pointer
+ ** remains valid. This means that this function can run without
+ ** invalidating cursors open on the btree. This is important in
+ ** shared-cache mode.
+ */
rc = relocatePage(pBt, pDbMemPage, eType, iPtrPage, iFreePage);
releasePage(pDbMemPage);
if( rc!=SQLITE_OK ) goto autovacuum_out;
@@ -1941,11 +2471,11 @@ static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){
if( rc!=SQLITE_OK ) goto autovacuum_out;
put4byte(&pBt->pPage1->aData[32], 0);
put4byte(&pBt->pPage1->aData[36], 0);
- if( rc!=SQLITE_OK ) goto autovacuum_out;
*nTrunc = finSize;
+ assert( finSize!=PENDING_BYTE_PAGE(pBt) );
autovacuum_out:
- assert( nRef==*sqlite3pager_stats(pPager) );
+ assert( nRef==sqlite3pager_refcount(pPager) );
if( rc!=SQLITE_OK ){
sqlite3pager_rollback(pPager);
}
@@ -1959,15 +2489,47 @@ autovacuum_out:
** This will release the write lock on the database file. If there
** are no active cursors, it also releases the read lock.
*/
-int sqlite3BtreeCommit(Btree *pBt){
- int rc = SQLITE_OK;
- if( pBt->inTrans==TRANS_WRITE ){
+int sqlite3BtreeCommit(Btree *p){
+ BtShared *pBt = p->pBt;
+
+ btreeIntegrity(p);
+
+ /* If the handle has a write-transaction open, commit the shared-btrees
+ ** transaction and set the shared state to TRANS_READ.
+ */
+ if( p->inTrans==TRANS_WRITE ){
+ int rc;
+ assert( pBt->inTransaction==TRANS_WRITE );
+ assert( pBt->nTransaction>0 );
rc = sqlite3pager_commit(pBt->pPager);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ pBt->inTransaction = TRANS_READ;
+ pBt->inStmt = 0;
}
- pBt->inTrans = TRANS_NONE;
- pBt->inStmt = 0;
+ unlockAllTables(p);
+
+ /* If the handle has any kind of transaction open, decrement the transaction
+ ** count of the shared btree. If the transaction count reaches 0, set
+ ** the shared state to TRANS_NONE. The unlockBtreeIfUnused() call below
+ ** will unlock the pager.
+ */
+ if( p->inTrans!=TRANS_NONE ){
+ pBt->nTransaction--;
+ if( 0==pBt->nTransaction ){
+ pBt->inTransaction = TRANS_NONE;
+ }
+ }
+
+ /* Set the handles current transaction state to TRANS_NONE and unlock
+ ** the pager if this call closed the only read or write transaction.
+ */
+ p->inTrans = TRANS_NONE;
unlockBtreeIfUnused(pBt);
- return rc;
+
+ btreeIntegrity(p);
+ return SQLITE_OK;
}
#ifndef NDEBUG
@@ -1976,29 +2538,30 @@ int sqlite3BtreeCommit(Btree *pBt){
** in assert() expressions, so it is only compiled if NDEBUG is not
** defined.
*/
-static int countWriteCursors(Btree *pBt){
+static int countWriteCursors(BtShared *pBt){
BtCursor *pCur;
int r = 0;
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
- if( pCur->wrFlag ) r++;
+ if( pCur->wrFlag ) r++;
}
return r;
}
#endif
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
/*
** Print debugging information about all cursors to standard output.
*/
-void sqlite3BtreeCursorList(Btree *pBt){
+void sqlite3BtreeCursorList(Btree *p){
BtCursor *pCur;
+ BtShared *pBt = p->pBt;
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
MemPage *pPage = pCur->pPage;
char *zMode = pCur->wrFlag ? "rw" : "ro";
sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n",
pCur, pCur->pgnoRoot, zMode,
pPage ? pPage->pgno : 0, pCur->idx,
- pCur->isValid ? "" : " eof"
+ (pCur->eState==CURSOR_VALID) ? "" : " eof"
);
}
}
@@ -2013,11 +2576,41 @@ void sqlite3BtreeCursorList(Btree *pBt){
** This will release the write lock on the database file. If there
** are no active cursors, it also releases the read lock.
*/
-int sqlite3BtreeRollback(Btree *pBt){
- int rc = SQLITE_OK;
+int sqlite3BtreeRollback(Btree *p){
+ int rc;
+ BtShared *pBt = p->pBt;
MemPage *pPage1;
- if( pBt->inTrans==TRANS_WRITE ){
- rc = sqlite3pager_rollback(pBt->pPager);
+
+ rc = saveAllCursors(pBt, 0, 0);
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ if( rc!=SQLITE_OK ){
+ /* This is a horrible situation. An IO or malloc() error occured whilst
+ ** trying to save cursor positions. If this is an automatic rollback (as
+ ** the result of a constraint, malloc() failure or IO error) then
+ ** the cache may be internally inconsistent (not contain valid trees) so
+ ** we cannot simply return the error to the caller. Instead, abort
+ ** all queries that may be using any of the cursors that failed to save.
+ */
+ while( pBt->pCursor ){
+ sqlite3 *db = pBt->pCursor->pBtree->pSqlite;
+ if( db ){
+ sqlite3AbortOtherActiveVdbes(db, 0);
+ }
+ }
+ }
+#endif
+ btreeIntegrity(p);
+ unlockAllTables(p);
+
+ if( p->inTrans==TRANS_WRITE ){
+ int rc2;
+
+ assert( TRANS_WRITE==pBt->inTransaction );
+ rc2 = sqlite3pager_rollback(pBt->pPager);
+ if( rc2!=SQLITE_OK ){
+ rc = rc2;
+ }
+
/* The rollback may have destroyed the pPage1->aData value. So
** call getPage() on page 1 again to make sure pPage1->aData is
** set correctly. */
@@ -2025,10 +2618,22 @@ int sqlite3BtreeRollback(Btree *pBt){
releasePage(pPage1);
}
assert( countWriteCursors(pBt)==0 );
+ pBt->inTransaction = TRANS_READ;
}
- pBt->inTrans = TRANS_NONE;
+
+ if( p->inTrans!=TRANS_NONE ){
+ assert( pBt->nTransaction>0 );
+ pBt->nTransaction--;
+ if( 0==pBt->nTransaction ){
+ pBt->inTransaction = TRANS_NONE;
+ }
+ }
+
+ p->inTrans = TRANS_NONE;
pBt->inStmt = 0;
unlockBtreeIfUnused(pBt);
+
+ btreeIntegrity(p);
return rc;
}
@@ -2047,11 +2652,13 @@ int sqlite3BtreeRollback(Btree *pBt){
** error occurs within the statement, the effect of that one statement
** can be rolled back without having to rollback the entire transaction.
*/
-int sqlite3BtreeBeginStmt(Btree *pBt){
+int sqlite3BtreeBeginStmt(Btree *p){
int rc;
- if( (pBt->inTrans!=TRANS_WRITE) || pBt->inStmt ){
+ BtShared *pBt = p->pBt;
+ if( (p->inTrans!=TRANS_WRITE) || pBt->inStmt ){
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}
+ assert( pBt->inTransaction==TRANS_WRITE );
rc = pBt->readOnly ? SQLITE_OK : sqlite3pager_stmt_begin(pBt->pPager);
pBt->inStmt = 1;
return rc;
@@ -2062,8 +2669,9 @@ int sqlite3BtreeBeginStmt(Btree *pBt){
** Commit the statment subtransaction currently in progress. If no
** subtransaction is active, this is a no-op.
*/
-int sqlite3BtreeCommitStmt(Btree *pBt){
+int sqlite3BtreeCommitStmt(Btree *p){
int rc;
+ BtShared *pBt = p->pBt;
if( pBt->inStmt && !pBt->readOnly ){
rc = sqlite3pager_stmt_commit(pBt->pPager);
}else{
@@ -2081,12 +2689,16 @@ int sqlite3BtreeCommitStmt(Btree *pBt){
** to use a cursor that was open at the beginning of this operation
** will result in an error.
*/
-int sqlite3BtreeRollbackStmt(Btree *pBt){
- int rc;
- if( pBt->inStmt==0 || pBt->readOnly ) return SQLITE_OK;
- rc = sqlite3pager_stmt_rollback(pBt->pPager);
- assert( countWriteCursors(pBt)==0 );
- pBt->inStmt = 0;
+int sqlite3BtreeRollbackStmt(Btree *p){
+ int rc = SQLITE_OK;
+ BtShared *pBt = p->pBt;
+ sqlite3MallocDisallow();
+ if( pBt->inStmt && !pBt->readOnly ){
+ rc = sqlite3pager_stmt_rollback(pBt->pPager);
+ assert( countWriteCursors(pBt)==0 );
+ pBt->inStmt = 0;
+ }
+ sqlite3MallocAllow();
return rc;
}
@@ -2150,7 +2762,7 @@ static int dfltCompare(
** always ignored for INTKEY tables.
*/
int sqlite3BtreeCursor(
- Btree *pBt, /* The btree */
+ Btree *p, /* The btree */
int iTable, /* Root page of table to open */
int wrFlag, /* 1 to write. 0 read-only */
int (*xCmp)(void*,int,const void*,int,const void*), /* Key Comparison func */
@@ -2159,6 +2771,7 @@ int sqlite3BtreeCursor(
){
int rc;
BtCursor *pCur;
+ BtShared *pBt = p->pBt;
*ppCur = 0;
if( wrFlag ){
@@ -2169,19 +2782,19 @@ int sqlite3BtreeCursor(
return SQLITE_LOCKED;
}
}
+
if( pBt->pPage1==0 ){
- rc = lockBtreeWithRetry(pBt);
+ rc = lockBtreeWithRetry(p);
if( rc!=SQLITE_OK ){
return rc;
}
}
- pCur = sqliteMallocRaw( sizeof(*pCur) );
+ pCur = sqliteMalloc( sizeof(*pCur) );
if( pCur==0 ){
rc = SQLITE_NOMEM;
goto create_cursor_exception;
}
pCur->pgnoRoot = (Pgno)iTable;
- pCur->pPage = 0; /* For exit-handler, in case getAndInitPage() fails. */
if( iTable==1 && sqlite3pager_pagecount(pBt->pPager)==0 ){
rc = SQLITE_EMPTY;
goto create_cursor_exception;
@@ -2190,22 +2803,24 @@ int sqlite3BtreeCursor(
if( rc!=SQLITE_OK ){
goto create_cursor_exception;
}
+
+ /* Now that no other errors can occur, finish filling in the BtCursor
+ ** variables, link the cursor into the BtShared list and set *ppCur (the
+ ** output argument to this function).
+ */
pCur->xCompare = xCmp ? xCmp : dfltCompare;
pCur->pArg = pArg;
- pCur->pBt = pBt;
+ pCur->pBtree = p;
pCur->wrFlag = wrFlag;
- pCur->idx = 0;
- memset(&pCur->info, 0, sizeof(pCur->info));
pCur->pNext = pBt->pCursor;
if( pCur->pNext ){
pCur->pNext->pPrev = pCur;
}
- pCur->pPrev = 0;
pBt->pCursor = pCur;
- pCur->isValid = 0;
+ pCur->eState = CURSOR_INVALID;
*ppCur = pCur;
- return SQLITE_OK;
+ return SQLITE_OK;
create_cursor_exception:
if( pCur ){
releasePage(pCur->pPage);
@@ -2234,7 +2849,8 @@ void sqlite3BtreeSetCompare(
** when the last cursor is closed.
*/
int sqlite3BtreeCloseCursor(BtCursor *pCur){
- Btree *pBt = pCur->pBt;
+ BtShared *pBt = pCur->pBtree->pBt;
+ restoreOrClearCursorPosition(pCur, 0);
if( pCur->pPrev ){
pCur->pPrev->pNext = pCur->pNext;
}else{
@@ -2301,13 +2917,17 @@ static void getCellInfo(BtCursor *pCur){
** itself, not the number of bytes in the key.
*/
int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
- if( !pCur->isValid ){
- *pSize = 0;
- }else{
- getCellInfo(pCur);
- *pSize = pCur->info.nKey;
+ int rc = restoreOrClearCursorPosition(pCur, 1);
+ if( rc==SQLITE_OK ){
+ assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID );
+ if( pCur->eState==CURSOR_INVALID ){
+ *pSize = 0;
+ }else{
+ getCellInfo(pCur);
+ *pSize = pCur->info.nKey;
+ }
}
- return SQLITE_OK;
+ return rc;
}
/*
@@ -2318,14 +2938,18 @@ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
** the database is empty) then *pSize is set to 0.
*/
int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
- if( !pCur->isValid ){
- /* Not pointing at a valid entry - set *pSize to 0. */
- *pSize = 0;
- }else{
- getCellInfo(pCur);
- *pSize = pCur->info.nData;
+ int rc = restoreOrClearCursorPosition(pCur, 1);
+ if( rc==SQLITE_OK ){
+ assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID );
+ if( pCur->eState==CURSOR_INVALID ){
+ /* Not pointing at a valid entry - set *pSize to 0. */
+ *pSize = 0;
+ }else{
+ getCellInfo(pCur);
+ *pSize = pCur->info.nData;
+ }
}
- return SQLITE_OK;
+ return rc;
}
/*
@@ -2348,19 +2972,18 @@ static int getPayload(
Pgno nextPage;
int rc;
MemPage *pPage;
- Btree *pBt;
+ BtShared *pBt;
int ovflSize;
u32 nKey;
assert( pCur!=0 && pCur->pPage!=0 );
- assert( pCur->isValid );
- pBt = pCur->pBt;
+ assert( pCur->eState==CURSOR_VALID );
+ pBt = pCur->pBtree->pBt;
pPage = pCur->pPage;
pageIntegrity(pPage);
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
getCellInfo(pCur);
- aPayload = pCur->info.pCell;
- aPayload += pCur->info.nHeader;
+ aPayload = pCur->info.pCell + pCur->info.nHeader;
if( pPage->intKey ){
nKey = 0;
}else{
@@ -2429,14 +3052,18 @@ static int getPayload(
** the available payload.
*/
int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
- assert( pCur->isValid );
- assert( pCur->pPage!=0 );
- if( pCur->pPage->intKey ){
- return SQLITE_CORRUPT_BKPT;
+ int rc = restoreOrClearCursorPosition(pCur, 1);
+ if( rc==SQLITE_OK ){
+ assert( pCur->eState==CURSOR_VALID );
+ assert( pCur->pPage!=0 );
+ if( pCur->pPage->intKey ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ assert( pCur->pPage->intKey==0 );
+ assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
+ rc = getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
}
- assert( pCur->pPage->intKey==0 );
- assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
- return getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
+ return rc;
}
/*
@@ -2449,10 +3076,14 @@ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
** the available payload.
*/
int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
- assert( pCur->isValid );
- assert( pCur->pPage!=0 );
- assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
- return getPayload(pCur, offset, amt, pBuf, 1);
+ int rc = restoreOrClearCursorPosition(pCur, 1);
+ if( rc==SQLITE_OK ){
+ assert( pCur->eState==CURSOR_VALID );
+ assert( pCur->pPage!=0 );
+ assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
+ rc = getPayload(pCur, offset, amt, pBuf, 1);
+ }
+ return rc;
}
/*
@@ -2485,7 +3116,7 @@ static const unsigned char *fetchPayload(
int nLocal;
assert( pCur!=0 && pCur->pPage!=0 );
- assert( pCur->isValid );
+ assert( pCur->eState==CURSOR_VALID );
pPage = pCur->pPage;
pageIntegrity(pPage);
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
@@ -2523,10 +3154,16 @@ static const unsigned char *fetchPayload(
** in the common case where no overflow pages are used.
*/
const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){
- return (const void*)fetchPayload(pCur, pAmt, 0);
+ if( pCur->eState==CURSOR_VALID ){
+ return (const void*)fetchPayload(pCur, pAmt, 0);
+ }
+ return 0;
}
const void *sqlite3BtreeDataFetch(BtCursor *pCur, int *pAmt){
- return (const void*)fetchPayload(pCur, pAmt, 1);
+ if( pCur->eState==CURSOR_VALID ){
+ return (const void*)fetchPayload(pCur, pAmt, 1);
+ }
+ return 0;
}
@@ -2538,9 +3175,9 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
int rc;
MemPage *pNewPage;
MemPage *pOldPage;
- Btree *pBt = pCur->pBt;
+ BtShared *pBt = pCur->pBtree->pBt;
- assert( pCur->isValid );
+ assert( pCur->eState==CURSOR_VALID );
rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage);
if( rc ) return rc;
pageIntegrity(pNewPage);
@@ -2587,7 +3224,7 @@ static void moveToParent(BtCursor *pCur){
MemPage *pPage;
int idxParent;
- assert( pCur->isValid );
+ assert( pCur->eState==CURSOR_VALID );
pPage = pCur->pPage;
assert( pPage!=0 );
assert( !isRootPage(pPage) );
@@ -2609,17 +3246,24 @@ static void moveToParent(BtCursor *pCur){
*/
static int moveToRoot(BtCursor *pCur){
MemPage *pRoot;
- int rc;
- Btree *pBt = pCur->pBt;
+ int rc = SQLITE_OK;
+ BtShared *pBt = pCur->pBtree->pBt;
- rc = getAndInitPage(pBt, pCur->pgnoRoot, &pRoot, 0);
- if( rc ){
- pCur->isValid = 0;
- return rc;
+ restoreOrClearCursorPosition(pCur, 0);
+ pRoot = pCur->pPage;
+ if( pRoot && pRoot->pgno==pCur->pgnoRoot ){
+ assert( pRoot->isInit );
+ }else{
+ if(
+ SQLITE_OK!=(rc = getAndInitPage(pBt, pCur->pgnoRoot, &pRoot, 0))
+ ){
+ pCur->eState = CURSOR_INVALID;
+ return rc;
+ }
+ releasePage(pCur->pPage);
+ pageIntegrity(pRoot);
+ pCur->pPage = pRoot;
}
- releasePage(pCur->pPage);
- pageIntegrity(pRoot);
- pCur->pPage = pRoot;
pCur->idx = 0;
pCur->info.nSize = 0;
if( pRoot->nCell==0 && !pRoot->leaf ){
@@ -2627,23 +3271,26 @@ static int moveToRoot(BtCursor *pCur){
assert( pRoot->pgno==1 );
subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]);
assert( subpage>0 );
- pCur->isValid = 1;
+ pCur->eState = CURSOR_VALID;
rc = moveToChild(pCur, subpage);
}
- pCur->isValid = pCur->pPage->nCell>0;
+ pCur->eState = ((pCur->pPage->nCell>0)?CURSOR_VALID:CURSOR_INVALID);
return rc;
}
/*
** Move the cursor down to the left-most leaf entry beneath the
** entry to which it is currently pointing.
+**
+** The left-most leaf is the one with the smallest key - the first
+** in ascending order.
*/
static int moveToLeftmost(BtCursor *pCur){
Pgno pgno;
int rc;
MemPage *pPage;
- assert( pCur->isValid );
+ assert( pCur->eState==CURSOR_VALID );
while( !(pPage = pCur->pPage)->leaf ){
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
pgno = get4byte(findCell(pPage, pCur->idx));
@@ -2659,13 +3306,16 @@ static int moveToLeftmost(BtCursor *pCur){
** between moveToLeftmost() and moveToRightmost(). moveToLeftmost()
** finds the left-most entry beneath the *entry* whereas moveToRightmost()
** finds the right-most entry beneath the *page*.
+**
+** The right-most entry is the one with the largest key - the last
+** key in ascending order.
*/
static int moveToRightmost(BtCursor *pCur){
Pgno pgno;
int rc;
MemPage *pPage;
- assert( pCur->isValid );
+ assert( pCur->eState==CURSOR_VALID );
while( !(pPage = pCur->pPage)->leaf ){
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
pCur->idx = pPage->nCell;
@@ -2685,7 +3335,7 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
int rc;
rc = moveToRoot(pCur);
if( rc ) return rc;
- if( pCur->isValid==0 ){
+ if( pCur->eState==CURSOR_INVALID ){
assert( pCur->pPage->nCell==0 );
*pRes = 1;
return SQLITE_OK;
@@ -2704,12 +3354,12 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
int rc;
rc = moveToRoot(pCur);
if( rc ) return rc;
- if( pCur->isValid==0 ){
+ if( CURSOR_INVALID==pCur->eState ){
assert( pCur->pPage->nCell==0 );
*pRes = 1;
return SQLITE_OK;
}
- assert( pCur->isValid );
+ assert( pCur->eState==CURSOR_VALID );
*pRes = 0;
rc = moveToRightmost(pCur);
return rc;
@@ -2720,7 +3370,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
**
** For INTKEY tables, only the nKey parameter is used. pKey is
** ignored. For other tables, nKey is the number of bytes of data
-** in nKey. The comparison function specified when the cursor was
+** in pKey. The comparison function specified when the cursor was
** created is used to compare keys.
**
** If an exact match is not found, then the cursor is always
@@ -2744,11 +3394,13 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
*/
int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
int rc;
+ int tryRightmost;
rc = moveToRoot(pCur);
if( rc ) return rc;
assert( pCur->pPage );
assert( pCur->pPage->isInit );
- if( pCur->isValid==0 ){
+ tryRightmost = pCur->pPage->intKey;
+ if( pCur->eState==CURSOR_INVALID ){
*pRes = -1;
assert( pCur->pPage->nCell==0 );
return SQLITE_OK;
@@ -2769,18 +3421,29 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
i64 nCellKey;
pCur->idx = (lwr+upr)/2;
pCur->info.nSize = 0;
- sqlite3BtreeKeySize(pCur, &nCellKey);
if( pPage->intKey ){
+ u8 *pCell;
+ if( tryRightmost ){
+ pCur->idx = upr;
+ }
+ pCell = findCell(pPage, pCur->idx) + pPage->childPtrSize;
+ if( pPage->hasData ){
+ u32 dummy;
+ pCell += getVarint32(pCell, &dummy);
+ }
+ getVarint(pCell, (u64 *)&nCellKey);
if( nCellKey<nKey ){
c = -1;
}else if( nCellKey>nKey ){
c = +1;
+ tryRightmost = 0;
}else{
c = 0;
}
}else{
int available;
pCellKey = (void *)fetchPayload(pCur, &available, 0);
+ nCellKey = pCur->info.nKey;
if( available>=nCellKey ){
c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey);
}else{
@@ -2840,7 +3503,11 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
** the first entry. TRUE is also returned if the table is empty.
*/
int sqlite3BtreeEof(BtCursor *pCur){
- return pCur->isValid==0;
+ /* TODO: What if the cursor is in CURSOR_REQUIRESEEK but all table entries
+ ** have been deleted? This API will need to change to return an error code
+ ** as well as the boolean result value.
+ */
+ return (CURSOR_VALID!=pCur->eState);
}
/*
@@ -2851,10 +3518,24 @@ int sqlite3BtreeEof(BtCursor *pCur){
*/
int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
int rc;
- MemPage *pPage = pCur->pPage;
+ MemPage *pPage;
+
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ rc = restoreOrClearCursorPosition(pCur, 1);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ if( pCur->skip>0 ){
+ pCur->skip = 0;
+ *pRes = 0;
+ return SQLITE_OK;
+ }
+ pCur->skip = 0;
+#endif
assert( pRes!=0 );
- if( pCur->isValid==0 ){
+ pPage = pCur->pPage;
+ if( CURSOR_INVALID==pCur->eState ){
*pRes = 1;
return SQLITE_OK;
}
@@ -2874,7 +3555,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
do{
if( isRootPage(pPage) ){
*pRes = 1;
- pCur->isValid = 0;
+ pCur->eState = CURSOR_INVALID;
return SQLITE_OK;
}
moveToParent(pCur);
@@ -2906,7 +3587,21 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
int rc;
Pgno pgno;
MemPage *pPage;
- if( pCur->isValid==0 ){
+
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ rc = restoreOrClearCursorPosition(pCur, 1);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ if( pCur->skip<0 ){
+ pCur->skip = 0;
+ *pRes = 0;
+ return SQLITE_OK;
+ }
+ pCur->skip = 0;
+#endif
+
+ if( CURSOR_INVALID==pCur->eState ){
*pRes = 1;
return SQLITE_OK;
}
@@ -2922,7 +3617,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
}else{
while( pCur->idx==0 ){
if( isRootPage(pPage) ){
- pCur->isValid = 0;
+ pCur->eState = CURSOR_INVALID;
*pRes = 1;
return SQLITE_OK;
}
@@ -2963,7 +3658,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
** is only used by auto-vacuum databases when allocating a new table.
*/
static int allocatePage(
- Btree *pBt,
+ BtShared *pBt,
MemPage **ppPage,
Pgno *pPgno,
Pgno nearby,
@@ -3150,7 +3845,7 @@ static int allocatePage(
*pPgno = sqlite3pager_pagecount(pBt->pPager) + 1;
#ifndef SQLITE_OMIT_AUTOVACUUM
- if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt->usableSize, *pPgno) ){
+ if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, *pPgno) ){
/* If *pPgno refers to a pointer-map page, allocate two new pages
** at the end of the file instead of one. The first allocated page
** becomes a new pointer-map page, the second is used by the caller.
@@ -3181,7 +3876,7 @@ static int allocatePage(
** sqlite3pager_unref() is NOT called for pPage.
*/
static int freePage(MemPage *pPage){
- Btree *pBt = pPage->pBt;
+ BtShared *pBt = pPage->pBt;
MemPage *pPage1 = pBt->pPage1;
int rc, n, k;
@@ -3197,6 +3892,15 @@ static int freePage(MemPage *pPage){
n = get4byte(&pPage1->aData[36]);
put4byte(&pPage1->aData[36], n+1);
+#ifdef SQLITE_SECURE_DELETE
+ /* If the SQLITE_SECURE_DELETE compile-time option is enabled, then
+ ** always fully overwrite deleted information with zeros.
+ */
+ rc = sqlite3pager_write(pPage->aData);
+ if( rc ) return rc;
+ memset(pPage->aData, 0, pPage->pBt->pageSize);
+#endif
+
#ifndef SQLITE_OMIT_AUTOVACUUM
/* If the database supports auto-vacuum, write an entry in the pointer-map
** to indicate that the page is free.
@@ -3237,7 +3941,9 @@ static int freePage(MemPage *pPage){
if( rc ) return rc;
put4byte(&pTrunk->aData[4], k+1);
put4byte(&pTrunk->aData[8+k*4], pPage->pgno);
+#ifndef SQLITE_SECURE_DELETE
sqlite3pager_dont_write(pBt->pPager, pPage->pgno);
+#endif
TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno));
}
releasePage(pTrunk);
@@ -3249,7 +3955,7 @@ static int freePage(MemPage *pPage){
** Free any overflow pages associated with the given Cell.
*/
static int clearCell(MemPage *pPage, unsigned char *pCell){
- Btree *pBt = pPage->pBt;
+ BtShared *pBt = pPage->pBt;
CellInfo info;
Pgno ovflPgno;
int rc;
@@ -3301,7 +4007,7 @@ static int fillInCell(
MemPage *pToRelease = 0;
unsigned char *pPrior;
unsigned char *pPayload;
- Btree *pBt = pPage->pBt;
+ BtShared *pBt = pPage->pBt;
Pgno pgnoOvfl = 0;
int nHeader;
CellInfo info;
@@ -3370,6 +4076,7 @@ static int fillInCell(
n = nPayload;
if( n>spaceLeft ) n = spaceLeft;
if( n>nSrc ) n = nSrc;
+ assert( pSrc );
memcpy(pPayload, pSrc, n);
nPayload -= n;
pPayload += n;
@@ -3390,10 +4097,11 @@ static int fillInCell(
** given in the second argument so that MemPage.pParent holds the
** pointer in the third argument.
*/
-static int reparentPage(Btree *pBt, Pgno pgno, MemPage *pNewParent, int idx){
+static int reparentPage(BtShared *pBt, Pgno pgno, MemPage *pNewParent, int idx){
MemPage *pThis;
unsigned char *aData;
+ assert( pNewParent!=0 );
if( pgno==0 ) return SQLITE_OK;
assert( pBt->pPager!=0 );
aData = sqlite3pager_lookup(pBt->pPager, pgno);
@@ -3404,7 +4112,7 @@ static int reparentPage(Btree *pBt, Pgno pgno, MemPage *pNewParent, int idx){
if( pThis->pParent!=pNewParent ){
if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData);
pThis->pParent = pNewParent;
- if( pNewParent ) sqlite3pager_ref(pNewParent->aData);
+ sqlite3pager_ref(pNewParent->aData);
}
pThis->idxParent = idx;
}
@@ -3433,7 +4141,7 @@ static int reparentPage(Btree *pBt, Pgno pgno, MemPage *pNewParent, int idx){
*/
static int reparentChildPages(MemPage *pPage){
int i;
- Btree *pBt = pPage->pBt;
+ BtShared *pBt = pPage->pBt;
int rc = SQLITE_OK;
if( pPage->leaf ) return SQLITE_OK;
@@ -3666,7 +4374,7 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){
u8 *pCell;
int szCell;
CellInfo info;
- Btree *pBt = pPage->pBt;
+ BtShared *pBt = pPage->pBt;
int parentIdx = pParent->nCell; /* pParent new divider cell index */
int parentSize; /* Size of new divider cell */
u8 parentCell[64]; /* Space for the new divider cell */
@@ -3775,7 +4483,7 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){
*/
static int balance_nonroot(MemPage *pPage){
MemPage *pParent; /* The parent of pPage */
- Btree *pBt; /* The whole database */
+ BtShared *pBt; /* The whole database */
int nCell = 0; /* Number of cells in apCell[] */
int nMaxCells = 0; /* Allocated size of apCell, szCell, aFrom. */
int nOld; /* Number of pages in apOld[] */
@@ -3796,7 +4504,6 @@ static int balance_nonroot(MemPage *pPage){
MemPage *apCopy[NB]; /* Private copies of apOld[] pages */
MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */
Pgno pgnoNew[NB+2]; /* Page numbers for each page in apNew[] */
- int idxDiv[NB]; /* Indices of divider cells in pParent */
u8 *apDiv[NB]; /* Divider cells in pParent */
int cntNew[NB+2]; /* Index in aCell[] of cell after i-th page */
int szNew[NB+2]; /* Combined size of cells place on i-th page */
@@ -3815,8 +4522,10 @@ static int balance_nonroot(MemPage *pPage){
assert( sqlite3pager_iswriteable(pPage->aData) );
pBt = pPage->pBt;
pParent = pPage->pParent;
- sqlite3pager_write(pParent->aData);
assert( pParent );
+ if( SQLITE_OK!=(rc = sqlite3pager_write(pParent->aData)) ){
+ return rc;
+ }
TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno));
#ifndef SQLITE_OMIT_QUICKBALANCE
@@ -3888,7 +4597,6 @@ static int balance_nonroot(MemPage *pPage){
nDiv = 0;
for(i=0, k=nxDiv; i<NB; i++, k++){
if( k<pParent->nCell ){
- idxDiv[i] = k;
apDiv[i] = findCell(pParent, k);
nDiv++;
assert( !pParent->leaf );
@@ -4117,6 +4825,7 @@ static int balance_nonroot(MemPage *pPage){
rc = sqlite3pager_write(pNew->aData);
if( rc ) goto balance_cleanup;
}else{
+ assert( i>0 );
rc = allocatePage(pBt, &pNew, &pgnoNew[i], pgnoNew[i-1], 0);
if( rc ) goto balance_cleanup;
apNew[i] = pNew;
@@ -4268,6 +4977,8 @@ static int balance_nonroot(MemPage *pPage){
}
}
assert( j==nCell );
+ assert( nOld>0 );
+ assert( nNew>0 );
if( (pageFlags & PTF_LEAF)==0 ){
memcpy(&apNew[nNew-1]->aData[8], &apCopy[nOld-1]->aData[8], 4);
}
@@ -4326,7 +5037,7 @@ static int balance_shallower(MemPage *pPage){
MemPage *pChild; /* The only child page of pPage */
Pgno pgnoChild; /* Page number for pChild */
int rc = SQLITE_OK; /* Return code from subprocedures */
- Btree *pBt; /* The main BTree structure */
+ BtShared *pBt; /* The main BTree structure */
int mxCellPerPage; /* Maximum number of cells per page */
u8 **apCell; /* All cells from pages being balanced */
int *szCell; /* Local size of all cells */
@@ -4428,7 +5139,7 @@ static int balance_deeper(MemPage *pPage){
int rc; /* Return value from subprocedures */
MemPage *pChild; /* Pointer to a new child page */
Pgno pgnoChild; /* Page number of the new child page */
- Btree *pBt; /* The BTree */
+ BtShared *pBt; /* The BTree */
int usableSize; /* Total usable size of a page */
u8 *data; /* Content of the parent page */
u8 *cdata; /* Content of the child page */
@@ -4517,10 +5228,12 @@ static int balance(MemPage *pPage, int insert){
** a page entirely and we do not want to leave any cursors
** pointing to non-existant pages or cells.
*/
-static int checkReadLocks(Btree *pBt, Pgno pgnoRoot, BtCursor *pExclude){
+static int checkReadLocks(BtShared *pBt, Pgno pgnoRoot, BtCursor *pExclude){
BtCursor *p;
for(p=pBt->pCursor; p; p=p->pNext){
+ u32 flags = (p->pBtree->pSqlite ? p->pBtree->pSqlite->flags : 0);
if( p->pgnoRoot!=pgnoRoot || p==pExclude ) continue;
+ if( p->wrFlag==0 && flags&SQLITE_ReadUncommitted ) continue;
if( p->wrFlag==0 ) return SQLITE_LOCKED;
if( p->pPage->pgno!=p->pgnoRoot ){
moveToRoot(p);
@@ -4547,11 +5260,11 @@ int sqlite3BtreeInsert(
int loc;
int szNew;
MemPage *pPage;
- Btree *pBt = pCur->pBt;
+ BtShared *pBt = pCur->pBtree->pBt;
unsigned char *oldCell;
unsigned char *newCell = 0;
- if( pBt->inTrans!=TRANS_WRITE ){
+ if( pBt->inTransaction!=TRANS_WRITE ){
/* Must start a transaction before doing an insert */
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}
@@ -4562,8 +5275,16 @@ int sqlite3BtreeInsert(
if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
}
- rc = sqlite3BtreeMoveto(pCur, pKey, nKey, &loc);
- if( rc ) return rc;
+
+ /* Save the positions of any other cursors open on this table */
+ restoreOrClearCursorPosition(pCur, 0);
+ if(
+ SQLITE_OK!=(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) ||
+ SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, nKey, &loc))
+ ){
+ return rc;
+ }
+
pPage = pCur->pPage;
assert( pPage->intKey || nKey>=0 );
assert( pPage->leaf || !pPage->leafData );
@@ -4579,7 +5300,7 @@ int sqlite3BtreeInsert(
if( rc ) goto end_insert;
assert( szNew==cellSizePtr(pPage, newCell) );
assert( szNew<=MX_CELL_SIZE(pBt) );
- if( loc==0 && pCur->isValid ){
+ if( loc==0 && CURSOR_VALID==pCur->eState ){
int szOld;
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
oldCell = findCell(pPage, pCur->idx);
@@ -4619,10 +5340,10 @@ int sqlite3BtreeDelete(BtCursor *pCur){
unsigned char *pCell;
int rc;
Pgno pgnoChild = 0;
- Btree *pBt = pCur->pBt;
+ BtShared *pBt = pCur->pBtree->pBt;
assert( pPage->isInit );
- if( pBt->inTrans!=TRANS_WRITE ){
+ if( pBt->inTransaction!=TRANS_WRITE ){
/* Must start a transaction before doing a delete */
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}
@@ -4636,8 +5357,19 @@ int sqlite3BtreeDelete(BtCursor *pCur){
if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
}
- rc = sqlite3pager_write(pPage->aData);
- if( rc ) return rc;
+
+ /* Restore the current cursor position (a no-op if the cursor is not in
+ ** CURSOR_REQUIRESEEK state) and save the positions of any other cursors
+ ** open on the same table. Then call sqlite3pager_write() on the page
+ ** that the entry will be deleted from.
+ */
+ if(
+ (rc = restoreOrClearCursorPosition(pCur, 1))!=0 ||
+ (rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur))!=0 ||
+ (rc = sqlite3pager_write(pPage->aData))!=0
+ ){
+ return rc;
+ }
/* Locate the cell within it's page and leave pCell pointing to the
** data. The clearCell() call frees any overflow pages associated with the
@@ -4660,7 +5392,9 @@ int sqlite3BtreeDelete(BtCursor *pCur){
*/
BtCursor leafCur;
unsigned char *pNext;
- int szNext;
+ int szNext; /* The compiler warning is wrong: szNext is always
+ ** initialized before use. Adding an extra initialization
+ ** to silence the compiler slows down the code. */
int notUsed;
unsigned char *tempCell = 0;
assert( !pPage->leafData );
@@ -4722,11 +5456,12 @@ int sqlite3BtreeDelete(BtCursor *pCur){
** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys
** BTREE_ZERODATA Used for SQL indices
*/
-int sqlite3BtreeCreateTable(Btree *pBt, int *piTable, int flags){
+int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
+ BtShared *pBt = p->pBt;
MemPage *pRoot;
Pgno pgnoRoot;
int rc;
- if( pBt->inTrans!=TRANS_WRITE ){
+ if( pBt->inTransaction!=TRANS_WRITE ){
/* Must start a transaction first */
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}
@@ -4753,14 +5488,14 @@ int sqlite3BtreeCreateTable(Btree *pBt, int *piTable, int flags){
** root page of the new table should go. meta[3] is the largest root-page
** created so far, so the new root-page is (meta[3]+1).
*/
- rc = sqlite3BtreeGetMeta(pBt, 4, &pgnoRoot);
+ rc = sqlite3BtreeGetMeta(p, 4, &pgnoRoot);
if( rc!=SQLITE_OK ) return rc;
pgnoRoot++;
/* The new root-page may not be allocated on a pointer-map page, or the
** PENDING_BYTE page.
*/
- if( pgnoRoot==PTRMAP_PAGENO(pBt->usableSize, pgnoRoot) ||
+ if( pgnoRoot==PTRMAP_PAGENO(pBt, pgnoRoot) ||
pgnoRoot==PENDING_BYTE_PAGE(pBt) ){
pgnoRoot++;
}
@@ -4820,7 +5555,7 @@ int sqlite3BtreeCreateTable(Btree *pBt, int *piTable, int flags){
releasePage(pRoot);
return rc;
}
- rc = sqlite3BtreeUpdateMeta(pBt, 4, pgnoRoot);
+ rc = sqlite3BtreeUpdateMeta(p, 4, pgnoRoot);
if( rc ){
releasePage(pRoot);
return rc;
@@ -4843,7 +5578,7 @@ int sqlite3BtreeCreateTable(Btree *pBt, int *piTable, int flags){
** the page to the freelist.
*/
static int clearDatabasePage(
- Btree *pBt, /* The BTree that contains the table */
+ BtShared *pBt, /* The BTree that contains the table */
Pgno pgno, /* Page number to clear */
MemPage *pParent, /* Parent page. NULL for the root */
int freePageFlag /* Deallocate page if true */
@@ -4894,23 +5629,35 @@ cleardatabasepage_out:
** read cursors on the table. Open write cursors are moved to the
** root of the table.
*/
-int sqlite3BtreeClearTable(Btree *pBt, int iTable){
+int sqlite3BtreeClearTable(Btree *p, int iTable){
int rc;
BtCursor *pCur;
- if( pBt->inTrans!=TRANS_WRITE ){
+ BtShared *pBt = p->pBt;
+ sqlite3 *db = p->pSqlite;
+ if( p->inTrans!=TRANS_WRITE ){
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}
- for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
- if( pCur->pgnoRoot==(Pgno)iTable ){
- if( pCur->wrFlag==0 ) return SQLITE_LOCKED;
- moveToRoot(pCur);
+
+ /* If this connection is not in read-uncommitted mode and currently has
+ ** a read-cursor open on the table being cleared, return SQLITE_LOCKED.
+ */
+ if( 0==db || 0==(db->flags&SQLITE_ReadUncommitted) ){
+ for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
+ if( pCur->pBtree==p && pCur->pgnoRoot==(Pgno)iTable ){
+ if( 0==pCur->wrFlag ){
+ return SQLITE_LOCKED;
+ }
+ moveToRoot(pCur);
+ }
}
}
- rc = clearDatabasePage(pBt, (Pgno)iTable, 0, 0);
- if( rc ){
- sqlite3BtreeRollback(pBt);
+
+ /* Save the position of all cursors open on this table */
+ if( SQLITE_OK!=(rc = saveAllCursors(pBt, iTable, 0)) ){
+ return rc;
}
- return rc;
+
+ return clearDatabasePage(pBt, (Pgno)iTable, 0, 0);
}
/*
@@ -4933,11 +5680,12 @@ int sqlite3BtreeClearTable(Btree *pBt, int iTable){
** The last root page is recorded in meta[3] and the value of
** meta[3] is updated by this procedure.
*/
-int sqlite3BtreeDropTable(Btree *pBt, int iTable, int *piMoved){
+int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
int rc;
MemPage *pPage = 0;
+ BtShared *pBt = p->pBt;
- if( pBt->inTrans!=TRANS_WRITE ){
+ if( p->inTrans!=TRANS_WRITE ){
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}
@@ -4953,7 +5701,7 @@ int sqlite3BtreeDropTable(Btree *pBt, int iTable, int *piMoved){
rc = getPage(pBt, (Pgno)iTable, &pPage);
if( rc ) return rc;
- rc = sqlite3BtreeClearTable(pBt, iTable);
+ rc = sqlite3BtreeClearTable(p, iTable);
if( rc ){
releasePage(pPage);
return rc;
@@ -4968,7 +5716,7 @@ int sqlite3BtreeDropTable(Btree *pBt, int iTable, int *piMoved){
#else
if( pBt->autoVacuum ){
Pgno maxRootPgno;
- rc = sqlite3BtreeGetMeta(pBt, 4, &maxRootPgno);
+ rc = sqlite3BtreeGetMeta(p, 4, &maxRootPgno);
if( rc!=SQLITE_OK ){
releasePage(pPage);
return rc;
@@ -5020,12 +5768,12 @@ int sqlite3BtreeDropTable(Btree *pBt, int iTable, int *piMoved){
if( maxRootPgno==PENDING_BYTE_PAGE(pBt) ){
maxRootPgno--;
}
- if( maxRootPgno==PTRMAP_PAGENO(pBt->usableSize, maxRootPgno) ){
+ if( maxRootPgno==PTRMAP_PAGENO(pBt, maxRootPgno) ){
maxRootPgno--;
}
assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) );
- rc = sqlite3BtreeUpdateMeta(pBt, 4, maxRootPgno);
+ rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno);
}else{
rc = freePage(pPage);
releasePage(pPage);
@@ -5050,9 +5798,20 @@ int sqlite3BtreeDropTable(Btree *pBt, int iTable, int *piMoved){
** layer (and the SetCookie and ReadCookie opcodes) the number of
** free pages is not visible. So Cookie[0] is the same as Meta[1].
*/
-int sqlite3BtreeGetMeta(Btree *pBt, int idx, u32 *pMeta){
+int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
int rc;
unsigned char *pP1;
+ BtShared *pBt = p->pBt;
+
+ /* Reading a meta-data value requires a read-lock on page 1 (and hence
+ ** the sqlite_master table. We grab this lock regardless of whether or
+ ** not the SQLITE_ReadUncommitted flag is set (the table rooted at page
+ ** 1 is treated as a special case by queryTableLock() and lockTable()).
+ */
+ rc = queryTableLock(p, 1, READ_LOCK);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
assert( idx>=0 && idx<=15 );
rc = sqlite3pager_get(pBt->pPager, 1, (void**)&pP1);
@@ -5067,18 +5826,21 @@ int sqlite3BtreeGetMeta(Btree *pBt, int idx, u32 *pMeta){
if( idx==4 && *pMeta>0 ) pBt->readOnly = 1;
#endif
- return SQLITE_OK;
+ /* Grab the read-lock on page 1. */
+ rc = lockTable(p, 1, READ_LOCK);
+ return rc;
}
/*
** Write meta-information back into the database. Meta[0] is
** read-only and may not be written.
*/
-int sqlite3BtreeUpdateMeta(Btree *pBt, int idx, u32 iMeta){
+int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){
+ BtShared *pBt = p->pBt;
unsigned char *pP1;
int rc;
assert( idx>=1 && idx<=15 );
- if( pBt->inTrans!=TRANS_WRITE ){
+ if( p->inTrans!=TRANS_WRITE ){
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}
assert( pBt->pPage1!=0 );
@@ -5094,6 +5856,9 @@ int sqlite3BtreeUpdateMeta(Btree *pBt, int idx, u32 iMeta){
** is currently pointing to.
*/
int sqlite3BtreeFlags(BtCursor *pCur){
+ /* TODO: What about CURSOR_REQUIRESEEK state? Probably need to call
+ ** restoreOrClearCursorPosition() here.
+ */
MemPage *pPage = pCur->pPage;
return pPage ? pPage->aData[pPage->hdrOffset] : 0;
}
@@ -5103,7 +5868,7 @@ int sqlite3BtreeFlags(BtCursor *pCur){
** Print a disassembly of the given page on standard output. This routine
** is used for debugging and testing only.
*/
-static int btreePageDump(Btree *pBt, int pgno, int recursive, MemPage *pParent){
+static int btreePageDump(BtShared *pBt, int pgno, int recursive, MemPage *pParent){
int rc;
MemPage *pPage;
int i, j, c;
@@ -5199,12 +5964,12 @@ static int btreePageDump(Btree *pBt, int pgno, int recursive, MemPage *pParent){
fflush(stdout);
return SQLITE_OK;
}
-int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
- return btreePageDump(pBt, pgno, recursive, 0);
+int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){
+ return btreePageDump(p->pBt, pgno, recursive, 0);
}
#endif
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
/*
** Fill aResult[] with information about the entry and page that the
** cursor is pointing to.
@@ -5227,6 +5992,11 @@ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){
MemPage *pPage = pCur->pPage;
BtCursor tmpCur;
+ int rc = restoreOrClearCursorPosition(pCur, 1);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+
pageIntegrity(pPage);
assert( pPage->isInit );
getTempCursor(pCur, &tmpCur);
@@ -5273,8 +6043,8 @@ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){
** Return the pager associated with a BTree. This routine is used for
** testing and debugging only.
*/
-Pager *sqlite3BtreePager(Btree *pBt){
- return pBt->pPager;
+Pager *sqlite3BtreePager(Btree *p){
+ return p->pBt->pPager;
}
/*
@@ -5283,7 +6053,7 @@ Pager *sqlite3BtreePager(Btree *pBt){
*/
typedef struct IntegrityCk IntegrityCk;
struct IntegrityCk {
- Btree *pBt; /* The tree being checked out */
+ BtShared *pBt; /* The tree being checked out */
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
int nPage; /* Number of pages in the database */
int *anRef; /* Number of times each page is referenced */
@@ -5463,19 +6233,14 @@ static int checkTreePage(
IntegrityCk *pCheck, /* Context for the sanity check */
int iPage, /* Page number of the page to check */
MemPage *pParent, /* Parent page */
- char *zParentContext, /* Parent context */
- char *zLowerBound, /* All keys should be greater than this, if not NULL */
- int nLower, /* Number of characters in zLowerBound */
- char *zUpperBound, /* All keys should be less than this, if not NULL */
- int nUpper /* Number of characters in zUpperBound */
+ char *zParentContext /* Parent context */
){
MemPage *pPage;
int i, rc, depth, d2, pgno, cnt;
int hdr, cellStart;
int nCell;
u8 *data;
- BtCursor cur;
- Btree *pBt;
+ BtShared *pBt;
int usableSize;
char zContext[100];
char *hit;
@@ -5484,7 +6249,7 @@ static int checkTreePage(
/* Check that the page exists
*/
- cur.pBt = pBt = pCheck->pBt;
+ pBt = pCheck->pBt;
usableSize = pBt->usableSize;
if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage, zParentContext) ) return 0;
@@ -5502,7 +6267,6 @@ static int checkTreePage(
/* Check out all the cells.
*/
depth = 0;
- cur.pPage = pPage;
for(i=0; i<pPage->nCell; i++){
u8 *pCell;
int sz;
@@ -5535,7 +6299,7 @@ static int checkTreePage(
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, zContext);
}
#endif
- d2 = checkTreePage(pCheck,pgno,pPage,zContext,0,0,0,0);
+ d2 = checkTreePage(pCheck,pgno,pPage,zContext);
if( i>0 && d2!=depth ){
checkAppendMsg(pCheck, zContext, "Child page depth differs");
}
@@ -5550,7 +6314,7 @@ static int checkTreePage(
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, 0);
}
#endif
- checkTreePage(pCheck, pgno, pPage, zContext,0,0,0,0);
+ checkTreePage(pCheck, pgno, pPage, zContext);
}
/* Check for complete coverage of the page
@@ -5618,13 +6382,14 @@ static int checkTreePage(
** and a pointer to that error message is returned. The calling function
** is responsible for freeing the error message when it is done.
*/
-char *sqlite3BtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){
+char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
int i;
int nRef;
IntegrityCk sCheck;
+ BtShared *pBt = p->pBt;
- nRef = *sqlite3pager_stats(pBt->pPager);
- if( lockBtreeWithRetry(pBt)!=SQLITE_OK ){
+ nRef = sqlite3pager_refcount(pBt->pPager);
+ if( lockBtreeWithRetry(p)!=SQLITE_OK ){
return sqliteStrDup("Unable to acquire a read lock on the database");
}
sCheck.pBt = pBt;
@@ -5661,7 +6426,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0, 0);
}
#endif
- checkTreePage(&sCheck, aRoot[i], 0, "List of tree roots: ", 0,0,0,0);
+ checkTreePage(&sCheck, aRoot[i], 0, "List of tree roots: ");
}
/* Make sure every page in the file is referenced
@@ -5676,11 +6441,11 @@ char *sqlite3BtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){
** references to pointer-map pages.
*/
if( sCheck.anRef[i]==0 &&
- (PTRMAP_PAGENO(pBt->usableSize, i)!=i || !pBt->autoVacuum) ){
+ (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
}
if( sCheck.anRef[i]!=0 &&
- (PTRMAP_PAGENO(pBt->usableSize, i)==i && pBt->autoVacuum) ){
+ (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i);
}
#endif
@@ -5689,10 +6454,10 @@ char *sqlite3BtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){
/* Make sure this analysis did not leave any unref() pages
*/
unlockBtreeIfUnused(pBt);
- if( nRef != *sqlite3pager_stats(pBt->pPager) ){
+ if( nRef != sqlite3pager_refcount(pBt->pPager) ){
checkAppendMsg(&sCheck, 0,
"Outstanding page count goes from %d to %d during this analysis",
- nRef, *sqlite3pager_stats(pBt->pPager)
+ nRef, sqlite3pager_refcount(pBt->pPager)
);
}
@@ -5706,17 +6471,17 @@ char *sqlite3BtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){
/*
** Return the full pathname of the underlying database file.
*/
-const char *sqlite3BtreeGetFilename(Btree *pBt){
- assert( pBt->pPager!=0 );
- return sqlite3pager_filename(pBt->pPager);
+const char *sqlite3BtreeGetFilename(Btree *p){
+ assert( p->pBt->pPager!=0 );
+ return sqlite3pager_filename(p->pBt->pPager);
}
/*
** Return the pathname of the directory that contains the database file.
*/
-const char *sqlite3BtreeGetDirname(Btree *pBt){
- assert( pBt->pPager!=0 );
- return sqlite3pager_dirname(pBt->pPager);
+const char *sqlite3BtreeGetDirname(Btree *p){
+ assert( p->pBt->pPager!=0 );
+ return sqlite3pager_dirname(p->pBt->pPager);
}
/*
@@ -5724,9 +6489,9 @@ const char *sqlite3BtreeGetDirname(Btree *pBt){
** value of this routine is the same regardless of whether the journal file
** has been created or not.
*/
-const char *sqlite3BtreeGetJournalname(Btree *pBt){
- assert( pBt->pPager!=0 );
- return sqlite3pager_journalname(pBt->pPager);
+const char *sqlite3BtreeGetJournalname(Btree *p){
+ assert( p->pBt->pPager!=0 );
+ return sqlite3pager_journalname(p->pBt->pPager);
}
#ifndef SQLITE_OMIT_VACUUM
@@ -5737,11 +6502,14 @@ const char *sqlite3BtreeGetJournalname(Btree *pBt){
** The size of file pBtFrom may be reduced by this operation.
** If anything goes wrong, the transaction on pBtFrom is rolled back.
*/
-int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
+int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
int rc = SQLITE_OK;
Pgno i, nPage, nToPage, iSkip;
- if( pBtTo->inTrans!=TRANS_WRITE || pBtFrom->inTrans!=TRANS_WRITE ){
+ BtShared *pBtTo = pTo->pBt;
+ BtShared *pBtFrom = pFrom->pBt;
+
+ if( pTo->inTrans!=TRANS_WRITE || pFrom->inTrans!=TRANS_WRITE ){
return SQLITE_ERROR;
}
if( pBtTo->pCursor ) return SQLITE_BUSY;
@@ -5770,7 +6538,7 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
rc = sqlite3pager_truncate(pBtTo->pPager, nPage);
}
if( rc ){
- sqlite3BtreeRollback(pBtTo);
+ sqlite3BtreeRollback(pTo);
}
return rc;
}
@@ -5779,15 +6547,22 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
/*
** Return non-zero if a transaction is active.
*/
-int sqlite3BtreeIsInTrans(Btree *pBt){
- return (pBt && (pBt->inTrans==TRANS_WRITE));
+int sqlite3BtreeIsInTrans(Btree *p){
+ return (p && (p->inTrans==TRANS_WRITE));
}
/*
** Return non-zero if a statement transaction is active.
*/
-int sqlite3BtreeIsInStmt(Btree *pBt){
- return (pBt && pBt->inStmt);
+int sqlite3BtreeIsInStmt(Btree *p){
+ return (p->pBt && p->pBt->inStmt);
+}
+
+/*
+** Return non-zero if a read (or write) transaction is active.
+*/
+int sqlite3BtreeIsInReadTrans(Btree *p){
+ return (p && (p->inTrans!=TRANS_NONE));
}
/*
@@ -5804,30 +6579,101 @@ int sqlite3BtreeIsInStmt(Btree *pBt){
** Once this is routine has returned, the only thing required to commit
** the write-transaction for this database file is to delete the journal.
*/
-int sqlite3BtreeSync(Btree *pBt, const char *zMaster){
- if( pBt->inTrans==TRANS_WRITE ){
-#ifndef SQLITE_OMIT_AUTOVACUUM
+int sqlite3BtreeSync(Btree *p, const char *zMaster){
+ int rc = SQLITE_OK;
+ if( p->inTrans==TRANS_WRITE ){
+ BtShared *pBt = p->pBt;
Pgno nTrunc = 0;
+#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
- int rc = autoVacuumCommit(pBt, &nTrunc);
- if( rc!=SQLITE_OK ) return rc;
+ rc = autoVacuumCommit(pBt, &nTrunc);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
}
- return sqlite3pager_sync(pBt->pPager, zMaster, nTrunc);
#endif
- return sqlite3pager_sync(pBt->pPager, zMaster, 0);
+ rc = sqlite3pager_sync(pBt->pPager, zMaster, nTrunc);
}
- return SQLITE_OK;
+ return rc;
+}
+
+/*
+** This function returns a pointer to a blob of memory associated with
+** a single shared-btree. The memory is used by client code for it's own
+** purposes (for example, to store a high-level schema associated with
+** the shared-btree). The btree layer manages reference counting issues.
+**
+** The first time this is called on a shared-btree, nBytes bytes of memory
+** are allocated, zeroed, and returned to the caller. For each subsequent
+** call the nBytes parameter is ignored and a pointer to the same blob
+** of memory returned.
+**
+** Just before the shared-btree is closed, the function passed as the
+** xFree argument when the memory allocation was made is invoked on the
+** blob of allocated memory. This function should not call sqliteFree()
+** on the memory, the btree layer does that.
+*/
+void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){
+ BtShared *pBt = p->pBt;
+ if( !pBt->pSchema ){
+ pBt->pSchema = sqliteMalloc(nBytes);
+ pBt->xFreeSchema = xFree;
+ }
+ return pBt->pSchema;
}
-#ifndef SQLITE_OMIT_GLOBALRECOVER
/*
-** Reset the btree and underlying pager after a malloc() failure. Any
-** transaction that was active when malloc() failed is rolled back.
+** Return true if another user of the same shared btree as the argument
+** handle holds an exclusive lock on the sqlite_master table.
*/
-int sqlite3BtreeReset(Btree *pBt){
- if( pBt->pCursor ) return SQLITE_BUSY;
- pBt->inTrans = TRANS_NONE;
- unlockBtreeIfUnused(pBt);
- return sqlite3pager_reset(pBt->pPager);
+int sqlite3BtreeSchemaLocked(Btree *p){
+ return (queryTableLock(p, MASTER_ROOT, READ_LOCK)!=SQLITE_OK);
+}
+
+
+#ifndef SQLITE_OMIT_SHARED_CACHE
+/*
+** Obtain a lock on the table whose root page is iTab. The
+** lock is a write lock if isWritelock is true or a read lock
+** if it is false.
+*/
+int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){
+ int rc = SQLITE_OK;
+ u8 lockType = (isWriteLock?WRITE_LOCK:READ_LOCK);
+ rc = queryTableLock(p, iTab, lockType);
+ if( rc==SQLITE_OK ){
+ rc = lockTable(p, iTab, lockType);
+ }
+ return rc;
+}
+#endif
+
+/*
+** The following debugging interface has to be in this file (rather
+** than in, for example, test1.c) so that it can get access to
+** the definition of BtShared.
+*/
+#if defined(SQLITE_DEBUG) && defined(TCLSH)
+#include <tcl.h>
+int sqlite3_shared_cache_report(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ const ThreadData *pTd = sqlite3ThreadDataReadOnly();
+ if( pTd->useSharedData ){
+ BtShared *pBt;
+ Tcl_Obj *pRet = Tcl_NewObj();
+ for(pBt=pTd->pBtree; pBt; pBt=pBt->pNext){
+ const char *zFile = sqlite3pager_filename(pBt->pPager);
+ Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(zFile, -1));
+ Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(pBt->nRef));
+ }
+ Tcl_SetObjResult(interp, pRet);
+ }
+#endif
+ return TCL_OK;
}
#endif
diff --git a/ext/pdo_sqlite/sqlite/src/btree.h b/ext/pdo_sqlite/sqlite/src/btree.h
index 9d4401ac81..896ebf11b1 100644
--- a/ext/pdo_sqlite/sqlite/src/btree.h
+++ b/ext/pdo_sqlite/sqlite/src/btree.h
@@ -36,10 +36,12 @@
*/
typedef struct Btree Btree;
typedef struct BtCursor BtCursor;
+typedef struct BtShared BtShared;
int sqlite3BtreeOpen(
const char *zFilename, /* Name of database file to open */
+ sqlite3 *db, /* Associated database connection */
Btree **, /* Return open Btree* here */
int flags /* Flags */
);
@@ -57,7 +59,7 @@ int sqlite3BtreeOpen(
int sqlite3BtreeClose(Btree*);
int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*);
int sqlite3BtreeSetCacheSize(Btree*,int);
-int sqlite3BtreeSetSafetyLevel(Btree*,int);
+int sqlite3BtreeSetSafetyLevel(Btree*,int,int);
int sqlite3BtreeSyncDisabled(Btree*);
int sqlite3BtreeSetPageSize(Btree*,int,int);
int sqlite3BtreeGetPageSize(Btree*);
@@ -73,8 +75,11 @@ int sqlite3BtreeRollbackStmt(Btree*);
int sqlite3BtreeCreateTable(Btree*, int*, int flags);
int sqlite3BtreeIsInTrans(Btree*);
int sqlite3BtreeIsInStmt(Btree*);
+int sqlite3BtreeIsInReadTrans(Btree*);
int sqlite3BtreeSync(Btree*, const char *zMaster);
-int sqlite3BtreeReset(Btree *);
+void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
+int sqlite3BtreeSchemaLocked(Btree *);
+int sqlite3BtreeLockTable(Btree *, int, u8);
const char *sqlite3BtreeGetFilename(Btree *);
const char *sqlite3BtreeGetDirname(Btree *);
diff --git a/ext/pdo_sqlite/sqlite/src/build.c b/ext/pdo_sqlite/sqlite/src/build.c
index 537eede8c0..5294c1a316 100644
--- a/ext/pdo_sqlite/sqlite/src/build.c
+++ b/ext/pdo_sqlite/sqlite/src/build.c
@@ -36,6 +36,88 @@ void sqlite3BeginParse(Parse *pParse, int explainFlag){
pParse->nVar = 0;
}
+#ifndef SQLITE_OMIT_SHARED_CACHE
+/*
+** The TableLock structure is only used by the sqlite3TableLock() and
+** codeTableLocks() functions.
+*/
+struct TableLock {
+ int iDb; /* The database containing the table to be locked */
+ int iTab; /* The root page of the table to be locked */
+ u8 isWriteLock; /* True for write lock. False for a read lock */
+ const char *zName; /* Name of the table */
+};
+
+/*
+** Record the fact that we want to lock a table at run-time.
+**
+** The table to be locked has root page iTab and is found in database iDb.
+** A read or a write lock can be taken depending on isWritelock.
+**
+** This routine just records the fact that the lock is desired. The
+** code to make the lock occur is generated by a later call to
+** codeTableLocks() which occurs during sqlite3FinishCoding().
+*/
+void sqlite3TableLock(
+ Parse *pParse, /* Parsing context */
+ int iDb, /* Index of the database containing the table to lock */
+ int iTab, /* Root page number of the table to be locked */
+ u8 isWriteLock, /* True for a write lock */
+ const char *zName /* Name of the table to be locked */
+){
+ int i;
+ int nBytes;
+ TableLock *p;
+
+ if( 0==sqlite3ThreadDataReadOnly()->useSharedData || iDb<0 ){
+ return;
+ }
+
+ for(i=0; i<pParse->nTableLock; i++){
+ p = &pParse->aTableLock[i];
+ if( p->iDb==iDb && p->iTab==iTab ){
+ p->isWriteLock = (p->isWriteLock || isWriteLock);
+ return;
+ }
+ }
+
+ nBytes = sizeof(TableLock) * (pParse->nTableLock+1);
+ sqliteReallocOrFree((void **)&pParse->aTableLock, nBytes);
+ if( pParse->aTableLock ){
+ p = &pParse->aTableLock[pParse->nTableLock++];
+ p->iDb = iDb;
+ p->iTab = iTab;
+ p->isWriteLock = isWriteLock;
+ p->zName = zName;
+ }
+}
+
+/*
+** Code an OP_TableLock instruction for each table locked by the
+** statement (configured by calls to sqlite3TableLock()).
+*/
+static void codeTableLocks(Parse *pParse){
+ int i;
+ Vdbe *pVdbe;
+ assert( sqlite3ThreadDataReadOnly()->useSharedData || pParse->nTableLock==0 );
+
+ if( 0==(pVdbe = sqlite3GetVdbe(pParse)) ){
+ return;
+ }
+
+ for(i=0; i<pParse->nTableLock; i++){
+ TableLock *p = &pParse->aTableLock[i];
+ int p1 = p->iDb;
+ if( p->isWriteLock ){
+ p1 = -1*(p1+1);
+ }
+ sqlite3VdbeOp3(pVdbe, OP_TableLock, p1, p->iTab, p->zName, P3_STATIC);
+ }
+}
+#else
+ #define codeTableLocks(x)
+#endif
+
/*
** This routine is called after a single SQL statement has been
** parsed and a VDBE program to execute that statement has been
@@ -50,13 +132,13 @@ void sqlite3FinishCoding(Parse *pParse){
sqlite3 *db;
Vdbe *v;
- if( sqlite3_malloc_failed ) return;
+ if( sqlite3MallocFailed() ) return;
if( pParse->nested ) return;
if( !pParse->pVdbe ){
if( pParse->rc==SQLITE_OK && pParse->nErr ){
pParse->rc = SQLITE_ERROR;
+ return;
}
- return;
}
/* Begin by generating some termination code at the end of the
@@ -82,6 +164,18 @@ void sqlite3FinishCoding(Parse *pParse){
sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
}
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( pParse->pVirtualLock ){
+ char *vtab = (char *)pParse->pVirtualLock->pVtab;
+ sqlite3VdbeOp3(v, OP_VBegin, 0, 0, vtab, P3_VTAB);
+ }
+#endif
+
+ /* Once all the cookies have been verified and transactions opened,
+ ** obtain the required table-locks. This is a no-op unless the
+ ** shared-cache feature is enabled.
+ */
+ codeTableLocks(pParse);
sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto);
}
@@ -99,7 +193,7 @@ void sqlite3FinishCoding(Parse *pParse){
/* Get the VDBE program ready for execution
*/
- if( v && pParse->nErr==0 ){
+ if( v && pParse->nErr==0 && !sqlite3MallocFailed() ){
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
sqlite3VdbeTrace(v, trace);
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3,
@@ -168,11 +262,10 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
Table *p = 0;
int i;
assert( zName!=0 );
- assert( (db->flags & SQLITE_Initialized) || db->init.busy );
for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue;
- p = sqlite3HashFind(&db->aDb[j].tblHash, zName, strlen(zName)+1);
+ p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName, strlen(zName)+1);
if( p ) break;
}
return p;
@@ -224,11 +317,14 @@ Table *sqlite3LocateTable(Parse *pParse, const char *zName, const char *zDbase){
Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
Index *p = 0;
int i;
- assert( (db->flags & SQLITE_Initialized) || db->init.busy );
for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
+ Schema *pSchema = db->aDb[j].pSchema;
if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue;
- p = sqlite3HashFind(&db->aDb[j].idxHash, zName, strlen(zName)+1);
+ assert( pSchema || (j==1 && !db->aDb[1].pBt) );
+ if( pSchema ){
+ p = sqlite3HashFind(&pSchema->idxHash, zName, strlen(zName)+1);
+ }
if( p ) break;
}
return p;
@@ -250,12 +346,11 @@ static void freeIndex(Index *p){
** it is not unlinked from the Table that it indexes.
** Unlinking from the Table must be done by the calling function.
*/
-static void sqliteDeleteIndex(sqlite3 *db, Index *p){
+static void sqliteDeleteIndex(Index *p){
Index *pOld;
+ const char *zName = p->zName;
- assert( db!=0 && p->zName!=0 );
- pOld = sqlite3HashInsert(&db->aDb[p->iDb].idxHash, p->zName,
- strlen(p->zName)+1, 0);
+ pOld = sqlite3HashInsert(&p->pSchema->idxHash, zName, strlen( zName)+1, 0);
assert( pOld==0 || pOld==p );
freeIndex(p);
}
@@ -269,9 +364,10 @@ static void sqliteDeleteIndex(sqlite3 *db, Index *p){
void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
Index *pIndex;
int len;
+ Hash *pHash = &db->aDb[iDb].pSchema->idxHash;
len = strlen(zIdxName);
- pIndex = sqlite3HashInsert(&db->aDb[iDb].idxHash, zIdxName, len+1, 0);
+ pIndex = sqlite3HashInsert(pHash, zIdxName, len+1, 0);
if( pIndex ){
if( pIndex->pTable->pIndex==pIndex ){
pIndex->pTable->pIndex = pIndex->pNext;
@@ -299,39 +395,21 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
** single file indicated.
*/
void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
- HashElem *pElem;
- Hash temp1;
- Hash temp2;
int i, j;
assert( iDb>=0 && iDb<db->nDb );
- db->flags &= ~SQLITE_Initialized;
for(i=iDb; i<db->nDb; i++){
Db *pDb = &db->aDb[i];
- temp1 = pDb->tblHash;
- temp2 = pDb->trigHash;
- sqlite3HashInit(&pDb->trigHash, SQLITE_HASH_STRING, 0);
- sqlite3HashClear(&pDb->aFKey);
- sqlite3HashClear(&pDb->idxHash);
- for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
- sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem));
- }
- sqlite3HashClear(&temp2);
- sqlite3HashInit(&pDb->tblHash, SQLITE_HASH_STRING, 0);
- for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
- Table *pTab = sqliteHashData(pElem);
- sqlite3DeleteTable(db, pTab);
- }
- sqlite3HashClear(&temp1);
- pDb->pSeqTab = 0;
- DbClearProperty(db, i, DB_SchemaLoaded);
+ if( pDb->pSchema ){
+ sqlite3SchemaFree(pDb->pSchema);
+ }
if( iDb>0 ) return;
}
assert( iDb==0 );
db->flags &= ~SQLITE_InternChanges;
/* If one or more of the auxiliary database files has been closed,
- ** then remove then from the auxiliary database list. We take the
+ ** then remove them from the auxiliary database list. We take the
** opportunity to do this here since we have just deleted all of the
** schema hash tables and therefore do not have to make any changes
** to any of those tables.
@@ -394,6 +472,7 @@ static void sqliteResetColumnNames(Table *pTable){
sqliteFree(pCol->zName);
sqlite3ExprDelete(pCol->pDflt);
sqliteFree(pCol->zType);
+ sqliteFree(pCol->zColl);
}
sqliteFree(pTable->aCol);
}
@@ -420,6 +499,8 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
Index *pIndex, *pNext;
FKey *pFKey, *pNextFKey;
+ db = 0;
+
if( pTable==0 ) return;
/* Do not delete the table until the reference count reaches zero. */
@@ -433,8 +514,8 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
*/
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
pNext = pIndex->pNext;
- assert( pIndex->iDb==pTable->iDb || (pTable->iDb==0 && pIndex->iDb==1) );
- sqliteDeleteIndex(db, pIndex);
+ assert( pIndex->pSchema==pTable->pSchema );
+ sqliteDeleteIndex(pIndex);
}
#ifndef SQLITE_OMIT_FOREIGN_KEY
@@ -443,8 +524,7 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
*/
for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){
pNextFKey = pFKey->pNextFrom;
- assert( pTable->iDb<db->nDb );
- assert( sqlite3HashFind(&db->aDb[pTable->iDb].aFKey,
+ assert( sqlite3HashFind(&pTable->pSchema->aFKey,
pFKey->zTo, strlen(pFKey->zTo)+1)!=pFKey );
sqliteFree(pFKey);
}
@@ -456,6 +536,10 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
sqliteFree(pTable->zName);
sqliteFree(pTable->zColAff);
sqlite3SelectDelete(pTable->pSelect);
+#ifndef SQLITE_OMIT_CHECK
+ sqlite3ExprDelete(pTable->pCheck);
+#endif
+ sqlite3VtabClear(pTable);
sqliteFree(pTable);
}
@@ -472,14 +556,14 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
assert( iDb>=0 && iDb<db->nDb );
assert( zTabName && zTabName[0] );
pDb = &db->aDb[iDb];
- p = sqlite3HashInsert(&pDb->tblHash, zTabName, strlen(zTabName)+1, 0);
+ p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, strlen(zTabName)+1,0);
if( p ){
#ifndef SQLITE_OMIT_FOREIGN_KEY
for(pF1=p->pFKey; pF1; pF1=pF1->pNextFrom){
int nTo = strlen(pF1->zTo) + 1;
- pF2 = sqlite3HashFind(&pDb->aFKey, pF1->zTo, nTo);
+ pF2 = sqlite3HashFind(&pDb->pSchema->aFKey, pF1->zTo, nTo);
if( pF2==pF1 ){
- sqlite3HashInsert(&pDb->aFKey, pF1->zTo, nTo, pF1->pNextTo);
+ sqlite3HashInsert(&pDb->pSchema->aFKey, pF1->zTo, nTo, pF1->pNextTo);
}else{
while( pF2 && pF2->pNextTo!=pF1 ){ pF2=pF2->pNextTo; }
if( pF2 ){
@@ -506,7 +590,7 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
char *sqlite3NameFromToken(Token *pName){
char *zName;
if( pName ){
- zName = sqliteStrNDup(pName->z, pName->n);
+ zName = sqliteStrNDup((char*)pName->z, pName->n);
sqlite3Dequote(zName);
}else{
zName = 0;
@@ -518,7 +602,9 @@ char *sqlite3NameFromToken(Token *pName){
** Open the sqlite_master table stored in database number iDb for
** writing. The table is opened using cursor 0.
*/
-void sqlite3OpenMasterTable(Vdbe *v, int iDb){
+void sqlite3OpenMasterTable(Parse *p, int iDb){
+ Vdbe *v = sqlite3GetVdbe(p);
+ sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb));
sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
sqlite3VdbeAddOp(v, OP_OpenWrite, 0, MASTER_ROOT);
sqlite3VdbeAddOp(v, OP_SetNumColumns, 0, 5); /* sqlite_master has 5 columns */
@@ -613,8 +699,7 @@ int sqlite3CheckObjectName(Parse *pParse, const char *zName){
** Begin constructing a new table representation in memory. This is
** the first of several action routines that get called in response
** to a CREATE TABLE statement. In particular, this routine is called
-** after seeing tokens "CREATE" and "TABLE" and the table name. The
-** pStart token is the CREATE and pName is the table name. The isTemp
+** after seeing tokens "CREATE" and "TABLE" and the table name. The isTemp
** flag is true if the table should be stored in the auxiliary database
** file instead of in the main database file. This is normally the case
** when the "TEMP" or "TEMPORARY" keyword occurs in between
@@ -628,11 +713,12 @@ int sqlite3CheckObjectName(Parse *pParse, const char *zName){
*/
void sqlite3StartTable(
Parse *pParse, /* Parser context */
- Token *pStart, /* The "CREATE" token */
Token *pName1, /* First part of the name of the table or view */
Token *pName2, /* Second part of the name of the table or view */
int isTemp, /* True if this is a TEMP table */
- int isView /* True if this is a VIEW */
+ int isView, /* True if this is a VIEW */
+ int isVirtual, /* True if this is a VIRTUAL table */
+ int noErr /* Do nothing if table already exists */
){
Table *pTable;
char *zName = 0; /* The name of the new table */
@@ -695,7 +781,7 @@ void sqlite3StartTable(
code = SQLITE_CREATE_TABLE;
}
}
- if( sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){
+ if( !isVirtual && sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){
goto begin_table_error;
}
}
@@ -703,20 +789,28 @@ void sqlite3StartTable(
/* Make sure the new table name does not collide with an existing
** index or table name in the same database. Issue an error message if
- ** it does.
+ ** it does. The exception is if the statement being parsed was passed
+ ** to an sqlite3_declare_vtab() call. In that case only the column names
+ ** and types will be used, so there is no need to test for namespace
+ ** collisions.
*/
- if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
- goto begin_table_error;
- }
- pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName);
- if( pTable ){
- sqlite3ErrorMsg(pParse, "table %T already exists", pName);
- goto begin_table_error;
- }
- if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){
- sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
- goto begin_table_error;
+ if( !IN_DECLARE_VTAB ){
+ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
+ goto begin_table_error;
+ }
+ pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName);
+ if( pTable ){
+ if( !noErr ){
+ sqlite3ErrorMsg(pParse, "table %T already exists", pName);
+ }
+ goto begin_table_error;
+ }
+ if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){
+ sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
+ goto begin_table_error;
+ }
}
+
pTable = sqliteMalloc( sizeof(Table) );
if( pTable==0 ){
pParse->rc = SQLITE_NOMEM;
@@ -724,11 +818,8 @@ void sqlite3StartTable(
goto begin_table_error;
}
pTable->zName = zName;
- pTable->nCol = 0;
- pTable->aCol = 0;
pTable->iPKey = -1;
- pTable->pIndex = 0;
- pTable->iDb = iDb;
+ pTable->pSchema = db->aDb[iDb].pSchema;
pTable->nRef = 1;
if( pParse->pNewTable ) sqlite3DeleteTable(db, pParse->pNewTable);
pParse->pNewTable = pTable;
@@ -739,7 +830,7 @@ void sqlite3StartTable(
*/
#ifndef SQLITE_OMIT_AUTOINCREMENT
if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){
- db->aDb[iDb].pSeqTab = pTable;
+ pTable->pSchema->pSeqTab = pTable;
}
#endif
@@ -753,17 +844,26 @@ void sqlite3StartTable(
*/
if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){
int lbl;
+ int fileFormat;
sqlite3BeginWriteOperation(pParse, 0, iDb);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( isVirtual ){
+ sqlite3VdbeAddOp(v, OP_VBegin, 0, 0);
+ }
+#endif
+
/* If the file format and encoding in the database have not been set,
** set them now.
*/
sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1); /* file_format */
lbl = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp(v, OP_If, 0, lbl);
- sqlite3VdbeAddOp(v, OP_Integer, db->file_format, 0);
+ fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
+ 1 : SQLITE_MAX_FILE_FORMAT;
+ sqlite3VdbeAddOp(v, OP_Integer, fileFormat, 0);
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
- sqlite3VdbeAddOp(v, OP_Integer, db->enc, 0);
+ sqlite3VdbeAddOp(v, OP_Integer, ENC(db), 0);
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 4);
sqlite3VdbeResolveLabel(v, lbl);
@@ -775,15 +875,15 @@ void sqlite3StartTable(
** The rowid value is needed by the code that sqlite3EndTable will
** generate.
*/
-#ifndef SQLITE_OMIT_VIEW
- if( isView ){
+#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
+ if( isView || isVirtual ){
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
}else
#endif
{
sqlite3VdbeAddOp(v, OP_CreateTable, iDb, 0);
}
- sqlite3OpenMasterTable(v, iDb);
+ sqlite3OpenMasterTable(pParse, iDb);
sqlite3VdbeAddOp(v, OP_NewRowid, 0, 0);
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
@@ -855,7 +955,6 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){
** be called next to set pCol->affinity correctly.
*/
pCol->affinity = SQLITE_AFF_NONE;
- pCol->pColl = pParse->db->pDfltColl;
p->nCol++;
}
@@ -891,6 +990,9 @@ void sqlite3AddNotNull(Parse *pParse, int onError){
** 'CLOB' | SQLITE_AFF_TEXT
** 'TEXT' | SQLITE_AFF_TEXT
** 'BLOB' | SQLITE_AFF_NONE
+** 'REAL' | SQLITE_AFF_REAL
+** 'FLOA' | SQLITE_AFF_REAL
+** 'DOUB' | SQLITE_AFF_REAL
**
** If none of the substrings in the above table are found,
** SQLITE_AFF_NUMERIC is returned.
@@ -911,10 +1013,21 @@ char sqlite3AffinityType(const Token *pType){
}else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ /* TEXT */
aff = SQLITE_AFF_TEXT;
}else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */
- && aff==SQLITE_AFF_NUMERIC ){
+ && (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){
aff = SQLITE_AFF_NONE;
+#ifndef SQLITE_OMIT_FLOATING_POINT
+ }else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */
+ && aff==SQLITE_AFF_NUMERIC ){
+ aff = SQLITE_AFF_REAL;
+ }else if( h==(('f'<<24)+('l'<<16)+('o'<<8)+'a') /* FLOA */
+ && aff==SQLITE_AFF_NUMERIC ){
+ aff = SQLITE_AFF_REAL;
+ }else if( h==(('d'<<24)+('o'<<16)+('u'<<8)+'b') /* DOUB */
+ && aff==SQLITE_AFF_NUMERIC ){
+ aff = SQLITE_AFF_REAL;
+#endif
}else if( (h&0x00FFFFFF)==(('i'<<16)+('n'<<8)+'t') ){ /* INT */
- aff = SQLITE_AFF_INTEGER;
+ aff = SQLITE_AFF_INTEGER;
break;
}
}
@@ -993,12 +1106,13 @@ void sqlite3AddPrimaryKey(
Parse *pParse, /* Parsing context */
ExprList *pList, /* List of field names to be indexed */
int onError, /* What to do with a uniqueness conflict */
- int autoInc /* True if the AUTOINCREMENT keyword is present */
+ int autoInc, /* True if the AUTOINCREMENT keyword is present */
+ int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */
){
Table *pTab = pParse->pNewTable;
char *zType = 0;
int iCol = -1, i;
- if( pTab==0 ) goto primary_key_exit;
+ if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit;
if( pTab->hasPrimKey ){
sqlite3ErrorMsg(pParse,
"table \"%s\" has more than one primary key", pTab->zName);
@@ -1024,7 +1138,8 @@ void sqlite3AddPrimaryKey(
if( iCol>=0 && iCol<pTab->nCol ){
zType = pTab->aCol[iCol].zType;
}
- if( zType && sqlite3StrICmp(zType, "INTEGER")==0 ){
+ if( zType && sqlite3StrICmp(zType, "INTEGER")==0
+ && sortOrder==SQLITE_SO_ASC ){
pTab->iPKey = iCol;
pTab->keyConf = onError;
pTab->autoInc = autoInc;
@@ -1034,7 +1149,7 @@ void sqlite3AddPrimaryKey(
"INTEGER PRIMARY KEY");
#endif
}else{
- sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0);
+ sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0);
pList = 0;
}
@@ -1044,46 +1159,50 @@ primary_key_exit:
}
/*
+** Add a new CHECK constraint to the table currently under construction.
+*/
+void sqlite3AddCheckConstraint(
+ Parse *pParse, /* Parsing context */
+ Expr *pCheckExpr /* The check expression */
+){
+#ifndef SQLITE_OMIT_CHECK
+ Table *pTab = pParse->pNewTable;
+ if( pTab && !IN_DECLARE_VTAB ){
+ /* The CHECK expression must be duplicated so that tokens refer
+ ** to malloced space and not the (ephemeral) text of the CREATE TABLE
+ ** statement */
+ pTab->pCheck = sqlite3ExprAnd(pTab->pCheck, sqlite3ExprDup(pCheckExpr));
+ }
+#endif
+ sqlite3ExprDelete(pCheckExpr);
+}
+
+/*
** Set the collation function of the most recently parsed table column
** to the CollSeq given.
*/
void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){
Table *p;
- Index *pIdx;
- CollSeq *pColl;
int i;
if( (p = pParse->pNewTable)==0 ) return;
i = p->nCol-1;
- pColl = sqlite3LocateCollSeq(pParse, zType, nType);
- p->aCol[i].pColl = pColl;
-
- /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
- ** then an index may have been created on this column before the
- ** collation type was added. Correct this if it is the case.
- */
- for(pIdx = p->pIndex; pIdx; pIdx=pIdx->pNext){
- assert( pIdx->nColumn==1 );
- if( pIdx->aiColumn[0]==i ) pIdx->keyInfo.aColl[0] = pColl;
- }
-}
-
-/*
-** Call sqlite3CheckCollSeq() for all collating sequences in an index,
-** in order to verify that all the necessary collating sequences are
-** loaded.
-*/
-int sqlite3CheckIndexCollSeq(Parse *pParse, Index *pIdx){
- if( pIdx ){
- int i;
- for(i=0; i<pIdx->nColumn; i++){
- if( sqlite3CheckCollSeq(pParse, pIdx->keyInfo.aColl[i]) ){
- return SQLITE_ERROR;
+ if( sqlite3LocateCollSeq(pParse, zType, nType) ){
+ Index *pIdx;
+ p->aCol[i].zColl = sqliteStrNDup(zType, nType);
+
+ /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
+ ** then an index may have been created on this column before the
+ ** collation type was added. Correct this if it is the case.
+ */
+ for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){
+ assert( pIdx->nColumn==1 );
+ if( pIdx->aiColumn[0]==i ){
+ pIdx->azColl[0] = p->aCol[i].zColl;
}
}
}
- return SQLITE_OK;
}
/*
@@ -1102,10 +1221,11 @@ int sqlite3CheckIndexCollSeq(Parse *pParse, Index *pIdx){
*/
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){
sqlite3 *db = pParse->db;
- u8 enc = db->enc;
+ u8 enc = ENC(db);
u8 initbusy = db->init.busy;
+ CollSeq *pColl;
- CollSeq *pColl = sqlite3FindCollSeq(db, enc, zName, nName, initbusy);
+ pColl = sqlite3FindCollSeq(db, enc, zName, nName, initbusy);
if( !initbusy && (!pColl || !pColl->xCmp) ){
pColl = sqlite3GetCollSeq(db, pColl, zName, nName);
if( !pColl ){
@@ -1138,7 +1258,7 @@ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){
** 1 chance in 2^32. So we're safe enough.
*/
void sqlite3ChangeCookie(sqlite3 *db, Vdbe *v, int iDb){
- sqlite3VdbeAddOp(v, OP_Integer, db->aDb[iDb].schema_cookie+1, 0);
+ sqlite3VdbeAddOp(v, OP_Integer, db->aDb[iDb].pSchema->schema_cookie+1, 0);
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0);
}
@@ -1186,7 +1306,7 @@ static void identPut(char *z, int *pIdx, char *zSignedIdent){
** table. Memory to hold the text of the statement is obtained
** from sqliteMalloc() and must be freed by the calling function.
*/
-static char *createTableStmt(Table *p){
+static char *createTableStmt(Table *p, int isTemp){
int i, k, n;
char *zStmt;
char *zSep, *zSep2, *zEnd, *z;
@@ -1212,7 +1332,7 @@ static char *createTableStmt(Table *p){
n += 35 + 6*p->nCol;
zStmt = sqliteMallocRaw( n );
if( zStmt==0 ) return 0;
- strcpy(zStmt, !OMIT_TEMPDB&&p->iDb==1 ? "CREATE TEMP TABLE ":"CREATE TABLE ");
+ strcpy(zStmt, !OMIT_TEMPDB&&isTemp ? "CREATE TEMP TABLE ":"CREATE TABLE ");
k = strlen(zStmt);
identPut(zStmt, &k, p->zName);
zStmt[k++] = '(';
@@ -1259,13 +1379,40 @@ void sqlite3EndTable(
){
Table *p;
sqlite3 *db = pParse->db;
+ int iDb;
- if( (pEnd==0 && pSelect==0) || pParse->nErr || sqlite3_malloc_failed ) return;
+ if( (pEnd==0 && pSelect==0) || pParse->nErr || sqlite3MallocFailed() ) {
+ return;
+ }
p = pParse->pNewTable;
if( p==0 ) return;
assert( !db->init.busy || !pSelect );
+ iDb = sqlite3SchemaToIndex(db, p->pSchema);
+
+#ifndef SQLITE_OMIT_CHECK
+ /* Resolve names in all CHECK constraint expressions.
+ */
+ if( p->pCheck ){
+ SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
+ NameContext sNC; /* Name context for pParse->pNewTable */
+
+ memset(&sNC, 0, sizeof(sNC));
+ memset(&sSrc, 0, sizeof(sSrc));
+ sSrc.nSrc = 1;
+ sSrc.a[0].zName = p->zName;
+ sSrc.a[0].pTab = p;
+ sSrc.a[0].iCursor = -1;
+ sNC.pParse = pParse;
+ sNC.pSrcList = &sSrc;
+ sNC.isCheck = 1;
+ if( sqlite3ExprResolveNames(&sNC, p->pCheck) ){
+ return;
+ }
+ }
+#endif /* !defined(SQLITE_OMIT_CHECK) */
+
/* If the db->init.busy is 1 it means we are reading the SQL off the
** "sqlite_master" or "sqlite_temp_master" table on the disk.
** So do not write to the disk again. Extract the root page number
@@ -1318,11 +1465,16 @@ void sqlite3EndTable(
** Once the SELECT has been coded by sqlite3Select(), it is in a
** suitable state to query for the column names and types to be used
** by the new table.
+ **
+ ** A shared-cache write-lock is not required to write to the new table,
+ ** as a schema-lock must have already been obtained to create it. Since
+ ** a schema-lock excludes all other database users, the write-lock would
+ ** be redundant.
*/
if( pSelect ){
Table *pSelTab;
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- sqlite3VdbeAddOp(v, OP_Integer, p->iDb, 0);
+ sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
sqlite3VdbeAddOp(v, OP_OpenWrite, 1, 0);
pParse->nTab = 2;
sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0, 0);
@@ -1341,7 +1493,7 @@ void sqlite3EndTable(
/* Compute the complete text of the CREATE statement */
if( pSelect ){
- zStmt = createTableStmt(p);
+ zStmt = createTableStmt(p, p->pSchema==pParse->db->aDb[1].pSchema);
}else{
n = pEnd->z - pParse->sNameToken.z + 1;
zStmt = sqlite3MPrintf("CREATE %s %.*s", zType2, n, pParse->sNameToken.z);
@@ -1357,22 +1509,22 @@ void sqlite3EndTable(
"UPDATE %Q.%s "
"SET type='%s', name=%Q, tbl_name=%Q, rootpage=#0, sql=%Q "
"WHERE rowid=#1",
- db->aDb[p->iDb].zName, SCHEMA_TABLE(p->iDb),
+ db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
zType,
p->zName,
p->zName,
zStmt
);
sqliteFree(zStmt);
- sqlite3ChangeCookie(db, v, p->iDb);
+ sqlite3ChangeCookie(db, v, iDb);
#ifndef SQLITE_OMIT_AUTOINCREMENT
/* Check to see if we need to create an sqlite_sequence table for
** keeping track of autoincrement keys.
*/
if( p->autoInc ){
- Db *pDb = &db->aDb[p->iDb];
- if( pDb->pSeqTab==0 ){
+ Db *pDb = &db->aDb[iDb];
+ if( pDb->pSchema->pSeqTab==0 ){
sqlite3NestedParse(pParse,
"CREATE TABLE %Q.sqlite_sequence(name,seq)",
pDb->zName
@@ -1382,7 +1534,7 @@ void sqlite3EndTable(
#endif
/* Reparse everything to update our internal data structures */
- sqlite3VdbeOp3(v, OP_ParseSchema, p->iDb, 0,
+ sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0,
sqlite3MPrintf("tbl_name='%q'",p->zName), P3_DYNAMIC);
}
@@ -1392,8 +1544,8 @@ void sqlite3EndTable(
if( db->init.busy && pParse->nErr==0 ){
Table *pOld;
FKey *pFKey;
- Db *pDb = &db->aDb[p->iDb];
- pOld = sqlite3HashInsert(&pDb->tblHash, p->zName, strlen(p->zName)+1, p);
+ Schema *pSchema = p->pSchema;
+ pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, strlen(p->zName)+1,p);
if( pOld ){
assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
return;
@@ -1401,8 +1553,8 @@ void sqlite3EndTable(
#ifndef SQLITE_OMIT_FOREIGN_KEY
for(pFKey=p->pFKey; pFKey; pFKey=pFKey->pNextFrom){
int nTo = strlen(pFKey->zTo) + 1;
- pFKey->pNextTo = sqlite3HashFind(&pDb->aFKey, pFKey->zTo, nTo);
- sqlite3HashInsert(&pDb->aFKey, pFKey->zTo, nTo, pFKey);
+ pFKey->pNextTo = sqlite3HashFind(&pSchema->aFKey, pFKey->zTo, nTo);
+ sqlite3HashInsert(&pSchema->aFKey, pFKey->zTo, nTo, pFKey);
}
#endif
pParse->pNewTable = 0;
@@ -1411,9 +1563,14 @@ void sqlite3EndTable(
#ifndef SQLITE_OMIT_ALTERTABLE
if( !p->pSelect ){
+ const char *zName = (const char *)pParse->sNameToken.z;
+ int nName;
assert( !pSelect && pCons && pEnd );
- if( pCons->z==0 ) pCons = pEnd;
- p->addColOffset = 13 + (pCons->z - pParse->sNameToken.z);
+ if( pCons->z==0 ){
+ pCons = pEnd;
+ }
+ nName = (const char *)pCons->z - zName;
+ p->addColOffset = 13 + sqlite3utf8CharLen(zName, nName);
}
#endif
}
@@ -1437,20 +1594,22 @@ void sqlite3CreateView(
Token sEnd;
DbFixer sFix;
Token *pName;
+ int iDb;
if( pParse->nVar>0 ){
sqlite3ErrorMsg(pParse, "parameters are not allowed in views");
sqlite3SelectDelete(pSelect);
return;
}
- sqlite3StartTable(pParse, pBegin, pName1, pName2, isTemp, 1);
+ sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, 0);
p = pParse->pNewTable;
if( p==0 || pParse->nErr ){
sqlite3SelectDelete(pSelect);
return;
}
sqlite3TwoPartName(pParse, pName1, pName2, &pName);
- if( sqlite3FixInit(&sFix, pParse, p->iDb, "view", pName)
+ iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
+ if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName)
&& sqlite3FixSelect(&sFix, pSelect)
){
sqlite3SelectDelete(pSelect);
@@ -1464,6 +1623,9 @@ void sqlite3CreateView(
*/
p->pSelect = sqlite3SelectDup(pSelect);
sqlite3SelectDelete(pSelect);
+ if( sqlite3MallocFailed() ){
+ return;
+ }
if( !pParse->db->init.busy ){
sqlite3ViewGetColumnNames(pParse, p);
}
@@ -1488,7 +1650,7 @@ void sqlite3CreateView(
}
#endif /* SQLITE_OMIT_VIEW */
-#ifndef SQLITE_OMIT_VIEW
+#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
/*
** The Table structure pTable is really a VIEW. Fill in the names of
** the columns of the view in the pTable structure. Return the number
@@ -1502,6 +1664,14 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
assert( pTable );
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( sqlite3VtabCallConnect(pParse, pTable) ){
+ return SQLITE_ERROR;
+ }
+ if( IsVirtual(pTable) ) return 0;
+#endif
+
+#ifndef SQLITE_OMIT_VIEW
/* A positive nCol means the columns names for this view are
** already known.
*/
@@ -1517,12 +1687,10 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
** Actually, this error is caught previously and so the following test
** should always fail. But we will leave it in place just to be safe.
*/
-#if 0
if( pTable->nCol<0 ){
sqlite3ErrorMsg(pParse, "view %s is circularly defined", pTable->zName);
return 1;
}
-#endif
assert( pTable->nCol>=0 );
/* If we get this far, it means we need to compute the table names.
@@ -1534,27 +1702,32 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
*/
assert( pTable->pSelect );
pSel = sqlite3SelectDup(pTable->pSelect);
- n = pParse->nTab;
- sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
- pTable->nCol = -1;
- pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel);
- pParse->nTab = n;
- if( pSelTab ){
- assert( pTable->aCol==0 );
- pTable->nCol = pSelTab->nCol;
- pTable->aCol = pSelTab->aCol;
- pSelTab->nCol = 0;
- pSelTab->aCol = 0;
- sqlite3DeleteTable(0, pSelTab);
- DbSetProperty(pParse->db, pTable->iDb, DB_UnresetViews);
- }else{
- pTable->nCol = 0;
+ if( pSel ){
+ n = pParse->nTab;
+ sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
+ pTable->nCol = -1;
+ pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel);
+ pParse->nTab = n;
+ if( pSelTab ){
+ assert( pTable->aCol==0 );
+ pTable->nCol = pSelTab->nCol;
+ pTable->aCol = pSelTab->aCol;
+ pSelTab->nCol = 0;
+ pSelTab->aCol = 0;
+ sqlite3DeleteTable(0, pSelTab);
+ pTable->pSchema->flags |= DB_UnresetViews;
+ }else{
+ pTable->nCol = 0;
+ nErr++;
+ }
+ sqlite3SelectDelete(pSel);
+ } else {
nErr++;
}
- sqlite3SelectDelete(pSel);
+#endif /* SQLITE_OMIT_VIEW */
return nErr;
}
-#endif /* SQLITE_OMIT_VIEW */
+#endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
#ifndef SQLITE_OMIT_VIEW
/*
@@ -1563,7 +1736,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
static void sqliteViewResetAll(sqlite3 *db, int idx){
HashElem *i;
if( !DbHasProperty(db, idx, DB_UnresetViews) ) return;
- for(i=sqliteHashFirst(&db->aDb[idx].tblHash); i; i=sqliteHashNext(i)){
+ for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){
Table *pTab = sqliteHashData(i);
if( pTab->pSelect ){
sqliteResetColumnNames(pTab);
@@ -1580,26 +1753,37 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
** used by SQLite when the btree layer moves a table root page. The
** root-page of a table or index in database iDb has changed from iFrom
** to iTo.
+**
+** Ticket #1728: The symbol table might still contain information
+** on tables and/or indices that are the process of being deleted.
+** If you are unlucky, one of those deleted indices or tables might
+** have the same rootpage number as the real table or index that is
+** being moved. So we cannot stop searching after the first match
+** because the first match might be for one of the deleted indices
+** or tables and not the table/index that is actually being moved.
+** We must continue looping until all tables and indices with
+** rootpage==iFrom have been converted to have a rootpage of iTo
+** in order to be certain that we got the right one.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
void sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){
HashElem *pElem;
-
- for(pElem=sqliteHashFirst(&pDb->tblHash); pElem; pElem=sqliteHashNext(pElem)){
+ Hash *pHash;
+
+ pHash = &pDb->pSchema->tblHash;
+ for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
if( pTab->tnum==iFrom ){
pTab->tnum = iTo;
- return;
}
}
- for(pElem=sqliteHashFirst(&pDb->idxHash); pElem; pElem=sqliteHashNext(pElem)){
+ pHash = &pDb->pSchema->idxHash;
+ for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){
Index *pIdx = sqliteHashData(pElem);
if( pIdx->tnum==iFrom ){
pIdx->tnum = iTo;
- return;
}
}
- assert(0);
}
#endif
@@ -1636,9 +1820,10 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
static void destroyTable(Parse *pParse, Table *pTab){
#ifdef SQLITE_OMIT_AUTOVACUUM
Index *pIdx;
- destroyRootPage(pParse, pTab->tnum, pTab->iDb);
+ int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ destroyRootPage(pParse, pTab->tnum, iDb);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- destroyRootPage(pParse, pIdx->tnum, pIdx->iDb);
+ destroyRootPage(pParse, pIdx->tnum, iDb);
}
#else
/* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM
@@ -1669,14 +1854,18 @@ static void destroyTable(Parse *pParse, Table *pTab){
}
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int iIdx = pIdx->tnum;
- assert( pIdx->iDb==pTab->iDb );
+ assert( pIdx->pSchema==pTab->pSchema );
if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){
iLargest = iIdx;
}
}
- if( iLargest==0 ) return;
- destroyRootPage(pParse, iLargest, pTab->iDb);
- iDestroyed = iLargest;
+ if( iLargest==0 ){
+ return;
+ }else{
+ int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ destroyRootPage(pParse, iLargest, iDb);
+ iDestroyed = iLargest;
+ }
}
#endif
}
@@ -1685,24 +1874,32 @@ static void destroyTable(Parse *pParse, Table *pTab){
** This routine is called to do the work of a DROP TABLE statement.
** pName is the name of the table to be dropped.
*/
-void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
+void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
Table *pTab;
Vdbe *v;
sqlite3 *db = pParse->db;
int iDb;
- if( pParse->nErr || sqlite3_malloc_failed ) goto exit_drop_table;
+ if( pParse->nErr || sqlite3MallocFailed() ){
+ goto exit_drop_table;
+ }
assert( pName->nSrc==1 );
pTab = sqlite3LocateTable(pParse, pName->a[0].zName, pName->a[0].zDatabase);
- if( pTab==0 ) goto exit_drop_table;
- iDb = pTab->iDb;
+ if( pTab==0 ){
+ if( noErr ){
+ sqlite3ErrorClear(pParse);
+ }
+ goto exit_drop_table;
+ }
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb>=0 && iDb<db->nDb );
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code;
- const char *zTab = SCHEMA_TABLE(pTab->iDb);
- const char *zDb = db->aDb[pTab->iDb].zName;
+ const char *zTab = SCHEMA_TABLE(iDb);
+ const char *zDb = db->aDb[iDb].zName;
+ const char *zArg2 = 0;
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
goto exit_drop_table;
}
@@ -1712,6 +1909,14 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
}else{
code = SQLITE_DROP_VIEW;
}
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ }else if( IsVirtual(pTab) ){
+ if( sqlite3ViewGetColumnNames(pParse, pTab) ){
+ goto exit_drop_table;
+ }
+ code = SQLITE_DROP_VTABLE;
+ zArg2 = pTab->pMod->zName;
+#endif
}else{
if( !OMIT_TEMPDB && iDb==1 ){
code = SQLITE_DROP_TEMP_TABLE;
@@ -1719,7 +1924,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
code = SQLITE_DROP_TABLE;
}
}
- if( sqlite3AuthCheck(pParse, code, pTab->zName, 0, zDb) ){
+ if( sqlite3AuthCheck(pParse, code, pTab->zName, zArg2, zDb) ){
goto exit_drop_table;
}
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
@@ -1727,7 +1932,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
}
}
#endif
- if( pTab->readOnly || pTab==db->aDb[iDb].pSeqTab ){
+ if( pTab->readOnly || pTab==db->aDb[iDb].pSchema->pSeqTab ){
sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
goto exit_drop_table;
}
@@ -1752,18 +1957,27 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
v = sqlite3GetVdbe(pParse);
if( v ){
Trigger *pTrigger;
- int iDb = pTab->iDb;
Db *pDb = &db->aDb[iDb];
sqlite3BeginWriteOperation(pParse, 0, iDb);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTab) ){
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ if( v ){
+ sqlite3VdbeAddOp(v, OP_VBegin, 0, 0);
+ }
+ }
+#endif
+
/* Drop all triggers associated with the table being dropped. Code
** is generated to remove entries from sqlite_master and/or
** sqlite_temp_master if required.
*/
pTrigger = pTab->pTrigger;
while( pTrigger ){
- assert( pTrigger->iDb==iDb || pTrigger->iDb==1 );
- sqlite3DropTriggerPtr(pParse, pTrigger, 1);
+ assert( pTrigger->pSchema==pTab->pSchema ||
+ pTrigger->pSchema==db->aDb[1].pSchema );
+ sqlite3DropTriggerPtr(pParse, pTrigger);
pTrigger = pTrigger->pNext;
}
@@ -1791,13 +2005,16 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",
pDb->zName, SCHEMA_TABLE(iDb), pTab->zName);
- if( !isView ){
+ if( !isView && !IsVirtual(pTab) ){
destroyTable(pParse, pTab);
}
/* Remove the table entry from SQLite's internal schema and modify
** the schema cookie.
*/
+ if( IsVirtual(pTab) ){
+ sqlite3VdbeOp3(v, OP_VDestroy, iDb, 0, pTab->zName, 0);
+ }
sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0);
sqlite3ChangeCookie(db, v, iDb);
}
@@ -1841,7 +2058,7 @@ void sqlite3CreateForeignKey(
char *z;
assert( pTo!=0 );
- if( p==0 || pParse->nErr ) goto fk_end;
+ if( p==0 || pParse->nErr || IN_DECLARE_VTAB ) goto fk_end;
if( pFromCol==0 ){
int iCol = p->nCol-1;
if( iCol<0 ) goto fk_end;
@@ -1958,21 +2175,18 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
int addr1; /* Address of top of loop */
int tnum; /* Root page of index */
Vdbe *v; /* Generate code into this virtual machine */
+ KeyInfo *pKey; /* KeyInfo for index */
+ int iDb = sqlite3SchemaToIndex(pParse->db, pIndex->pSchema);
#ifndef SQLITE_OMIT_AUTHORIZATION
if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0,
- pParse->db->aDb[pIndex->iDb].zName ) ){
+ pParse->db->aDb[iDb].zName ) ){
return;
}
#endif
- /* Ensure all the required collation sequences are available. This
- ** routine will invoke the collation-needed callback if necessary (and
- ** if one has been registered).
- */
- if( sqlite3CheckIndexCollSeq(pParse, pIndex) ){
- return;
- }
+ /* Require a write-lock on the table to perform this operation */
+ sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
@@ -1981,12 +2195,12 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
tnum = 0;
}else{
tnum = pIndex->tnum;
- sqlite3VdbeAddOp(v, OP_Clear, tnum, pIndex->iDb);
+ sqlite3VdbeAddOp(v, OP_Clear, tnum, iDb);
}
- sqlite3VdbeAddOp(v, OP_Integer, pIndex->iDb, 0);
- sqlite3VdbeOp3(v, OP_OpenWrite, iIdx, tnum,
- (char*)&pIndex->keyInfo, P3_KEYINFO);
- sqlite3OpenTableForReading(v, iTab, pTab);
+ sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
+ pKey = sqlite3IndexKeyinfo(pParse, pIndex);
+ sqlite3VdbeOp3(v, OP_OpenWrite, iIdx, tnum, (char *)pKey, P3_KEYINFO_HANDOFF);
+ sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0);
sqlite3GenerateIndexKey(v, pIndex, iTab);
if( pIndex->onError!=OE_None ){
@@ -2027,20 +2241,30 @@ void sqlite3CreateIndex(
ExprList *pList, /* A list of columns to be indexed */
int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
Token *pStart, /* The CREATE token that begins a CREATE TABLE statement */
- Token *pEnd /* The ")" that closes the CREATE INDEX statement */
+ Token *pEnd, /* The ")" that closes the CREATE INDEX statement */
+ int sortOrder, /* Sort order of primary key when pList==NULL */
+ int ifNotExist /* Omit error if index already exists */
){
- Table *pTab = 0; /* Table to be indexed */
- Index *pIndex = 0; /* The index to be created */
- char *zName = 0;
+ Table *pTab = 0; /* Table to be indexed */
+ Index *pIndex = 0; /* The index to be created */
+ char *zName = 0; /* Name of the index */
+ int nName; /* Number of characters in zName */
int i, j;
- Token nullId; /* Fake token for an empty ID list */
- DbFixer sFix; /* For assigning database names to pTable */
+ Token nullId; /* Fake token for an empty ID list */
+ DbFixer sFix; /* For assigning database names to pTable */
+ int sortOrderMask; /* 1 to honor DESC in index. 0 to ignore. */
sqlite3 *db = pParse->db;
+ Db *pDb; /* The specific table containing the indexed database */
+ int iDb; /* Index of the database that is being written */
+ Token *pName = 0; /* Unqualified name of the index to create */
+ struct ExprList_item *pListItem; /* For looping over pList */
+ int nCol;
+ int nExtra = 0;
+ char *zExtra;
- int iDb; /* Index of the database that is being written */
- Token *pName = 0; /* Unqualified name of the index to create */
-
- if( pParse->nErr || sqlite3_malloc_failed ) goto exit_create_index;
+ if( pParse->nErr || sqlite3MallocFailed() || IN_DECLARE_VTAB ){
+ goto exit_create_index;
+ }
/*
** Find the table that is to be indexed. Return early if not found.
@@ -2060,7 +2284,7 @@ void sqlite3CreateIndex(
** is a temp table. If so, set the database to 1.
*/
pTab = sqlite3SrcListLookup(pParse, pTblName);
- if( pName2 && pName2->n==0 && pTab && pTab->iDb==1 ){
+ if( pName2 && pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){
iDb = 1;
}
#endif
@@ -2075,12 +2299,14 @@ void sqlite3CreateIndex(
pTab = sqlite3LocateTable(pParse, pTblName->a[0].zName,
pTblName->a[0].zDatabase);
if( !pTab ) goto exit_create_index;
- assert( iDb==pTab->iDb );
+ assert( db->aDb[iDb].pSchema==pTab->pSchema );
}else{
assert( pName==0 );
- pTab = pParse->pNewTable;
- iDb = pTab->iDb;
+ pTab = pParse->pNewTable;
+ if( !pTab ) goto exit_create_index;
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
}
+ pDb = &db->aDb[iDb];
if( pTab==0 || pParse->nErr ) goto exit_create_index;
if( pTab->readOnly ){
@@ -2093,6 +2319,12 @@ void sqlite3CreateIndex(
goto exit_create_index;
}
#endif
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTab) ){
+ sqlite3ErrorMsg(pParse, "virtual tables may not be indexed");
+ goto exit_create_index;
+ }
+#endif
/*
** Find the name of the index. Make sure there is not already another
@@ -2116,8 +2348,10 @@ void sqlite3CreateIndex(
}
if( !db->init.busy ){
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index;
- if( sqlite3FindIndex(db, zName, db->aDb[iDb].zName)!=0 ){
- sqlite3ErrorMsg(pParse, "index %s already exists", zName);
+ if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){
+ if( !ifNotExist ){
+ sqlite3ErrorMsg(pParse, "index %s already exists", zName);
+ }
goto exit_create_index;
}
if( sqlite3FindTable(db, zName, 0)!=0 ){
@@ -2140,7 +2374,7 @@ void sqlite3CreateIndex(
*/
#ifndef SQLITE_OMIT_AUTHORIZATION
{
- const char *zDb = db->aDb[iDb].zName;
+ const char *zDb = pDb->zName;
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){
goto exit_create_index;
}
@@ -2157,56 +2391,96 @@ void sqlite3CreateIndex(
** So create a fake list to simulate this.
*/
if( pList==0 ){
- nullId.z = pTab->aCol[pTab->nCol-1].zName;
- nullId.n = strlen(nullId.z);
+ nullId.z = (u8*)pTab->aCol[pTab->nCol-1].zName;
+ nullId.n = strlen((char*)nullId.z);
pList = sqlite3ExprListAppend(0, 0, &nullId);
if( pList==0 ) goto exit_create_index;
+ pList->a[0].sortOrder = sortOrder;
+ }
+
+ /* Figure out how many bytes of space are required to store explicitly
+ ** specified collation sequence names.
+ */
+ for(i=0; i<pList->nExpr; i++){
+ Expr *pExpr = pList->a[i].pExpr;
+ if( pExpr ){
+ nExtra += (1 + strlen(pExpr->pColl->zName));
+ }
}
/*
** Allocate the index structure.
*/
- pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 + sizeof(int) +
- (sizeof(int)*2 + sizeof(CollSeq*))*pList->nExpr );
- if( sqlite3_malloc_failed ) goto exit_create_index;
- pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nExpr];
- pIndex->aiRowEst = (unsigned*)&pIndex->aiColumn[pList->nExpr];
- pIndex->zName = (char*)&pIndex->aiRowEst[pList->nExpr+1];
+ nName = strlen(zName);
+ nCol = pList->nExpr;
+ pIndex = sqliteMalloc(
+ sizeof(Index) + /* Index structure */
+ sizeof(int)*nCol + /* Index.aiColumn */
+ sizeof(int)*(nCol+1) + /* Index.aiRowEst */
+ sizeof(char *)*nCol + /* Index.azColl */
+ sizeof(u8)*nCol + /* Index.aSortOrder */
+ nName + 1 + /* Index.zName */
+ nExtra /* Collation sequence names */
+ );
+ if( sqlite3MallocFailed() ) goto exit_create_index;
+ pIndex->azColl = (char**)(&pIndex[1]);
+ pIndex->aiColumn = (int *)(&pIndex->azColl[nCol]);
+ pIndex->aiRowEst = (unsigned *)(&pIndex->aiColumn[nCol]);
+ pIndex->aSortOrder = (u8 *)(&pIndex->aiRowEst[nCol+1]);
+ pIndex->zName = (char *)(&pIndex->aSortOrder[nCol]);
+ zExtra = (char *)(&pIndex->zName[nName+1]);
strcpy(pIndex->zName, zName);
pIndex->pTable = pTab;
pIndex->nColumn = pList->nExpr;
pIndex->onError = onError;
pIndex->autoIndex = pName==0;
- pIndex->iDb = iDb;
+ pIndex->pSchema = db->aDb[iDb].pSchema;
+
+ /* Check to see if we should honor DESC requests on index columns
+ */
+ if( pDb->pSchema->file_format>=4 ){
+ sortOrderMask = -1; /* Honor DESC */
+ }else{
+ sortOrderMask = 0; /* Ignore DESC */
+ }
/* Scan the names of the columns of the table to be indexed and
** load the column indices into the Index structure. Report an error
** if any column is not found.
*/
- for(i=0; i<pList->nExpr; i++){
- for(j=0; j<pTab->nCol; j++){
- if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[j].zName)==0 ) break;
+ for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
+ const char *zColName = pListItem->zName;
+ Column *pTabCol;
+ int requestedSortOrder;
+ char *zColl; /* Collation sequence */
+
+ for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
+ if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break;
}
if( j>=pTab->nCol ){
sqlite3ErrorMsg(pParse, "table %s has no column named %s",
- pTab->zName, pList->a[i].zName);
+ pTab->zName, zColName);
goto exit_create_index;
}
pIndex->aiColumn[i] = j;
- if( pList->a[i].pExpr ){
- assert( pList->a[i].pExpr->pColl );
- pIndex->keyInfo.aColl[i] = pList->a[i].pExpr->pColl;
+ if( pListItem->pExpr ){
+ assert( pListItem->pExpr->pColl );
+ zColl = zExtra;
+ strcpy(zExtra, pListItem->pExpr->pColl->zName);
+ zExtra += (strlen(zColl) + 1);
}else{
- pIndex->keyInfo.aColl[i] = pTab->aCol[j].pColl;
+ zColl = pTab->aCol[j].zColl;
+ if( !zColl ){
+ zColl = db->pDfltColl->zName;
+ }
}
- assert( pIndex->keyInfo.aColl[i] );
- if( !db->init.busy &&
- sqlite3CheckCollSeq(pParse, pIndex->keyInfo.aColl[i])
- ){
+ if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl, -1) ){
goto exit_create_index;
}
+ pIndex->azColl[i] = zColl;
+ requestedSortOrder = pListItem->sortOrder & sortOrderMask;
+ pIndex->aSortOrder[i] = requestedSortOrder;
}
- pIndex->keyInfo.nField = pList->nExpr;
sqlite3DefaultRowEst(pIndex);
if( pTab==pParse->pNewTable ){
@@ -2232,8 +2506,11 @@ void sqlite3CreateIndex(
if( pIdx->nColumn!=pIndex->nColumn ) continue;
for(k=0; k<pIdx->nColumn; k++){
+ const char *z1 = pIdx->azColl[k];
+ const char *z2 = pIndex->azColl[k];
if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
- if( pIdx->keyInfo.aColl[k]!=pIndex->keyInfo.aColl[k] ) break;
+ if( pIdx->aSortOrder[k]!=pIndex->aSortOrder[k] ) break;
+ if( z1!=z2 && sqlite3StrICmp(z1, z2) ) break;
}
if( k==pIdx->nColumn ){
if( pIdx->onError!=pIndex->onError ){
@@ -2262,7 +2539,7 @@ void sqlite3CreateIndex(
*/
if( db->init.busy ){
Index *p;
- p = sqlite3HashInsert(&db->aDb[pIndex->iDb].idxHash,
+ p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
pIndex->zName, strlen(pIndex->zName)+1, pIndex);
if( p ){
assert( p==pIndex ); /* Malloc must have failed */
@@ -2297,6 +2574,7 @@ void sqlite3CreateIndex(
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto exit_create_index;
+
/* Create the rootpage for the index
*/
sqlite3BeginWriteOperation(pParse, 1, iDb);
@@ -2375,6 +2653,22 @@ exit_create_index:
}
/*
+** Generate code to make sure the file format number is at least minFormat.
+** The generated code will increase the file format number if necessary.
+*/
+void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){
+ Vdbe *v;
+ v = sqlite3GetVdbe(pParse);
+ if( v ){
+ sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1);
+ sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0);
+ sqlite3VdbeAddOp(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3);
+ sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0);
+ sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
+ }
+}
+
+/*
** Fill the Index.aiRowEst[] array with default information - information
** to be used when we have not run the ANALYZE command.
**
@@ -2397,8 +2691,12 @@ void sqlite3DefaultRowEst(Index *pIdx){
int i;
assert( a!=0 );
a[0] = 1000000;
- for(i=pIdx->nColumn; i>=1; i--){
- a[i] = 10;
+ for(i=pIdx->nColumn; i>=5; i--){
+ a[i] = 5;
+ }
+ while( i>=1 ){
+ a[i] = 11 - i;
+ i--;
}
if( pIdx->onError!=OE_None ){
a[pIdx->nColumn] = 1;
@@ -2409,12 +2707,13 @@ void sqlite3DefaultRowEst(Index *pIdx){
** This routine will drop an existing named index. This routine
** implements the DROP INDEX statement.
*/
-void sqlite3DropIndex(Parse *pParse, SrcList *pName){
+void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
Index *pIndex;
Vdbe *v;
sqlite3 *db = pParse->db;
+ int iDb;
- if( pParse->nErr || sqlite3_malloc_failed ){
+ if( pParse->nErr || sqlite3MallocFailed() ){
goto exit_drop_index;
}
assert( pName->nSrc==1 );
@@ -2423,7 +2722,9 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName){
}
pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
if( pIndex==0 ){
- sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0);
+ if( !ifExists ){
+ sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0);
+ }
pParse->checkSchema = 1;
goto exit_drop_index;
}
@@ -2432,16 +2733,17 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName){
"or PRIMARY KEY constraint cannot be dropped", 0);
goto exit_drop_index;
}
+ iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code = SQLITE_DROP_INDEX;
Table *pTab = pIndex->pTable;
- const char *zDb = db->aDb[pIndex->iDb].zName;
- const char *zTab = SCHEMA_TABLE(pIndex->iDb);
+ const char *zDb = db->aDb[iDb].zName;
+ const char *zTab = SCHEMA_TABLE(iDb);
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
goto exit_drop_index;
}
- if( !OMIT_TEMPDB && pIndex->iDb ) code = SQLITE_DROP_TEMP_INDEX;
+ if( !OMIT_TEMPDB && iDb ) code = SQLITE_DROP_TEMP_INDEX;
if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
goto exit_drop_index;
}
@@ -2451,7 +2753,6 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName){
/* Generate code to remove the index and from the master table */
v = sqlite3GetVdbe(pParse);
if( v ){
- int iDb = pIndex->iDb;
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE name=%Q",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
@@ -2611,6 +2912,7 @@ SrcList *sqlite3SrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){
pItem->zName = sqlite3NameFromToken(pTable);
pItem->zDatabase = sqlite3NameFromToken(pDatabase);
pItem->iCursor = -1;
+ pItem->isPopulated = 0;
pList->nSrc++;
return pList;
}
@@ -2621,11 +2923,14 @@ SrcList *sqlite3SrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){
void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
int i;
struct SrcList_item *pItem;
- for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
- if( pItem->iCursor>=0 ) break;
- pItem->iCursor = pParse->nTab++;
- if( pItem->pSelect ){
- sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc);
+ assert(pList || sqlite3MallocFailed() );
+ if( pList ){
+ for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
+ if( pItem->iCursor>=0 ) break;
+ pItem->iCursor = pParse->nTab++;
+ if( pItem->pSelect ){
+ sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc);
+ }
}
}
}
@@ -2667,7 +2972,7 @@ void sqlite3BeginTransaction(Parse *pParse, int type){
int i;
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
- if( pParse->nErr || sqlite3_malloc_failed ) return;
+ if( pParse->nErr || sqlite3MallocFailed() ) return;
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return;
v = sqlite3GetVdbe(pParse);
@@ -2688,7 +2993,7 @@ void sqlite3CommitTransaction(Parse *pParse){
Vdbe *v;
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
- if( pParse->nErr || sqlite3_malloc_failed ) return;
+ if( pParse->nErr || sqlite3MallocFailed() ) return;
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return;
v = sqlite3GetVdbe(pParse);
@@ -2705,7 +3010,7 @@ void sqlite3RollbackTransaction(Parse *pParse){
Vdbe *v;
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
- if( pParse->nErr || sqlite3_malloc_failed ) return;
+ if( pParse->nErr || sqlite3MallocFailed() ) return;
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return;
v = sqlite3GetVdbe(pParse);
@@ -2718,7 +3023,7 @@ void sqlite3RollbackTransaction(Parse *pParse){
** Make sure the TEMP database is open and available for use. Return
** the number of errors. Leave any error messages in the pParse structure.
*/
-static int sqlite3OpenTempDatabase(Parse *pParse){
+int sqlite3OpenTempDatabase(Parse *pParse){
sqlite3 *db = pParse->db;
if( db->aDb[1].pBt==0 && !pParse->explain ){
int rc = sqlite3BtreeFactory(db, 0, 0, MAX_PAGES, &db->aDb[1].pBt);
@@ -2737,6 +3042,7 @@ static int sqlite3OpenTempDatabase(Parse *pParse){
return 1;
}
}
+ assert( db->aDb[1].pSchema );
}
return 0;
}
@@ -2777,11 +3083,11 @@ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
if( iDb>=0 ){
assert( iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 || iDb==1 );
- assert( iDb<32 );
+ assert( iDb<MAX_ATTACHED+2 );
mask = 1<<iDb;
if( (pParse->cookieMask & mask)==0 ){
pParse->cookieMask |= mask;
- pParse->cookieValue[iDb] = db->aDb[iDb].schema_cookie;
+ pParse->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
if( !OMIT_TEMPDB && iDb==1 ){
sqlite3OpenTempDatabase(pParse);
}
@@ -2825,12 +3131,13 @@ void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
** true if it does and false if it does not.
*/
#ifndef SQLITE_OMIT_REINDEX
-static int collationMatch(CollSeq *pColl, Index *pIndex){
- int n = pIndex->keyInfo.nField;
- CollSeq **pp = pIndex->keyInfo.aColl;
- while( n-- ){
- if( *pp==pColl ) return 1;
- pp++;
+static int collationMatch(const char *zColl, Index *pIndex){
+ int i;
+ for(i=0; i<pIndex->nColumn; i++){
+ const char *z = pIndex->azColl[i];
+ if( z==zColl || (z && zColl && 0==sqlite3StrICmp(z, zColl)) ){
+ return 1;
+ }
}
return 0;
}
@@ -2841,12 +3148,13 @@ static int collationMatch(CollSeq *pColl, Index *pIndex){
** If pColl==0 then recompute all indices of pTab.
*/
#ifndef SQLITE_OMIT_REINDEX
-static void reindexTable(Parse *pParse, Table *pTab, CollSeq *pColl){
+static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){
Index *pIndex; /* An index associated with pTab */
for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
- if( pColl==0 || collationMatch(pColl,pIndex) ){
- sqlite3BeginWriteOperation(pParse, 0, pTab->iDb);
+ if( zColl==0 || collationMatch(zColl, pIndex) ){
+ int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3RefillIndex(pParse, pIndex, -1);
}
}
@@ -2859,7 +3167,7 @@ static void reindexTable(Parse *pParse, Table *pTab, CollSeq *pColl){
** all indices everywhere.
*/
#ifndef SQLITE_OMIT_REINDEX
-static void reindexDatabases(Parse *pParse, CollSeq *pColl){
+static void reindexDatabases(Parse *pParse, char const *zColl){
Db *pDb; /* A single database */
int iDb; /* The database index number */
sqlite3 *db = pParse->db; /* The database connection */
@@ -2867,10 +3175,10 @@ static void reindexDatabases(Parse *pParse, CollSeq *pColl){
Table *pTab; /* A table in the database */
for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
- if( pDb==0 ) continue;
- for(k=sqliteHashFirst(&pDb->tblHash); k; k=sqliteHashNext(k)){
+ assert( pDb!=0 );
+ for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
pTab = (Table*)sqliteHashData(k);
- reindexTable(pParse, pTab, pColl);
+ reindexTable(pParse, pTab, zColl);
}
}
}
@@ -2910,9 +3218,14 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
reindexDatabases(pParse, 0);
return;
}else if( pName2==0 || pName2->z==0 ){
- pColl = sqlite3FindCollSeq(db, db->enc, pName1->z, pName1->n, 0);
+ assert( pName1->z );
+ pColl = sqlite3FindCollSeq(db, ENC(db), (char*)pName1->z, pName1->n, 0);
if( pColl ){
- reindexDatabases(pParse, pColl);
+ char *zColl = sqliteStrNDup((const char *)pName1->z, pName1->n);
+ if( zColl ){
+ reindexDatabases(pParse, zColl);
+ sqliteFree(zColl);
+ }
return;
}
}
@@ -2936,3 +3249,38 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed");
}
#endif
+
+/*
+** Return a dynamicly allocated KeyInfo structure that can be used
+** with OP_OpenRead or OP_OpenWrite to access database index pIdx.
+**
+** If successful, a pointer to the new structure is returned. In this case
+** the caller is responsible for calling sqliteFree() on the returned
+** pointer. If an error occurs (out of memory or missing collation
+** sequence), NULL is returned and the state of pParse updated to reflect
+** the error.
+*/
+KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){
+ int i;
+ int nCol = pIdx->nColumn;
+ int nBytes = sizeof(KeyInfo) + (nCol-1)*sizeof(CollSeq*) + nCol;
+ KeyInfo *pKey = (KeyInfo *)sqliteMalloc(nBytes);
+
+ if( pKey ){
+ pKey->aSortOrder = (u8 *)&(pKey->aColl[nCol]);
+ assert( &pKey->aSortOrder[nCol]==&(((u8 *)pKey)[nBytes]) );
+ for(i=0; i<nCol; i++){
+ char *zColl = pIdx->azColl[i];
+ assert( zColl );
+ pKey->aColl[i] = sqlite3LocateCollSeq(pParse, zColl, -1);
+ pKey->aSortOrder[i] = pIdx->aSortOrder[i];
+ }
+ pKey->nField = nCol;
+ }
+
+ if( pParse->nErr ){
+ sqliteFree(pKey);
+ pKey = 0;
+ }
+ return pKey;
+}
diff --git a/ext/pdo_sqlite/sqlite/src/callback.c b/ext/pdo_sqlite/sqlite/src/callback.c
index 2103c3f711..ac748361bb 100644
--- a/ext/pdo_sqlite/sqlite/src/callback.c
+++ b/ext/pdo_sqlite/sqlite/src/callback.c
@@ -29,17 +29,19 @@ static void callCollNeeded(sqlite3 *db, const char *zName, int nName){
if( db->xCollNeeded ){
char *zExternal = sqliteStrNDup(zName, nName);
if( !zExternal ) return;
- db->xCollNeeded(db->pCollNeededArg, db, (int)db->enc, zExternal);
+ db->xCollNeeded(db->pCollNeededArg, db, (int)ENC(db), zExternal);
sqliteFree(zExternal);
}
#ifndef SQLITE_OMIT_UTF16
if( db->xCollNeeded16 ){
char const *zExternal;
- sqlite3_value *pTmp = sqlite3GetTransientValue(db);
- sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF8, SQLITE_STATIC);
+ sqlite3_value *pTmp = sqlite3ValueNew();
+ sqlite3ValueSetStr(pTmp, nName, zName, SQLITE_UTF8, SQLITE_STATIC);
zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE);
- if( !zExternal ) return;
- db->xCollNeeded16(db->pCollNeededArg, db, (int)db->enc, zExternal);
+ if( zExternal ){
+ db->xCollNeeded16(db->pCollNeededArg, db, (int)ENC(db), zExternal);
+ }
+ sqlite3ValueFree(pTmp);
}
#endif
}
@@ -90,14 +92,14 @@ CollSeq *sqlite3GetCollSeq(
p = pColl;
if( !p ){
- p = sqlite3FindCollSeq(db, db->enc, zName, nName, 0);
+ p = sqlite3FindCollSeq(db, ENC(db), zName, nName, 0);
}
if( !p || !p->xCmp ){
/* No collation sequence of this type for this encoding is registered.
** Call the collation factory to see if it can supply us with one.
*/
callCollNeeded(db, zName, nName);
- p = sqlite3FindCollSeq(db, db->enc, zName, nName, 0);
+ p = sqlite3FindCollSeq(db, ENC(db), zName, nName, 0);
}
if( p && !p->xCmp && synthCollSeq(db, p) ){
p = 0;
@@ -128,6 +130,7 @@ int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
pParse->nErr++;
return SQLITE_ERROR;
}
+ assert( p==pColl );
}
return SQLITE_OK;
}
@@ -175,8 +178,11 @@ static CollSeq *findCollSeqEntry(
** return the pColl pointer to be deleted (because it wasn't added
** to the hash table).
*/
- assert( !pDel || (sqlite3_malloc_failed && pDel==pColl) );
- sqliteFree(pDel);
+ assert( !pDel || (sqlite3MallocFailed() && pDel==pColl) );
+ if( pDel ){
+ sqliteFree(pDel);
+ pColl = 0;
+ }
}
}
return pColl;
@@ -197,7 +203,12 @@ CollSeq *sqlite3FindCollSeq(
int nName,
int create
){
- CollSeq *pColl = findCollSeqEntry(db, zName, nName, create);
+ CollSeq *pColl;
+ if( zName ){
+ pColl = findCollSeqEntry(db, zName, nName, create);
+ }else{
+ pColl = db->pDfltColl;
+ }
assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE );
if( pColl ) pColl += enc-1;
@@ -286,7 +297,7 @@ FuncDef *sqlite3FindFunction(
** new entry to the hash table and return it.
*/
if( createFlag && bestmatch<6 &&
- (pBest = sqliteMalloc(sizeof(*pBest)+nName)) ){
+ (pBest = sqliteMalloc(sizeof(*pBest)+nName))!=0 ){
pBest->nArg = nArg;
pBest->pNext = pFirst;
pBest->iPrefEnc = enc;
@@ -303,3 +314,55 @@ FuncDef *sqlite3FindFunction(
}
return 0;
}
+
+/*
+** Free all resources held by the schema structure. The void* argument points
+** at a Schema struct. This function does not call sqliteFree() on the
+** pointer itself, it just cleans up subsiduary resources (i.e. the contents
+** of the schema hash tables).
+*/
+void sqlite3SchemaFree(void *p){
+ Hash temp1;
+ Hash temp2;
+ HashElem *pElem;
+ Schema *pSchema = (Schema *)p;
+
+ temp1 = pSchema->tblHash;
+ temp2 = pSchema->trigHash;
+ sqlite3HashInit(&pSchema->trigHash, SQLITE_HASH_STRING, 0);
+ sqlite3HashClear(&pSchema->aFKey);
+ sqlite3HashClear(&pSchema->idxHash);
+ for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
+ sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem));
+ }
+ sqlite3HashClear(&temp2);
+ sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0);
+ for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
+ Table *pTab = sqliteHashData(pElem);
+ sqlite3DeleteTable(0, pTab);
+ }
+ sqlite3HashClear(&temp1);
+ pSchema->pSeqTab = 0;
+ pSchema->flags &= ~DB_SchemaLoaded;
+}
+
+/*
+** Find and return the schema associated with a BTree. Create
+** a new one if necessary.
+*/
+Schema *sqlite3SchemaGet(Btree *pBt){
+ Schema * p;
+ if( pBt ){
+ p = (Schema *)sqlite3BtreeSchema(pBt,sizeof(Schema),sqlite3SchemaFree);
+ }else{
+ p = (Schema *)sqliteMalloc(sizeof(Schema));
+ }
+ if( p && 0==p->file_format ){
+ sqlite3HashInit(&p->tblHash, SQLITE_HASH_STRING, 0);
+ sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0);
+ sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0);
+ sqlite3HashInit(&p->aFKey, SQLITE_HASH_STRING, 1);
+ p->enc = SQLITE_UTF8;
+ }
+ return p;
+}
diff --git a/ext/pdo_sqlite/sqlite/src/complete.c b/ext/pdo_sqlite/sqlite/src/complete.c
new file mode 100644
index 0000000000..660417b066
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/complete.c
@@ -0,0 +1,263 @@
+/*
+** 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.
+**
+*************************************************************************
+** An tokenizer for SQL
+**
+** This file contains C code that implements the sqlite3_complete() API.
+** This code used to be part of the tokenizer.c source file. But by
+** separating it out, the code will be automatically omitted from
+** static links that do not use it.
+**
+** $Id$
+*/
+#include "sqliteInt.h"
+#ifndef SQLITE_OMIT_COMPLETE
+
+/*
+** This is defined in tokenize.c. We just have to import the definition.
+*/
+extern const char sqlite3IsIdChar[];
+#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsIdChar[c-0x20]))
+
+
+/*
+** Token types used by the sqlite3_complete() routine. See the header
+** comments on that procedure for additional information.
+*/
+#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.
+**
+** Special handling is require for CREATE TRIGGER statements.
+** Whenever the CREATE TRIGGER keywords are seen, the statement
+** must end with ";END;".
+**
+** This implementation uses a state machine with 7 states:
+**
+** (0) START At the beginning or end of an SQL statement. This routine
+** returns 1 if it ends in the START state and 0 if it ends
+** in any other state.
+**
+** (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.
+**
+** (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
+**
+** (4) TRIGGER We are in the middle of a trigger definition that must be
+** ended by a semicolon, the keyword END, and another semicolon.
+**
+** (5) SEMI We've seen the first semicolon in the ";END;" that occurs at
+** the end of a trigger definition.
+**
+** (6) END We've seen the ";END" of the ";END;" that occurs at the end
+** of a trigger difinition.
+**
+** Transitions between states above are determined by tokens extracted
+** from the input. The following tokens are significant:
+**
+** (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 */
+
+#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: ** 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 ){
+ case ';': { /* A semicolon */
+ token = tkSEMI;
+ break;
+ }
+ case ' ':
+ case '\r':
+ case '\t':
+ case '\n':
+ case '\f': { /* White space is ignored */
+ token = tkWS;
+ break;
+ }
+ case '/': { /* C-style comments */
+ if( zSql[1]!='*' ){
+ token = tkOTHER;
+ break;
+ }
+ zSql += 2;
+ while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; }
+ if( zSql[0]==0 ) return 0;
+ zSql++;
+ token = tkWS;
+ break;
+ }
+ case '-': { /* SQL-style comments from "--" to end of line */
+ if( zSql[1]!='-' ){
+ token = tkOTHER;
+ break;
+ }
+ while( *zSql && *zSql!='\n' ){ zSql++; }
+ if( *zSql==0 ) return state==0;
+ token = tkWS;
+ break;
+ }
+ case '[': { /* Microsoft-style identifiers in [...] */
+ zSql++;
+ while( *zSql && *zSql!=']' ){ zSql++; }
+ if( *zSql==0 ) return 0;
+ token = tkOTHER;
+ break;
+ }
+ case '`': /* Grave-accent quoted symbols used by MySQL */
+ case '"': /* single- and double-quoted strings */
+ case '\'': {
+ int c = *zSql;
+ zSql++;
+ while( *zSql && *zSql!=c ){ zSql++; }
+ if( *zSql==0 ) return 0;
+ token = tkOTHER;
+ break;
+ }
+ default: {
+ int c;
+ if( IdChar((u8)*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 ){
+ token = tkCREATE;
+ }else{
+ token = tkOTHER;
+ }
+ break;
+ }
+ case 't': case 'T': {
+ if( nId==7 && sqlite3StrNICmp(zSql, "trigger", 7)==0 ){
+ token = tkTRIGGER;
+ }else if( nId==4 && sqlite3StrNICmp(zSql, "temp", 4)==0 ){
+ token = tkTEMP;
+ }else if( nId==9 && sqlite3StrNICmp(zSql, "temporary", 9)==0 ){
+ token = tkTEMP;
+ }else{
+ token = tkOTHER;
+ }
+ break;
+ }
+ case 'e': case 'E': {
+ if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){
+ token = tkEND;
+ }else
+#ifndef SQLITE_OMIT_EXPLAIN
+ if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){
+ token = tkEXPLAIN;
+ }else
+#endif
+ {
+ token = tkOTHER;
+ }
+ break;
+ }
+ default: {
+ token = tkOTHER;
+ break;
+ }
+ }
+#endif /* SQLITE_OMIT_TRIGGER */
+ zSql += nId-1;
+ }else{
+ /* Operators and special symbols */
+ token = tkOTHER;
+ }
+ break;
+ }
+ }
+ state = trans[state][token];
+ 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
+** UTF-8.
+*/
+int sqlite3_complete16(const void *zSql){
+ sqlite3_value *pVal;
+ char const *zSql8;
+ int rc = 0;
+
+ pVal = sqlite3ValueNew();
+ sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
+ zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8);
+ if( zSql8 ){
+ rc = sqlite3_complete(zSql8);
+ }
+ sqlite3ValueFree(pVal);
+ return sqlite3ApiExit(0, rc);
+}
+#endif /* SQLITE_OMIT_UTF16 */
+#endif /* SQLITE_OMIT_COMPLETE */
diff --git a/ext/pdo_sqlite/sqlite/src/date.c b/ext/pdo_sqlite/sqlite/src/date.c
index 7d398df489..9146906181 100644
--- a/ext/pdo_sqlite/sqlite/src/date.c
+++ b/ext/pdo_sqlite/sqlite/src/date.c
@@ -105,18 +105,20 @@ static int getDigits(const char *zDate, ...){
val = 0;
while( N-- ){
if( !isdigit(*(u8*)zDate) ){
- return cnt;
+ goto end_getDigits;
}
val = val*10 + *zDate - '0';
zDate++;
}
if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
- return cnt;
+ goto end_getDigits;
}
*pVal = val;
zDate++;
cnt++;
}while( nextC );
+end_getDigits:
+ va_end(ap);
return cnt;
}
@@ -236,7 +238,7 @@ static void computeJD(DateTime *p){
if( p->validHMS ){
p->rJD += (p->h*3600.0 + p->m*60.0 + p->s)/86400.0;
if( p->validTZ ){
- p->rJD += p->tz*60/86400.0;
+ p->rJD -= p->tz*60/86400.0;
p->validHMS = 0;
p->validTZ = 0;
}
@@ -639,10 +641,10 @@ static int isDate(int argc, sqlite3_value **argv, DateTime *p){
int i;
if( argc==0 ) return 1;
if( SQLITE_NULL==sqlite3_value_type(argv[0]) ||
- parseDateOrTime(sqlite3_value_text(argv[0]), p) ) return 1;
+ parseDateOrTime((char*)sqlite3_value_text(argv[0]), p) ) return 1;
for(i=1; i<argc; i++){
if( SQLITE_NULL==sqlite3_value_type(argv[i]) ||
- parseModifier(sqlite3_value_text(argv[i]), p) ) return 1;
+ parseModifier((char*)sqlite3_value_text(argv[i]), p) ) return 1;
}
return 0;
}
@@ -755,7 +757,7 @@ static void strftimeFunc(
DateTime x;
int n, i, j;
char *z;
- const char *zFmt = sqlite3_value_text(argv[0]);
+ const char *zFmt = (const char*)sqlite3_value_text(argv[0]);
char zBuf[100];
if( zFmt==0 || isDate(argc-1, argv+1, &x) ) return;
for(i=0, n=1; zFmt[i]; i++, n++){
@@ -816,20 +818,20 @@ static void strftimeFunc(
case 'H': sprintf(&z[j],"%02d",x.h); j+=2; break;
case 'W': /* Fall thru */
case 'j': {
- int n; /* Number of days since 1st day of year */
+ int nDay; /* Number of days since 1st day of year */
DateTime y = x;
y.validJD = 0;
y.M = 1;
y.D = 1;
computeJD(&y);
- n = x.rJD - y.rJD;
+ nDay = x.rJD - y.rJD;
if( zFmt[i]=='W' ){
int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
wd = ((int)(x.rJD+0.5)) % 7;
- sprintf(&z[j],"%02d",(n+7-wd)/7);
+ sprintf(&z[j],"%02d",(nDay+7-wd)/7);
j += 2;
}else{
- sprintf(&z[j],"%03d",n+1);
+ sprintf(&z[j],"%03d",nDay+1);
j += 3;
}
break;
@@ -974,7 +976,7 @@ void sqlite3RegisterDateTimeFunctions(sqlite3 *db){
int i;
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
- sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
+ sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
}
#else
@@ -989,7 +991,7 @@ void sqlite3RegisterDateTimeFunctions(sqlite3 *db){
int i;
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
- sqlite3_create_function(db, aFuncs[i].zName, 0, SQLITE_UTF8,
+ sqlite3CreateFunc(db, aFuncs[i].zName, 0, SQLITE_UTF8,
aFuncs[i].zFormat, currentTimeFunc, 0, 0);
}
#endif
diff --git a/ext/pdo_sqlite/sqlite/src/delete.c b/ext/pdo_sqlite/sqlite/src/delete.c
index 7eb618b78f..ee1bc930b2 100644
--- a/ext/pdo_sqlite/sqlite/src/delete.c
+++ b/ext/pdo_sqlite/sqlite/src/delete.c
@@ -42,8 +42,12 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
** writable return 0;
*/
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
- if( pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0
- && pParse->nested==0 ){
+ if( (pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0
+ && pParse->nested==0)
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ || (pTab->pMod && pTab->pMod->pModule->xUpdate==0)
+#endif
+ ){
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
return 1;
}
@@ -59,14 +63,21 @@ int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
/*
** Generate code that will open a table for reading.
*/
-void sqlite3OpenTableForReading(
- Vdbe *v, /* Generate code into this VDBE */
+void sqlite3OpenTable(
+ Parse *p, /* Generate code into this VDBE */
int iCur, /* The cursor number of the table */
- Table *pTab /* The table to be opened */
+ int iDb, /* The database index in sqlite3.aDb[] */
+ Table *pTab, /* The table to be opened */
+ int opcode /* OP_OpenRead or OP_OpenWrite */
){
- sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
+ Vdbe *v;
+ if( IsVirtual(pTab) ) return;
+ v = sqlite3GetVdbe(p);
+ assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
+ sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName);
+ sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
VdbeComment((v, "# %s", pTab->zName));
- sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
+ sqlite3VdbeAddOp(v, opcode, iCur, pTab->tnum);
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
}
@@ -95,6 +106,7 @@ void sqlite3DeleteFrom(
AuthContext sContext; /* Authorization context */
int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */
NameContext sNC; /* Name context to resolve expressions in */
+ int iDb;
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to delete from a view */
@@ -102,7 +114,7 @@ void sqlite3DeleteFrom(
#endif
sContext.pParse = 0;
- if( pParse->nErr || sqlite3_malloc_failed ){
+ if( pParse->nErr || sqlite3MallocFailed() ){
goto delete_from_cleanup;
}
db = pParse->db;
@@ -134,15 +146,16 @@ void sqlite3DeleteFrom(
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
goto delete_from_cleanup;
}
- assert( pTab->iDb<db->nDb );
- zDb = db->aDb[pTab->iDb].zName;
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ assert( iDb<db->nDb );
+ zDb = db->aDb[iDb].zName;
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
goto delete_from_cleanup;
}
/* If pTab is really a view, make sure it has been initialized.
*/
- if( isView && sqlite3ViewGetColumnNames(pParse, pTab) ){
+ if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto delete_from_cleanup;
}
@@ -176,14 +189,14 @@ void sqlite3DeleteFrom(
goto delete_from_cleanup;
}
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
- sqlite3BeginWriteOperation(pParse, triggers_exist, pTab->iDb);
+ sqlite3BeginWriteOperation(pParse, triggers_exist, iDb);
/* If we are trying to delete from a view, realize that view into
** a ephemeral table.
*/
if( isView ){
Select *pView = sqlite3SelectDup(pTab->pSelect);
- sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0);
+ sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0);
sqlite3SelectDelete(pView);
}
@@ -198,40 +211,36 @@ 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 && !triggers_exist ){
+ if( pWhere==0 && !triggers_exist && !IsVirtual(pTab) ){
if( db->flags & SQLITE_CountRows ){
/* If counting rows deleted, just count the total number of
** entries in the table. */
int endOfLoop = sqlite3VdbeMakeLabel(v);
- int addr;
+ int addr2;
if( !isView ){
- sqlite3OpenTableForReading(v, iCur, pTab);
+ sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
}
sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2);
- addr = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
- sqlite3VdbeAddOp(v, OP_Next, iCur, addr);
+ addr2 = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
+ sqlite3VdbeAddOp(v, OP_Next, iCur, addr2);
sqlite3VdbeResolveLabel(v, endOfLoop);
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
if( !isView ){
- sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb);
+ sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, iDb);
+ if( !pParse->nested ){
+ sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
+ }
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->iDb);
+ assert( pIdx->pSchema==pTab->pSchema );
+ sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, iDb);
}
}
- }
-
+ }
/* The usual case: There is a WHERE clause so we have to scan through
** the table and pick which records to delete.
*/
else{
- /* Ensure all required collation sequences are available. */
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){
- goto delete_from_cleanup;
- }
- }
-
/* Begin the database scan
*/
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
@@ -239,7 +248,7 @@ void sqlite3DeleteFrom(
/* Remember the rowid of every item to be deleted.
*/
- sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
+ sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
@@ -269,7 +278,7 @@ void sqlite3DeleteFrom(
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
if( !isView ){
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- sqlite3OpenTableForReading(v, iCur, pTab);
+ sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
}
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
@@ -300,7 +309,15 @@ void sqlite3DeleteFrom(
}
/* Delete the row */
- sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTab) ){
+ pParse->pVirtualLock = pTab;
+ sqlite3VdbeOp3(v, OP_VUpdate, 0, 1, (const char*)pTab->pVtab, P3_VTAB);
+ }else
+#endif
+ {
+ sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0);
+ }
}
/* If there are row triggers, close all cursors then invoke
@@ -323,7 +340,7 @@ void sqlite3DeleteFrom(
sqlite3VdbeResolveLabel(v, end);
/* Close the cursors after the loop if there are no row triggers */
- if( !triggers_exist ){
+ if( !triggers_exist && !IsVirtual(pTab) ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
}
@@ -339,7 +356,7 @@ void sqlite3DeleteFrom(
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);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P3_STATIC);
}
delete_from_cleanup:
@@ -378,8 +395,11 @@ void sqlite3GenerateRowDelete(
){
int addr;
addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
- sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
+ sqlite3GenerateRowIndexDelete(v, pTab, iCur, 0);
sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
+ if( count ){
+ sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
+ }
sqlite3VdbeJumpHere(v, addr);
}
@@ -400,7 +420,6 @@ void sqlite3GenerateRowDelete(
** deleted.
*/
void sqlite3GenerateRowIndexDelete(
- sqlite3 *db, /* The database containing the index */
Vdbe *v, /* Generate code into this VDBE */
Table *pTab, /* Table containing the row to be deleted */
int iCur, /* Cursor number for the table */
diff --git a/ext/pdo_sqlite/sqlite/src/experimental.c b/ext/pdo_sqlite/sqlite/src/experimental.c
deleted file mode 100644
index ec40891a3a..0000000000
--- a/ext/pdo_sqlite/sqlite/src/experimental.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-** 2005 January 20
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file contains C code routines that are not a part of the official
-** SQLite API. These routines are unsupported.
-**
-** $Id$
-*/
-#include "sqliteInt.h"
-#include "os.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);
-}
diff --git a/ext/pdo_sqlite/sqlite/src/expr.c b/ext/pdo_sqlite/sqlite/src/expr.c
index 1276fe9f6a..e26aba5b38 100644
--- a/ext/pdo_sqlite/sqlite/src/expr.c
+++ b/ext/pdo_sqlite/sqlite/src/expr.c
@@ -75,12 +75,10 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
char sqlite3CompareAffinity(Expr *pExpr, char aff2){
char aff1 = sqlite3ExprAffinity(pExpr);
if( aff1 && aff2 ){
- /* Both sides of the comparison are columns. If one has numeric or
- ** integer affinity, use that. Otherwise use no affinity.
+ /* Both sides of the comparison are columns. If one has numeric
+ ** affinity, use that. Otherwise use no affinity.
*/
- if( aff1==SQLITE_AFF_INTEGER || aff2==SQLITE_AFF_INTEGER ){
- return SQLITE_AFF_INTEGER;
- }else if( aff1==SQLITE_AFF_NUMERIC || aff2==SQLITE_AFF_NUMERIC ){
+ if( sqlite3IsNumericAffinity(aff1) || sqlite3IsNumericAffinity(aff2) ){
return SQLITE_AFF_NUMERIC;
}else{
return SQLITE_AFF_NONE;
@@ -89,7 +87,6 @@ char sqlite3CompareAffinity(Expr *pExpr, char aff2){
/* Neither side of the comparison is a column. Compare the
** results directly.
*/
- /* return SQLITE_AFF_NUMERIC; // Ticket #805 */
return SQLITE_AFF_NONE;
}else{
/* One side is a column, the other is not. Use the columns affinity. */
@@ -129,11 +126,14 @@ static char comparisonAffinity(Expr *pExpr){
*/
int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){
char aff = comparisonAffinity(pExpr);
- return
- (aff==SQLITE_AFF_NONE) ||
- (aff==SQLITE_AFF_NUMERIC && idx_affinity==SQLITE_AFF_INTEGER) ||
- (aff==SQLITE_AFF_INTEGER && idx_affinity==SQLITE_AFF_NUMERIC) ||
- (aff==idx_affinity);
+ switch( aff ){
+ case SQLITE_AFF_NONE:
+ return 1;
+ case SQLITE_AFF_TEXT:
+ return idx_affinity==SQLITE_AFF_TEXT;
+ default:
+ return sqlite3IsNumericAffinity(idx_affinity);
+ }
}
/*
@@ -212,6 +212,19 @@ Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, const Token *pToken){
}
/*
+** Works like sqlite3Expr() but frees its pLeft and pRight arguments
+** if it fails due to a malloc problem.
+*/
+Expr *sqlite3ExprOrFree(int op, Expr *pLeft, Expr *pRight, const Token *pToken){
+ Expr *pNew = sqlite3Expr(op, pLeft, pRight, pToken);
+ if( pNew==0 ){
+ sqlite3ExprDelete(pLeft);
+ sqlite3ExprDelete(pRight);
+ }
+ return pNew;
+}
+
+/*
** When doing a nested parse, you can include terms in an expression
** that look like this: #0 #1 #2 ... These terms refer to elements
** on the stack. "#0" means the top of the stack.
@@ -235,7 +248,7 @@ Expr *sqlite3RegisterExpr(Parse *pParse, Token *pToken){
if( p==0 ){
return 0; /* Malloc failed */
}
- depth = atoi(&pToken->z[1]);
+ depth = atoi((char*)&pToken->z[1]);
p->iTable = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_Dup, depth, 0);
sqlite3VdbeAddOp(v, OP_MemStore, p->iTable, 1);
@@ -263,7 +276,7 @@ Expr *sqlite3ExprAnd(Expr *pLeft, Expr *pRight){
void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
assert( pRight!=0 );
assert( pLeft!=0 );
- if( !sqlite3_malloc_failed && pRight->z && pLeft->z ){
+ if( !sqlite3MallocFailed() && pRight->z && pLeft->z ){
assert( pLeft->dyn==0 || pLeft->z[pLeft->n]==0 );
if( pLeft->dyn==0 && pRight->dyn==0 ){
pExpr->span.z = pLeft->z;
@@ -280,6 +293,7 @@ void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
*/
Expr *sqlite3ExprFunction(ExprList *pList, Token *pToken){
Expr *pNew;
+ assert( pToken );
pNew = sqliteMalloc( sizeof(Expr) );
if( pNew==0 ){
sqlite3ExprListDelete(pList); /* Avoid leaking memory when malloc fails */
@@ -287,12 +301,8 @@ Expr *sqlite3ExprFunction(ExprList *pList, Token *pToken){
}
pNew->op = TK_FUNCTION;
pNew->pList = pList;
- if( pToken ){
- assert( pToken->dyn==0 );
- pNew->token = *pToken;
- }else{
- pNew->token.z = 0;
- }
+ assert( pToken->dyn==0 );
+ pNew->token = *pToken;
pNew->span = pNew->token;
return pNew;
}
@@ -327,7 +337,7 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
/* Wildcard of the form "?nnn". Convert "nnn" to an integer and
** use it as the variable number */
int i;
- pExpr->iTable = i = atoi(&pToken->z[1]);
+ pExpr->iTable = i = atoi((char*)&pToken->z[1]);
if( i<1 || i>SQLITE_MAX_VARIABLE_NUMBER ){
sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
SQLITE_MAX_VARIABLE_NUMBER);
@@ -355,10 +365,10 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
pExpr->iTable = ++pParse->nVar;
if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){
pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10;
- sqlite3ReallocOrFree((void**)&pParse->apVarExpr,
+ sqliteReallocOrFree((void**)&pParse->apVarExpr,
pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) );
}
- if( !sqlite3_malloc_failed ){
+ if( !sqlite3MallocFailed() ){
assert( pParse->apVarExpr!=0 );
pParse->apVarExpr[pParse->nVarExpr++] = pExpr;
}
@@ -415,7 +425,7 @@ Expr *sqlite3ExprDup(Expr *p){
if( pNew==0 ) return 0;
memcpy(pNew, p, sizeof(*pNew));
if( p->token.z!=0 ){
- pNew->token.z = sqliteStrNDup(p->token.z, p->token.n);
+ pNew->token.z = (u8*)sqliteStrNDup((char*)p->token.z, p->token.n);
pNew->token.dyn = 1;
}else{
assert( pNew->token.z==0 );
@@ -432,7 +442,7 @@ void sqlite3TokenCopy(Token *pTo, Token *pFrom){
if( pTo->dyn ) sqliteFree((char*)pTo->z);
if( pFrom->z ){
pTo->n = pFrom->n;
- pTo->z = sqliteStrNDup(pFrom->z, pFrom->n);
+ pTo->z = (u8*)sqliteStrNDup((char*)pFrom->z, pFrom->n);
pTo->dyn = 1;
}else{
pTo->z = 0;
@@ -462,7 +472,8 @@ ExprList *sqlite3ExprListDup(ExprList *p){
sqlite3TokenCopy(&pNewExpr->span, &pOldExpr->span);
}
assert( pNewExpr==0 || pNewExpr->span.z!=0
- || pOldExpr->span.z==0 || sqlite3_malloc_failed );
+ || pOldExpr->span.z==0
+ || sqlite3MallocFailed() );
pItem->zName = sqliteStrDup(pOldItem->zName);
pItem->sortOrder = pOldItem->sortOrder;
pItem->isAgg = pOldItem->isAgg;
@@ -497,6 +508,7 @@ SrcList *sqlite3SrcListDup(SrcList *p){
pNewItem->zAlias = sqliteStrDup(pOldItem->zAlias);
pNewItem->jointype = pOldItem->jointype;
pNewItem->iCursor = pOldItem->iCursor;
+ pNewItem->isPopulated = pOldItem->isPopulated;
pTab = pNewItem->pTab = pOldItem->pTab;
if( pTab ){
pTab->nRef++;
@@ -548,12 +560,12 @@ Select *sqlite3SelectDup(Select *p){
pNew->iOffset = -1;
pNew->isResolved = p->isResolved;
pNew->isAgg = p->isAgg;
- pNew->usesVirt = 0;
+ pNew->usesEphm = 0;
pNew->disallowOrderBy = 0;
pNew->pRightmost = 0;
- pNew->addrOpenVirt[0] = -1;
- pNew->addrOpenVirt[1] = -1;
- pNew->addrOpenVirt[2] = -1;
+ pNew->addrOpenEphm[0] = -1;
+ pNew->addrOpenEphm[1] = -1;
+ pNew->addrOpenEphm[2] = -1;
return pNew;
}
#else
@@ -752,7 +764,7 @@ int sqlite3ExprIsConstantOrFunction(Expr *p){
int sqlite3ExprIsInteger(Expr *p, int *pValue){
switch( p->op ){
case TK_INTEGER: {
- if( sqlite3GetInt32(p->token.z, pValue) ){
+ if( sqlite3GetInt32((char*)p->token.z, pValue) ){
return 1;
}
break;
@@ -809,7 +821,7 @@ int sqlite3IsRowid(const char *z){
** in pParse and return non-zero. Return zero on success.
*/
static int lookupName(
- Parse *pParse, /* The parsing context */
+ Parse *pParse, /* The parsing context */
Token *pDbToken, /* Name of the database containing table, or NULL */
Token *pTableToken, /* Name of table containing column, or NULL */
Token *pColumnToken, /* Name of the column. */
@@ -831,22 +843,24 @@ static int lookupName(
zDb = sqlite3NameFromToken(pDbToken);
zTab = sqlite3NameFromToken(pTableToken);
zCol = sqlite3NameFromToken(pColumnToken);
- if( sqlite3_malloc_failed ){
+ if( sqlite3MallocFailed() ){
goto lookupname_end;
}
pExpr->iTable = -1;
while( pNC && cnt==0 ){
+ ExprList *pEList;
SrcList *pSrcList = pNC->pSrcList;
- ExprList *pEList = pNC->pEList;
- /* assert( zTab==0 || pEList==0 ); */
if( pSrcList ){
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
- Table *pTab = pItem->pTab;
+ Table *pTab;
+ int iDb;
Column *pCol;
- if( pTab==0 ) continue;
+ pTab = pItem->pTab;
+ assert( pTab!=0 );
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( pTab->nCol>0 );
if( zTab ){
if( pItem->zAlias ){
@@ -855,27 +869,28 @@ static int lookupName(
}else{
char *zTabName = pTab->zName;
if( zTabName==0 || sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
- if( zDb!=0 && sqlite3StrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){
+ if( zDb!=0 && sqlite3StrICmp(db->aDb[iDb].zName, zDb)!=0 ){
continue;
}
}
}
if( 0==(cntTab++) ){
pExpr->iTable = pItem->iCursor;
- pExpr->iDb = pTab->iDb;
+ pExpr->pSchema = pTab->pSchema;
pMatch = pItem;
}
for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
+ const char *zColl = pTab->aCol[j].zColl;
IdList *pUsing;
cnt++;
pExpr->iTable = pItem->iCursor;
pMatch = pItem;
- pExpr->iDb = pTab->iDb;
+ pExpr->pSchema = pTab->pSchema;
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
pExpr->iColumn = j==pTab->iPKey ? -1 : j;
pExpr->affinity = pTab->aCol[j].affinity;
- pExpr->pColl = pTab->aCol[j].pColl;
+ pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
if( pItem->jointype & JT_NATURAL ){
/* If this match occurred in the left table of a natural join,
** then skip the right table to avoid a duplicate match */
@@ -919,17 +934,18 @@ static int lookupName(
}
if( pTab ){
- int j;
+ int iCol;
Column *pCol = pTab->aCol;
- pExpr->iDb = pTab->iDb;
+ pExpr->pSchema = pTab->pSchema;
cntTab++;
- for(j=0; j < pTab->nCol; j++, pCol++) {
+ for(iCol=0; iCol < pTab->nCol; iCol++, pCol++) {
if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
+ const char *zColl = pTab->aCol[iCol].zColl;
cnt++;
- pExpr->iColumn = j==pTab->iPKey ? -1 : j;
- pExpr->affinity = pTab->aCol[j].affinity;
- pExpr->pColl = pTab->aCol[j].pColl;
+ pExpr->iColumn = iCol==pTab->iPKey ? -1 : iCol;
+ pExpr->affinity = pTab->aCol[iCol].affinity;
+ pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
pExpr->pTab = pTab;
break;
}
@@ -959,7 +975,7 @@ static int lookupName(
** Note that the expression in the result set should have already been
** resolved by the time the WHERE clause is resolved.
*/
- if( cnt==0 && pEList!=0 && zTab==0 ){
+ if( cnt==0 && (pEList = pNC->pEList)!=0 && zTab==0 ){
for(j=0; j<pEList->nExpr; j++){
char *zAs = pEList->a[j].zName;
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
@@ -1006,9 +1022,9 @@ static int lookupName(
char *zErr;
zErr = cnt==0 ? "no such column: %s" : "ambiguous column name: %s";
if( zDb ){
- sqlite3SetString(&z, zDb, ".", zTab, ".", zCol, 0);
+ sqlite3SetString(&z, zDb, ".", zTab, ".", zCol, (char*)0);
}else if( zTab ){
- sqlite3SetString(&z, zTab, ".", zCol, 0);
+ sqlite3SetString(&z, zTab, ".", zCol, (char*)0);
}else{
z = sqliteStrDup(zCol);
}
@@ -1077,20 +1093,19 @@ lookupname_end_2:
*/
static int nameResolverStep(void *pArg, Expr *pExpr){
NameContext *pNC = (NameContext*)pArg;
- SrcList *pSrcList;
Parse *pParse;
if( pExpr==0 ) return 1;
assert( pNC!=0 );
- pSrcList = pNC->pSrcList;
pParse = pNC->pParse;
if( ExprHasAnyProperty(pExpr, EP_Resolved) ) return 1;
ExprSetProperty(pExpr, EP_Resolved);
#ifndef NDEBUG
- if( pSrcList ){
+ if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){
+ SrcList *pSrcList = pNC->pSrcList;
int i;
- for(i=0; i<pSrcList->nSrc; i++){
+ for(i=0; i<pNC->pSrcList->nSrc; i++){
assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab);
}
}
@@ -1149,9 +1164,9 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
int nId; /* Number of characters in function name */
const char *zId; /* The function name. */
FuncDef *pDef; /* Information about the function */
- int enc = pParse->db->enc; /* The database encoding */
+ int enc = ENC(pParse->db); /* The database encoding */
- zId = pExpr->token.z;
+ zId = (char*)pExpr->token.z;
nId = pExpr->token.n;
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
if( pDef==0 ){
@@ -1197,13 +1212,27 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
case TK_IN: {
if( pExpr->pSelect ){
int nRef = pNC->nRef;
+#ifndef SQLITE_OMIT_CHECK
+ if( pNC->isCheck ){
+ sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints");
+ }
+#endif
sqlite3SelectResolve(pParse, pExpr->pSelect, pNC);
assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){
ExprSetProperty(pExpr, EP_VarSelect);
}
}
+ break;
+ }
+#ifndef SQLITE_OMIT_CHECK
+ case TK_VARIABLE: {
+ if( pNC->isCheck ){
+ sqlite3ErrorMsg(pParse,"parameters prohibited in CHECK constraints");
+ }
+ break;
}
+#endif
}
return 0;
}
@@ -1261,17 +1290,16 @@ struct QueryCoder {
/*
-** Generate code for subqueries and IN operators.
+** Generate code for scalar subqueries used as an expression
+** and IN operators. Examples:
**
-** IN operators comes in two forms:
+** (SELECT a FROM b) -- subquery
+** EXISTS (SELECT a FROM b) -- EXISTS subquery
+** x IN (4,5,11) -- IN operator with list on right-hand side
+** x IN (SELECT a FROM b) -- IN operator with subquery on the right
**
-** expr IN (exprlist)
-** and
-** expr IN (SELECT ...)
-**
-** The first form is handled by creating a set holding the list
-** of allowed values. The second form causes the SELECT to generate
-** a temporary table.
+** The pExpr parameter describes the expression that contains the IN
+** operator or subquery.
*/
#ifndef SQLITE_OMIT_SUBQUERY
void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
@@ -1293,7 +1321,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
int mem = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0);
testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0);
- assert( testAddr>0 || sqlite3_malloc_failed );
+ assert( testAddr>0 || sqlite3MallocFailed() );
sqlite3VdbeAddOp(v, OP_MemInt, 1, mem);
}
@@ -1301,7 +1329,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
case TK_IN: {
char affinity;
KeyInfo keyInfo;
- int addr; /* Address of OP_OpenVirtual instruction */
+ int addr; /* Address of OP_OpenEphemeral instruction */
affinity = sqlite3ExprAffinity(pExpr->pLeft);
@@ -1319,7 +1347,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
** is used.
*/
pExpr->iTable = pParse->nTab++;
- addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, pExpr->iTable, 0);
+ addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, pExpr->iTable, 0);
memset(&keyInfo, 0, sizeof(keyInfo));
keyInfo.nField = 1;
sqlite3VdbeAddOp(v, OP_SetNumColumns, pExpr->iTable, 1);
@@ -1352,7 +1380,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
struct ExprList_item *pItem;
if( !affinity ){
- affinity = SQLITE_AFF_NUMERIC;
+ affinity = SQLITE_AFF_NONE;
}
keyInfo.aColl[0] = pExpr->pLeft->pColl;
@@ -1366,11 +1394,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
** expression we need to rerun this code each time.
*/
if( testAddr>0 && !sqlite3ExprIsConstant(pE2) ){
- VdbeOp *aOp = sqlite3VdbeGetOp(v, testAddr-1);
- int i;
- for(i=0; i<3; i++){
- aOp[i].opcode = OP_Noop;
- }
+ sqlite3VdbeChangeToNoop(v, testAddr-1, 3);
testAddr = 0;
}
@@ -1390,21 +1414,25 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
** value of this select in a memory cell and record the number
** of the memory cell in iColumn.
*/
- int sop;
+ static const Token one = { (u8*)"1", 0, 1 };
Select *pSel;
+ int iMem;
+ int sop;
- pExpr->iColumn = pParse->nMem++;
+ pExpr->iColumn = iMem = pParse->nMem++;
pSel = pExpr->pSelect;
if( pExpr->op==TK_SELECT ){
sop = SRT_Mem;
+ sqlite3VdbeAddOp(v, OP_MemNull, iMem, 0);
+ VdbeComment((v, "# Init subquery result"));
}else{
- static const Token one = { "1", 0, 1 };
sop = SRT_Exists;
- sqlite3ExprListDelete(pSel->pEList);
- pSel->pEList = sqlite3ExprListAppend(0,
- sqlite3Expr(TK_INTEGER, 0, 0, &one), 0);
+ sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem);
+ VdbeComment((v, "# Init EXISTS result"));
}
- sqlite3Select(pParse, pSel, sop, pExpr->iColumn, 0, 0, 0, 0);
+ sqlite3ExprDelete(pSel->pLimit);
+ pSel->pLimit = sqlite3Expr(TK_INTEGER, 0, 0, &one);
+ sqlite3Select(pParse, pSel, sop, iMem, 0, 0, 0, 0);
break;
}
}
@@ -1444,6 +1472,8 @@ static void codeInteger(Vdbe *v, const char *z, int n){
void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
Vdbe *v = pParse->pVdbe;
int op;
+ int stackChng = 1; /* Amount of change to stack depth */
+
if( v==0 ) return;
if( pExpr==0 ){
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
@@ -1465,16 +1495,30 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
/* Otherwise, fall thru into the TK_COLUMN case */
}
case TK_COLUMN: {
- if( pExpr->iColumn>=0 ){
- sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn);
- sqlite3ColumnDefault(v, pExpr->pTab, pExpr->iColumn);
+ if( pExpr->iTable<0 ){
+ /* This only happens when coding check constraints */
+ assert( pParse->ckOffset>0 );
+ sqlite3VdbeAddOp(v, OP_Dup, pParse->ckOffset-pExpr->iColumn-1, 1);
+ }else if( pExpr->iColumn>=0 ){
+ Table *pTab = pExpr->pTab;
+ int iCol = pExpr->iColumn;
+ int op = (pTab && IsVirtual(pTab)) ? OP_VColumn : OP_Column;
+ sqlite3VdbeAddOp(v, op, pExpr->iTable, iCol);
+ sqlite3ColumnDefault(v, pTab, iCol);
+#ifndef SQLITE_OMIT_FLOATING_POINT
+ if( pTab && pTab->aCol[iCol].affinity==SQLITE_AFF_REAL ){
+ sqlite3VdbeAddOp(v, OP_RealAffinity, 0, 0);
+ }
+#endif
}else{
- sqlite3VdbeAddOp(v, OP_Rowid, pExpr->iTable, 0);
+ Table *pTab = pExpr->pTab;
+ int op = (pTab && IsVirtual(pTab)) ? OP_VRowid : OP_Rowid;
+ sqlite3VdbeAddOp(v, op, pExpr->iTable, 0);
}
break;
}
case TK_INTEGER: {
- codeInteger(v, pExpr->token.z, pExpr->token.n);
+ codeInteger(v, (char*)pExpr->token.z, pExpr->token.n);
break;
}
case TK_FLOAT:
@@ -1482,7 +1526,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
assert( TK_FLOAT==OP_Real );
assert( TK_STRING==OP_String8 );
sqlite3DequoteExpr(pExpr);
- sqlite3VdbeOp3(v, op, 0, 0, pExpr->token.z, pExpr->token.n);
+ sqlite3VdbeOp3(v, op, 0, 0, (char*)pExpr->token.z, pExpr->token.n);
break;
}
case TK_NULL: {
@@ -1495,7 +1539,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
const char *z;
assert( TK_BLOB==OP_HexBlob );
n = pExpr->token.n - 3;
- z = pExpr->token.z + 2;
+ z = (char*)pExpr->token.z + 2;
assert( n>=0 );
if( n==0 ){
z = "";
@@ -1507,7 +1551,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
case TK_VARIABLE: {
sqlite3VdbeAddOp(v, OP_Variable, pExpr->iTable, 0);
if( pExpr->token.n>1 ){
- sqlite3VdbeChangeP3(v, -1, pExpr->token.z, pExpr->token.n);
+ sqlite3VdbeChangeP3(v, -1, (char*)pExpr->token.z, pExpr->token.n);
}
break;
}
@@ -1518,16 +1562,17 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
#ifndef SQLITE_OMIT_CAST
case TK_CAST: {
/* Expressions of the form: CAST(pLeft AS token) */
- int aff, op;
+ int aff, to_op;
sqlite3ExprCode(pParse, pExpr->pLeft);
aff = sqlite3AffinityType(&pExpr->token);
- switch( aff ){
- case SQLITE_AFF_INTEGER: op = OP_ToInt; break;
- case SQLITE_AFF_NUMERIC: op = OP_ToNumeric; break;
- case SQLITE_AFF_TEXT: op = OP_ToText; break;
- case SQLITE_AFF_NONE: op = OP_ToBlob; break;
- }
- sqlite3VdbeAddOp(v, op, 0, 0);
+ to_op = aff - SQLITE_AFF_TEXT + OP_ToText;
+ assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT );
+ assert( to_op==OP_ToBlob || aff!=SQLITE_AFF_NONE );
+ assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC );
+ assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER );
+ assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL );
+ sqlite3VdbeAddOp(v, to_op, 0, 0);
+ stackChng = 0;
break;
}
#endif /* SQLITE_OMIT_CAST */
@@ -1546,6 +1591,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3ExprCode(pParse, pExpr->pRight);
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0);
+ stackChng = -1;
break;
}
case TK_AND:
@@ -1574,6 +1620,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3ExprCode(pParse, pExpr->pRight);
sqlite3VdbeAddOp(v, op, 0, 0);
+ stackChng = -1;
break;
}
case TK_UMINUS: {
@@ -1581,8 +1628,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
assert( pLeft );
if( pLeft->op==TK_FLOAT || pLeft->op==TK_INTEGER ){
Token *p = &pLeft->token;
- char *z = sqliteMalloc( p->n + 2 );
- sprintf(z, "-%.*s", p->n, p->z);
+ char *z = sqlite3MPrintf("-%.*s", p->n, p->z);
if( pLeft->op==TK_FLOAT ){
sqlite3VdbeOp3(v, OP_Real, 0, 0, z, p->n+1);
}else{
@@ -1599,6 +1645,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
assert( TK_NOT==OP_Not );
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3VdbeAddOp(v, op, 0, 0);
+ stackChng = 0;
break;
}
case TK_ISNULL:
@@ -1611,11 +1658,17 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
dest = sqlite3VdbeCurrentAddr(v) + 2;
sqlite3VdbeAddOp(v, op, 1, dest);
sqlite3VdbeAddOp(v, OP_AddImm, -1, 0);
+ stackChng = 0;
break;
}
case TK_AGG_FUNCTION: {
AggInfo *pInfo = pExpr->pAggInfo;
- sqlite3VdbeAddOp(v, OP_MemLoad, pInfo->aFunc[pExpr->iAgg].iMem, 0);
+ if( pInfo==0 ){
+ sqlite3ErrorMsg(pParse, "misuse of aggregate: %T",
+ &pExpr->span);
+ }else{
+ sqlite3VdbeAddOp(v, OP_MemLoad, pInfo->aFunc[pExpr->iAgg].iMem, 0);
+ }
break;
}
case TK_CONST_FUNC:
@@ -1627,13 +1680,32 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
const char *zId;
int constMask = 0;
int i;
- u8 enc = pParse->db->enc;
+ u8 enc = ENC(pParse->db);
CollSeq *pColl = 0;
- zId = pExpr->token.z;
+ zId = (char*)pExpr->token.z;
nId = pExpr->token.n;
pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, enc, 0);
assert( pDef!=0 );
nExpr = sqlite3ExprCodeExprList(pParse, pList);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ /* Possibly overload the function if the first argument is
+ ** a virtual table column.
+ **
+ ** For infix functions (LIKE, GLOB, REGEXP, and MATCH) use the
+ ** second argument, not the first, as the argument to test to
+ ** see if it is a column in a virtual table. This is done because
+ ** the left operand of infix functions (the operand we want to
+ ** control overloading) ends up as the second argument to the
+ ** function. The expression "A glob B" is equivalent to
+ ** "glob(B,A). We want to use the A in "A glob B" to test
+ ** for function overloading. But we use the B term in "glob(B,A)".
+ */
+ if( nExpr>=2 && (pExpr->flags & EP_InfixFunc) ){
+ pDef = sqlite3VtabOverloadFunction(pDef, nExpr, pList->a[1].pExpr);
+ }else if( nExpr>0 ){
+ pDef = sqlite3VtabOverloadFunction(pDef, nExpr, pList->a[0].pExpr);
+ }
+#endif
for(i=0; i<nExpr && i<32; i++){
if( sqlite3ExprIsConstant(pList->a[i].pExpr) ){
constMask |= (1<<i);
@@ -1647,12 +1719,15 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ);
}
sqlite3VdbeOp3(v, OP_Function, constMask, nExpr, (char*)pDef, P3_FUNCDEF);
+ stackChng = 1-nExpr;
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
case TK_EXISTS:
case TK_SELECT: {
- sqlite3CodeSubselect(pParse, pExpr);
+ if( pExpr->iColumn==0 ){
+ sqlite3CodeSubselect(pParse, pExpr);
+ }
sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0);
VdbeComment((v, "# load subquery result"));
break;
@@ -1660,6 +1735,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
case TK_IN: {
int addr;
char affinity;
+ int ckOffset = pParse->ckOffset;
sqlite3CodeSubselect(pParse, pExpr);
/* Figure out the affinity to use to create a key from the results
@@ -1669,6 +1745,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
affinity = comparisonAffinity(pExpr);
sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
+ pParse->ckOffset = ckOffset+1;
/* Code the <expr> from "<expr> IN (...)". The temporary table
** pExpr->iTable contains the values that make up the (...) set.
@@ -1705,6 +1782,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
case TK_UPLUS:
case TK_AS: {
sqlite3ExprCode(pParse, pExpr->pLeft);
+ stackChng = 0;
break;
}
case TK_CASE: {
@@ -1763,16 +1841,22 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
pExpr->iColumn == OE_Fail );
sqlite3DequoteExpr(pExpr);
sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn,
- pExpr->token.z, pExpr->token.n);
+ (char*)pExpr->token.z, pExpr->token.n);
} else {
assert( pExpr->iColumn == OE_Ignore );
sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0);
sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->trigStack->ignoreJump);
VdbeComment((v, "# raise(IGNORE)"));
}
+ stackChng = 0;
+ break;
}
#endif
- break;
+ }
+
+ if( pParse->ckOffset ){
+ pParse->ckOffset += stackChng;
+ assert( pParse->ckOffset );
}
}
@@ -1840,6 +1924,7 @@ int sqlite3ExprCodeExprList(
void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Vdbe *v = pParse->pVdbe;
int op = 0;
+ int ckOffset = pParse->ckOffset;
if( v==0 || pExpr==0 ) return;
op = pExpr->op;
switch( op ){
@@ -1914,6 +1999,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
break;
}
}
+ pParse->ckOffset = ckOffset;
}
/*
@@ -1927,6 +2013,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Vdbe *v = pParse->pVdbe;
int op = 0;
+ int ckOffset = pParse->ckOffset;
if( v==0 || pExpr==0 ) return;
/* The value of pExpr->op and op are related as follows:
@@ -2023,6 +2110,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
break;
}
}
+ pParse->ckOffset = ckOffset;
}
/*
@@ -2031,10 +2119,8 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
*/
int sqlite3ExprCompare(Expr *pA, Expr *pB){
int i;
- if( pA==0 ){
- return pB==0;
- }else if( pB==0 ){
- return 0;
+ if( pA==0||pB==0 ){
+ return pB==pA;
}
if( pA->op!=pB->op ) return 0;
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0;
@@ -2056,7 +2142,9 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
if( pA->token.z ){
if( pB->token.z==0 ) return 0;
if( pB->token.n!=pA->token.n ) return 0;
- if( sqlite3StrNICmp(pA->token.z, pB->token.z, pB->token.n)!=0 ) return 0;
+ if( sqlite3StrNICmp((char*)pA->token.z,(char*)pB->token.z,pB->token.n)!=0 ){
+ return 0;
+ }
}
return 1;
}
@@ -2180,14 +2268,14 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){
if( i>=pAggInfo->nFunc ){
/* pExpr is original. Make a new entry in pAggInfo->aFunc[]
*/
- u8 enc = pParse->db->enc;
+ u8 enc = ENC(pParse->db);
i = addAggInfoFunc(pAggInfo);
if( i>=0 ){
pItem = &pAggInfo->aFunc[i];
pItem->pExpr = pExpr;
pItem->iMem = pParse->nMem++;
pItem->pFunc = sqlite3FindFunction(pParse->db,
- pExpr->token.z, pExpr->token.n,
+ (char*)pExpr->token.z, pExpr->token.n,
pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
if( pExpr->flags & EP_Distinct ){
pItem->iDistinct = pParse->nTab++;
diff --git a/ext/pdo_sqlite/sqlite/src/func.c b/ext/pdo_sqlite/sqlite/src/func.c
index cdb674fa28..bf422f92c5 100644
--- a/ext/pdo_sqlite/sqlite/src/func.c
+++ b/ext/pdo_sqlite/sqlite/src/func.c
@@ -20,7 +20,6 @@
*/
#include "sqliteInt.h"
#include <ctype.h>
-#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include "vdbeInt.h"
@@ -101,7 +100,7 @@ static void lengthFunc(
break;
}
case SQLITE_TEXT: {
- const char *z = sqlite3_value_text(argv[0]);
+ const unsigned char *z = sqlite3_value_text(argv[0]);
for(len=0; *z; z++){ if( (0xc0&*z)!=0x80 ) len++; }
sqlite3_result_int(context, len);
break;
@@ -121,7 +120,13 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
switch( sqlite3_value_type(argv[0]) ){
case SQLITE_INTEGER: {
i64 iVal = sqlite3_value_int64(argv[0]);
- if( iVal<0 ) iVal = iVal * -1;
+ if( iVal<0 ){
+ if( (iVal<<1)==0 ){
+ sqlite3_result_error(context, "integer overflow", -1);
+ return;
+ }
+ iVal = -iVal;
+ }
sqlite3_result_int64(context, iVal);
break;
}
@@ -131,7 +136,7 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}
default: {
double rVal = sqlite3_value_double(argv[0]);
- if( rVal<0 ) rVal = rVal * -1.0;
+ if( rVal<0 ) rVal = -rVal;
sqlite3_result_double(context, rVal);
break;
}
@@ -146,8 +151,8 @@ static void substrFunc(
int argc,
sqlite3_value **argv
){
- const char *z;
- const char *z2;
+ const unsigned char *z;
+ const unsigned char *z2;
int i;
int p1, p2, len;
@@ -178,7 +183,7 @@ static void substrFunc(
}
while( z[i] && (z[i]&0xc0)==0x80 ){ i++; p2++; }
if( p2<0 ) p2 = 0;
- sqlite3_result_text(context, &z[p1], p2, SQLITE_TRANSIENT);
+ sqlite3_result_text(context, (char*)&z[p1], p2, SQLITE_TRANSIENT);
}
/*
@@ -195,10 +200,11 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
if( n>30 ) n = 30;
if( n<0 ) n = 0;
}
- if( SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
r = sqlite3_value_double(argv[0]);
sqlite3_snprintf(sizeof(zBuf),zBuf,"%.*f",n,r);
- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
+ sqlite3AtoF(zBuf, &r);
+ sqlite3_result_double(context, r);
}
/*
@@ -210,11 +216,11 @@ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
z = sqliteMalloc(sqlite3_value_bytes(argv[0])+1);
if( z==0 ) return;
- strcpy(z, sqlite3_value_text(argv[0]));
+ strcpy((char*)z, (char*)sqlite3_value_text(argv[0]));
for(i=0; z[i]; i++){
z[i] = toupper(z[i]);
}
- sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
+ sqlite3_result_text(context, (char*)z, -1, SQLITE_TRANSIENT);
sqliteFree(z);
}
static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
@@ -223,11 +229,11 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
z = sqliteMalloc(sqlite3_value_bytes(argv[0])+1);
if( z==0 ) return;
- strcpy(z, sqlite3_value_text(argv[0]));
+ strcpy((char*)z, (char*)sqlite3_value_text(argv[0]));
for(i=0; z[i]; i++){
z[i] = tolower(z[i]);
}
- sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
+ sqlite3_result_text(context, (char*)z, -1, SQLITE_TRANSIENT);
sqliteFree(z);
}
@@ -258,9 +264,11 @@ static void randomFunc(
int argc,
sqlite3_value **argv
){
- int r;
+ sqlite_int64 r;
sqlite3Randomness(sizeof(r), &r);
- sqlite3_result_int(context, r);
+ if( (r<<1)==0 ) r = 0; /* Prevent 0x8000.... as the result so that we */
+ /* can always do abs() of the result */
+ sqlite3_result_int64(context, r);
}
/*
@@ -495,7 +503,7 @@ static void likeFunc(
** Otherwise, return an error.
*/
const unsigned char *zEsc = sqlite3_value_text(argv[2]);
- if( sqlite3utf8CharLen(zEsc, -1)!=1 ){
+ if( sqlite3utf8CharLen((char*)zEsc, -1)!=1 ){
sqlite3_result_error(context,
"ESCAPE expression must be a single character", -1);
return;
@@ -539,6 +547,19 @@ static void versionFunc(
sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
}
+/*
+** The MATCH() function is unimplemented. If anybody tries to use it,
+** return an error.
+*/
+static void matchStub(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ static const char zErr[] = "MATCH is not implemented";
+ sqlite3_result_error(context, zErr, sizeof(zErr)-1);
+}
+
/*
** EXPERIMENTAL - This is not an official function. The interface may
@@ -592,7 +613,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}
case SQLITE_TEXT: {
int i,j,n;
- const char *zArg = sqlite3_value_text(argv[0]);
+ const unsigned char *zArg = sqlite3_value_text(argv[0]);
char *z;
for(i=n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; }
@@ -633,6 +654,7 @@ static void soundexFunc(sqlite3_context *context, int argc, sqlite3_value **argv
};
assert( argc==1 );
zIn = (u8*)sqlite3_value_text(argv[0]);
+ if( zIn==0 ) zIn = "";
for(i=0; zIn[i] && !isalpha(zIn[i]); i++){}
if( zIn[i] ){
zResult[0] = toupper(zIn[i]);
@@ -653,6 +675,26 @@ static void soundexFunc(sqlite3_context *context, int argc, sqlite3_value **argv
}
#endif
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+/*
+** A function that loads a shared-library extension then returns NULL.
+*/
+static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){
+ const char *zFile = (const char *)sqlite3_value_text(argv[0]);
+ const char *zProc = 0;
+ sqlite3 *db = sqlite3_user_data(context);
+ char *zErrMsg = 0;
+
+ if( argc==2 ){
+ zProc = (const char *)sqlite3_value_text(argv[1]);
+ }
+ if( sqlite3_load_extension(db, zFile, zProc, &zErrMsg) ){
+ sqlite3_result_error(context, zErrMsg, -1);
+ sqlite3_free(zErrMsg);
+ }
+}
+#endif
+
#ifdef SQLITE_TEST
/*
** This function generates a string of random characters. Used for
@@ -692,7 +734,7 @@ static void randStr(sqlite3_context *context, int argc, sqlite3_value **argv){
zBuf[i] = zSrc[zBuf[i]%(sizeof(zSrc)-1)];
}
zBuf[n] = 0;
- sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT);
+ sqlite3_result_text(context, (char*)zBuf, n, SQLITE_TRANSIENT);
}
#endif /* SQLITE_TEST */
@@ -728,17 +770,17 @@ static void test_destructor(
test_destructor_count_var++;
assert( nArg==1 );
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
- len = sqlite3ValueBytes(argv[0], db->enc);
+ len = sqlite3ValueBytes(argv[0], ENC(db));
zVal = sqliteMalloc(len+3);
zVal[len] = 0;
zVal[len-1] = 0;
assert( zVal );
zVal++;
- memcpy(zVal, sqlite3ValueText(argv[0], db->enc), len);
- if( db->enc==SQLITE_UTF8 ){
+ memcpy(zVal, sqlite3ValueText(argv[0], ENC(db)), len);
+ if( ENC(db)==SQLITE_UTF8 ){
sqlite3_result_text(pCtx, zVal, -1, destructor);
#ifndef SQLITE_OMIT_UTF16
- }else if( db->enc==SQLITE_UTF16LE ){
+ }else if( ENC(db)==SQLITE_UTF16LE ){
sqlite3_result_text16le(pCtx, zVal, -1, destructor);
}else{
sqlite3_result_text16be(pCtx, zVal, -1, destructor);
@@ -776,7 +818,7 @@ static void test_auxdata(
char *zRet = sqliteMalloc(nArg*2);
if( !zRet ) return;
for(i=0; i<nArg; i++){
- char const *z = sqlite3_value_text(argv[i]);
+ char const *z = (char*)sqlite3_value_text(argv[i]);
if( z ){
char *zAux = sqlite3_get_auxdata(pCtx, i);
if( zAux ){
@@ -807,7 +849,7 @@ static void test_error(
int nArg,
sqlite3_value **argv
){
- sqlite3_result_error(pCtx, sqlite3_value_text(argv[0]), 0);
+ sqlite3_result_error(pCtx, (char*)sqlite3_value_text(argv[0]), 0);
}
#endif /* SQLITE_TEST */
@@ -817,25 +859,45 @@ static void test_error(
*/
typedef struct SumCtx SumCtx;
struct SumCtx {
- double sum; /* Sum of terms */
- int cnt; /* Number of elements summed */
- u8 seenFloat; /* True if there has been any floating point value */
+ double rSum; /* Floating point sum */
+ i64 iSum; /* Integer sum */
+ i64 cnt; /* Number of elements summed */
+ u8 overflow; /* True if integer overflow seen */
+ u8 approx; /* True if non-integer value was input to the sum */
};
/*
-** Routines used to compute the sum or average.
+** Routines used to compute the sum, average, and total.
+**
+** The SUM() function follows the (broken) SQL standard which means
+** that it returns NULL if it sums over no inputs. TOTAL returns
+** 0.0 in that case. In addition, TOTAL always returns a float where
+** SUM might return an integer if it never encounters a floating point
+** value. TOTAL never fails, but SUM might through an exception if
+** it overflows an integer.
*/
static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
SumCtx *p;
int type;
assert( argc==1 );
p = sqlite3_aggregate_context(context, sizeof(*p));
- type = sqlite3_value_type(argv[0]);
+ type = sqlite3_value_numeric_type(argv[0]);
if( p && type!=SQLITE_NULL ){
- p->sum += sqlite3_value_double(argv[0]);
p->cnt++;
- if( type==SQLITE_FLOAT ){
- p->seenFloat = 1;
+ if( type==SQLITE_INTEGER ){
+ i64 v = sqlite3_value_int64(argv[0]);
+ p->rSum += v;
+ if( (p->approx|p->overflow)==0 ){
+ i64 iNewSum = p->iSum + v;
+ int s1 = p->iSum >> (sizeof(i64)*8-1);
+ int s2 = v >> (sizeof(i64)*8-1);
+ int s3 = iNewSum >> (sizeof(i64)*8-1);
+ p->overflow = (s1&s2&~s3) | (~s1&~s2&s3);
+ p->iSum = iNewSum;
+ }
+ }else{
+ p->rSum += sqlite3_value_double(argv[0]);
+ p->approx = 1;
}
}
}
@@ -843,10 +905,12 @@ static void sumFinalize(sqlite3_context *context){
SumCtx *p;
p = sqlite3_aggregate_context(context, 0);
if( p && p->cnt>0 ){
- if( p->seenFloat ){
- sqlite3_result_double(context, p->sum);
+ if( p->overflow ){
+ sqlite3_result_error(context,"integer overflow",-1);
+ }else if( p->approx ){
+ sqlite3_result_double(context, p->rSum);
}else{
- sqlite3_result_int64(context, (i64)p->sum);
+ sqlite3_result_int64(context, p->iSum);
}
}
}
@@ -854,20 +918,14 @@ static void avgFinalize(sqlite3_context *context){
SumCtx *p;
p = sqlite3_aggregate_context(context, 0);
if( p && p->cnt>0 ){
- sqlite3_result_double(context, p->sum/(double)p->cnt);
+ sqlite3_result_double(context, p->rSum/(double)p->cnt);
}
}
-
-/*
-** An instance of the following structure holds the context of a
-** variance or standard deviation computation.
-*/
-typedef struct StdDevCtx StdDevCtx;
-struct StdDevCtx {
- double sum; /* Sum of terms */
- double sum2; /* Sum of the squares of terms */
- int cnt; /* Number of terms counted */
-};
+static void totalFinalize(sqlite3_context *context){
+ SumCtx *p;
+ p = sqlite3_aggregate_context(context, 0);
+ sqlite3_result_double(context, p ? p->rSum : 0.0);
+}
/*
** The following structure keeps track of state information for the
@@ -875,7 +933,7 @@ struct StdDevCtx {
*/
typedef struct CountCtx CountCtx;
struct CountCtx {
- int n;
+ i64 n;
};
/*
@@ -891,7 +949,7 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
static void countFinalize(sqlite3_context *context){
CountCtx *p;
p = sqlite3_aggregate_context(context, 0);
- sqlite3_result_int(context, p ? p->n : 0);
+ sqlite3_result_int64(context, p ? p->n : 0);
}
/*
@@ -978,9 +1036,14 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
{ "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid },
{ "changes", 0, 1, SQLITE_UTF8, 0, changes },
{ "total_changes", 0, 1, SQLITE_UTF8, 0, total_changes },
+ { "match", 2, 0, SQLITE_UTF8, 0, matchStub },
#ifdef SQLITE_SOUNDEX
{ "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
#endif
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ { "load_extension", 1, 1, SQLITE_UTF8, 0, loadExt },
+ { "load_extension", 2, 1, SQLITE_UTF8, 0, loadExt },
+#endif
#ifdef SQLITE_TEST
{ "randstr", 2, 0, SQLITE_UTF8, 0, randStr },
{ "test_destructor", 1, 1, SQLITE_UTF8, 0, test_destructor},
@@ -1000,6 +1063,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
{ "min", 1, 0, 1, minmaxStep, minMaxFinalize },
{ "max", 1, 2, 1, minmaxStep, minMaxFinalize },
{ "sum", 1, 0, 0, sumStep, sumFinalize },
+ { "total", 1, 0, 0, sumStep, totalFinalize },
{ "avg", 1, 0, 0, sumStep, avgFinalize },
{ "count", 0, 0, 0, countStep, countFinalize },
{ "count", 1, 0, 0, countStep, countFinalize },
@@ -1012,7 +1076,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
case 1: pArg = db; break;
case 2: pArg = (void *)(-1); break;
}
- sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
+ sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
aFuncs[i].eTextRep, pArg, aFuncs[i].xFunc, 0, 0);
if( aFuncs[i].needCollSeq ){
FuncDef *pFunc = sqlite3FindFunction(db, aFuncs[i].zName,
@@ -1025,13 +1089,16 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions(db);
#endif
+#ifndef SQLITE_OMIT_PARSER
+ sqlite3AttachFunctions(db);
+#endif
for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
void *pArg = 0;
switch( aAggs[i].argType ){
case 1: pArg = db; break;
case 2: pArg = (void *)(-1); break;
}
- sqlite3_create_function(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8,
+ sqlite3CreateFunc(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8,
pArg, 0, aAggs[i].xStep, aAggs[i].xFinalize);
if( aAggs[i].needCollSeq ){
FuncDef *pFunc = sqlite3FindFunction( db, aAggs[i].zName,
@@ -1043,7 +1110,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
}
sqlite3RegisterDateTimeFunctions(db);
#ifdef SQLITE_SSE
- sqlite3SseFunctions(db);
+ (void)sqlite3SseFunctions(db);
#endif
#ifdef SQLITE_CASE_SENSITIVE_LIKE
sqlite3RegisterLikeFunctions(db, 1);
@@ -1075,9 +1142,9 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
}else{
pInfo = (struct compareInfo*)&likeInfoNorm;
}
- sqlite3_create_function(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
- sqlite3_create_function(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
- sqlite3_create_function(db, "glob", 2, SQLITE_UTF8,
+ sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
+ sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
+ sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8,
(struct compareInfo*)&globInfo, likeFunc, 0,0);
setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
setLikeOptFlag(db, "like",
@@ -1099,7 +1166,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
if( pExpr->pList->nExpr!=2 ){
return 0;
}
- pDef = sqlite3FindFunction(db, pExpr->token.z, pExpr->token.n, 2,
+ pDef = sqlite3FindFunction(db, (char*)pExpr->token.z, pExpr->token.n, 2,
SQLITE_UTF8, 0);
if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){
return 0;
diff --git a/ext/pdo_sqlite/sqlite/src/hash.c b/ext/pdo_sqlite/sqlite/src/hash.c
index e01aae7163..1c32c1b7cc 100644
--- a/ext/pdo_sqlite/sqlite/src/hash.c
+++ b/ext/pdo_sqlite/sqlite/src/hash.c
@@ -41,6 +41,8 @@ void sqlite3HashInit(Hash *pNew, int keyClass, int copyKey){
pNew->count = 0;
pNew->htsize = 0;
pNew->ht = 0;
+ pNew->xMalloc = sqlite3MallocX;
+ pNew->xFree = sqlite3FreeX;
}
/* Remove all entries from a hash table. Reclaim all memory.
@@ -53,15 +55,15 @@ void sqlite3HashClear(Hash *pH){
assert( pH!=0 );
elem = pH->first;
pH->first = 0;
- if( pH->ht ) sqliteFree(pH->ht);
+ if( pH->ht ) pH->xFree(pH->ht);
pH->ht = 0;
pH->htsize = 0;
while( elem ){
HashElem *next_elem = elem->next;
if( pH->copyKey && elem->pKey ){
- sqliteFree(elem->pKey);
+ pH->xFree(elem->pKey);
}
- sqliteFree(elem);
+ pH->xFree(elem);
elem = next_elem;
}
pH->count = 0;
@@ -222,9 +224,9 @@ static void rehash(Hash *pH, int new_size){
int (*xHash)(const void*,int); /* The hash function */
assert( (new_size & (new_size-1))==0 );
- new_ht = (struct _ht *)sqliteMalloc( new_size*sizeof(struct _ht) );
+ new_ht = (struct _ht *)pH->xMalloc( new_size*sizeof(struct _ht) );
if( new_ht==0 ) return;
- if( pH->ht ) sqliteFree(pH->ht);
+ if( pH->ht ) pH->xFree(pH->ht);
pH->ht = new_ht;
pH->htsize = new_size;
xHash = hashFunction(pH->keyClass);
@@ -290,10 +292,15 @@ static void removeElementGivenHash(
pEntry->chain = 0;
}
if( pH->copyKey && elem->pKey ){
- sqliteFree(elem->pKey);
+ pH->xFree(elem->pKey);
}
- sqliteFree( elem );
+ pH->xFree( elem );
pH->count--;
+ if( pH->count<=0 ){
+ assert( pH->first==0 );
+ assert( pH->count==0 );
+ sqlite3HashClear(pH);
+ }
}
/* Attempt to locate an element of the hash table pH with a key
@@ -353,12 +360,12 @@ void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){
return old_data;
}
if( data==0 ) return 0;
- new_elem = (HashElem*)sqliteMalloc( sizeof(HashElem) );
+ new_elem = (HashElem*)pH->xMalloc( sizeof(HashElem) );
if( new_elem==0 ) return data;
if( pH->copyKey && pKey!=0 ){
- new_elem->pKey = sqliteMallocRaw( nKey );
+ new_elem->pKey = pH->xMalloc( nKey );
if( new_elem->pKey==0 ){
- sqliteFree(new_elem);
+ pH->xFree(new_elem);
return data;
}
memcpy((void*)new_elem->pKey, pKey, nKey);
@@ -371,7 +378,7 @@ void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){
rehash(pH,8);
if( pH->htsize==0 ){
pH->count = 0;
- sqliteFree(new_elem);
+ pH->xFree(new_elem);
return data;
}
}
diff --git a/ext/pdo_sqlite/sqlite/src/hash.h b/ext/pdo_sqlite/sqlite/src/hash.h
index cf004ddc53..4707649489 100644
--- a/ext/pdo_sqlite/sqlite/src/hash.h
+++ b/ext/pdo_sqlite/sqlite/src/hash.h
@@ -34,6 +34,8 @@ struct Hash {
char copyKey; /* True if copy of key made on insert */
int count; /* Number of entries in this table */
HashElem *first; /* The first element of the array */
+ void *(*xMalloc)(int); /* malloc() function to use */
+ void (*xFree)(void *); /* free() function to use */
int htsize; /* Number of buckets in the hash table */
struct _ht { /* the hash table */
int count; /* Number of entries with this hash */
diff --git a/ext/pdo_sqlite/sqlite/src/insert.c b/ext/pdo_sqlite/sqlite/src/insert.c
index 37f9f4ee57..d4cf74a3d7 100644
--- a/ext/pdo_sqlite/sqlite/src/insert.c
+++ b/ext/pdo_sqlite/sqlite/src/insert.c
@@ -23,10 +23,11 @@
**
** Character Column affinity
** ------------------------------
-** 'n' NUMERIC
-** 'i' INTEGER
-** 't' TEXT
-** 'o' NONE
+** 'a' TEXT
+** 'b' NONE
+** 'c' NUMERIC
+** 'd' INTEGER
+** 'e' REAL
*/
void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
if( !pIdx->zColAff ){
@@ -61,10 +62,11 @@ void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
**
** Character Column affinity
** ------------------------------
-** 'n' NUMERIC
-** 'i' INTEGER
-** 't' TEXT
-** 'o' NONE
+** 'a' TEXT
+** 'b' NONE
+** 'c' NUMERIC
+** 'd' INTEGER
+** 'e' REAL
*/
void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
/* The first time a column affinity string for a particular table
@@ -102,15 +104,15 @@ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
**
** No checking is done for sub-selects that are part of expressions.
*/
-static int selectReadsTable(Select *p, int iDb, int iTab){
+static int selectReadsTable(Select *p, Schema *pSchema, 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(pItem->pSelect, iDb, iTab) ) return 1;
+ if( selectReadsTable(pItem->pSelect, pSchema, iTab) ) return 1;
}else{
- if( pItem->pTab->iDb==iDb && pItem->pTab->tnum==iTab ) return 1;
+ if( pItem->pTab->pSchema==pSchema && pItem->pTab->tnum==iTab ) return 1;
}
}
return 0;
@@ -212,6 +214,7 @@ void sqlite3Insert(
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 iDb;
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to insert into a view */
@@ -219,10 +222,12 @@ void sqlite3Insert(
#endif
#ifndef SQLITE_OMIT_AUTOINCREMENT
- int counterRowid; /* Memory cell holding rowid of autoinc counter */
+ int counterRowid = 0; /* Memory cell holding rowid of autoinc counter */
#endif
- if( pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup;
+ if( pParse->nErr || sqlite3MallocFailed() ){
+ goto insert_cleanup;
+ }
db = pParse->db;
/* Locate the table into which we will be inserting new information.
@@ -234,8 +239,9 @@ void sqlite3Insert(
if( pTab==0 ){
goto insert_cleanup;
}
- assert( pTab->iDb<db->nDb );
- pDb = &db->aDb[pTab->iDb];
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ assert( iDb<db->nDb );
+ pDb = &db->aDb[iDb];
zDb = pDb->zName;
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){
goto insert_cleanup;
@@ -263,27 +269,22 @@ void sqlite3Insert(
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
goto insert_cleanup;
}
- if( pTab==0 ) goto insert_cleanup;
+ assert( pTab!=0 );
/* If pTab is really a view, make sure it has been initialized.
+ ** ViewGetColumnNames() is a no-op if pTab is not a view (or virtual
+ ** module table).
*/
- if( isView && sqlite3ViewGetColumnNames(pParse, pTab) ){
+ if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto insert_cleanup;
}
- /* Ensure all required collation sequences are available. */
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){
- goto insert_cleanup;
- }
- }
-
/* Allocate a VDBE
*/
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto insert_cleanup;
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
- sqlite3BeginWriteOperation(pParse, pSelect || triggers_exist, pTab->iDb);
+ sqlite3BeginWriteOperation(pParse, pSelect || triggers_exist, iDb);
/* if there are row triggers, allocate a temp table for new.* references. */
if( triggers_exist ){
@@ -298,22 +299,20 @@ void sqlite3Insert(
*/
if( pTab->autoInc ){
int iCur = pParse->nTab;
- int base = sqlite3VdbeCurrentAddr(v);
+ int addr = 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);
+ sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
+ sqlite3VdbeAddOp(v, OP_Rewind, iCur, addr+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_Ne, 0x100, addr+12);
sqlite3VdbeAddOp(v, OP_Rowid, 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_Goto, 0, addr+13);
+ sqlite3VdbeAddOp(v, OP_Next, iCur, addr+4);
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
#endif /* SQLITE_OMIT_AUTOINCREMENT */
@@ -336,7 +335,9 @@ void sqlite3Insert(
/* 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;
+ if( rc || pParse->nErr || sqlite3MallocFailed() ){
+ goto insert_cleanup;
+ }
iCleanup = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup);
@@ -351,7 +352,7 @@ void sqlite3Insert(
** of the tables being read by the SELECT statement. Also use a
** temp table in the case of row triggers.
*/
- if( triggers_exist || selectReadsTable(pSelect, pTab->iDb, pTab->tnum) ){
+ if( triggers_exist || selectReadsTable(pSelect,pTab->pSchema,pTab->tnum) ){
useTempTable = 1;
}
@@ -362,7 +363,6 @@ void sqlite3Insert(
srcTab = pParse->nTab++;
sqlite3VdbeResolveLabel(v, iInsertBlock);
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
- sqlite3TableAffinityStr(v, pTab);
sqlite3VdbeAddOp(v, OP_NewRowid, srcTab, 0);
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
sqlite3VdbeAddOp(v, OP_Insert, srcTab, 0);
@@ -373,7 +373,7 @@ void sqlite3Insert(
** back up and execute the SELECT code above.
*/
sqlite3VdbeJumpHere(v, iInitCode);
- sqlite3VdbeAddOp(v, OP_OpenVirtual, srcTab, 0);
+ sqlite3VdbeAddOp(v, OP_OpenEphemeral, srcTab, 0);
sqlite3VdbeAddOp(v, OP_SetNumColumns, srcTab, nColumn);
sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop);
sqlite3VdbeResolveLabel(v, iCleanup);
@@ -569,6 +569,10 @@ void sqlite3Insert(
** case the record number is the same as that column.
*/
if( !isView ){
+ if( IsVirtual(pTab) ){
+ /* The row that the VUpdate opcode will delete: none */
+ sqlite3VdbeAddOp(v, OP_Null, 0, 0);
+ }
if( keyColumn>=0 ){
if( useTempTable ){
sqlite3VdbeAddOp(v, OP_Column, srcTab, keyColumn);
@@ -584,6 +588,8 @@ void sqlite3Insert(
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem);
sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
+ }else if( IsVirtual(pTab) ){
+ sqlite3VdbeAddOp(v, OP_Null, 0, 0);
}else{
sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem);
}
@@ -626,16 +632,25 @@ void sqlite3Insert(
/* Generate code to check constraints and generate index keys and
** do the insertion.
*/
- sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0,
- 0, onError, endOfLoop);
- sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0,
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTab) ){
+ pParse->pVirtualLock = pTab;
+ sqlite3VdbeOp3(v, OP_VUpdate, 1, pTab->nCol+2,
+ (const char*)pTab->pVtab, P3_VTAB);
+ }else
+#endif
+ {
+ sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0,
+ 0, onError, endOfLoop);
+ sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0,
(triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1);
+ }
}
/* Update the count of rows that are inserted
*/
if( (db->flags & SQLITE_CountRows)!=0 ){
- sqlite3VdbeAddOp(v, OP_MemIncr, iCntMem, 0);
+ sqlite3VdbeAddOp(v, OP_MemIncr, 1, iCntMem);
}
if( triggers_exist ){
@@ -667,7 +682,7 @@ void sqlite3Insert(
sqlite3VdbeResolveLabel(v, iCleanup);
}
- if( !triggers_exist ){
+ if( !triggers_exist && !IsVirtual(pTab) ){
/* Close all tables opened */
sqlite3VdbeAddOp(v, OP_Close, base, 0);
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
@@ -682,12 +697,10 @@ void sqlite3Insert(
*/
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);
+ int addr = sqlite3VdbeCurrentAddr(v);
+ sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
sqlite3VdbeAddOp(v, OP_MemLoad, counterRowid, 0);
- sqlite3VdbeAddOp(v, OP_NotNull, -1, base+7);
+ sqlite3VdbeAddOp(v, OP_NotNull, -1, addr+7);
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
sqlite3VdbeAddOp(v, OP_NewRowid, iCur, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
@@ -707,7 +720,7 @@ void sqlite3Insert(
sqlite3VdbeAddOp(v, OP_MemLoad, iCntMem, 0);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, "rows inserted", P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", P3_STATIC);
}
insert_cleanup:
@@ -870,7 +883,24 @@ void sqlite3GenerateConstraintChecks(
/* Test all CHECK constraints
*/
- /**** TBD ****/
+#ifndef SQLITE_OMIT_CHECK
+ if( pTab->pCheck && (pParse->db->flags & SQLITE_IgnoreChecks)==0 ){
+ int allOk = sqlite3VdbeMakeLabel(v);
+ assert( pParse->ckOffset==0 );
+ pParse->ckOffset = nCol;
+ sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, 1);
+ assert( pParse->ckOffset==nCol );
+ pParse->ckOffset = 0;
+ onError = overrideError!=OE_Default ? overrideError : OE_Abort;
+ if( onError==OE_Ignore || onError==OE_Replace ){
+ sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRowids, 0);
+ sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest);
+ }else{
+ sqlite3VdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError);
+ }
+ sqlite3VdbeResolveLabel(v, allOk);
+ }
+#endif /* !defined(SQLITE_OMIT_CHECK) */
/* If we have an INTEGER PRIMARY KEY, make sure the primary key
** of the new record does not previously exist. Except, if this
@@ -904,7 +934,7 @@ void sqlite3GenerateConstraintChecks(
break;
}
case OE_Replace: {
- sqlite3GenerateRowIndexDelete(pParse->db, v, pTab, base, 0);
+ sqlite3GenerateRowIndexDelete(v, pTab, base, 0);
if( isUpdate ){
sqlite3VdbeAddOp(v, OP_Dup, nCol+hasTwoRowids, 1);
sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);
@@ -1067,9 +1097,13 @@ void sqlite3CompleteInsertion(
if( pParse->nested ){
pik_flags = 0;
}else{
- pik_flags = (OPFLAG_NCHANGE|(isUpdate?0:OPFLAG_LASTROWID));
+ pik_flags = OPFLAG_NCHANGE;
+ pik_flags |= (isUpdate?OPFLAG_ISUPDATE:OPFLAG_LASTROWID);
}
sqlite3VdbeAddOp(v, OP_Insert, base, pik_flags);
+ if( !pParse->nested ){
+ sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
+ }
if( isUpdate && rowidChng ){
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
@@ -1088,18 +1122,21 @@ void sqlite3OpenTableAndIndices(
int op /* OP_OpenRead or OP_OpenWrite */
){
int i;
+ int iDb;
Index *pIdx;
- Vdbe *v = sqlite3GetVdbe(pParse);
+ Vdbe *v;
+
+ if( IsVirtual(pTab) ) return;
+ iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ v = sqlite3GetVdbe(pParse);
assert( v!=0 );
- sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
- VdbeComment((v, "# %s", pTab->zName));
- sqlite3VdbeAddOp(v, op, base, pTab->tnum);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, base, pTab->nCol);
+ sqlite3OpenTable(pParse, base, iDb, pTab, op);
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
- sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
+ KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
+ assert( pIdx->pSchema==pTab->pSchema );
+ sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
VdbeComment((v, "# %s", pIdx->zName));
- sqlite3VdbeOp3(v, op, i+base, pIdx->tnum,
- (char*)&pIdx->keyInfo, P3_KEYINFO);
+ sqlite3VdbeOp3(v, op, i+base, pIdx->tnum, (char*)pKey, P3_KEYINFO_HANDOFF);
}
if( pParse->nTab<=base+i ){
pParse->nTab = base+i;
diff --git a/ext/pdo_sqlite/sqlite/src/keywordhash.h b/ext/pdo_sqlite/sqlite/src/keywordhash.h
index f825ba977c..bc0898f3be 100644
--- a/ext/pdo_sqlite/sqlite/src/keywordhash.h
+++ b/ext/pdo_sqlite/sqlite/src/keywordhash.h
@@ -1,61 +1,61 @@
-/* Hash score: 156 */
+/* Hash score: 167 */
static int keywordCode(const char *z, int n){
- static const char zText[526] =
+ static const char zText[544] =
"ABORTABLEFTEMPORARYADDATABASELECTHENDEFAULTRANSACTIONATURALTER"
"AISEACHECKEYAFTEREFERENCESCAPELSEXCEPTRIGGEREGEXPLAINITIALLYANALYZE"
"XCLUSIVEXISTSTATEMENTANDEFERRABLEATTACHAVINGLOBEFOREIGNOREINDEX"
"AUTOINCREMENTBEGINNERENAMEBETWEENOTNULLIKEBYCASCADEFERREDELETE"
"CASECASTCOLLATECOLUMNCOMMITCONFLICTCONSTRAINTERSECTCREATECROSS"
- "CURRENT_DATECURRENT_TIMESTAMPRAGMATCHDESCDETACHDISTINCTDROPRIMARY"
- "FAILIMITFROMFULLGROUPDATEIMMEDIATEINSERTINSTEADINTOFFSETISNULL"
- "JOINORDEREPLACEOUTERESTRICTRIGHTROLLBACKROWHENUNIONUNIQUEUSING"
- "VACUUMVALUESVIEWHERE";
+ "CURRENT_DATECURRENT_TIMESTAMPLANDESCDETACHDISTINCTDROPRAGMATCH"
+ "FAILIMITFROMFULLGROUPDATEIFIMMEDIATEINSERTINSTEADINTOFFSETISNULL"
+ "JOINORDEREPLACEOUTERESTRICTPRIMARYQUERYRIGHTROLLBACKROWHENUNION"
+ "UNIQUEUSINGVACUUMVALUESVIEWHEREVIRTUAL";
static const unsigned char aHash[127] = {
- 91, 81, 104, 90, 0, 4, 0, 0, 111, 0, 77, 0, 0,
- 94, 44, 0, 92, 0, 103, 106, 96, 0, 0, 10, 0, 0,
- 110, 0, 107, 102, 0, 28, 48, 0, 41, 0, 0, 65, 71,
- 0, 63, 19, 0, 0, 36, 83, 0, 105, 74, 0, 0, 33,
- 0, 61, 37, 0, 8, 0, 112, 38, 12, 0, 78, 40, 25,
- 66, 0, 0, 31, 82, 53, 30, 50, 20, 88, 0, 34, 0,
+ 92, 80, 107, 91, 0, 4, 0, 0, 114, 0, 83, 0, 0,
+ 95, 44, 76, 93, 0, 106, 109, 97, 90, 0, 10, 0, 0,
+ 113, 0, 117, 103, 0, 28, 48, 0, 41, 0, 0, 65, 71,
+ 0, 63, 19, 0, 105, 36, 104, 0, 108, 74, 0, 0, 33,
+ 0, 61, 37, 0, 8, 0, 115, 38, 12, 0, 77, 40, 25,
+ 66, 0, 0, 31, 81, 53, 30, 50, 20, 88, 0, 34, 0,
75, 26, 0, 72, 0, 0, 0, 64, 47, 67, 22, 87, 29,
- 69, 86, 0, 1, 0, 9, 100, 58, 18, 0, 109, 76, 98,
- 54, 6, 85, 0, 0, 49, 93, 0, 101, 0, 70, 0, 0,
- 15, 0, 113, 51, 56, 0, 2, 55, 0, 108,
+ 69, 86, 0, 1, 0, 9, 101, 58, 18, 0, 112, 82, 99,
+ 54, 6, 85, 0, 0, 49, 94, 0, 102, 0, 70, 0, 0,
+ 15, 0, 116, 51, 56, 0, 2, 55, 0, 111,
};
- static const unsigned char aNext[113] = {
+ static const unsigned char aNext[117] = {
0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0,
0, 11, 0, 0, 0, 0, 5, 13, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0,
0, 0, 16, 0, 23, 52, 0, 0, 0, 0, 45, 0, 59,
- 0, 0, 0, 0, 0, 0, 0, 0, 73, 42, 0, 0, 24,
- 60, 21, 0, 80, 32, 68, 0, 0, 84, 46, 0, 0, 0,
- 0, 0, 0, 0, 39, 95, 97, 0, 0, 99, 0, 14, 27,
- 79, 0, 57, 89, 0, 35, 0, 62, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 73, 42, 0, 24, 60,
+ 21, 0, 79, 0, 0, 68, 0, 0, 84, 46, 0, 0, 0,
+ 0, 0, 0, 0, 0, 39, 96, 98, 0, 0, 100, 0, 32,
+ 0, 14, 27, 78, 0, 57, 89, 0, 35, 0, 62, 0, 110,
};
- static const unsigned char aLen[113] = {
+ static const unsigned char aLen[117] = {
5, 5, 4, 4, 9, 2, 3, 8, 2, 6, 4, 3, 7,
11, 2, 7, 5, 5, 4, 5, 3, 5, 10, 6, 4, 6,
7, 6, 7, 9, 3, 7, 9, 6, 9, 3, 10, 6, 6,
4, 6, 3, 7, 6, 7, 5, 13, 2, 2, 5, 5, 6,
7, 3, 7, 4, 4, 2, 7, 3, 8, 6, 4, 4, 7,
- 6, 6, 8, 10, 9, 6, 5, 12, 12, 17, 6, 5, 4,
- 6, 8, 2, 4, 7, 4, 5, 4, 4, 5, 6, 9, 6,
- 7, 4, 2, 6, 3, 6, 4, 5, 7, 5, 8, 5, 8,
- 3, 4, 5, 6, 5, 6, 6, 4, 5,
+ 6, 6, 8, 10, 9, 6, 5, 12, 12, 17, 4, 4, 6,
+ 8, 2, 4, 6, 5, 4, 5, 4, 4, 5, 6, 2, 9,
+ 6, 7, 4, 2, 6, 3, 6, 4, 5, 7, 5, 8, 7,
+ 5, 5, 8, 3, 4, 5, 6, 5, 6, 6, 4, 5, 7,
};
- static const unsigned short int aOffset[113] = {
+ static const unsigned short int aOffset[117] = {
0, 4, 7, 10, 10, 14, 19, 21, 26, 27, 32, 34, 36,
42, 51, 52, 57, 61, 65, 67, 71, 74, 78, 86, 91, 94,
99, 105, 108, 113, 118, 122, 128, 136, 141, 150, 152, 162, 167,
172, 175, 177, 177, 181, 185, 187, 192, 194, 196, 205, 208, 212,
218, 224, 224, 227, 230, 234, 236, 237, 241, 248, 254, 258, 262,
- 269, 275, 281, 289, 296, 305, 311, 316, 328, 328, 344, 348, 353,
- 357, 363, 364, 371, 374, 381, 384, 389, 393, 397, 400, 406, 415,
- 421, 428, 431, 431, 434, 437, 443, 447, 451, 458, 462, 470, 475,
- 483, 485, 489, 494, 500, 505, 511, 517, 520,
+ 269, 275, 281, 289, 296, 305, 311, 316, 328, 328, 344, 348, 352,
+ 358, 359, 366, 369, 373, 378, 381, 386, 390, 394, 397, 403, 405,
+ 414, 420, 427, 430, 430, 433, 436, 442, 446, 450, 457, 461, 469,
+ 476, 481, 486, 494, 496, 500, 505, 511, 516, 522, 528, 531, 536,
};
- static const unsigned char aCode[113] = {
+ static const unsigned char aCode[117] = {
TK_ABORT, TK_TABLE, TK_JOIN_KW, TK_TEMP, TK_TEMP,
TK_OR, TK_ADD, TK_DATABASE, TK_AS, TK_SELECT,
TK_THEN, TK_END, TK_DEFAULT, TK_TRANSACTION,TK_ON,
@@ -71,19 +71,20 @@ static int keywordCode(const char *z, int n){
TK_DEFERRED, TK_DELETE, TK_CASE, TK_CAST, TK_COLLATE,
TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_CONSTRAINT, TK_INTERSECT,
TK_CREATE, TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, TK_CTIME_KW,
- TK_PRAGMA, TK_MATCH, TK_DESC, TK_DETACH, TK_DISTINCT,
- TK_IS, TK_DROP, TK_PRIMARY, TK_FAIL, TK_LIMIT,
- TK_FROM, TK_JOIN_KW, TK_GROUP, TK_UPDATE, TK_IMMEDIATE,
- TK_INSERT, TK_INSTEAD, TK_INTO, TK_OF, TK_OFFSET,
- TK_SET, TK_ISNULL, TK_JOIN, TK_ORDER, TK_REPLACE,
- TK_JOIN_KW, TK_RESTRICT, TK_JOIN_KW, TK_ROLLBACK, TK_ROW,
- TK_WHEN, TK_UNION, TK_UNIQUE, TK_USING, TK_VACUUM,
- TK_VALUES, TK_VIEW, TK_WHERE,
+ TK_PLAN, TK_DESC, TK_DETACH, TK_DISTINCT, TK_IS,
+ TK_DROP, TK_PRAGMA, TK_MATCH, TK_FAIL, TK_LIMIT,
+ TK_FROM, TK_JOIN_KW, TK_GROUP, TK_UPDATE, TK_IF,
+ TK_IMMEDIATE, TK_INSERT, TK_INSTEAD, TK_INTO, TK_OF,
+ TK_OFFSET, TK_SET, TK_ISNULL, TK_JOIN, TK_ORDER,
+ TK_REPLACE, TK_JOIN_KW, TK_RESTRICT, TK_PRIMARY, TK_QUERY,
+ TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_WHEN, TK_UNION,
+ TK_UNIQUE, TK_USING, TK_VACUUM, TK_VALUES, TK_VIEW,
+ TK_WHERE, TK_VIRTUAL,
};
int h, i;
if( n<2 ) return TK_ID;
- h = ((sqlite3UpperToLower[((unsigned char*)z)[0]]*4) ^
- (sqlite3UpperToLower[((unsigned char*)z)[n-1]]*3) ^
+ h = ((charMap(z[0])*4) ^
+ (charMap(z[n-1])*3) ^
n) % 127;
for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){
if( aLen[i]==n && sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){
@@ -92,6 +93,6 @@ static int keywordCode(const char *z, int n){
}
return TK_ID;
}
-int sqlite3KeywordCode(const char *z, int n){
- return keywordCode(z, n);
+int sqlite3KeywordCode(const unsigned char *z, int n){
+ return keywordCode((char*)z, n);
}
diff --git a/ext/pdo_sqlite/sqlite/src/legacy.c b/ext/pdo_sqlite/sqlite/src/legacy.c
index f575f1f0ce..c75791e1bd 100644
--- a/ext/pdo_sqlite/sqlite/src/legacy.c
+++ b/ext/pdo_sqlite/sqlite/src/legacy.c
@@ -54,8 +54,8 @@ int sqlite3_exec(
pStmt = 0;
rc = sqlite3_prepare(db, zSql, -1, &pStmt, &zLeftover);
+ assert( rc==SQLITE_OK || pStmt==0 );
if( rc!=SQLITE_OK ){
- if( pStmt ) sqlite3_finalize(pStmt);
continue;
}
if( !pStmt ){
@@ -68,9 +68,8 @@ int sqlite3_exec(
nCallback = 0;
nCol = sqlite3_column_count(pStmt);
- azCols = sqliteMalloc(2*nCol*sizeof(const char *));
- if( nCol && !azCols ){
- rc = SQLITE_NOMEM;
+ azCols = sqliteMalloc(2*nCol*sizeof(const char *) + 1);
+ if( azCols==0 ){
goto exec_out;
}
@@ -122,11 +121,9 @@ exec_out:
if( pStmt ) sqlite3_finalize(pStmt);
if( azCols ) sqliteFree(azCols);
- if( sqlite3_malloc_failed ){
- rc = SQLITE_NOMEM;
- }
+ rc = sqlite3ApiExit(0, rc);
if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){
- *pzErrMsg = malloc(1+strlen(sqlite3_errmsg(db)));
+ *pzErrMsg = sqlite3_malloc(1+strlen(sqlite3_errmsg(db)));
if( *pzErrMsg ){
strcpy(*pzErrMsg, sqlite3_errmsg(db));
}
diff --git a/ext/pdo_sqlite/sqlite/src/loadext.c b/ext/pdo_sqlite/sqlite/src/loadext.c
new file mode 100644
index 0000000000..60ec053cfb
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/loadext.c
@@ -0,0 +1,355 @@
+/*
+** 2006 June 7
+**
+** 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 code used to dynamically load extensions into
+** the SQLite library.
+*/
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+
+#define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */
+#include "sqlite3ext.h"
+#include "sqliteInt.h"
+#include <string.h>
+#include <ctype.h>
+
+/*
+** Some API routines are omitted when various features are
+** excluded from a build of SQLite. Substitute a NULL pointer
+** for any missing APIs.
+*/
+#ifndef SQLITE_ENABLE_COLUMN_METADATA
+# define sqlite3_column_database_name 0
+# define sqlite3_column_database_name16 0
+# define sqlite3_column_table_name 0
+# define sqlite3_column_table_name16 0
+# define sqlite3_column_origin_name 0
+# define sqlite3_column_origin_name16 0
+# define sqlite3_table_column_metadata 0
+#endif
+
+#ifdef SQLITE_OMIT_AUTHORIZATION
+# define sqlite3_set_authorizer 0
+#endif
+
+#ifdef SQLITE_OMIT_UTF16
+# define sqlite3_bind_text16 0
+# define sqlite3_collation_needed16 0
+# define sqlite3_column_decltype16 0
+# define sqlite3_column_name16 0
+# define sqlite3_column_text16 0
+# define sqlite3_complete16 0
+# define sqlite3_create_collation16 0
+# define sqlite3_create_function16 0
+# define sqlite3_errmsg16 0
+# define sqlite3_open16 0
+# define sqlite3_prepare16 0
+# define sqlite3_result_error16 0
+# define sqlite3_result_text16 0
+# define sqlite3_result_text16be 0
+# define sqlite3_result_text16le 0
+# define sqlite3_value_text16 0
+# define sqlite3_value_text16be 0
+# define sqlite3_value_text16le 0
+#endif
+
+#ifdef SQLITE_OMIT_COMPLETE
+# define sqlite3_complete 0
+# define sqlite3_complete16 0
+#endif
+
+#ifdef SQLITE_OMIT_PROGRESS_CALLBACK
+# define sqlite3_progress_handler 0
+#endif
+
+#ifdef SQLITE_OMIT_VIRTUALTABLE
+# define sqlite3_create_module 0
+# define sqlite3_declare_vtab 0
+#endif
+
+/*
+** The following structure contains pointers to all SQLite API routines.
+** A pointer to this structure is passed into extensions when they are
+** loaded so that the extension can make calls back into the SQLite
+** library.
+**
+** When adding new APIs, add them to the bottom of this structure
+** in order to preserve backwards compatibility.
+**
+** Extensions that use newer APIs should first call the
+** sqlite3_libversion_number() to make sure that the API they
+** intend to use is supported by the library. Extensions should
+** also check to make sure that the pointer to the function is
+** not NULL before calling it.
+*/
+const sqlite3_api_routines sqlite3_api = {
+ sqlite3_aggregate_context,
+ sqlite3_aggregate_count,
+ sqlite3_bind_blob,
+ sqlite3_bind_double,
+ sqlite3_bind_int,
+ sqlite3_bind_int64,
+ sqlite3_bind_null,
+ sqlite3_bind_parameter_count,
+ sqlite3_bind_parameter_index,
+ sqlite3_bind_parameter_name,
+ sqlite3_bind_text,
+ sqlite3_bind_text16,
+ sqlite3_bind_value,
+ sqlite3_busy_handler,
+ sqlite3_busy_timeout,
+ sqlite3_changes,
+ sqlite3_close,
+ sqlite3_collation_needed,
+ sqlite3_collation_needed16,
+ sqlite3_column_blob,
+ sqlite3_column_bytes,
+ sqlite3_column_bytes16,
+ sqlite3_column_count,
+ sqlite3_column_database_name,
+ sqlite3_column_database_name16,
+ sqlite3_column_decltype,
+ sqlite3_column_decltype16,
+ sqlite3_column_double,
+ sqlite3_column_int,
+ sqlite3_column_int64,
+ sqlite3_column_name,
+ sqlite3_column_name16,
+ sqlite3_column_origin_name,
+ sqlite3_column_origin_name16,
+ sqlite3_column_table_name,
+ sqlite3_column_table_name16,
+ sqlite3_column_text,
+ sqlite3_column_text16,
+ sqlite3_column_type,
+ sqlite3_column_value,
+ sqlite3_commit_hook,
+ sqlite3_complete,
+ sqlite3_complete16,
+ sqlite3_create_collation,
+ sqlite3_create_collation16,
+ sqlite3_create_function,
+ sqlite3_create_function16,
+ sqlite3_create_module,
+ sqlite3_data_count,
+ sqlite3_db_handle,
+ sqlite3_declare_vtab,
+ sqlite3_enable_shared_cache,
+ sqlite3_errcode,
+ sqlite3_errmsg,
+ sqlite3_errmsg16,
+ sqlite3_exec,
+ sqlite3_expired,
+ sqlite3_finalize,
+ sqlite3_free,
+ sqlite3_free_table,
+ sqlite3_get_autocommit,
+ sqlite3_get_auxdata,
+ sqlite3_get_table,
+ sqlite3_global_recover,
+ sqlite3_interrupt,
+ sqlite3_last_insert_rowid,
+ sqlite3_libversion,
+ sqlite3_libversion_number,
+ sqlite3_malloc,
+ sqlite3_mprintf,
+ sqlite3_open,
+ sqlite3_open16,
+ sqlite3_prepare,
+ sqlite3_prepare16,
+ sqlite3_profile,
+ sqlite3_progress_handler,
+ sqlite3_realloc,
+ sqlite3_reset,
+ sqlite3_result_blob,
+ sqlite3_result_double,
+ sqlite3_result_error,
+ sqlite3_result_error16,
+ sqlite3_result_int,
+ sqlite3_result_int64,
+ sqlite3_result_null,
+ sqlite3_result_text,
+ sqlite3_result_text16,
+ sqlite3_result_text16be,
+ sqlite3_result_text16le,
+ sqlite3_result_value,
+ sqlite3_rollback_hook,
+ sqlite3_set_authorizer,
+ sqlite3_set_auxdata,
+ sqlite3_snprintf,
+ sqlite3_step,
+ sqlite3_table_column_metadata,
+ sqlite3_thread_cleanup,
+ sqlite3_total_changes,
+ sqlite3_trace,
+ sqlite3_transfer_bindings,
+ sqlite3_update_hook,
+ sqlite3_user_data,
+ sqlite3_value_blob,
+ sqlite3_value_bytes,
+ sqlite3_value_bytes16,
+ sqlite3_value_double,
+ sqlite3_value_int,
+ sqlite3_value_int64,
+ sqlite3_value_numeric_type,
+ sqlite3_value_text,
+ sqlite3_value_text16,
+ sqlite3_value_text16be,
+ sqlite3_value_text16le,
+ sqlite3_value_type,
+ sqlite3_vmprintf,
+ /*
+ ** The original API set ends here. All extensions can call any
+ ** of the APIs above provided that the pointer is not NULL. But
+ ** before calling APIs that follow, extension should check the
+ ** sqlite3_libversion_number() to make sure they are dealing with
+ ** a library that is new enough to support that API.
+ *************************************************************************
+ */
+};
+
+/*
+** The windows implementation of shared-library loaders
+*/
+#if defined(_WIN32) || defined(WIN32) || defined(__MINGW32__) || defined(__BORLANDC__)
+# include <windows.h>
+# define SQLITE_LIBRARY_TYPE HANDLE
+# define SQLITE_OPEN_LIBRARY(A) LoadLibrary(A)
+# define SQLITE_FIND_SYMBOL(A,B) GetProcAddress(A,B)
+# define SQLITE_CLOSE_LIBRARY(A) FreeLibrary(A)
+#endif /* windows */
+
+/*
+** The unix implementation of shared-library loaders
+*/
+#if defined(HAVE_DLOPEN) && !defined(SQLITE_LIBRARY_TYPE)
+# include <dlfcn.h>
+# define SQLITE_LIBRARY_TYPE void*
+# define SQLITE_OPEN_LIBRARY(A) dlopen(A, RTLD_NOW | RTLD_GLOBAL)
+# define SQLITE_FIND_SYMBOL(A,B) dlsym(A,B)
+# define SQLITE_CLOSE_LIBRARY(A) dlclose(A)
+#endif
+
+/*
+** Attempt to load an SQLite extension library contained in the file
+** zFile. The entry point is zProc. zProc may be 0 in which case a
+** default entry point name (sqlite3_extension_init) is used. Use
+** of the default name is recommended.
+**
+** Return SQLITE_OK on success and SQLITE_ERROR if something goes wrong.
+**
+** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with
+** error message text. The calling function should free this memory
+** by calling sqlite3_free().
+*/
+int sqlite3_load_extension(
+ sqlite3 *db, /* Load the extension into this database connection */
+ const char *zFile, /* Name of the shared library containing extension */
+ const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
+ char **pzErrMsg /* Put error message here if not 0 */
+){
+#ifdef SQLITE_LIBRARY_TYPE
+ SQLITE_LIBRARY_TYPE handle;
+ int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
+ char *zErrmsg = 0;
+ SQLITE_LIBRARY_TYPE *aHandle;
+
+ /* Ticket #1863. To avoid a creating security problems for older
+ ** applications that relink against newer versions of SQLite, the
+ ** ability to run load_extension is turned off by default. One
+ ** must call sqlite3_enable_load_extension() to turn on extension
+ ** loading. Otherwise you get the following error.
+ */
+ if( (db->flags & SQLITE_LoadExtension)==0 ){
+ if( pzErrMsg ){
+ *pzErrMsg = sqlite3_mprintf("not authorized");
+ }
+ return SQLITE_ERROR;
+ }
+
+ if( zProc==0 ){
+ zProc = "sqlite3_extension_init";
+ }
+
+ handle = SQLITE_OPEN_LIBRARY(zFile);
+ if( handle==0 ){
+ if( pzErrMsg ){
+ *pzErrMsg = sqlite3_mprintf("unable to open shared library [%s]", zFile);
+ }
+ return SQLITE_ERROR;
+ }
+ xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
+ SQLITE_FIND_SYMBOL(handle, zProc);
+ if( xInit==0 ){
+ if( pzErrMsg ){
+ *pzErrMsg = sqlite3_mprintf("no entry point [%s] in shared library [%s]",
+ zProc, zFile);
+ }
+ SQLITE_CLOSE_LIBRARY(handle);
+ return SQLITE_ERROR;
+ }else if( xInit(db, &zErrmsg, &sqlite3_api) ){
+ if( pzErrMsg ){
+ *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
+ }
+ sqlite3_free(zErrmsg);
+ SQLITE_CLOSE_LIBRARY(handle);
+ return SQLITE_ERROR;
+ }
+
+ /* Append the new shared library handle to the db->aExtension array. */
+ db->nExtension++;
+ aHandle = sqliteMalloc(sizeof(handle)*db->nExtension);
+ if( aHandle==0 ){
+ return SQLITE_NOMEM;
+ }
+ if( db->nExtension>0 ){
+ memcpy(aHandle, db->aExtension, sizeof(handle)*(db->nExtension-1));
+ }
+ sqliteFree(db->aExtension);
+ db->aExtension = aHandle;
+
+ ((SQLITE_LIBRARY_TYPE*)db->aExtension)[db->nExtension-1] = handle;
+ return SQLITE_OK;
+#else
+ if( pzErrMsg ){
+ *pzErrMsg = sqlite3_mprintf("extension loading is disabled");
+ }
+ return SQLITE_ERROR;
+#endif
+}
+
+/*
+** Call this routine when the database connection is closing in order
+** to clean up loaded extensions
+*/
+void sqlite3CloseExtensions(sqlite3 *db){
+#ifdef SQLITE_LIBRARY_TYPE
+ int i;
+ for(i=0; i<db->nExtension; i++){
+ SQLITE_CLOSE_LIBRARY(((SQLITE_LIBRARY_TYPE*)db->aExtension)[i]);
+ }
+ sqliteFree(db->aExtension);
+#endif
+}
+
+/*
+** Enable or disable extension loading. Extension loading is disabled by
+** default so as not to open security holes in older applications.
+*/
+int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
+ if( onoff ){
+ db->flags |= SQLITE_LoadExtension;
+ }else{
+ db->flags &= ~SQLITE_LoadExtension;
+ }
+ return SQLITE_OK;
+}
+
+#endif /* SQLITE_OMIT_LOAD_EXTENSION */
diff --git a/ext/pdo_sqlite/sqlite/src/main.c b/ext/pdo_sqlite/sqlite/src/main.c
index c42df158e4..eccf83be69 100644
--- a/ext/pdo_sqlite/sqlite/src/main.c
+++ b/ext/pdo_sqlite/sqlite/src/main.c
@@ -26,32 +26,9 @@
*/
const int sqlite3one = 1;
-#ifndef SQLITE_OMIT_GLOBALRECOVER
-/*
-** Linked list of all open database handles. This is used by the
-** sqlite3_global_recover() function. Entries are added to the list
-** by openDatabase() and removed by sqlite3_close().
-*/
-static sqlite3 *pDbList = 0;
-#endif
-
-#ifndef SQLITE_OMIT_UTF16
-/*
-** Return the transient sqlite3_value object used for encoding conversions
-** during SQL compilation.
-*/
-sqlite3_value *sqlite3GetTransientValue(sqlite3 *db){
- if( !db->pValue ){
- db->pValue = sqlite3ValueNew();
- }
- return db->pValue;
-}
-#endif
-
/*
** The version of the library
*/
-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; }
@@ -132,10 +109,14 @@ int sqlite3_close(sqlite3 *db){
}
#ifdef SQLITE_SSE
- sqlite3_finalize(db->pFetch);
+ {
+ extern void sqlite3SseCleanup(sqlite3*);
+ sqlite3SseCleanup(db);
+ }
#endif
/* If there are any outstanding VMs, return SQLITE_BUSY. */
+ sqlite3ResetInternalSchema(db, 0);
if( db->pVdbe ){
sqlite3Error(db, SQLITE_BUSY,
"Unable to close due to unfinalised statements");
@@ -153,11 +134,16 @@ int sqlite3_close(sqlite3 *db){
return SQLITE_ERROR;
}
+ sqlite3VtabRollback(db);
+
for(j=0; j<db->nDb; j++){
struct Db *pDb = &db->aDb[j];
if( pDb->pBt ){
sqlite3BtreeClose(pDb->pBt);
pDb->pBt = 0;
+ if( j!=1 ){
+ pDb->pSchema = 0;
+ }
}
}
sqlite3ResetInternalSchema(db, 0);
@@ -176,36 +162,32 @@ int sqlite3_close(sqlite3 *db){
sqliteFree(pColl);
}
sqlite3HashClear(&db->aCollSeq);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){
+ Module *pMod = (Module *)sqliteHashData(i);
+ sqliteFree(pMod);
+ }
+ sqlite3HashClear(&db->aModule);
+#endif
sqlite3HashClear(&db->aFunc);
sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */
- if( db->pValue ){
- sqlite3ValueFree(db->pValue);
- }
if( db->pErr ){
sqlite3ValueFree(db->pErr);
}
-
-#ifndef SQLITE_OMIT_GLOBALRECOVER
- {
- sqlite3 *pPrev;
- sqlite3OsEnterMutex();
- pPrev = pDbList;
- while( pPrev && pPrev->pNext!=db ){
- pPrev = pPrev->pNext;
- }
- if( pPrev ){
- pPrev->pNext = db->pNext;
- }else{
- assert( pDbList==db );
- pDbList = db->pNext;
- }
- sqlite3OsLeaveMutex();
- }
-#endif
+ sqlite3CloseExtensions(db);
db->magic = SQLITE_MAGIC_ERROR;
+
+ /* The temp-database schema is allocated differently from the other schema
+ ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()).
+ ** So it needs to be freed here. Todo: Why not roll the temp schema into
+ ** the same sqliteMalloc() as the one that allocates the database
+ ** structure?
+ */
+ sqliteFree(db->aDb[1].pSchema);
sqliteFree(db);
+ sqlite3ReleaseThreadData();
return SQLITE_OK;
}
@@ -214,13 +196,25 @@ int sqlite3_close(sqlite3 *db){
*/
void sqlite3RollbackAll(sqlite3 *db){
int i;
+ int inTrans = 0;
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt ){
+ if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){
+ inTrans = 1;
+ }
sqlite3BtreeRollback(db->aDb[i].pBt);
db->aDb[i].inTrans = 0;
}
}
- sqlite3ResetInternalSchema(db, 0);
+ sqlite3VtabRollback(db);
+ if( db->flags&SQLITE_InternChanges ){
+ sqlite3ResetInternalSchema(db, 0);
+ }
+
+ /* If one has been configured, invoke the rollback-hook callback */
+ if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
+ db->xRollbackCallback(db->pRollbackArg);
+ }
}
/*
@@ -271,7 +265,7 @@ static int sqliteDefaultBusyCallback(
void *ptr, /* Database connection */
int count /* Number of times table has been busy */
){
-#if SQLITE_MIN_SLEEP_MS==1
+#if OS_WIN || (defined(HAVE_USLEEP) && HAVE_USLEEP)
static const u8 delays[] =
{ 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 };
static const u8 totals[] =
@@ -373,6 +367,9 @@ void sqlite3_progress_handler(
** specified number of milliseconds before returning 0.
*/
int sqlite3_busy_timeout(sqlite3 *db, int ms){
+ if( sqlite3SafetyCheck(db) ){
+ return SQLITE_MISUSE;
+ }
if( ms>0 ){
db->busyTimeout = ms;
sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db);
@@ -386,25 +383,43 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){
** Cause any pending operation to stop at its earliest opportunity.
*/
void sqlite3_interrupt(sqlite3 *db){
- if( !sqlite3SafetyCheck(db) ){
- db->flags |= SQLITE_Interrupt;
+ if( db && (db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_BUSY) ){
+ db->u1.isInterrupted = 1;
}
}
/*
-** Windows systems should call this routine to free memory that
-** is returned in the in the errmsg parameter of sqlite3_open() when
-** SQLite is a DLL. For some reason, it does not work to call free()
-** directly.
+** Memory allocation routines that use SQLites internal memory
+** memory allocator. Depending on how SQLite is compiled, the
+** internal memory allocator might be just an alias for the
+** system default malloc/realloc/free. Or the built-in allocator
+** might do extra stuff like put sentinals around buffers to
+** check for overruns or look for memory leaks.
**
-** Note that we need to call free() not sqliteFree() here.
+** Use sqlite3_free() to free memory returned by sqlite3_mprintf().
*/
-void sqlite3_free(char *p){ free(p); }
+void sqlite3_free(void *p){ if( p ) sqlite3OsFree(p); }
+void *sqlite3_malloc(int nByte){ return nByte>0 ? sqlite3OsMalloc(nByte) : 0; }
+void *sqlite3_realloc(void *pOld, int nByte){
+ if( pOld ){
+ if( nByte>0 ){
+ return sqlite3OsRealloc(pOld, nByte);
+ }else{
+ sqlite3OsFree(pOld);
+ return 0;
+ }
+ }else{
+ return sqlite3_malloc(nByte);
+ }
+}
/*
-** Create new user functions.
+** This function is exactly the same as sqlite3_create_function(), except
+** that it is designed to be called by internal code. The difference is
+** that if a malloc() fails in sqlite3_create_function(), an error code
+** is returned and the mallocFailed flag cleared.
*/
-int sqlite3_create_function(
+int sqlite3CreateFunc(
sqlite3 *db,
const char *zFunctionName,
int nArg,
@@ -426,6 +441,7 @@ int sqlite3_create_function(
(!xFunc && (!xFinal && xStep)) ||
(nArg<-1 || nArg>127) ||
(255<(nName = strlen(zFunctionName))) ){
+ sqlite3Error(db, SQLITE_ERROR, "bad parameters");
return SQLITE_ERROR;
}
@@ -441,10 +457,10 @@ int sqlite3_create_function(
enc = SQLITE_UTF16NATIVE;
}else if( enc==SQLITE_ANY ){
int rc;
- rc = sqlite3_create_function(db, zFunctionName, nArg, SQLITE_UTF8,
+ rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8,
pUserData, xFunc, xStep, xFinal);
if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3_create_function(db, zFunctionName, nArg, SQLITE_UTF16LE,
+ rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE,
pUserData, xFunc, xStep, xFinal);
if( rc!=SQLITE_OK ) return rc;
enc = SQLITE_UTF16BE;
@@ -463,6 +479,7 @@ int sqlite3_create_function(
if( db->activeVdbeCnt ){
sqlite3Error(db, SQLITE_BUSY,
"Unable to delete/modify user-function due to active statements");
+ assert( !sqlite3MallocFailed() );
return SQLITE_BUSY;
}else{
sqlite3ExpirePreparedStatements(db);
@@ -470,42 +487,57 @@ int sqlite3_create_function(
}
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 1);
- if( p==0 ) return SQLITE_NOMEM;
- p->flags = 0;
- p->xFunc = xFunc;
- p->xStep = xStep;
- p->xFinalize = xFinal;
- p->pUserData = pUserData;
+ if( p ){
+ p->flags = 0;
+ p->xFunc = xFunc;
+ p->xStep = xStep;
+ p->xFinalize = xFinal;
+ p->pUserData = pUserData;
+ p->nArg = nArg;
+ }
return SQLITE_OK;
}
+
+/*
+** Create new user functions.
+*/
+int sqlite3_create_function(
+ sqlite3 *db,
+ const char *zFunctionName,
+ int nArg,
+ int enc,
+ void *p,
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
+ void (*xStep)(sqlite3_context*,int,sqlite3_value **),
+ void (*xFinal)(sqlite3_context*)
+){
+ int rc;
+ assert( !sqlite3MallocFailed() );
+ rc = sqlite3CreateFunc(db, zFunctionName, nArg, enc, p, xFunc, xStep, xFinal);
+
+ return sqlite3ApiExit(db, rc);
+}
+
#ifndef SQLITE_OMIT_UTF16
int sqlite3_create_function16(
sqlite3 *db,
const void *zFunctionName,
int nArg,
int eTextRep,
- void *pUserData,
+ void *p,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
){
int rc;
- char const *zFunc8;
- sqlite3_value *pTmp;
+ char *zFunc8;
+ assert( !sqlite3MallocFailed() );
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
- pTmp = sqlite3GetTransientValue(db);
- sqlite3ValueSetStr(pTmp, -1, zFunctionName, SQLITE_UTF16NATIVE,SQLITE_STATIC);
- zFunc8 = sqlite3ValueText(pTmp, SQLITE_UTF8);
+ zFunc8 = sqlite3utf16to8(zFunctionName, -1);
+ rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal);
+ sqliteFree(zFunc8);
- if( !zFunc8 ){
- return SQLITE_NOMEM;
- }
- rc = sqlite3_create_function(db, zFunc8, nArg, eTextRep,
- pUserData, xFunc, xStep, xFinal);
- return rc;
+ return sqlite3ApiExit(db, rc);
}
#endif
@@ -547,7 +579,7 @@ void *sqlite3_profile(
/*** EXPERIMENTAL ***
**
** Register a function to be invoked when a transaction comments.
-** If either function returns non-zero, then the commit becomes a
+** If the invoked function returns non-zero, then the commit becomes a
** rollback.
*/
void *sqlite3_commit_hook(
@@ -561,6 +593,35 @@ void *sqlite3_commit_hook(
return pOld;
}
+/*
+** Register a callback to be invoked each time a row is updated,
+** inserted or deleted using this database connection.
+*/
+void *sqlite3_update_hook(
+ sqlite3 *db, /* Attach the hook to this database */
+ void (*xCallback)(void*,int,char const *,char const *,sqlite_int64),
+ void *pArg /* Argument to the function */
+){
+ void *pRet = db->pUpdateArg;
+ db->xUpdateCallback = xCallback;
+ db->pUpdateArg = pArg;
+ return pRet;
+}
+
+/*
+** Register a callback to be invoked each time a transaction is rolled
+** back by this database connection.
+*/
+void *sqlite3_rollback_hook(
+ sqlite3 *db, /* Attach the hook to this database */
+ void (*xCallback)(void*), /* Callback function */
+ void *pArg /* Argument to the function */
+){
+ void *pRet = db->pRollbackArg;
+ db->xRollbackCallback = xCallback;
+ db->pRollbackArg = pArg;
+ return pRet;
+}
/*
** This routine is called to create a connection to a database BTree
@@ -621,7 +682,7 @@ int sqlite3BtreeFactory(
#endif /* SQLITE_OMIT_MEMORYDB */
}
- rc = sqlite3BtreeOpen(zFilename, ppBtree, btree_flags);
+ rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btree_flags);
if( rc==SQLITE_OK ){
sqlite3BtreeSetBusyHandler(*ppBtree, (void*)&db->busyHandler);
sqlite3BtreeSetCacheSize(*ppBtree, nCache);
@@ -635,13 +696,13 @@ int sqlite3BtreeFactory(
*/
const char *sqlite3_errmsg(sqlite3 *db){
const char *z;
- if( sqlite3_malloc_failed ){
+ if( !db || sqlite3MallocFailed() ){
return sqlite3ErrStr(SQLITE_NOMEM);
}
if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
return sqlite3ErrStr(SQLITE_MISUSE);
}
- z = sqlite3_value_text(db->pErr);
+ z = (char*)sqlite3_value_text(db->pErr);
if( z==0 ){
z = sqlite3ErrStr(db->errCode);
}
@@ -674,7 +735,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){
};
const void *z;
- if( sqlite3_malloc_failed ){
+ if( sqlite3MallocFailed() ){
return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
}
if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
@@ -686,15 +747,17 @@ const void *sqlite3_errmsg16(sqlite3 *db){
SQLITE_UTF8, SQLITE_STATIC);
z = sqlite3_value_text16(db->pErr);
}
+ sqlite3ApiExit(0, 0);
return z;
}
#endif /* SQLITE_OMIT_UTF16 */
/*
-** Return the most recent error code generated by an SQLite routine.
+** Return the most recent error code generated by an SQLite routine. If NULL is
+** passed to this function, we assume a malloc() failed during sqlite3_open().
*/
int sqlite3_errcode(sqlite3 *db){
- if( sqlite3_malloc_failed ){
+ if( !db || sqlite3MallocFailed() ){
return SQLITE_NOMEM;
}
if( sqlite3SafetyCheck(db) ){
@@ -704,6 +767,63 @@ int sqlite3_errcode(sqlite3 *db){
}
/*
+** Create a new collating function for database "db". The name is zName
+** and the encoding is enc.
+*/
+static int createCollation(
+ sqlite3* db,
+ const char *zName,
+ int enc,
+ void* pCtx,
+ int(*xCompare)(void*,int,const void*,int,const void*)
+){
+ CollSeq *pColl;
+ int enc2;
+
+ if( sqlite3SafetyCheck(db) ){
+ return SQLITE_MISUSE;
+ }
+
+ /* 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.
+ */
+ enc2 = enc & ~SQLITE_UTF16_ALIGNED;
+ if( enc2==SQLITE_UTF16 ){
+ enc2 = SQLITE_UTF16NATIVE;
+ }
+
+ if( (enc2&~3)!=0 ){
+ sqlite3Error(db, SQLITE_ERROR, "unknown encoding");
+ 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)enc2, 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)enc2, zName, strlen(zName), 1);
+ if( pColl ){
+ pColl->xCmp = xCompare;
+ pColl->pUser = pCtx;
+ pColl->enc = enc2 | (enc & SQLITE_UTF16_ALIGNED);
+ }
+ sqlite3Error(db, SQLITE_OK, 0);
+ return SQLITE_OK;
+}
+
+
+/*
** This routine does the work of opening a database on behalf of
** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"
** is UTF-8 encoded.
@@ -713,9 +833,11 @@ static int openDatabase(
sqlite3 **ppDb /* OUT: Returned database handle */
){
sqlite3 *db;
- int rc, i;
+ int rc;
CollSeq *pColl;
+ assert( !sqlite3MallocFailed() );
+
/* Allocate the sqlite data structure */
db = sqliteMalloc( sizeof(sqlite3) );
if( db==0 ) goto opendb_out;
@@ -723,33 +845,34 @@ static int openDatabase(
db->magic = SQLITE_MAGIC_BUSY;
db->nDb = 2;
db->aDb = db->aDbStatic;
- db->enc = SQLITE_UTF8;
db->autoCommit = 1;
- db->flags |= SQLITE_ShortColNames;
+ db->flags |= SQLITE_ShortColNames
+#if SQLITE_DEFAULT_FILE_FORMAT<4
+ | SQLITE_LegacyFileFmt
+#endif
+ ;
sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0);
- for(i=0; i<db->nDb; i++){
- sqlite3HashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0);
- sqlite3HashInit(&db->aDb[i].idxHash, SQLITE_HASH_STRING, 0);
- sqlite3HashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0);
- sqlite3HashInit(&db->aDb[i].aFKey, SQLITE_HASH_STRING, 1);
- }
-
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ sqlite3HashInit(&db->aModule, SQLITE_HASH_STRING, 0);
+#endif
+
/* Add the default collation sequence BINARY. BINARY works for both UTF-8
** 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.
*/
- 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 );
+ if( createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc) ||
+ createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc) ||
+ createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc) ||
+ (db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0))==0
+ ){
+ assert( sqlite3MallocFailed() );
db->magic = SQLITE_MAGIC_CLOSED;
goto opendb_out;
}
/* Also add a UTF-8 case-insensitive collation sequence. */
- sqlite3_create_collation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc);
+ createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc);
/* Set flags on the built-in collating sequences */
db->pDfltColl->type = SQLITE_COLL_BINARY;
@@ -765,6 +888,9 @@ static int openDatabase(
db->magic = SQLITE_MAGIC_CLOSED;
goto opendb_out;
}
+ db->aDb[0].pSchema = sqlite3SchemaGet(db->aDb[0].pBt);
+ db->aDb[1].pSchema = sqlite3SchemaGet(0);
+
/* The default safety_level for the main database is 'full'; for the temp
** database it is 'NONE'. This matches the pager layer defaults.
@@ -776,29 +902,23 @@ static int openDatabase(
db->aDb[1].safety_level = 1;
#endif
-
/* Register all built-in functions, but do not attempt to read the
** database schema yet. This is delayed until the first time the database
** is accessed.
*/
- sqlite3RegisterBuiltinFunctions(db);
- sqlite3Error(db, SQLITE_OK, 0);
+ if( !sqlite3MallocFailed() ){
+ sqlite3RegisterBuiltinFunctions(db);
+ sqlite3Error(db, SQLITE_OK, 0);
+ }
db->magic = SQLITE_MAGIC_OPEN;
opendb_out:
- if( sqlite3_errcode(db)==SQLITE_OK && sqlite3_malloc_failed ){
- sqlite3Error(db, SQLITE_NOMEM, 0);
+ if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){
+ sqlite3_close(db);
+ db = 0;
}
*ppDb = db;
-#ifndef SQLITE_OMIT_GLOBALRECOVER
- if( db ){
- sqlite3OsEnterMutex();
- db->pNext = pDbList;
- pDbList = db;
- sqlite3OsLeaveMutex();
- }
-#endif
- return sqlite3_errcode(db);
+ return sqlite3ApiExit(0, rc);
}
/*
@@ -820,9 +940,10 @@ int sqlite3_open16(
sqlite3 **ppDb
){
char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */
- int rc = SQLITE_NOMEM;
+ int rc = SQLITE_OK;
sqlite3_value *pVal;
+ assert( zFilename );
assert( ppDb );
*ppDb = 0;
pVal = sqlite3ValueNew();
@@ -831,14 +952,16 @@ int sqlite3_open16(
if( zFilename8 ){
rc = openDatabase(zFilename8, ppDb);
if( rc==SQLITE_OK && *ppDb ){
- sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
+ rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
+ if( rc!=SQLITE_OK ){
+ sqlite3_close(*ppDb);
+ *ppDb = 0;
+ }
}
}
- if( pVal ){
- sqlite3ValueFree(pVal);
- }
+ sqlite3ValueFree(pVal);
- return rc;
+ return sqlite3ApiExit(0, rc);
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -890,53 +1013,10 @@ int sqlite3_create_collation(
void* pCtx,
int(*xCompare)(void*,int,const void*,int,const void*)
){
- CollSeq *pColl;
- int rc = SQLITE_OK;
-
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
-
- /* 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.
- */
- if( enc==SQLITE_UTF16 ){
- enc = SQLITE_UTF16NATIVE;
- }
-
- if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF16LE && enc!=SQLITE_UTF16BE ){
- sqlite3Error(db, SQLITE_ERROR,
- "Param 3 to sqlite3_create_collation() must be one of "
- "SQLITE_UTF8, SQLITE_UTF16, SQLITE_UTF16LE or SQLITE_UTF16BE"
- );
- 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;
- }else{
- pColl->xCmp = xCompare;
- pColl->pUser = pCtx;
- pColl->enc = enc;
- }
- sqlite3Error(db, rc, 0);
- return rc;
+ int rc;
+ assert( !sqlite3MallocFailed() );
+ rc = createCollation(db, zName, enc, pCtx, xCompare);
+ return sqlite3ApiExit(db, rc);
}
#ifndef SQLITE_OMIT_UTF16
@@ -950,15 +1030,15 @@ int sqlite3_create_collation16(
void* pCtx,
int(*xCompare)(void*,int,const void*,int,const void*)
){
- char const *zName8;
- sqlite3_value *pTmp;
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
+ int rc = SQLITE_OK;
+ char *zName8;
+ assert( !sqlite3MallocFailed() );
+ zName8 = sqlite3utf16to8(zName, -1);
+ if( zName8 ){
+ rc = createCollation(db, zName8, enc, pCtx, xCompare);
+ sqliteFree(zName8);
}
- pTmp = sqlite3GetTransientValue(db);
- sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF16NATIVE, SQLITE_STATIC);
- zName8 = sqlite3ValueText(pTmp, SQLITE_UTF8);
- return sqlite3_create_collation(db, zName8, enc, pCtx, xCompare);
+ return sqlite3ApiExit(db, rc);
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -1002,37 +1082,11 @@ int sqlite3_collation_needed16(
#ifndef SQLITE_OMIT_GLOBALRECOVER
/*
-** This function is called to recover from a malloc failure that occured
-** within SQLite.
-**
-** This function is *not* threadsafe. Calling this from within a threaded
-** application when threads other than the caller have used SQLite is
-** dangerous and will almost certainly result in malfunctions.
+** This function is now an anachronism. It used to be used to recover from a
+** malloc() failure, but SQLite now does this automatically.
*/
int sqlite3_global_recover(){
- int rc = SQLITE_OK;
-
- if( sqlite3_malloc_failed ){
- sqlite3 *db;
- int i;
- sqlite3_malloc_failed = 0;
- for(db=pDbList; db; db=db->pNext ){
- sqlite3ExpirePreparedStatements(db);
- for(i=0; i<db->nDb; i++){
- Btree *pBt = db->aDb[i].pBt;
- if( pBt && (rc=sqlite3BtreeReset(pBt)) ){
- goto recover_out;
- }
- }
- db->autoCommit = 1;
- }
- }
-
-recover_out:
- if( rc!=SQLITE_OK ){
- sqlite3_malloc_failed = 1;
- }
- return rc;
+ return SQLITE_OK;
}
#endif
@@ -1058,3 +1112,176 @@ int sqlite3Corrupt(void){
return SQLITE_CORRUPT;
}
#endif
+
+
+#ifndef SQLITE_OMIT_SHARED_CACHE
+/*
+** Enable or disable the shared pager and schema features for the
+** current thread.
+**
+** This routine should only be called when there are no open
+** database connections.
+*/
+int sqlite3_enable_shared_cache(int enable){
+ ThreadData *pTd = sqlite3ThreadData();
+ if( pTd ){
+ /* It is only legal to call sqlite3_enable_shared_cache() when there
+ ** are no currently open b-trees that were opened by the calling thread.
+ ** This condition is only easy to detect if the shared-cache were
+ ** previously enabled (and is being disabled).
+ */
+ if( pTd->pBtree && !enable ){
+ assert( pTd->useSharedData );
+ return SQLITE_MISUSE;
+ }
+
+ pTd->useSharedData = enable;
+ sqlite3ReleaseThreadData();
+ }
+ return sqlite3ApiExit(0, SQLITE_OK);
+}
+#endif
+
+/*
+** This is a convenience routine that makes sure that all thread-specific
+** data for this thread has been deallocated.
+*/
+void sqlite3_thread_cleanup(void){
+ ThreadData *pTd = sqlite3OsThreadSpecificData(0);
+ if( pTd ){
+ memset(pTd, 0, sizeof(*pTd));
+ sqlite3OsThreadSpecificData(-1);
+ }
+}
+
+/*
+** Return meta information about a specific column of a database table.
+** See comment in sqlite3.h (sqlite.h.in) for details.
+*/
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
+int sqlite3_table_column_metadata(
+ sqlite3 *db, /* Connection handle */
+ const char *zDbName, /* Database name or NULL */
+ const char *zTableName, /* Table name */
+ const char *zColumnName, /* Column name */
+ char const **pzDataType, /* OUTPUT: Declared data type */
+ char const **pzCollSeq, /* OUTPUT: Collation sequence name */
+ int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */
+ int *pPrimaryKey, /* OUTPUT: True if column part of PK */
+ int *pAutoinc /* OUTPUT: True if colums is auto-increment */
+){
+ int rc;
+ char *zErrMsg = 0;
+ Table *pTab = 0;
+ Column *pCol = 0;
+ int iCol;
+
+ char const *zDataType = 0;
+ char const *zCollSeq = 0;
+ int notnull = 0;
+ int primarykey = 0;
+ int autoinc = 0;
+
+ /* Ensure the database schema has been loaded */
+ if( sqlite3SafetyOn(db) ){
+ return SQLITE_MISUSE;
+ }
+ rc = sqlite3Init(db, &zErrMsg);
+ if( SQLITE_OK!=rc ){
+ goto error_out;
+ }
+
+ /* Locate the table in question */
+ pTab = sqlite3FindTable(db, zTableName, zDbName);
+ if( !pTab || pTab->pSelect ){
+ pTab = 0;
+ goto error_out;
+ }
+
+ /* Find the column for which info is requested */
+ if( sqlite3IsRowid(zColumnName) ){
+ iCol = pTab->iPKey;
+ if( iCol>=0 ){
+ pCol = &pTab->aCol[iCol];
+ }
+ }else{
+ for(iCol=0; iCol<pTab->nCol; iCol++){
+ pCol = &pTab->aCol[iCol];
+ if( 0==sqlite3StrICmp(pCol->zName, zColumnName) ){
+ break;
+ }
+ }
+ if( iCol==pTab->nCol ){
+ pTab = 0;
+ goto error_out;
+ }
+ }
+
+ /* The following block stores the meta information that will be returned
+ ** to the caller in local variables zDataType, zCollSeq, notnull, primarykey
+ ** and autoinc. At this point there are two possibilities:
+ **
+ ** 1. The specified column name was rowid", "oid" or "_rowid_"
+ ** and there is no explicitly declared IPK column.
+ **
+ ** 2. The table is not a view and the column name identified an
+ ** explicitly declared column. Copy meta information from *pCol.
+ */
+ if( pCol ){
+ zDataType = pCol->zType;
+ zCollSeq = pCol->zColl;
+ notnull = (pCol->notNull?1:0);
+ primarykey = (pCol->isPrimKey?1:0);
+ autoinc = ((pTab->iPKey==iCol && pTab->autoInc)?1:0);
+ }else{
+ zDataType = "INTEGER";
+ primarykey = 1;
+ }
+ if( !zCollSeq ){
+ zCollSeq = "BINARY";
+ }
+
+error_out:
+ if( sqlite3SafetyOff(db) ){
+ rc = SQLITE_MISUSE;
+ }
+
+ /* Whether the function call succeeded or failed, set the output parameters
+ ** to whatever their local counterparts contain. If an error did occur,
+ ** this has the effect of zeroing all output parameters.
+ */
+ if( pzDataType ) *pzDataType = zDataType;
+ if( pzCollSeq ) *pzCollSeq = zCollSeq;
+ if( pNotNull ) *pNotNull = notnull;
+ if( pPrimaryKey ) *pPrimaryKey = primarykey;
+ if( pAutoinc ) *pAutoinc = autoinc;
+
+ if( SQLITE_OK==rc && !pTab ){
+ sqlite3SetString(&zErrMsg, "no such table column: ", zTableName, ".",
+ zColumnName, 0);
+ rc = SQLITE_ERROR;
+ }
+ sqlite3Error(db, rc, (zErrMsg?"%s":0), zErrMsg);
+ sqliteFree(zErrMsg);
+ return sqlite3ApiExit(db, rc);
+}
+#endif
+
+/*
+** 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);
+}
diff --git a/ext/pdo_sqlite/sqlite/src/opcodes.h b/ext/pdo_sqlite/sqlite/src/opcodes.h
index 4db3ec1639..c113f8f1c1 100644
--- a/ext/pdo_sqlite/sqlite/src/opcodes.h
+++ b/ext/pdo_sqlite/sqlite/src/opcodes.h
@@ -1,149 +1,161 @@
/* Automatically generated. Do not edit */
/* See the mkopcodeh.awk script for details */
#define OP_MemLoad 1
-#define OP_HexBlob 134 /* same as TK_BLOB */
-#define OP_Column 2
-#define OP_SetCookie 3
-#define OP_IfMemPos 4
-#define OP_Real 133 /* same as TK_FLOAT */
-#define OP_Sequence 5
-#define OP_MoveGt 6
-#define OP_Ge 80 /* same as TK_GE */
-#define OP_RowKey 7
-#define OP_Eq 76 /* same as TK_EQ */
-#define OP_OpenWrite 8
-#define OP_NotNull 74 /* same as TK_NOTNULL */
-#define OP_If 9
-#define OP_ToInt 10
-#define OP_String8 95 /* same as TK_STRING */
+#define OP_VNext 2
+#define OP_HexBlob 127 /* same as TK_BLOB */
+#define OP_Column 3
+#define OP_SetCookie 4
+#define OP_IfMemPos 5
+#define OP_Real 126 /* same as TK_FLOAT */
+#define OP_Sequence 6
+#define OP_MoveGt 7
+#define OP_Ge 73 /* same as TK_GE */
+#define OP_RowKey 8
+#define OP_Eq 69 /* same as TK_EQ */
+#define OP_OpenWrite 9
+#define OP_NotNull 67 /* same as TK_NOTNULL */
+#define OP_If 10
+#define OP_ToInt 142 /* same as TK_TO_INT */
+#define OP_String8 88 /* same as TK_STRING */
#define OP_Pop 11
-#define OP_CollSeq 12
-#define OP_OpenRead 13
-#define OP_Expire 14
-#define OP_AutoCommit 15
-#define OP_Gt 77 /* same as TK_GT */
-#define OP_IntegrityCk 16
-#define OP_Sort 17
-#define OP_Function 18
-#define OP_And 68 /* same as TK_AND */
-#define OP_Subtract 87 /* same as TK_MINUS */
-#define OP_Noop 19
-#define OP_Return 20
-#define OP_Remainder 90 /* same as TK_REM */
-#define OP_NewRowid 21
-#define OP_Multiply 88 /* same as TK_STAR */
-#define OP_Variable 22
-#define OP_String 23
-#define OP_ParseSchema 24
-#define OP_Close 25
-#define OP_CreateIndex 26
-#define OP_IsUnique 27
-#define OP_IdxIsNull 28
-#define OP_NotFound 29
-#define OP_Int64 30
-#define OP_MustBeInt 31
-#define OP_Halt 32
-#define OP_Rowid 33
-#define OP_IdxLT 34
-#define OP_AddImm 35
-#define OP_Statement 36
-#define OP_RowData 37
-#define OP_MemMax 38
-#define OP_Push 39
-#define OP_Or 67 /* same as TK_OR */
-#define OP_NotExists 40
-#define OP_MemIncr 41
-#define OP_Gosub 42
-#define OP_Divide 89 /* same as TK_SLASH */
-#define OP_Integer 43
-#define OP_ToNumeric 44
-#define OP_MemInt 45
-#define OP_Prev 46
-#define OP_Concat 91 /* same as TK_CONCAT */
-#define OP_BitAnd 82 /* same as TK_BITAND */
-#define OP_CreateTable 47
-#define OP_Last 48
-#define OP_IsNull 73 /* same as TK_ISNULL */
-#define OP_IdxRowid 49
-#define OP_MakeIdxRec 50
-#define OP_ShiftRight 85 /* same as TK_RSHIFT */
-#define OP_ResetCount 51
-#define OP_FifoWrite 52
-#define OP_Callback 53
-#define OP_ContextPush 54
-#define OP_DropTrigger 55
-#define OP_DropIndex 56
-#define OP_IdxGE 57
-#define OP_IdxDelete 58
-#define OP_Vacuum 59
-#define OP_MoveLe 60
-#define OP_IfNot 61
-#define OP_DropTable 62
-#define OP_MakeRecord 63
-#define OP_ToBlob 64
-#define OP_Delete 65
-#define OP_AggFinal 66
-#define OP_ShiftLeft 84 /* same as TK_LSHIFT */
-#define OP_Dup 70
-#define OP_Goto 71
-#define OP_FifoRead 72
-#define OP_Clear 81
-#define OP_IdxGT 93
-#define OP_MoveLt 96
-#define OP_Le 78 /* same as TK_LE */
-#define OP_VerifyCookie 97
-#define OP_AggStep 98
-#define OP_Pull 99
-#define OP_ToText 100
-#define OP_Not 69 /* same as TK_NOT */
-#define OP_SetNumColumns 101
-#define OP_AbsValue 102
-#define OP_Transaction 103
-#define OP_Negative 92 /* same as TK_UMINUS */
-#define OP_Ne 75 /* same as TK_NE */
-#define OP_ContextPop 104
-#define OP_BitOr 83 /* same as TK_BITOR */
-#define OP_Next 105
-#define OP_IdxInsert 106
-#define OP_Distinct 107
-#define OP_Lt 79 /* same as TK_LT */
-#define OP_Insert 108
-#define OP_Destroy 109
-#define OP_ReadCookie 110
-#define OP_ForceInt 111
-#define OP_LoadAnalysis 112
-#define OP_OpenVirtual 113
-#define OP_Explain 114
-#define OP_OpenPseudo 115
-#define OP_Null 116
-#define OP_Blob 117
-#define OP_Add 86 /* same as TK_PLUS */
-#define OP_MemStore 118
-#define OP_Rewind 119
-#define OP_MoveGe 120
-#define OP_BitNot 94 /* same as TK_BITNOT */
-#define OP_MemMove 121
-#define OP_MemNull 122
-#define OP_Found 123
-#define OP_NullRow 124
+#define OP_VRowid 12
+#define OP_CollSeq 13
+#define OP_OpenRead 14
+#define OP_Expire 15
+#define OP_AutoCommit 17
+#define OP_Gt 70 /* same as TK_GT */
+#define OP_IntegrityCk 18
+#define OP_Sort 19
+#define OP_Function 20
+#define OP_And 62 /* same as TK_AND */
+#define OP_Subtract 80 /* same as TK_MINUS */
+#define OP_Noop 21
+#define OP_Return 22
+#define OP_Remainder 83 /* same as TK_REM */
+#define OP_NewRowid 23
+#define OP_Multiply 81 /* same as TK_STAR */
+#define OP_IfMemNeg 24
+#define OP_Variable 25
+#define OP_String 26
+#define OP_RealAffinity 27
+#define OP_ParseSchema 28
+#define OP_VOpen 29
+#define OP_Close 30
+#define OP_CreateIndex 31
+#define OP_IsUnique 32
+#define OP_IdxIsNull 33
+#define OP_NotFound 34
+#define OP_Int64 35
+#define OP_MustBeInt 36
+#define OP_Halt 37
+#define OP_Rowid 38
+#define OP_IdxLT 39
+#define OP_AddImm 40
+#define OP_Statement 41
+#define OP_RowData 42
+#define OP_MemMax 43
+#define OP_Push 44
+#define OP_Or 61 /* same as TK_OR */
+#define OP_NotExists 45
+#define OP_MemIncr 46
+#define OP_Gosub 47
+#define OP_Divide 82 /* same as TK_SLASH */
+#define OP_Integer 48
+#define OP_ToNumeric 141 /* same as TK_TO_NUMERIC*/
+#define OP_MemInt 49
+#define OP_Prev 50
+#define OP_Concat 84 /* same as TK_CONCAT */
+#define OP_BitAnd 75 /* same as TK_BITAND */
+#define OP_VColumn 51
+#define OP_CreateTable 52
+#define OP_Last 53
+#define OP_IsNull 66 /* same as TK_ISNULL */
+#define OP_IdxRowid 54
+#define OP_MakeIdxRec 55
+#define OP_ShiftRight 78 /* same as TK_RSHIFT */
+#define OP_ResetCount 56
+#define OP_FifoWrite 57
+#define OP_Callback 58
+#define OP_ContextPush 59
+#define OP_DropTrigger 60
+#define OP_DropIndex 63
+#define OP_IdxGE 64
+#define OP_IdxDelete 65
+#define OP_Vacuum 74
+#define OP_MoveLe 86
+#define OP_IfNot 89
+#define OP_DropTable 90
+#define OP_MakeRecord 91
+#define OP_ToBlob 140 /* same as TK_TO_BLOB */
+#define OP_Delete 92
+#define OP_AggFinal 93
+#define OP_ShiftLeft 77 /* same as TK_LSHIFT */
+#define OP_Dup 94
+#define OP_Goto 95
+#define OP_TableLock 96
+#define OP_FifoRead 97
+#define OP_Clear 98
+#define OP_IdxGT 99
+#define OP_MoveLt 100
+#define OP_Le 71 /* same as TK_LE */
+#define OP_VerifyCookie 101
+#define OP_AggStep 102
+#define OP_Pull 103
+#define OP_ToText 139 /* same as TK_TO_TEXT */
+#define OP_Not 16 /* same as TK_NOT */
+#define OP_ToReal 143 /* same as TK_TO_REAL */
+#define OP_SetNumColumns 104
+#define OP_AbsValue 105
+#define OP_Transaction 106
+#define OP_VFilter 107
+#define OP_Negative 85 /* same as TK_UMINUS */
+#define OP_Ne 68 /* same as TK_NE */
+#define OP_VDestroy 108
+#define OP_ContextPop 109
+#define OP_BitOr 76 /* same as TK_BITOR */
+#define OP_Next 110
+#define OP_IdxInsert 111
+#define OP_Distinct 112
+#define OP_Lt 72 /* same as TK_LT */
+#define OP_Insert 113
+#define OP_Destroy 114
+#define OP_ReadCookie 115
+#define OP_ForceInt 116
+#define OP_LoadAnalysis 117
+#define OP_Explain 118
+#define OP_IfMemZero 119
+#define OP_OpenPseudo 120
+#define OP_OpenEphemeral 121
+#define OP_Null 122
+#define OP_Blob 123
+#define OP_Add 79 /* same as TK_PLUS */
+#define OP_MemStore 124
+#define OP_Rewind 125
+#define OP_MoveGe 128
+#define OP_VBegin 129
+#define OP_VUpdate 130
+#define OP_BitNot 87 /* same as TK_BITNOT */
+#define OP_VCreate 131
+#define OP_MemMove 132
+#define OP_MemNull 133
+#define OP_Found 134
+#define OP_NullRow 135
/* The following opcode values are never used */
-#define OP_NotUsed_125 125
-#define OP_NotUsed_126 126
-#define OP_NotUsed_127 127
-#define OP_NotUsed_128 128
-#define OP_NotUsed_129 129
-#define OP_NotUsed_130 130
-#define OP_NotUsed_131 131
-#define OP_NotUsed_132 132
+#define OP_NotUsed_136 136
+#define OP_NotUsed_137 137
+#define OP_NotUsed_138 138
-#define NOPUSH_MASK_0 65368
-#define NOPUSH_MASK_1 47898
-#define NOPUSH_MASK_2 22493
-#define NOPUSH_MASK_3 32761
-#define NOPUSH_MASK_4 65215
-#define NOPUSH_MASK_5 30719
-#define NOPUSH_MASK_6 40895
-#define NOPUSH_MASK_7 6603
-#define NOPUSH_MASK_8 0
-#define NOPUSH_MASK_9 0
+/* Opcodes that are guaranteed to never push a value onto the stack
+** contain a 1 their corresponding position of the following mask
+** set. See the opcodeNoPush() function in vdbeaux.c */
+#define NOPUSH_MASK_0 0xeeb4
+#define NOPUSH_MASK_1 0x796b
+#define NOPUSH_MASK_2 0xfbb7
+#define NOPUSH_MASK_3 0xff24
+#define NOPUSH_MASK_4 0xffff
+#define NOPUSH_MASK_5 0xb6ef
+#define NOPUSH_MASK_6 0xfdfd
+#define NOPUSH_MASK_7 0x33b3
+#define NOPUSH_MASK_8 0xf8cf
+#define NOPUSH_MASK_9 0x0000
diff --git a/ext/pdo_sqlite/sqlite/src/os.c b/ext/pdo_sqlite/sqlite/src/os.c
new file mode 100644
index 0000000000..ec482fe0e7
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/os.c
@@ -0,0 +1,92 @@
+/*
+** 2005 November 29
+**
+** 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 OS interface code that is common to all
+** architectures.
+*/
+#define _SQLITE_OS_C_ 1
+#include "sqliteInt.h"
+#include "os.h"
+
+/*
+** The following routines are convenience wrappers around methods
+** of the OsFile object. This is mostly just syntactic sugar. All
+** of this would be completely automatic if SQLite were coded using
+** C++ instead of plain old C.
+*/
+int sqlite3OsClose(OsFile **pId){
+ OsFile *id;
+ if( pId!=0 && (id = *pId)!=0 ){
+ return id->pMethod->xClose(pId);
+ }else{
+ return SQLITE_OK;
+ }
+}
+int sqlite3OsOpenDirectory(OsFile *id, const char *zName){
+ return id->pMethod->xOpenDirectory(id, zName);
+}
+int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
+ return id->pMethod->xRead(id, pBuf, amt);
+}
+int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
+ return id->pMethod->xWrite(id, pBuf, amt);
+}
+int sqlite3OsSeek(OsFile *id, i64 offset){
+ return id->pMethod->xSeek(id, offset);
+}
+int sqlite3OsTruncate(OsFile *id, i64 size){
+ return id->pMethod->xTruncate(id, size);
+}
+int sqlite3OsSync(OsFile *id, int fullsync){
+ return id->pMethod->xSync(id, fullsync);
+}
+void sqlite3OsSetFullSync(OsFile *id, int value){
+ id->pMethod->xSetFullSync(id, value);
+}
+#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
+/* This method is currently only used while interactively debugging the
+** pager. More specificly, it can only be used when sqlite3DebugPrintf() is
+** included in the build. */
+int sqlite3OsFileHandle(OsFile *id){
+ return id->pMethod->xFileHandle(id);
+}
+#endif
+int sqlite3OsFileSize(OsFile *id, i64 *pSize){
+ return id->pMethod->xFileSize(id, pSize);
+}
+int sqlite3OsLock(OsFile *id, int lockType){
+ return id->pMethod->xLock(id, lockType);
+}
+int sqlite3OsUnlock(OsFile *id, int lockType){
+ return id->pMethod->xUnlock(id, lockType);
+}
+int sqlite3OsLockState(OsFile *id){
+ return id->pMethod->xLockState(id);
+}
+int sqlite3OsCheckReservedLock(OsFile *id){
+ return id->pMethod->xCheckReservedLock(id);
+}
+
+#ifdef SQLITE_ENABLE_REDEF_IO
+/*
+** A function to return a pointer to the virtual function table.
+** This routine really does not accomplish very much since the
+** virtual function table is a global variable and anybody who
+** can call this function can just as easily access the variable
+** for themselves. Nevertheless, we include this routine for
+** backwards compatibility with an earlier redefinable I/O
+** interface design.
+*/
+struct sqlite3OsVtbl *sqlite3_os_switch(void){
+ return &sqlite3Os;
+}
+#endif
diff --git a/ext/pdo_sqlite/sqlite/src/os.h b/ext/pdo_sqlite/sqlite/src/os.h
index a161d134a6..4433f5d022 100644
--- a/ext/pdo_sqlite/sqlite/src/os.h
+++ b/ext/pdo_sqlite/sqlite/src/os.h
@@ -18,23 +18,28 @@
#define _SQLITE_OS_H_
/*
-** Figure out if we are dealing with Unix, Windows or MacOS.
-**
-** N.B. MacOS means Mac Classic (or Carbon). Treat Darwin (OS X) as Unix.
-** The MacOS build is designed to use CodeWarrior (tested with v8)
+** Figure out if we are dealing with Unix, Windows, or some other
+** operating system.
*/
-#if !defined(OS_UNIX) && !defined(OS_TEST) && !defined(OS_OTHER)
+#if !defined(OS_UNIX) && !defined(OS_OTHER)
# define OS_OTHER 0
# ifndef OS_WIN
# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
# define OS_WIN 1
# define OS_UNIX 0
+# define OS_OS2 0
+# elif defined(_EMX_) || defined(_OS2) || defined(OS2) || defined(_OS2_) || defined(__OS2__)
+# define OS_WIN 0
+# define OS_UNIX 0
+# define OS_OS2 1
# else
# define OS_WIN 0
# define OS_UNIX 1
+# define OS_OS2 0
# endif
# else
# define OS_UNIX 0
+# define OS_OS2 0
# endif
#else
# ifndef OS_WIN
@@ -42,25 +47,23 @@
# endif
#endif
+
/*
-** Invoke the appropriate operating-system specific header file.
+** Define the maximum size of a temporary filename
*/
-#if OS_TEST
-# include "os_test.h"
-#endif
-#if OS_UNIX
-# include "os_unix.h"
-#endif
#if OS_WIN
-# include "os_win.h"
-#endif
-
-/* os_other.c and os_other.h are not delivered with SQLite. These files
-** are place-holders that can be filled in by third-party developers to
-** implement backends to their on proprietary operating systems.
-*/
-#if OS_OTHER
-# include "os_other.h"
+# include <windows.h>
+# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
+#elif OS_OS2
+# define INCL_DOSDATETIME
+# define INCL_DOSFILEMGR
+# define INCL_DOSERRORS
+# define INCL_DOSMISC
+# define INCL_DOSPROCESS
+# include <os2.h>
+# define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP)
+#else
+# define SQLITE_TEMPNAME_SIZE 200
#endif
/* If the SET_FULLSYNC macro is not defined above, then make it
@@ -84,6 +87,129 @@
#endif
/*
+** Define the interfaces for Unix, Windows, and OS/2.
+*/
+#if OS_UNIX
+#define sqlite3OsOpenReadWrite sqlite3UnixOpenReadWrite
+#define sqlite3OsOpenExclusive sqlite3UnixOpenExclusive
+#define sqlite3OsOpenReadOnly sqlite3UnixOpenReadOnly
+#define sqlite3OsDelete sqlite3UnixDelete
+#define sqlite3OsFileExists sqlite3UnixFileExists
+#define sqlite3OsFullPathname sqlite3UnixFullPathname
+#define sqlite3OsIsDirWritable sqlite3UnixIsDirWritable
+#define sqlite3OsSyncDirectory sqlite3UnixSyncDirectory
+#define sqlite3OsTempFileName sqlite3UnixTempFileName
+#define sqlite3OsRandomSeed sqlite3UnixRandomSeed
+#define sqlite3OsSleep sqlite3UnixSleep
+#define sqlite3OsCurrentTime sqlite3UnixCurrentTime
+#define sqlite3OsEnterMutex sqlite3UnixEnterMutex
+#define sqlite3OsLeaveMutex sqlite3UnixLeaveMutex
+#define sqlite3OsInMutex sqlite3UnixInMutex
+#define sqlite3OsThreadSpecificData sqlite3UnixThreadSpecificData
+#define sqlite3OsMalloc sqlite3GenericMalloc
+#define sqlite3OsRealloc sqlite3GenericRealloc
+#define sqlite3OsFree sqlite3GenericFree
+#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
+#endif
+#if OS_WIN
+#define sqlite3OsOpenReadWrite sqlite3WinOpenReadWrite
+#define sqlite3OsOpenExclusive sqlite3WinOpenExclusive
+#define sqlite3OsOpenReadOnly sqlite3WinOpenReadOnly
+#define sqlite3OsDelete sqlite3WinDelete
+#define sqlite3OsFileExists sqlite3WinFileExists
+#define sqlite3OsFullPathname sqlite3WinFullPathname
+#define sqlite3OsIsDirWritable sqlite3WinIsDirWritable
+#define sqlite3OsSyncDirectory sqlite3WinSyncDirectory
+#define sqlite3OsTempFileName sqlite3WinTempFileName
+#define sqlite3OsRandomSeed sqlite3WinRandomSeed
+#define sqlite3OsSleep sqlite3WinSleep
+#define sqlite3OsCurrentTime sqlite3WinCurrentTime
+#define sqlite3OsEnterMutex sqlite3WinEnterMutex
+#define sqlite3OsLeaveMutex sqlite3WinLeaveMutex
+#define sqlite3OsInMutex sqlite3WinInMutex
+#define sqlite3OsThreadSpecificData sqlite3WinThreadSpecificData
+#define sqlite3OsMalloc sqlite3GenericMalloc
+#define sqlite3OsRealloc sqlite3GenericRealloc
+#define sqlite3OsFree sqlite3GenericFree
+#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
+#endif
+#if OS_OS2
+#define sqlite3OsOpenReadWrite sqlite3Os2OpenReadWrite
+#define sqlite3OsOpenExclusive sqlite3Os2OpenExclusive
+#define sqlite3OsOpenReadOnly sqlite3Os2OpenReadOnly
+#define sqlite3OsDelete sqlite3Os2Delete
+#define sqlite3OsFileExists sqlite3Os2FileExists
+#define sqlite3OsFullPathname sqlite3Os2FullPathname
+#define sqlite3OsIsDirWritable sqlite3Os2IsDirWritable
+#define sqlite3OsSyncDirectory sqlite3Os2SyncDirectory
+#define sqlite3OsTempFileName sqlite3Os2TempFileName
+#define sqlite3OsRandomSeed sqlite3Os2RandomSeed
+#define sqlite3OsSleep sqlite3Os2Sleep
+#define sqlite3OsCurrentTime sqlite3Os2CurrentTime
+#define sqlite3OsEnterMutex sqlite3Os2EnterMutex
+#define sqlite3OsLeaveMutex sqlite3Os2LeaveMutex
+#define sqlite3OsInMutex sqlite3Os2InMutex
+#define sqlite3OsThreadSpecificData sqlite3Os2ThreadSpecificData
+#define sqlite3OsMalloc sqlite3GenericMalloc
+#define sqlite3OsRealloc sqlite3GenericRealloc
+#define sqlite3OsFree sqlite3GenericFree
+#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
+#endif
+
+
+
+
+/*
+** If using an alternative OS interface, then we must have an "os_other.h"
+** header file available for that interface. Presumably the "os_other.h"
+** header file contains #defines similar to those above.
+*/
+#if OS_OTHER
+# include "os_other.h"
+#endif
+
+
+
+/*
+** Forward declarations
+*/
+typedef struct OsFile OsFile;
+typedef struct IoMethod IoMethod;
+
+/*
+** An instance of the following structure contains pointers to all
+** methods on an OsFile object.
+*/
+struct IoMethod {
+ int (*xClose)(OsFile**);
+ int (*xOpenDirectory)(OsFile*, const char*);
+ int (*xRead)(OsFile*, void*, int amt);
+ int (*xWrite)(OsFile*, const void*, int amt);
+ int (*xSeek)(OsFile*, i64 offset);
+ int (*xTruncate)(OsFile*, i64 size);
+ int (*xSync)(OsFile*, int);
+ void (*xSetFullSync)(OsFile *id, int setting);
+ int (*xFileHandle)(OsFile *id);
+ int (*xFileSize)(OsFile*, i64 *pSize);
+ int (*xLock)(OsFile*, int);
+ int (*xUnlock)(OsFile*, int);
+ int (*xLockState)(OsFile *id);
+ int (*xCheckReservedLock)(OsFile *id);
+};
+
+/*
+** The OsFile object describes an open disk file in an OS-dependent way.
+** The version of OsFile defined here is a generic version. Each OS
+** implementation defines its own subclass of this structure that contains
+** additional information needed to handle file I/O. But the pMethod
+** entry (pointing to the virtual function table) always occurs first
+** so that we can always find the appropriate methods.
+*/
+struct OsFile {
+ IoMethod const *pMethod;
+};
+
+/*
** The following values may be passed as the second argument to
** sqlite3OsLock(). The various locks exhibit the following semantics:
**
@@ -137,8 +263,10 @@
** a random byte is selected for a shared lock. The pool of bytes for
** shared locks begins at SHARED_FIRST.
**
-** These #defines are available in os.h so that Unix can use the same
-** byte ranges for locking. This leaves open the possiblity of having
+** These #defines are available in sqlite_aux.h so that adaptors for
+** connecting SQLite to other operating systems can use the same byte
+** ranges for locking. In particular, the same locking strategy and
+** byte ranges are used for Unix. This leaves open the possiblity of having
** clients on win95, winNT, and unix all talking to the same shared file
** and all locking correctly. To do so would require that samba (or whatever
** tool is being used for file sharing) implements locks correctly between
@@ -172,36 +300,181 @@ extern unsigned int sqlite3_pending_byte;
#define SHARED_FIRST (PENDING_BYTE+2)
#define SHARED_SIZE 510
-
-int sqlite3OsDelete(const char*);
-int sqlite3OsFileExists(const char*);
-int sqlite3OsOpenReadWrite(const char*, OsFile*, int*);
-int sqlite3OsOpenExclusive(const char*, OsFile*, int);
-int sqlite3OsOpenReadOnly(const char*, OsFile*);
-int sqlite3OsOpenDirectory(const char*, OsFile*);
-int sqlite3OsSyncDirectory(const char*);
-int sqlite3OsTempFileName(char*);
-int sqlite3OsIsDirWritable(char*);
-int sqlite3OsClose(OsFile*);
+/*
+** Prototypes for operating system interface routines.
+*/
+int sqlite3OsClose(OsFile**);
+int sqlite3OsOpenDirectory(OsFile*, const char*);
int sqlite3OsRead(OsFile*, void*, int amt);
int sqlite3OsWrite(OsFile*, const void*, int amt);
int sqlite3OsSeek(OsFile*, i64 offset);
-int sqlite3OsSync(OsFile*, int);
int sqlite3OsTruncate(OsFile*, i64 size);
+int sqlite3OsSync(OsFile*, int);
+void sqlite3OsSetFullSync(OsFile *id, int setting);
+int sqlite3OsFileHandle(OsFile *id);
int sqlite3OsFileSize(OsFile*, i64 *pSize);
-char *sqlite3OsFullPathname(const char*);
int sqlite3OsLock(OsFile*, int);
int sqlite3OsUnlock(OsFile*, int);
+int sqlite3OsLockState(OsFile *id);
int sqlite3OsCheckReservedLock(OsFile *id);
-
-
-/* The interface for file I/O is above. Other miscellaneous functions
-** are below */
-
+int sqlite3OsOpenReadWrite(const char*, OsFile**, int*);
+int sqlite3OsOpenExclusive(const char*, OsFile**, int);
+int sqlite3OsOpenReadOnly(const char*, OsFile**);
+int sqlite3OsDelete(const char*);
+int sqlite3OsFileExists(const char*);
+char *sqlite3OsFullPathname(const char*);
+int sqlite3OsIsDirWritable(char*);
+int sqlite3OsSyncDirectory(const char*);
+int sqlite3OsTempFileName(char*);
int sqlite3OsRandomSeed(char*);
int sqlite3OsSleep(int ms);
int sqlite3OsCurrentTime(double*);
void sqlite3OsEnterMutex(void);
void sqlite3OsLeaveMutex(void);
+int sqlite3OsInMutex(int);
+ThreadData *sqlite3OsThreadSpecificData(int);
+void *sqlite3OsMalloc(int);
+void *sqlite3OsRealloc(void *, int);
+void sqlite3OsFree(void *);
+int sqlite3OsAllocationSize(void *);
+
+/*
+** If the SQLITE_ENABLE_REDEF_IO macro is defined, then the OS-layer
+** interface routines are not called directly but are invoked using
+** pointers to functions. This allows the implementation of various
+** OS-layer interface routines to be modified at run-time. There are
+** obscure but legitimate reasons for wanting to do this. But for
+** most users, a direct call to the underlying interface is preferable
+** so the the redefinable I/O interface is turned off by default.
+*/
+#ifdef SQLITE_ENABLE_REDEF_IO
+
+/*
+** When redefinable I/O is enabled, a single global instance of the
+** following structure holds pointers to the routines that SQLite
+** uses to talk with the underlying operating system. Modify this
+** structure (before using any SQLite API!) to accomodate perculiar
+** operating system interfaces or behaviors.
+*/
+struct sqlite3OsVtbl {
+ int (*xOpenReadWrite)(const char*, OsFile**, int*);
+ int (*xOpenExclusive)(const char*, OsFile**, int);
+ int (*xOpenReadOnly)(const char*, OsFile**);
+
+ int (*xDelete)(const char*);
+ int (*xFileExists)(const char*);
+ char *(*xFullPathname)(const char*);
+ int (*xIsDirWritable)(char*);
+ int (*xSyncDirectory)(const char*);
+ int (*xTempFileName)(char*);
+
+ int (*xRandomSeed)(char*);
+ int (*xSleep)(int ms);
+ int (*xCurrentTime)(double*);
+
+ void (*xEnterMutex)(void);
+ void (*xLeaveMutex)(void);
+ int (*xInMutex)(int);
+ ThreadData *(*xThreadSpecificData)(int);
+
+ void *(*xMalloc)(int);
+ void *(*xRealloc)(void *, int);
+ void (*xFree)(void *);
+ int (*xAllocationSize)(void *);
+};
+
+/* Macro used to comment out routines that do not exists when there is
+** no disk I/O
+*/
+#ifdef SQLITE_OMIT_DISKIO
+# define IF_DISKIO(X) 0
+#else
+# define IF_DISKIO(X) X
+#endif
+
+#ifdef _SQLITE_OS_C_
+ /*
+ ** The os.c file implements the global virtual function table.
+ */
+ struct sqlite3OsVtbl sqlite3Os = {
+ IF_DISKIO( sqlite3OsOpenReadWrite ),
+ IF_DISKIO( sqlite3OsOpenExclusive ),
+ IF_DISKIO( sqlite3OsOpenReadOnly ),
+ IF_DISKIO( sqlite3OsDelete ),
+ IF_DISKIO( sqlite3OsFileExists ),
+ IF_DISKIO( sqlite3OsFullPathname ),
+ IF_DISKIO( sqlite3OsIsDirWritable ),
+ IF_DISKIO( sqlite3OsSyncDirectory ),
+ IF_DISKIO( sqlite3OsTempFileName ),
+ sqlite3OsRandomSeed,
+ sqlite3OsSleep,
+ sqlite3OsCurrentTime,
+ sqlite3OsEnterMutex,
+ sqlite3OsLeaveMutex,
+ sqlite3OsInMutex,
+ sqlite3OsThreadSpecificData,
+ sqlite3OsMalloc,
+ sqlite3OsRealloc,
+ sqlite3OsFree,
+ sqlite3OsAllocationSize
+ };
+#else
+ /*
+ ** Files other than os.c just reference the global virtual function table.
+ */
+ extern struct sqlite3OsVtbl sqlite3Os;
+#endif /* _SQLITE_OS_C_ */
+
+
+/* This additional API routine is available with redefinable I/O */
+struct sqlite3OsVtbl *sqlite3_os_switch(void);
+
+
+/*
+** Redefine the OS interface to go through the virtual function table
+** rather than calling routines directly.
+*/
+#undef sqlite3OsOpenReadWrite
+#undef sqlite3OsOpenExclusive
+#undef sqlite3OsOpenReadOnly
+#undef sqlite3OsDelete
+#undef sqlite3OsFileExists
+#undef sqlite3OsFullPathname
+#undef sqlite3OsIsDirWritable
+#undef sqlite3OsSyncDirectory
+#undef sqlite3OsTempFileName
+#undef sqlite3OsRandomSeed
+#undef sqlite3OsSleep
+#undef sqlite3OsCurrentTime
+#undef sqlite3OsEnterMutex
+#undef sqlite3OsLeaveMutex
+#undef sqlite3OsInMutex
+#undef sqlite3OsThreadSpecificData
+#undef sqlite3OsMalloc
+#undef sqlite3OsRealloc
+#undef sqlite3OsFree
+#undef sqlite3OsAllocationSize
+#define sqlite3OsOpenReadWrite sqlite3Os.xOpenReadWrite
+#define sqlite3OsOpenExclusive sqlite3Os.xOpenExclusive
+#define sqlite3OsOpenReadOnly sqlite3Os.xOpenReadOnly
+#define sqlite3OsDelete sqlite3Os.xDelete
+#define sqlite3OsFileExists sqlite3Os.xFileExists
+#define sqlite3OsFullPathname sqlite3Os.xFullPathname
+#define sqlite3OsIsDirWritable sqlite3Os.xIsDirWritable
+#define sqlite3OsSyncDirectory sqlite3Os.xSyncDirectory
+#define sqlite3OsTempFileName sqlite3Os.xTempFileName
+#define sqlite3OsRandomSeed sqlite3Os.xRandomSeed
+#define sqlite3OsSleep sqlite3Os.xSleep
+#define sqlite3OsCurrentTime sqlite3Os.xCurrentTime
+#define sqlite3OsEnterMutex sqlite3Os.xEnterMutex
+#define sqlite3OsLeaveMutex sqlite3Os.xLeaveMutex
+#define sqlite3OsInMutex sqlite3Os.xInMutex
+#define sqlite3OsThreadSpecificData sqlite3Os.xThreadSpecificData
+#define sqlite3OsMalloc sqlite3Os.xMalloc
+#define sqlite3OsRealloc sqlite3Os.xRealloc
+#define sqlite3OsFree sqlite3Os.xFree
+#define sqlite3OsAllocationSize sqlite3Os.xAllocationSize
+
+#endif /* SQLITE_ENABLE_REDEF_IO */
#endif /* _SQLITE_OS_H_ */
diff --git a/ext/pdo_sqlite/sqlite/src/os_common.h b/ext/pdo_sqlite/sqlite/src/os_common.h
index b19ff05906..d65c352ddf 100644
--- a/ext/pdo_sqlite/sqlite/src/os_common.h
+++ b/ext/pdo_sqlite/sqlite/src/os_common.h
@@ -88,6 +88,7 @@ static unsigned int elapse;
** is used for testing the I/O recovery logic.
*/
#ifdef SQLITE_TEST
+int sqlite3_io_error_hit = 0;
int sqlite3_io_error_pending = 0;
int sqlite3_diskfull_pending = 0;
int sqlite3_diskfull = 0;
@@ -95,7 +96,7 @@ int sqlite3_diskfull = 0;
if( sqlite3_io_error_pending ) \
if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; }
static void local_ioerr(){
- sqlite3_io_error_pending = 0; /* Really just a place to set a breakpoint */
+ sqlite3_io_error_hit = 1; /* Really just a place to set a breakpoint */
}
#define SimulateDiskfullError \
if( sqlite3_diskfull_pending ){ \
@@ -121,3 +122,67 @@ int sqlite3_open_file_count = 0;
#else
#define OpenCounter(X)
#endif
+
+/*
+** sqlite3GenericMalloc
+** sqlite3GenericRealloc
+** sqlite3GenericOsFree
+** sqlite3GenericAllocationSize
+**
+** Implementation of the os level dynamic memory allocation interface in terms
+** of the standard malloc(), realloc() and free() found in many operating
+** systems. No rocket science here.
+**
+** There are two versions of these four functions here. The version
+** implemented here is only used if memory-management or memory-debugging is
+** enabled. This version allocates an extra 8-bytes at the beginning of each
+** block and stores the size of the allocation there.
+**
+** If neither memory-management or debugging is enabled, the second
+** set of implementations is used instead.
+*/
+#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || defined (SQLITE_MEMDEBUG)
+void *sqlite3GenericMalloc(int n){
+ char *p = (char *)malloc(n+8);
+ assert(n>0);
+ assert(sizeof(int)<=8);
+ if( p ){
+ *(int *)p = n;
+ p += 8;
+ }
+ return (void *)p;
+}
+void *sqlite3GenericRealloc(void *p, int n){
+ char *p2 = ((char *)p - 8);
+ assert(n>0);
+ p2 = (char*)realloc(p2, n+8);
+ if( p2 ){
+ *(int *)p2 = n;
+ p2 += 8;
+ }
+ return (void *)p2;
+}
+void sqlite3GenericFree(void *p){
+ assert(p);
+ free((void *)((char *)p - 8));
+}
+int sqlite3GenericAllocationSize(void *p){
+ return p ? *(int *)((char *)p - 8) : 0;
+}
+#else
+void *sqlite3GenericMalloc(int n){
+ char *p = (char *)malloc(n);
+ return (void *)p;
+}
+void *sqlite3GenericRealloc(void *p, int n){
+ assert(n>0);
+ p = realloc(p, n);
+ return p;
+}
+void sqlite3GenericFree(void *p){
+ assert(p);
+ free(p);
+}
+/* Never actually used, but needed for the linker */
+int sqlite3GenericAllocationSize(void *p){ return 0; }
+#endif
diff --git a/ext/pdo_sqlite/sqlite/src/os_mac.c b/ext/pdo_sqlite/sqlite/src/os_mac.c
deleted file mode 100644
index f84c168d4a..0000000000
--- a/ext/pdo_sqlite/sqlite/src/os_mac.c
+++ /dev/null
@@ -1,738 +0,0 @@
-/*
-** 2004 May 22
-**
-** 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 code that is specific classic mac. Mac OS X
-** uses the os_unix.c file, not this one.
-*/
-#include "sqliteInt.h"
-#include "os.h"
-#if OS_MAC /* This file used on classic mac only */
-
-#include <extras.h>
-#include <path2fss.h>
-#include <TextUtils.h>
-#include <FinderRegistry.h>
-#include <Folders.h>
-#include <Timer.h>
-#include <OSUtils.h>
-
-/*
-** Macros used to determine whether or not to use threads.
-*/
-#if defined(THREADSAFE) && THREADSAFE
-# include <Multiprocessing.h>
-# define SQLITE_MACOS_MULTITASKING 1
-#endif
-
-/*
-** Include code that is common to all os_*.c files
-*/
-#include "os_common.h"
-
-/*
-** Delete the named file
-*/
-int sqlite3OsDelete(const char *zFilename){
- unlink(zFilename);
- return SQLITE_OK;
-}
-
-/*
-** Return TRUE if the named file exists.
-*/
-int sqlite3OsFileExists(const char *zFilename){
- return access(zFilename, 0)==0;
-}
-
-/*
-** Attempt to open a file for both reading and writing. If that
-** fails, try opening it read-only. If the file does not exist,
-** try to create it.
-**
-** On success, a handle for the open file is written to *id
-** and *pReadonly is set to 0 if the file was opened for reading and
-** writing or 1 if the file was opened read-only. The function returns
-** SQLITE_OK.
-**
-** On failure, the function returns SQLITE_CANTOPEN and leaves
-** *id and *pReadonly unchanged.
-*/
-int sqlite3OsOpenReadWrite(
- const char *zFilename,
- OsFile *id,
- int *pReadonly
-){
- FSSpec fsSpec;
-# ifdef _LARGE_FILE
- HFSUniStr255 dfName;
- FSRef fsRef;
- if( __path2fss(zFilename, &fsSpec) != noErr ){
- if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
- return SQLITE_CANTOPEN;
- }
- if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
- return SQLITE_CANTOPEN;
- FSGetDataForkName(&dfName);
- if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
- fsRdWrShPerm, &(id->refNum)) != noErr ){
- if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
- fsRdWrPerm, &(id->refNum)) != noErr ){
- if (FSOpenFork(&fsRef, dfName.length, dfName.unicode,
- fsRdPerm, &(id->refNum)) != noErr )
- return SQLITE_CANTOPEN;
- else
- *pReadonly = 1;
- } else
- *pReadonly = 0;
- } else
- *pReadonly = 0;
-# else
- __path2fss(zFilename, &fsSpec);
- if( !sqlite3OsFileExists(zFilename) ){
- if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
- return SQLITE_CANTOPEN;
- }
- if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNum)) != noErr ){
- if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr ){
- if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr )
- return SQLITE_CANTOPEN;
- else
- *pReadonly = 1;
- } else
- *pReadonly = 0;
- } else
- *pReadonly = 0;
-# endif
- if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){
- id->refNumRF = -1;
- }
- id->locked = 0;
- id->delOnClose = 0;
- OpenCounter(+1);
- return SQLITE_OK;
-}
-
-
-/*
-** Attempt to open a new file for exclusive access by this process.
-** The file will be opened for both reading and writing. To avoid
-** a potential security problem, we do not allow the file to have
-** previously existed. Nor do we allow the file to be a symbolic
-** link.
-**
-** If delFlag is true, then make arrangements to automatically delete
-** the file when it is closed.
-**
-** On success, write the file handle into *id and return SQLITE_OK.
-**
-** On failure, return SQLITE_CANTOPEN.
-*/
-int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
- FSSpec fsSpec;
-# ifdef _LARGE_FILE
- HFSUniStr255 dfName;
- FSRef fsRef;
- __path2fss(zFilename, &fsSpec);
- if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
- return SQLITE_CANTOPEN;
- if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
- return SQLITE_CANTOPEN;
- FSGetDataForkName(&dfName);
- if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
- fsRdWrPerm, &(id->refNum)) != noErr )
- return SQLITE_CANTOPEN;
-# else
- __path2fss(zFilename, &fsSpec);
- if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
- return SQLITE_CANTOPEN;
- if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr )
- return SQLITE_CANTOPEN;
-# endif
- id->refNumRF = -1;
- id->locked = 0;
- id->delOnClose = delFlag;
- if (delFlag)
- id->pathToDel = sqlite3OsFullPathname(zFilename);
- OpenCounter(+1);
- return SQLITE_OK;
-}
-
-/*
-** Attempt to open a new file for read-only access.
-**
-** On success, write the file handle into *id and return SQLITE_OK.
-**
-** On failure, return SQLITE_CANTOPEN.
-*/
-int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
- FSSpec fsSpec;
-# ifdef _LARGE_FILE
- HFSUniStr255 dfName;
- FSRef fsRef;
- if( __path2fss(zFilename, &fsSpec) != noErr )
- return SQLITE_CANTOPEN;
- if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
- return SQLITE_CANTOPEN;
- FSGetDataForkName(&dfName);
- if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
- fsRdPerm, &(id->refNum)) != noErr )
- return SQLITE_CANTOPEN;
-# else
- __path2fss(zFilename, &fsSpec);
- if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr )
- return SQLITE_CANTOPEN;
-# endif
- if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){
- id->refNumRF = -1;
- }
- id->locked = 0;
- id->delOnClose = 0;
- OpenCounter(+1);
- return SQLITE_OK;
-}
-
-/*
-** Attempt to open a file descriptor for the directory that contains a
-** file. This file descriptor can be used to fsync() the directory
-** in order to make sure the creation of a new file is actually written
-** to disk.
-**
-** This routine is only meaningful for Unix. It is a no-op under
-** windows since windows does not support hard links.
-**
-** On success, a handle for a previously open file is at *id is
-** updated with the new directory file descriptor and SQLITE_OK is
-** returned.
-**
-** On failure, the function returns SQLITE_CANTOPEN and leaves
-** *id unchanged.
-*/
-int sqlite3OsOpenDirectory(
- const char *zDirname,
- OsFile *id
-){
- return SQLITE_OK;
-}
-
-/*
-** Create a temporary file name in zBuf. zBuf must be big enough to
-** hold at least SQLITE_TEMPNAME_SIZE characters.
-*/
-int sqlite3OsTempFileName(char *zBuf){
- static char zChars[] =
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "0123456789";
- int i, j;
- char zTempPath[SQLITE_TEMPNAME_SIZE];
- char zdirName[32];
- CInfoPBRec infoRec;
- Str31 dirName;
- memset(&infoRec, 0, sizeof(infoRec));
- memset(zTempPath, 0, SQLITE_TEMPNAME_SIZE);
- if( FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder,
- &(infoRec.dirInfo.ioVRefNum), &(infoRec.dirInfo.ioDrParID)) == noErr ){
- infoRec.dirInfo.ioNamePtr = dirName;
- do{
- infoRec.dirInfo.ioFDirIndex = -1;
- infoRec.dirInfo.ioDrDirID = infoRec.dirInfo.ioDrParID;
- if( PBGetCatInfoSync(&infoRec) == noErr ){
- CopyPascalStringToC(dirName, zdirName);
- i = strlen(zdirName);
- memmove(&(zTempPath[i+1]), zTempPath, strlen(zTempPath));
- strcpy(zTempPath, zdirName);
- zTempPath[i] = ':';
- }else{
- *zTempPath = 0;
- break;
- }
- } while( infoRec.dirInfo.ioDrDirID != fsRtDirID );
- }
- if( *zTempPath == 0 )
- getcwd(zTempPath, SQLITE_TEMPNAME_SIZE-24);
- for(;;){
- sprintf(zBuf, "%s"TEMP_FILE_PREFIX, zTempPath);
- j = strlen(zBuf);
- sqlite3Randomness(15, &zBuf[j]);
- for(i=0; i<15; i++, j++){
- zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
- }
- zBuf[j] = 0;
- if( !sqlite3OsFileExists(zBuf) ) break;
- }
- return SQLITE_OK;
-}
-
-/*
-** Close a file.
-*/
-int sqlite3OsClose(OsFile *id){
- if( id->refNumRF!=-1 )
- FSClose(id->refNumRF);
-# ifdef _LARGE_FILE
- FSCloseFork(id->refNum);
-# else
- FSClose(id->refNum);
-# endif
- if( id->delOnClose ){
- unlink(id->pathToDel);
- sqliteFree(id->pathToDel);
- }
- OpenCounter(-1);
- return SQLITE_OK;
-}
-
-/*
-** Read data from a file into a buffer. Return SQLITE_OK if all
-** bytes were read successfully and SQLITE_IOERR if anything goes
-** wrong.
-*/
-int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
- int got;
- SimulateIOError(SQLITE_IOERR);
- TRACE2("READ %d\n", last_page);
-# ifdef _LARGE_FILE
- FSReadFork(id->refNum, fsAtMark, 0, (ByteCount)amt, pBuf, (ByteCount*)&got);
-# else
- got = amt;
- FSRead(id->refNum, &got, pBuf);
-# endif
- if( got==amt ){
- return SQLITE_OK;
- }else{
- return SQLITE_IOERR;
- }
-}
-
-/*
-** Write data from a buffer into a file. Return SQLITE_OK on success
-** or some other error code on failure.
-*/
-int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
- OSErr oserr;
- int wrote = 0;
- SimulateIOError(SQLITE_IOERR);
- TRACE2("WRITE %d\n", last_page);
- while( amt>0 ){
-# ifdef _LARGE_FILE
- oserr = FSWriteFork(id->refNum, fsAtMark, 0,
- (ByteCount)amt, pBuf, (ByteCount*)&wrote);
-# else
- wrote = amt;
- oserr = FSWrite(id->refNum, &wrote, pBuf);
-# endif
- if( wrote == 0 || oserr != noErr)
- break;
- amt -= wrote;
- pBuf = &((char*)pBuf)[wrote];
- }
- if( oserr != noErr || amt>wrote ){
- return SQLITE_FULL;
- }
- return SQLITE_OK;
-}
-
-/*
-** Move the read/write pointer in a file.
-*/
-int sqlite3OsSeek(OsFile *id, off_t offset){
- off_t curSize;
- SEEK(offset/1024 + 1);
- if( sqlite3OsFileSize(id, &curSize) != SQLITE_OK ){
- return SQLITE_IOERR;
- }
- if( offset >= curSize ){
- if( sqlite3OsTruncate(id, offset+1) != SQLITE_OK ){
- return SQLITE_IOERR;
- }
- }
-# ifdef _LARGE_FILE
- if( FSSetForkPosition(id->refNum, fsFromStart, offset) != noErr ){
-# else
- if( SetFPos(id->refNum, fsFromStart, offset) != noErr ){
-# endif
- return SQLITE_IOERR;
- }else{
- return SQLITE_OK;
- }
-}
-
-/*
-** Make sure all writes to a particular file are committed to disk.
-**
-** Under Unix, also make sure that the directory entry for the file
-** has been created by fsync-ing the directory that contains the file.
-** If we do not do this and we encounter a power failure, the directory
-** entry for the journal might not exist after we reboot. The next
-** SQLite to access the file will not know that the journal exists (because
-** the directory entry for the journal was never created) and the transaction
-** will not roll back - possibly leading to database corruption.
-*/
-int sqlite3OsSync(OsFile *id){
-# ifdef _LARGE_FILE
- if( FSFlushFork(id->refNum) != noErr ){
-# else
- ParamBlockRec params;
- memset(&params, 0, sizeof(ParamBlockRec));
- params.ioParam.ioRefNum = id->refNum;
- if( PBFlushFileSync(&params) != noErr ){
-# endif
- return SQLITE_IOERR;
- }else{
- return SQLITE_OK;
- }
-}
-
-/*
-** Sync the directory zDirname. This is a no-op on operating systems other
-** than UNIX.
-*/
-int sqlite3OsSyncDirectory(const char *zDirname){
- SimulateIOError(SQLITE_IOERR);
- return SQLITE_OK;
-}
-
-/*
-** Truncate an open file to a specified size
-*/
-int sqlite3OsTruncate(OsFile *id, off_t nByte){
- SimulateIOError(SQLITE_IOERR);
-# ifdef _LARGE_FILE
- if( FSSetForkSize(id->refNum, fsFromStart, nByte) != noErr){
-# else
- if( SetEOF(id->refNum, nByte) != noErr ){
-# endif
- return SQLITE_IOERR;
- }else{
- return SQLITE_OK;
- }
-}
-
-/*
-** Determine the current size of a file in bytes
-*/
-int sqlite3OsFileSize(OsFile *id, off_t *pSize){
-# ifdef _LARGE_FILE
- if( FSGetForkSize(id->refNum, pSize) != noErr){
-# else
- if( GetEOF(id->refNum, pSize) != noErr ){
-# endif
- return SQLITE_IOERR;
- }else{
- return SQLITE_OK;
- }
-}
-
-/*
-** Windows file locking notes: [similar issues apply to MacOS]
-**
-** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
-** those functions are not available. So we use only LockFile() and
-** UnlockFile().
-**
-** LockFile() prevents not just writing but also reading by other processes.
-** (This is a design error on the part of Windows, but there is nothing
-** we can do about that.) So the region used for locking is at the
-** end of the file where it is unlikely to ever interfere with an
-** actual read attempt.
-**
-** A database read lock is obtained by locking a single randomly-chosen
-** byte out of a specific range of bytes. The lock byte is obtained at
-** random so two separate readers can probably access the file at the
-** same time, unless they are unlucky and choose the same lock byte.
-** A database write lock is obtained by locking all bytes in the range.
-** There can only be one writer.
-**
-** A lock is obtained on the first byte of the lock range before acquiring
-** either a read lock or a write lock. This prevents two processes from
-** attempting to get a lock at a same time. The semantics of
-** sqlite3OsReadLock() require that if there is already a write lock, that
-** lock is converted into a read lock atomically. The lock on the first
-** byte allows us to drop the old write lock and get the read lock without
-** another process jumping into the middle and messing us up. The same
-** argument applies to sqlite3OsWriteLock().
-**
-** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
-** which means we can use reader/writer locks. When reader writer locks
-** are used, the lock is placed on the same range of bytes that is used
-** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
-** will support two or more Win95 readers or two or more WinNT readers.
-** But a single Win95 reader will lock out all WinNT readers and a single
-** WinNT reader will lock out all other Win95 readers.
-**
-** Note: On MacOS we use the resource fork for locking.
-**
-** The following #defines specify the range of bytes used for locking.
-** N_LOCKBYTE is the number of bytes available for doing the locking.
-** The first byte used to hold the lock while the lock is changing does
-** not count toward this number. FIRST_LOCKBYTE is the address of
-** the first byte in the range of bytes used for locking.
-*/
-#define N_LOCKBYTE 10239
-#define FIRST_LOCKBYTE (0x000fffff - N_LOCKBYTE)
-
-/*
-** Change the status of the lock on the file "id" to be a readlock.
-** If the file was write locked, then this reduces the lock to a read.
-** If the file was read locked, then this acquires a new read lock.
-**
-** Return SQLITE_OK on success and SQLITE_BUSY on failure. If this
-** library was compiled with large file support (LFS) but LFS is not
-** available on the host, then an SQLITE_NOLFS is returned.
-*/
-int sqlite3OsReadLock(OsFile *id){
- int rc;
- if( id->locked>0 || id->refNumRF == -1 ){
- rc = SQLITE_OK;
- }else{
- int lk;
- OSErr res;
- int cnt = 5;
- ParamBlockRec params;
- sqlite3Randomness(sizeof(lk), &lk);
- lk = (lk & 0x7fffffff)%N_LOCKBYTE + 1;
- memset(&params, 0, sizeof(params));
- params.ioParam.ioRefNum = id->refNumRF;
- params.ioParam.ioPosMode = fsFromStart;
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
- params.ioParam.ioReqCount = 1;
- while( cnt-->0 && (res = PBLockRangeSync(&params))!=noErr ){
- UInt32 finalTicks;
- Delay(1, &finalTicks); /* 1/60 sec */
- }
- if( res == noErr ){
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
- params.ioParam.ioReqCount = N_LOCKBYTE;
- PBUnlockRangeSync(&params);
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE+lk;
- params.ioParam.ioReqCount = 1;
- res = PBLockRangeSync(&params);
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
- params.ioParam.ioReqCount = 1;
- PBUnlockRangeSync(&params);
- }
- if( res == noErr ){
- id->locked = lk;
- rc = SQLITE_OK;
- }else{
- rc = SQLITE_BUSY;
- }
- }
- return rc;
-}
-
-/*
-** Change the lock status to be an exclusive or write lock. Return
-** SQLITE_OK on success and SQLITE_BUSY on a failure. If this
-** library was compiled with large file support (LFS) but LFS is not
-** available on the host, then an SQLITE_NOLFS is returned.
-*/
-int sqlite3OsWriteLock(OsFile *id){
- int rc;
- if( id->locked<0 || id->refNumRF == -1 ){
- rc = SQLITE_OK;
- }else{
- OSErr res;
- int cnt = 5;
- ParamBlockRec params;
- memset(&params, 0, sizeof(params));
- params.ioParam.ioRefNum = id->refNumRF;
- params.ioParam.ioPosMode = fsFromStart;
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
- params.ioParam.ioReqCount = 1;
- while( cnt-->0 && (res = PBLockRangeSync(&params))!=noErr ){
- UInt32 finalTicks;
- Delay(1, &finalTicks); /* 1/60 sec */
- }
- if( res == noErr ){
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE + id->locked;
- params.ioParam.ioReqCount = 1;
- if( id->locked==0
- || PBUnlockRangeSync(&params)==noErr ){
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
- params.ioParam.ioReqCount = N_LOCKBYTE;
- res = PBLockRangeSync(&params);
- }else{
- res = afpRangeNotLocked;
- }
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
- params.ioParam.ioReqCount = 1;
- PBUnlockRangeSync(&params);
- }
- if( res == noErr ){
- id->locked = -1;
- rc = SQLITE_OK;
- }else{
- rc = SQLITE_BUSY;
- }
- }
- return rc;
-}
-
-/*
-** Unlock the given file descriptor. If the file descriptor was
-** not previously locked, then this routine is a no-op. If this
-** library was compiled with large file support (LFS) but LFS is not
-** available on the host, then an SQLITE_NOLFS is returned.
-*/
-int sqlite3OsUnlock(OsFile *id){
- int rc;
- ParamBlockRec params;
- memset(&params, 0, sizeof(params));
- params.ioParam.ioRefNum = id->refNumRF;
- params.ioParam.ioPosMode = fsFromStart;
- if( id->locked==0 || id->refNumRF == -1 ){
- rc = SQLITE_OK;
- }else if( id->locked<0 ){
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
- params.ioParam.ioReqCount = N_LOCKBYTE;
- PBUnlockRangeSync(&params);
- rc = SQLITE_OK;
- id->locked = 0;
- }else{
- params.ioParam.ioPosOffset = FIRST_LOCKBYTE+id->locked;
- params.ioParam.ioReqCount = 1;
- PBUnlockRangeSync(&params);
- rc = SQLITE_OK;
- id->locked = 0;
- }
- return rc;
-}
-
-/*
-** Get information to seed the random number generator. The seed
-** is written into the buffer zBuf[256]. The calling function must
-** supply a sufficiently large buffer.
-*/
-int sqlite3OsRandomSeed(char *zBuf){
- /* We have to initialize zBuf to prevent valgrind from reporting
- ** errors. The reports issued by valgrind are incorrect - we would
- ** prefer that the randomness be increased by making use of the
- ** uninitialized space in zBuf - but valgrind errors tend to worry
- ** some users. Rather than argue, it seems easier just to initialize
- ** the whole array and silence valgrind, even if that means less randomness
- ** in the random seed.
- **
- ** When testing, initializing zBuf[] to zero is all we do. That means
- ** that we always use the same random number sequence.* This makes the
- ** tests repeatable.
- */
- memset(zBuf, 0, 256);
-#if !defined(SQLITE_TEST)
- {
- int pid;
- Microseconds((UnsignedWide*)zBuf);
- pid = getpid();
- memcpy(&zBuf[sizeof(UnsignedWide)], &pid, sizeof(pid));
- }
-#endif
- return SQLITE_OK;
-}
-
-/*
-** Sleep for a little while. Return the amount of time slept.
-*/
-int sqlite3OsSleep(int ms){
- UInt32 finalTicks;
- UInt32 ticks = (((UInt32)ms+16)*3)/50; /* 1/60 sec per tick */
- Delay(ticks, &finalTicks);
- return (int)((ticks*50)/3);
-}
-
-/*
-** Static variables used for thread synchronization
-*/
-static int inMutex = 0;
-#ifdef SQLITE_MACOS_MULTITASKING
- static MPCriticalRegionID criticalRegion;
-#endif
-
-/*
-** The following pair of routine implement mutual exclusion for
-** multi-threaded processes. Only a single thread is allowed to
-** executed code that is surrounded by EnterMutex() and LeaveMutex().
-**
-** SQLite uses only a single Mutex. There is not much critical
-** code and what little there is executes quickly and without blocking.
-*/
-void sqlite3OsEnterMutex(){
-#ifdef SQLITE_MACOS_MULTITASKING
- static volatile int notInit = 1;
- if( notInit ){
- if( notInit == 2 ) /* as close as you can get to thread safe init */
- MPYield();
- else{
- notInit = 2;
- MPCreateCriticalRegion(&criticalRegion);
- notInit = 0;
- }
- }
- MPEnterCriticalRegion(criticalRegion, kDurationForever);
-#endif
- assert( !inMutex );
- inMutex = 1;
-}
-void sqlite3OsLeaveMutex(){
- assert( inMutex );
- inMutex = 0;
-#ifdef SQLITE_MACOS_MULTITASKING
- MPExitCriticalRegion(criticalRegion);
-#endif
-}
-
-/*
-** Turn a relative pathname into a full pathname. Return a pointer
-** to the full pathname stored in space obtained from sqliteMalloc().
-** The calling function is responsible for freeing this space once it
-** is no longer needed.
-*/
-char *sqlite3OsFullPathname(const char *zRelative){
- char *zFull = 0;
- if( zRelative[0]==':' ){
- char zBuf[_MAX_PATH+1];
- sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), &(zRelative[1]),
- (char*)0);
- }else{
- if( strchr(zRelative, ':') ){
- sqlite3SetString(&zFull, zRelative, (char*)0);
- }else{
- char zBuf[_MAX_PATH+1];
- sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), zRelative, (char*)0);
- }
- }
- return zFull;
-}
-
-/*
-** The following variable, if set to a non-zero value, becomes the result
-** returned from sqlite3OsCurrentTime(). This is used for testing.
-*/
-#ifdef SQLITE_TEST
-int sqlite3_current_time = 0;
-#endif
-
-/*
-** Find the current time (in Universal Coordinated Time). Write the
-** current time and date as a Julian Day number into *prNow and
-** return 0. Return 1 if the time and date cannot be found.
-*/
-int sqlite3OsCurrentTime(double *prNow){
- *prNow = 0.0; /**** FIX ME *****/
-#ifdef SQLITE_TEST
- if( sqlite3_current_time ){
- *prNow = sqlite3_current_time/86400.0 + 2440587.5;
- }
-#endif
- return 0;
-}
-
-#endif /* OS_MAC */
diff --git a/ext/pdo_sqlite/sqlite/src/os_mac.h b/ext/pdo_sqlite/sqlite/src/os_mac.h
deleted file mode 100644
index 5b60f81837..0000000000
--- a/ext/pdo_sqlite/sqlite/src/os_mac.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-** 2004 May 22
-**
-** 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 header file defines OS-specific features of classic Mac.
-** OS X uses the os_unix.h file, not this one.
-*/
-#ifndef _SQLITE_OS_MAC_H_
-#define _SQLITE_OS_MAC_H_
-
-
-#include <unistd.h>
-#include <Files.h>
-#define SQLITE_TEMPNAME_SIZE _MAX_PATH
-#define SQLITE_MIN_SLEEP_MS 17
-
-/*
-** The OsFile structure is a operating-system independing representation
-** of an open file handle. It is defined differently for each architecture.
-**
-** This is the definition for class Mac.
-*/
-typedef struct OsFile OsFile;
-struct OsFile {
- SInt16 refNum; /* Data fork/file reference number */
- SInt16 refNumRF; /* Resource fork reference number (for locking) */
- int locked; /* 0: unlocked, <0: write lock, >0: read lock */
- int delOnClose; /* True if file is to be deleted on close */
- char *pathToDel; /* Name of file to delete on close */
-};
-
-
-#endif /* _SQLITE_OS_MAC_H_ */
diff --git a/ext/pdo_sqlite/sqlite/src/os_unix.c b/ext/pdo_sqlite/sqlite/src/os_unix.c
index f4e09b5364..5b58cb7aac 100644
--- a/ext/pdo_sqlite/sqlite/src/os_unix.c
+++ b/ext/pdo_sqlite/sqlite/src/os_unix.c
@@ -16,15 +16,101 @@
#include "os.h"
#if OS_UNIX /* This file is used on unix only */
+/*
+** These #defines should enable >2GB file support on Posix if the
+** underlying operating system supports it. If the OS lacks
+** large file support, these should be no-ops.
+**
+** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
+** on the compiler command line. This is necessary if you are compiling
+** on a recent machine (ex: RedHat 7.2) but you want your code to work
+** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2
+** without this option, LFS is enable. But LFS does not exist in the kernel
+** in RedHat 6.0, so the code won't work. Hence, for maximum binary
+** portability you should omit LFS.
+*/
+#ifndef SQLITE_DISABLE_LFS
+# define _LARGE_FILE 1
+# ifndef _FILE_OFFSET_BITS
+# define _FILE_OFFSET_BITS 64
+# endif
+# define _LARGEFILE_SOURCE 1
+#endif
+/*
+** standard include files.
+*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <errno.h>
-#include <unistd.h>
+
+/*
+** If we are to be thread-safe, include the pthreads header and define
+** the SQLITE_UNIX_THREADS macro.
+*/
+#if defined(THREADSAFE) && THREADSAFE
+# include <pthread.h>
+# define SQLITE_UNIX_THREADS 1
+#endif
+
+/*
+** Default permissions when creating a new file
+*/
+#ifndef SQLITE_DEFAULT_FILE_PERMISSIONS
+# define SQLITE_DEFAULT_FILE_PERMISSIONS 0644
+#endif
+
+
+
+/*
+** The unixFile structure is subclass of OsFile specific for the unix
+** protability layer.
+*/
+typedef struct unixFile unixFile;
+struct unixFile {
+ IoMethod const *pMethod; /* Always the first entry */
+ struct openCnt *pOpen; /* Info about all open fd's on this inode */
+ struct lockInfo *pLock; /* Info about locks on this inode */
+ int h; /* The file descriptor */
+ unsigned char locktype; /* The type of lock held on this fd */
+ unsigned char isOpen; /* True if needs to be closed */
+ unsigned char fullSync; /* Use F_FULLSYNC if available */
+ int dirfd; /* File descriptor for the directory */
+ i64 offset; /* Seek offset */
+#ifdef SQLITE_UNIX_THREADS
+ pthread_t tid; /* The thread that "owns" this OsFile */
+#endif
+};
+
+/*
+** Provide the ability to override some OS-layer functions during
+** testing. This is used to simulate OS crashes to verify that
+** commits are atomic even in the event of an OS crash.
+*/
+#ifdef SQLITE_CRASH_TEST
+ extern int sqlite3CrashTestEnable;
+ extern int sqlite3CrashOpenReadWrite(const char*, OsFile**, int*);
+ extern int sqlite3CrashOpenExclusive(const char*, OsFile**, int);
+ extern int sqlite3CrashOpenReadOnly(const char*, OsFile**, int);
+# define CRASH_TEST_OVERRIDE(X,A,B,C) \
+ if(sqlite3CrashTestEnable){ return X(A,B,C); }
+#else
+# define CRASH_TEST_OVERRIDE(X,A,B,C) /* no-op */
+#endif
+
+
+/*
+** Include code that is common to all os_*.c files
+*/
+#include "os_common.h"
/*
** Do not include any of the File I/O interface procedures if the
-** SQLITE_OMIT_DISKIO macro is defined (indicating that there database
+** SQLITE_OMIT_DISKIO macro is defined (indicating that the database
** will be in-memory only)
*/
#ifndef SQLITE_OMIT_DISKIO
@@ -51,18 +137,13 @@
** The DJGPP compiler environment looks mostly like Unix, but it
** lacks the fcntl() system call. So redefine fcntl() to be something
** that always succeeds. This means that locking does not occur under
-** DJGPP. But its DOS - what did you expect?
+** DJGPP. But it's DOS - what did you expect?
*/
#ifdef __DJGPP__
# define fcntl(A,B,C) 0
#endif
/*
-** Include code that is common to all os_*.c files
-*/
-#include "os_common.h"
-
-/*
** The threadid macro resolves to the thread-id or to 0. Used for
** testing and debugging only.
*/
@@ -80,10 +161,18 @@
** means that sqlite3* database handles cannot be moved from one thread
** to another. This logic makes sure a user does not try to do that
** by mistake.
+**
+** Version 3.3.1 (2006-01-15): OsFiles can be moved from one thread to
+** another as long as we are running on a system that supports threads
+** overriding each others locks (which now the most common behavior)
+** or if no locks are held. But the OsFile.pLock field needs to be
+** recomputed because its key includes the thread-id. See the
+** transferOwnership() function below for additional information
*/
-#ifdef SQLITE_UNIX_THREADS
-# define SET_THREADID(X) X->tid = pthread_self()
-# define CHECK_THREADID(X) (!pthread_equal(X->tid, pthread_self()))
+#if defined(SQLITE_UNIX_THREADS)
+# define SET_THREADID(X) (X)->tid = pthread_self()
+# define CHECK_THREADID(X) (threadsOverrideEachOthersLocks==0 && \
+ !pthread_equal((X)->tid, pthread_self()))
#else
# define SET_THREADID(X)
# define CHECK_THREADID(X) 0
@@ -195,14 +284,14 @@
**
** If threads cannot override each others locks, then we set the
** lockKey.tid field to the thread ID. If threads can override
-** each others locks then tid is always set to zero. tid is also
-** set to zero if we compile without threading support.
+** each others locks then tid is always set to zero. tid is omitted
+** if we compile without threading support.
*/
struct lockKey {
dev_t dev; /* Device number */
ino_t ino; /* Inode number */
#ifdef SQLITE_UNIX_THREADS
- pthread_t tid; /* Thread ID or zero if threads cannot override each other */
+ pthread_t tid; /* Thread ID or zero if threads can override each other */
#endif
};
@@ -248,12 +337,14 @@ struct openCnt {
};
/*
-** These hash table maps inodes and process IDs into lockInfo and openCnt
-** structures. Access to these hash tables must be protected by a mutex.
+** These hash tables map inodes and file descriptors (really, lockKey and
+** openKey structures) into lockInfo and openCnt structures. Access to
+** these hash tables must be protected by a mutex.
*/
-static Hash lockHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
-static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
-
+static Hash lockHash = {SQLITE_HASH_BINARY, 0, 0, 0,
+ sqlite3ThreadSafeMalloc, sqlite3ThreadSafeFree, 0, 0};
+static Hash openHash = {SQLITE_HASH_BINARY, 0, 0, 0,
+ sqlite3ThreadSafeMalloc, sqlite3ThreadSafeFree, 0, 0};
#ifdef SQLITE_UNIX_THREADS
/*
@@ -263,8 +354,25 @@ static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
** 0: No. Threads cannot override each others locks.
** 1: Yes. Threads can override each others locks.
** -1: We don't know yet.
+**
+** On some systems, we know at compile-time if threads can override each
+** others locks. On those systems, the SQLITE_THREAD_OVERRIDE_LOCK macro
+** will be set appropriately. On other systems, we have to check at
+** runtime. On these latter systems, SQLTIE_THREAD_OVERRIDE_LOCK is
+** undefined.
+**
+** This variable normally has file scope only. But during testing, we make
+** it a global so that the test code can change its value in order to verify
+** that the right stuff happens in either case.
*/
-static int threadsOverrideEachOthersLocks = -1;
+#ifndef SQLITE_THREAD_OVERRIDE_LOCK
+# define SQLITE_THREAD_OVERRIDE_LOCK -1
+#endif
+#ifdef SQLITE_TEST
+int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK;
+#else
+static int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK;
+#endif
/*
** This structure holds information passed into individual test
@@ -283,7 +391,7 @@ struct threadTestData {
** This routine is used for troubleshooting locks on multithreaded
** platforms. Enable by compiling with the -DSQLITE_LOCK_TRACE
** command-line option on the compiler. This code is normally
-** turnned off.
+** turned off.
*/
static int lockTrace(int fd, int op, struct flock *p){
char *zOpName, *zType;
@@ -353,7 +461,7 @@ static void *threadLockingTest(void *pArg){
** can override each others locks then sets the
** threadsOverrideEachOthersLocks variable appropriately.
*/
-static void testThreadLockingBehavior(fd_orig){
+static void testThreadLockingBehavior(int fd_orig){
int fd;
struct threadTestData d[2];
pthread_t t[2];
@@ -381,10 +489,11 @@ static void testThreadLockingBehavior(fd_orig){
** Release a lockInfo structure previously allocated by findLockInfo().
*/
static void releaseLockInfo(struct lockInfo *pLock){
+ assert( sqlite3OsInMutex(1) );
pLock->nRef--;
if( pLock->nRef==0 ){
sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0);
- sqliteFree(pLock);
+ sqlite3ThreadSafeFree(pLock);
}
}
@@ -392,18 +501,19 @@ static void releaseLockInfo(struct lockInfo *pLock){
** Release a openCnt structure previously allocated by findLockInfo().
*/
static void releaseOpenCnt(struct openCnt *pOpen){
+ assert( sqlite3OsInMutex(1) );
pOpen->nRef--;
if( pOpen->nRef==0 ){
sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0);
- sqliteFree(pOpen->aPending);
- sqliteFree(pOpen);
+ free(pOpen->aPending);
+ sqlite3ThreadSafeFree(pOpen);
}
}
/*
** Given a file descriptor, locate lockInfo and openCnt structures that
-** describes that file descriptor. Create a new ones if necessary. The
-** return values might be unset if an error occurs.
+** describes that file descriptor. Create new ones if necessary. The
+** return values might be uninitialized if an error occurs.
**
** Return the number of errors.
*/
@@ -420,6 +530,8 @@ static int findLockInfo(
struct openCnt *pOpen;
rc = fstat(fd, &statbuf);
if( rc!=0 ) return 1;
+
+ assert( sqlite3OsInMutex(1) );
memset(&key1, 0, sizeof(key1));
key1.dev = statbuf.st_dev;
key1.ino = statbuf.st_ino;
@@ -435,8 +547,11 @@ static int findLockInfo(
pLock = (struct lockInfo*)sqlite3HashFind(&lockHash, &key1, sizeof(key1));
if( pLock==0 ){
struct lockInfo *pOld;
- pLock = sqliteMallocRaw( sizeof(*pLock) );
- if( pLock==0 ) return 1;
+ pLock = sqlite3ThreadSafeMalloc( sizeof(*pLock) );
+ if( pLock==0 ){
+ rc = 1;
+ goto exit_findlockinfo;
+ }
pLock->key = key1;
pLock->nRef = 1;
pLock->cnt = 0;
@@ -444,44 +559,114 @@ static int findLockInfo(
pOld = sqlite3HashInsert(&lockHash, &pLock->key, sizeof(key1), pLock);
if( pOld!=0 ){
assert( pOld==pLock );
- sqliteFree(pLock);
- return 1;
+ sqlite3ThreadSafeFree(pLock);
+ rc = 1;
+ goto exit_findlockinfo;
}
}else{
pLock->nRef++;
}
*ppLock = pLock;
- pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2));
- if( pOpen==0 ){
- struct openCnt *pOld;
- pOpen = sqliteMallocRaw( sizeof(*pOpen) );
+ if( ppOpen!=0 ){
+ pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2));
if( pOpen==0 ){
- releaseLockInfo(pLock);
- return 1;
- }
- pOpen->key = key2;
- pOpen->nRef = 1;
- pOpen->nLock = 0;
- pOpen->nPending = 0;
- pOpen->aPending = 0;
- pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen);
- if( pOld!=0 ){
- assert( pOld==pOpen );
- sqliteFree(pOpen);
- releaseLockInfo(pLock);
- return 1;
+ struct openCnt *pOld;
+ pOpen = sqlite3ThreadSafeMalloc( sizeof(*pOpen) );
+ if( pOpen==0 ){
+ releaseLockInfo(pLock);
+ rc = 1;
+ goto exit_findlockinfo;
+ }
+ pOpen->key = key2;
+ pOpen->nRef = 1;
+ pOpen->nLock = 0;
+ pOpen->nPending = 0;
+ pOpen->aPending = 0;
+ pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen);
+ if( pOld!=0 ){
+ assert( pOld==pOpen );
+ sqlite3ThreadSafeFree(pOpen);
+ releaseLockInfo(pLock);
+ rc = 1;
+ goto exit_findlockinfo;
+ }
+ }else{
+ pOpen->nRef++;
}
- }else{
- pOpen->nRef++;
+ *ppOpen = pOpen;
}
- *ppOpen = pOpen;
- return 0;
+
+exit_findlockinfo:
+ return rc;
+}
+
+#ifdef SQLITE_DEBUG
+/*
+** Helper function for printing out trace information from debugging
+** binaries. This returns the string represetation of the supplied
+** integer lock-type.
+*/
+static const char *locktypeName(int locktype){
+ switch( locktype ){
+ case NO_LOCK: return "NONE";
+ case SHARED_LOCK: return "SHARED";
+ case RESERVED_LOCK: return "RESERVED";
+ case PENDING_LOCK: return "PENDING";
+ case EXCLUSIVE_LOCK: return "EXCLUSIVE";
+ }
+ return "ERROR";
}
+#endif
+
+/*
+** If we are currently in a different thread than the thread that the
+** unixFile argument belongs to, then transfer ownership of the unixFile
+** over to the current thread.
+**
+** A unixFile is only owned by a thread on systems where one thread is
+** unable to override locks created by a different thread. RedHat9 is
+** an example of such a system.
+**
+** Ownership transfer is only allowed if the unixFile is currently unlocked.
+** If the unixFile is locked and an ownership is wrong, then return
+** SQLITE_MISUSE. SQLITE_OK is returned if everything works.
+*/
+#ifdef SQLITE_UNIX_THREADS
+static int transferOwnership(unixFile *pFile){
+ int rc;
+ pthread_t hSelf;
+ if( threadsOverrideEachOthersLocks ){
+ /* Ownership transfers not needed on this system */
+ return SQLITE_OK;
+ }
+ hSelf = pthread_self();
+ if( pthread_equal(pFile->tid, hSelf) ){
+ /* We are still in the same thread */
+ TRACE1("No-transfer, same thread\n");
+ return SQLITE_OK;
+ }
+ if( pFile->locktype!=NO_LOCK ){
+ /* We cannot change ownership while we are holding a lock! */
+ return SQLITE_MISUSE;
+ }
+ TRACE4("Transfer ownership of %d from %d to %d\n", pFile->h,pFile->tid,hSelf);
+ pFile->tid = hSelf;
+ releaseLockInfo(pFile->pLock);
+ rc = findLockInfo(pFile->h, &pFile->pLock, 0);
+ TRACE5("LOCK %d is now %s(%s,%d)\n", pFile->h,
+ locktypeName(pFile->locktype),
+ locktypeName(pFile->pLock->locktype), pFile->pLock->cnt);
+ return rc;
+}
+#else
+ /* On single-threaded builds, ownership transfer is a no-op */
+# define transferOwnership(X) SQLITE_OK
+#endif
/*
** Delete the named file
*/
-int sqlite3OsDelete(const char *zFilename){
+int sqlite3UnixDelete(const char *zFilename){
unlink(zFilename);
return SQLITE_OK;
}
@@ -489,10 +674,13 @@ int sqlite3OsDelete(const char *zFilename){
/*
** Return TRUE if the named file exists.
*/
-int sqlite3OsFileExists(const char *zFilename){
+int sqlite3UnixFileExists(const char *zFilename){
return access(zFilename, 0)==0;
}
+/* Forward declaration */
+static int allocateUnixFile(unixFile *pInit, OsFile **pId);
+
/*
** Attempt to open a file for both reading and writing. If that
** fails, try opening it read-only. If the file does not exist,
@@ -506,25 +694,26 @@ int sqlite3OsFileExists(const char *zFilename){
** On failure, the function returns SQLITE_CANTOPEN and leaves
** *id and *pReadonly unchanged.
*/
-int sqlite3OsOpenReadWrite(
+int sqlite3UnixOpenReadWrite(
const char *zFilename,
- OsFile *id,
+ OsFile **pId,
int *pReadonly
){
int rc;
- assert( !id->isOpen );
- id->dirfd = -1;
- SET_THREADID(id);
- id->h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY,
+ unixFile f;
+
+ CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadWrite, zFilename, pId, pReadonly);
+ assert( 0==*pId );
+ f.h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY,
SQLITE_DEFAULT_FILE_PERMISSIONS);
- if( id->h<0 ){
+ if( f.h<0 ){
#ifdef EISDIR
if( errno==EISDIR ){
return SQLITE_CANTOPEN;
}
#endif
- id->h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
- if( id->h<0 ){
+ f.h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
+ if( f.h<0 ){
return SQLITE_CANTOPEN;
}
*pReadonly = 1;
@@ -532,17 +721,14 @@ int sqlite3OsOpenReadWrite(
*pReadonly = 0;
}
sqlite3OsEnterMutex();
- rc = findLockInfo(id->h, &id->pLock, &id->pOpen);
+ rc = findLockInfo(f.h, &f.pLock, &f.pOpen);
sqlite3OsLeaveMutex();
if( rc ){
- close(id->h);
+ close(f.h);
return SQLITE_NOMEM;
}
- id->locktype = 0;
- id->isOpen = 1;
- TRACE3("OPEN %-3d %s\n", id->h, zFilename);
- OpenCounter(+1);
- return SQLITE_OK;
+ TRACE3("OPEN %-3d %s\n", f.h, zFilename);
+ return allocateUnixFile(&f, pId);
}
@@ -560,36 +746,31 @@ int sqlite3OsOpenReadWrite(
**
** On failure, return SQLITE_CANTOPEN.
*/
-int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
+int sqlite3UnixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
int rc;
- assert( !id->isOpen );
- if( access(zFilename, 0)==0 ){
- return SQLITE_CANTOPEN;
- }
- SET_THREADID(id);
- id->dirfd = -1;
- id->h = open(zFilename,
+ unixFile f;
+
+ CRASH_TEST_OVERRIDE(sqlite3CrashOpenExclusive, zFilename, pId, delFlag);
+ assert( 0==*pId );
+ f.h = open(zFilename,
O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY,
SQLITE_DEFAULT_FILE_PERMISSIONS);
- if( id->h<0 ){
+ if( f.h<0 ){
return SQLITE_CANTOPEN;
}
sqlite3OsEnterMutex();
- rc = findLockInfo(id->h, &id->pLock, &id->pOpen);
+ rc = findLockInfo(f.h, &f.pLock, &f.pOpen);
sqlite3OsLeaveMutex();
if( rc ){
- close(id->h);
+ close(f.h);
unlink(zFilename);
return SQLITE_NOMEM;
}
- id->locktype = 0;
- id->isOpen = 1;
if( delFlag ){
unlink(zFilename);
}
- TRACE3("OPEN-EX %-3d %s\n", id->h, zFilename);
- OpenCounter(+1);
- return SQLITE_OK;
+ TRACE3("OPEN-EX %-3d %s\n", f.h, zFilename);
+ return allocateUnixFile(&f, pId);
}
/*
@@ -599,27 +780,25 @@ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
**
** On failure, return SQLITE_CANTOPEN.
*/
-int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
+int sqlite3UnixOpenReadOnly(const char *zFilename, OsFile **pId){
int rc;
- assert( !id->isOpen );
- SET_THREADID(id);
- id->dirfd = -1;
- id->h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
- if( id->h<0 ){
+ unixFile f;
+
+ CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadOnly, zFilename, pId, 0);
+ assert( 0==*pId );
+ f.h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
+ if( f.h<0 ){
return SQLITE_CANTOPEN;
}
sqlite3OsEnterMutex();
- rc = findLockInfo(id->h, &id->pLock, &id->pOpen);
+ rc = findLockInfo(f.h, &f.pLock, &f.pOpen);
sqlite3OsLeaveMutex();
if( rc ){
- close(id->h);
+ close(f.h);
return SQLITE_NOMEM;
}
- id->locktype = 0;
- id->isOpen = 1;
- TRACE3("OPEN-RO %-3d %s\n", id->h, zFilename);
- OpenCounter(+1);
- return SQLITE_OK;
+ TRACE3("OPEN-RO %-3d %s\n", f.h, zFilename);
+ return allocateUnixFile(&f, pId);
}
/*
@@ -631,29 +810,30 @@ int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
** This routine is only meaningful for Unix. It is a no-op under
** windows since windows does not support hard links.
**
-** On success, a handle for a previously open file is at *id is
+** On success, a handle for a previously open file at *id is
** updated with the new directory file descriptor and SQLITE_OK is
** returned.
**
** On failure, the function returns SQLITE_CANTOPEN and leaves
** *id unchanged.
*/
-int sqlite3OsOpenDirectory(
- const char *zDirname,
- OsFile *id
+static int unixOpenDirectory(
+ OsFile *id,
+ const char *zDirname
){
- if( !id->isOpen ){
+ unixFile *pFile = (unixFile*)id;
+ if( pFile==0 ){
/* Do not open the directory if the corresponding file is not already
** open. */
return SQLITE_CANTOPEN;
}
- SET_THREADID(id);
- assert( id->dirfd<0 );
- id->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0);
- if( id->dirfd<0 ){
+ SET_THREADID(pFile);
+ assert( pFile->dirfd<0 );
+ pFile->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0);
+ if( pFile->dirfd<0 ){
return SQLITE_CANTOPEN;
}
- TRACE3("OPENDIR %-3d %s\n", id->dirfd, zDirname);
+ TRACE3("OPENDIR %-3d %s\n", pFile->dirfd, zDirname);
return SQLITE_OK;
}
@@ -661,6 +841,8 @@ int sqlite3OsOpenDirectory(
** If the following global variable points to a string which is the
** name of a directory, then that directory will be used to store
** temporary files.
+**
+** See also the "PRAGMA temp_store_directory" SQL command.
*/
char *sqlite3_temp_directory = 0;
@@ -668,7 +850,7 @@ char *sqlite3_temp_directory = 0;
** Create a temporary file name in zBuf. zBuf must be big enough to
** hold at least SQLITE_TEMPNAME_SIZE characters.
*/
-int sqlite3OsTempFileName(char *zBuf){
+int sqlite3UnixTempFileName(char *zBuf){
static const char *azDirs[] = {
0,
"/var/tmp",
@@ -704,35 +886,54 @@ 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){
+int sqlite3UnixIsDirWritable(char *zBuf){
+#ifndef SQLITE_OMIT_PAGER_PRAGMAS
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;
+#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
return 1;
}
-#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
+
+/*
+** Seek to the offset in id->offset then read cnt bytes into pBuf.
+** Return the number of bytes actually read. Update the offset.
+*/
+static int seekAndRead(unixFile *id, void *pBuf, int cnt){
+ int got;
+#ifdef USE_PREAD
+ got = pread(id->h, pBuf, cnt, id->offset);
+#else
+ lseek(id->h, id->offset, SEEK_SET);
+ got = read(id->h, pBuf, cnt);
+#endif
+ if( got>0 ){
+ id->offset += got;
+ }
+ return got;
+}
/*
** Read data from a file into a buffer. Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
-int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
+static int unixRead(OsFile *id, void *pBuf, int amt){
int got;
- assert( id->isOpen );
+ assert( id );
SimulateIOError(SQLITE_IOERR);
TIMER_START;
- got = read(id->h, pBuf, amt);
+ got = seekAndRead((unixFile*)id, pBuf, amt);
TIMER_END;
- TRACE5("READ %-3d %5d %7d %d\n", id->h, got, last_page, TIMER_ELAPSED);
+ TRACE5("READ %-3d %5d %7d %d\n", ((unixFile*)id)->h, got,
+ last_page, TIMER_ELAPSED);
SEEK(0);
/* if( got<0 ) got = 0; */
if( got==amt ){
@@ -743,22 +944,42 @@ int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
}
/*
+** Seek to the offset in id->offset then read cnt bytes into pBuf.
+** Return the number of bytes actually read. Update the offset.
+*/
+static int seekAndWrite(unixFile *id, const void *pBuf, int cnt){
+ int got;
+#ifdef USE_PREAD
+ got = pwrite(id->h, pBuf, cnt, id->offset);
+#else
+ lseek(id->h, id->offset, SEEK_SET);
+ got = write(id->h, pBuf, cnt);
+#endif
+ if( got>0 ){
+ id->offset += got;
+ }
+ return got;
+}
+
+
+/*
** Write data from a buffer into a file. Return SQLITE_OK on success
** or some other error code on failure.
*/
-int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
+static int unixWrite(OsFile *id, const void *pBuf, int amt){
int wrote = 0;
- assert( id->isOpen );
+ assert( id );
assert( amt>0 );
SimulateIOError(SQLITE_IOERR);
SimulateDiskfullError;
TIMER_START;
- while( amt>0 && (wrote = write(id->h, pBuf, amt))>0 ){
+ while( amt>0 && (wrote = seekAndWrite((unixFile*)id, pBuf, amt))>0 ){
amt -= wrote;
pBuf = &((char*)pBuf)[wrote];
}
TIMER_END;
- TRACE5("WRITE %-3d %5d %7d %d\n", id->h, wrote, last_page, TIMER_ELAPSED);
+ TRACE5("WRITE %-3d %5d %7d %d\n", ((unixFile*)id)->h, wrote,
+ last_page, TIMER_ELAPSED);
SEEK(0);
if( amt>0 ){
return SQLITE_FULL;
@@ -769,13 +990,13 @@ int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
/*
** Move the read/write pointer in a file.
*/
-int sqlite3OsSeek(OsFile *id, i64 offset){
- assert( id->isOpen );
+static int unixSeek(OsFile *id, i64 offset){
+ assert( id );
SEEK(offset/1024 + 1);
#ifdef SQLITE_TEST
if( offset ) SimulateDiskfullError
#endif
- lseek(id->h, offset, SEEK_SET);
+ ((unixFile*)id)->offset = offset;
return SQLITE_OK;
}
@@ -788,6 +1009,25 @@ int sqlite3_sync_count = 0;
int sqlite3_fullsync_count = 0;
#endif
+/*
+** Use the fdatasync() API only if the HAVE_FDATASYNC macro is defined.
+** Otherwise use fsync() in its place.
+*/
+#ifndef HAVE_FDATASYNC
+# define fdatasync fsync
+#endif
+
+/*
+** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not
+** the F_FULLFSYNC macro is defined. F_FULLFSYNC is currently
+** only available on Mac OS X. But that could change.
+*/
+#ifdef F_FULLFSYNC
+# define HAVE_FULLFSYNC 1
+#else
+# define HAVE_FULLFSYNC 0
+#endif
+
/*
** The fsync() system call does not work as advertised on many
@@ -819,7 +1059,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
rc = SQLITE_OK;
#else
-#ifdef F_FULLFSYNC
+#if HAVE_FULLFSYNC
if( fullSync ){
rc = fcntl(fd, F_FULLFSYNC, 0);
}else{
@@ -829,12 +1069,9 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
if( rc ) rc = fsync(fd);
#else /* if !defined(F_FULLSYNC) */
-#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO>0
if( dataOnly ){
rc = fdatasync(fd);
- }else
-#endif /* _POSIX_SYNCHRONIZED_IO > 0 */
- {
+ }else{
rc = fsync(fd);
}
#endif /* defined(F_FULLFSYNC) */
@@ -858,18 +1095,34 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
** the directory entry for the journal was never created) and the transaction
** will not roll back - possibly leading to database corruption.
*/
-int sqlite3OsSync(OsFile *id, int dataOnly){
- assert( id->isOpen );
+static int unixSync(OsFile *id, int dataOnly){
+ unixFile *pFile = (unixFile*)id;
+ assert( pFile );
SimulateIOError(SQLITE_IOERR);
- TRACE2("SYNC %-3d\n", id->h);
- if( full_fsync(id->h, id->fullSync, dataOnly) ){
+ TRACE2("SYNC %-3d\n", pFile->h);
+ if( full_fsync(pFile->h, pFile->fullSync, dataOnly) ){
return SQLITE_IOERR;
}
- if( id->dirfd>=0 ){
- TRACE2("DIRSYNC %-3d\n", id->dirfd);
- full_fsync(id->dirfd, id->fullSync, 0);
- close(id->dirfd); /* Only need to sync once, so close the directory */
- id->dirfd = -1; /* when we are done. */
+ if( pFile->dirfd>=0 ){
+ TRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd,
+ HAVE_FULLFSYNC, pFile->fullSync);
+#ifndef SQLITE_DISABLE_DIRSYNC
+ /* The directory sync is only attempted if full_fsync is
+ ** turned off or unavailable. If a full_fsync occurred above,
+ ** then the directory sync is superfluous.
+ */
+ if( (!HAVE_FULLFSYNC || !pFile->fullSync) && full_fsync(pFile->dirfd,0,0) ){
+ /*
+ ** We have received multiple reports of fsync() returning
+ ** errors when applied to directories on certain file systems.
+ ** A failed directory sync is not a big deal. So it seems
+ ** better to ignore the error. Ticket #1657
+ */
+ /* return SQLITE_IOERR; */
+ }
+#endif
+ close(pFile->dirfd); /* Only need to sync once, so close the directory */
+ pFile->dirfd = -1; /* when we are done. */
}
return SQLITE_OK;
}
@@ -882,7 +1135,10 @@ int sqlite3OsSync(OsFile *id, int dataOnly){
** before making changes to individual journals on a multi-database commit.
** The F_FULLFSYNC option is not needed here.
*/
-int sqlite3OsSyncDirectory(const char *zDirname){
+int sqlite3UnixSyncDirectory(const char *zDirname){
+#ifdef SQLITE_DISABLE_DIRSYNC
+ return SQLITE_OK;
+#else
int fd;
int r;
SimulateIOError(SQLITE_IOERR);
@@ -894,25 +1150,26 @@ int sqlite3OsSyncDirectory(const char *zDirname){
r = fsync(fd);
close(fd);
return ((r==0)?SQLITE_OK:SQLITE_IOERR);
+#endif
}
/*
** Truncate an open file to a specified size
*/
-int sqlite3OsTruncate(OsFile *id, i64 nByte){
- assert( id->isOpen );
+static int unixTruncate(OsFile *id, i64 nByte){
+ assert( id );
SimulateIOError(SQLITE_IOERR);
- return ftruncate(id->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
+ return ftruncate(((unixFile*)id)->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
}
/*
** Determine the current size of a file in bytes
*/
-int sqlite3OsFileSize(OsFile *id, i64 *pSize){
+static int unixFileSize(OsFile *id, i64 *pSize){
struct stat buf;
- assert( id->isOpen );
+ assert( id );
SimulateIOError(SQLITE_IOERR);
- if( fstat(id->h, &buf)!=0 ){
+ if( fstat(((unixFile*)id)->h, &buf)!=0 ){
return SQLITE_IOERR;
}
*pSize = buf.st_size;
@@ -925,15 +1182,15 @@ int sqlite3OsFileSize(OsFile *id, i64 *pSize){
** non-zero. If the file is unlocked or holds only SHARED locks, then
** return zero.
*/
-int sqlite3OsCheckReservedLock(OsFile *id){
+static int unixCheckReservedLock(OsFile *id){
int r = 0;
+ unixFile *pFile = (unixFile*)id;
- assert( id->isOpen );
- if( CHECK_THREADID(id) ) return SQLITE_MISUSE;
- sqlite3OsEnterMutex(); /* Needed because id->pLock is shared across threads */
+ assert( pFile );
+ sqlite3OsEnterMutex(); /* Because pFile->pLock is shared across threads */
/* Check if a thread in this process holds such a lock */
- if( id->pLock->locktype>SHARED_LOCK ){
+ if( pFile->pLock->locktype>SHARED_LOCK ){
r = 1;
}
@@ -945,36 +1202,18 @@ int sqlite3OsCheckReservedLock(OsFile *id){
lock.l_start = RESERVED_BYTE;
lock.l_len = 1;
lock.l_type = F_WRLCK;
- fcntl(id->h, F_GETLK, &lock);
+ fcntl(pFile->h, F_GETLK, &lock);
if( lock.l_type!=F_UNLCK ){
r = 1;
}
}
sqlite3OsLeaveMutex();
- TRACE3("TEST WR-LOCK %d %d\n", id->h, r);
+ TRACE3("TEST WR-LOCK %d %d\n", pFile->h, r);
return r;
}
-#ifdef SQLITE_DEBUG
-/*
-** Helper function for printing out trace information from debugging
-** binaries. This returns the string represetation of the supplied
-** integer lock-type.
-*/
-static const char * locktypeName(int locktype){
- switch( locktype ){
- case NO_LOCK: return "NONE";
- case SHARED_LOCK: return "SHARED";
- case RESERVED_LOCK: return "RESERVED";
- case PENDING_LOCK: return "PENDING";
- case EXCLUSIVE_LOCK: return "EXCLUSIVE";
- }
- return "ERROR";
-}
-#endif
-
/*
** Lock the file with the lock specified by parameter locktype - one
** of the following:
@@ -999,7 +1238,7 @@ static const char * locktypeName(int locktype){
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-int sqlite3OsLock(OsFile *id, int locktype){
+static int unixLock(OsFile *id, int locktype){
/* The following describes the implementation of the various locks and
** lock transitions in terms of the POSIX advisory shared and exclusive
** lock primitives (called read-locks and write-locks below, to avoid
@@ -1039,39 +1278,49 @@ int sqlite3OsLock(OsFile *id, int locktype){
** even if the locking primitive used is always a write-lock.
*/
int rc = SQLITE_OK;
- struct lockInfo *pLock = id->pLock;
+ unixFile *pFile = (unixFile*)id;
+ struct lockInfo *pLock = pFile->pLock;
struct flock lock;
int s;
- assert( id->isOpen );
- TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", id->h, locktypeName(locktype),
- locktypeName(id->locktype), locktypeName(pLock->locktype), pLock->cnt
- ,getpid() );
- if( CHECK_THREADID(id) ) return SQLITE_MISUSE;
+ assert( pFile );
+ TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", pFile->h,
+ locktypeName(locktype), locktypeName(pFile->locktype),
+ locktypeName(pLock->locktype), pLock->cnt , getpid());
/* If there is already a lock of this type or more restrictive on the
** OsFile, do nothing. Don't use the end_lock: exit path, as
** sqlite3OsEnterMutex() hasn't been called yet.
*/
- if( id->locktype>=locktype ){
- TRACE3("LOCK %d %s ok (already held)\n", id->h, locktypeName(locktype));
+ if( pFile->locktype>=locktype ){
+ TRACE3("LOCK %d %s ok (already held)\n", pFile->h,
+ locktypeName(locktype));
return SQLITE_OK;
}
/* Make sure the locking sequence is correct
*/
- assert( id->locktype!=NO_LOCK || locktype==SHARED_LOCK );
+ assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
assert( locktype!=PENDING_LOCK );
- assert( locktype!=RESERVED_LOCK || id->locktype==SHARED_LOCK );
+ assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
- /* This mutex is needed because id->pLock is shared across threads
+ /* This mutex is needed because pFile->pLock is shared across threads
*/
sqlite3OsEnterMutex();
+ /* Make sure the current thread owns the pFile.
+ */
+ rc = transferOwnership(pFile);
+ if( rc!=SQLITE_OK ){
+ sqlite3OsLeaveMutex();
+ return rc;
+ }
+ pLock = pFile->pLock;
+
/* If some thread using this PID has a lock via a different OsFile*
** handle that precludes the requested lock, return BUSY.
*/
- if( (id->locktype!=pLock->locktype &&
+ if( (pFile->locktype!=pLock->locktype &&
(pLock->locktype>=PENDING_LOCK || locktype>SHARED_LOCK))
){
rc = SQLITE_BUSY;
@@ -1085,11 +1334,11 @@ int sqlite3OsLock(OsFile *id, int locktype){
if( locktype==SHARED_LOCK &&
(pLock->locktype==SHARED_LOCK || pLock->locktype==RESERVED_LOCK) ){
assert( locktype==SHARED_LOCK );
- assert( id->locktype==0 );
+ assert( pFile->locktype==0 );
assert( pLock->cnt>0 );
- id->locktype = SHARED_LOCK;
+ pFile->locktype = SHARED_LOCK;
pLock->cnt++;
- id->pOpen->nLock++;
+ pFile->pOpen->nLock++;
goto end_lock;
}
@@ -1102,11 +1351,11 @@ int sqlite3OsLock(OsFile *id, int locktype){
** be released.
*/
if( locktype==SHARED_LOCK
- || (locktype==EXCLUSIVE_LOCK && id->locktype<PENDING_LOCK)
+ || (locktype==EXCLUSIVE_LOCK && pFile->locktype<PENDING_LOCK)
){
lock.l_type = (locktype==SHARED_LOCK?F_RDLCK:F_WRLCK);
lock.l_start = PENDING_BYTE;
- s = fcntl(id->h, F_SETLK, &lock);
+ s = fcntl(pFile->h, F_SETLK, &lock);
if( s ){
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
goto end_lock;
@@ -1124,21 +1373,21 @@ int sqlite3OsLock(OsFile *id, int locktype){
/* Now get the read-lock */
lock.l_start = SHARED_FIRST;
lock.l_len = SHARED_SIZE;
- s = fcntl(id->h, F_SETLK, &lock);
+ s = fcntl(pFile->h, F_SETLK, &lock);
/* Drop the temporary PENDING lock */
lock.l_start = PENDING_BYTE;
lock.l_len = 1L;
lock.l_type = F_UNLCK;
- if( fcntl(id->h, F_SETLK, &lock)!=0 ){
+ if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){
rc = SQLITE_IOERR; /* This should never happen */
goto end_lock;
}
if( s ){
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
}else{
- id->locktype = SHARED_LOCK;
- id->pOpen->nLock++;
+ pFile->locktype = SHARED_LOCK;
+ pFile->pOpen->nLock++;
pLock->cnt = 1;
}
}else if( locktype==EXCLUSIVE_LOCK && pLock->cnt>1 ){
@@ -1150,7 +1399,7 @@ int sqlite3OsLock(OsFile *id, int locktype){
** assumed that there is a SHARED or greater lock on the file
** already.
*/
- assert( 0!=id->locktype );
+ assert( 0!=pFile->locktype );
lock.l_type = F_WRLCK;
switch( locktype ){
case RESERVED_LOCK:
@@ -1163,63 +1412,62 @@ int sqlite3OsLock(OsFile *id, int locktype){
default:
assert(0);
}
- s = fcntl(id->h, F_SETLK, &lock);
+ s = fcntl(pFile->h, F_SETLK, &lock);
if( s ){
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
}
}
if( rc==SQLITE_OK ){
- id->locktype = locktype;
+ pFile->locktype = locktype;
pLock->locktype = locktype;
}else if( locktype==EXCLUSIVE_LOCK ){
- id->locktype = PENDING_LOCK;
+ pFile->locktype = PENDING_LOCK;
pLock->locktype = PENDING_LOCK;
}
end_lock:
sqlite3OsLeaveMutex();
- TRACE4("LOCK %d %s %s\n", id->h, locktypeName(locktype),
+ TRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype),
rc==SQLITE_OK ? "ok" : "failed");
return rc;
}
/*
-** Lower the locking level on file descriptor id to locktype. locktype
+** Lower the locking level on file descriptor pFile to locktype. locktype
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
-**
-** It is not possible for this routine to fail if the second argument
-** is NO_LOCK. If the second argument is SHARED_LOCK, this routine
-** might return SQLITE_IOERR instead of SQLITE_OK.
*/
-int sqlite3OsUnlock(OsFile *id, int locktype){
+static int unixUnlock(OsFile *id, int locktype){
struct lockInfo *pLock;
struct flock lock;
int rc = SQLITE_OK;
+ unixFile *pFile = (unixFile*)id;
- assert( id->isOpen );
- TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", id->h, locktype, id->locktype,
- id->pLock->locktype, id->pLock->cnt, getpid());
- if( CHECK_THREADID(id) ) return SQLITE_MISUSE;
+ assert( pFile );
+ TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", pFile->h, locktype,
+ pFile->locktype, pFile->pLock->locktype, pFile->pLock->cnt, getpid());
assert( locktype<=SHARED_LOCK );
- if( id->locktype<=locktype ){
+ if( pFile->locktype<=locktype ){
return SQLITE_OK;
}
+ if( CHECK_THREADID(pFile) ){
+ return SQLITE_MISUSE;
+ }
sqlite3OsEnterMutex();
- pLock = id->pLock;
+ pLock = pFile->pLock;
assert( pLock->cnt!=0 );
- if( id->locktype>SHARED_LOCK ){
- assert( pLock->locktype==id->locktype );
+ if( pFile->locktype>SHARED_LOCK ){
+ assert( pLock->locktype==pFile->locktype );
if( locktype==SHARED_LOCK ){
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST;
lock.l_len = SHARED_SIZE;
- if( fcntl(id->h, F_SETLK, &lock)!=0 ){
+ if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){
/* This should never happen */
rc = SQLITE_IOERR;
}
@@ -1228,7 +1476,7 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
lock.l_whence = SEEK_SET;
lock.l_start = PENDING_BYTE;
lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE );
- if( fcntl(id->h, F_SETLK, &lock)==0 ){
+ if( fcntl(pFile->h, F_SETLK, &lock)==0 ){
pLock->locktype = SHARED_LOCK;
}else{
rc = SQLITE_IOERR; /* This should never happen */
@@ -1246,7 +1494,7 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = lock.l_len = 0L;
- if( fcntl(id->h, F_SETLK, &lock)==0 ){
+ if( fcntl(pFile->h, F_SETLK, &lock)==0 ){
pLock->locktype = NO_LOCK;
}else{
rc = SQLITE_IOERR; /* This should never happen */
@@ -1257,7 +1505,7 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
** count reaches zero, close any other file descriptors whose close
** was deferred because of outstanding locks.
*/
- pOpen = id->pOpen;
+ pOpen = pFile->pOpen;
pOpen->nLock--;
assert( pOpen->nLock>=0 );
if( pOpen->nLock==0 && pOpen->nPending>0 ){
@@ -1265,26 +1513,28 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
for(i=0; i<pOpen->nPending; i++){
close(pOpen->aPending[i]);
}
- sqliteFree(pOpen->aPending);
+ free(pOpen->aPending);
pOpen->nPending = 0;
pOpen->aPending = 0;
}
}
sqlite3OsLeaveMutex();
- id->locktype = locktype;
+ pFile->locktype = locktype;
return rc;
}
/*
** Close a file.
*/
-int sqlite3OsClose(OsFile *id){
- if( !id->isOpen ) return SQLITE_OK;
- if( CHECK_THREADID(id) ) return SQLITE_MISUSE;
- sqlite3OsUnlock(id, NO_LOCK);
+static int unixClose(OsFile **pId){
+ unixFile *id = (unixFile*)*pId;
+
+ if( !id ) return SQLITE_OK;
+ unixUnlock(*pId, NO_LOCK);
if( id->dirfd>=0 ) close(id->dirfd);
id->dirfd = -1;
sqlite3OsEnterMutex();
+
if( id->pOpen->nLock ){
/* If there are outstanding locks, do not actually close the file just
** yet because that would clear those locks. Instead, add the file
@@ -1293,7 +1543,7 @@ int sqlite3OsClose(OsFile *id){
*/
int *aNew;
struct openCnt *pOpen = id->pOpen;
- aNew = sqliteRealloc( pOpen->aPending, (pOpen->nPending+1)*sizeof(int) );
+ aNew = realloc( pOpen->aPending, (pOpen->nPending+1)*sizeof(int) );
if( aNew==0 ){
/* If a malloc fails, just leak the file descriptor */
}else{
@@ -1307,10 +1557,13 @@ int sqlite3OsClose(OsFile *id){
}
releaseLockInfo(id->pLock);
releaseOpenCnt(id->pOpen);
+
sqlite3OsLeaveMutex();
id->isOpen = 0;
TRACE2("CLOSE %-3d\n", id->h);
OpenCounter(-1);
+ sqlite3ThreadSafeFree(id);
+ *pId = 0;
return SQLITE_OK;
}
@@ -1320,7 +1573,7 @@ int sqlite3OsClose(OsFile *id){
** The calling function is responsible for freeing this space once it
** is no longer needed.
*/
-char *sqlite3OsFullPathname(const char *zRelative){
+char *sqlite3UnixFullPathname(const char *zRelative){
char *zFull = 0;
if( zRelative[0]=='/' ){
sqlite3SetString(&zFull, zRelative, (char*)0);
@@ -1334,9 +1587,109 @@ char *sqlite3OsFullPathname(const char *zRelative){
(char*)0);
sqliteFree(zBuf);
}
+
+#if 0
+ /*
+ ** Remove "/./" path elements and convert "/A/./" path elements
+ ** to just "/".
+ */
+ if( zFull ){
+ int i, j;
+ for(i=j=0; zFull[i]; i++){
+ if( zFull[i]=='/' ){
+ if( zFull[i+1]=='/' ) continue;
+ if( zFull[i+1]=='.' && zFull[i+2]=='/' ){
+ i += 1;
+ continue;
+ }
+ if( zFull[i+1]=='.' && zFull[i+2]=='.' && zFull[i+3]=='/' ){
+ while( j>0 && zFull[j-1]!='/' ){ j--; }
+ i += 3;
+ continue;
+ }
+ }
+ zFull[j++] = zFull[i];
+ }
+ zFull[j] = 0;
+ }
+#endif
+
return zFull;
}
+/*
+** Change the value of the fullsync flag in the given file descriptor.
+*/
+static void unixSetFullSync(OsFile *id, int v){
+ ((unixFile*)id)->fullSync = v;
+}
+
+/*
+** Return the underlying file handle for an OsFile
+*/
+static int unixFileHandle(OsFile *id){
+ return ((unixFile*)id)->h;
+}
+
+/*
+** Return an integer that indices the type of lock currently held
+** by this handle. (Used for testing and analysis only.)
+*/
+static int unixLockState(OsFile *id){
+ return ((unixFile*)id)->locktype;
+}
+
+/*
+** This vector defines all the methods that can operate on an OsFile
+** for unix.
+*/
+static const IoMethod sqlite3UnixIoMethod = {
+ unixClose,
+ unixOpenDirectory,
+ unixRead,
+ unixWrite,
+ unixSeek,
+ unixTruncate,
+ unixSync,
+ unixSetFullSync,
+ unixFileHandle,
+ unixFileSize,
+ unixLock,
+ unixUnlock,
+ unixLockState,
+ unixCheckReservedLock,
+};
+
+/*
+** Allocate memory for a unixFile. Initialize the new unixFile
+** to the value given in pInit and return a pointer to the new
+** OsFile. If we run out of memory, close the file and return NULL.
+*/
+static int allocateUnixFile(unixFile *pInit, OsFile **pId){
+ unixFile *pNew;
+ pInit->dirfd = -1;
+ pInit->fullSync = 0;
+ pInit->locktype = 0;
+ pInit->offset = 0;
+ SET_THREADID(pInit);
+ pNew = sqlite3ThreadSafeMalloc( sizeof(unixFile) );
+ if( pNew==0 ){
+ close(pInit->h);
+ sqlite3OsEnterMutex();
+ releaseLockInfo(pInit->pLock);
+ releaseOpenCnt(pInit->pOpen);
+ sqlite3OsLeaveMutex();
+ *pId = 0;
+ return SQLITE_NOMEM;
+ }else{
+ *pNew = *pInit;
+ pNew->pMethod = &sqlite3UnixIoMethod;
+ *pId = (OsFile*)pNew;
+ OpenCounter(+1);
+ return SQLITE_OK;
+ }
+}
+
#endif /* SQLITE_OMIT_DISKIO */
/***************************************************************************
@@ -1350,7 +1703,7 @@ char *sqlite3OsFullPathname(const char *zRelative){
** is written into the buffer zBuf[256]. The calling function must
** supply a sufficiently large buffer.
*/
-int sqlite3OsRandomSeed(char *zBuf){
+int sqlite3UnixRandomSeed(char *zBuf){
/* We have to initialize zBuf to prevent valgrind from reporting
** errors. The reports issued by valgrind are incorrect - we would
** prefer that the randomness be increased by making use of the
@@ -1360,7 +1713,7 @@ int sqlite3OsRandomSeed(char *zBuf){
** in the random seed.
**
** When testing, initializing zBuf[] to zero is all we do. That means
- ** that we always use the same random number sequence.* This makes the
+ ** that we always use the same random number sequence. This makes the
** tests repeatable.
*/
memset(zBuf, 0, 256);
@@ -1369,7 +1722,9 @@ int sqlite3OsRandomSeed(char *zBuf){
int pid, fd;
fd = open("/dev/urandom", O_RDONLY);
if( fd<0 ){
- time((time_t*)zBuf);
+ time_t t;
+ time(&t);
+ memcpy(zBuf, &t, sizeof(t));
pid = getpid();
memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid));
}else{
@@ -1383,8 +1738,9 @@ int sqlite3OsRandomSeed(char *zBuf){
/*
** Sleep for a little while. Return the amount of time slept.
+** The argument is the number of milliseconds we want to sleep.
*/
-int sqlite3OsSleep(int ms){
+int sqlite3UnixSleep(int ms){
#if defined(HAVE_USLEEP) && HAVE_USLEEP
usleep(ms*1000);
return ms;
@@ -1395,11 +1751,42 @@ int sqlite3OsSleep(int ms){
}
/*
-** Static variables used for thread synchronization
+** Static variables used for thread synchronization.
+**
+** inMutex the nesting depth of the recursive mutex. The thread
+** holding mutexMain can read this variable at any time.
+** But is must hold mutexAux to change this variable. Other
+** threads must hold mutexAux to read the variable and can
+** never write.
+**
+** mutexOwner The thread id of the thread holding mutexMain. Same
+** access rules as for inMutex.
+**
+** mutexOwnerValid True if the value in mutexOwner is valid. The same
+** access rules apply as for inMutex.
+**
+** mutexMain The main mutex. Hold this mutex in order to get exclusive
+** access to SQLite data structures.
+**
+** mutexAux An auxiliary mutex needed to access variables defined above.
+**
+** Mutexes are always acquired in this order: mutexMain mutexAux. It
+** is not necessary to acquire mutexMain in order to get mutexAux - just
+** do not attempt to acquire them in the reverse order: mutexAux mutexMain.
+** Either get the mutexes with mutexMain first or get mutexAux only.
+**
+** When running on a platform where the three variables inMutex, mutexOwner,
+** and mutexOwnerValid can be set atomically, the mutexAux is not required.
+** On many systems, all three are 32-bit integers and writing to a 32-bit
+** integer is atomic. I think. But there are no guarantees. So it seems
+** safer to protect them using mutexAux.
*/
static int inMutex = 0;
#ifdef SQLITE_UNIX_THREADS
-static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_t mutexOwner; /* Thread holding mutexMain */
+static int mutexOwnerValid = 0; /* True if mutexOwner is valid */
+static pthread_mutex_t mutexMain = PTHREAD_MUTEX_INITIALIZER; /* The mutex */
+static pthread_mutex_t mutexAux = PTHREAD_MUTEX_INITIALIZER; /* Aux mutex */
#endif
/*
@@ -1409,19 +1796,164 @@ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
**
** SQLite uses only a single Mutex. There is not much critical
** code and what little there is executes quickly and without blocking.
+**
+** As of version 3.3.2, this mutex must be recursive.
*/
-void sqlite3OsEnterMutex(){
+void sqlite3UnixEnterMutex(){
+#ifdef SQLITE_UNIX_THREADS
+ pthread_mutex_lock(&mutexAux);
+ if( !mutexOwnerValid || !pthread_equal(mutexOwner, pthread_self()) ){
+ pthread_mutex_unlock(&mutexAux);
+ pthread_mutex_lock(&mutexMain);
+ assert( inMutex==0 );
+ assert( !mutexOwnerValid );
+ pthread_mutex_lock(&mutexAux);
+ mutexOwner = pthread_self();
+ mutexOwnerValid = 1;
+ }
+ inMutex++;
+ pthread_mutex_unlock(&mutexAux);
+#else
+ inMutex++;
+#endif
+}
+void sqlite3UnixLeaveMutex(){
+ assert( inMutex>0 );
#ifdef SQLITE_UNIX_THREADS
- pthread_mutex_lock(&mutex);
+ pthread_mutex_lock(&mutexAux);
+ inMutex--;
+ assert( pthread_equal(mutexOwner, pthread_self()) );
+ if( inMutex==0 ){
+ assert( mutexOwnerValid );
+ mutexOwnerValid = 0;
+ pthread_mutex_unlock(&mutexMain);
+ }
+ pthread_mutex_unlock(&mutexAux);
+#else
+ inMutex--;
#endif
- assert( !inMutex );
- inMutex = 1;
}
-void sqlite3OsLeaveMutex(){
- assert( inMutex );
- inMutex = 0;
+
+/*
+** Return TRUE if the mutex is currently held.
+**
+** If the thisThrd parameter is true, return true only if the
+** calling thread holds the mutex. If the parameter is false, return
+** true if any thread holds the mutex.
+*/
+int sqlite3UnixInMutex(int thisThrd){
#ifdef SQLITE_UNIX_THREADS
- pthread_mutex_unlock(&mutex);
+ int rc;
+ pthread_mutex_lock(&mutexAux);
+ rc = inMutex>0 && (thisThrd==0 || pthread_equal(mutexOwner,pthread_self()));
+ pthread_mutex_unlock(&mutexAux);
+ return rc;
+#else
+ return inMutex>0;
+#endif
+}
+
+/*
+** Remember the number of thread-specific-data blocks allocated.
+** Use this to verify that we are not leaking thread-specific-data.
+** Ticket #1601
+*/
+#ifdef SQLITE_TEST
+int sqlite3_tsd_count = 0;
+# ifdef SQLITE_UNIX_THREADS
+ static pthread_mutex_t tsd_counter_mutex = PTHREAD_MUTEX_INITIALIZER;
+# define TSD_COUNTER(N) \
+ pthread_mutex_lock(&tsd_counter_mutex); \
+ sqlite3_tsd_count += N; \
+ pthread_mutex_unlock(&tsd_counter_mutex);
+# else
+# define TSD_COUNTER(N) sqlite3_tsd_count += N
+# endif
+#else
+# define TSD_COUNTER(N) /* no-op */
+#endif
+
+/*
+** If called with allocateFlag>0, then return a pointer to thread
+** specific data for the current thread. Allocate and zero the
+** thread-specific data if it does not already exist.
+**
+** If called with allocateFlag==0, then check the current thread
+** specific data. Return it if it exists. If it does not exist,
+** then return NULL.
+**
+** If called with allocateFlag<0, check to see if the thread specific
+** data is allocated and is all zero. If it is then deallocate it.
+** Return a pointer to the thread specific data or NULL if it is
+** unallocated or gets deallocated.
+*/
+ThreadData *sqlite3UnixThreadSpecificData(int allocateFlag){
+ static const ThreadData zeroData = {0}; /* Initializer to silence warnings
+ ** from broken compilers */
+#ifdef SQLITE_UNIX_THREADS
+ static pthread_key_t key;
+ static int keyInit = 0;
+ ThreadData *pTsd;
+
+ if( !keyInit ){
+ sqlite3OsEnterMutex();
+ if( !keyInit ){
+ int rc;
+ rc = pthread_key_create(&key, 0);
+ if( rc ){
+ sqlite3OsLeaveMutex();
+ return 0;
+ }
+ keyInit = 1;
+ }
+ sqlite3OsLeaveMutex();
+ }
+
+ pTsd = pthread_getspecific(key);
+ if( allocateFlag>0 ){
+ if( pTsd==0 ){
+ if( !sqlite3TestMallocFail() ){
+ pTsd = sqlite3OsMalloc(sizeof(zeroData));
+ }
+#ifdef SQLITE_MEMDEBUG
+ sqlite3_isFail = 0;
+#endif
+ if( pTsd ){
+ *pTsd = zeroData;
+ pthread_setspecific(key, pTsd);
+ TSD_COUNTER(+1);
+ }
+ }
+ }else if( pTsd!=0 && allocateFlag<0
+ && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){
+ sqlite3OsFree(pTsd);
+ pthread_setspecific(key, 0);
+ TSD_COUNTER(-1);
+ pTsd = 0;
+ }
+ return pTsd;
+#else
+ static ThreadData *pTsd = 0;
+ if( allocateFlag>0 ){
+ if( pTsd==0 ){
+ if( !sqlite3TestMallocFail() ){
+ pTsd = sqlite3OsMalloc( sizeof(zeroData) );
+ }
+#ifdef SQLITE_MEMDEBUG
+ sqlite3_isFail = 0;
+#endif
+ if( pTsd ){
+ *pTsd = zeroData;
+ TSD_COUNTER(+1);
+ }
+ }
+ }else if( pTsd!=0 && allocateFlag<0
+ && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){
+ sqlite3OsFree(pTsd);
+ TSD_COUNTER(-1);
+ pTsd = 0;
+ }
+ return pTsd;
#endif
}
@@ -1438,7 +1970,7 @@ int sqlite3_current_time = 0;
** current time and date as a Julian Day number into *prNow and
** return 0. Return 1 if the time and date cannot be found.
*/
-int sqlite3OsCurrentTime(double *prNow){
+int sqlite3UnixCurrentTime(double *prNow){
#ifdef NO_GETTOD
time_t t;
time(&t);
diff --git a/ext/pdo_sqlite/sqlite/src/os_win.c b/ext/pdo_sqlite/sqlite/src/os_win.c
index ad874ae633..6c167ab5b8 100644
--- a/ext/pdo_sqlite/sqlite/src/os_win.c
+++ b/ext/pdo_sqlite/sqlite/src/os_win.c
@@ -35,6 +35,49 @@
#include "os_common.h"
/*
+** Determine if we are dealing with WindowsCE - which has a much
+** reduced API.
+*/
+#if defined(_WIN32_WCE)
+# define OS_WINCE 1
+#else
+# define OS_WINCE 0
+#endif
+
+/*
+** WinCE lacks native support for file locking so we have to fake it
+** with some code of our own.
+*/
+#if OS_WINCE
+typedef struct winceLock {
+ int nReaders; /* Number of reader locks obtained */
+ BOOL bPending; /* Indicates a pending lock has been obtained */
+ BOOL bReserved; /* Indicates a reserved lock has been obtained */
+ BOOL bExclusive; /* Indicates an exclusive lock has been obtained */
+} winceLock;
+#endif
+
+/*
+** The winFile structure is a subclass of OsFile specific to the win32
+** portability layer.
+*/
+typedef struct winFile winFile;
+struct winFile {
+ IoMethod const *pMethod;/* Must be first */
+ HANDLE h; /* Handle for accessing the file */
+ unsigned char locktype; /* Type of lock currently held on this file */
+ short sharedLockByte; /* Randomly chosen byte used as a shared lock */
+#if OS_WINCE
+ WCHAR *zDeleteOnClose; /* Name of file to delete when closing */
+ HANDLE hMutex; /* Mutex used to control access to shared lock */
+ HANDLE hShared; /* Shared memory segment used for locking */
+ winceLock local; /* Locks obtained by this instance of winFile */
+ winceLock *shared; /* Global shared lock memory for the file */
+#endif
+};
+
+
+/*
** Do not include any of the File I/O interface procedures if the
** SQLITE_OMIT_DISKIO macro is defined (indicating that there database
** will be in-memory only)
@@ -56,8 +99,8 @@
int sqlite3_os_type = 0;
/*
-** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.
-** Return false (zero) for Win95, Win98, or WinME.
+** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
+** or WinCE. Return false (zero) for Win95, Win98, or WinME.
**
** Here is an interesting observation: Win95, Win98, and WinME lack
** the LockFileEx() API. But we can still statically link against that
@@ -66,34 +109,38 @@ int sqlite3_os_type = 0;
** WinNT/2K/XP so that we will know whether or not we can safely call
** the LockFileEx() API.
*/
-static int isNT(void){
- if( sqlite3_os_type==0 ){
- OSVERSIONINFO sInfo;
- sInfo.dwOSVersionInfoSize = sizeof(sInfo);
- GetVersionEx(&sInfo);
- sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
+#if OS_WINCE
+# define isNT() (1)
+#else
+ static int isNT(void){
+ if( sqlite3_os_type==0 ){
+ OSVERSIONINFO sInfo;
+ sInfo.dwOSVersionInfoSize = sizeof(sInfo);
+ GetVersionEx(&sInfo);
+ sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
+ }
+ return sqlite3_os_type==2;
}
- return sqlite3_os_type==2;
-}
+#endif /* OS_WINCE */
/*
** Convert a UTF-8 string to UTF-32. Space to hold the returned string
** is obtained from sqliteMalloc.
*/
static WCHAR *utf8ToUnicode(const char *zFilename){
- int nByte;
+ int nChar;
WCHAR *zWideFilename;
if( !isNT() ){
return 0;
}
- nByte = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0)*sizeof(WCHAR);
- zWideFilename = sqliteMalloc( nByte*sizeof(zWideFilename[0]) );
+ nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
+ zWideFilename = sqliteMalloc( nChar*sizeof(zWideFilename[0]) );
if( zWideFilename==0 ){
return 0;
}
- nByte = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nByte);
- if( nByte==0 ){
+ nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar);
+ if( nChar==0 ){
sqliteFree(zWideFilename);
zWideFilename = 0;
}
@@ -122,37 +169,369 @@ static char *unicodeToUtf8(const WCHAR *zWideFilename){
return zFilename;
}
+#if OS_WINCE
+/*************************************************************************
+** This section contains code for WinCE only.
+*/
+/*
+** WindowsCE does not have a localtime() function. So create a
+** substitute.
+*/
+#include <time.h>
+struct tm *__cdecl localtime(const time_t *t)
+{
+ static struct tm y;
+ FILETIME uTm, lTm;
+ SYSTEMTIME pTm;
+ i64 t64;
+ t64 = *t;
+ t64 = (t64 + 11644473600)*10000000;
+ uTm.dwLowDateTime = t64 & 0xFFFFFFFF;
+ uTm.dwHighDateTime= t64 >> 32;
+ FileTimeToLocalFileTime(&uTm,&lTm);
+ FileTimeToSystemTime(&lTm,&pTm);
+ y.tm_year = pTm.wYear - 1900;
+ y.tm_mon = pTm.wMonth - 1;
+ y.tm_wday = pTm.wDayOfWeek;
+ y.tm_mday = pTm.wDay;
+ y.tm_hour = pTm.wHour;
+ y.tm_min = pTm.wMinute;
+ y.tm_sec = pTm.wSecond;
+ return &y;
+}
+
+/* This will never be called, but defined to make the code compile */
+#define GetTempPathA(a,b)
+
+#define LockFile(a,b,c,d,e) winceLockFile(&a, b, c, d, e)
+#define UnlockFile(a,b,c,d,e) winceUnlockFile(&a, b, c, d, e)
+#define LockFileEx(a,b,c,d,e,f) winceLockFileEx(&a, b, c, d, e, f)
+
+#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-offsetof(winFile,h)]
+
+/*
+** Acquire a lock on the handle h
+*/
+static void winceMutexAcquire(HANDLE h){
+ DWORD dwErr;
+ do {
+ dwErr = WaitForSingleObject(h, INFINITE);
+ } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED);
+}
+/*
+** Release a lock acquired by winceMutexAcquire()
+*/
+#define winceMutexRelease(h) ReleaseMutex(h)
+
+/*
+** Create the mutex and shared memory used for locking in the file
+** descriptor pFile
+*/
+static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
+ WCHAR *zTok;
+ WCHAR *zName = utf8ToUnicode(zFilename);
+ BOOL bInit = TRUE;
+
+ /* Initialize the local lockdata */
+ ZeroMemory(&pFile->local, sizeof(pFile->local));
+
+ /* Replace the backslashes from the filename and lowercase it
+ ** to derive a mutex name. */
+ zTok = CharLowerW(zName);
+ for (;*zTok;zTok++){
+ if (*zTok == '\\') *zTok = '_';
+ }
+
+ /* Create/open the named mutex */
+ pFile->hMutex = CreateMutexW(NULL, FALSE, zName);
+ if (!pFile->hMutex){
+ sqliteFree(zName);
+ return FALSE;
+ }
+
+ /* Acquire the mutex before continuing */
+ winceMutexAcquire(pFile->hMutex);
+
+ /* Since the names of named mutexes, semaphores, file mappings etc are
+ ** case-sensitive, take advantage of that by uppercasing the mutex name
+ ** and using that as the shared filemapping name.
+ */
+ CharUpperW(zName);
+ pFile->hShared = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
+ PAGE_READWRITE, 0, sizeof(winceLock),
+ zName);
+
+ /* Set a flag that indicates we're the first to create the memory so it
+ ** must be zero-initialized */
+ if (GetLastError() == ERROR_ALREADY_EXISTS){
+ bInit = FALSE;
+ }
+
+ sqliteFree(zName);
+
+ /* If we succeeded in making the shared memory handle, map it. */
+ if (pFile->hShared){
+ pFile->shared = (winceLock*)MapViewOfFile(pFile->hShared,
+ FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock));
+ /* If mapping failed, close the shared memory handle and erase it */
+ if (!pFile->shared){
+ CloseHandle(pFile->hShared);
+ pFile->hShared = NULL;
+ }
+ }
+
+ /* If shared memory could not be created, then close the mutex and fail */
+ if (pFile->hShared == NULL){
+ winceMutexRelease(pFile->hMutex);
+ CloseHandle(pFile->hMutex);
+ pFile->hMutex = NULL;
+ return FALSE;
+ }
+
+ /* Initialize the shared memory if we're supposed to */
+ if (bInit) {
+ ZeroMemory(pFile->shared, sizeof(winceLock));
+ }
+
+ winceMutexRelease(pFile->hMutex);
+ return TRUE;
+}
+
+/*
+** Destroy the part of winFile that deals with wince locks
+*/
+static void winceDestroyLock(winFile *pFile){
+ if (pFile->hMutex){
+ /* Acquire the mutex */
+ winceMutexAcquire(pFile->hMutex);
+
+ /* The following blocks should probably assert in debug mode, but they
+ are to cleanup in case any locks remained open */
+ if (pFile->local.nReaders){
+ pFile->shared->nReaders --;
+ }
+ if (pFile->local.bReserved){
+ pFile->shared->bReserved = FALSE;
+ }
+ if (pFile->local.bPending){
+ pFile->shared->bPending = FALSE;
+ }
+ if (pFile->local.bExclusive){
+ pFile->shared->bExclusive = FALSE;
+ }
+
+ /* De-reference and close our copy of the shared memory handle */
+ UnmapViewOfFile(pFile->shared);
+ CloseHandle(pFile->hShared);
+
+ /* Done with the mutex */
+ winceMutexRelease(pFile->hMutex);
+ CloseHandle(pFile->hMutex);
+ pFile->hMutex = NULL;
+ }
+}
+
+/*
+** An implementation of the LockFile() API of windows for wince
+*/
+static BOOL winceLockFile(
+ HANDLE *phFile,
+ DWORD dwFileOffsetLow,
+ DWORD dwFileOffsetHigh,
+ DWORD nNumberOfBytesToLockLow,
+ DWORD nNumberOfBytesToLockHigh
+){
+ winFile *pFile = HANDLE_TO_WINFILE(phFile);
+ BOOL bReturn = FALSE;
+
+ if (!pFile->hMutex) return TRUE;
+ winceMutexAcquire(pFile->hMutex);
+
+ /* Wanting an exclusive lock? */
+ if (dwFileOffsetLow == SHARED_FIRST
+ && nNumberOfBytesToLockLow == SHARED_SIZE){
+ if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){
+ pFile->shared->bExclusive = TRUE;
+ pFile->local.bExclusive = TRUE;
+ bReturn = TRUE;
+ }
+ }
+
+ /* Want a read-only lock? */
+ else if ((dwFileOffsetLow >= SHARED_FIRST &&
+ dwFileOffsetLow < SHARED_FIRST + SHARED_SIZE) &&
+ nNumberOfBytesToLockLow == 1){
+ if (pFile->shared->bExclusive == 0){
+ pFile->local.nReaders ++;
+ if (pFile->local.nReaders == 1){
+ pFile->shared->nReaders ++;
+ }
+ bReturn = TRUE;
+ }
+ }
+
+ /* Want a pending lock? */
+ else if (dwFileOffsetLow == PENDING_BYTE && nNumberOfBytesToLockLow == 1){
+ /* If no pending lock has been acquired, then acquire it */
+ if (pFile->shared->bPending == 0) {
+ pFile->shared->bPending = TRUE;
+ pFile->local.bPending = TRUE;
+ bReturn = TRUE;
+ }
+ }
+ /* Want a reserved lock? */
+ else if (dwFileOffsetLow == RESERVED_BYTE && nNumberOfBytesToLockLow == 1){
+ if (pFile->shared->bReserved == 0) {
+ pFile->shared->bReserved = TRUE;
+ pFile->local.bReserved = TRUE;
+ bReturn = TRUE;
+ }
+ }
+
+ winceMutexRelease(pFile->hMutex);
+ return bReturn;
+}
+
+/*
+** An implementation of the UnlockFile API of windows for wince
+*/
+static BOOL winceUnlockFile(
+ HANDLE *phFile,
+ DWORD dwFileOffsetLow,
+ DWORD dwFileOffsetHigh,
+ DWORD nNumberOfBytesToUnlockLow,
+ DWORD nNumberOfBytesToUnlockHigh
+){
+ winFile *pFile = HANDLE_TO_WINFILE(phFile);
+ BOOL bReturn = FALSE;
+
+ if (!pFile->hMutex) return TRUE;
+ winceMutexAcquire(pFile->hMutex);
+
+ /* Releasing a reader lock or an exclusive lock */
+ if (dwFileOffsetLow >= SHARED_FIRST &&
+ dwFileOffsetLow < SHARED_FIRST + SHARED_SIZE){
+ /* Did we have an exclusive lock? */
+ if (pFile->local.bExclusive){
+ pFile->local.bExclusive = FALSE;
+ pFile->shared->bExclusive = FALSE;
+ bReturn = TRUE;
+ }
+
+ /* Did we just have a reader lock? */
+ else if (pFile->local.nReaders){
+ pFile->local.nReaders --;
+ if (pFile->local.nReaders == 0)
+ {
+ pFile->shared->nReaders --;
+ }
+ bReturn = TRUE;
+ }
+ }
+
+ /* Releasing a pending lock */
+ else if (dwFileOffsetLow == PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){
+ if (pFile->local.bPending){
+ pFile->local.bPending = FALSE;
+ pFile->shared->bPending = FALSE;
+ bReturn = TRUE;
+ }
+ }
+ /* Releasing a reserved lock */
+ else if (dwFileOffsetLow == RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){
+ if (pFile->local.bReserved) {
+ pFile->local.bReserved = FALSE;
+ pFile->shared->bReserved = FALSE;
+ bReturn = TRUE;
+ }
+ }
+
+ winceMutexRelease(pFile->hMutex);
+ return bReturn;
+}
+
+/*
+** An implementation of the LockFileEx() API of windows for wince
+*/
+static BOOL winceLockFileEx(
+ HANDLE *phFile,
+ DWORD dwFlags,
+ DWORD dwReserved,
+ DWORD nNumberOfBytesToLockLow,
+ DWORD nNumberOfBytesToLockHigh,
+ LPOVERLAPPED lpOverlapped
+){
+ /* If the caller wants a shared read lock, forward this call
+ ** to winceLockFile */
+ if (lpOverlapped->Offset == SHARED_FIRST &&
+ dwFlags == 1 &&
+ nNumberOfBytesToLockLow == SHARED_SIZE){
+ return winceLockFile(phFile, SHARED_FIRST, 0, 1, 0);
+ }
+ return FALSE;
+}
+/*
+** End of the special code for wince
+*****************************************************************************/
+#endif /* OS_WINCE */
/*
-** Delete the named file
+** Delete the named file.
+**
+** Note that windows does not allow a file to be deleted if some other
+** process has it open. Sometimes a virus scanner or indexing program
+** will open a journal file shortly after it is created in order to do
+** whatever it is it does. While this other process is holding the
+** file open, we will be unable to delete it. To work around this
+** problem, we delay 100 milliseconds and try to delete again. Up
+** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
+** up and returning an error.
*/
-int sqlite3OsDelete(const char *zFilename){
+#define MX_DELETION_ATTEMPTS 3
+int sqlite3WinDelete(const char *zFilename){
WCHAR *zWide = utf8ToUnicode(zFilename);
+ int cnt = 0;
+ int rc;
if( zWide ){
- DeleteFileW(zWide);
+ do{
+ rc = DeleteFileW(zWide);
+ }while( rc==0 && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
sqliteFree(zWide);
}else{
- DeleteFileA(zFilename);
+#if OS_WINCE
+ return SQLITE_NOMEM;
+#else
+ do{
+ rc = DeleteFileA(zFilename);
+ }while( rc==0 && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
+#endif
}
TRACE2("DELETE \"%s\"\n", zFilename);
- return SQLITE_OK;
+ return rc==0 ? SQLITE_OK : SQLITE_IOERR;
}
/*
** Return TRUE if the named file exists.
*/
-int sqlite3OsFileExists(const char *zFilename){
+int sqlite3WinFileExists(const char *zFilename){
int exists = 0;
WCHAR *zWide = utf8ToUnicode(zFilename);
if( zWide ){
exists = GetFileAttributesW(zWide) != 0xffffffff;
sqliteFree(zWide);
}else{
+#if OS_WINCE
+ return SQLITE_NOMEM;
+#else
exists = GetFileAttributesA(zFilename) != 0xffffffff;
+#endif
}
return exists;
}
+/* Forward declaration */
+static int allocateWinFile(winFile *pInit, OsFile **pId);
+
/*
** Attempt to open a file for both reading and writing. If that
** fails, try opening it read-only. If the file does not exist,
@@ -166,14 +545,15 @@ int sqlite3OsFileExists(const char *zFilename){
** On failure, the function returns SQLITE_CANTOPEN and leaves
** *id and *pReadonly unchanged.
*/
-int sqlite3OsOpenReadWrite(
+int sqlite3WinOpenReadWrite(
const char *zFilename,
- OsFile *id,
+ OsFile **pId,
int *pReadonly
){
+ winFile f;
HANDLE h;
WCHAR *zWide = utf8ToUnicode(zFilename);
- assert( !id->isOpen );
+ assert( *pId==0 );
if( zWide ){
h = CreateFileW(zWide,
GENERIC_READ | GENERIC_WRITE,
@@ -186,7 +566,7 @@ int sqlite3OsOpenReadWrite(
if( h==INVALID_HANDLE_VALUE ){
h = CreateFileW(zWide,
GENERIC_READ,
- FILE_SHARE_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
@@ -200,8 +580,18 @@ int sqlite3OsOpenReadWrite(
}else{
*pReadonly = 0;
}
+#if OS_WINCE
+ if (!winceCreateLock(zFilename, &f)){
+ CloseHandle(h);
+ sqliteFree(zWide);
+ return SQLITE_CANTOPEN;
+ }
+#endif
sqliteFree(zWide);
}else{
+#if OS_WINCE
+ return SQLITE_NOMEM;
+#else
h = CreateFileA(zFilename,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
@@ -213,7 +603,7 @@ int sqlite3OsOpenReadWrite(
if( h==INVALID_HANDLE_VALUE ){
h = CreateFileA(zFilename,
GENERIC_READ,
- FILE_SHARE_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
@@ -226,14 +616,14 @@ int sqlite3OsOpenReadWrite(
}else{
*pReadonly = 0;
}
+#endif /* OS_WINCE */
}
- id->h = h;
- id->locktype = NO_LOCK;
- id->sharedLockByte = 0;
- id->isOpen = 1;
- OpenCounter(+1);
+ f.h = h;
+#if OS_WINCE
+ f.zDeleteOnClose = 0;
+#endif
TRACE3("OPEN R/W %d \"%s\"\n", h, zFilename);
- return SQLITE_OK;
+ return allocateWinFile(&f, pId);
}
@@ -250,48 +640,65 @@ int sqlite3OsOpenReadWrite(
** On success, write the file handle into *id and return SQLITE_OK.
**
** On failure, return SQLITE_CANTOPEN.
+**
+** Sometimes if we have just deleted a prior journal file, windows
+** will fail to open a new one because there is a "pending delete".
+** To work around this bug, we pause for 100 milliseconds and attempt
+** a second open after the first one fails. The whole operation only
+** fails if both open attempts are unsuccessful.
*/
-int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
+int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
+ winFile f;
HANDLE h;
int fileflags;
WCHAR *zWide = utf8ToUnicode(zFilename);
- assert( !id->isOpen );
+ assert( *pId == 0 );
+ fileflags = FILE_FLAG_RANDOM_ACCESS;
+#if !OS_WINCE
if( delFlag ){
- fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS
- | FILE_FLAG_DELETE_ON_CLOSE;
- }else{
- fileflags = FILE_FLAG_RANDOM_ACCESS;
+ fileflags |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE;
}
+#endif
if( zWide ){
- h = CreateFileW(zWide,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- CREATE_ALWAYS,
- fileflags,
- NULL
- );
+ int cnt = 0;
+ do{
+ h = CreateFileW(zWide,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ fileflags,
+ NULL
+ );
+ }while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) );
sqliteFree(zWide);
}else{
- h = CreateFileA(zFilename,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- CREATE_ALWAYS,
- fileflags,
- NULL
- );
+#if OS_WINCE
+ return SQLITE_NOMEM;
+#else
+ int cnt = 0;
+ do{
+ h = CreateFileA(zFilename,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ fileflags,
+ NULL
+ );
+ }while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) );
+#endif /* OS_WINCE */
}
if( h==INVALID_HANDLE_VALUE ){
return SQLITE_CANTOPEN;
}
- id->h = h;
- id->locktype = NO_LOCK;
- id->sharedLockByte = 0;
- id->isOpen = 1;
- OpenCounter(+1);
+ f.h = h;
+#if OS_WINCE
+ f.zDeleteOnClose = delFlag ? utf8ToUnicode(zFilename) : 0;
+ f.hMutex = NULL;
+#endif
TRACE3("OPEN EX %d \"%s\"\n", h, zFilename);
- return SQLITE_OK;
+ return allocateWinFile(&f, pId);
}
/*
@@ -301,10 +708,11 @@ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
**
** On failure, return SQLITE_CANTOPEN.
*/
-int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
+int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){
+ winFile f;
HANDLE h;
WCHAR *zWide = utf8ToUnicode(zFilename);
- assert( !id->isOpen );
+ assert( *pId==0 );
if( zWide ){
h = CreateFileW(zWide,
GENERIC_READ,
@@ -316,6 +724,9 @@ int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
);
sqliteFree(zWide);
}else{
+#if OS_WINCE
+ return SQLITE_NOMEM;
+#else
h = CreateFileA(zFilename,
GENERIC_READ,
0,
@@ -324,17 +735,18 @@ int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL
);
+#endif
}
if( h==INVALID_HANDLE_VALUE ){
return SQLITE_CANTOPEN;
}
- id->h = h;
- id->locktype = NO_LOCK;
- id->sharedLockByte = 0;
- id->isOpen = 1;
- OpenCounter(+1);
+ f.h = h;
+#if OS_WINCE
+ f.zDeleteOnClose = 0;
+ f.hMutex = NULL;
+#endif
TRACE3("OPEN RO %d \"%s\"\n", h, zFilename);
- return SQLITE_OK;
+ return allocateWinFile(&f, pId);
}
/*
@@ -353,9 +765,9 @@ int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
** On failure, the function returns SQLITE_CANTOPEN and leaves
** *id unchanged.
*/
-int sqlite3OsOpenDirectory(
- const char *zDirname,
- OsFile *id
+static int winOpenDirectory(
+ OsFile *id,
+ const char *zDirname
){
return SQLITE_OK;
}
@@ -371,7 +783,7 @@ char *sqlite3_temp_directory = 0;
** Create a temporary file name in zBuf. zBuf must be big enough to
** hold at least SQLITE_TEMPNAME_SIZE characters.
*/
-int sqlite3OsTempFileName(char *zBuf){
+int sqlite3WinTempFileName(char *zBuf){
static char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@@ -412,15 +824,36 @@ int sqlite3OsTempFileName(char *zBuf){
/*
** Close a file.
+**
+** It is reported that an attempt to close a handle might sometimes
+** fail. This is a very unreasonable result, but windows is notorious
+** for being unreasonable so I do not doubt that it might happen. If
+** the close fails, we pause for 100 milliseconds and try again. As
+** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before
+** giving up and returning an error.
*/
-int sqlite3OsClose(OsFile *id){
- if( id->isOpen ){
- TRACE2("CLOSE %d\n", id->h);
- CloseHandle(id->h);
+#define MX_CLOSE_ATTEMPT 3
+static int winClose(OsFile **pId){
+ winFile *pFile;
+ int rc = 1;
+ if( pId && (pFile = (winFile*)*pId)!=0 ){
+ int rc, cnt = 0;
+ TRACE2("CLOSE %d\n", pFile->h);
+ do{
+ rc = CloseHandle(pFile->h);
+ }while( rc==0 && cnt++ < MX_CLOSE_ATTEMPT && (Sleep(100), 1) );
+#if OS_WINCE
+ winceDestroyLock(pFile);
+ if( pFile->zDeleteOnClose ){
+ DeleteFileW(pFile->zDeleteOnClose);
+ sqliteFree(pFile->zDeleteOnClose);
+ }
+#endif
OpenCounter(-1);
- id->isOpen = 0;
+ sqliteFree(pFile);
+ *pId = 0;
}
- return SQLITE_OK;
+ return rc ? SQLITE_OK : SQLITE_IOERR;
}
/*
@@ -428,12 +861,12 @@ int sqlite3OsClose(OsFile *id){
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
-int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
+static int winRead(OsFile *id, void *pBuf, int amt){
DWORD got;
- assert( id->isOpen );
+ assert( id!=0 );
SimulateIOError(SQLITE_IOERR);
- TRACE3("READ %d lock=%d\n", id->h, id->locktype);
- if( !ReadFile(id->h, pBuf, amt, &got, 0) ){
+ TRACE3("READ %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
+ if( !ReadFile(((winFile*)id)->h, pBuf, amt, &got, 0) ){
got = 0;
}
if( got==(DWORD)amt ){
@@ -447,15 +880,16 @@ int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
** Write data from a buffer into a file. Return SQLITE_OK on success
** or some other error code on failure.
*/
-int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
+static int winWrite(OsFile *id, const void *pBuf, int amt){
int rc = 0;
DWORD wrote;
- assert( id->isOpen );
+ assert( id!=0 );
SimulateIOError(SQLITE_IOERR);
SimulateDiskfullError;
- TRACE3("WRITE %d lock=%d\n", id->h, id->locktype);
+ TRACE3("WRITE %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
assert( amt>0 );
- while( amt>0 && (rc = WriteFile(id->h, pBuf, amt, &wrote, 0))!=0 && wrote>0 ){
+ while( amt>0 && (rc = WriteFile(((winFile*)id)->h, pBuf, amt, &wrote, 0))!=0
+ && wrote>0 ){
amt -= wrote;
pBuf = &((char*)pBuf)[wrote];
}
@@ -475,17 +909,17 @@ int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
/*
** Move the read/write pointer in a file.
*/
-int sqlite3OsSeek(OsFile *id, i64 offset){
+static int winSeek(OsFile *id, i64 offset){
LONG upperBits = offset>>32;
LONG lowerBits = offset & 0xffffffff;
DWORD rc;
- assert( id->isOpen );
+ assert( id!=0 );
#ifdef SQLITE_TEST
if( offset ) SimulateDiskfullError
#endif
SEEK(offset/1024 + 1);
- rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN);
- TRACE3("SEEK %d %lld\n", id->h, offset);
+ rc = SetFilePointer(((winFile*)id)->h, lowerBits, &upperBits, FILE_BEGIN);
+ TRACE3("SEEK %d %lld\n", ((winFile*)id)->h, offset);
if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){
return SQLITE_FULL;
}
@@ -495,10 +929,10 @@ int sqlite3OsSeek(OsFile *id, i64 offset){
/*
** Make sure all writes to a particular file are committed to disk.
*/
-int sqlite3OsSync(OsFile *id, int dataOnly){
- assert( id->isOpen );
- TRACE3("SYNC %d lock=%d\n", id->h, id->locktype);
- if( FlushFileBuffers(id->h) ){
+static int winSync(OsFile *id, int dataOnly){
+ assert( id!=0 );
+ TRACE3("SYNC %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
+ if( FlushFileBuffers(((winFile*)id)->h) ){
return SQLITE_OK;
}else{
return SQLITE_IOERR;
@@ -509,7 +943,7 @@ int sqlite3OsSync(OsFile *id, int dataOnly){
** Sync the directory zDirname. This is a no-op on operating systems other
** than UNIX.
*/
-int sqlite3OsSyncDirectory(const char *zDirname){
+int sqlite3WinSyncDirectory(const char *zDirname){
SimulateIOError(SQLITE_IOERR);
return SQLITE_OK;
}
@@ -517,34 +951,41 @@ int sqlite3OsSyncDirectory(const char *zDirname){
/*
** Truncate an open file to a specified size
*/
-int sqlite3OsTruncate(OsFile *id, i64 nByte){
+static int winTruncate(OsFile *id, i64 nByte){
LONG upperBits = nByte>>32;
- assert( id->isOpen );
- TRACE3("TRUNCATE %d %lld\n", id->h, nByte);
+ assert( id!=0 );
+ TRACE3("TRUNCATE %d %lld\n", ((winFile*)id)->h, nByte);
SimulateIOError(SQLITE_IOERR);
- SetFilePointer(id->h, nByte, &upperBits, FILE_BEGIN);
- SetEndOfFile(id->h);
+ SetFilePointer(((winFile*)id)->h, nByte, &upperBits, FILE_BEGIN);
+ SetEndOfFile(((winFile*)id)->h);
return SQLITE_OK;
}
/*
** Determine the current size of a file in bytes
*/
-int sqlite3OsFileSize(OsFile *id, i64 *pSize){
+static int winFileSize(OsFile *id, i64 *pSize){
DWORD upperBits, lowerBits;
- assert( id->isOpen );
+ assert( id!=0 );
SimulateIOError(SQLITE_IOERR);
- lowerBits = GetFileSize(id->h, &upperBits);
+ lowerBits = GetFileSize(((winFile*)id)->h, &upperBits);
*pSize = (((i64)upperBits)<<32) + lowerBits;
return SQLITE_OK;
}
/*
+** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems.
+*/
+#ifndef LOCKFILE_FAIL_IMMEDIATELY
+# define LOCKFILE_FAIL_IMMEDIATELY 1
+#endif
+
+/*
** Acquire a reader lock.
** Different API routines are called depending on whether or not this
** is Win95 or WinNT.
*/
-static int getReadLock(OsFile *id){
+static int getReadLock(winFile *id){
int res;
if( isNT() ){
OVERLAPPED ovlp;
@@ -564,12 +1005,12 @@ static int getReadLock(OsFile *id){
/*
** Undo a readlock
*/
-static int unlockReadLock(OsFile *id){
+static int unlockReadLock(winFile *pFile){
int res;
if( isNT() ){
- res = UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
+ res = UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
}else{
- res = UnlockFile(id->h, SHARED_FIRST + id->sharedLockByte, 0, 1, 0);
+ res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0);
}
return res;
}
@@ -579,7 +1020,7 @@ static int unlockReadLock(OsFile *id){
** Check that a given pathname is a directory and is writable
**
*/
-int sqlite3OsIsDirWritable(char *zDirname){
+int sqlite3WinIsDirWritable(char *zDirname){
int fileAttr;
WCHAR *zWide;
if( zDirname==0 ) return 0;
@@ -589,7 +1030,11 @@ int sqlite3OsIsDirWritable(char *zDirname){
fileAttr = GetFileAttributesW(zWide);
sqliteFree(zWide);
}else{
+#if OS_WINCE
+ return 0;
+#else
fileAttr = GetFileAttributesA(zDirname);
+#endif
}
if( fileAttr == 0xffffffff ) return 0;
if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){
@@ -620,45 +1065,46 @@ int sqlite3OsIsDirWritable(char *zDirname){
** RESERVED -> (PENDING) -> EXCLUSIVE
** PENDING -> EXCLUSIVE
**
-** This routine will only increase a lock. The sqlite3OsUnlock() routine
+** This routine will only increase a lock. The winUnlock() routine
** erases all locks at once and returns us immediately to locking level 0.
** It is not possible to lower the locking level one step at a time. You
** must go straight to locking level 0.
*/
-int sqlite3OsLock(OsFile *id, int locktype){
+static int winLock(OsFile *id, int locktype){
int rc = SQLITE_OK; /* Return code from subroutines */
int res = 1; /* Result of a windows lock call */
int newLocktype; /* Set id->locktype to this value before exiting */
int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
+ winFile *pFile = (winFile*)id;
- assert( id->isOpen );
+ assert( pFile!=0 );
TRACE5("LOCK %d %d was %d(%d)\n",
- id->h, locktype, id->locktype, id->sharedLockByte);
+ pFile->h, locktype, pFile->locktype, pFile->sharedLockByte);
/* If there is already a lock of this type or more restrictive on the
** OsFile, do nothing. Don't use the end_lock: exit path, as
** sqlite3OsEnterMutex() hasn't been called yet.
*/
- if( id->locktype>=locktype ){
+ if( pFile->locktype>=locktype ){
return SQLITE_OK;
}
/* Make sure the locking sequence is correct
*/
- assert( id->locktype!=NO_LOCK || locktype==SHARED_LOCK );
+ assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
assert( locktype!=PENDING_LOCK );
- assert( locktype!=RESERVED_LOCK || id->locktype==SHARED_LOCK );
+ assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
/* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
** the PENDING_LOCK byte is temporary.
*/
- newLocktype = id->locktype;
- if( id->locktype==NO_LOCK
- || (locktype==EXCLUSIVE_LOCK && id->locktype==RESERVED_LOCK)
+ newLocktype = pFile->locktype;
+ if( pFile->locktype==NO_LOCK
+ || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK)
){
int cnt = 3;
- while( cnt-->0 && (res = LockFile(id->h, PENDING_BYTE, 0, 1, 0))==0 ){
+ while( cnt-->0 && (res = LockFile(pFile->h, PENDING_BYTE, 0, 1, 0))==0 ){
/* Try 3 times to get the pending lock. The pending lock might be
** held by another reader process who will release it momentarily.
*/
@@ -671,8 +1117,8 @@ int sqlite3OsLock(OsFile *id, int locktype){
/* Acquire a shared lock
*/
if( locktype==SHARED_LOCK && res ){
- assert( id->locktype==NO_LOCK );
- res = getReadLock(id);
+ assert( pFile->locktype==NO_LOCK );
+ res = getReadLock(pFile);
if( res ){
newLocktype = SHARED_LOCK;
}
@@ -681,8 +1127,8 @@ int sqlite3OsLock(OsFile *id, int locktype){
/* Acquire a RESERVED lock
*/
if( locktype==RESERVED_LOCK && res ){
- assert( id->locktype==SHARED_LOCK );
- res = LockFile(id->h, RESERVED_BYTE, 0, 1, 0);
+ assert( pFile->locktype==SHARED_LOCK );
+ res = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
if( res ){
newLocktype = RESERVED_LOCK;
}
@@ -698,10 +1144,10 @@ int sqlite3OsLock(OsFile *id, int locktype){
/* Acquire an EXCLUSIVE lock
*/
if( locktype==EXCLUSIVE_LOCK && res ){
- assert( id->locktype>=SHARED_LOCK );
- res = unlockReadLock(id);
+ assert( pFile->locktype>=SHARED_LOCK );
+ res = unlockReadLock(pFile);
TRACE2("unreadlock = %d\n", res);
- res = LockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
+ res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
if( res ){
newLocktype = EXCLUSIVE_LOCK;
}else{
@@ -713,7 +1159,7 @@ int sqlite3OsLock(OsFile *id, int locktype){
** release it now.
*/
if( gotPendingLock && locktype==SHARED_LOCK ){
- UnlockFile(id->h, PENDING_BYTE, 0, 1, 0);
+ UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
}
/* Update the state of the lock has held in the file descriptor then
@@ -722,11 +1168,11 @@ int sqlite3OsLock(OsFile *id, int locktype){
if( res ){
rc = SQLITE_OK;
}else{
- TRACE4("LOCK FAILED %d trying for %d but got %d\n", id->h,
+ TRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
locktype, newLocktype);
rc = SQLITE_BUSY;
}
- id->locktype = newLocktype;
+ pFile->locktype = newLocktype;
return rc;
}
@@ -735,19 +1181,20 @@ int sqlite3OsLock(OsFile *id, int locktype){
** file by this or any other process. If such a lock is held, return
** non-zero, otherwise zero.
*/
-int sqlite3OsCheckReservedLock(OsFile *id){
+static int winCheckReservedLock(OsFile *id){
int rc;
- assert( id->isOpen );
- if( id->locktype>=RESERVED_LOCK ){
+ winFile *pFile = (winFile*)id;
+ assert( pFile!=0 );
+ if( pFile->locktype>=RESERVED_LOCK ){
rc = 1;
- TRACE3("TEST WR-LOCK %d %d (local)\n", id->h, rc);
+ TRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc);
}else{
- rc = LockFile(id->h, RESERVED_BYTE, 0, 1, 0);
+ rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
if( rc ){
- UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0);
+ UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
}
rc = !rc;
- TRACE3("TEST WR-LOCK %d %d (remote)\n", id->h, rc);
+ TRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc);
}
return rc;
}
@@ -763,32 +1210,33 @@ int sqlite3OsCheckReservedLock(OsFile *id){
** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
** might return SQLITE_IOERR;
*/
-int sqlite3OsUnlock(OsFile *id, int locktype){
+static int winUnlock(OsFile *id, int locktype){
int type;
int rc = SQLITE_OK;
- assert( id->isOpen );
+ winFile *pFile = (winFile*)id;
+ assert( pFile!=0 );
assert( locktype<=SHARED_LOCK );
- TRACE5("UNLOCK %d to %d was %d(%d)\n", id->h, locktype,
- id->locktype, id->sharedLockByte);
- type = id->locktype;
+ TRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
+ pFile->locktype, pFile->sharedLockByte);
+ type = pFile->locktype;
if( type>=EXCLUSIVE_LOCK ){
- UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
- if( locktype==SHARED_LOCK && !getReadLock(id) ){
+ UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
+ if( locktype==SHARED_LOCK && !getReadLock(pFile) ){
/* This should never happen. We should always be able to
** reacquire the read lock */
rc = SQLITE_IOERR;
}
}
if( type>=RESERVED_LOCK ){
- UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0);
+ UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
}
if( locktype==NO_LOCK && type>=SHARED_LOCK ){
- unlockReadLock(id);
+ unlockReadLock(pFile);
}
if( type>=PENDING_LOCK ){
- UnlockFile(id->h, PENDING_BYTE, 0, 1, 0);
+ UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
}
- id->locktype = locktype;
+ pFile->locktype = locktype;
return rc;
}
@@ -798,17 +1246,21 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
** The calling function is responsible for freeing this space once it
** is no longer needed.
*/
-char *sqlite3OsFullPathname(const char *zRelative){
- char *zNotUsed;
+char *sqlite3WinFullPathname(const char *zRelative){
char *zFull;
- WCHAR *zWide;
+#if defined(__CYGWIN__)
int nByte;
-#ifdef __CYGWIN__
nByte = strlen(zRelative) + MAX_PATH + 1001;
zFull = sqliteMalloc( nByte );
if( zFull==0 ) return 0;
if( cygwin_conv_to_full_win32_path(zRelative, zFull) ) return 0;
+#elif OS_WINCE
+ /* WinCE has no concept of a relative pathname, or so I am told. */
+ zFull = sqliteStrDup(zRelative);
#else
+ char *zNotUsed;
+ WCHAR *zWide;
+ int nByte;
zWide = utf8ToUnicode(zRelative);
if( zWide ){
WCHAR *zTemp, *zNotUsedW;
@@ -829,6 +1281,76 @@ char *sqlite3OsFullPathname(const char *zRelative){
return zFull;
}
+/*
+** The fullSync option is meaningless on windows. This is a no-op.
+*/
+static void winSetFullSync(OsFile *id, int v){
+ return;
+}
+
+/*
+** Return the underlying file handle for an OsFile
+*/
+static int winFileHandle(OsFile *id){
+ return (int)((winFile*)id)->h;
+}
+
+/*
+** Return an integer that indices the type of lock currently held
+** by this handle. (Used for testing and analysis only.)
+*/
+static int winLockState(OsFile *id){
+ return ((winFile*)id)->locktype;
+}
+
+/*
+** This vector defines all the methods that can operate on an OsFile
+** for win32.
+*/
+static const IoMethod sqlite3WinIoMethod = {
+ winClose,
+ winOpenDirectory,
+ winRead,
+ winWrite,
+ winSeek,
+ winTruncate,
+ winSync,
+ winSetFullSync,
+ winFileHandle,
+ winFileSize,
+ winLock,
+ winUnlock,
+ winLockState,
+ winCheckReservedLock,
+};
+
+/*
+** Allocate memory for an OsFile. Initialize the new OsFile
+** to the value given in pInit and return a pointer to the new
+** OsFile. If we run out of memory, close the file and return NULL.
+*/
+static int allocateWinFile(winFile *pInit, OsFile **pId){
+ winFile *pNew;
+ pNew = sqliteMalloc( sizeof(*pNew) );
+ if( pNew==0 ){
+ CloseHandle(pInit->h);
+#if OS_WINCE
+ sqliteFree(pInit->zDeleteOnClose);
+#endif
+ *pId = 0;
+ return SQLITE_NOMEM;
+ }else{
+ *pNew = *pInit;
+ pNew->pMethod = &sqlite3WinIoMethod;
+ pNew->locktype = NO_LOCK;
+ pNew->sharedLockByte = 0;
+ *pId = (OsFile*)pNew;
+ OpenCounter(+1);
+ return SQLITE_OK;
+ }
+}
+
+
#endif /* SQLITE_OMIT_DISKIO */
/***************************************************************************
** Everything above deals with file I/O. Everything that follows deals
@@ -840,7 +1362,7 @@ char *sqlite3OsFullPathname(const char *zRelative){
** is written into the buffer zBuf[256]. The calling function must
** supply a sufficiently large buffer.
*/
-int sqlite3OsRandomSeed(char *zBuf){
+int sqlite3WinRandomSeed(char *zBuf){
/* We have to initialize zBuf to prevent valgrind from reporting
** errors. The reports issued by valgrind are incorrect - we would
** prefer that the randomness be increased by making use of the
@@ -861,7 +1383,7 @@ int sqlite3OsRandomSeed(char *zBuf){
/*
** Sleep for a little while. Return the amount of time slept.
*/
-int sqlite3OsSleep(int ms){
+int sqlite3WinSleep(int ms){
Sleep(ms);
return ms;
}
@@ -871,18 +1393,22 @@ int sqlite3OsSleep(int ms){
*/
static int inMutex = 0;
#ifdef SQLITE_W32_THREADS
+ static DWORD mutexOwner;
static CRITICAL_SECTION cs;
#endif
/*
-** The following pair of routine implement mutual exclusion for
+** The following pair of routines implement mutual exclusion for
** multi-threaded processes. Only a single thread is allowed to
** executed code that is surrounded by EnterMutex() and LeaveMutex().
**
** SQLite uses only a single Mutex. There is not much critical
** code and what little there is executes quickly and without blocking.
+**
+** Version 3.3.1 and earlier used a simple mutex. Beginning with
+** version 3.3.2, a recursive mutex is required.
*/
-void sqlite3OsEnterMutex(){
+void sqlite3WinEnterMutex(){
#ifdef SQLITE_W32_THREADS
static int isInit = 0;
while( !isInit ){
@@ -895,19 +1421,36 @@ void sqlite3OsEnterMutex(){
}
}
EnterCriticalSection(&cs);
+ mutexOwner = GetCurrentThreadId();
#endif
- assert( !inMutex );
- inMutex = 1;
+ inMutex++;
}
-void sqlite3OsLeaveMutex(){
+void sqlite3WinLeaveMutex(){
assert( inMutex );
- inMutex = 0;
+ inMutex--;
#ifdef SQLITE_W32_THREADS
+ assert( mutexOwner==GetCurrentThreadId() );
LeaveCriticalSection(&cs);
#endif
}
/*
+** Return TRUE if the mutex is currently held.
+**
+** If the thisThreadOnly parameter is true, return true if and only if the
+** calling thread holds the mutex. If the parameter is false, return
+** true if any thread holds the mutex.
+*/
+int sqlite3WinInMutex(int thisThreadOnly){
+#ifdef SQLITE_W32_THREADS
+ return inMutex>0 && (thisThreadOnly==0 || mutexOwner==GetCurrentThreadId());
+#else
+ return inMutex>0;
+#endif
+}
+
+
+/*
** The following variable, if set to a non-zero value, becomes the result
** returned from sqlite3OsCurrentTime(). This is used for testing.
*/
@@ -920,13 +1463,19 @@ int sqlite3_current_time = 0;
** current time and date as a Julian Day number into *prNow and
** return 0. Return 1 if the time and date cannot be found.
*/
-int sqlite3OsCurrentTime(double *prNow){
+int sqlite3WinCurrentTime(double *prNow){
FILETIME ft;
/* FILETIME structure is a 64-bit value representing the number of
100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
*/
double now;
+#if OS_WINCE
+ SYSTEMTIME time;
+ GetSystemTime(&time);
+ SystemTimeToFileTime(&time,&ft);
+#else
GetSystemTimeAsFileTime( &ft );
+#endif
now = ((double)ft.dwHighDateTime) * 4294967296.0;
*prNow = (now + ft.dwLowDateTime)/864000000000.0 + 2305813.5;
#ifdef SQLITE_TEST
@@ -937,4 +1486,71 @@ int sqlite3OsCurrentTime(double *prNow){
return 0;
}
+/*
+** Remember the number of thread-specific-data blocks allocated.
+** Use this to verify that we are not leaking thread-specific-data.
+** Ticket #1601
+*/
+#ifdef SQLITE_TEST
+int sqlite3_tsd_count = 0;
+# define TSD_COUNTER_INCR InterlockedIncrement(&sqlite3_tsd_count)
+# define TSD_COUNTER_DECR InterlockedDecrement(&sqlite3_tsd_count)
+#else
+# define TSD_COUNTER_INCR /* no-op */
+# define TSD_COUNTER_DECR /* no-op */
+#endif
+
+
+
+/*
+** If called with allocateFlag>1, then return a pointer to thread
+** specific data for the current thread. Allocate and zero the
+** thread-specific data if it does not already exist necessary.
+**
+** If called with allocateFlag==0, then check the current thread
+** specific data. Return it if it exists. If it does not exist,
+** then return NULL.
+**
+** If called with allocateFlag<0, check to see if the thread specific
+** data is allocated and is all zero. If it is then deallocate it.
+** Return a pointer to the thread specific data or NULL if it is
+** unallocated or gets deallocated.
+*/
+ThreadData *sqlite3WinThreadSpecificData(int allocateFlag){
+ static int key;
+ static int keyInit = 0;
+ static const ThreadData zeroData = {0};
+ ThreadData *pTsd;
+
+ if( !keyInit ){
+ sqlite3OsEnterMutex();
+ if( !keyInit ){
+ key = TlsAlloc();
+ if( key==0xffffffff ){
+ sqlite3OsLeaveMutex();
+ return 0;
+ }
+ keyInit = 1;
+ }
+ sqlite3OsLeaveMutex();
+ }
+ pTsd = TlsGetValue(key);
+ if( allocateFlag>0 ){
+ if( !pTsd ){
+ pTsd = sqlite3OsMalloc( sizeof(zeroData) );
+ if( pTsd ){
+ *pTsd = zeroData;
+ TlsSetValue(key, pTsd);
+ TSD_COUNTER_INCR;
+ }
+ }
+ }else if( pTsd!=0 && allocateFlag<0
+ && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){
+ sqlite3OsFree(pTsd);
+ TlsSetValue(key, 0);
+ TSD_COUNTER_DECR;
+ pTsd = 0;
+ }
+ return pTsd;
+}
#endif /* OS_WIN */
diff --git a/ext/pdo_sqlite/sqlite/src/pager.c b/ext/pdo_sqlite/sqlite/src/pager.c
index f06d3fec6c..7f4b6f952f 100644
--- a/ext/pdo_sqlite/sqlite/src/pager.c
+++ b/ext/pdo_sqlite/sqlite/src/pager.c
@@ -46,21 +46,14 @@
/*
** The following two macros are used within the TRACEX() macros above
-** to print out file-descriptors. They are required so that tracing
-** can be turned on when using both the regular os_unix.c and os_test.c
-** backends.
+** to print out file-descriptors.
**
** PAGERID() takes a pointer to a Pager struct as it's argument. The
** associated file-descriptor is returned. FILEHANDLEID() takes an OsFile
** struct as it's argument.
*/
-#ifdef OS_TEST
-#define PAGERID(p) (p->fd->fd.h)
-#define FILEHANDLEID(fd) (fd->fd.h)
-#else
-#define PAGERID(p) (p->fd.h)
-#define FILEHANDLEID(fd) (fd.h)
-#endif
+#define PAGERID(p) ((int)(p->fd))
+#define FILEHANDLEID(fd) ((int)fd)
/*
** The page cache as a whole is always in one of the following
@@ -168,7 +161,8 @@ struct PgHdr {
u8 needSync; /* Sync journal before writing this page */
u8 alwaysRollback; /* Disable dont_rollback() for this page */
short int nRef; /* Number of users of this page */
- PgHdr *pDirty; /* Dirty pages sorted by PgHdr.pgno */
+ PgHdr *pDirty, *pPrevDirty; /* Dirty pages */
+ u32 notUsed; /* Buffer space */
#ifdef SQLITE_CHECK_PAGES
u32 pageHash;
#endif
@@ -197,9 +191,11 @@ struct PgHistory {
** A macro used for invoking the codec if there is one
*/
#ifdef SQLITE_HAS_CODEC
-# define CODEC(P,D,N,X) if( P->xCodec ){ P->xCodec(P->pCodecArg,D,N,X); }
+# define CODEC1(P,D,N,X) if( P->xCodec!=0 ){ P->xCodec(P->pCodecArg,D,N,X); }
+# define CODEC2(P,D,N,X) ((char*)(P->xCodec!=0?P->xCodec(P->pCodecArg,D,N,X):D))
#else
-# define CODEC(P,D,N,X)
+# define CODEC1(P,D,N,X) /* NO-OP */
+# define CODEC2(P,D,N,X) ((char*)D)
#endif
/*
@@ -213,25 +209,15 @@ struct PgHistory {
((PgHistory*)&((char*)(&(P)[1]))[(PGR)->pageSize+(PGR)->nExtra])
/*
-** How big to make the hash table used for locating in-memory pages
-** by page number. This macro looks a little silly, but is evaluated
-** at compile-time, not run-time (at least for gcc this is true).
-*/
-#define N_PG_HASH (\
- (MAX_PAGES>1024)?2048: \
- (MAX_PAGES>512)?1024: \
- (MAX_PAGES>256)?512: \
- (MAX_PAGES>128)?256: \
- (MAX_PAGES>64)?128:64 \
-)
-
-/*
-** Hash a page number
-*/
-#define pager_hash(PN) ((PN)&(N_PG_HASH-1))
-
-/*
** A open page cache is an instance of the following structure.
+**
+** Pager.errCode may be set to SQLITE_IOERR, SQLITE_CORRUPT, SQLITE_PROTOCOL
+** or SQLITE_FULL. Once one of the first three errors occurs, it persists
+** and is returned as the result of every major pager API call. The
+** SQLITE_FULL return code is slightly different. It persists only until the
+** next successful rollback is performed on the pager cache. Also,
+** SQLITE_FULL does not affect the sqlite3pager_get() and sqlite3pager_lookup()
+** APIs, they may still be used successfully.
*/
struct Pager {
u8 journalOpen; /* True if journal file descriptors is valid */
@@ -243,8 +229,9 @@ struct Pager {
u8 stmtAutoopen; /* Open stmt journal when main journal is opened*/
u8 noSync; /* Do not sync the journal if true */
u8 fullSync; /* Do extra syncs of the journal for robustness */
+ u8 full_fsync; /* Use F_FULLFSYNC when available */
u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */
- u8 errMask; /* One of several kinds of errors */
+ u8 errCode; /* One of several kinds of errors */
u8 tempFile; /* zFilename is a temporary file */
u8 readOnly; /* True for a read-only database */
u8 needSync; /* True if an fsync() is needed on the journal */
@@ -269,13 +256,14 @@ struct Pager {
char *zFilename; /* Name of the database file */
char *zJournal; /* Name of the journal file */
char *zDirectory; /* Directory hold database and journal files */
- OsFile fd, jfd; /* File descriptors for database and journal */
- OsFile stfd; /* File descriptor for the statement subjournal*/
+ OsFile *fd, *jfd; /* File descriptors for database and journal */
+ OsFile *stfd; /* File descriptor for the statement subjournal*/
BusyHandler *pBusyHandler; /* Pointer to sqlite.busyHandler */
PgHdr *pFirst, *pLast; /* List of free pages */
PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */
PgHdr *pAll; /* List of all pages */
PgHdr *pStmt; /* List of pages in the statement subjournal */
+ PgHdr *pDirty; /* List of all dirty pages */
i64 journalOff; /* Current byte offset in the journal file */
i64 journalHdr; /* Byte offset to previous journal header */
i64 stmtHdrOff; /* First journal header written this statement */
@@ -288,9 +276,13 @@ struct Pager {
#endif
void (*xDestructor)(void*,int); /* Call this routine when freeing pages */
void (*xReiniter)(void*,int); /* Call this routine when reloading pages */
- void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
+ void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
void *pCodecArg; /* First argument to xCodec() */
- PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number to PgHdr */
+ int nHash; /* Size of the pager hash table */
+ PgHdr **aHash; /* Hash table to map page number to PgHdr */
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ Pager *pNext; /* Linked list of pagers in this thread */
+#endif
};
/*
@@ -304,15 +296,6 @@ struct Pager {
#endif
/*
-** These are bits that can be set in Pager.errMask.
-*/
-#define PAGER_ERR_FULL 0x01 /* a write() failed */
-#define PAGER_ERR_MEM 0x02 /* malloc() failed */
-#define PAGER_ERR_LOCK 0x04 /* error in the locking protocol */
-#define PAGER_ERR_CORRUPT 0x08 /* database or journal corruption */
-#define PAGER_ERR_DISK 0x10 /* general disk I/O error - bad hard drive? */
-
-/*
** Journal files begin with the following magic string. The data
** was obtained from /dev/random. It is used only as a sanity check.
**
@@ -387,7 +370,7 @@ static const unsigned char aJournalMagic[] = {
/*
** Enable reference count tracking (for debugging) here:
*/
-#ifdef SQLITE_DEBUG
+#ifdef SQLITE_TEST
int pager3_refinfo_enable = 0;
static void pager_refinfo(PgHdr *p){
static int cnt = 0;
@@ -403,6 +386,38 @@ static const unsigned char aJournalMagic[] = {
# define REFINFO(X)
#endif
+
+/*
+** Change the size of the pager hash table to N. N must be a power
+** of two.
+*/
+static void pager_resize_hash_table(Pager *pPager, int N){
+ PgHdr **aHash, *pPg;
+ assert( N>0 && (N&(N-1))==0 );
+ aHash = sqliteMalloc( sizeof(aHash[0])*N );
+ if( aHash==0 ){
+ /* Failure to rehash is not an error. It is only a performance hit. */
+ return;
+ }
+ sqliteFree(pPager->aHash);
+ pPager->nHash = N;
+ pPager->aHash = aHash;
+ for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
+ int h;
+ if( pPg->pgno==0 ){
+ assert( pPg->pNextHash==0 && pPg->pPrevHash==0 );
+ continue;
+ }
+ h = pPg->pgno & (N-1);
+ pPg->pNextHash = aHash[h];
+ if( aHash[h] ){
+ aHash[h]->pPrevHash = pPg;
+ }
+ aHash[h] = pPg;
+ pPg->pPrevHash = 0;
+ }
+}
+
/*
** Read a 32-bit integer from the given file descriptor. Store the integer
** that is read in *pRes. Return SQLITE_OK if everything worked, or an
@@ -411,42 +426,32 @@ static const unsigned char aJournalMagic[] = {
** All values are stored on disk as big-endian.
*/
static int read32bits(OsFile *fd, u32 *pRes){
- u32 res;
- int rc;
- rc = sqlite3OsRead(fd, &res, sizeof(res));
+ unsigned char ac[4];
+ int rc = sqlite3OsRead(fd, ac, sizeof(ac));
if( rc==SQLITE_OK ){
- unsigned char ac[4];
- memcpy(ac, &res, 4);
- res = (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3];
+ *pRes = (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3];
}
- *pRes = res;
return rc;
}
/*
-** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK
-** on success or an error code is something goes wrong.
+** Write a 32-bit integer into a string buffer in big-endian byte order.
*/
-static int write32bits(OsFile *fd, u32 val){
- unsigned char ac[4];
+static void put32bits(char *ac, u32 val){
ac[0] = (val>>24) & 0xff;
ac[1] = (val>>16) & 0xff;
ac[2] = (val>>8) & 0xff;
ac[3] = val & 0xff;
- return sqlite3OsWrite(fd, ac, 4);
}
/*
-** Write the 32-bit integer 'val' into the page identified by page header
-** 'p' at offset 'offset'.
+** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK
+** on success or an error code is something goes wrong.
*/
-static void store32bits(u32 val, PgHdr *p, int offset){
- unsigned char *ac;
- ac = &((unsigned char*)PGHDR_TO_DATA(p))[offset];
- ac[0] = (val>>24) & 0xff;
- ac[1] = (val>>16) & 0xff;
- ac[2] = (val>>8) & 0xff;
- ac[3] = val & 0xff;
+static int write32bits(OsFile *fd, u32 val){
+ char ac[4];
+ put32bits(ac, val);
+ return sqlite3OsWrite(fd, ac, 4);
}
/*
@@ -461,16 +466,25 @@ static u32 retrieve32bits(PgHdr *p, int offset){
/*
-** Convert the bits in the pPager->errMask into an approprate
-** return code.
+** This function should be called when an error occurs within the pager
+** code. The first argument is a pointer to the pager structure, the
+** second the error-code about to be returned by a pager API function.
+** The value returned is a copy of the second argument to this function.
+**
+** If the second argument is SQLITE_IOERR, SQLITE_CORRUPT or SQLITE_PROTOCOL,
+** the error becomes persistent. All subsequent API calls on this Pager
+** will immediately return the same error code.
*/
-static int pager_errcode(Pager *pPager){
- int rc = SQLITE_OK;
- if( pPager->errMask & PAGER_ERR_LOCK ) rc = SQLITE_PROTOCOL;
- if( pPager->errMask & PAGER_ERR_DISK ) rc = SQLITE_IOERR;
- if( pPager->errMask & PAGER_ERR_FULL ) rc = SQLITE_FULL;
- if( pPager->errMask & PAGER_ERR_MEM ) rc = SQLITE_NOMEM;
- if( pPager->errMask & PAGER_ERR_CORRUPT ) rc = SQLITE_CORRUPT;
+static int pager_error(Pager *pPager, int rc){
+ assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK );
+ if(
+ rc==SQLITE_FULL ||
+ rc==SQLITE_IOERR ||
+ rc==SQLITE_CORRUPT ||
+ rc==SQLITE_PROTOCOL
+ ){
+ pPager->errCode = rc;
+ }
return rc;
}
@@ -496,7 +510,7 @@ static u32 pager_pagehash(PgHdr *pPage){
#define CHECK_PAGE(x) checkPage(x)
static void checkPage(PgHdr *pPg){
Pager *pPager = pPg->pPager;
- assert( !pPg->pageHash || pPager->errMask || MEMDB || pPg->dirty ||
+ assert( !pPg->pageHash || pPager->errCode || MEMDB || pPg->dirty ||
pPg->pageHash==pager_pagehash(pPg) );
}
@@ -597,7 +611,7 @@ static int seekJournalHdr(Pager *pPager){
assert( offset>=c );
assert( (offset-c)<JOURNAL_HDR_SZ(pPager) );
pPager->journalOff = offset;
- return sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
+ return sqlite3OsSeek(pPager->jfd, pPager->journalOff);
}
/*
@@ -615,6 +629,7 @@ static int seekJournalHdr(Pager *pPager){
** Followed by (JOURNAL_HDR_SZ - 24) bytes of unused space.
*/
static int writeJournalHdr(Pager *pPager){
+ char zHeader[sizeof(aJournalMagic)+16];
int rc = seekJournalHdr(pPager);
if( rc ) return rc;
@@ -633,33 +648,25 @@ static int writeJournalHdr(Pager *pPager){
** Actually maybe the whole journal header should be delayed until that
** point. Think about this.
*/
- rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
-
- if( rc==SQLITE_OK ){
- /* The nRec Field. 0xFFFFFFFF for no-sync journals. */
- rc = write32bits(&pPager->jfd, pPager->noSync ? 0xffffffff : 0);
- }
- if( rc==SQLITE_OK ){
- /* The random check-hash initialiser */
- sqlite3Randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
- rc = write32bits(&pPager->jfd, pPager->cksumInit);
- }
- if( rc==SQLITE_OK ){
- /* The initial database size */
- rc = write32bits(&pPager->jfd, pPager->dbSize);
- }
- if( rc==SQLITE_OK ){
- /* The assumed sector size for this process */
- rc = write32bits(&pPager->jfd, pPager->sectorSize);
- }
+ memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
+ /* The nRec Field. 0xFFFFFFFF for no-sync journals. */
+ put32bits(&zHeader[sizeof(aJournalMagic)], pPager->noSync ? 0xffffffff : 0);
+ /* The random check-hash initialiser */
+ sqlite3Randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
+ put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit);
+ /* The initial database size */
+ put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbSize);
+ /* The assumed sector size for this process */
+ put32bits(&zHeader[sizeof(aJournalMagic)+12], pPager->sectorSize);
+ rc = sqlite3OsWrite(pPager->jfd, zHeader, sizeof(zHeader));
/* The journal header has been written successfully. Seek the journal
** file descriptor to the end of the journal header sector.
*/
if( rc==SQLITE_OK ){
- rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff-1);
+ rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff-1);
if( rc==SQLITE_OK ){
- rc = sqlite3OsWrite(&pPager->jfd, "\000", 1);
+ rc = sqlite3OsWrite(pPager->jfd, "\000", 1);
}
}
return rc;
@@ -697,20 +704,20 @@ static int readJournalHdr(
return SQLITE_DONE;
}
- rc = sqlite3OsRead(&pPager->jfd, aMagic, sizeof(aMagic));
+ rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic));
if( rc ) return rc;
if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){
return SQLITE_DONE;
}
- rc = read32bits(&pPager->jfd, pNRec);
+ rc = read32bits(pPager->jfd, pNRec);
if( rc ) return rc;
- rc = read32bits(&pPager->jfd, &pPager->cksumInit);
+ rc = read32bits(pPager->jfd, &pPager->cksumInit);
if( rc ) return rc;
- rc = read32bits(&pPager->jfd, pDbSize);
+ rc = read32bits(pPager->jfd, pDbSize);
if( rc ) return rc;
/* Update the assumed sector-size to match the value used by
@@ -719,11 +726,11 @@ static int readJournalHdr(
** is being called from within pager_playback(). The local value
** of Pager.sectorSize is restored at the end of that routine.
*/
- rc = read32bits(&pPager->jfd, (u32 *)&pPager->sectorSize);
+ rc = read32bits(pPager->jfd, (u32 *)&pPager->sectorSize);
if( rc ) return rc;
pPager->journalOff += JOURNAL_HDR_SZ(pPager);
- rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
+ rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff);
return rc;
}
@@ -743,12 +750,16 @@ static int readJournalHdr(
**
** The master journal page checksum is the sum of the bytes in the master
** journal name.
+**
+** If zMaster is a NULL pointer (occurs for a single database transaction),
+** this call is a no-op.
*/
static int writeMasterJournal(Pager *pPager, const char *zMaster){
int rc;
int len;
int i;
- u32 cksum = 0;
+ u32 cksum = 0;
+ char zBuf[sizeof(aJournalMagic)+2*4];
if( !zMaster || pPager->setMaster) return SQLITE_OK;
pPager->setMaster = 1;
@@ -768,19 +779,16 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
}
pPager->journalOff += (len+20);
- rc = write32bits(&pPager->jfd, PAGER_MJ_PGNO(pPager));
+ rc = write32bits(pPager->jfd, PAGER_MJ_PGNO(pPager));
if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3OsWrite(&pPager->jfd, zMaster, len);
+ rc = sqlite3OsWrite(pPager->jfd, zMaster, len);
if( rc!=SQLITE_OK ) return rc;
- rc = write32bits(&pPager->jfd, len);
- if( rc!=SQLITE_OK ) return rc;
-
- rc = write32bits(&pPager->jfd, cksum);
- if( rc!=SQLITE_OK ) return rc;
-
- rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
+ put32bits(zBuf, len);
+ put32bits(&zBuf[4], cksum);
+ memcpy(&zBuf[8], aJournalMagic, sizeof(aJournalMagic));
+ rc = sqlite3OsWrite(pPager->jfd, zBuf, 8+sizeof(aJournalMagic));
pPager->needSync = !pPager->noSync;
return rc;
}
@@ -829,7 +837,9 @@ static void page_remove_from_stmt_list(PgHdr *pPg){
** a pointer to the page or NULL if not found.
*/
static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
- PgHdr *p = pPager->aHash[pager_hash(pgno)];
+ PgHdr *p;
+ if( pPager->aHash==0 ) return 0;
+ p = pPager->aHash[pgno & (pPager->nHash-1)];
while( p && p->pgno!=pgno ){
p = p->pNextHash;
}
@@ -844,7 +854,7 @@ static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
*/
static void pager_reset(Pager *pPager){
PgHdr *pPg, *pNext;
- if( pPager->errMask ) return;
+ if( pPager->errCode ) return;
for(pPg=pPager->pAll; pPg; pPg=pNext){
pNext = pPg->pNextAll;
sqliteFree(pPg);
@@ -853,12 +863,14 @@ static void pager_reset(Pager *pPager){
pPager->pFirstSynced = 0;
pPager->pLast = 0;
pPager->pAll = 0;
- memset(pPager->aHash, 0, sizeof(pPager->aHash));
+ pPager->nHash = 0;
+ sqliteFree(pPager->aHash);
pPager->nPage = 0;
+ pPager->aHash = 0;
if( pPager->state>=PAGER_RESERVED ){
sqlite3pager_rollback(pPager);
}
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
+ sqlite3OsUnlock(pPager->fd, NO_LOCK);
pPager->state = PAGER_UNLOCK;
pPager->dbSize = -1;
pPager->nRef = 0;
@@ -866,29 +878,6 @@ static void pager_reset(Pager *pPager){
}
/*
-** This function is used to reset the pager after a malloc() failure. This
-** doesn't work with in-memory databases. If a malloc() fails when an
-** in-memory database is in use it is not possible to recover.
-**
-** If a transaction or statement transaction is active, it is rolled back.
-**
-** It is an error to call this function if any pages are in use.
-*/
-#ifndef SQLITE_OMIT_GLOBALRECOVER
-int sqlite3pager_reset(Pager *pPager){
- if( pPager ){
- if( pPager->nRef || MEMDB ){
- return SQLITE_ERROR;
- }
- pPager->errMask &= ~(PAGER_ERR_MEM);
- pager_reset(pPager);
- }
- return SQLITE_OK;
-}
-#endif
-
-
-/*
** When this routine is called, the pager has the journal file open and
** a RESERVED or EXCLUSIVE lock on the database. This routine releases
** the database lock and acquires a SHARED lock in its place. The journal
@@ -924,16 +913,19 @@ static int pager_unwritelock(Pager *pPager){
pPg->pageHash = pager_pagehash(pPg);
#endif
}
+ pPager->pDirty = 0;
pPager->dirtyCache = 0;
pPager->nRec = 0;
}else{
assert( pPager->aInJournal==0 );
assert( pPager->dirtyCache==0 || pPager->useJournal==0 );
}
- rc = sqlite3OsUnlock(&pPager->fd, SHARED_LOCK);
+ rc = sqlite3OsUnlock(pPager->fd, SHARED_LOCK);
pPager->state = PAGER_SHARED;
pPager->origDbSize = 0;
pPager->setMaster = 0;
+ pPager->needSync = 0;
+ pPager->pFirstSynced = pPager->pFirst;
return rc;
}
@@ -957,7 +949,7 @@ static int pager_unwritelock(Pager *pPager){
** only the middle sector is corrupt, we will still have a reasonable
** chance of failing the checksum and thus detecting the problem.
*/
-static u32 pager_cksum(Pager *pPager, Pgno pgno, const char *aData){
+static u32 pager_cksum(Pager *pPager, const u8 *aData){
u32 cksum = pPager->cksumInit;
int i = pPager->pageSize-200;
while( i>0 ){
@@ -967,6 +959,9 @@ static u32 pager_cksum(Pager *pPager, Pgno pgno, const char *aData){
return cksum;
}
+/* Forward declaration */
+static void makeClean(PgHdr*);
+
/*
** Read a single page from the journal file opened on file descriptor
** jfd. Playback this one page.
@@ -985,7 +980,7 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
/* useCksum should be true for the main journal and false for
** statement journals. Verify that this is always the case
*/
- assert( jfd == (useCksum ? &pPager->jfd : &pPager->stfd) );
+ assert( jfd == (useCksum ? pPager->jfd : pPager->stfd) );
rc = read32bits(jfd, &pgno);
@@ -1009,7 +1004,7 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
rc = read32bits(jfd, &cksum);
if( rc ) return rc;
pPager->journalOff += 4;
- if( pager_cksum(pPager, pgno, aData)!=cksum ){
+ if( pager_cksum(pPager, aData)!=cksum ){
return SQLITE_DONE;
}
}
@@ -1040,11 +1035,13 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 );
TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno);
if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){
- rc = sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
+ rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize);
if( rc==SQLITE_OK ){
- rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize);
+ rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize);
+ }
+ if( pPg ){
+ makeClean(pPg);
}
- if( pPg ) pPg->dirty = 0;
}
if( pPg ){
/* No page should ever be explicitly rolled back that is in use, except
@@ -1063,7 +1060,7 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
#ifdef SQLITE_CHECK_PAGES
pPg->pageHash = pager_pagehash(pPg);
#endif
- CODEC(pPager, pData, pPg->pgno, 3);
+ CODEC1(pPager, pData, pPg->pgno, 3);
}
return rc;
}
@@ -1082,18 +1079,17 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
static int pager_delmaster(const char *zMaster){
int rc;
int master_open = 0;
- OsFile master;
+ OsFile *master = 0;
char *zMasterJournal = 0; /* Contents of master journal file */
i64 nMasterJournal; /* Size of master journal file */
/* Open the master journal file exclusively in case some other process
** is running this routine also. Not that it makes too much difference.
*/
- memset(&master, 0, sizeof(master));
rc = sqlite3OsOpenReadOnly(zMaster, &master);
if( rc!=SQLITE_OK ) goto delmaster_out;
master_open = 1;
- rc = sqlite3OsFileSize(&master, &nMasterJournal);
+ rc = sqlite3OsFileSize(master, &nMasterJournal);
if( rc!=SQLITE_OK ) goto delmaster_out;
if( nMasterJournal>0 ){
@@ -1108,7 +1104,7 @@ static int pager_delmaster(const char *zMaster){
rc = SQLITE_NOMEM;
goto delmaster_out;
}
- rc = sqlite3OsRead(&master, zMasterJournal, nMasterJournal);
+ rc = sqlite3OsRead(master, zMasterJournal, nMasterJournal);
if( rc!=SQLITE_OK ) goto delmaster_out;
zJournal = zMasterJournal;
@@ -1118,16 +1114,15 @@ static int pager_delmaster(const char *zMaster){
** Open it and check if it points at the master journal. If
** so, return without deleting the master journal file.
*/
- OsFile journal;
+ OsFile *journal = 0;
int c;
- memset(&journal, 0, sizeof(journal));
rc = sqlite3OsOpenReadOnly(zJournal, &journal);
if( rc!=SQLITE_OK ){
goto delmaster_out;
}
- rc = readMasterJournal(&journal, &zMasterPtr);
+ rc = readMasterJournal(journal, &zMasterPtr);
sqlite3OsClose(&journal);
if( rc!=SQLITE_OK ){
goto delmaster_out;
@@ -1172,13 +1167,13 @@ static int pager_reload_cache(Pager *pPager){
char zBuf[SQLITE_MAX_PAGE_SIZE];
if( !pPg->dirty ) continue;
if( (int)pPg->pgno <= pPager->origDbSize ){
- rc = sqlite3OsSeek(&pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1));
+ rc = sqlite3OsSeek(pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1));
if( rc==SQLITE_OK ){
- rc = sqlite3OsRead(&pPager->fd, zBuf, pPager->pageSize);
+ rc = sqlite3OsRead(pPager->fd, zBuf, pPager->pageSize);
}
TRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
if( rc ) break;
- CODEC(pPager, zBuf, pPg->pgno, 2);
+ CODEC1(pPager, zBuf, pPg->pgno, 2);
}else{
memset(zBuf, 0, pPager->pageSize);
}
@@ -1196,6 +1191,7 @@ static int pager_reload_cache(Pager *pPager){
pPg->pageHash = pager_pagehash(pPg);
#endif
}
+ pPager->pDirty = 0;
return rc;
}
@@ -1205,7 +1201,7 @@ static int pager_reload_cache(Pager *pPager){
*/
static int pager_truncate(Pager *pPager, int nPage){
assert( pPager->state>=PAGER_EXCLUSIVE );
- return sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(i64)nPage);
+ return sqlite3OsTruncate(pPager->fd, pPager->pageSize*(i64)nPage);
}
/*
@@ -1273,7 +1269,7 @@ static int pager_playback(Pager *pPager){
** the journal is empty.
*/
assert( pPager->journalOpen );
- rc = sqlite3OsFileSize(&pPager->jfd, &szJ);
+ rc = sqlite3OsFileSize(pPager->jfd, &szJ);
if( rc!=SQLITE_OK ){
goto end_playback;
}
@@ -1283,7 +1279,7 @@ static int pager_playback(Pager *pPager){
** present on disk, then the journal is not hot and does not need to be
** played back.
*/
- rc = readMasterJournal(&pPager->jfd, &zMaster);
+ rc = readMasterJournal(pPager->jfd, &zMaster);
assert( rc!=SQLITE_DONE );
if( rc!=SQLITE_OK || (zMaster && !sqlite3OsFileExists(zMaster)) ){
sqliteFree(zMaster);
@@ -1291,7 +1287,7 @@ static int pager_playback(Pager *pPager){
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
goto end_playback;
}
- sqlite3OsSeek(&pPager->jfd, 0);
+ sqlite3OsSeek(pPager->jfd, 0);
pPager->journalOff = 0;
/* This loop terminates either when the readJournalHdr() call returns
@@ -1334,13 +1330,10 @@ static int pager_playback(Pager *pPager){
pPager->dbSize = mxPg;
}
- /* rc = sqlite3OsSeek(&pPager->jfd, JOURNAL_HDR_SZ(pPager)); */
- if( rc!=SQLITE_OK ) goto end_playback;
-
/* Copy original pages out of the journal and back into the database file.
*/
for(i=0; i<nRec; i++){
- rc = pager_playback_one_page(pPager, &pPager->jfd, 1);
+ rc = pager_playback_one_page(pPager, pPager->jfd, 1);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
@@ -1352,13 +1345,8 @@ static int pager_playback(Pager *pPager){
}
}
}
-
- /* Pages that have been written to the journal but never synced
- ** where not restored by the loop above. We have to restore those
- ** pages by reading them back from the original database.
- */
- assert( rc==SQLITE_OK );
- pager_reload_cache(pPager);
+ /*NOTREACHED*/
+ assert( 0 );
end_playback:
if( rc==SQLITE_OK ){
@@ -1407,7 +1395,7 @@ static int pager_stmt_playback(Pager *pPager){
#ifndef NDEBUG
{
i64 os_szJ;
- rc = sqlite3OsFileSize(&pPager->jfd, &os_szJ);
+ rc = sqlite3OsFileSize(pPager->jfd, &os_szJ);
if( rc!=SQLITE_OK ) return rc;
assert( szJ==os_szJ );
}
@@ -1433,7 +1421,7 @@ static int pager_stmt_playback(Pager *pPager){
/* Figure out how many records are in the statement journal.
*/
assert( pPager->stmtInUse && pPager->journalOpen );
- sqlite3OsSeek(&pPager->stfd, 0);
+ sqlite3OsSeek(pPager->stfd, 0);
nRec = pPager->stmtNRec;
/* Copy original pages out of the statement journal and back into the
@@ -1442,7 +1430,7 @@ static int pager_stmt_playback(Pager *pPager){
** journals.
*/
for(i=nRec-1; i>=0; i--){
- rc = pager_playback_one_page(pPager, &pPager->stfd, 0);
+ rc = pager_playback_one_page(pPager, pPager->stfd, 0);
assert( rc!=SQLITE_DONE );
if( rc!=SQLITE_OK ) goto end_stmt_playback;
}
@@ -1455,7 +1443,7 @@ static int pager_stmt_playback(Pager *pPager){
** If it is not zero, then Pager.stmtHdrOff is the offset to the start
** of the first journal header written during this statement transaction.
*/
- rc = sqlite3OsSeek(&pPager->jfd, pPager->stmtJSize);
+ rc = sqlite3OsSeek(pPager->jfd, pPager->stmtJSize);
if( rc!=SQLITE_OK ){
goto end_stmt_playback;
}
@@ -1463,24 +1451,24 @@ static int pager_stmt_playback(Pager *pPager){
pPager->cksumInit = pPager->stmtCksum;
assert( JOURNAL_HDR_SZ(pPager)<(pPager->pageSize+8) );
while( pPager->journalOff <= (hdrOff-(pPager->pageSize+8)) ){
- rc = pager_playback_one_page(pPager, &pPager->jfd, 1);
+ rc = pager_playback_one_page(pPager, pPager->jfd, 1);
assert( rc!=SQLITE_DONE );
if( rc!=SQLITE_OK ) goto end_stmt_playback;
}
while( pPager->journalOff < szJ ){
- u32 nRec;
+ u32 nJRec; /* Number of Journal Records */
u32 dummy;
- rc = readJournalHdr(pPager, szJ, &nRec, &dummy);
+ rc = readJournalHdr(pPager, szJ, &nJRec, &dummy);
if( rc!=SQLITE_OK ){
assert( rc!=SQLITE_DONE );
goto end_stmt_playback;
}
- if( nRec==0 ){
- nRec = (szJ - pPager->journalOff) / (pPager->pageSize+8);
+ if( nJRec==0 ){
+ nJRec = (szJ - pPager->journalOff) / (pPager->pageSize+8);
}
- for(i=nRec-1; i>=0 && pPager->journalOff < szJ; i--){
- rc = pager_playback_one_page(pPager, &pPager->jfd, 1);
+ for(i=nJRec-1; i>=0 && pPager->journalOff < szJ; i--){
+ rc = pager_playback_one_page(pPager, pPager->jfd, 1);
assert( rc!=SQLITE_DONE );
if( rc!=SQLITE_OK ) goto end_stmt_playback;
}
@@ -1489,10 +1477,7 @@ static int pager_stmt_playback(Pager *pPager){
pPager->journalOff = szJ;
end_stmt_playback:
- if( rc!=SQLITE_OK ){
- pPager->errMask |= PAGER_ERR_CORRUPT;
- rc = SQLITE_CORRUPT;
- }else{
+ if( rc==SQLITE_OK) {
pPager->journalOff = szJ;
/* pager_reload_cache(pPager); */
}
@@ -1537,9 +1522,10 @@ void sqlite3pager_set_cachesize(Pager *pPager, int mxPage){
** and FULL=3.
*/
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
-void sqlite3pager_set_safety_level(Pager *pPager, int level){
+void sqlite3pager_set_safety_level(Pager *pPager, int level, int full_fsync){
pPager->noSync = level==1 || pPager->tempFile;
pPager->fullSync = level==3 && !pPager->tempFile;
+ pPager->full_fsync = full_fsync;
if( pPager->noSync ) pPager->needSync = 0;
}
#endif
@@ -1549,7 +1535,9 @@ void sqlite3pager_set_safety_level(Pager *pPager, int level){
** attempts to open a temporary file. This information is used for
** testing and analysis only.
*/
+#ifdef SQLITE_TEST
int sqlite3_opentemp_count = 0;
+#endif
/*
** Open a temporary file. Write the name of the file into zFile
@@ -1560,14 +1548,16 @@ int sqlite3_opentemp_count = 0;
** The OS will automatically delete the temporary file when it is
** closed.
*/
-static int sqlite3pager_opentemp(char *zFile, OsFile *fd){
+static int sqlite3pager_opentemp(char *zFile, OsFile **pFd){
int cnt = 8;
int rc;
+#ifdef SQLITE_TEST
sqlite3_opentemp_count++; /* Used for testing and analysis only */
+#endif
do{
cnt--;
sqlite3OsTempFileName(zFile);
- rc = sqlite3OsOpenExclusive(zFile, fd, 1);
+ rc = sqlite3OsOpenExclusive(zFile, pFd, 1);
}while( cnt>0 && rc!=SQLITE_OK && rc!=SQLITE_NOMEM );
return rc;
}
@@ -1592,10 +1582,10 @@ int sqlite3pager_open(
int nExtra, /* Extra bytes append to each in-memory page */
int flags /* flags controlling this file */
){
- Pager *pPager;
+ Pager *pPager = 0;
char *zFullPathname = 0;
- int nameLen;
- OsFile fd;
+ int nameLen; /* Compiler is wrong. This is always initialized before use */
+ OsFile *fd;
int rc = SQLITE_OK;
int i;
int tempFile = 0;
@@ -1604,18 +1594,36 @@ int sqlite3pager_open(
int useJournal = (flags & PAGER_OMIT_JOURNAL)==0;
int noReadlock = (flags & PAGER_NO_READLOCK)!=0;
char zTemp[SQLITE_TEMPNAME_SIZE];
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ /* A malloc() cannot fail in sqlite3ThreadData() as one or more calls to
+ ** malloc() must have already been made by this thread before it gets
+ ** to this point. This means the ThreadData must have been allocated already
+ ** so that ThreadData.nAlloc can be set. It would be nice to assert
+ ** that ThreadData.nAlloc is non-zero, but alas this breaks test cases
+ ** written to invoke the pager directly.
+ */
+ ThreadData *pTsd = sqlite3ThreadData();
+ assert( pTsd );
+#endif
+ /* If malloc() has already failed return SQLITE_NOMEM. Before even
+ ** testing for this, set *ppPager to NULL so the caller knows the pager
+ ** structure was never allocated.
+ */
*ppPager = 0;
- memset(&fd, 0, sizeof(fd));
- if( sqlite3_malloc_failed ){
+ if( sqlite3MallocFailed() ){
return SQLITE_NOMEM;
}
+ memset(&fd, 0, sizeof(fd));
+
+ /* Open the pager file and set zFullPathname to point at malloc()ed
+ ** memory containing the complete filename (i.e. including the directory).
+ */
if( zFilename && zFilename[0] ){
#ifndef SQLITE_OMIT_MEMORYDB
if( strcmp(zFilename,":memory:")==0 ){
memDb = 1;
zFullPathname = sqliteStrDup("");
- rc = SQLITE_OK;
}else
#endif
{
@@ -1632,66 +1640,75 @@ int sqlite3pager_open(
tempFile = 1;
}
}
- if( !zFullPathname ){
- sqlite3OsClose(&fd);
- return SQLITE_NOMEM;
- }
- if( rc!=SQLITE_OK ){
- sqlite3OsClose(&fd);
- sqliteFree(zFullPathname);
- return rc;
+
+ /* Allocate the Pager structure. As part of the same allocation, allocate
+ ** space for the full paths of the file, directory and journal
+ ** (Pager.zFilename, Pager.zDirectory and Pager.zJournal).
+ */
+ if( zFullPathname ){
+ nameLen = strlen(zFullPathname);
+ pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
}
- nameLen = strlen(zFullPathname);
- pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
- if( pPager==0 ){
+
+ /* If an error occured in either of the blocks above, free the memory
+ ** pointed to by zFullPathname, free the Pager structure and close the
+ ** file. Since the pager is not allocated there is no need to set
+ ** any Pager.errMask variables.
+ */
+ if( !pPager || !zFullPathname || rc!=SQLITE_OK ){
sqlite3OsClose(&fd);
sqliteFree(zFullPathname);
- return SQLITE_NOMEM;
+ sqliteFree(pPager);
+ return ((rc==SQLITE_OK)?SQLITE_NOMEM:rc);
}
+
TRACE3("OPEN %d %s\n", FILEHANDLEID(fd), zFullPathname);
pPager->zFilename = (char*)&pPager[1];
pPager->zDirectory = &pPager->zFilename[nameLen+1];
pPager->zJournal = &pPager->zDirectory[nameLen+1];
strcpy(pPager->zFilename, zFullPathname);
strcpy(pPager->zDirectory, zFullPathname);
+
for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){}
if( i>0 ) pPager->zDirectory[i-1] = 0;
strcpy(pPager->zJournal, zFullPathname);
sqliteFree(zFullPathname);
strcpy(&pPager->zJournal[nameLen], "-journal");
pPager->fd = fd;
-#if OS_UNIX
- pPager->fd.pPager = pPager;
-#endif
- pPager->journalOpen = 0;
+ /* pPager->journalOpen = 0; */
pPager->useJournal = useJournal && !memDb;
pPager->noReadlock = noReadlock && readOnly;
- pPager->stmtOpen = 0;
- pPager->stmtInUse = 0;
- pPager->nRef = 0;
+ /* pPager->stmtOpen = 0; */
+ /* pPager->stmtInUse = 0; */
+ /* pPager->nRef = 0; */
pPager->dbSize = memDb-1;
pPager->pageSize = SQLITE_DEFAULT_PAGE_SIZE;
- pPager->stmtSize = 0;
- pPager->stmtJSize = 0;
- pPager->nPage = 0;
- pPager->nMaxPage = 0;
+ /* pPager->stmtSize = 0; */
+ /* pPager->stmtJSize = 0; */
+ /* pPager->nPage = 0; */
+ /* pPager->nMaxPage = 0; */
pPager->mxPage = 100;
- pPager->state = PAGER_UNLOCK;
- pPager->errMask = 0;
+ assert( PAGER_UNLOCK==0 );
+ /* pPager->state = PAGER_UNLOCK; */
+ /* pPager->errMask = 0; */
pPager->tempFile = tempFile;
pPager->memDb = memDb;
pPager->readOnly = readOnly;
- pPager->needSync = 0;
+ /* pPager->needSync = 0; */
pPager->noSync = pPager->tempFile || !useJournal;
pPager->fullSync = (pPager->noSync?0:1);
- pPager->pFirst = 0;
- pPager->pFirstSynced = 0;
- pPager->pLast = 0;
+ /* pPager->pFirst = 0; */
+ /* pPager->pFirstSynced = 0; */
+ /* pPager->pLast = 0; */
pPager->nExtra = FORCE_ALIGNMENT(nExtra);
pPager->sectorSize = PAGER_SECTOR_SIZE;
- pPager->pBusyHandler = 0;
- memset(pPager->aHash, 0, sizeof(pPager->aHash));
+ /* pPager->pBusyHandler = 0; */
+ /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
*ppPager = pPager;
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ pPager->pNext = pTsd->pPager;
+ pTsd->pPager = pPager;
+#endif
return SQLITE_OK;
}
@@ -1739,14 +1756,50 @@ int sqlite3pager_set_pagesize(Pager *pPager, int pageSize){
}
/*
+** The following set of routines are used to disable the simulated
+** I/O error mechanism. These routines are used to avoid simulated
+** errors in places where we do not care about errors.
+**
+** Unless -DSQLITE_TEST=1 is used, these routines are all no-ops
+** and generate no code.
+*/
+#ifdef SQLITE_TEST
+extern int sqlite3_io_error_pending;
+extern int sqlite3_io_error_hit;
+static int saved_cnt;
+void clear_simulated_io_error(){
+ sqlite3_io_error_hit = 0;
+}
+void disable_simulated_io_errors(void){
+ saved_cnt = sqlite3_io_error_pending;
+ sqlite3_io_error_pending = -1;
+}
+void enable_simulated_io_errors(void){
+ sqlite3_io_error_pending = saved_cnt;
+}
+#else
+# define clear_simulated_io_error()
+# define disable_simulated_io_errors()
+# define enable_simulated_io_errors()
+#endif
+
+/*
** Read the first N bytes from the beginning of the file into memory
-** that pDest points to. No error checking is done.
+** that pDest points to.
+**
+** No error checking is done. The rational for this is that this function
+** may be called even if the file does not exist or contain a header. In
+** these cases sqlite3OsRead() will return an error, to which the correct
+** response is to zero the memory at pDest and continue. A real IO error
+** will presumably recur and be picked up later (Todo: Think about this).
*/
void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
memset(pDest, 0, N);
if( MEMDB==0 ){
- sqlite3OsSeek(&pPager->fd, 0);
- sqlite3OsRead(&pPager->fd, pDest, N);
+ disable_simulated_io_errors();
+ sqlite3OsSeek(pPager->fd, 0);
+ sqlite3OsRead(pPager->fd, pDest, N);
+ enable_simulated_io_errors();
}
}
@@ -1765,8 +1818,8 @@ int sqlite3pager_pagecount(Pager *pPager){
if( pPager->dbSize>=0 ){
n = pPager->dbSize;
} else {
- if( sqlite3OsFileSize(&pPager->fd, &n)!=SQLITE_OK ){
- pPager->errMask |= PAGER_ERR_DISK;
+ if( sqlite3OsFileSize(pPager->fd, &n)!=SQLITE_OK ){
+ pager_error(pPager, SQLITE_IOERR);
return 0;
}
if( n>0 && n<pPager->pageSize ){
@@ -1784,12 +1837,26 @@ int sqlite3pager_pagecount(Pager *pPager){
return n;
}
+
+#ifndef SQLITE_OMIT_MEMORYDB
+/*
+** Clear a PgHistory block
+*/
+static void clearHistory(PgHistory *pHist){
+ sqliteFree(pHist->pOrig);
+ sqliteFree(pHist->pStmt);
+ pHist->pOrig = 0;
+ pHist->pStmt = 0;
+}
+#else
+#define clearHistory(x)
+#endif
+
/*
** Forward declaration
*/
static int syncJournal(Pager*);
-
/*
** Unlink pPg from it's hash chain. Also set the page number to 0 to indicate
** that the page is not part of any hash chain. This is required because the
@@ -1798,21 +1865,22 @@ static int syncJournal(Pager*);
*/
static void unlinkHashChain(Pager *pPager, PgHdr *pPg){
if( pPg->pgno==0 ){
- /* If the page number is zero, then this page is not in any hash chain. */
+ assert( pPg->pNextHash==0 && pPg->pPrevHash==0 );
return;
}
if( pPg->pNextHash ){
pPg->pNextHash->pPrevHash = pPg->pPrevHash;
}
if( pPg->pPrevHash ){
- assert( pPager->aHash[pager_hash(pPg->pgno)]!=pPg );
+ assert( pPager->aHash[pPg->pgno & (pPager->nHash-1)]!=pPg );
pPg->pPrevHash->pNextHash = pPg->pNextHash;
}else{
- int h = pager_hash(pPg->pgno);
- assert( pPager->aHash[h]==pPg );
+ int h = pPg->pgno & (pPager->nHash-1);
pPager->aHash[h] = pPg->pNextHash;
}
-
+ if( MEMDB ){
+ clearHistory(PGHDR_TO_HIST(pPg, pPager));
+ }
pPg->pgno = 0;
pPg->pNextHash = pPg->pPrevHash = 0;
}
@@ -1871,6 +1939,7 @@ static void memoryTruncate(Pager *pPager){
}else{
*ppPg = pPg->pNextAll;
unlinkPage(pPg);
+ makeClean(pPg);
sqliteFree(pPg);
pPager->nPage--;
}
@@ -1897,7 +1966,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
rc = SQLITE_OK;
}else{
do {
- rc = sqlite3OsLock(&pPager->fd, locktype);
+ rc = sqlite3OsLock(pPager->fd, locktype);
}while( rc==SQLITE_BUSY && sqlite3InvokeBusyHandler(pPager->pBusyHandler) );
if( rc==SQLITE_OK ){
pPager->state = locktype;
@@ -1912,8 +1981,8 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
int rc;
sqlite3pager_pagecount(pPager);
- if( pPager->errMask!=0 ){
- rc = pager_errcode(pPager);
+ if( pPager->errCode ){
+ rc = pPager->errCode;
return rc;
}
if( nPage>=(unsigned)pPager->dbSize ){
@@ -1950,9 +2019,25 @@ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
** and their memory is freed. Any attempt to use a page associated
** with this page cache after this function returns will likely
** result in a coredump.
+**
+** This function always succeeds. If a transaction is active an attempt
+** is made to roll it back. If an error occurs during the rollback
+** a hot journal may be left in the filesystem but no error is returned
+** to the caller.
*/
int sqlite3pager_close(Pager *pPager){
PgHdr *pPg, *pNext;
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ /* A malloc() cannot fail in sqlite3ThreadData() as one or more calls to
+ ** malloc() must have already been made by this thread before it gets
+ ** to this point. This means the ThreadData must have been allocated already
+ ** so that ThreadData.nAlloc can be set.
+ */
+ ThreadData *pTsd = sqlite3ThreadData();
+ assert( pPager );
+ assert( pTsd && pTsd->nAlloc );
+#endif
+
switch( pPager->state ){
case PAGER_RESERVED:
case PAGER_SYNCED:
@@ -1961,24 +2046,18 @@ int sqlite3pager_close(Pager *pPager){
** operation. So disable IO error simulation so that testing
** works more easily.
*/
-#if defined(SQLITE_TEST) && (defined(OS_UNIX) || defined(OS_WIN))
- extern int sqlite3_io_error_pending;
- int ioerr_cnt = sqlite3_io_error_pending;
- sqlite3_io_error_pending = -1;
-#endif
+ disable_simulated_io_errors();
sqlite3pager_rollback(pPager);
-#if defined(SQLITE_TEST) && (defined(OS_UNIX) || defined(OS_WIN))
- sqlite3_io_error_pending = ioerr_cnt;
-#endif
+ enable_simulated_io_errors();
if( !MEMDB ){
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
+ sqlite3OsUnlock(pPager->fd, NO_LOCK);
}
- assert( pPager->errMask || pPager->journalOpen==0 );
+ assert( pPager->errCode || pPager->journalOpen==0 );
break;
}
case PAGER_SHARED: {
if( !MEMDB ){
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
+ sqlite3OsUnlock(pPager->fd, NO_LOCK);
}
break;
}
@@ -2000,7 +2079,7 @@ int sqlite3pager_close(Pager *pPager){
sqliteFree(pPg);
}
TRACE2("CLOSE %d\n", PAGERID(pPager));
- assert( pPager->errMask || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
+ assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
if( pPager->journalOpen ){
sqlite3OsClose(&pPager->jfd);
}
@@ -2015,6 +2094,19 @@ int sqlite3pager_close(Pager *pPager){
** }
*/
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ /* Remove the pager from the linked list of pagers starting at
+ ** ThreadData.pPager if memory-management is enabled.
+ */
+ if( pPager==pTsd->pPager ){
+ pTsd->pPager = pPager->pNext;
+ }else{
+ Pager *pTmp;
+ for(pTmp = pTsd->pPager; pTmp->pNext!=pPager; pTmp=pTmp->pNext){}
+ pTmp->pNext = pPager->pNext;
+ }
+#endif
+ sqliteFree(pPager->aHash);
sqliteFree(pPager);
return SQLITE_OK;
}
@@ -2120,7 +2212,7 @@ static int syncJournal(Pager *pPager){
** with the nRec computed from the size of the journal file.
*/
i64 jSz;
- rc = sqlite3OsFileSize(&pPager->jfd, &jSz);
+ rc = sqlite3OsFileSize(pPager->jfd, &jSz);
if( rc!=0 ) return rc;
assert( pPager->journalOff==jSz );
}
@@ -2133,20 +2225,20 @@ static int syncJournal(Pager *pPager){
*/
if( pPager->fullSync ){
TRACE2("SYNC journal of %d\n", PAGERID(pPager));
- rc = sqlite3OsSync(&pPager->jfd, 0);
+ rc = sqlite3OsSync(pPager->jfd, 0);
if( rc!=0 ) return rc;
}
- rc = sqlite3OsSeek(&pPager->jfd,
+ rc = sqlite3OsSeek(pPager->jfd,
pPager->journalHdr + sizeof(aJournalMagic));
if( rc ) return rc;
- rc = write32bits(&pPager->jfd, pPager->nRec);
+ rc = write32bits(pPager->jfd, pPager->nRec);
if( rc ) return rc;
- rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
+ rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff);
if( rc ) return rc;
}
TRACE2("SYNC journal of %d\n", PAGERID(pPager));
- rc = sqlite3OsSync(&pPager->jfd, pPager->fullSync);
+ rc = sqlite3OsSync(pPager->jfd, pPager->full_fsync);
if( rc!=0 ) return rc;
pPager->journalStarted = 1;
}
@@ -2177,6 +2269,68 @@ static int syncJournal(Pager *pPager){
}
/*
+** Merge two lists of pages connected by pDirty and in pgno order.
+** Do not both fixing the pPrevDirty pointers.
+*/
+static PgHdr *merge_pagelist(PgHdr *pA, PgHdr *pB){
+ PgHdr result, *pTail;
+ pTail = &result;
+ while( pA && pB ){
+ if( pA->pgno<pB->pgno ){
+ pTail->pDirty = pA;
+ pTail = pA;
+ pA = pA->pDirty;
+ }else{
+ pTail->pDirty = pB;
+ pTail = pB;
+ pB = pB->pDirty;
+ }
+ }
+ if( pA ){
+ pTail->pDirty = pA;
+ }else if( pB ){
+ pTail->pDirty = pB;
+ }else{
+ pTail->pDirty = 0;
+ }
+ return result.pDirty;
+}
+
+/*
+** Sort the list of pages in accending order by pgno. Pages are
+** connected by pDirty pointers. The pPrevDirty pointers are
+** corrupted by this sort.
+*/
+#define N_SORT_BUCKET 25
+static PgHdr *sort_pagelist(PgHdr *pIn){
+ PgHdr *a[N_SORT_BUCKET], *p;
+ int i;
+ memset(a, 0, sizeof(a));
+ while( pIn ){
+ p = pIn;
+ pIn = p->pDirty;
+ p->pDirty = 0;
+ for(i=0; i<N_SORT_BUCKET-1; i++){
+ if( a[i]==0 ){
+ a[i] = p;
+ break;
+ }else{
+ p = merge_pagelist(a[i], p);
+ a[i] = 0;
+ }
+ }
+ if( i==N_SORT_BUCKET-1 ){
+ a[i] = merge_pagelist(a[i], p);
+ }
+ }
+ p = a[0];
+ for(i=1; i<N_SORT_BUCKET; i++){
+ p = merge_pagelist(p, a[i]);
+ }
+ return p;
+}
+
+/*
** Given a list of pages (connected by the PgHdr.pDirty pointer) write
** every one of those pages out to the database file and mark them all
** as clean.
@@ -2209,9 +2363,10 @@ static int pager_write_pagelist(PgHdr *pList){
return rc;
}
+ pList = sort_pagelist(pList);
while( pList ){
assert( pList->dirty );
- rc = sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
+ rc = sqlite3OsSeek(pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
if( rc ) return rc;
/* If there are dirty pages in the page cache with page numbers greater
** than Pager.dbSize, this means sqlite3pager_truncate() was called to
@@ -2219,10 +2374,9 @@ static int pager_write_pagelist(PgHdr *pList){
** any such pages to the file.
*/
if( pList->pgno<=pPager->dbSize ){
- CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
+ char *pData = CODEC2(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
TRACE3("STORE %d page %d\n", PAGERID(pPager), pList->pgno);
- rc = sqlite3OsWrite(&pPager->fd, PGHDR_TO_DATA(pList), pPager->pageSize);
- CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0);
+ rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize);
TEST_INCR(pPager->nWrite);
}
#ifndef NDEBUG
@@ -2246,15 +2400,7 @@ static int pager_write_pagelist(PgHdr *pList){
** collected even if they are still in use.
*/
static PgHdr *pager_get_all_dirty_pages(Pager *pPager){
- PgHdr *p, *pList;
- pList = 0;
- for(p=pPager->pAll; p; p=p->pNextAll){
- if( p->dirty ){
- p->pDirty = pList;
- pList = p;
- }
- }
- return pList;
+ return pPager->pDirty;
}
/*
@@ -2268,7 +2414,7 @@ static PgHdr *pager_get_all_dirty_pages(Pager *pPager){
static int hasHotJournal(Pager *pPager){
if( !pPager->useJournal ) return 0;
if( !sqlite3OsFileExists(pPager->zJournal) ) return 0;
- if( sqlite3OsCheckReservedLock(&pPager->fd) ) return 0;
+ if( sqlite3OsCheckReservedLock(pPager->fd) ) return 0;
if( sqlite3pager_pagecount(pPager)==0 ){
sqlite3OsDelete(pPager->zJournal);
return 0;
@@ -2278,6 +2424,172 @@ static int hasHotJournal(Pager *pPager){
}
/*
+** Try to find a page in the cache that can be recycled.
+**
+** This routine may return SQLITE_IOERR, SQLITE_FULL or SQLITE_OK. It
+** does not set the pPager->errCode variable.
+*/
+static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
+ PgHdr *pPg;
+ *ppPg = 0;
+
+ /* Find a page to recycle. Try to locate a page that does not
+ ** require us to do an fsync() on the journal.
+ */
+ pPg = pPager->pFirstSynced;
+
+ /* If we could not find a page that does not require an fsync()
+ ** on the journal file then fsync the journal file. This is a
+ ** very slow operation, so we work hard to avoid it. But sometimes
+ ** it can't be helped.
+ */
+ if( pPg==0 && pPager->pFirst && syncOk && !MEMDB){
+ int rc = syncJournal(pPager);
+ if( rc!=0 ){
+ return rc;
+ }
+ if( pPager->fullSync ){
+ /* If in full-sync mode, write a new journal header into the
+ ** journal file. This is done to avoid ever modifying a journal
+ ** header that is involved in the rollback of pages that have
+ ** already been written to the database (in case the header is
+ ** trashed when the nRec field is updated).
+ */
+ pPager->nRec = 0;
+ assert( pPager->journalOff > 0 );
+ rc = writeJournalHdr(pPager);
+ if( rc!=0 ){
+ return rc;
+ }
+ }
+ pPg = pPager->pFirst;
+ }
+ if( pPg==0 ){
+ return SQLITE_OK;
+ }
+
+ assert( pPg->nRef==0 );
+
+ /* Write the page to the database file if it is dirty.
+ */
+ if( pPg->dirty ){
+ int rc;
+ assert( pPg->needSync==0 );
+ makeClean(pPg);
+ pPg->dirty = 1;
+ pPg->pDirty = 0;
+ rc = pager_write_pagelist( pPg );
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ }
+ assert( pPg->dirty==0 );
+
+ /* If the page we are recycling is marked as alwaysRollback, then
+ ** set the global alwaysRollback flag, thus disabling the
+ ** sqlite_dont_rollback() optimization for the rest of this transaction.
+ ** It is necessary to do this because the page marked alwaysRollback
+ ** might be reloaded at a later time but at that point we won't remember
+ ** that is was marked alwaysRollback. This means that all pages must
+ ** be marked as alwaysRollback from here on out.
+ */
+ if( pPg->alwaysRollback ){
+ pPager->alwaysRollback = 1;
+ }
+
+ /* Unlink the old page from the free list and the hash table
+ */
+ unlinkPage(pPg);
+ TEST_INCR(pPager->nOvfl);
+
+ *ppPg = pPg;
+ return SQLITE_OK;
+}
+
+/*
+** This function is called to free superfluous dynamically allocated memory
+** held by the pager system. Memory in use by any SQLite pager allocated
+** by the current thread may be sqliteFree()ed.
+**
+** nReq is the number of bytes of memory required. Once this much has
+** been released, the function returns. A negative value for nReq means
+** free as much memory as possible. The return value is the total number
+** of bytes of memory released.
+*/
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+int sqlite3pager_release_memory(int nReq){
+ const ThreadData *pTsdro = sqlite3ThreadDataReadOnly();
+ Pager *p;
+ int nReleased = 0;
+ int i;
+
+ /* If the the global mutex is held, this subroutine becomes a
+ ** o-op; zero bytes of memory are freed. This is because
+ ** some of the code invoked by this function may also
+ ** try to obtain the mutex, resulting in a deadlock.
+ */
+ if( sqlite3OsInMutex(0) ){
+ return 0;
+ }
+
+ /* Outermost loop runs for at most two iterations. First iteration we
+ ** try to find memory that can be released without calling fsync(). Second
+ ** iteration (which only runs if the first failed to free nReq bytes of
+ ** memory) is permitted to call fsync(). This is of course much more
+ ** expensive.
+ */
+ for(i=0; i<=1; i++){
+
+ /* Loop through all the SQLite pagers opened by the current thread. */
+ for(p=pTsdro->pPager; p && (nReq<0 || nReleased<nReq); p=p->pNext){
+ PgHdr *pPg;
+ int rc;
+
+ /* For each pager, try to free as many pages as possible (without
+ ** calling fsync() if this is the first iteration of the outermost
+ ** loop).
+ */
+ while( SQLITE_OK==(rc = pager_recycle(p, i, &pPg)) && pPg) {
+ /* We've found a page to free. At this point the page has been
+ ** removed from the page hash-table, free-list and synced-list
+ ** (pFirstSynced). It is still in the all pages (pAll) list.
+ ** Remove it from this list before freeing.
+ **
+ ** Todo: Check the Pager.pStmt list to make sure this is Ok. It
+ ** probably is though.
+ */
+ PgHdr *pTmp;
+ assert( pPg );
+ page_remove_from_stmt_list(pPg);
+ if( pPg==p->pAll ){
+ p->pAll = pPg->pNextAll;
+ }else{
+ for( pTmp=p->pAll; pTmp->pNextAll!=pPg; pTmp=pTmp->pNextAll ){}
+ pTmp->pNextAll = pPg->pNextAll;
+ }
+ nReleased += sqliteAllocSize(pPg);
+ sqliteFree(pPg);
+ }
+
+ if( rc!=SQLITE_OK ){
+ /* An error occured whilst writing to the database file or
+ ** journal in pager_recycle(). The error is not returned to the
+ ** caller of this function. Instead, set the Pager.errCode variable.
+ ** The error will be returned to the user (or users, in the case
+ ** of a shared pager cache) of the pager for which the error occured.
+ */
+ assert( rc==SQLITE_IOERR || rc==SQLITE_FULL );
+ assert( p->state>=PAGER_RESERVED );
+ pager_error(p, rc);
+ }
+ }
+ }
+
+ return nReleased;
+}
+#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
+
+/*
** Acquire a page.
**
** A read lock on the disk file is obtained when the first page is acquired.
@@ -2315,8 +2627,8 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
*/
assert( pPager!=0 );
*ppPage = 0;
- if( pPager->errMask & ~(PAGER_ERR_FULL) ){
- return pager_errcode(pPager);
+ if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
+ return pPager->errCode;
}
/* If this is the first page accessed, then get a SHARED lock
@@ -2326,7 +2638,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
if( !pPager->noReadlock ){
rc = pager_wait_on_lock(pPager, SHARED_LOCK);
if( rc!=SQLITE_OK ){
- return rc;
+ return pager_error(pPager, rc);
}
}
@@ -2334,8 +2646,6 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
** database file, then it either needs to be played back or deleted.
*/
if( hasHotJournal(pPager) ){
- int rc;
-
/* Get an EXCLUSIVE lock on the database file. At this point it is
** important that a RESERVED lock is not obtained on the way to the
** EXCLUSIVE lock. If it were, another process might open the
@@ -2347,11 +2657,11 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
** second process will get to this point in the code and fail to
** obtain it's own EXCLUSIVE lock on the database file.
*/
- rc = sqlite3OsLock(&pPager->fd, EXCLUSIVE_LOCK);
+ rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
if( rc!=SQLITE_OK ){
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
+ sqlite3OsUnlock(pPager->fd, NO_LOCK);
pPager->state = PAGER_UNLOCK;
- return rc;
+ return pager_error(pPager, rc);
}
pPager->state = PAGER_EXCLUSIVE;
@@ -2365,7 +2675,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
*/
rc = sqlite3OsOpenReadOnly(pPager->zJournal, &pPager->jfd);
if( rc!=SQLITE_OK ){
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
+ sqlite3OsUnlock(pPager->fd, NO_LOCK);
pPager->state = PAGER_UNLOCK;
return SQLITE_BUSY;
}
@@ -2380,7 +2690,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
*/
rc = pager_playback(pPager);
if( rc!=SQLITE_OK ){
- return rc;
+ return pager_error(pPager, rc);
}
}
pPg = 0;
@@ -2397,11 +2707,17 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
TEST_INCR(pPager->nMiss);
if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 || MEMDB ){
/* Create a new page */
+ if( pPager->nPage>=pPager->nHash ){
+ pager_resize_hash_table(pPager,
+ pPager->nHash<256 ? 256 : pPager->nHash*2);
+ if( pPager->nHash==0 ){
+ return SQLITE_NOMEM;
+ }
+ }
pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize
+ sizeof(u32) + pPager->nExtra
+ MEMDB*sizeof(PgHistory) );
if( pPg==0 ){
- pPager->errMask |= PAGER_ERR_MEM;
return SQLITE_NOMEM;
}
memset(pPg, 0, sizeof(*pPg));
@@ -2417,70 +2733,11 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
pPager->nMaxPage++;
}
}else{
- /* Find a page to recycle. Try to locate a page that does not
- ** require us to do an fsync() on the journal.
- */
- pPg = pPager->pFirstSynced;
-
- /* If we could not find a page that does not require an fsync()
- ** on the journal file then fsync the journal file. This is a
- ** very slow operation, so we work hard to avoid it. But sometimes
- ** it can't be helped.
- */
- if( pPg==0 ){
- int rc = syncJournal(pPager);
- if( rc!=0 ){
- sqlite3pager_rollback(pPager);
- return SQLITE_IOERR;
- }
- if( pPager->fullSync ){
- /* If in full-sync mode, write a new journal header into the
- ** journal file. This is done to avoid ever modifying a journal
- ** header that is involved in the rollback of pages that have
- ** already been written to the database (in case the header is
- ** trashed when the nRec field is updated).
- */
- pPager->nRec = 0;
- assert( pPager->journalOff > 0 );
- rc = writeJournalHdr(pPager);
- if( rc!=0 ){
- sqlite3pager_rollback(pPager);
- return SQLITE_IOERR;
- }
- }
- pPg = pPager->pFirst;
- }
- assert( pPg->nRef==0 );
-
- /* Write the page to the database file if it is dirty.
- */
- if( pPg->dirty ){
- assert( pPg->needSync==0 );
- pPg->pDirty = 0;
- rc = pager_write_pagelist( pPg );
- if( rc!=SQLITE_OK ){
- sqlite3pager_rollback(pPager);
- return SQLITE_IOERR;
- }
- }
- assert( pPg->dirty==0 );
-
- /* If the page we are recycling is marked as alwaysRollback, then
- ** set the global alwaysRollback flag, thus disabling the
- ** sqlite_dont_rollback() optimization for the rest of this transaction.
- ** It is necessary to do this because the page marked alwaysRollback
- ** might be reloaded at a later time but at that point we won't remember
- ** that is was marked alwaysRollback. This means that all pages must
- ** be marked as alwaysRollback from here on out.
- */
- if( pPg->alwaysRollback ){
- pPager->alwaysRollback = 1;
+ rc = pager_recycle(pPager, 1, &pPg);
+ if( rc!=SQLITE_OK ){
+ return rc;
}
-
- /* Unlink the old page from the free list and the hash table
- */
- unlinkPage(pPg);
- TEST_INCR(pPager->nOvfl);
+ assert(pPg) ;
}
pPg->pgno = pgno;
if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){
@@ -2498,49 +2755,62 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
}else{
page_remove_from_stmt_list(pPg);
}
- pPg->dirty = 0;
+ makeClean(pPg);
pPg->nRef = 1;
REFINFO(pPg);
+
pPager->nRef++;
- h = pager_hash(pgno);
- pPg->pNextHash = pPager->aHash[h];
- pPager->aHash[h] = pPg;
- if( pPg->pNextHash ){
- assert( pPg->pNextHash->pPrevHash==0 );
- pPg->pNextHash->pPrevHash = pPg;
- }
if( pPager->nExtra>0 ){
memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
}
- if( pPager->errMask!=0 ){
+ if( pPager->errCode ){
sqlite3pager_unref(PGHDR_TO_DATA(pPg));
- rc = pager_errcode(pPager);
+ rc = pPager->errCode;
return rc;
}
- if( sqlite3pager_pagecount(pPager)<(int)pgno ){
+
+ /* Populate the page with data, either by reading from the database
+ ** file, or by setting the entire page to zero.
+ */
+ if( sqlite3pager_pagecount(pPager)<(int)pgno || MEMDB ){
memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
}else{
- int rc;
assert( MEMDB==0 );
- rc = sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
+ rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize);
if( rc==SQLITE_OK ){
- rc = sqlite3OsRead(&pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize);
+ rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg),
+ pPager->pageSize);
}
TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
- CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
+ CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
if( rc!=SQLITE_OK ){
i64 fileSize;
- if( sqlite3OsFileSize(&pPager->fd,&fileSize)!=SQLITE_OK
- || fileSize>=pgno*pPager->pageSize ){
+ int rc2 = sqlite3OsFileSize(pPager->fd, &fileSize);
+ if( rc2!=SQLITE_OK || fileSize>=pgno*pPager->pageSize ){
+ /* An IO error occured in one of the the sqlite3OsSeek() or
+ ** sqlite3OsRead() calls above. */
+ pPg->pgno = 0;
sqlite3pager_unref(PGHDR_TO_DATA(pPg));
return rc;
}else{
+ clear_simulated_io_error();
memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
}
}else{
TEST_INCR(pPager->nRead);
}
}
+
+ /* Link the page into the page hash table */
+ h = pgno & (pPager->nHash-1);
+ assert( pgno!=0 );
+ pPg->pNextHash = pPager->aHash[h];
+ pPager->aHash[h] = pPg;
+ if( pPg->pNextHash ){
+ assert( pPg->pNextHash->pPrevHash==0 );
+ pPg->pNextHash->pPrevHash = pPg;
+ }
+
#ifdef SQLITE_CHECK_PAGES
pPg->pageHash = pager_pagehash(pPg);
#endif
@@ -2569,7 +2839,7 @@ void *sqlite3pager_lookup(Pager *pPager, Pgno pgno){
assert( pPager!=0 );
assert( pgno!=0 );
- if( pPager->errMask & ~(PAGER_ERR_FULL) ){
+ if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
return 0;
}
pPg = pager_lookup(pPager, pgno);
@@ -2651,23 +2921,24 @@ static int pager_open_journal(Pager *pPager){
rc = SQLITE_NOMEM;
goto failed_to_open_journal;
}
- rc = sqlite3OsOpenExclusive(pPager->zJournal, &pPager->jfd,pPager->tempFile);
+ rc = sqlite3OsOpenExclusive(pPager->zJournal, &pPager->jfd,
+ pPager->tempFile);
pPager->journalOff = 0;
pPager->setMaster = 0;
pPager->journalHdr = 0;
if( rc!=SQLITE_OK ){
goto failed_to_open_journal;
}
- SET_FULLSYNC(pPager->jfd, pPager->fullSync);
- SET_FULLSYNC(pPager->fd, pPager->fullSync);
- sqlite3OsOpenDirectory(pPager->zDirectory, &pPager->jfd);
+ sqlite3OsSetFullSync(pPager->jfd, pPager->full_fsync);
+ sqlite3OsSetFullSync(pPager->fd, pPager->full_fsync);
+ sqlite3OsOpenDirectory(pPager->jfd, pPager->zDirectory);
pPager->journalOpen = 1;
pPager->journalStarted = 0;
pPager->needSync = 0;
pPager->alwaysRollback = 0;
pPager->nRec = 0;
- if( pPager->errMask!=0 ){
- rc = pager_errcode(pPager);
+ if( pPager->errCode ){
+ rc = pPager->errCode;
goto failed_to_open_journal;
}
pPager->origDbSize = pPager->dbSize;
@@ -2677,7 +2948,7 @@ static int pager_open_journal(Pager *pPager){
if( pPager->stmtAutoopen && rc==SQLITE_OK ){
rc = sqlite3pager_stmt_begin(pPager);
}
- if( rc!=SQLITE_OK ){
+ if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
rc = pager_unwritelock(pPager);
if( rc==SQLITE_OK ){
rc = SQLITE_FULL;
@@ -2688,8 +2959,17 @@ static int pager_open_journal(Pager *pPager){
failed_to_open_journal:
sqliteFree(pPager->aInJournal);
pPager->aInJournal = 0;
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
- pPager->state = PAGER_UNLOCK;
+ if( rc==SQLITE_NOMEM ){
+ /* If this was a malloc() failure, then we will not be closing the pager
+ ** file. So delete any journal file we may have just created. Otherwise,
+ ** the system will get confused, we have a read-lock on the file and a
+ ** mysterious journal has appeared in the filesystem.
+ */
+ sqlite3OsDelete(pPager->zJournal);
+ }else{
+ sqlite3OsUnlock(pPager->fd, NO_LOCK);
+ pPager->state = PAGER_UNLOCK;
+ }
return rc;
}
@@ -2732,7 +3012,7 @@ int sqlite3pager_begin(void *pData, int exFlag){
pPager->state = PAGER_EXCLUSIVE;
pPager->origDbSize = pPager->dbSize;
}else{
- rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
+ rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK);
if( rc==SQLITE_OK ){
pPager->state = PAGER_RESERVED;
if( exFlag ){
@@ -2753,6 +3033,42 @@ int sqlite3pager_begin(void *pData, int exFlag){
}
/*
+** Make a page dirty. Set its dirty flag and add it to the dirty
+** page list.
+*/
+static void makeDirty(PgHdr *pPg){
+ if( pPg->dirty==0 ){
+ Pager *pPager = pPg->pPager;
+ pPg->dirty = 1;
+ pPg->pDirty = pPager->pDirty;
+ if( pPager->pDirty ){
+ pPager->pDirty->pPrevDirty = pPg;
+ }
+ pPg->pPrevDirty = 0;
+ pPager->pDirty = pPg;
+ }
+}
+
+/*
+** Make a page clean. Clear its dirty bit and remove it from the
+** dirty page list.
+*/
+static void makeClean(PgHdr *pPg){
+ if( pPg->dirty ){
+ pPg->dirty = 0;
+ if( pPg->pDirty ){
+ pPg->pDirty->pPrevDirty = pPg->pPrevDirty;
+ }
+ if( pPg->pPrevDirty ){
+ pPg->pPrevDirty->pDirty = pPg->pDirty;
+ }else{
+ pPg->pPager->pDirty = pPg->pDirty;
+ }
+ }
+}
+
+
+/*
** Mark a data page as writeable. The page is written into the journal
** if it is not there already. This routine must be called before making
** changes to a page.
@@ -2776,8 +3092,8 @@ int sqlite3pager_write(void *pData){
/* Check for errors
*/
- if( pPager->errMask ){
- return pager_errcode(pPager);
+ if( pPager->errCode ){
+ return pPager->errCode;
}
if( pPager->readOnly ){
return SQLITE_PERM;
@@ -2790,7 +3106,7 @@ int sqlite3pager_write(void *pData){
/* Mark the page as dirty. If the page has already been written
** to the journal then we can return right away.
*/
- pPg->dirty = 1;
+ makeDirty(pPg);
if( pPg->inJournal && (pPg->inStmt || pPager->stmtInUse==0) ){
pPager->dirtyCache = 1;
}else{
@@ -2822,7 +3138,6 @@ int sqlite3pager_write(void *pData){
if( !pPg->inJournal && (pPager->useJournal || MEMDB) ){
if( (int)pPg->pgno <= pPager->origDbSize ){
int szPg;
- u32 saved;
if( MEMDB ){
PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
TRACE3("JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
@@ -2832,28 +3147,33 @@ int sqlite3pager_write(void *pData){
memcpy(pHist->pOrig, PGHDR_TO_DATA(pPg), pPager->pageSize);
}
}else{
- u32 cksum;
+ u32 cksum, saved;
+ char *pData2, *pEnd;
/* We should never write to the journal file the page that
** contains the database locks. The following assert verifies
** that we do not. */
assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
- CODEC(pPager, pData, pPg->pgno, 7);
- cksum = pager_cksum(pPager, pPg->pgno, pData);
- saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager);
- store32bits(cksum, pPg, pPager->pageSize);
+ pData2 = CODEC2(pPager, pData, pPg->pgno, 7);
+ cksum = pager_cksum(pPager, (u8*)pData2);
+ pEnd = pData2 + pPager->pageSize;
+ pData2 -= 4;
+ saved = *(u32*)pEnd;
+ put32bits(pEnd, cksum);
szPg = pPager->pageSize+8;
- store32bits(pPg->pgno, pPg, -4);
- rc = sqlite3OsWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
+ put32bits(pData2, pPg->pgno);
+ rc = sqlite3OsWrite(pPager->jfd, pData2, szPg);
pPager->journalOff += szPg;
TRACE4("JOURNAL %d page %d needSync=%d\n",
PAGERID(pPager), pPg->pgno, pPg->needSync);
- CODEC(pPager, pData, pPg->pgno, 0);
- *(u32*)PGHDR_TO_EXTRA(pPg, pPager) = saved;
+ *(u32*)pEnd = saved;
+
+ /* An error has occured writing to the journal file. The
+ ** transaction will be rolled back by the layer above.
+ */
if( rc!=SQLITE_OK ){
- sqlite3pager_rollback(pPager);
- pPager->errMask |= PAGER_ERR_FULL;
return rc;
}
+
pPager->nRec++;
assert( pPager->aInJournal!=0 );
pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
@@ -2890,14 +3210,11 @@ int sqlite3pager_write(void *pData){
}
TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
}else{
- store32bits(pPg->pgno, pPg, -4);
- CODEC(pPager, pData, pPg->pgno, 7);
- rc = sqlite3OsWrite(&pPager->stfd,((char*)pData)-4, pPager->pageSize+4);
+ char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7)-4;
+ put32bits(pData2, pPg->pgno);
+ rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize+4);
TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
- CODEC(pPager, pData, pPg->pgno, 0);
if( rc!=SQLITE_OK ){
- sqlite3pager_rollback(pPager);
- pPager->errMask |= PAGER_ERR_FULL;
return rc;
}
pPager->stmtNRec++;
@@ -2924,10 +3241,12 @@ int sqlite3pager_write(void *pData){
** to sqlite3pager_write(). In other words, return TRUE if it is ok
** to change the content of the page.
*/
+#ifndef NDEBUG
int sqlite3pager_iswriteable(void *pData){
PgHdr *pPg = DATA_TO_PGHDR(pData);
return pPg->dirty;
}
+#endif
#ifndef SQLITE_OMIT_VACUUM
/*
@@ -2980,8 +3299,9 @@ void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){
if( MEMDB ) return;
pPg = pager_lookup(pPager, pgno);
+ assert( pPg!=0 ); /* We never call _dont_write unless the page is in mem */
pPg->alwaysRollback = 1;
- if( pPg && pPg->dirty && !pPager->stmtInUse ){
+ if( pPg->dirty && !pPager->stmtInUse ){
if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSize<pPager->dbSize ){
/* If this pages is the last page in the file and the file has grown
** during the current transaction, then do NOT mark the page as clean.
@@ -2993,7 +3313,7 @@ void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){
*/
}else{
TRACE3("DONT_WRITE page %d of %d\n", pgno, PAGERID(pPager));
- pPg->dirty = 0;
+ makeClean(pPg);
#ifdef SQLITE_CHECK_PAGES
pPg->pageHash = pager_pagehash(pPg);
#endif
@@ -3032,20 +3352,6 @@ void sqlite3pager_dont_rollback(void *pData){
}
-#ifndef SQLITE_OMIT_MEMORYDB
-/*
-** Clear a PgHistory block
-*/
-static void clearHistory(PgHistory *pHist){
- sqliteFree(pHist->pOrig);
- sqliteFree(pHist->pStmt);
- pHist->pOrig = 0;
- pHist->pStmt = 0;
-}
-#else
-#define clearHistory(x)
-#endif
-
/*
** Commit all changes to the database and release the write lock.
**
@@ -3057,16 +3363,8 @@ int sqlite3pager_commit(Pager *pPager){
int rc;
PgHdr *pPg;
- if( pPager->errMask==PAGER_ERR_FULL ){
- rc = sqlite3pager_rollback(pPager);
- if( rc==SQLITE_OK ){
- rc = SQLITE_FULL;
- }
- return rc;
- }
- if( pPager->errMask!=0 ){
- rc = pager_errcode(pPager);
- return rc;
+ if( pPager->errCode ){
+ return pPager->errCode;
}
if( pPager->state<PAGER_RESERVED ){
return SQLITE_ERROR;
@@ -3079,9 +3377,11 @@ int sqlite3pager_commit(Pager *pPager){
pPg->dirty = 0;
pPg->inJournal = 0;
pPg->inStmt = 0;
+ pPg->needSync = 0;
pPg->pPrevStmt = pPg->pNextStmt = 0;
pPg = pPg->pDirty;
}
+ pPager->pDirty = 0;
#ifndef NDEBUG
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
@@ -3104,17 +3404,10 @@ int sqlite3pager_commit(Pager *pPager){
}
assert( pPager->journalOpen );
rc = sqlite3pager_sync(pPager, 0, 0);
- if( rc!=SQLITE_OK ){
- goto commit_abort;
+ if( rc==SQLITE_OK ){
+ rc = pager_unwritelock(pPager);
+ pPager->dbSize = -1;
}
- rc = pager_unwritelock(pPager);
- pPager->dbSize = -1;
- return rc;
-
- /* Jump here if anything goes wrong during the commit process.
- */
-commit_abort:
- sqlite3pager_rollback(pPager);
return rc;
}
@@ -3156,12 +3449,11 @@ int sqlite3pager_rollback(Pager *pPager){
p->inJournal = 0;
p->inStmt = 0;
p->pPrevStmt = p->pNextStmt = 0;
-
if( pPager->xReiniter ){
pPager->xReiniter(PGHDR_TO_DATA(p), pPager->pageSize);
}
-
}
+ pPager->pDirty = 0;
pPager->pStmt = 0;
pPager->dbSize = pPager->origDbSize;
memoryTruncate(pPager);
@@ -3176,11 +3468,11 @@ int sqlite3pager_rollback(Pager *pPager){
return rc;
}
- if( pPager->errMask!=0 && pPager->errMask!=PAGER_ERR_FULL ){
+ if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
if( pPager->state>=PAGER_EXCLUSIVE ){
pager_playback(pPager);
}
- return pager_errcode(pPager);
+ return pPager->errCode;
}
if( pPager->state==PAGER_RESERVED ){
int rc2;
@@ -3192,12 +3484,13 @@ int sqlite3pager_rollback(Pager *pPager){
}else{
rc = pager_playback(pPager);
}
- if( rc!=SQLITE_OK ){
- rc = SQLITE_CORRUPT_BKPT;
- pPager->errMask |= PAGER_ERR_CORRUPT;
- }
pPager->dbSize = -1;
- return rc;
+
+ /* If an error occurs during a ROLLBACK, we can no longer trust the pager
+ ** cache. So call pager_error() on the way out to make any error
+ ** persistent.
+ */
+ return pager_error(pPager, rc);
}
/*
@@ -3209,6 +3502,14 @@ int sqlite3pager_isreadonly(Pager *pPager){
}
/*
+** Return the number of references to the pager.
+*/
+int sqlite3pager_refcount(Pager *pPager){
+ return pPager->nRef;
+}
+
+#ifdef SQLITE_TEST
+/*
** This routine is used for testing and analysis only.
*/
int *sqlite3pager_stats(Pager *pPager){
@@ -3218,16 +3519,15 @@ int *sqlite3pager_stats(Pager *pPager){
a[2] = pPager->mxPage;
a[3] = pPager->dbSize;
a[4] = pPager->state;
- a[5] = pPager->errMask;
-#ifdef SQLITE_TEST
+ a[5] = pPager->errCode;
a[6] = pPager->nHit;
a[7] = pPager->nMiss;
a[8] = pPager->nOvfl;
a[9] = pPager->nRead;
a[10] = pPager->nWrite;
-#endif
return a;
}
+#endif
/*
** Set the statement rollback point.
@@ -3254,11 +3554,11 @@ int sqlite3pager_stmt_begin(Pager *pPager){
assert( pPager->journalOpen );
pPager->aInStmt = sqliteMalloc( pPager->dbSize/8 + 1 );
if( pPager->aInStmt==0 ){
- sqlite3OsLock(&pPager->fd, SHARED_LOCK);
+ /* sqlite3OsLock(pPager->fd, SHARED_LOCK); */
return SQLITE_NOMEM;
}
#ifndef NDEBUG
- rc = sqlite3OsFileSize(&pPager->jfd, &pPager->stmtJSize);
+ rc = sqlite3OsFileSize(pPager->jfd, &pPager->stmtJSize);
if( rc ) goto stmt_begin_failed;
assert( pPager->stmtJSize == pPager->journalOff );
#endif
@@ -3291,8 +3591,8 @@ int sqlite3pager_stmt_commit(Pager *pPager){
PgHdr *pPg, *pNext;
TRACE2("STMT-COMMIT %d\n", PAGERID(pPager));
if( !MEMDB ){
- sqlite3OsSeek(&pPager->stfd, 0);
- /* sqlite3OsTruncate(&pPager->stfd, 0); */
+ sqlite3OsSeek(pPager->stfd, 0);
+ /* sqlite3OsTruncate(pPager->stfd, 0); */
sqliteFree( pPager->aInStmt );
pPager->aInStmt = 0;
}
@@ -3380,7 +3680,7 @@ int sqlite3pager_nosync(Pager *pPager){
*/
void sqlite3pager_set_codec(
Pager *pPager,
- void (*xCodec)(void*,void*,Pgno,int),
+ void *(*xCodec)(void*,void*,Pgno,int),
void *pCodecArg
){
pPager->xCodec = xCodec;
@@ -3409,7 +3709,7 @@ static int pager_incr_changecounter(Pager *pPager){
/* Increment the value just read and write it back to byte 24. */
change_counter++;
- store32bits(change_counter, pPgHdr, 24);
+ put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);
/* Release the page reference. */
sqlite3pager_unref(pPage);
@@ -3495,10 +3795,12 @@ int sqlite3pager_sync(Pager *pPager, const char *zMaster, Pgno nTrunc){
/* Sync the database file. */
if( !pPager->noSync ){
- rc = sqlite3OsSync(&pPager->fd, 0);
+ rc = sqlite3OsSync(pPager->fd, 0);
}
pPager->state = PAGER_SYNCED;
+ }else if( MEMDB && nTrunc!=0 ){
+ rc = sqlite3pager_truncate(pPager, nTrunc);
}
sync_exit:
@@ -3553,7 +3855,7 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
if( pPgOld ){
assert( pPgOld->nRef==0 );
unlinkHashChain(pPager, pPgOld);
- pPgOld->dirty = 0;
+ makeClean(pPgOld);
if( pPgOld->needSync ){
assert( pPgOld->inJournal );
pPg->inJournal = 1;
@@ -3563,8 +3865,9 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
}
/* Change the page number for pPg and insert it into the new hash-chain. */
+ assert( pgno!=0 );
pPg->pgno = pgno;
- h = pager_hash(pgno);
+ h = pgno & (pPager->nHash-1);
if( pPager->aHash[h] ){
assert( pPager->aHash[h]->pPrevHash==0 );
pPager->aHash[h]->pPrevHash = pPg;
@@ -3573,7 +3876,7 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
pPager->aHash[h] = pPg;
pPg->pPrevHash = 0;
- pPg->dirty = 1;
+ makeDirty(pPg);
pPager->dirtyCache = 1;
if( needSyncPgno ){
@@ -3594,7 +3897,7 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
pPager->needSync = 1;
DATA_TO_PGHDR(pNeedSync)->needSync = 1;
DATA_TO_PGHDR(pNeedSync)->inJournal = 1;
- DATA_TO_PGHDR(pNeedSync)->dirty = 1;
+ makeDirty(DATA_TO_PGHDR(pNeedSync));
sqlite3pager_unref(pNeedSync);
}
@@ -3609,11 +3912,7 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
** PENDING_LOCK, or EXCLUSIVE_LOCK.
*/
int sqlite3pager_lockstate(Pager *pPager){
-#ifdef OS_TEST
- return pPager->fd->fd.locktype;
-#else
- return pPager->fd.locktype;
-#endif
+ return sqlite3OsLockState(pPager->fd);
}
#endif
diff --git a/ext/pdo_sqlite/sqlite/src/pager.h b/ext/pdo_sqlite/sqlite/src/pager.h
index feba78a7ad..555e52a031 100644
--- a/ext/pdo_sqlite/sqlite/src/pager.h
+++ b/ext/pdo_sqlite/sqlite/src/pager.h
@@ -16,6 +16,9 @@
** @(#) $Id$
*/
+#ifndef _PAGER_H_
+#define _PAGER_H_
+
/*
** The default size of a database page.
*/
@@ -95,16 +98,18 @@ int sqlite3pager_stmt_commit(Pager*);
int sqlite3pager_stmt_rollback(Pager*);
void sqlite3pager_dont_rollback(void*);
void sqlite3pager_dont_write(Pager*, Pgno);
+int sqlite3pager_refcount(Pager*);
int *sqlite3pager_stats(Pager*);
-void sqlite3pager_set_safety_level(Pager*,int);
+void sqlite3pager_set_safety_level(Pager*,int,int);
const char *sqlite3pager_filename(Pager*);
const char *sqlite3pager_dirname(Pager*);
const char *sqlite3pager_journalname(Pager*);
int sqlite3pager_nosync(Pager*);
int sqlite3pager_rename(Pager*, const char *zNewName);
-void sqlite3pager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*);
+void sqlite3pager_set_codec(Pager*,void*(*)(void*,void*,Pgno,int),void*);
int sqlite3pager_movepage(Pager*,void*,Pgno);
int sqlite3pager_reset(Pager*);
+int sqlite3pager_release_memory(int);
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
int sqlite3pager_lockstate(Pager*);
@@ -114,3 +119,5 @@ int sqlite3pager_lockstate(Pager*);
void sqlite3pager_refdump(Pager*);
int pager3_refinfo_enable;
#endif
+
+#endif /* _PAGER_H_ */
diff --git a/ext/pdo_sqlite/sqlite/src/parse.c b/ext/pdo_sqlite/sqlite/src/parse.c
index 432a262fd4..3aa31ac144 100644
--- a/ext/pdo_sqlite/sqlite/src/parse.c
+++ b/ext/pdo_sqlite/sqlite/src/parse.c
@@ -4,7 +4,7 @@
/* First off, code is include which follows the "include" declaration
** in the input file. */
#include <stdio.h>
-#line 51 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 56 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
#include "sqliteInt.h"
#include "parse.h"
@@ -23,7 +23,7 @@ struct LimitVal {
** GLOB, NOT LIKE, and NOT GLOB operators.
*/
struct LikeOp {
- Token operator; /* "like" or "glob" or "regexp" */
+ Token eOperator; /* "like" or "glob" or "regexp" */
int not; /* True if the NOT keyword is present */
};
@@ -43,7 +43,7 @@ struct TrigEvent { int a; IdList * b; };
*/
struct AttachKey { int type; Token key; };
-#line 48 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 48 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
/* Next is all token values, in a form suitable for use by makeheaders.
** This section will be null unless lemon is run with the -m switch.
*/
@@ -93,25 +93,26 @@ struct AttachKey { int type; Token key; };
** defined, then do no error processing.
*/
#define YYCODETYPE unsigned char
-#define YYNOCODE 247
+#define YYNOCODE 248
#define YYACTIONTYPE unsigned short int
+#define YYWILDCARD 60
#define sqlite3ParserTOKENTYPE Token
typedef union {
sqlite3ParserTOKENTYPE yy0;
- struct TrigEvent yy30;
- Expr* yy62;
- SrcList* yy151;
- Token yy198;
- struct LimitVal yy220;
- struct LikeOp yy222;
- IdList* yy240;
- int yy280;
- struct {int value; int mask;} yy359;
- TriggerStep* yy360;
- struct AttachKey yy361;
- Select* yy375;
- ExprList* yy418;
- int yy493;
+ int yy46;
+ struct LikeOp yy72;
+ Expr* yy172;
+ ExprList* yy174;
+ Select* yy219;
+ struct LimitVal yy234;
+ TriggerStep* yy243;
+ struct TrigEvent yy370;
+ SrcList* yy373;
+ Expr * yy386;
+ struct {int value; int mask;} yy405;
+ Token yy410;
+ IdList* yy432;
+ int yy495;
} YYMINORTYPE;
#define YYSTACKDEPTH 100
#define sqlite3ParserARG_SDECL Parse *pParse;
@@ -119,9 +120,9 @@ typedef union {
#define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse
#define sqlite3ParserARG_STORE yypParser->pParse = pParse
#define YYNSTATE 581
-#define YYNRULE 311
-#define YYERRORSYMBOL 146
-#define YYERRSYMDT yy493
+#define YYNRULE 309
+#define YYERRORSYMBOL 139
+#define YYERRSYMDT yy495
#define YYFALLBACK 1
#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
@@ -175,487 +176,411 @@ typedef union {
** yy_default[] Default action for each state.
*/
static const YYACTIONTYPE yy_action[] = {
- /* 0 */ 286, 584, 113, 140, 142, 138, 144, 581, 150, 152,
- /* 10 */ 154, 156, 158, 160, 162, 164, 166, 168, 3, 577,
- /* 20 */ 740, 170, 178, 150, 152, 154, 156, 158, 160, 162,
- /* 30 */ 164, 166, 168, 158, 160, 162, 164, 166, 168, 135,
- /* 40 */ 97, 171, 181, 186, 191, 180, 185, 146, 148, 140,
- /* 50 */ 142, 138, 144, 51, 150, 152, 154, 156, 158, 160,
- /* 60 */ 162, 164, 166, 168, 16, 17, 18, 114, 7, 248,
- /* 70 */ 150, 152, 154, 156, 158, 160, 162, 164, 166, 168,
- /* 80 */ 13, 37, 362, 40, 59, 67, 69, 326, 357, 170,
- /* 90 */ 6, 5, 331, 95, 364, 359, 25, 374, 258, 893,
- /* 100 */ 1, 580, 514, 13, 4, 575, 33, 135, 97, 171,
- /* 110 */ 181, 186, 191, 180, 185, 146, 148, 140, 142, 138,
- /* 120 */ 144, 9, 150, 152, 154, 156, 158, 160, 162, 164,
- /* 130 */ 166, 168, 374, 136, 592, 80, 112, 99, 269, 34,
- /* 140 */ 32, 33, 132, 373, 115, 14, 15, 378, 333, 99,
- /* 150 */ 380, 387, 392, 13, 367, 370, 194, 170, 78, 500,
- /* 160 */ 525, 315, 395, 369, 375, 408, 10, 98, 14, 15,
- /* 170 */ 78, 200, 286, 864, 113, 135, 97, 171, 181, 186,
- /* 180 */ 191, 180, 185, 146, 148, 140, 142, 138, 144, 80,
- /* 190 */ 150, 152, 154, 156, 158, 160, 162, 164, 166, 168,
- /* 200 */ 104, 105, 106, 661, 496, 376, 374, 170, 467, 13,
- /* 210 */ 2, 28, 237, 4, 409, 33, 3, 577, 14, 15,
- /* 220 */ 51, 132, 133, 115, 241, 135, 97, 171, 181, 186,
- /* 230 */ 191, 180, 185, 146, 148, 140, 142, 138, 144, 114,
- /* 240 */ 150, 152, 154, 156, 158, 160, 162, 164, 166, 168,
- /* 250 */ 40, 59, 67, 69, 326, 357, 136, 44, 45, 501,
- /* 260 */ 473, 463, 359, 36, 361, 130, 128, 660, 275, 31,
- /* 270 */ 84, 99, 356, 378, 14, 15, 380, 387, 392, 52,
- /* 280 */ 170, 117, 122, 123, 113, 541, 369, 643, 395, 348,
- /* 290 */ 98, 54, 78, 200, 302, 57, 58, 819, 135, 97,
- /* 300 */ 171, 181, 186, 191, 180, 185, 146, 148, 140, 142,
- /* 310 */ 138, 144, 861, 150, 152, 154, 156, 158, 160, 162,
- /* 320 */ 164, 166, 168, 104, 105, 106, 817, 80, 48, 316,
- /* 330 */ 162, 164, 166, 168, 319, 277, 12, 49, 99, 303,
- /* 340 */ 283, 818, 99, 124, 304, 99, 241, 172, 593, 114,
- /* 350 */ 50, 193, 46, 378, 170, 13, 380, 387, 392, 78,
- /* 360 */ 260, 276, 47, 78, 200, 64, 78, 260, 395, 174,
- /* 370 */ 175, 221, 135, 97, 171, 181, 186, 191, 180, 185,
- /* 380 */ 146, 148, 140, 142, 138, 144, 199, 150, 152, 154,
- /* 390 */ 156, 158, 160, 162, 164, 166, 168, 173, 252, 261,
- /* 400 */ 120, 122, 123, 212, 170, 268, 254, 130, 128, 288,
- /* 410 */ 590, 176, 246, 187, 192, 414, 195, 241, 197, 198,
- /* 420 */ 14, 15, 135, 97, 171, 181, 186, 191, 180, 185,
- /* 430 */ 146, 148, 140, 142, 138, 144, 433, 150, 152, 154,
- /* 440 */ 156, 158, 160, 162, 164, 166, 168, 311, 99, 707,
- /* 450 */ 99, 422, 708, 417, 275, 81, 318, 598, 99, 219,
- /* 460 */ 13, 231, 124, 13, 176, 48, 187, 192, 20, 78,
- /* 470 */ 317, 78, 214, 195, 49, 197, 198, 462, 170, 78,
- /* 480 */ 200, 116, 27, 13, 410, 113, 591, 50, 80, 225,
- /* 490 */ 195, 11, 197, 198, 506, 235, 135, 97, 171, 181,
- /* 500 */ 186, 191, 180, 185, 146, 148, 140, 142, 138, 144,
- /* 510 */ 80, 150, 152, 154, 156, 158, 160, 162, 164, 166,
- /* 520 */ 168, 277, 215, 324, 606, 14, 15, 301, 14, 15,
- /* 530 */ 512, 13, 508, 240, 196, 486, 195, 685, 197, 198,
- /* 540 */ 22, 834, 445, 331, 462, 170, 444, 276, 14, 15,
- /* 550 */ 114, 468, 278, 394, 599, 280, 470, 288, 446, 680,
- /* 560 */ 13, 321, 404, 135, 97, 171, 181, 186, 191, 180,
- /* 570 */ 185, 146, 148, 140, 142, 138, 144, 80, 150, 152,
- /* 580 */ 154, 156, 158, 160, 162, 164, 166, 168, 74, 99,
- /* 590 */ 540, 366, 73, 99, 352, 289, 14, 15, 176, 333,
- /* 600 */ 187, 192, 486, 869, 359, 273, 283, 542, 543, 867,
- /* 610 */ 78, 500, 510, 170, 78, 323, 682, 176, 472, 187,
- /* 620 */ 192, 746, 118, 470, 119, 14, 15, 195, 346, 197,
- /* 630 */ 198, 135, 97, 171, 181, 186, 191, 180, 185, 146,
- /* 640 */ 148, 140, 142, 138, 144, 99, 150, 152, 154, 156,
- /* 650 */ 158, 160, 162, 164, 166, 168, 532, 334, 341, 343,
- /* 660 */ 841, 39, 195, 170, 197, 198, 78, 94, 124, 356,
- /* 670 */ 271, 353, 439, 441, 440, 544, 883, 428, 72, 862,
- /* 680 */ 288, 135, 97, 171, 181, 186, 191, 180, 185, 146,
- /* 690 */ 148, 140, 142, 138, 144, 13, 150, 152, 154, 156,
- /* 700 */ 158, 160, 162, 164, 166, 168, 195, 99, 197, 198,
- /* 710 */ 406, 330, 195, 170, 197, 198, 568, 405, 306, 195,
- /* 720 */ 42, 197, 198, 65, 195, 539, 197, 198, 78, 96,
- /* 730 */ 66, 135, 97, 171, 181, 186, 191, 180, 185, 146,
- /* 740 */ 148, 140, 142, 138, 144, 885, 150, 152, 154, 156,
- /* 750 */ 158, 160, 162, 164, 166, 168, 99, 740, 99, 298,
- /* 760 */ 14, 15, 272, 170, 13, 74, 572, 86, 600, 73,
- /* 770 */ 126, 127, 614, 709, 309, 478, 24, 78, 247, 78,
- /* 780 */ 111, 135, 97, 171, 181, 186, 191, 180, 185, 146,
- /* 790 */ 148, 140, 142, 138, 144, 99, 150, 152, 154, 156,
- /* 800 */ 158, 160, 162, 164, 166, 168, 99, 238, 113, 239,
- /* 810 */ 295, 26, 296, 170, 338, 337, 78, 137, 294, 320,
- /* 820 */ 347, 239, 348, 390, 211, 348, 30, 78, 139, 14,
- /* 830 */ 15, 135, 189, 171, 181, 186, 191, 180, 185, 146,
- /* 840 */ 148, 140, 142, 138, 144, 99, 150, 152, 154, 156,
- /* 850 */ 158, 160, 162, 164, 166, 168, 99, 80, 99, 372,
- /* 860 */ 399, 442, 348, 170, 298, 243, 78, 141, 363, 601,
- /* 870 */ 428, 437, 438, 114, 411, 269, 605, 78, 143, 78,
- /* 880 */ 145, 448, 97, 171, 181, 186, 191, 180, 185, 146,
- /* 890 */ 148, 140, 142, 138, 144, 99, 150, 152, 154, 156,
- /* 900 */ 158, 160, 162, 164, 166, 168, 99, 80, 99, 430,
- /* 910 */ 99, 296, 555, 170, 413, 856, 78, 147, 672, 457,
- /* 920 */ 352, 348, 298, 443, 465, 45, 35, 78, 149, 78,
- /* 930 */ 151, 78, 153, 171, 181, 186, 191, 180, 185, 146,
- /* 940 */ 148, 140, 142, 138, 144, 99, 150, 152, 154, 156,
- /* 950 */ 158, 160, 162, 164, 166, 168, 99, 459, 99, 29,
- /* 960 */ 79, 464, 183, 483, 71, 339, 78, 155, 709, 421,
- /* 970 */ 428, 79, 109, 99, 491, 71, 296, 78, 157, 78,
- /* 980 */ 159, 490, 243, 109, 99, 340, 99, 449, 857, 223,
- /* 990 */ 99, 460, 182, 709, 78, 161, 99, 349, 827, 136,
- /* 1000 */ 223, 99, 80, 201, 99, 78, 163, 78, 165, 507,
- /* 1010 */ 136, 78, 167, 42, 201, 38, 493, 78, 169, 569,
- /* 1020 */ 207, 205, 78, 177, 674, 78, 179, 477, 203, 76,
- /* 1030 */ 77, 207, 205, 98, 99, 84, 99, 42, 336, 203,
- /* 1040 */ 76, 77, 99, 43, 98, 41, 428, 79, 494, 80,
- /* 1050 */ 428, 71, 84, 99, 352, 78, 188, 78, 190, 109,
- /* 1060 */ 499, 428, 497, 78, 202, 60, 104, 105, 106, 107,
- /* 1070 */ 108, 209, 213, 99, 78, 204, 223, 104, 105, 106,
- /* 1080 */ 107, 108, 209, 213, 820, 509, 136, 53, 383, 511,
- /* 1090 */ 201, 99, 56, 61, 78, 206, 55, 428, 428, 889,
- /* 1100 */ 513, 99, 243, 99, 352, 99, 79, 207, 205, 312,
- /* 1110 */ 71, 99, 78, 208, 483, 203, 76, 77, 109, 533,
- /* 1120 */ 98, 497, 78, 220, 78, 222, 78, 232, 84, 99,
- /* 1130 */ 428, 353, 78, 234, 352, 223, 517, 521, 389, 99,
- /* 1140 */ 62, 530, 99, 64, 63, 136, 68, 529, 70, 201,
- /* 1150 */ 78, 236, 352, 104, 105, 106, 107, 108, 209, 213,
- /* 1160 */ 78, 249, 99, 78, 265, 877, 207, 205, 398, 527,
- /* 1170 */ 99, 615, 616, 313, 203, 76, 77, 99, 523, 98,
- /* 1180 */ 80, 353, 8, 78, 270, 99, 456, 19, 21, 23,
- /* 1190 */ 412, 78, 300, 75, 78, 310, 82, 84, 78, 365,
- /* 1200 */ 563, 83, 547, 99, 87, 553, 78, 393, 85, 557,
- /* 1210 */ 99, 353, 104, 105, 106, 107, 108, 209, 213, 99,
- /* 1220 */ 269, 536, 99, 467, 78, 434, 88, 266, 534, 353,
- /* 1230 */ 560, 78, 481, 566, 264, 89, 250, 90, 93, 91,
- /* 1240 */ 78, 485, 101, 78, 498, 92, 100, 102, 103, 110,
- /* 1250 */ 131, 121, 134, 125, 129, 168, 184, 242, 686, 687,
- /* 1260 */ 688, 210, 233, 218, 224, 216, 227, 226, 217, 229,
- /* 1270 */ 228, 230, 243, 251, 515, 519, 463, 245, 253, 244,
- /* 1280 */ 505, 257, 255, 256, 258, 84, 259, 262, 263, 239,
- /* 1290 */ 267, 279, 274, 281, 282, 299, 285, 292, 284, 287,
- /* 1300 */ 290, 293, 297, 305, 314, 291, 307, 322, 308, 325,
- /* 1310 */ 327, 345, 329, 328, 332, 350, 354, 330, 358, 335,
- /* 1320 */ 342, 379, 381, 382, 344, 351, 368, 385, 355, 371,
- /* 1330 */ 388, 360, 396, 397, 400, 401, 415, 54, 416, 386,
- /* 1340 */ 384, 391, 418, 402, 407, 419, 377, 420, 423, 424,
- /* 1350 */ 403, 426, 425, 427, 429, 435, 431, 849, 436, 854,
- /* 1360 */ 432, 855, 450, 447, 451, 452, 454, 453, 825, 455,
- /* 1370 */ 458, 826, 469, 461, 466, 747, 748, 848, 471, 464,
- /* 1380 */ 863, 480, 474, 475, 476, 482, 865, 479, 487, 484,
- /* 1390 */ 489, 488, 492, 866, 495, 868, 504, 679, 502, 681,
- /* 1400 */ 833, 875, 518, 503, 516, 739, 520, 524, 522, 742,
- /* 1410 */ 745, 531, 526, 835, 535, 528, 538, 537, 836, 837,
- /* 1420 */ 838, 839, 545, 546, 840, 550, 876, 556, 551, 878,
- /* 1430 */ 548, 549, 554, 879, 559, 882, 884, 562, 886, 561,
- /* 1440 */ 552, 558, 564, 567, 570, 565, 571, 887, 576, 574,
- /* 1450 */ 573, 888, 578, 559, 559, 579,
+ /* 0 */ 287, 67, 291, 69, 150, 168, 206, 431, 61, 61,
+ /* 10 */ 61, 61, 66, 63, 63, 63, 63, 64, 64, 65,
+ /* 20 */ 65, 65, 66, 441, 322, 164, 444, 450, 68, 63,
+ /* 30 */ 63, 63, 63, 64, 64, 65, 65, 65, 66, 64,
+ /* 40 */ 64, 65, 65, 65, 66, 60, 58, 295, 454, 455,
+ /* 50 */ 451, 451, 62, 62, 61, 61, 61, 61, 513, 63,
+ /* 60 */ 63, 63, 63, 64, 64, 65, 65, 65, 66, 287,
+ /* 70 */ 318, 67, 431, 69, 150, 79, 160, 114, 224, 314,
+ /* 80 */ 229, 315, 172, 249, 891, 120, 580, 515, 518, 2,
+ /* 90 */ 250, 566, 422, 35, 223, 444, 450, 528, 20, 57,
+ /* 100 */ 384, 381, 63, 63, 63, 63, 64, 64, 65, 65,
+ /* 110 */ 65, 66, 287, 473, 60, 58, 295, 454, 455, 451,
+ /* 120 */ 451, 62, 62, 61, 61, 61, 61, 389, 63, 63,
+ /* 130 */ 63, 63, 64, 64, 65, 65, 65, 66, 444, 450,
+ /* 140 */ 91, 311, 385, 480, 236, 383, 269, 204, 2, 83,
+ /* 150 */ 581, 384, 381, 470, 196, 439, 209, 60, 58, 295,
+ /* 160 */ 454, 455, 451, 451, 62, 62, 61, 61, 61, 61,
+ /* 170 */ 170, 63, 63, 63, 63, 64, 64, 65, 65, 65,
+ /* 180 */ 66, 287, 486, 439, 209, 132, 109, 270, 423, 443,
+ /* 190 */ 402, 281, 390, 391, 441, 517, 164, 318, 507, 67,
+ /* 200 */ 526, 69, 150, 562, 423, 143, 516, 444, 450, 145,
+ /* 210 */ 146, 578, 882, 373, 882, 511, 171, 156, 514, 422,
+ /* 220 */ 40, 337, 426, 19, 287, 140, 60, 58, 295, 454,
+ /* 230 */ 455, 451, 451, 62, 62, 61, 61, 61, 61, 380,
+ /* 240 */ 63, 63, 63, 63, 64, 64, 65, 65, 65, 66,
+ /* 250 */ 444, 450, 575, 404, 405, 428, 428, 428, 329, 332,
+ /* 260 */ 240, 545, 67, 468, 69, 150, 271, 287, 291, 60,
+ /* 270 */ 58, 295, 454, 455, 451, 451, 62, 62, 61, 61,
+ /* 280 */ 61, 61, 124, 63, 63, 63, 63, 64, 64, 65,
+ /* 290 */ 65, 65, 66, 444, 450, 401, 510, 389, 290, 544,
+ /* 300 */ 65, 65, 65, 66, 507, 389, 542, 405, 443, 294,
+ /* 310 */ 434, 435, 60, 58, 295, 454, 455, 451, 451, 62,
+ /* 320 */ 62, 61, 61, 61, 61, 206, 63, 63, 63, 63,
+ /* 330 */ 64, 64, 65, 65, 65, 66, 519, 514, 366, 287,
+ /* 340 */ 75, 426, 148, 490, 224, 314, 229, 315, 172, 249,
+ /* 350 */ 367, 265, 264, 1, 574, 286, 250, 389, 416, 445,
+ /* 360 */ 446, 206, 390, 391, 177, 444, 450, 340, 343, 344,
+ /* 370 */ 390, 391, 208, 357, 428, 428, 428, 360, 168, 345,
+ /* 380 */ 431, 448, 449, 78, 60, 58, 295, 454, 455, 451,
+ /* 390 */ 451, 62, 62, 61, 61, 61, 61, 476, 63, 63,
+ /* 400 */ 63, 63, 64, 64, 65, 65, 65, 66, 287, 447,
+ /* 410 */ 177, 561, 493, 340, 343, 344, 21, 318, 518, 318,
+ /* 420 */ 431, 318, 390, 391, 318, 345, 475, 400, 20, 563,
+ /* 430 */ 564, 489, 151, 177, 444, 450, 340, 343, 344, 422,
+ /* 440 */ 34, 422, 34, 422, 34, 431, 422, 34, 345, 192,
+ /* 450 */ 237, 147, 527, 60, 58, 295, 454, 455, 451, 451,
+ /* 460 */ 62, 62, 61, 61, 61, 61, 423, 63, 63, 63,
+ /* 470 */ 63, 64, 64, 65, 65, 65, 66, 287, 230, 348,
+ /* 480 */ 408, 512, 298, 423, 334, 431, 318, 206, 318, 296,
+ /* 490 */ 318, 208, 409, 154, 465, 9, 465, 458, 464, 389,
+ /* 500 */ 374, 465, 173, 444, 450, 410, 173, 406, 422, 40,
+ /* 510 */ 422, 48, 422, 48, 321, 434, 435, 407, 324, 475,
+ /* 520 */ 457, 457, 60, 58, 295, 454, 455, 451, 451, 62,
+ /* 530 */ 62, 61, 61, 61, 61, 459, 63, 63, 63, 63,
+ /* 540 */ 64, 64, 65, 65, 65, 66, 287, 318, 499, 238,
+ /* 550 */ 253, 480, 389, 338, 408, 149, 421, 306, 289, 307,
+ /* 560 */ 420, 389, 289, 389, 390, 391, 409, 250, 500, 422,
+ /* 570 */ 27, 155, 444, 450, 431, 422, 3, 208, 539, 410,
+ /* 580 */ 335, 328, 578, 881, 324, 881, 457, 457, 484, 423,
+ /* 590 */ 242, 60, 58, 295, 454, 455, 451, 451, 62, 62,
+ /* 600 */ 61, 61, 61, 61, 255, 63, 63, 63, 63, 64,
+ /* 610 */ 64, 65, 65, 65, 66, 287, 368, 390, 391, 488,
+ /* 620 */ 90, 299, 324, 575, 457, 457, 390, 391, 390, 391,
+ /* 630 */ 318, 525, 494, 318, 392, 393, 394, 518, 524, 431,
+ /* 640 */ 241, 444, 450, 183, 477, 181, 571, 20, 324, 297,
+ /* 650 */ 457, 457, 422, 28, 541, 422, 23, 505, 287, 339,
+ /* 660 */ 60, 58, 295, 454, 455, 451, 451, 62, 62, 61,
+ /* 670 */ 61, 61, 61, 318, 63, 63, 63, 63, 64, 64,
+ /* 680 */ 65, 65, 65, 66, 444, 450, 421, 535, 354, 535,
+ /* 690 */ 420, 259, 300, 505, 816, 422, 32, 74, 505, 76,
+ /* 700 */ 188, 287, 505, 60, 58, 295, 454, 455, 451, 451,
+ /* 710 */ 62, 62, 61, 61, 61, 61, 318, 63, 63, 63,
+ /* 720 */ 63, 64, 64, 65, 65, 65, 66, 444, 450, 174,
+ /* 730 */ 175, 176, 377, 216, 423, 480, 248, 301, 422, 53,
+ /* 740 */ 505, 505, 259, 259, 287, 259, 60, 70, 295, 454,
+ /* 750 */ 455, 451, 451, 62, 62, 61, 61, 61, 61, 365,
+ /* 760 */ 63, 63, 63, 63, 64, 64, 65, 65, 65, 66,
+ /* 770 */ 444, 450, 247, 319, 244, 302, 304, 248, 167, 156,
+ /* 780 */ 361, 248, 379, 260, 552, 259, 554, 287, 259, 219,
+ /* 790 */ 58, 295, 454, 455, 451, 451, 62, 62, 61, 61,
+ /* 800 */ 61, 61, 318, 63, 63, 63, 63, 64, 64, 65,
+ /* 810 */ 65, 65, 66, 444, 450, 484, 432, 484, 22, 248,
+ /* 820 */ 248, 207, 388, 364, 422, 24, 555, 364, 54, 556,
+ /* 830 */ 309, 119, 437, 437, 295, 454, 455, 451, 451, 62,
+ /* 840 */ 62, 61, 61, 61, 61, 318, 63, 63, 63, 63,
+ /* 850 */ 64, 64, 65, 65, 65, 66, 71, 325, 318, 4,
+ /* 860 */ 318, 537, 318, 293, 259, 536, 259, 422, 51, 318,
+ /* 870 */ 161, 320, 71, 325, 318, 4, 355, 356, 305, 293,
+ /* 880 */ 422, 96, 422, 93, 422, 98, 225, 320, 327, 217,
+ /* 890 */ 115, 422, 99, 218, 190, 318, 422, 110, 226, 443,
+ /* 900 */ 318, 259, 318, 417, 327, 272, 427, 372, 318, 5,
+ /* 910 */ 418, 318, 413, 414, 330, 443, 318, 422, 111, 73,
+ /* 920 */ 72, 197, 422, 16, 422, 97, 152, 71, 316, 317,
+ /* 930 */ 422, 33, 426, 422, 94, 73, 72, 487, 422, 52,
+ /* 940 */ 318, 200, 274, 71, 316, 317, 71, 325, 426, 4,
+ /* 950 */ 318, 206, 318, 293, 318, 423, 463, 318, 12, 179,
+ /* 960 */ 423, 320, 422, 112, 615, 428, 428, 428, 429, 430,
+ /* 970 */ 11, 323, 422, 113, 422, 25, 422, 36, 327, 422,
+ /* 980 */ 37, 428, 428, 428, 429, 430, 11, 498, 497, 443,
+ /* 990 */ 158, 18, 318, 423, 81, 220, 221, 222, 101, 182,
+ /* 1000 */ 482, 318, 169, 318, 491, 318, 12, 318, 440, 73,
+ /* 1010 */ 72, 202, 466, 276, 422, 26, 474, 71, 316, 317,
+ /* 1020 */ 277, 318, 426, 422, 38, 422, 39, 422, 41, 422,
+ /* 1030 */ 42, 318, 199, 423, 544, 503, 252, 124, 124, 198,
+ /* 1040 */ 318, 479, 201, 422, 43, 318, 483, 452, 318, 246,
+ /* 1050 */ 347, 318, 124, 422, 29, 428, 428, 428, 429, 430,
+ /* 1060 */ 11, 495, 422, 30, 496, 576, 318, 422, 44, 501,
+ /* 1070 */ 422, 45, 318, 422, 46, 520, 318, 533, 534, 318,
+ /* 1080 */ 540, 318, 124, 502, 185, 371, 273, 264, 422, 47,
+ /* 1090 */ 254, 288, 256, 257, 422, 31, 206, 258, 422, 10,
+ /* 1100 */ 352, 422, 49, 422, 50, 577, 548, 549, 169, 88,
+ /* 1110 */ 559, 263, 88, 359, 362, 573, 363, 285, 266, 267,
+ /* 1120 */ 376, 268, 551, 560, 275, 375, 278, 279, 231, 570,
+ /* 1130 */ 227, 142, 398, 326, 469, 436, 438, 472, 494, 159,
+ /* 1140 */ 504, 547, 506, 558, 387, 395, 342, 396, 397, 8,
+ /* 1150 */ 312, 313, 292, 416, 81, 403, 333, 232, 411, 80,
+ /* 1160 */ 228, 331, 419, 415, 56, 77, 210, 412, 239, 166,
+ /* 1170 */ 467, 211, 470, 471, 121, 82, 102, 336, 349, 282,
+ /* 1180 */ 508, 424, 521, 522, 529, 523, 351, 180, 233, 509,
+ /* 1190 */ 234, 184, 235, 283, 531, 425, 353, 85, 186, 117,
+ /* 1200 */ 358, 128, 369, 370, 308, 567, 568, 243, 543, 481,
+ /* 1210 */ 245, 212, 485, 189, 386, 569, 572, 129, 95, 214,
+ /* 1220 */ 215, 399, 550, 116, 130, 205, 55, 616, 131, 617,
+ /* 1230 */ 162, 163, 433, 134, 59, 213, 442, 557, 137, 100,
+ /* 1240 */ 138, 139, 453, 456, 460, 153, 165, 461, 261, 462,
+ /* 1250 */ 6, 122, 13, 12, 7, 532, 478, 123, 157, 492,
+ /* 1260 */ 103, 341, 89, 251, 104, 84, 105, 346, 226, 178,
+ /* 1270 */ 350, 141, 530, 125, 303, 169, 262, 187, 106, 126,
+ /* 1280 */ 538, 284, 546, 127, 191, 14, 194, 92, 17, 86,
+ /* 1290 */ 87, 193, 195, 133, 108, 553, 135, 565, 136, 15,
+ /* 1300 */ 107, 203, 378, 280, 144, 382, 558, 118, 579, 558,
+ /* 1310 */ 558, 310,
};
static const YYCODETYPE yy_lookahead[] = {
- /* 0 */ 28, 11, 30, 77, 78, 79, 80, 0, 82, 83,
- /* 10 */ 84, 85, 86, 87, 88, 89, 90, 91, 11, 12,
- /* 20 */ 11, 49, 81, 82, 83, 84, 85, 86, 87, 88,
- /* 30 */ 89, 90, 91, 86, 87, 88, 89, 90, 91, 67,
- /* 40 */ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
- /* 50 */ 78, 79, 80, 69, 82, 83, 84, 85, 86, 87,
- /* 60 */ 88, 89, 90, 91, 17, 18, 19, 95, 11, 29,
- /* 70 */ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
- /* 80 */ 30, 97, 98, 99, 100, 101, 102, 103, 104, 49,
- /* 90 */ 150, 151, 50, 53, 26, 111, 156, 155, 30, 147,
- /* 100 */ 148, 149, 162, 30, 152, 163, 164, 67, 68, 69,
- /* 110 */ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
- /* 120 */ 80, 153, 82, 83, 84, 85, 86, 87, 88, 89,
- /* 130 */ 90, 91, 155, 65, 11, 195, 28, 155, 129, 165,
- /* 140 */ 163, 164, 168, 169, 170, 95, 96, 97, 106, 155,
- /* 150 */ 100, 101, 102, 30, 86, 87, 162, 49, 176, 177,
- /* 160 */ 220, 88, 112, 95, 187, 188, 154, 99, 95, 96,
- /* 170 */ 176, 177, 28, 21, 30, 67, 68, 69, 70, 71,
- /* 180 */ 72, 73, 74, 75, 76, 77, 78, 79, 80, 195,
- /* 190 */ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
- /* 200 */ 132, 133, 134, 27, 222, 29, 155, 49, 56, 30,
- /* 210 */ 149, 160, 218, 152, 163, 164, 11, 12, 95, 96,
- /* 220 */ 69, 168, 169, 170, 230, 67, 68, 69, 70, 71,
- /* 230 */ 72, 73, 74, 75, 76, 77, 78, 79, 80, 95,
- /* 240 */ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
- /* 250 */ 99, 100, 101, 102, 103, 104, 65, 192, 193, 107,
- /* 260 */ 108, 109, 111, 174, 175, 86, 87, 27, 29, 29,
- /* 270 */ 118, 155, 183, 97, 95, 96, 100, 101, 102, 99,
- /* 280 */ 49, 171, 172, 173, 30, 106, 95, 27, 112, 29,
- /* 290 */ 99, 111, 176, 177, 162, 17, 18, 139, 67, 68,
- /* 300 */ 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
- /* 310 */ 79, 80, 15, 82, 83, 84, 85, 86, 87, 88,
- /* 320 */ 89, 90, 91, 132, 133, 134, 21, 195, 22, 27,
- /* 330 */ 88, 89, 90, 91, 218, 96, 155, 31, 155, 207,
- /* 340 */ 208, 21, 155, 233, 212, 155, 230, 49, 11, 95,
- /* 350 */ 44, 26, 46, 97, 49, 30, 100, 101, 102, 176,
- /* 360 */ 177, 122, 56, 176, 177, 105, 176, 177, 112, 71,
- /* 370 */ 72, 140, 67, 68, 69, 70, 71, 72, 73, 74,
- /* 380 */ 75, 76, 77, 78, 79, 80, 27, 82, 83, 84,
- /* 390 */ 85, 86, 87, 88, 89, 90, 91, 99, 215, 216,
- /* 400 */ 171, 172, 173, 27, 49, 218, 216, 86, 87, 168,
- /* 410 */ 11, 223, 224, 225, 226, 24, 114, 230, 116, 117,
- /* 420 */ 95, 96, 67, 68, 69, 70, 71, 72, 73, 74,
- /* 430 */ 75, 76, 77, 78, 79, 80, 139, 82, 83, 84,
- /* 440 */ 85, 86, 87, 88, 89, 90, 91, 206, 155, 27,
- /* 450 */ 155, 60, 27, 62, 29, 162, 27, 11, 155, 139,
- /* 460 */ 30, 141, 233, 30, 223, 22, 225, 226, 154, 176,
- /* 470 */ 177, 176, 177, 114, 31, 116, 117, 162, 49, 176,
- /* 480 */ 177, 26, 26, 30, 28, 30, 11, 44, 195, 46,
- /* 490 */ 114, 16, 116, 117, 24, 140, 67, 68, 69, 70,
- /* 500 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
- /* 510 */ 195, 82, 83, 84, 85, 86, 87, 88, 89, 90,
- /* 520 */ 91, 96, 227, 27, 11, 95, 96, 26, 95, 96,
- /* 530 */ 60, 30, 62, 230, 115, 220, 114, 118, 116, 117,
- /* 540 */ 154, 11, 32, 50, 162, 49, 36, 122, 95, 96,
- /* 550 */ 95, 236, 122, 178, 11, 122, 241, 168, 48, 11,
- /* 560 */ 30, 88, 69, 67, 68, 69, 70, 71, 72, 73,
- /* 570 */ 74, 75, 76, 77, 78, 79, 80, 195, 82, 83,
- /* 580 */ 84, 85, 86, 87, 88, 89, 90, 91, 115, 155,
- /* 590 */ 155, 27, 119, 155, 155, 206, 95, 96, 223, 106,
- /* 600 */ 225, 226, 220, 11, 111, 207, 208, 172, 173, 11,
- /* 610 */ 176, 177, 142, 49, 176, 177, 11, 223, 236, 225,
- /* 620 */ 226, 11, 27, 241, 29, 95, 96, 114, 189, 116,
- /* 630 */ 117, 67, 68, 69, 70, 71, 72, 73, 74, 75,
- /* 640 */ 76, 77, 78, 79, 80, 155, 82, 83, 84, 85,
- /* 650 */ 86, 87, 88, 89, 90, 91, 222, 107, 108, 109,
- /* 660 */ 11, 175, 114, 49, 116, 117, 176, 177, 233, 183,
- /* 670 */ 29, 232, 107, 108, 109, 26, 11, 155, 26, 15,
- /* 680 */ 168, 67, 68, 69, 70, 71, 72, 73, 74, 75,
- /* 690 */ 76, 77, 78, 79, 80, 30, 82, 83, 84, 85,
- /* 700 */ 86, 87, 88, 89, 90, 91, 114, 155, 116, 117,
- /* 710 */ 183, 184, 114, 49, 116, 117, 194, 190, 206, 114,
- /* 720 */ 106, 116, 117, 34, 114, 76, 116, 117, 176, 177,
- /* 730 */ 41, 67, 68, 69, 70, 71, 72, 73, 74, 75,
- /* 740 */ 76, 77, 78, 79, 80, 11, 82, 83, 84, 85,
- /* 750 */ 86, 87, 88, 89, 90, 91, 155, 11, 155, 155,
- /* 760 */ 95, 96, 121, 49, 30, 115, 244, 198, 11, 119,
- /* 770 */ 132, 133, 120, 28, 205, 29, 154, 176, 177, 176,
- /* 780 */ 177, 67, 68, 69, 70, 71, 72, 73, 74, 75,
- /* 790 */ 76, 77, 78, 79, 80, 155, 82, 83, 84, 85,
- /* 800 */ 86, 87, 88, 89, 90, 91, 155, 27, 30, 29,
- /* 810 */ 27, 157, 29, 49, 98, 99, 176, 177, 214, 27,
- /* 820 */ 27, 29, 29, 27, 162, 29, 27, 176, 177, 95,
- /* 830 */ 96, 67, 68, 69, 70, 71, 72, 73, 74, 75,
- /* 840 */ 76, 77, 78, 79, 80, 155, 82, 83, 84, 85,
- /* 850 */ 86, 87, 88, 89, 90, 91, 155, 195, 155, 167,
- /* 860 */ 27, 52, 29, 49, 155, 120, 176, 177, 176, 11,
- /* 870 */ 155, 58, 59, 95, 162, 129, 11, 176, 177, 176,
- /* 880 */ 177, 25, 68, 69, 70, 71, 72, 73, 74, 75,
- /* 890 */ 76, 77, 78, 79, 80, 155, 82, 83, 84, 85,
- /* 900 */ 86, 87, 88, 89, 90, 91, 155, 195, 155, 194,
- /* 910 */ 155, 29, 134, 49, 158, 106, 176, 177, 11, 27,
- /* 920 */ 155, 29, 155, 214, 192, 193, 166, 176, 177, 176,
- /* 930 */ 177, 176, 177, 69, 70, 71, 72, 73, 74, 75,
- /* 940 */ 76, 77, 78, 79, 80, 155, 82, 83, 84, 85,
- /* 950 */ 86, 87, 88, 89, 90, 91, 155, 101, 155, 161,
- /* 960 */ 26, 67, 69, 155, 30, 37, 176, 177, 106, 162,
- /* 970 */ 155, 26, 38, 155, 27, 30, 29, 176, 177, 176,
- /* 980 */ 177, 214, 120, 38, 155, 57, 155, 231, 106, 55,
- /* 990 */ 155, 235, 99, 11, 176, 177, 155, 232, 142, 65,
- /* 1000 */ 55, 155, 195, 69, 155, 176, 177, 176, 177, 194,
- /* 1010 */ 65, 176, 177, 106, 69, 155, 162, 176, 177, 64,
- /* 1020 */ 86, 87, 176, 177, 130, 176, 177, 219, 94, 95,
- /* 1030 */ 96, 86, 87, 99, 155, 118, 155, 106, 110, 94,
- /* 1040 */ 95, 96, 155, 39, 99, 178, 155, 26, 131, 195,
- /* 1050 */ 155, 30, 118, 155, 155, 176, 177, 176, 177, 38,
- /* 1060 */ 27, 155, 29, 176, 177, 51, 132, 133, 134, 135,
- /* 1070 */ 136, 137, 138, 155, 176, 177, 55, 132, 133, 134,
- /* 1080 */ 135, 136, 137, 138, 139, 194, 65, 178, 189, 194,
- /* 1090 */ 69, 155, 47, 179, 176, 177, 186, 155, 155, 144,
- /* 1100 */ 194, 155, 120, 155, 155, 155, 26, 86, 87, 88,
- /* 1110 */ 30, 155, 176, 177, 155, 94, 95, 96, 38, 27,
- /* 1120 */ 99, 29, 176, 177, 176, 177, 176, 177, 118, 155,
- /* 1130 */ 155, 232, 176, 177, 155, 55, 194, 194, 189, 155,
- /* 1140 */ 178, 131, 155, 105, 180, 65, 178, 162, 26, 69,
- /* 1150 */ 176, 177, 155, 132, 133, 134, 135, 136, 137, 138,
- /* 1160 */ 176, 177, 155, 176, 177, 11, 86, 87, 189, 194,
- /* 1170 */ 155, 120, 120, 155, 94, 95, 96, 155, 219, 99,
- /* 1180 */ 195, 232, 15, 176, 177, 155, 189, 20, 21, 22,
- /* 1190 */ 23, 176, 177, 197, 176, 177, 196, 118, 176, 177,
- /* 1200 */ 33, 195, 35, 155, 199, 51, 176, 177, 197, 42,
- /* 1210 */ 155, 232, 132, 133, 134, 135, 136, 137, 138, 155,
- /* 1220 */ 129, 54, 155, 56, 176, 177, 200, 126, 61, 232,
- /* 1230 */ 63, 176, 177, 66, 127, 201, 124, 202, 128, 203,
- /* 1240 */ 176, 177, 155, 176, 177, 204, 120, 120, 155, 26,
- /* 1250 */ 168, 27, 27, 234, 234, 91, 99, 155, 118, 118,
- /* 1260 */ 118, 26, 139, 21, 26, 228, 193, 27, 229, 155,
- /* 1270 */ 29, 27, 120, 125, 107, 108, 109, 159, 29, 155,
- /* 1280 */ 113, 104, 217, 179, 30, 118, 167, 217, 179, 29,
- /* 1290 */ 125, 155, 209, 155, 122, 106, 159, 123, 155, 155,
- /* 1300 */ 210, 26, 155, 27, 120, 211, 210, 27, 211, 178,
- /* 1310 */ 155, 26, 182, 181, 155, 217, 217, 184, 167, 185,
- /* 1320 */ 185, 155, 51, 26, 185, 179, 176, 27, 179, 176,
- /* 1330 */ 26, 186, 51, 26, 103, 155, 155, 111, 159, 178,
- /* 1340 */ 180, 178, 155, 181, 188, 159, 188, 28, 155, 159,
- /* 1350 */ 182, 238, 237, 106, 159, 45, 239, 15, 43, 106,
- /* 1360 */ 240, 106, 142, 52, 155, 159, 155, 106, 11, 26,
- /* 1370 */ 178, 142, 21, 15, 191, 130, 130, 11, 11, 67,
- /* 1380 */ 21, 76, 191, 155, 110, 200, 11, 155, 130, 76,
- /* 1390 */ 26, 155, 221, 11, 26, 11, 200, 11, 121, 11,
- /* 1400 */ 11, 11, 200, 155, 121, 11, 191, 200, 110, 11,
- /* 1410 */ 11, 26, 130, 11, 155, 221, 159, 155, 11, 11,
- /* 1420 */ 11, 11, 155, 27, 11, 28, 11, 40, 155, 11,
- /* 1430 */ 242, 168, 168, 11, 155, 11, 11, 159, 11, 155,
- /* 1440 */ 243, 242, 155, 24, 143, 159, 155, 11, 145, 245,
- /* 1450 */ 144, 11, 13, 246, 246, 14,
+ /* 0 */ 16, 218, 16, 220, 221, 21, 111, 23, 70, 71,
+ /* 10 */ 72, 73, 84, 75, 76, 77, 78, 79, 80, 81,
+ /* 20 */ 82, 83, 84, 162, 163, 164, 42, 43, 74, 75,
+ /* 30 */ 76, 77, 78, 79, 80, 81, 82, 83, 84, 79,
+ /* 40 */ 80, 81, 82, 83, 84, 61, 62, 63, 64, 65,
+ /* 50 */ 66, 67, 68, 69, 70, 71, 72, 73, 170, 75,
+ /* 60 */ 76, 77, 78, 79, 80, 81, 82, 83, 84, 16,
+ /* 70 */ 148, 218, 88, 220, 221, 22, 90, 91, 92, 93,
+ /* 80 */ 94, 95, 96, 97, 140, 141, 142, 170, 148, 145,
+ /* 90 */ 104, 238, 170, 171, 154, 42, 43, 157, 158, 46,
+ /* 100 */ 1, 2, 75, 76, 77, 78, 79, 80, 81, 82,
+ /* 110 */ 83, 84, 16, 22, 61, 62, 63, 64, 65, 66,
+ /* 120 */ 67, 68, 69, 70, 71, 72, 73, 23, 75, 76,
+ /* 130 */ 77, 78, 79, 80, 81, 82, 83, 84, 42, 43,
+ /* 140 */ 44, 143, 144, 162, 222, 142, 14, 149, 145, 19,
+ /* 150 */ 0, 1, 2, 23, 156, 79, 80, 61, 62, 63,
+ /* 160 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+ /* 170 */ 156, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ /* 180 */ 84, 16, 201, 79, 80, 53, 21, 55, 190, 59,
+ /* 190 */ 169, 159, 88, 89, 162, 163, 164, 148, 177, 218,
+ /* 200 */ 182, 220, 221, 99, 190, 114, 161, 42, 43, 79,
+ /* 210 */ 80, 19, 20, 215, 22, 170, 202, 203, 88, 170,
+ /* 220 */ 171, 207, 92, 19, 16, 21, 61, 62, 63, 64,
+ /* 230 */ 65, 66, 67, 68, 69, 70, 71, 72, 73, 241,
+ /* 240 */ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ /* 250 */ 42, 43, 60, 186, 187, 125, 126, 127, 187, 210,
+ /* 260 */ 211, 11, 218, 219, 220, 221, 134, 16, 16, 61,
+ /* 270 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+ /* 280 */ 72, 73, 22, 75, 76, 77, 78, 79, 80, 81,
+ /* 290 */ 82, 83, 84, 42, 43, 168, 169, 23, 151, 49,
+ /* 300 */ 81, 82, 83, 84, 177, 23, 186, 187, 59, 165,
+ /* 310 */ 166, 167, 61, 62, 63, 64, 65, 66, 67, 68,
+ /* 320 */ 69, 70, 71, 72, 73, 111, 75, 76, 77, 78,
+ /* 330 */ 79, 80, 81, 82, 83, 84, 182, 88, 124, 16,
+ /* 340 */ 132, 92, 22, 20, 92, 93, 94, 95, 96, 97,
+ /* 350 */ 100, 101, 102, 19, 244, 245, 104, 23, 98, 42,
+ /* 360 */ 43, 111, 88, 89, 90, 42, 43, 93, 94, 95,
+ /* 370 */ 88, 89, 228, 226, 125, 126, 127, 230, 21, 105,
+ /* 380 */ 23, 64, 65, 132, 61, 62, 63, 64, 65, 66,
+ /* 390 */ 67, 68, 69, 70, 71, 72, 73, 115, 75, 76,
+ /* 400 */ 77, 78, 79, 80, 81, 82, 83, 84, 16, 92,
+ /* 410 */ 90, 148, 20, 93, 94, 95, 19, 148, 148, 148,
+ /* 420 */ 23, 148, 88, 89, 148, 105, 22, 157, 158, 166,
+ /* 430 */ 167, 20, 156, 90, 42, 43, 93, 94, 95, 170,
+ /* 440 */ 171, 170, 171, 170, 171, 88, 170, 171, 105, 156,
+ /* 450 */ 148, 181, 182, 61, 62, 63, 64, 65, 66, 67,
+ /* 460 */ 68, 69, 70, 71, 72, 73, 190, 75, 76, 77,
+ /* 470 */ 78, 79, 80, 81, 82, 83, 84, 16, 191, 16,
+ /* 480 */ 12, 20, 213, 190, 213, 88, 148, 111, 148, 213,
+ /* 490 */ 148, 228, 24, 89, 225, 19, 225, 20, 225, 23,
+ /* 500 */ 124, 225, 43, 42, 43, 37, 43, 39, 170, 171,
+ /* 510 */ 170, 171, 170, 171, 165, 166, 167, 49, 107, 115,
+ /* 520 */ 109, 110, 61, 62, 63, 64, 65, 66, 67, 68,
+ /* 530 */ 69, 70, 71, 72, 73, 20, 75, 76, 77, 78,
+ /* 540 */ 79, 80, 81, 82, 83, 84, 16, 148, 30, 211,
+ /* 550 */ 20, 162, 23, 148, 12, 156, 108, 217, 99, 217,
+ /* 560 */ 112, 23, 99, 23, 88, 89, 24, 104, 50, 170,
+ /* 570 */ 171, 148, 42, 43, 23, 170, 171, 228, 18, 37,
+ /* 580 */ 148, 39, 19, 20, 107, 22, 109, 110, 148, 190,
+ /* 590 */ 201, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ /* 600 */ 70, 71, 72, 73, 14, 75, 76, 77, 78, 79,
+ /* 610 */ 80, 81, 82, 83, 84, 16, 56, 88, 89, 81,
+ /* 620 */ 21, 103, 107, 60, 109, 110, 88, 89, 88, 89,
+ /* 630 */ 148, 177, 178, 148, 7, 8, 9, 148, 184, 88,
+ /* 640 */ 148, 42, 43, 53, 115, 55, 157, 158, 107, 209,
+ /* 650 */ 109, 110, 170, 171, 94, 170, 171, 148, 16, 81,
+ /* 660 */ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+ /* 670 */ 71, 72, 73, 148, 75, 76, 77, 78, 79, 80,
+ /* 680 */ 81, 82, 83, 84, 42, 43, 108, 100, 101, 102,
+ /* 690 */ 112, 148, 183, 148, 134, 170, 171, 131, 148, 133,
+ /* 700 */ 156, 16, 148, 61, 62, 63, 64, 65, 66, 67,
+ /* 710 */ 68, 69, 70, 71, 72, 73, 148, 75, 76, 77,
+ /* 720 */ 78, 79, 80, 81, 82, 83, 84, 42, 43, 100,
+ /* 730 */ 101, 102, 189, 183, 190, 162, 227, 183, 170, 171,
+ /* 740 */ 148, 148, 148, 148, 16, 148, 61, 62, 63, 64,
+ /* 750 */ 65, 66, 67, 68, 69, 70, 71, 72, 73, 215,
+ /* 760 */ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ /* 770 */ 42, 43, 227, 148, 201, 183, 183, 227, 202, 203,
+ /* 780 */ 236, 227, 239, 189, 189, 148, 189, 16, 148, 146,
+ /* 790 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+ /* 800 */ 72, 73, 148, 75, 76, 77, 78, 79, 80, 81,
+ /* 810 */ 82, 83, 84, 42, 43, 148, 20, 148, 22, 227,
+ /* 820 */ 227, 193, 148, 148, 170, 171, 189, 148, 200, 189,
+ /* 830 */ 242, 243, 125, 126, 63, 64, 65, 66, 67, 68,
+ /* 840 */ 69, 70, 71, 72, 73, 148, 75, 76, 77, 78,
+ /* 850 */ 79, 80, 81, 82, 83, 84, 16, 17, 148, 19,
+ /* 860 */ 148, 25, 148, 23, 148, 29, 148, 170, 171, 148,
+ /* 870 */ 19, 31, 16, 17, 148, 19, 209, 41, 209, 23,
+ /* 880 */ 170, 171, 170, 171, 170, 171, 92, 31, 48, 214,
+ /* 890 */ 148, 170, 171, 214, 22, 148, 170, 171, 104, 59,
+ /* 900 */ 148, 148, 148, 27, 48, 189, 148, 189, 148, 192,
+ /* 910 */ 34, 148, 7, 8, 148, 59, 148, 170, 171, 79,
+ /* 920 */ 80, 156, 170, 171, 170, 171, 156, 87, 88, 89,
+ /* 930 */ 170, 171, 92, 170, 171, 79, 80, 81, 170, 171,
+ /* 940 */ 148, 19, 189, 87, 88, 89, 16, 17, 92, 19,
+ /* 950 */ 148, 111, 148, 23, 148, 190, 20, 148, 22, 156,
+ /* 960 */ 190, 31, 170, 171, 113, 125, 126, 127, 128, 129,
+ /* 970 */ 130, 16, 170, 171, 170, 171, 170, 171, 48, 170,
+ /* 980 */ 171, 125, 126, 127, 128, 129, 130, 91, 92, 59,
+ /* 990 */ 5, 69, 148, 190, 122, 10, 11, 12, 13, 156,
+ /* 1000 */ 20, 148, 22, 148, 20, 148, 22, 148, 162, 79,
+ /* 1010 */ 80, 26, 148, 28, 170, 171, 204, 87, 88, 89,
+ /* 1020 */ 35, 148, 92, 170, 171, 170, 171, 170, 171, 170,
+ /* 1030 */ 171, 148, 47, 190, 49, 20, 20, 22, 22, 54,
+ /* 1040 */ 148, 148, 57, 170, 171, 148, 148, 92, 148, 148,
+ /* 1050 */ 20, 148, 22, 170, 171, 125, 126, 127, 128, 129,
+ /* 1060 */ 130, 148, 170, 171, 179, 20, 148, 170, 171, 179,
+ /* 1070 */ 170, 171, 148, 170, 171, 148, 148, 51, 52, 148,
+ /* 1080 */ 20, 148, 22, 179, 232, 100, 101, 102, 170, 171,
+ /* 1090 */ 148, 106, 148, 148, 170, 171, 111, 148, 170, 171,
+ /* 1100 */ 233, 170, 171, 170, 171, 60, 20, 20, 22, 22,
+ /* 1110 */ 20, 148, 22, 148, 148, 20, 148, 22, 148, 148,
+ /* 1120 */ 135, 148, 148, 148, 148, 148, 148, 148, 194, 148,
+ /* 1130 */ 173, 192, 150, 224, 173, 229, 229, 173, 178, 6,
+ /* 1140 */ 173, 195, 173, 195, 147, 147, 174, 147, 147, 22,
+ /* 1150 */ 155, 99, 40, 98, 122, 172, 119, 195, 172, 120,
+ /* 1160 */ 172, 117, 172, 174, 121, 131, 223, 180, 97, 113,
+ /* 1170 */ 153, 212, 23, 161, 153, 99, 19, 116, 15, 175,
+ /* 1180 */ 161, 190, 172, 172, 153, 172, 153, 152, 196, 180,
+ /* 1190 */ 197, 153, 198, 175, 153, 199, 38, 131, 152, 61,
+ /* 1200 */ 153, 19, 153, 15, 153, 33, 153, 205, 185, 206,
+ /* 1210 */ 205, 212, 206, 185, 1, 153, 138, 188, 160, 212,
+ /* 1220 */ 212, 20, 195, 32, 188, 44, 19, 113, 188, 113,
+ /* 1230 */ 113, 113, 20, 185, 19, 176, 20, 195, 216, 176,
+ /* 1240 */ 216, 19, 92, 108, 11, 19, 22, 20, 234, 20,
+ /* 1250 */ 118, 19, 22, 22, 118, 235, 115, 20, 113, 20,
+ /* 1260 */ 19, 44, 237, 20, 19, 19, 19, 44, 104, 96,
+ /* 1270 */ 16, 21, 17, 99, 36, 22, 134, 99, 19, 45,
+ /* 1280 */ 45, 5, 1, 103, 123, 19, 14, 237, 231, 69,
+ /* 1290 */ 69, 114, 116, 114, 240, 17, 103, 20, 123, 19,
+ /* 1300 */ 14, 136, 58, 137, 19, 3, 247, 243, 4, 247,
+ /* 1310 */ 247, 246,
};
-#define YY_SHIFT_USE_DFLT (-75)
+#define YY_SHIFT_USE_DFLT (-106)
+#define YY_SHIFT_MAX 382
static const short yy_shift_ofst[] = {
- /* 0 */ 205, 7, -75, -75, 1167, -10, 57, -75, 47, 475,
- /* 10 */ 399, 123, 337, -75, -75, -75, -75, -75, -75, 475,
- /* 20 */ 446, 475, 543, 475, 757, 456, 858, 453, 240, 799,
- /* 30 */ 865, 50, -75, 254, -75, -16, -75, 453, 151, -75,
- /* 40 */ 931, -75, 1004, 306, -75, -75, -75, -75, -75, -75,
- /* 50 */ -75, 180, 931, -75, 1045, -75, 278, -75, -75, 1014,
- /* 60 */ 689, 931, 1038, -75, -75, -75, -75, 931, -75, 1122,
- /* 70 */ 1080, 652, 473, -75, -75, 1080, 1051, 1052, -75, 934,
- /* 80 */ -75, 302, 1079, -75, 650, -75, 641, 1091, 1101, 1107,
- /* 90 */ 1112, 1110, -75, 1080, 40, 1080, 714, 1080, -75, 1126,
- /* 100 */ 453, 1127, 453, -75, -75, -75, -75, -75, -75, 1223,
- /* 110 */ 1080, 108, 254, -75, -75, 455, 321, 595, -75, 321,
- /* 120 */ 1224, -75, -75, -75, 638, -75, -75, -75, 638, -75,
- /* 130 */ -75, -75, -75, 1225, -75, 1080, -75, 814, 1080, -12,
- /* 140 */ 1080, -12, 1080, -12, 1080, -12, 1080, -74, 1080, -74,
- /* 150 */ 1080, -53, 1080, -53, 1080, -53, 1080, -53, 1080, 242,
- /* 160 */ 1080, 242, 1080, 1164, 1080, 1164, 1080, 1164, 1080, -75,
- /* 170 */ -75, 298, -75, -75, -75, -75, 1080, -59, 1080, -12,
- /* 180 */ -75, 893, -75, 1157, -75, -75, -75, 1080, 764, 1080,
- /* 190 */ -74, -75, 325, 934, 359, 419, 1140, 1141, 1142, -75,
- /* 200 */ 714, 1080, 864, 1080, -75, 1080, -75, 1080, -75, 1235,
- /* 210 */ 1079, 376, -75, 945, 158, 1123, 320, 1242, -75, 1080,
- /* 220 */ 231, 1080, 714, 1238, 443, 1240, -75, 1241, 453, 1244,
- /* 230 */ -75, 1080, 305, 1080, 355, 1080, 714, 780, -75, 1080,
- /* 240 */ -75, -75, 1152, 453, -75, -75, -75, 864, 1080, 714,
- /* 250 */ 1148, 1080, 1249, 1080, 1177, 689, -75, 1254, -75, -75,
- /* 260 */ 714, 1177, 689, -75, 1080, 714, 1165, 1080, 1260, 1080,
- /* 270 */ 714, -75, -75, 239, -75, -75, -75, 430, -75, 433,
- /* 280 */ -75, 1172, -75, 501, 1152, 144, 453, -75, -75, 1189,
- /* 290 */ 1174, -75, 1275, 453, 783, -75, 453, -75, -75, 1080,
- /* 300 */ 714, 1079, 422, 425, 1276, 144, 1189, 1174, -75, 1021,
- /* 310 */ -28, -75, -75, 1184, 73, -75, -75, 429, -75, 792,
- /* 320 */ -75, 1280, -75, 496, 931, -75, 453, 1285, -75, 42,
- /* 330 */ -75, 453, -75, 550, 928, -75, 716, -75, -75, -75,
- /* 340 */ -75, 928, -75, 928, -75, 453, 793, -75, 453, 1177,
- /* 350 */ 689, -75, -75, 1177, 689, -75, -75, 1254, -75, 1045,
- /* 360 */ -75, -75, 68, -75, 1080, 564, -75, 191, -75, -75,
- /* 370 */ 191, -75, -75, -75, -75, 176, 256, -75, 453, -75,
- /* 380 */ 1271, 1297, 453, 260, 1300, 931, -75, 1304, 453, 796,
- /* 390 */ 931, -75, 1080, 614, -75, 1281, 1307, 453, 833, 1231,
- /* 400 */ 453, 1285, -75, 493, 1226, -75, -75, -75, -75, -75,
- /* 410 */ 1079, 513, 856, 391, 453, 1152, -75, 453, 745, 1319,
- /* 420 */ 1079, 548, 453, 1152, 510, 565, 1247, 453, 1152, -75,
- /* 430 */ 1310, 297, 1342, 1080, 664, 1315, 813, -75, -75, 1253,
- /* 440 */ 1255, 809, 453, 882, -75, -75, 1311, -75, -75, 1220,
- /* 450 */ 453, 862, 1261, 453, 1343, 453, 892, 907, 1357, 1229,
- /* 460 */ 1358, 152, 592, 894, 306, -75, 1245, 1246, 1351, 1366,
- /* 470 */ 1367, 152, 1359, 1312, 453, 1274, 453, 746, 453, 1305,
- /* 480 */ 1080, 714, 1375, 1313, 1080, 714, 1258, 453, 1364, 453,
- /* 490 */ 947, -75, 917, 598, 1368, 1080, 1033, 1080, 714, 1382,
- /* 500 */ 714, 1277, 453, 9, 1384, 470, 453, 1386, 453, 1388,
- /* 510 */ 453, 1389, 453, 1390, 605, 1283, 453, 9, 1394, 1312,
- /* 520 */ 453, 1298, 453, 746, 1398, 1282, 453, 1364, 1010, 610,
- /* 530 */ 1385, 1080, 1092, 1399, 530, 1402, 453, 1152, 649, 179,
- /* 540 */ 1407, 1408, 1409, 1410, 453, 1396, 1413, 1387, 254, 1397,
- /* 550 */ 453, 1154, 1415, 778, 1418, 1422, -75, 1387, 453, 1424,
- /* 560 */ 665, 982, 1425, 734, 982, 1427, 1419, 453, 955, 1301,
- /* 570 */ 453, 1436, 1306, 1303, 453, 1440, -75, 1439, 1441, -75,
- /* 580 */ -75,
+ /* 0 */ 99, 840, 985, -16, 840, 930, 930, 930, 274, -105,
+ /* 10 */ 96, 930, 930, 930, 930, 930, -46, 250, 104, 540,
+ /* 20 */ 551, 76, 76, 53, 165, 208, 251, 323, 392, 461,
+ /* 30 */ 530, 599, 642, 685, 642, 642, 642, 642, 642, 642,
+ /* 40 */ 642, 642, 642, 642, 642, 642, 642, 642, 642, 642,
+ /* 50 */ 642, 728, 771, 771, 856, 930, 930, 930, 930, 930,
+ /* 60 */ 930, 930, 930, 930, 930, 930, 930, 930, 930, 930,
+ /* 70 */ 930, 930, 930, 930, 930, 930, 930, 930, 930, 930,
+ /* 80 */ 930, 930, 930, 930, 930, 930, 930, 930, 930, 930,
+ /* 90 */ 930, 930, 930, -62, -62, -14, 27, 27, -40, 219,
+ /* 100 */ 463, 560, 540, 540, 540, 540, 540, 540, 540, 551,
+ /* 110 */ -72, -106, -106, -106, 130, 252, 468, 468, 192, 563,
+ /* 120 */ 150, 357, 540, 357, 540, 540, 540, 540, 540, 540,
+ /* 130 */ 540, 540, 540, 540, 540, 540, 540, 214, 376, -105,
+ /* 140 */ -105, -105, -106, -106, -106, 249, 249, 320, 343, 411,
+ /* 150 */ 334, 477, 515, 542, 282, 529, 476, 538, 627, 540,
+ /* 160 */ 540, 578, 540, 540, 397, 540, 540, 404, 540, 540,
+ /* 170 */ 541, 404, 540, 540, 518, 518, 518, 540, 540, 541,
+ /* 180 */ 540, 540, 541, 540, 836, 587, 540, 540, 541, 540,
+ /* 190 */ 540, 540, 541, 540, 540, 540, 541, 541, 540, 540,
+ /* 200 */ 540, 540, 540, 540, 204, 876, 448, 91, 707, 707,
+ /* 210 */ 566, 876, 876, 459, 876, 876, 260, 872, 872, 1133,
+ /* 220 */ 1133, 1133, 1133, 1127, 1052, 1052, 1112, 1052, 1055, 1052,
+ /* 230 */ -105, 1032, 1037, 1039, 1044, 1043, 1034, 1056, 1071, 1149,
+ /* 240 */ 1071, 1056, 1076, 1061, 1076, 1061, 1157, 1071, 1071, 1149,
+ /* 250 */ 1112, 1052, 1052, 1052, 1157, 1163, 1056, 1056, 1056, 1056,
+ /* 260 */ 1158, 1066, 1163, 1056, 1138, 1138, 1182, 1032, 1056, 1188,
+ /* 270 */ 1188, 1188, 1032, 1138, 1182, 1056, 1172, 1172, 1056, 1056,
+ /* 280 */ 1078, -106, -106, -106, -106, -106, -106, 317, 132, 629,
+ /* 290 */ 590, 794, 905, 851, 796, 955, 936, 980, 984, 896,
+ /* 300 */ 1015, 1016, 1030, 1026, 1060, 1086, 1087, 1090, 922, 1095,
+ /* 310 */ 1045, 1213, 1201, 1191, 1181, 1207, 1114, 1116, 1117, 1118,
+ /* 320 */ 1215, 1212, 1216, 1150, 1135, 1222, 1233, 1226, 1227, 1224,
+ /* 330 */ 1229, 1132, 1230, 1136, 1231, 1141, 1232, 1237, 1145, 1239,
+ /* 340 */ 1217, 1241, 1243, 1245, 1246, 1223, 1247, 1173, 1164, 1254,
+ /* 350 */ 1255, 1250, 1174, 1238, 1234, 1253, 1235, 1142, 1178, 1259,
+ /* 360 */ 1276, 1281, 1180, 1220, 1221, 1161, 1266, 1177, 1272, 1176,
+ /* 370 */ 1278, 1179, 1193, 1175, 1280, 1277, 1286, 1244, 1165, 1166,
+ /* 380 */ 1285, 1302, 1304,
};
-#define YY_REDUCE_USE_DFLT (-61)
+#define YY_REDUCE_USE_DFLT (-218)
+#define YY_REDUCE_MAX 286
static const short yy_reduce_ofst[] = {
- /* 0 */ -48, 61, -61, -61, -60, -61, -61, -61, -32, 12,
- /* 10 */ -61, 181, -61, -61, -61, -61, -61, -61, -61, 314,
- /* 20 */ -61, 386, -61, 622, -61, 654, -61, 51, 798, -61,
- /* 30 */ -61, -23, -61, -26, 760, 89, -61, 860, 486, -61,
- /* 40 */ 867, -61, -61, 65, -61, -61, -61, -61, -61, -61,
- /* 50 */ -61, -61, 909, -61, 910, -61, -61, -61, -61, -61,
- /* 60 */ 914, 962, 964, -61, -61, -61, -61, 968, -61, -61,
- /* 70 */ 438, -61, 996, -61, -61, 116, -61, -61, -61, 293,
- /* 80 */ -61, 1000, 1006, -61, 1011, 569, 1005, 1026, 1034, 1035,
- /* 90 */ 1036, 1041, -61, 490, 394, 552, 394, 601, -61, -61,
- /* 100 */ 1087, -61, 1093, -61, -61, -61, -61, -61, -61, -61,
- /* 110 */ 603, 394, 53, -61, -61, 1082, 110, -61, -61, 229,
- /* 120 */ -61, -61, -61, -61, 1019, -61, -61, -61, 1020, -61,
- /* 130 */ -61, -61, -61, -61, -61, 640, -61, 394, 651, 394,
- /* 140 */ 690, 394, 701, 394, 703, 394, 740, 394, 751, 394,
- /* 150 */ 753, 394, 755, 394, 790, 394, 801, 394, 803, 394,
- /* 160 */ 818, 394, 829, 394, 831, 394, 835, 394, 841, 394,
- /* 170 */ -61, -61, -61, -61, -61, -61, 846, 188, 849, 394,
- /* 180 */ -61, -61, -61, -61, -61, -61, -61, 879, 394, 881,
- /* 190 */ 394, -61, 1102, -6, 1000, -61, -61, -61, -61, -61,
- /* 200 */ 394, 887, 394, 898, 394, 918, 394, 936, 394, -61,
- /* 210 */ 662, 1000, -61, 295, 394, 1037, 1039, -61, -61, 946,
- /* 220 */ 394, 948, 394, -61, 1073, -61, -61, -61, 1114, -61,
- /* 230 */ -61, 950, 394, 956, 394, 974, 394, -61, -61, 303,
- /* 240 */ -61, -61, 1118, 1124, -61, -61, -61, 394, 984, 394,
- /* 250 */ -61, 183, -61, 190, 1065, 1104, -61, 1119, -61, -61,
- /* 260 */ 394, 1070, 1109, -61, 987, 394, -61, 187, -61, 1007,
- /* 270 */ 394, -61, 398, 1083, -61, -61, -61, 1136, -61, 1138,
- /* 280 */ -61, -61, -61, 1143, 1137, 389, 1144, -61, -61, 1090,
- /* 290 */ 1094, -61, -61, 604, -61, -61, 1147, -61, -61, 1015,
- /* 300 */ 394, 132, 1000, 1083, -61, 512, 1096, 1097, -61, 1018,
- /* 310 */ 241, -61, -61, -61, 1087, -61, -61, 394, -61, -61,
- /* 320 */ -61, -61, -61, 394, 1131, -61, 1155, 1132, 1130, 1133,
- /* 330 */ -61, 1159, -61, -61, 1134, -61, -61, -61, -61, -61,
- /* 340 */ -61, 1135, -61, 1139, -61, 439, -61, -61, 765, 1098,
- /* 350 */ 1146, -61, -61, 1099, 1149, -61, -61, 1151, -61, 1145,
- /* 360 */ -61, -61, 692, -61, 1022, 394, -61, 1150, -61, -61,
- /* 370 */ 1153, -61, -61, -61, -61, 1156, 1158, -61, 1166, -61,
- /* 380 */ -61, -61, 899, 1160, -61, 1161, -61, -61, 949, -61,
- /* 390 */ 1163, -61, 1030, 375, -61, -61, -61, 979, -61, -61,
- /* 400 */ 1180, 1162, 1168, 527, -61, -61, -61, -61, -61, -61,
- /* 410 */ 712, 1000, 756, -61, 1181, 1179, -61, 1187, 1186, -61,
- /* 420 */ 807, 1000, 1193, 1190, 1115, 1113, -61, 715, 1195, -61,
- /* 430 */ 1117, 1120, -61, 1048, 394, -61, -61, -61, -61, -61,
- /* 440 */ -61, -61, 709, -61, -61, -61, -61, -61, -61, -61,
- /* 450 */ 1209, 1206, -61, 1211, -61, 997, -61, 1192, -61, -61,
- /* 460 */ -61, 315, 1000, 1183, 732, -61, -61, -61, -61, -61,
- /* 470 */ -61, 382, -61, 1191, 1228, -61, 808, 1185, 1232, -61,
- /* 480 */ 1055, 394, -61, -61, 1064, 394, -61, 1236, 1171, 767,
- /* 490 */ -61, -61, 854, 1000, -61, -18, -61, 1067, 394, -61,
- /* 500 */ 394, -61, 1248, 1196, -61, -61, 815, -61, 891, -61,
- /* 510 */ 895, -61, 906, -61, 1000, -61, 942, 1202, -61, 1215,
- /* 520 */ 943, -61, 959, 1207, -61, -61, 975, 1194, 985, 1000,
- /* 530 */ -61, 434, -61, -61, 1259, -61, 1262, 1257, -61, 435,
- /* 540 */ -61, -61, -61, -61, 1267, -61, -61, 1188, 1263, -61,
- /* 550 */ 1273, 1197, -61, 1264, -61, -61, -61, 1199, 1279, -61,
- /* 560 */ 1284, 1278, -61, 1287, 1286, -61, -61, 522, -61, -61,
- /* 570 */ 1291, -61, -61, 1204, -58, -61, -61, -61, -61, -61,
- /* 580 */ -61,
+ /* 0 */ -56, 276, -2, -19, 399, 269, 49, 271, 270, 14,
+ /* 10 */ -147, -78, 273, 338, 340, 342, 44, 544, 263, -60,
+ /* 20 */ 32, 144, 349, -217, -217, -217, -217, -217, -217, -217,
+ /* 30 */ -217, -217, -217, -217, -217, -217, -217, -217, -217, -217,
+ /* 40 */ -217, -217, -217, -217, -217, -217, -217, -217, -217, -217,
+ /* 50 */ -217, -217, -217, -217, 405, 482, 485, 525, 568, 654,
+ /* 60 */ 697, 710, 712, 714, 721, 726, 747, 752, 754, 760,
+ /* 70 */ 763, 768, 792, 802, 804, 806, 809, 844, 853, 855,
+ /* 80 */ 857, 859, 873, 883, 892, 897, 900, 903, 918, 924,
+ /* 90 */ 928, 931, 933, -217, -217, 127, -217, -217, -217, -217,
+ /* 100 */ 454, 147, 509, 550, 554, 592, 593, 543, 489, -139,
+ /* 110 */ -217, -217, -217, -217, 45, 21, 67, 120, 110, 110,
+ /* 120 */ 3, 389, 440, 573, 545, 594, 667, 675, 669, 595,
+ /* 130 */ 597, 637, 640, 716, 718, 679, 753, 293, 765, 770,
+ /* 140 */ 803, 843, 628, 576, 588, -112, -83, 18, 154, 287,
+ /* 150 */ 302, 287, 287, 71, 423, 432, 492, 625, 643, 674,
+ /* 160 */ 742, 717, 625, 758, 846, 766, 864, 812, 893, 898,
+ /* 170 */ 287, 812, 901, 913, 885, 890, 904, 927, 942, 287,
+ /* 180 */ 944, 945, 287, 949, 852, 867, 963, 965, 287, 966,
+ /* 190 */ 968, 970, 287, 971, 973, 974, 287, 287, 975, 976,
+ /* 200 */ 977, 978, 979, 981, 982, 957, 939, 934, 906, 907,
+ /* 210 */ 909, 961, 964, 960, 967, 969, 972, 946, 948, 997,
+ /* 220 */ 998, 1000, 1001, 995, 983, 986, 987, 988, 989, 990,
+ /* 230 */ 991, 962, 992, 993, 994, 996, 943, 1017, 959, 1012,
+ /* 240 */ 999, 1021, 1002, 1003, 1005, 1006, 1004, 1007, 1008, 1019,
+ /* 250 */ 1009, 1010, 1011, 1013, 1018, 1035, 1031, 1033, 1038, 1041,
+ /* 260 */ 1014, 1020, 1046, 1047, 1023, 1028, 1022, 1027, 1049, 1029,
+ /* 270 */ 1036, 1040, 1042, 1048, 1024, 1051, 1025, 1050, 1053, 1062,
+ /* 280 */ 1054, 1058, 1059, 1063, 1057, 1064, 1065,
};
static const YYACTIONTYPE yy_default[] = {
- /* 0 */ 587, 587, 582, 585, 892, 892, 892, 586, 594, 892,
- /* 10 */ 892, 892, 892, 614, 615, 616, 595, 596, 597, 892,
- /* 20 */ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
- /* 30 */ 892, 892, 607, 617, 627, 609, 626, 892, 892, 628,
- /* 40 */ 672, 635, 892, 892, 673, 676, 677, 678, 872, 873,
- /* 50 */ 874, 892, 672, 636, 657, 655, 892, 658, 659, 892,
- /* 60 */ 728, 672, 643, 637, 644, 726, 727, 672, 638, 892,
- /* 70 */ 892, 758, 692, 690, 691, 824, 764, 759, 755, 892,
- /* 80 */ 683, 892, 892, 684, 692, 694, 701, 740, 731, 733,
- /* 90 */ 721, 735, 689, 892, 736, 892, 737, 892, 757, 892,
- /* 100 */ 892, 760, 892, 761, 762, 763, 765, 766, 767, 892,
- /* 110 */ 892, 892, 892, 612, 613, 619, 847, 892, 620, 847,
- /* 120 */ 892, 621, 624, 625, 892, 842, 844, 845, 892, 843,
- /* 130 */ 846, 623, 622, 892, 768, 892, 771, 773, 892, 774,
- /* 140 */ 892, 775, 892, 776, 892, 777, 892, 778, 892, 779,
- /* 150 */ 892, 780, 892, 781, 892, 782, 892, 783, 892, 784,
- /* 160 */ 892, 785, 892, 786, 892, 787, 892, 788, 892, 789,
- /* 170 */ 790, 892, 791, 798, 805, 808, 892, 793, 892, 792,
- /* 180 */ 795, 892, 796, 892, 799, 797, 804, 892, 892, 892,
- /* 190 */ 806, 807, 892, 824, 892, 892, 892, 892, 892, 811,
- /* 200 */ 823, 892, 800, 892, 801, 892, 802, 892, 803, 892,
- /* 210 */ 892, 892, 813, 892, 892, 892, 892, 892, 814, 892,
- /* 220 */ 892, 892, 815, 892, 892, 892, 870, 892, 892, 892,
- /* 230 */ 871, 892, 892, 892, 892, 892, 816, 892, 809, 824,
- /* 240 */ 821, 822, 709, 892, 710, 812, 794, 772, 892, 738,
- /* 250 */ 892, 892, 722, 892, 729, 728, 723, 892, 611, 730,
- /* 260 */ 725, 729, 728, 724, 892, 734, 892, 824, 732, 892,
- /* 270 */ 741, 693, 704, 702, 703, 712, 713, 892, 714, 892,
- /* 280 */ 715, 892, 716, 892, 709, 700, 892, 698, 699, 718,
- /* 290 */ 720, 705, 892, 892, 892, 719, 892, 753, 754, 892,
- /* 300 */ 717, 704, 892, 892, 892, 700, 718, 720, 706, 892,
- /* 310 */ 700, 695, 696, 892, 892, 697, 810, 892, 756, 892,
- /* 320 */ 769, 892, 770, 892, 672, 639, 892, 828, 645, 640,
- /* 330 */ 646, 892, 647, 892, 892, 648, 892, 651, 652, 653,
- /* 340 */ 654, 892, 649, 892, 650, 892, 892, 829, 892, 729,
- /* 350 */ 728, 830, 832, 729, 728, 831, 641, 892, 642, 657,
- /* 360 */ 656, 629, 892, 630, 892, 892, 631, 892, 632, 764,
- /* 370 */ 892, 633, 634, 618, 610, 892, 892, 662, 892, 665,
- /* 380 */ 892, 892, 892, 892, 892, 672, 666, 892, 892, 892,
- /* 390 */ 672, 667, 892, 672, 668, 892, 892, 892, 892, 892,
- /* 400 */ 892, 828, 645, 670, 892, 669, 671, 663, 664, 608,
- /* 410 */ 892, 892, 604, 892, 892, 709, 602, 892, 892, 892,
- /* 420 */ 892, 892, 892, 709, 853, 892, 892, 892, 709, 711,
- /* 430 */ 858, 892, 892, 892, 892, 892, 892, 859, 860, 892,
- /* 440 */ 892, 892, 892, 892, 850, 851, 892, 852, 603, 892,
- /* 450 */ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
- /* 460 */ 892, 892, 892, 892, 892, 675, 892, 892, 892, 892,
- /* 470 */ 892, 892, 892, 674, 892, 892, 892, 892, 892, 892,
- /* 480 */ 892, 743, 892, 892, 892, 744, 892, 892, 751, 892,
- /* 490 */ 892, 752, 892, 892, 892, 892, 892, 892, 749, 892,
- /* 500 */ 750, 892, 892, 892, 892, 892, 892, 892, 892, 892,
- /* 510 */ 892, 892, 892, 892, 892, 892, 892, 892, 892, 674,
- /* 520 */ 892, 892, 892, 892, 892, 892, 892, 751, 892, 892,
- /* 530 */ 892, 892, 892, 892, 892, 892, 892, 709, 892, 847,
- /* 540 */ 892, 892, 892, 892, 892, 892, 892, 881, 892, 892,
- /* 550 */ 892, 892, 892, 892, 892, 892, 880, 881, 892, 892,
- /* 560 */ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892,
- /* 570 */ 892, 892, 892, 890, 892, 892, 891, 588, 892, 589,
+ /* 0 */ 587, 813, 890, 702, 890, 813, 890, 813, 890, 706,
+ /* 10 */ 864, 809, 813, 890, 890, 890, 784, 890, 835, 890,
+ /* 20 */ 618, 835, 835, 737, 890, 890, 890, 890, 890, 890,
+ /* 30 */ 890, 890, 738, 890, 812, 808, 804, 806, 805, 739,
+ /* 40 */ 726, 735, 742, 718, 849, 744, 745, 750, 751, 865,
+ /* 50 */ 868, 772, 790, 771, 890, 890, 890, 890, 890, 890,
+ /* 60 */ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ /* 70 */ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ /* 80 */ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ /* 90 */ 890, 890, 890, 774, 795, 611, 773, 783, 775, 776,
+ /* 100 */ 671, 606, 890, 890, 890, 890, 890, 890, 890, 890,
+ /* 110 */ 777, 778, 791, 792, 890, 890, 890, 890, 890, 890,
+ /* 120 */ 587, 702, 890, 702, 890, 890, 890, 890, 890, 890,
+ /* 130 */ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ /* 140 */ 890, 890, 696, 706, 883, 890, 890, 662, 890, 890,
+ /* 150 */ 890, 890, 890, 890, 890, 890, 890, 890, 594, 592,
+ /* 160 */ 890, 694, 890, 890, 620, 890, 890, 704, 890, 890,
+ /* 170 */ 709, 710, 890, 890, 890, 890, 890, 890, 890, 608,
+ /* 180 */ 890, 890, 683, 890, 841, 890, 890, 890, 856, 890,
+ /* 190 */ 890, 890, 854, 890, 890, 890, 685, 747, 823, 890,
+ /* 200 */ 890, 869, 871, 890, 890, 729, 694, 703, 890, 890,
+ /* 210 */ 807, 729, 729, 641, 729, 729, 644, 741, 741, 591,
+ /* 220 */ 591, 591, 591, 661, 673, 673, 658, 673, 644, 673,
+ /* 230 */ 890, 741, 732, 734, 722, 736, 890, 711, 730, 890,
+ /* 240 */ 730, 711, 719, 721, 719, 721, 817, 730, 730, 890,
+ /* 250 */ 658, 673, 673, 673, 817, 603, 711, 711, 711, 711,
+ /* 260 */ 845, 848, 603, 711, 675, 675, 752, 741, 711, 682,
+ /* 270 */ 682, 682, 741, 675, 752, 711, 867, 867, 711, 711,
+ /* 280 */ 876, 628, 646, 646, 851, 883, 888, 890, 890, 890,
+ /* 290 */ 890, 890, 890, 759, 890, 890, 890, 890, 890, 890,
+ /* 300 */ 890, 890, 890, 890, 890, 890, 890, 890, 830, 890,
+ /* 310 */ 890, 890, 890, 890, 890, 890, 764, 760, 890, 761,
+ /* 320 */ 890, 890, 890, 890, 688, 890, 890, 890, 890, 890,
+ /* 330 */ 890, 890, 723, 890, 733, 890, 890, 890, 890, 890,
+ /* 340 */ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ /* 350 */ 890, 890, 890, 890, 843, 844, 890, 890, 890, 890,
+ /* 360 */ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
+ /* 370 */ 890, 890, 890, 890, 890, 890, 890, 875, 890, 890,
+ /* 380 */ 878, 588, 890, 582, 585, 584, 586, 590, 593, 615,
+ /* 390 */ 616, 617, 595, 596, 597, 598, 599, 600, 601, 607,
+ /* 400 */ 609, 627, 629, 636, 674, 677, 678, 679, 859, 860,
+ /* 410 */ 861, 637, 656, 659, 660, 638, 645, 727, 728, 639,
+ /* 420 */ 692, 693, 756, 686, 687, 691, 758, 762, 763, 765,
+ /* 430 */ 766, 614, 621, 622, 625, 626, 831, 833, 832, 834,
+ /* 440 */ 624, 623, 767, 770, 779, 780, 782, 788, 794, 797,
+ /* 450 */ 781, 786, 787, 789, 793, 796, 689, 690, 800, 802,
+ /* 460 */ 803, 857, 858, 798, 810, 811, 712, 801, 785, 724,
+ /* 470 */ 613, 731, 725, 695, 705, 714, 715, 716, 717, 700,
+ /* 480 */ 701, 707, 720, 754, 755, 708, 697, 698, 699, 799,
+ /* 490 */ 757, 768, 769, 640, 647, 648, 649, 652, 653, 654,
+ /* 500 */ 655, 650, 651, 818, 819, 821, 820, 642, 643, 657,
+ /* 510 */ 630, 631, 632, 633, 764, 634, 635, 619, 612, 663,
+ /* 520 */ 666, 667, 668, 669, 670, 672, 664, 665, 610, 602,
+ /* 530 */ 604, 713, 837, 846, 847, 842, 838, 839, 840, 605,
+ /* 540 */ 814, 815, 676, 748, 749, 836, 850, 852, 753, 853,
+ /* 550 */ 855, 880, 680, 681, 684, 822, 862, 740, 743, 746,
+ /* 560 */ 824, 825, 826, 827, 828, 829, 863, 866, 870, 872,
+ /* 570 */ 873, 874, 877, 879, 884, 885, 886, 889, 887, 589,
/* 580 */ 583,
};
-#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
+#define YY_SZ_ACTTAB (int)(sizeof(yy_action)/sizeof(yy_action[0]))
/* The next table maps tokens into fallback tokens. If a construct
** like the following:
@@ -670,75 +595,68 @@ static const YYACTIONTYPE yy_default[] = {
#ifdef YYFALLBACK
static const YYCODETYPE yyFallback[] = {
0, /* $ => nothing */
- 0, /* END_OF_FILE => nothing */
- 0, /* ILLEGAL => nothing */
- 0, /* SPACE => nothing */
- 0, /* UNCLOSED_STRING => nothing */
- 0, /* COMMENT => nothing */
- 0, /* FUNCTION => nothing */
- 0, /* COLUMN => nothing */
- 0, /* AGG_FUNCTION => nothing */
- 0, /* AGG_COLUMN => nothing */
- 0, /* CONST_FUNC => nothing */
0, /* SEMI => nothing */
- 30, /* EXPLAIN => ID */
- 30, /* QUERY => ID */
- 30, /* PLAN => ID */
- 30, /* BEGIN => ID */
+ 23, /* EXPLAIN => ID */
+ 23, /* QUERY => ID */
+ 23, /* PLAN => ID */
+ 23, /* BEGIN => ID */
0, /* TRANSACTION => nothing */
- 30, /* DEFERRED => ID */
- 30, /* IMMEDIATE => ID */
- 30, /* EXCLUSIVE => ID */
+ 23, /* DEFERRED => ID */
+ 23, /* IMMEDIATE => ID */
+ 23, /* EXCLUSIVE => ID */
0, /* COMMIT => nothing */
- 30, /* END => ID */
+ 23, /* END => ID */
0, /* ROLLBACK => nothing */
0, /* CREATE => nothing */
0, /* TABLE => nothing */
- 30, /* TEMP => ID */
+ 23, /* IF => ID */
+ 0, /* NOT => nothing */
+ 0, /* EXISTS => nothing */
+ 23, /* TEMP => ID */
0, /* LP => nothing */
0, /* RP => nothing */
0, /* AS => nothing */
0, /* COMMA => nothing */
0, /* ID => nothing */
- 30, /* ABORT => ID */
- 30, /* AFTER => ID */
- 30, /* ANALYZE => ID */
- 30, /* ASC => ID */
- 30, /* ATTACH => ID */
- 30, /* BEFORE => ID */
- 30, /* CASCADE => ID */
- 30, /* CAST => ID */
- 30, /* CONFLICT => ID */
- 30, /* DATABASE => ID */
- 30, /* DESC => ID */
- 30, /* DETACH => ID */
- 30, /* EACH => ID */
- 30, /* FAIL => ID */
- 30, /* FOR => ID */
- 30, /* IGNORE => ID */
- 30, /* INITIALLY => ID */
- 30, /* INSTEAD => ID */
- 30, /* LIKE_KW => ID */
- 30, /* MATCH => ID */
- 30, /* KEY => ID */
- 30, /* OF => ID */
- 30, /* OFFSET => ID */
- 30, /* PRAGMA => ID */
- 30, /* RAISE => ID */
- 30, /* REPLACE => ID */
- 30, /* RESTRICT => ID */
- 30, /* ROW => ID */
- 30, /* STATEMENT => ID */
- 30, /* TRIGGER => ID */
- 30, /* VACUUM => ID */
- 30, /* VIEW => ID */
- 30, /* REINDEX => ID */
- 30, /* RENAME => ID */
- 30, /* CTIME_KW => ID */
- 30, /* ALTER => ID */
+ 23, /* ABORT => ID */
+ 23, /* AFTER => ID */
+ 23, /* ANALYZE => ID */
+ 23, /* ASC => ID */
+ 23, /* ATTACH => ID */
+ 23, /* BEFORE => ID */
+ 23, /* CASCADE => ID */
+ 23, /* CAST => ID */
+ 23, /* CONFLICT => ID */
+ 23, /* DATABASE => ID */
+ 23, /* DESC => ID */
+ 23, /* DETACH => ID */
+ 23, /* EACH => ID */
+ 23, /* FAIL => ID */
+ 23, /* FOR => ID */
+ 23, /* IGNORE => ID */
+ 23, /* INITIALLY => ID */
+ 23, /* INSTEAD => ID */
+ 23, /* LIKE_KW => ID */
+ 23, /* MATCH => ID */
+ 23, /* KEY => ID */
+ 23, /* OF => ID */
+ 23, /* OFFSET => ID */
+ 23, /* PRAGMA => ID */
+ 23, /* RAISE => ID */
+ 23, /* REPLACE => ID */
+ 23, /* RESTRICT => ID */
+ 23, /* ROW => ID */
+ 23, /* STATEMENT => ID */
+ 23, /* TRIGGER => ID */
+ 23, /* VACUUM => ID */
+ 23, /* VIEW => ID */
+ 23, /* VIRTUAL => ID */
+ 23, /* REINDEX => ID */
+ 23, /* RENAME => ID */
+ 23, /* CTIME_KW => ID */
+ 0, /* ANY => nothing */
0, /* OR => nothing */
0, /* AND => nothing */
- 0, /* NOT => nothing */
0, /* IS => nothing */
0, /* BETWEEN => nothing */
0, /* IN => nothing */
@@ -785,8 +703,8 @@ static const YYCODETYPE yyFallback[] = {
0, /* DROP => nothing */
0, /* UNION => nothing */
0, /* ALL => nothing */
- 0, /* INTERSECT => nothing */
0, /* EXCEPT => nothing */
+ 0, /* INTERSECT => nothing */
0, /* SELECT => nothing */
0, /* DISTINCT => nothing */
0, /* DOT => nothing */
@@ -806,12 +724,12 @@ static const YYCODETYPE yyFallback[] = {
0, /* BLOB => nothing */
0, /* REGISTER => nothing */
0, /* VARIABLE => nothing */
- 0, /* EXISTS => nothing */
0, /* CASE => nothing */
0, /* WHEN => nothing */
0, /* THEN => nothing */
0, /* ELSE => nothing */
0, /* INDEX => nothing */
+ 0, /* ALTER => nothing */
0, /* TO => nothing */
0, /* ADD => nothing */
0, /* COLUMNKW => nothing */
@@ -885,68 +803,68 @@ void sqlite3ParserTrace(FILE *TraceFILE, char *zTracePrompt){
/* For tracing shifts, the names of all terminals and nonterminals
** are required. The following table supplies these names */
static const char *const yyTokenName[] = {
- "$", "END_OF_FILE", "ILLEGAL", "SPACE",
- "UNCLOSED_STRING", "COMMENT", "FUNCTION", "COLUMN",
- "AGG_FUNCTION", "AGG_COLUMN", "CONST_FUNC", "SEMI",
- "EXPLAIN", "QUERY", "PLAN", "BEGIN",
- "TRANSACTION", "DEFERRED", "IMMEDIATE", "EXCLUSIVE",
- "COMMIT", "END", "ROLLBACK", "CREATE",
- "TABLE", "TEMP", "LP", "RP",
- "AS", "COMMA", "ID", "ABORT",
- "AFTER", "ANALYZE", "ASC", "ATTACH",
- "BEFORE", "CASCADE", "CAST", "CONFLICT",
- "DATABASE", "DESC", "DETACH", "EACH",
- "FAIL", "FOR", "IGNORE", "INITIALLY",
- "INSTEAD", "LIKE_KW", "MATCH", "KEY",
- "OF", "OFFSET", "PRAGMA", "RAISE",
- "REPLACE", "RESTRICT", "ROW", "STATEMENT",
- "TRIGGER", "VACUUM", "VIEW", "REINDEX",
- "RENAME", "CTIME_KW", "ALTER", "OR",
- "AND", "NOT", "IS", "BETWEEN",
- "IN", "ISNULL", "NOTNULL", "NE",
- "EQ", "GT", "LE", "LT",
- "GE", "ESCAPE", "BITAND", "BITOR",
- "LSHIFT", "RSHIFT", "PLUS", "MINUS",
- "STAR", "SLASH", "REM", "CONCAT",
- "UMINUS", "UPLUS", "BITNOT", "STRING",
- "JOIN_KW", "CONSTRAINT", "DEFAULT", "NULL",
- "PRIMARY", "UNIQUE", "CHECK", "REFERENCES",
- "COLLATE", "AUTOINCR", "ON", "DELETE",
- "UPDATE", "INSERT", "SET", "DEFERRABLE",
- "FOREIGN", "DROP", "UNION", "ALL",
- "INTERSECT", "EXCEPT", "SELECT", "DISTINCT",
- "DOT", "FROM", "JOIN", "USING",
- "ORDER", "BY", "GROUP", "HAVING",
- "LIMIT", "WHERE", "INTO", "VALUES",
- "INTEGER", "FLOAT", "BLOB", "REGISTER",
- "VARIABLE", "EXISTS", "CASE", "WHEN",
- "THEN", "ELSE", "INDEX", "TO",
- "ADD", "COLUMNKW", "error", "input",
- "cmdlist", "ecmd", "cmdx", "cmd",
- "explain", "transtype", "trans_opt", "nm",
- "create_table", "create_table_args", "temp", "dbnm",
- "columnlist", "conslist_opt", "select", "column",
- "columnid", "type", "carglist", "id",
- "ids", "typetoken", "typename", "signed",
- "plus_num", "minus_num", "carg", "ccons",
- "term", "expr", "onconf", "sortorder",
- "autoinc", "idxlist_opt", "refargs", "defer_subclause",
- "refarg", "refact", "init_deferred_pred_opt", "conslist",
- "tcons", "idxlist", "defer_subclause_opt", "orconf",
- "resolvetype", "raisetype", "fullname", "oneselect",
- "multiselect_op", "distinct", "selcollist", "from",
- "where_opt", "groupby_opt", "having_opt", "orderby_opt",
- "limit_opt", "sclp", "as", "seltablist",
- "stl_prefix", "joinop", "on_opt", "using_opt",
- "seltablist_paren", "joinop2", "inscollist", "sortlist",
- "sortitem", "collate", "exprlist", "setlist",
- "insert_cmd", "inscollist_opt", "itemlist", "likeop",
- "escape", "between_op", "in_op", "case_operand",
- "case_exprlist", "case_else", "expritem", "uniqueflag",
- "idxitem", "plus_opt", "number", "trigger_decl",
- "trigger_cmd_list", "trigger_time", "trigger_event", "foreach_clause",
- "when_clause", "trigger_cmd", "database_kw_opt", "key_opt",
- "add_column_fullname", "kwcolumn_opt",
+ "$", "SEMI", "EXPLAIN", "QUERY",
+ "PLAN", "BEGIN", "TRANSACTION", "DEFERRED",
+ "IMMEDIATE", "EXCLUSIVE", "COMMIT", "END",
+ "ROLLBACK", "CREATE", "TABLE", "IF",
+ "NOT", "EXISTS", "TEMP", "LP",
+ "RP", "AS", "COMMA", "ID",
+ "ABORT", "AFTER", "ANALYZE", "ASC",
+ "ATTACH", "BEFORE", "CASCADE", "CAST",
+ "CONFLICT", "DATABASE", "DESC", "DETACH",
+ "EACH", "FAIL", "FOR", "IGNORE",
+ "INITIALLY", "INSTEAD", "LIKE_KW", "MATCH",
+ "KEY", "OF", "OFFSET", "PRAGMA",
+ "RAISE", "REPLACE", "RESTRICT", "ROW",
+ "STATEMENT", "TRIGGER", "VACUUM", "VIEW",
+ "VIRTUAL", "REINDEX", "RENAME", "CTIME_KW",
+ "ANY", "OR", "AND", "IS",
+ "BETWEEN", "IN", "ISNULL", "NOTNULL",
+ "NE", "EQ", "GT", "LE",
+ "LT", "GE", "ESCAPE", "BITAND",
+ "BITOR", "LSHIFT", "RSHIFT", "PLUS",
+ "MINUS", "STAR", "SLASH", "REM",
+ "CONCAT", "UMINUS", "UPLUS", "BITNOT",
+ "STRING", "JOIN_KW", "CONSTRAINT", "DEFAULT",
+ "NULL", "PRIMARY", "UNIQUE", "CHECK",
+ "REFERENCES", "COLLATE", "AUTOINCR", "ON",
+ "DELETE", "UPDATE", "INSERT", "SET",
+ "DEFERRABLE", "FOREIGN", "DROP", "UNION",
+ "ALL", "EXCEPT", "INTERSECT", "SELECT",
+ "DISTINCT", "DOT", "FROM", "JOIN",
+ "USING", "ORDER", "BY", "GROUP",
+ "HAVING", "LIMIT", "WHERE", "INTO",
+ "VALUES", "INTEGER", "FLOAT", "BLOB",
+ "REGISTER", "VARIABLE", "CASE", "WHEN",
+ "THEN", "ELSE", "INDEX", "ALTER",
+ "TO", "ADD", "COLUMNKW", "error",
+ "input", "cmdlist", "ecmd", "cmdx",
+ "cmd", "explain", "transtype", "trans_opt",
+ "nm", "create_table", "create_table_args", "temp",
+ "ifnotexists", "dbnm", "columnlist", "conslist_opt",
+ "select", "column", "columnid", "type",
+ "carglist", "id", "ids", "typetoken",
+ "typename", "signed", "plus_num", "minus_num",
+ "carg", "ccons", "term", "expr",
+ "onconf", "sortorder", "autoinc", "idxlist_opt",
+ "refargs", "defer_subclause", "refarg", "refact",
+ "init_deferred_pred_opt", "conslist", "tcons", "idxlist",
+ "defer_subclause_opt", "orconf", "resolvetype", "raisetype",
+ "ifexists", "fullname", "oneselect", "multiselect_op",
+ "distinct", "selcollist", "from", "where_opt",
+ "groupby_opt", "having_opt", "orderby_opt", "limit_opt",
+ "sclp", "as", "seltablist", "stl_prefix",
+ "joinop", "on_opt", "using_opt", "seltablist_paren",
+ "joinop2", "inscollist", "sortlist", "sortitem",
+ "collate", "exprlist", "setlist", "insert_cmd",
+ "inscollist_opt", "itemlist", "likeop", "escape",
+ "between_op", "in_op", "case_operand", "case_exprlist",
+ "case_else", "expritem", "uniqueflag", "idxitem",
+ "plus_opt", "number", "trigger_decl", "trigger_cmd_list",
+ "trigger_time", "trigger_event", "foreach_clause", "when_clause",
+ "trigger_cmd", "database_kw_opt", "key_opt", "add_column_fullname",
+ "kwcolumn_opt", "create_vtab", "vtabarglist", "vtabarg",
+ "vtabargtoken", "lp", "anylist",
};
#endif /* NDEBUG */
@@ -975,296 +893,294 @@ static const char *const yyRuleName[] = {
/* 18 */ "cmd ::= END trans_opt",
/* 19 */ "cmd ::= ROLLBACK trans_opt",
/* 20 */ "cmd ::= create_table create_table_args",
- /* 21 */ "create_table ::= CREATE temp TABLE nm dbnm",
- /* 22 */ "temp ::= TEMP",
- /* 23 */ "temp ::=",
- /* 24 */ "create_table_args ::= LP columnlist conslist_opt RP",
- /* 25 */ "create_table_args ::= AS select",
- /* 26 */ "columnlist ::= columnlist COMMA column",
- /* 27 */ "columnlist ::= column",
- /* 28 */ "column ::= columnid type carglist",
- /* 29 */ "columnid ::= nm",
- /* 30 */ "id ::= ID",
- /* 31 */ "ids ::= ID",
- /* 32 */ "ids ::= STRING",
- /* 33 */ "nm ::= ID",
- /* 34 */ "nm ::= STRING",
- /* 35 */ "nm ::= JOIN_KW",
- /* 36 */ "type ::=",
- /* 37 */ "type ::= typetoken",
- /* 38 */ "typetoken ::= typename",
- /* 39 */ "typetoken ::= typename LP signed RP",
- /* 40 */ "typetoken ::= typename LP signed COMMA signed RP",
- /* 41 */ "typename ::= ids",
- /* 42 */ "typename ::= typename ids",
- /* 43 */ "signed ::= plus_num",
- /* 44 */ "signed ::= minus_num",
- /* 45 */ "carglist ::= carglist carg",
- /* 46 */ "carglist ::=",
- /* 47 */ "carg ::= CONSTRAINT nm ccons",
- /* 48 */ "carg ::= ccons",
- /* 49 */ "carg ::= DEFAULT term",
- /* 50 */ "carg ::= DEFAULT LP expr RP",
- /* 51 */ "carg ::= DEFAULT PLUS term",
- /* 52 */ "carg ::= DEFAULT MINUS term",
- /* 53 */ "carg ::= DEFAULT id",
- /* 54 */ "ccons ::= NULL onconf",
- /* 55 */ "ccons ::= NOT NULL onconf",
- /* 56 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
- /* 57 */ "ccons ::= UNIQUE onconf",
- /* 58 */ "ccons ::= CHECK LP expr RP onconf",
- /* 59 */ "ccons ::= REFERENCES nm idxlist_opt refargs",
- /* 60 */ "ccons ::= defer_subclause",
- /* 61 */ "ccons ::= COLLATE id",
- /* 62 */ "autoinc ::=",
- /* 63 */ "autoinc ::= AUTOINCR",
- /* 64 */ "refargs ::=",
- /* 65 */ "refargs ::= refargs refarg",
- /* 66 */ "refarg ::= MATCH nm",
- /* 67 */ "refarg ::= ON DELETE refact",
- /* 68 */ "refarg ::= ON UPDATE refact",
- /* 69 */ "refarg ::= ON INSERT refact",
- /* 70 */ "refact ::= SET NULL",
- /* 71 */ "refact ::= SET DEFAULT",
- /* 72 */ "refact ::= CASCADE",
- /* 73 */ "refact ::= RESTRICT",
- /* 74 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
- /* 75 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
- /* 76 */ "init_deferred_pred_opt ::=",
- /* 77 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
- /* 78 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
- /* 79 */ "conslist_opt ::=",
- /* 80 */ "conslist_opt ::= COMMA conslist",
- /* 81 */ "conslist ::= conslist COMMA tcons",
- /* 82 */ "conslist ::= conslist tcons",
- /* 83 */ "conslist ::= tcons",
- /* 84 */ "tcons ::= CONSTRAINT nm",
- /* 85 */ "tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf",
- /* 86 */ "tcons ::= UNIQUE LP idxlist RP onconf",
- /* 87 */ "tcons ::= CHECK expr onconf",
- /* 88 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt",
- /* 89 */ "defer_subclause_opt ::=",
- /* 90 */ "defer_subclause_opt ::= defer_subclause",
- /* 91 */ "onconf ::=",
- /* 92 */ "onconf ::= ON CONFLICT resolvetype",
- /* 93 */ "orconf ::=",
- /* 94 */ "orconf ::= OR resolvetype",
- /* 95 */ "resolvetype ::= raisetype",
- /* 96 */ "resolvetype ::= IGNORE",
- /* 97 */ "resolvetype ::= REPLACE",
- /* 98 */ "cmd ::= DROP TABLE fullname",
- /* 99 */ "cmd ::= CREATE temp VIEW nm dbnm AS select",
- /* 100 */ "cmd ::= DROP VIEW fullname",
- /* 101 */ "cmd ::= select",
- /* 102 */ "select ::= oneselect",
- /* 103 */ "select ::= select multiselect_op oneselect",
- /* 104 */ "multiselect_op ::= UNION",
- /* 105 */ "multiselect_op ::= UNION ALL",
- /* 106 */ "multiselect_op ::= INTERSECT",
- /* 107 */ "multiselect_op ::= EXCEPT",
- /* 108 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
- /* 109 */ "distinct ::= DISTINCT",
- /* 110 */ "distinct ::= ALL",
- /* 111 */ "distinct ::=",
- /* 112 */ "sclp ::= selcollist COMMA",
- /* 113 */ "sclp ::=",
- /* 114 */ "selcollist ::= sclp expr as",
- /* 115 */ "selcollist ::= sclp STAR",
- /* 116 */ "selcollist ::= sclp nm DOT STAR",
- /* 117 */ "as ::= AS nm",
- /* 118 */ "as ::= ids",
- /* 119 */ "as ::=",
- /* 120 */ "from ::=",
- /* 121 */ "from ::= FROM seltablist",
- /* 122 */ "stl_prefix ::= seltablist joinop",
- /* 123 */ "stl_prefix ::=",
- /* 124 */ "seltablist ::= stl_prefix nm dbnm as on_opt using_opt",
- /* 125 */ "seltablist ::= stl_prefix LP seltablist_paren RP as on_opt using_opt",
- /* 126 */ "seltablist_paren ::= select",
- /* 127 */ "seltablist_paren ::= seltablist",
- /* 128 */ "dbnm ::=",
- /* 129 */ "dbnm ::= DOT nm",
- /* 130 */ "fullname ::= nm dbnm",
- /* 131 */ "joinop ::= COMMA",
- /* 132 */ "joinop ::= JOIN",
- /* 133 */ "joinop ::= JOIN_KW JOIN",
- /* 134 */ "joinop ::= JOIN_KW nm JOIN",
- /* 135 */ "joinop ::= JOIN_KW nm nm JOIN",
- /* 136 */ "on_opt ::= ON expr",
- /* 137 */ "on_opt ::=",
- /* 138 */ "using_opt ::= USING LP inscollist RP",
- /* 139 */ "using_opt ::=",
- /* 140 */ "orderby_opt ::=",
- /* 141 */ "orderby_opt ::= ORDER BY sortlist",
- /* 142 */ "sortlist ::= sortlist COMMA sortitem collate sortorder",
- /* 143 */ "sortlist ::= sortitem collate sortorder",
- /* 144 */ "sortitem ::= expr",
- /* 145 */ "sortorder ::= ASC",
- /* 146 */ "sortorder ::= DESC",
- /* 147 */ "sortorder ::=",
- /* 148 */ "collate ::=",
- /* 149 */ "collate ::= COLLATE id",
- /* 150 */ "groupby_opt ::=",
- /* 151 */ "groupby_opt ::= GROUP BY exprlist",
- /* 152 */ "having_opt ::=",
- /* 153 */ "having_opt ::= HAVING expr",
- /* 154 */ "limit_opt ::=",
- /* 155 */ "limit_opt ::= LIMIT expr",
- /* 156 */ "limit_opt ::= LIMIT expr OFFSET expr",
- /* 157 */ "limit_opt ::= LIMIT expr COMMA expr",
- /* 158 */ "cmd ::= DELETE FROM fullname where_opt",
- /* 159 */ "where_opt ::=",
- /* 160 */ "where_opt ::= WHERE expr",
- /* 161 */ "cmd ::= UPDATE orconf fullname SET setlist where_opt",
- /* 162 */ "setlist ::= setlist COMMA nm EQ expr",
- /* 163 */ "setlist ::= nm EQ expr",
- /* 164 */ "cmd ::= insert_cmd INTO fullname inscollist_opt VALUES LP itemlist RP",
- /* 165 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select",
- /* 166 */ "insert_cmd ::= INSERT orconf",
- /* 167 */ "insert_cmd ::= REPLACE",
- /* 168 */ "itemlist ::= itemlist COMMA expr",
- /* 169 */ "itemlist ::= expr",
- /* 170 */ "inscollist_opt ::=",
- /* 171 */ "inscollist_opt ::= LP inscollist RP",
- /* 172 */ "inscollist ::= inscollist COMMA nm",
- /* 173 */ "inscollist ::= nm",
- /* 174 */ "expr ::= term",
- /* 175 */ "expr ::= LP expr RP",
- /* 176 */ "term ::= NULL",
- /* 177 */ "expr ::= ID",
- /* 178 */ "expr ::= JOIN_KW",
- /* 179 */ "expr ::= nm DOT nm",
- /* 180 */ "expr ::= nm DOT nm DOT nm",
- /* 181 */ "term ::= INTEGER",
- /* 182 */ "term ::= FLOAT",
+ /* 21 */ "create_table ::= CREATE temp TABLE ifnotexists nm dbnm",
+ /* 22 */ "ifnotexists ::=",
+ /* 23 */ "ifnotexists ::= IF NOT EXISTS",
+ /* 24 */ "temp ::= TEMP",
+ /* 25 */ "temp ::=",
+ /* 26 */ "create_table_args ::= LP columnlist conslist_opt RP",
+ /* 27 */ "create_table_args ::= AS select",
+ /* 28 */ "columnlist ::= columnlist COMMA column",
+ /* 29 */ "columnlist ::= column",
+ /* 30 */ "column ::= columnid type carglist",
+ /* 31 */ "columnid ::= nm",
+ /* 32 */ "id ::= ID",
+ /* 33 */ "ids ::= ID|STRING",
+ /* 34 */ "nm ::= ID",
+ /* 35 */ "nm ::= STRING",
+ /* 36 */ "nm ::= JOIN_KW",
+ /* 37 */ "type ::=",
+ /* 38 */ "type ::= typetoken",
+ /* 39 */ "typetoken ::= typename",
+ /* 40 */ "typetoken ::= typename LP signed RP",
+ /* 41 */ "typetoken ::= typename LP signed COMMA signed RP",
+ /* 42 */ "typename ::= ids",
+ /* 43 */ "typename ::= typename ids",
+ /* 44 */ "signed ::= plus_num",
+ /* 45 */ "signed ::= minus_num",
+ /* 46 */ "carglist ::= carglist carg",
+ /* 47 */ "carglist ::=",
+ /* 48 */ "carg ::= CONSTRAINT nm ccons",
+ /* 49 */ "carg ::= ccons",
+ /* 50 */ "carg ::= DEFAULT term",
+ /* 51 */ "carg ::= DEFAULT LP expr RP",
+ /* 52 */ "carg ::= DEFAULT PLUS term",
+ /* 53 */ "carg ::= DEFAULT MINUS term",
+ /* 54 */ "carg ::= DEFAULT id",
+ /* 55 */ "ccons ::= NULL onconf",
+ /* 56 */ "ccons ::= NOT NULL onconf",
+ /* 57 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
+ /* 58 */ "ccons ::= UNIQUE onconf",
+ /* 59 */ "ccons ::= CHECK LP expr RP",
+ /* 60 */ "ccons ::= REFERENCES nm idxlist_opt refargs",
+ /* 61 */ "ccons ::= defer_subclause",
+ /* 62 */ "ccons ::= COLLATE id",
+ /* 63 */ "autoinc ::=",
+ /* 64 */ "autoinc ::= AUTOINCR",
+ /* 65 */ "refargs ::=",
+ /* 66 */ "refargs ::= refargs refarg",
+ /* 67 */ "refarg ::= MATCH nm",
+ /* 68 */ "refarg ::= ON DELETE refact",
+ /* 69 */ "refarg ::= ON UPDATE refact",
+ /* 70 */ "refarg ::= ON INSERT refact",
+ /* 71 */ "refact ::= SET NULL",
+ /* 72 */ "refact ::= SET DEFAULT",
+ /* 73 */ "refact ::= CASCADE",
+ /* 74 */ "refact ::= RESTRICT",
+ /* 75 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
+ /* 76 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
+ /* 77 */ "init_deferred_pred_opt ::=",
+ /* 78 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
+ /* 79 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
+ /* 80 */ "conslist_opt ::=",
+ /* 81 */ "conslist_opt ::= COMMA conslist",
+ /* 82 */ "conslist ::= conslist COMMA tcons",
+ /* 83 */ "conslist ::= conslist tcons",
+ /* 84 */ "conslist ::= tcons",
+ /* 85 */ "tcons ::= CONSTRAINT nm",
+ /* 86 */ "tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf",
+ /* 87 */ "tcons ::= UNIQUE LP idxlist RP onconf",
+ /* 88 */ "tcons ::= CHECK LP expr RP onconf",
+ /* 89 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt",
+ /* 90 */ "defer_subclause_opt ::=",
+ /* 91 */ "defer_subclause_opt ::= defer_subclause",
+ /* 92 */ "onconf ::=",
+ /* 93 */ "onconf ::= ON CONFLICT resolvetype",
+ /* 94 */ "orconf ::=",
+ /* 95 */ "orconf ::= OR resolvetype",
+ /* 96 */ "resolvetype ::= raisetype",
+ /* 97 */ "resolvetype ::= IGNORE",
+ /* 98 */ "resolvetype ::= REPLACE",
+ /* 99 */ "cmd ::= DROP TABLE ifexists fullname",
+ /* 100 */ "ifexists ::= IF EXISTS",
+ /* 101 */ "ifexists ::=",
+ /* 102 */ "cmd ::= CREATE temp VIEW nm dbnm AS select",
+ /* 103 */ "cmd ::= DROP VIEW ifexists fullname",
+ /* 104 */ "cmd ::= select",
+ /* 105 */ "select ::= oneselect",
+ /* 106 */ "select ::= select multiselect_op oneselect",
+ /* 107 */ "multiselect_op ::= UNION",
+ /* 108 */ "multiselect_op ::= UNION ALL",
+ /* 109 */ "multiselect_op ::= EXCEPT|INTERSECT",
+ /* 110 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
+ /* 111 */ "distinct ::= DISTINCT",
+ /* 112 */ "distinct ::= ALL",
+ /* 113 */ "distinct ::=",
+ /* 114 */ "sclp ::= selcollist COMMA",
+ /* 115 */ "sclp ::=",
+ /* 116 */ "selcollist ::= sclp expr as",
+ /* 117 */ "selcollist ::= sclp STAR",
+ /* 118 */ "selcollist ::= sclp nm DOT STAR",
+ /* 119 */ "as ::= AS nm",
+ /* 120 */ "as ::= ids",
+ /* 121 */ "as ::=",
+ /* 122 */ "from ::=",
+ /* 123 */ "from ::= FROM seltablist",
+ /* 124 */ "stl_prefix ::= seltablist joinop",
+ /* 125 */ "stl_prefix ::=",
+ /* 126 */ "seltablist ::= stl_prefix nm dbnm as on_opt using_opt",
+ /* 127 */ "seltablist ::= stl_prefix LP seltablist_paren RP as on_opt using_opt",
+ /* 128 */ "seltablist_paren ::= select",
+ /* 129 */ "seltablist_paren ::= seltablist",
+ /* 130 */ "dbnm ::=",
+ /* 131 */ "dbnm ::= DOT nm",
+ /* 132 */ "fullname ::= nm dbnm",
+ /* 133 */ "joinop ::= COMMA|JOIN",
+ /* 134 */ "joinop ::= JOIN_KW JOIN",
+ /* 135 */ "joinop ::= JOIN_KW nm JOIN",
+ /* 136 */ "joinop ::= JOIN_KW nm nm JOIN",
+ /* 137 */ "on_opt ::= ON expr",
+ /* 138 */ "on_opt ::=",
+ /* 139 */ "using_opt ::= USING LP inscollist RP",
+ /* 140 */ "using_opt ::=",
+ /* 141 */ "orderby_opt ::=",
+ /* 142 */ "orderby_opt ::= ORDER BY sortlist",
+ /* 143 */ "sortlist ::= sortlist COMMA sortitem collate sortorder",
+ /* 144 */ "sortlist ::= sortitem collate sortorder",
+ /* 145 */ "sortitem ::= expr",
+ /* 146 */ "sortorder ::= ASC",
+ /* 147 */ "sortorder ::= DESC",
+ /* 148 */ "sortorder ::=",
+ /* 149 */ "collate ::=",
+ /* 150 */ "collate ::= COLLATE id",
+ /* 151 */ "groupby_opt ::=",
+ /* 152 */ "groupby_opt ::= GROUP BY exprlist",
+ /* 153 */ "having_opt ::=",
+ /* 154 */ "having_opt ::= HAVING expr",
+ /* 155 */ "limit_opt ::=",
+ /* 156 */ "limit_opt ::= LIMIT expr",
+ /* 157 */ "limit_opt ::= LIMIT expr OFFSET expr",
+ /* 158 */ "limit_opt ::= LIMIT expr COMMA expr",
+ /* 159 */ "cmd ::= DELETE FROM fullname where_opt",
+ /* 160 */ "where_opt ::=",
+ /* 161 */ "where_opt ::= WHERE expr",
+ /* 162 */ "cmd ::= UPDATE orconf fullname SET setlist where_opt",
+ /* 163 */ "setlist ::= setlist COMMA nm EQ expr",
+ /* 164 */ "setlist ::= nm EQ expr",
+ /* 165 */ "cmd ::= insert_cmd INTO fullname inscollist_opt VALUES LP itemlist RP",
+ /* 166 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select",
+ /* 167 */ "insert_cmd ::= INSERT orconf",
+ /* 168 */ "insert_cmd ::= REPLACE",
+ /* 169 */ "itemlist ::= itemlist COMMA expr",
+ /* 170 */ "itemlist ::= expr",
+ /* 171 */ "inscollist_opt ::=",
+ /* 172 */ "inscollist_opt ::= LP inscollist RP",
+ /* 173 */ "inscollist ::= inscollist COMMA nm",
+ /* 174 */ "inscollist ::= nm",
+ /* 175 */ "expr ::= term",
+ /* 176 */ "expr ::= LP expr RP",
+ /* 177 */ "term ::= NULL",
+ /* 178 */ "expr ::= ID",
+ /* 179 */ "expr ::= JOIN_KW",
+ /* 180 */ "expr ::= nm DOT nm",
+ /* 181 */ "expr ::= nm DOT nm DOT nm",
+ /* 182 */ "term ::= INTEGER|FLOAT|BLOB",
/* 183 */ "term ::= STRING",
- /* 184 */ "term ::= BLOB",
- /* 185 */ "expr ::= REGISTER",
- /* 186 */ "expr ::= VARIABLE",
- /* 187 */ "expr ::= CAST LP expr AS typetoken RP",
- /* 188 */ "expr ::= ID LP distinct exprlist RP",
- /* 189 */ "expr ::= ID LP STAR RP",
- /* 190 */ "term ::= CTIME_KW",
- /* 191 */ "expr ::= expr AND expr",
- /* 192 */ "expr ::= expr OR expr",
- /* 193 */ "expr ::= expr LT expr",
- /* 194 */ "expr ::= expr GT expr",
- /* 195 */ "expr ::= expr LE expr",
- /* 196 */ "expr ::= expr GE expr",
- /* 197 */ "expr ::= expr NE expr",
- /* 198 */ "expr ::= expr EQ expr",
- /* 199 */ "expr ::= expr BITAND expr",
- /* 200 */ "expr ::= expr BITOR expr",
- /* 201 */ "expr ::= expr LSHIFT expr",
- /* 202 */ "expr ::= expr RSHIFT expr",
- /* 203 */ "expr ::= expr PLUS expr",
- /* 204 */ "expr ::= expr MINUS expr",
- /* 205 */ "expr ::= expr STAR expr",
- /* 206 */ "expr ::= expr SLASH expr",
- /* 207 */ "expr ::= expr REM expr",
- /* 208 */ "expr ::= expr CONCAT expr",
- /* 209 */ "likeop ::= LIKE_KW",
- /* 210 */ "likeop ::= NOT LIKE_KW",
- /* 211 */ "escape ::= ESCAPE expr",
- /* 212 */ "escape ::=",
- /* 213 */ "expr ::= expr likeop expr escape",
- /* 214 */ "expr ::= expr ISNULL",
- /* 215 */ "expr ::= expr IS NULL",
- /* 216 */ "expr ::= expr NOTNULL",
- /* 217 */ "expr ::= expr NOT NULL",
- /* 218 */ "expr ::= expr IS NOT NULL",
- /* 219 */ "expr ::= NOT expr",
- /* 220 */ "expr ::= BITNOT expr",
- /* 221 */ "expr ::= MINUS expr",
- /* 222 */ "expr ::= PLUS expr",
- /* 223 */ "between_op ::= BETWEEN",
- /* 224 */ "between_op ::= NOT BETWEEN",
- /* 225 */ "expr ::= expr between_op expr AND expr",
- /* 226 */ "in_op ::= IN",
- /* 227 */ "in_op ::= NOT IN",
- /* 228 */ "expr ::= expr in_op LP exprlist RP",
- /* 229 */ "expr ::= LP select RP",
- /* 230 */ "expr ::= expr in_op LP select RP",
- /* 231 */ "expr ::= expr in_op nm dbnm",
- /* 232 */ "expr ::= EXISTS LP select RP",
- /* 233 */ "expr ::= CASE case_operand case_exprlist case_else END",
- /* 234 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
- /* 235 */ "case_exprlist ::= WHEN expr THEN expr",
- /* 236 */ "case_else ::= ELSE expr",
- /* 237 */ "case_else ::=",
- /* 238 */ "case_operand ::= expr",
- /* 239 */ "case_operand ::=",
- /* 240 */ "exprlist ::= exprlist COMMA expritem",
- /* 241 */ "exprlist ::= expritem",
- /* 242 */ "expritem ::= expr",
- /* 243 */ "expritem ::=",
- /* 244 */ "cmd ::= CREATE uniqueflag INDEX nm dbnm ON nm LP idxlist RP onconf",
- /* 245 */ "uniqueflag ::= UNIQUE",
- /* 246 */ "uniqueflag ::=",
- /* 247 */ "idxlist_opt ::=",
- /* 248 */ "idxlist_opt ::= LP idxlist RP",
- /* 249 */ "idxlist ::= idxlist COMMA idxitem collate sortorder",
- /* 250 */ "idxlist ::= idxitem collate sortorder",
- /* 251 */ "idxitem ::= nm",
- /* 252 */ "cmd ::= DROP INDEX fullname",
- /* 253 */ "cmd ::= VACUUM",
- /* 254 */ "cmd ::= VACUUM nm",
- /* 255 */ "cmd ::= PRAGMA nm dbnm EQ nm",
- /* 256 */ "cmd ::= PRAGMA nm dbnm EQ ON",
- /* 257 */ "cmd ::= PRAGMA nm dbnm EQ plus_num",
- /* 258 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
- /* 259 */ "cmd ::= PRAGMA nm dbnm LP nm RP",
- /* 260 */ "cmd ::= PRAGMA nm dbnm",
- /* 261 */ "plus_num ::= plus_opt number",
- /* 262 */ "minus_num ::= MINUS number",
- /* 263 */ "number ::= INTEGER",
- /* 264 */ "number ::= FLOAT",
- /* 265 */ "plus_opt ::= PLUS",
- /* 266 */ "plus_opt ::=",
- /* 267 */ "cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END",
- /* 268 */ "trigger_decl ::= temp TRIGGER nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
- /* 269 */ "trigger_time ::= BEFORE",
- /* 270 */ "trigger_time ::= AFTER",
- /* 271 */ "trigger_time ::= INSTEAD OF",
- /* 272 */ "trigger_time ::=",
- /* 273 */ "trigger_event ::= DELETE",
- /* 274 */ "trigger_event ::= INSERT",
- /* 275 */ "trigger_event ::= UPDATE",
- /* 276 */ "trigger_event ::= UPDATE OF inscollist",
- /* 277 */ "foreach_clause ::=",
- /* 278 */ "foreach_clause ::= FOR EACH ROW",
- /* 279 */ "foreach_clause ::= FOR EACH STATEMENT",
- /* 280 */ "when_clause ::=",
- /* 281 */ "when_clause ::= WHEN expr",
- /* 282 */ "trigger_cmd_list ::= trigger_cmd SEMI trigger_cmd_list",
- /* 283 */ "trigger_cmd_list ::=",
- /* 284 */ "trigger_cmd ::= UPDATE orconf nm SET setlist where_opt",
- /* 285 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt VALUES LP itemlist RP",
- /* 286 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt select",
- /* 287 */ "trigger_cmd ::= DELETE FROM nm where_opt",
- /* 288 */ "trigger_cmd ::= select",
- /* 289 */ "expr ::= RAISE LP IGNORE RP",
- /* 290 */ "expr ::= RAISE LP raisetype COMMA nm RP",
- /* 291 */ "raisetype ::= ROLLBACK",
- /* 292 */ "raisetype ::= ABORT",
- /* 293 */ "raisetype ::= FAIL",
- /* 294 */ "cmd ::= DROP TRIGGER fullname",
- /* 295 */ "cmd ::= ATTACH database_kw_opt ids AS nm key_opt",
- /* 296 */ "key_opt ::=",
- /* 297 */ "key_opt ::= KEY ids",
- /* 298 */ "key_opt ::= KEY BLOB",
- /* 299 */ "database_kw_opt ::= DATABASE",
- /* 300 */ "database_kw_opt ::=",
- /* 301 */ "cmd ::= DETACH database_kw_opt nm",
- /* 302 */ "cmd ::= REINDEX",
- /* 303 */ "cmd ::= REINDEX nm dbnm",
- /* 304 */ "cmd ::= ANALYZE",
- /* 305 */ "cmd ::= ANALYZE nm dbnm",
- /* 306 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
- /* 307 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column",
- /* 308 */ "add_column_fullname ::= fullname",
- /* 309 */ "kwcolumn_opt ::=",
- /* 310 */ "kwcolumn_opt ::= COLUMNKW",
+ /* 184 */ "expr ::= REGISTER",
+ /* 185 */ "expr ::= VARIABLE",
+ /* 186 */ "expr ::= CAST LP expr AS typetoken RP",
+ /* 187 */ "expr ::= ID LP distinct exprlist RP",
+ /* 188 */ "expr ::= ID LP STAR RP",
+ /* 189 */ "term ::= CTIME_KW",
+ /* 190 */ "expr ::= expr AND expr",
+ /* 191 */ "expr ::= expr OR expr",
+ /* 192 */ "expr ::= expr LT|GT|GE|LE expr",
+ /* 193 */ "expr ::= expr EQ|NE expr",
+ /* 194 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
+ /* 195 */ "expr ::= expr PLUS|MINUS expr",
+ /* 196 */ "expr ::= expr STAR|SLASH|REM expr",
+ /* 197 */ "expr ::= expr CONCAT expr",
+ /* 198 */ "likeop ::= LIKE_KW",
+ /* 199 */ "likeop ::= NOT LIKE_KW",
+ /* 200 */ "likeop ::= MATCH",
+ /* 201 */ "likeop ::= NOT MATCH",
+ /* 202 */ "escape ::= ESCAPE expr",
+ /* 203 */ "escape ::=",
+ /* 204 */ "expr ::= expr likeop expr escape",
+ /* 205 */ "expr ::= expr ISNULL|NOTNULL",
+ /* 206 */ "expr ::= expr IS NULL",
+ /* 207 */ "expr ::= expr NOT NULL",
+ /* 208 */ "expr ::= expr IS NOT NULL",
+ /* 209 */ "expr ::= NOT|BITNOT expr",
+ /* 210 */ "expr ::= MINUS expr",
+ /* 211 */ "expr ::= PLUS expr",
+ /* 212 */ "between_op ::= BETWEEN",
+ /* 213 */ "between_op ::= NOT BETWEEN",
+ /* 214 */ "expr ::= expr between_op expr AND expr",
+ /* 215 */ "in_op ::= IN",
+ /* 216 */ "in_op ::= NOT IN",
+ /* 217 */ "expr ::= expr in_op LP exprlist RP",
+ /* 218 */ "expr ::= LP select RP",
+ /* 219 */ "expr ::= expr in_op LP select RP",
+ /* 220 */ "expr ::= expr in_op nm dbnm",
+ /* 221 */ "expr ::= EXISTS LP select RP",
+ /* 222 */ "expr ::= CASE case_operand case_exprlist case_else END",
+ /* 223 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
+ /* 224 */ "case_exprlist ::= WHEN expr THEN expr",
+ /* 225 */ "case_else ::= ELSE expr",
+ /* 226 */ "case_else ::=",
+ /* 227 */ "case_operand ::= expr",
+ /* 228 */ "case_operand ::=",
+ /* 229 */ "exprlist ::= exprlist COMMA expritem",
+ /* 230 */ "exprlist ::= expritem",
+ /* 231 */ "expritem ::= expr",
+ /* 232 */ "expritem ::=",
+ /* 233 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP",
+ /* 234 */ "uniqueflag ::= UNIQUE",
+ /* 235 */ "uniqueflag ::=",
+ /* 236 */ "idxlist_opt ::=",
+ /* 237 */ "idxlist_opt ::= LP idxlist RP",
+ /* 238 */ "idxlist ::= idxlist COMMA idxitem collate sortorder",
+ /* 239 */ "idxlist ::= idxitem collate sortorder",
+ /* 240 */ "idxitem ::= nm",
+ /* 241 */ "cmd ::= DROP INDEX ifexists fullname",
+ /* 242 */ "cmd ::= VACUUM",
+ /* 243 */ "cmd ::= VACUUM nm",
+ /* 244 */ "cmd ::= PRAGMA nm dbnm EQ nm",
+ /* 245 */ "cmd ::= PRAGMA nm dbnm EQ ON",
+ /* 246 */ "cmd ::= PRAGMA nm dbnm EQ plus_num",
+ /* 247 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
+ /* 248 */ "cmd ::= PRAGMA nm dbnm LP nm RP",
+ /* 249 */ "cmd ::= PRAGMA nm dbnm",
+ /* 250 */ "plus_num ::= plus_opt number",
+ /* 251 */ "minus_num ::= MINUS number",
+ /* 252 */ "number ::= INTEGER|FLOAT",
+ /* 253 */ "plus_opt ::= PLUS",
+ /* 254 */ "plus_opt ::=",
+ /* 255 */ "cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END",
+ /* 256 */ "trigger_decl ::= temp TRIGGER nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
+ /* 257 */ "trigger_time ::= BEFORE",
+ /* 258 */ "trigger_time ::= AFTER",
+ /* 259 */ "trigger_time ::= INSTEAD OF",
+ /* 260 */ "trigger_time ::=",
+ /* 261 */ "trigger_event ::= DELETE|INSERT",
+ /* 262 */ "trigger_event ::= UPDATE",
+ /* 263 */ "trigger_event ::= UPDATE OF inscollist",
+ /* 264 */ "foreach_clause ::=",
+ /* 265 */ "foreach_clause ::= FOR EACH ROW",
+ /* 266 */ "foreach_clause ::= FOR EACH STATEMENT",
+ /* 267 */ "when_clause ::=",
+ /* 268 */ "when_clause ::= WHEN expr",
+ /* 269 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
+ /* 270 */ "trigger_cmd_list ::=",
+ /* 271 */ "trigger_cmd ::= UPDATE orconf nm SET setlist where_opt",
+ /* 272 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt VALUES LP itemlist RP",
+ /* 273 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt select",
+ /* 274 */ "trigger_cmd ::= DELETE FROM nm where_opt",
+ /* 275 */ "trigger_cmd ::= select",
+ /* 276 */ "expr ::= RAISE LP IGNORE RP",
+ /* 277 */ "expr ::= RAISE LP raisetype COMMA nm RP",
+ /* 278 */ "raisetype ::= ROLLBACK",
+ /* 279 */ "raisetype ::= ABORT",
+ /* 280 */ "raisetype ::= FAIL",
+ /* 281 */ "cmd ::= DROP TRIGGER fullname",
+ /* 282 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
+ /* 283 */ "key_opt ::=",
+ /* 284 */ "key_opt ::= KEY expr",
+ /* 285 */ "database_kw_opt ::= DATABASE",
+ /* 286 */ "database_kw_opt ::=",
+ /* 287 */ "cmd ::= DETACH database_kw_opt expr",
+ /* 288 */ "cmd ::= REINDEX",
+ /* 289 */ "cmd ::= REINDEX nm dbnm",
+ /* 290 */ "cmd ::= ANALYZE",
+ /* 291 */ "cmd ::= ANALYZE nm dbnm",
+ /* 292 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
+ /* 293 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column",
+ /* 294 */ "add_column_fullname ::= fullname",
+ /* 295 */ "kwcolumn_opt ::=",
+ /* 296 */ "kwcolumn_opt ::= COLUMNKW",
+ /* 297 */ "cmd ::= create_vtab",
+ /* 298 */ "cmd ::= create_vtab LP vtabarglist RP",
+ /* 299 */ "create_vtab ::= CREATE VIRTUAL TABLE nm dbnm USING nm",
+ /* 300 */ "vtabarglist ::= vtabarg",
+ /* 301 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
+ /* 302 */ "vtabarg ::=",
+ /* 303 */ "vtabarg ::= vtabarg vtabargtoken",
+ /* 304 */ "vtabargtoken ::= ANY",
+ /* 305 */ "vtabargtoken ::= lp anylist RP",
+ /* 306 */ "lp ::= LP",
+ /* 307 */ "anylist ::=",
+ /* 308 */ "anylist ::= anylist ANY",
};
#endif /* NDEBUG */
@@ -1322,72 +1238,81 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
** which appear on the RHS of the rule, but which are not used
** inside the C code.
*/
- case 162:
+ case 156:
+ case 190:
+ case 207:
+#line 374 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3SelectDelete((yypminor->yy219));}
+#line 1248 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 170:
+ case 171:
case 195:
- case 212:
-#line 370 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3SelectDelete((yypminor->yy375));}
-#line 1332 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 197:
+ case 205:
+ case 211:
+ case 219:
+ case 222:
+ case 224:
+ case 225:
+ case 235:
+#line 631 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3ExprDelete((yypminor->yy172));}
+#line 1263 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 176:
- case 177:
+ case 175:
+ case 183:
+ case 193:
+ case 196:
+ case 198:
case 200:
- case 202:
case 210:
- case 216:
- case 230:
-#line 629 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3ExprDelete((yypminor->yy62));}
-#line 1343 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 213:
+ case 214:
+ case 217:
+ case 223:
+#line 865 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3ExprListDelete((yypminor->yy174));}
+#line 1278 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 181:
case 189:
- case 198:
- case 201:
+ case 194:
+ case 202:
case 203:
- case 205:
- case 215:
- case 218:
- case 219:
- case 222:
- case 228:
-#line 876 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3ExprListDelete((yypminor->yy418));}
-#line 1358 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 502 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3SrcListDelete((yypminor->yy373));}
+#line 1286 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 194:
case 199:
- case 207:
- case 208:
-#line 499 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3SrcListDelete((yypminor->yy151));}
-#line 1366 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 204:
-#line 561 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 563 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3ExprDelete((yypminor->yy220).pLimit);
- sqlite3ExprDelete((yypminor->yy220).pOffset);
+ sqlite3ExprDelete((yypminor->yy234).pLimit);
+ sqlite3ExprDelete((yypminor->yy234).pOffset);
}
-#line 1374 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1294 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 211:
- case 214:
- case 221:
-#line 517 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3IdListDelete((yypminor->yy240));}
-#line 1381 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 206:
+ case 209:
+ case 216:
+#line 519 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3IdListDelete((yypminor->yy432));}
+#line 1301 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
+ case 231:
case 236:
- case 241:
-#line 969 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3DeleteTriggerStep((yypminor->yy360));}
-#line 1387 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 959 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3DeleteTriggerStep((yypminor->yy243));}
+#line 1307 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 233:
+#line 943 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3IdListDelete((yypminor->yy370).b);}
+#line 1312 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 238:
-#line 953 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3IdListDelete((yypminor->yy30).b);}
-#line 1392 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1027 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3ExprDelete((yypminor->yy386));}
+#line 1317 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
default: break; /* If no destructor action specified: do nothing */
}
@@ -1451,14 +1376,12 @@ void sqlite3ParserFree(
*/
static int yy_find_shift_action(
yyParser *pParser, /* The parser */
- int iLookAhead /* The look-ahead token */
+ YYCODETYPE iLookAhead /* The look-ahead token */
){
int i;
int stateno = pParser->yystack[pParser->yyidx].stateno;
- /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
- i = yy_shift_ofst[stateno];
- if( i==YY_SHIFT_USE_DFLT ){
+ if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
return yy_default[stateno];
}
if( iLookAhead==YYNOCODE ){
@@ -1466,19 +1389,35 @@ static int yy_find_shift_action(
}
i += iLookAhead;
if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
+ if( iLookAhead>0 ){
#ifdef YYFALLBACK
- int iFallback; /* Fallback token */
- if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
- && (iFallback = yyFallback[iLookAhead])!=0 ){
+ int iFallback; /* Fallback token */
+ if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
+ && (iFallback = yyFallback[iLookAhead])!=0 ){
#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
- yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
+ }
+#endif
+ return yy_find_shift_action(pParser, iFallback);
}
#endif
- return yy_find_shift_action(pParser, iFallback);
+#ifdef YYWILDCARD
+ {
+ int j = i - iLookAhead + YYWILDCARD;
+ if( j>=0 && j<YY_SZ_ACTTAB && yy_lookahead[j]==YYWILDCARD ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]);
+ }
+#endif /* NDEBUG */
+ return yy_action[j];
+ }
+ }
+#endif /* YYWILDCARD */
}
-#endif
return yy_default[stateno];
}else{
return yy_action[i];
@@ -1495,13 +1434,13 @@ static int yy_find_shift_action(
*/
static int yy_find_reduce_action(
int stateno, /* Current state number */
- int iLookAhead /* The look-ahead token */
+ YYCODETYPE iLookAhead /* The look-ahead token */
){
int i;
/* int stateno = pParser->yystack[pParser->yyidx].stateno; */
- i = yy_reduce_ofst[stateno];
- if( i==YY_REDUCE_USE_DFLT ){
+ if( stateno>YY_REDUCE_MAX ||
+ (i = yy_reduce_ofst[stateno])==YY_REDUCE_USE_DFLT ){
return yy_default[stateno];
}
if( iLookAhead==YYNOCODE ){
@@ -1537,6 +1476,11 @@ static void yy_shift(
while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
/* Here code is inserted which will execute if the parser
** stack every overflows */
+#line 44 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+
+ sqlite3ErrorMsg(pParse, "parser stack overflow");
+ pParse->parseError = 1;
+#line 1486 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
return;
}
@@ -1563,317 +1507,315 @@ static const struct {
YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
unsigned char nrhs; /* Number of right-hand side symbols in the rule */
} yyRuleInfo[] = {
+ { 140, 1 },
+ { 141, 2 },
+ { 141, 1 },
+ { 143, 1 },
+ { 142, 1 },
+ { 142, 3 },
+ { 145, 0 },
+ { 145, 1 },
+ { 145, 3 },
+ { 144, 3 },
+ { 147, 0 },
{ 147, 1 },
- { 148, 2 },
- { 148, 1 },
- { 150, 1 },
- { 149, 1 },
- { 149, 3 },
+ { 147, 2 },
+ { 146, 0 },
+ { 146, 1 },
+ { 146, 1 },
+ { 146, 1 },
+ { 144, 2 },
+ { 144, 2 },
+ { 144, 2 },
+ { 144, 2 },
+ { 149, 6 },
{ 152, 0 },
- { 152, 1 },
{ 152, 3 },
- { 151, 3 },
- { 154, 0 },
+ { 151, 1 },
+ { 151, 0 },
+ { 150, 4 },
+ { 150, 2 },
+ { 154, 3 },
{ 154, 1 },
- { 154, 2 },
- { 153, 0 },
- { 153, 1 },
- { 153, 1 },
- { 153, 1 },
- { 151, 2 },
- { 151, 2 },
- { 151, 2 },
- { 151, 2 },
- { 156, 5 },
+ { 157, 3 },
{ 158, 1 },
- { 158, 0 },
- { 157, 4 },
- { 157, 2 },
- { 160, 3 },
- { 160, 1 },
- { 163, 3 },
+ { 161, 1 },
+ { 162, 1 },
+ { 148, 1 },
+ { 148, 1 },
+ { 148, 1 },
+ { 159, 0 },
+ { 159, 1 },
+ { 163, 1 },
+ { 163, 4 },
+ { 163, 6 },
{ 164, 1 },
- { 167, 1 },
- { 168, 1 },
- { 168, 1 },
- { 155, 1 },
- { 155, 1 },
- { 155, 1 },
- { 165, 0 },
+ { 164, 2 },
{ 165, 1 },
- { 169, 1 },
+ { 165, 1 },
+ { 160, 2 },
+ { 160, 0 },
+ { 168, 3 },
+ { 168, 1 },
+ { 168, 2 },
+ { 168, 4 },
+ { 168, 3 },
+ { 168, 3 },
+ { 168, 2 },
+ { 169, 2 },
+ { 169, 3 },
+ { 169, 5 },
+ { 169, 2 },
{ 169, 4 },
- { 169, 6 },
- { 170, 1 },
- { 170, 2 },
- { 171, 1 },
- { 171, 1 },
- { 166, 2 },
- { 166, 0 },
- { 174, 3 },
+ { 169, 4 },
+ { 169, 1 },
+ { 169, 2 },
+ { 174, 0 },
{ 174, 1 },
- { 174, 2 },
- { 174, 4 },
- { 174, 3 },
- { 174, 3 },
- { 174, 2 },
- { 175, 2 },
- { 175, 3 },
- { 175, 5 },
- { 175, 2 },
- { 175, 5 },
- { 175, 4 },
- { 175, 1 },
- { 175, 2 },
+ { 176, 0 },
+ { 176, 2 },
+ { 178, 2 },
+ { 178, 3 },
+ { 178, 3 },
+ { 178, 3 },
+ { 179, 2 },
+ { 179, 2 },
+ { 179, 1 },
+ { 179, 1 },
+ { 177, 3 },
+ { 177, 2 },
{ 180, 0 },
- { 180, 1 },
- { 182, 0 },
+ { 180, 2 },
+ { 180, 2 },
+ { 155, 0 },
+ { 155, 2 },
+ { 181, 3 },
+ { 181, 2 },
+ { 181, 1 },
{ 182, 2 },
- { 184, 2 },
- { 184, 3 },
- { 184, 3 },
- { 184, 3 },
+ { 182, 7 },
+ { 182, 5 },
+ { 182, 5 },
+ { 182, 10 },
+ { 184, 0 },
+ { 184, 1 },
+ { 172, 0 },
+ { 172, 3 },
+ { 185, 0 },
{ 185, 2 },
- { 185, 2 },
- { 185, 1 },
- { 185, 1 },
- { 183, 3 },
- { 183, 2 },
- { 186, 0 },
- { 186, 2 },
- { 186, 2 },
- { 161, 0 },
- { 161, 2 },
- { 187, 3 },
- { 187, 2 },
- { 187, 1 },
+ { 186, 1 },
+ { 186, 1 },
+ { 186, 1 },
+ { 144, 4 },
{ 188, 2 },
- { 188, 7 },
- { 188, 5 },
- { 188, 3 },
- { 188, 10 },
- { 190, 0 },
- { 190, 1 },
- { 178, 0 },
- { 178, 3 },
- { 191, 0 },
+ { 188, 0 },
+ { 144, 7 },
+ { 144, 4 },
+ { 144, 1 },
+ { 156, 1 },
+ { 156, 3 },
+ { 191, 1 },
{ 191, 2 },
+ { 191, 1 },
+ { 190, 9 },
{ 192, 1 },
{ 192, 1 },
- { 192, 1 },
- { 151, 3 },
- { 151, 7 },
- { 151, 3 },
- { 151, 1 },
- { 162, 1 },
- { 162, 3 },
- { 196, 1 },
- { 196, 2 },
- { 196, 1 },
- { 196, 1 },
- { 195, 9 },
- { 197, 1 },
- { 197, 1 },
- { 197, 0 },
+ { 192, 0 },
+ { 200, 2 },
+ { 200, 0 },
+ { 193, 3 },
+ { 193, 2 },
+ { 193, 4 },
+ { 201, 2 },
+ { 201, 1 },
+ { 201, 0 },
+ { 194, 0 },
+ { 194, 2 },
+ { 203, 2 },
+ { 203, 0 },
+ { 202, 6 },
+ { 202, 7 },
+ { 207, 1 },
+ { 207, 1 },
+ { 153, 0 },
+ { 153, 2 },
+ { 189, 2 },
+ { 204, 1 },
+ { 204, 2 },
+ { 204, 3 },
+ { 204, 4 },
{ 205, 2 },
{ 205, 0 },
- { 198, 3 },
- { 198, 2 },
- { 198, 4 },
- { 206, 2 },
- { 206, 1 },
+ { 206, 4 },
{ 206, 0 },
+ { 198, 0 },
+ { 198, 3 },
+ { 210, 5 },
+ { 210, 3 },
+ { 211, 1 },
+ { 173, 1 },
+ { 173, 1 },
+ { 173, 0 },
+ { 212, 0 },
+ { 212, 2 },
+ { 196, 0 },
+ { 196, 3 },
+ { 197, 0 },
+ { 197, 2 },
{ 199, 0 },
{ 199, 2 },
- { 208, 2 },
- { 208, 0 },
- { 207, 6 },
- { 207, 7 },
- { 212, 1 },
- { 212, 1 },
- { 159, 0 },
- { 159, 2 },
- { 194, 2 },
- { 209, 1 },
- { 209, 1 },
- { 209, 2 },
+ { 199, 4 },
+ { 199, 4 },
+ { 144, 4 },
+ { 195, 0 },
+ { 195, 2 },
+ { 144, 6 },
+ { 214, 5 },
+ { 214, 3 },
+ { 144, 8 },
+ { 144, 5 },
+ { 215, 2 },
+ { 215, 1 },
+ { 217, 3 },
+ { 217, 1 },
+ { 216, 0 },
+ { 216, 3 },
{ 209, 3 },
- { 209, 4 },
- { 210, 2 },
- { 210, 0 },
- { 211, 4 },
- { 211, 0 },
- { 203, 0 },
- { 203, 3 },
- { 215, 5 },
- { 215, 3 },
- { 216, 1 },
- { 179, 1 },
- { 179, 1 },
- { 179, 0 },
- { 217, 0 },
- { 217, 2 },
- { 201, 0 },
- { 201, 3 },
- { 202, 0 },
- { 202, 2 },
- { 204, 0 },
- { 204, 2 },
- { 204, 4 },
- { 204, 4 },
- { 151, 4 },
- { 200, 0 },
- { 200, 2 },
- { 151, 6 },
- { 219, 5 },
- { 219, 3 },
- { 151, 8 },
- { 151, 5 },
- { 220, 2 },
+ { 209, 1 },
+ { 171, 1 },
+ { 171, 3 },
+ { 170, 1 },
+ { 171, 1 },
+ { 171, 1 },
+ { 171, 3 },
+ { 171, 5 },
+ { 170, 1 },
+ { 170, 1 },
+ { 171, 1 },
+ { 171, 1 },
+ { 171, 6 },
+ { 171, 5 },
+ { 171, 4 },
+ { 170, 1 },
+ { 171, 3 },
+ { 171, 3 },
+ { 171, 3 },
+ { 171, 3 },
+ { 171, 3 },
+ { 171, 3 },
+ { 171, 3 },
+ { 171, 3 },
+ { 218, 1 },
+ { 218, 2 },
+ { 218, 1 },
+ { 218, 2 },
+ { 219, 2 },
+ { 219, 0 },
+ { 171, 4 },
+ { 171, 2 },
+ { 171, 3 },
+ { 171, 3 },
+ { 171, 4 },
+ { 171, 2 },
+ { 171, 2 },
+ { 171, 2 },
{ 220, 1 },
- { 222, 3 },
- { 222, 1 },
- { 221, 0 },
- { 221, 3 },
- { 214, 3 },
- { 214, 1 },
- { 177, 1 },
- { 177, 3 },
- { 176, 1 },
- { 177, 1 },
- { 177, 1 },
- { 177, 3 },
- { 177, 5 },
- { 176, 1 },
- { 176, 1 },
- { 176, 1 },
- { 176, 1 },
- { 177, 1 },
- { 177, 1 },
- { 177, 6 },
- { 177, 5 },
- { 177, 4 },
- { 176, 1 },
- { 177, 3 },
- { 177, 3 },
- { 177, 3 },
- { 177, 3 },
- { 177, 3 },
- { 177, 3 },
- { 177, 3 },
- { 177, 3 },
- { 177, 3 },
- { 177, 3 },
- { 177, 3 },
- { 177, 3 },
- { 177, 3 },
- { 177, 3 },
- { 177, 3 },
- { 177, 3 },
- { 177, 3 },
- { 177, 3 },
- { 223, 1 },
- { 223, 2 },
+ { 220, 2 },
+ { 171, 5 },
+ { 221, 1 },
+ { 221, 2 },
+ { 171, 5 },
+ { 171, 3 },
+ { 171, 5 },
+ { 171, 4 },
+ { 171, 4 },
+ { 171, 5 },
+ { 223, 5 },
+ { 223, 4 },
{ 224, 2 },
{ 224, 0 },
- { 177, 4 },
- { 177, 2 },
- { 177, 3 },
- { 177, 2 },
- { 177, 3 },
- { 177, 4 },
- { 177, 2 },
- { 177, 2 },
- { 177, 2 },
- { 177, 2 },
+ { 222, 1 },
+ { 222, 0 },
+ { 213, 3 },
+ { 213, 1 },
{ 225, 1 },
- { 225, 2 },
- { 177, 5 },
+ { 225, 0 },
+ { 144, 11 },
{ 226, 1 },
- { 226, 2 },
- { 177, 5 },
- { 177, 3 },
- { 177, 5 },
- { 177, 4 },
- { 177, 4 },
- { 177, 5 },
- { 228, 5 },
- { 228, 4 },
- { 229, 2 },
- { 229, 0 },
+ { 226, 0 },
+ { 175, 0 },
+ { 175, 3 },
+ { 183, 5 },
+ { 183, 3 },
{ 227, 1 },
- { 227, 0 },
- { 218, 3 },
- { 218, 1 },
- { 230, 1 },
- { 230, 0 },
- { 151, 11 },
- { 231, 1 },
- { 231, 0 },
- { 181, 0 },
- { 181, 3 },
- { 189, 5 },
- { 189, 3 },
+ { 144, 4 },
+ { 144, 1 },
+ { 144, 2 },
+ { 144, 5 },
+ { 144, 5 },
+ { 144, 5 },
+ { 144, 5 },
+ { 144, 6 },
+ { 144, 3 },
+ { 166, 2 },
+ { 167, 2 },
+ { 229, 1 },
+ { 228, 1 },
+ { 228, 0 },
+ { 144, 5 },
+ { 230, 10 },
{ 232, 1 },
- { 151, 3 },
- { 151, 1 },
- { 151, 2 },
- { 151, 5 },
- { 151, 5 },
- { 151, 5 },
- { 151, 5 },
- { 151, 6 },
- { 151, 3 },
- { 172, 2 },
- { 173, 2 },
- { 234, 1 },
- { 234, 1 },
+ { 232, 1 },
+ { 232, 2 },
+ { 232, 0 },
{ 233, 1 },
- { 233, 0 },
- { 151, 5 },
- { 235, 10 },
- { 237, 1 },
+ { 233, 1 },
+ { 233, 3 },
+ { 234, 0 },
+ { 234, 3 },
+ { 234, 3 },
+ { 235, 0 },
+ { 235, 2 },
+ { 231, 3 },
+ { 231, 0 },
+ { 236, 6 },
+ { 236, 8 },
+ { 236, 5 },
+ { 236, 4 },
+ { 236, 1 },
+ { 171, 4 },
+ { 171, 6 },
+ { 187, 1 },
+ { 187, 1 },
+ { 187, 1 },
+ { 144, 3 },
+ { 144, 6 },
+ { 238, 0 },
+ { 238, 2 },
{ 237, 1 },
- { 237, 2 },
{ 237, 0 },
- { 238, 1 },
- { 238, 1 },
- { 238, 1 },
- { 238, 3 },
- { 239, 0 },
- { 239, 3 },
- { 239, 3 },
+ { 144, 3 },
+ { 144, 1 },
+ { 144, 3 },
+ { 144, 1 },
+ { 144, 3 },
+ { 144, 6 },
+ { 144, 6 },
+ { 239, 1 },
{ 240, 0 },
- { 240, 2 },
- { 236, 3 },
- { 236, 0 },
- { 241, 6 },
- { 241, 8 },
- { 241, 5 },
- { 241, 4 },
- { 241, 1 },
- { 177, 4 },
- { 177, 6 },
- { 193, 1 },
- { 193, 1 },
- { 193, 1 },
- { 151, 3 },
- { 151, 6 },
+ { 240, 1 },
+ { 144, 1 },
+ { 144, 4 },
+ { 241, 7 },
+ { 242, 1 },
+ { 242, 3 },
{ 243, 0 },
{ 243, 2 },
- { 243, 2 },
- { 242, 1 },
- { 242, 0 },
- { 151, 3 },
- { 151, 1 },
- { 151, 3 },
- { 151, 1 },
- { 151, 3 },
- { 151, 6 },
- { 151, 6 },
{ 244, 1 },
- { 245, 0 },
+ { 244, 3 },
{ 245, 1 },
+ { 246, 0 },
+ { 246, 2 },
};
static void yy_accept(yyParser*); /* Forward Declaration */
@@ -1895,7 +1837,7 @@ static void yy_reduce(
yymsp = &yypParser->yystack[yypParser->yyidx];
#ifndef NDEBUG
if( yyTraceFILE && yyruleno>=0
- && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
+ && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
yyRuleName[yyruleno]);
}
@@ -1923,777 +1865,781 @@ static void yy_reduce(
** break;
*/
case 3:
-#line 102 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 100 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{ sqlite3FinishCoding(pParse); }
-#line 1930 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1873 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 6:
-#line 105 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 103 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{ sqlite3BeginParse(pParse, 0); }
-#line 1935 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1878 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 7:
-#line 107 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 105 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{ sqlite3BeginParse(pParse, 1); }
-#line 1940 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1883 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 8:
-#line 108 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 106 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{ sqlite3BeginParse(pParse, 2); }
-#line 1945 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1888 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 9:
-#line 114 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy280);}
-#line 1950 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 112 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy46);}
+#line 1893 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 13:
-#line 119 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy280 = TK_DEFERRED;}
-#line 1955 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 117 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy46 = TK_DEFERRED;}
+#line 1898 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 14:
case 15:
case 16:
- case 104:
- case 106:
case 107:
-#line 120 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy280 = yymsp[0].major;}
-#line 1965 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 109:
+#line 118 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy46 = yymsp[0].major;}
+#line 1907 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 17:
case 18:
-#line 123 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 121 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3CommitTransaction(pParse);}
-#line 1971 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1913 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 19:
-#line 125 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 123 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3RollbackTransaction(pParse);}
-#line 1976 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1918 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 21:
-#line 130 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 128 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3StartTable(pParse,&yymsp[-4].minor.yy0,&yymsp[-1].minor.yy198,&yymsp[0].minor.yy198,yymsp[-3].minor.yy280,0);
+ sqlite3StartTable(pParse,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410,yymsp[-4].minor.yy46,0,0,yymsp[-2].minor.yy46);
}
-#line 1983 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1925 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 22:
+ case 25:
case 63:
case 77:
- case 109:
- case 224:
- case 227:
-#line 135 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy280 = 1;}
-#line 1993 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 79:
+ case 90:
+ case 101:
+ case 112:
+ case 113:
+ case 212:
+ case 215:
+#line 132 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy46 = 0;}
+#line 1940 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 23:
- case 62:
- case 76:
+ case 24:
+ case 64:
case 78:
- case 89:
- case 110:
+ case 100:
case 111:
- case 223:
- case 226:
-#line 137 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy280 = 0;}
-#line 2006 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 213:
+ case 216:
+#line 133 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy46 = 1;}
+#line 1952 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 24:
-#line 138 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 26:
+#line 139 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3EndTable(pParse,&yymsp[-1].minor.yy198,&yymsp[0].minor.yy0,0);
+ sqlite3EndTable(pParse,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy0,0);
}
-#line 2013 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1959 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 25:
-#line 141 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 27:
+#line 142 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3EndTable(pParse,0,0,yymsp[0].minor.yy375);
- sqlite3SelectDelete(yymsp[0].minor.yy375);
+ sqlite3EndTable(pParse,0,0,yymsp[0].minor.yy219);
+ sqlite3SelectDelete(yymsp[0].minor.yy219);
}
-#line 2021 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1967 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 28:
-#line 153 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 30:
+#line 154 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy198.z = yymsp[-2].minor.yy198.z;
- yygotominor.yy198.n = (pParse->sLastToken.z-yymsp[-2].minor.yy198.z) + pParse->sLastToken.n;
+ yygotominor.yy410.z = yymsp[-2].minor.yy410.z;
+ yygotominor.yy410.n = (pParse->sLastToken.z-yymsp[-2].minor.yy410.z) + pParse->sLastToken.n;
}
-#line 2029 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1975 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 29:
-#line 157 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 31:
+#line 158 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3AddColumn(pParse,&yymsp[0].minor.yy198);
- yygotominor.yy198 = yymsp[0].minor.yy198;
+ sqlite3AddColumn(pParse,&yymsp[0].minor.yy410);
+ yygotominor.yy410 = yymsp[0].minor.yy410;
}
-#line 2037 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1983 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 30:
- case 31:
case 32:
case 33:
case 34:
case 35:
- case 263:
- case 264:
-#line 167 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy198 = yymsp[0].minor.yy0;}
-#line 2049 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 37:
-#line 227 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy198);}
-#line 2054 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 36:
+ case 252:
+#line 168 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy410 = yymsp[0].minor.yy0;}
+#line 1993 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 38:
- case 41:
- case 117:
- case 118:
- case 129:
- case 149:
- case 251:
- case 261:
- case 262:
-#line 228 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy198 = yymsp[0].minor.yy198;}
-#line 2067 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 228 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy410);}
+#line 1998 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 39:
-#line 229 "ext/pdo_sqlite/sqlite/src/parse.y"
-{
- yygotominor.yy198.z = yymsp[-3].minor.yy198.z;
- yygotominor.yy198.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy198.z;
-}
-#line 2075 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 42:
+ case 119:
+ case 120:
+ case 131:
+ case 150:
+ case 240:
+ case 250:
+ case 251:
+#line 229 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy410 = yymsp[0].minor.yy410;}
+#line 2011 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 40:
-#line 233 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 230 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy198.z = yymsp[-5].minor.yy198.z;
- yygotominor.yy198.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy198.z;
+ yygotominor.yy410.z = yymsp[-3].minor.yy410.z;
+ yygotominor.yy410.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy410.z;
}
-#line 2083 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2019 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 42:
-#line 239 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy198.z=yymsp[-1].minor.yy198.z; yygotominor.yy198.n=yymsp[0].minor.yy198.n+(yymsp[0].minor.yy198.z-yymsp[-1].minor.yy198.z);}
-#line 2088 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 41:
+#line 234 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{
+ yygotominor.yy410.z = yymsp[-5].minor.yy410.z;
+ yygotominor.yy410.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy410.z;
+}
+#line 2027 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 43:
-#line 241 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = atoi(yymsp[0].minor.yy198.z); }
-#line 2093 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 240 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy410.z=yymsp[-1].minor.yy410.z; yygotominor.yy410.n=yymsp[0].minor.yy410.n+(yymsp[0].minor.yy410.z-yymsp[-1].minor.yy410.z);}
+#line 2032 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 44:
-#line 242 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = -atoi(yymsp[0].minor.yy198.z); }
-#line 2098 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 242 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = atoi((char*)yymsp[0].minor.yy410.z); }
+#line 2037 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 49:
- case 51:
-#line 251 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy62);}
-#line 2104 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 45:
+#line 243 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = -atoi((char*)yymsp[0].minor.yy410.z); }
+#line 2042 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 50:
-#line 252 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy62);}
-#line 2109 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
case 52:
-#line 254 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 252 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy172);}
+#line 2048 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 51:
+#line 253 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy172);}
+#line 2053 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 53:
+#line 255 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- Expr *p = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy62, 0, 0);
+ Expr *p = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy172, 0, 0);
sqlite3AddDefaultValue(pParse,p);
}
-#line 2117 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2061 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 53:
-#line 258 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 54:
+#line 259 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- Expr *p = sqlite3Expr(TK_STRING, 0, 0, &yymsp[0].minor.yy198);
+ Expr *p = sqlite3Expr(TK_STRING, 0, 0, &yymsp[0].minor.yy410);
sqlite3AddDefaultValue(pParse,p);
}
-#line 2125 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 55:
-#line 267 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3AddNotNull(pParse, yymsp[0].minor.yy280);}
-#line 2130 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2069 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 56:
-#line 269 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy280,yymsp[0].minor.yy280);}
-#line 2135 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 268 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3AddNotNull(pParse, yymsp[0].minor.yy46);}
+#line 2074 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 57:
-#line 270 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy280,0,0);}
-#line 2140 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 270 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy46,yymsp[0].minor.yy46,yymsp[-2].minor.yy46);}
+#line 2079 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 58:
-#line 271 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3ExprDelete(yymsp[-2].minor.yy62);}
-#line 2145 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 271 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy46,0,0,0,0);}
+#line 2084 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 59:
-#line 273 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy198,yymsp[-1].minor.yy418,yymsp[0].minor.yy280);}
-#line 2150 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 272 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy172);}
+#line 2089 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 60:
-#line 274 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy280);}
-#line 2155 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 274 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy410,yymsp[-1].minor.yy174,yymsp[0].minor.yy46);}
+#line 2094 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 61:
-#line 275 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3AddCollateType(pParse, yymsp[0].minor.yy198.z, yymsp[0].minor.yy198.n);}
-#line 2160 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 275 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy46);}
+#line 2099 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 64:
-#line 288 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = OE_Restrict * 0x010101; }
-#line 2165 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 62:
+#line 276 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3AddCollateType(pParse, (char*)yymsp[0].minor.yy410.z, yymsp[0].minor.yy410.n);}
+#line 2104 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 65:
-#line 289 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = (yymsp[-1].minor.yy280 & yymsp[0].minor.yy359.mask) | yymsp[0].minor.yy359.value; }
-#line 2170 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 289 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = OE_Restrict * 0x010101; }
+#line 2109 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 66:
-#line 291 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy359.value = 0; yygotominor.yy359.mask = 0x000000; }
-#line 2175 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 290 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = (yymsp[-1].minor.yy46 & yymsp[0].minor.yy405.mask) | yymsp[0].minor.yy405.value; }
+#line 2114 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 67:
-#line 292 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy359.value = yymsp[0].minor.yy280; yygotominor.yy359.mask = 0x0000ff; }
-#line 2180 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 292 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy405.value = 0; yygotominor.yy405.mask = 0x000000; }
+#line 2119 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 68:
-#line 293 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy359.value = yymsp[0].minor.yy280<<8; yygotominor.yy359.mask = 0x00ff00; }
-#line 2185 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 293 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy405.value = yymsp[0].minor.yy46; yygotominor.yy405.mask = 0x0000ff; }
+#line 2124 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 69:
-#line 294 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy359.value = yymsp[0].minor.yy280<<16; yygotominor.yy359.mask = 0xff0000; }
-#line 2190 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 294 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy405.value = yymsp[0].minor.yy46<<8; yygotominor.yy405.mask = 0x00ff00; }
+#line 2129 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 70:
-#line 296 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = OE_SetNull; }
-#line 2195 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 295 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy405.value = yymsp[0].minor.yy46<<16; yygotominor.yy405.mask = 0xff0000; }
+#line 2134 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 71:
-#line 297 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = OE_SetDflt; }
-#line 2200 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 297 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = OE_SetNull; }
+#line 2139 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 72:
-#line 298 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = OE_Cascade; }
-#line 2205 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 298 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = OE_SetDflt; }
+#line 2144 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 73:
-#line 299 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = OE_Restrict; }
-#line 2210 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 299 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = OE_Cascade; }
+#line 2149 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 74:
+#line 300 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = OE_Restrict; }
+#line 2154 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
case 75:
- case 90:
- case 92:
- case 94:
+ case 76:
+ case 91:
+ case 93:
case 95:
- case 166:
-#line 301 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy280 = yymsp[0].minor.yy280;}
-#line 2221 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 79:
-#line 311 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy198.n = 0; yygotominor.yy198.z = 0;}
-#line 2226 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 96:
+ case 167:
+#line 302 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy46 = yymsp[0].minor.yy46;}
+#line 2165 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 80:
-#line 312 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy198 = yymsp[-1].minor.yy0;}
-#line 2231 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 312 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy410.n = 0; yygotominor.yy410.z = 0;}
+#line 2170 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 85:
-#line 318 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy418,yymsp[0].minor.yy280,yymsp[-2].minor.yy280);}
-#line 2236 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 81:
+#line 313 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy410 = yymsp[-1].minor.yy0;}
+#line 2175 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 86:
-#line 320 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy418,yymsp[0].minor.yy280,0,0);}
-#line 2241 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 319 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy174,yymsp[0].minor.yy46,yymsp[-2].minor.yy46,0);}
+#line 2180 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 87:
+#line 321 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy174,yymsp[0].minor.yy46,0,0,0,0);}
+#line 2185 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 88:
-#line 323 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 322 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy172);}
+#line 2190 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 89:
+#line 324 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy418, &yymsp[-3].minor.yy198, yymsp[-2].minor.yy418, yymsp[-1].minor.yy280);
- sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy280);
+ sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy174, &yymsp[-3].minor.yy410, yymsp[-2].minor.yy174, yymsp[-1].minor.yy46);
+ sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy46);
}
-#line 2249 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 91:
- case 93:
-#line 337 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy280 = OE_Default;}
-#line 2255 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2198 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 96:
-#line 342 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy280 = OE_Ignore;}
-#line 2260 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 92:
+ case 94:
+#line 338 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy46 = OE_Default;}
+#line 2204 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 97:
- case 167:
-#line 343 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy280 = OE_Replace;}
-#line 2266 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 343 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy46 = OE_Ignore;}
+#line 2209 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 98:
-#line 347 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 168:
+#line 344 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy46 = OE_Replace;}
+#line 2215 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 99:
+#line 348 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3DropTable(pParse, yymsp[0].minor.yy151, 0);
+ sqlite3DropTable(pParse, yymsp[0].minor.yy373, 0, yymsp[-1].minor.yy46);
}
-#line 2273 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2222 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 99:
-#line 354 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 102:
+#line 358 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3CreateView(pParse, &yymsp[-6].minor.yy0, &yymsp[-3].minor.yy198, &yymsp[-2].minor.yy198, yymsp[0].minor.yy375, yymsp[-5].minor.yy280);
+ sqlite3CreateView(pParse, &yymsp[-6].minor.yy0, &yymsp[-3].minor.yy410, &yymsp[-2].minor.yy410, yymsp[0].minor.yy219, yymsp[-5].minor.yy46);
}
-#line 2280 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2229 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 100:
-#line 357 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 103:
+#line 361 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3DropTable(pParse, yymsp[0].minor.yy151, 1);
+ sqlite3DropTable(pParse, yymsp[0].minor.yy373, 1, yymsp[-1].minor.yy46);
}
-#line 2287 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2236 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 101:
-#line 364 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 104:
+#line 368 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3Select(pParse, yymsp[0].minor.yy375, SRT_Callback, 0, 0, 0, 0, 0);
- sqlite3SelectDelete(yymsp[0].minor.yy375);
+ sqlite3Select(pParse, yymsp[0].minor.yy219, SRT_Callback, 0, 0, 0, 0, 0);
+ sqlite3SelectDelete(yymsp[0].minor.yy219);
}
-#line 2295 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2244 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 102:
- case 126:
-#line 374 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy375 = yymsp[0].minor.yy375;}
-#line 2301 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 105:
+ case 128:
+#line 378 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy219 = yymsp[0].minor.yy219;}
+#line 2250 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 103:
-#line 376 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 106:
+#line 380 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- if( yymsp[0].minor.yy375 ){
- yymsp[0].minor.yy375->op = yymsp[-1].minor.yy280;
- yymsp[0].minor.yy375->pPrior = yymsp[-2].minor.yy375;
+ if( yymsp[0].minor.yy219 ){
+ yymsp[0].minor.yy219->op = yymsp[-1].minor.yy46;
+ yymsp[0].minor.yy219->pPrior = yymsp[-2].minor.yy219;
}
- yygotominor.yy375 = yymsp[0].minor.yy375;
+ yygotominor.yy219 = yymsp[0].minor.yy219;
}
-#line 2312 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 105:
-#line 385 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy280 = TK_ALL;}
-#line 2317 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2261 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 108:
-#line 390 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 389 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy46 = TK_ALL;}
+#line 2266 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 110:
+#line 393 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy375 = sqlite3SelectNew(yymsp[-6].minor.yy418,yymsp[-5].minor.yy151,yymsp[-4].minor.yy62,yymsp[-3].minor.yy418,yymsp[-2].minor.yy62,yymsp[-1].minor.yy418,yymsp[-7].minor.yy280,yymsp[0].minor.yy220.pLimit,yymsp[0].minor.yy220.pOffset);
+ yygotominor.yy219 = sqlite3SelectNew(yymsp[-6].minor.yy174,yymsp[-5].minor.yy373,yymsp[-4].minor.yy172,yymsp[-3].minor.yy174,yymsp[-2].minor.yy172,yymsp[-1].minor.yy174,yymsp[-7].minor.yy46,yymsp[0].minor.yy234.pLimit,yymsp[0].minor.yy234.pOffset);
}
-#line 2324 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2273 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 112:
- case 248:
-#line 411 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy418 = yymsp[-1].minor.yy418;}
-#line 2330 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 114:
+ case 237:
+#line 414 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy174 = yymsp[-1].minor.yy174;}
+#line 2279 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 113:
- case 140:
- case 150:
- case 247:
-#line 412 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy418 = 0;}
-#line 2338 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 115:
+ case 141:
+ case 151:
+ case 236:
+#line 415 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy174 = 0;}
+#line 2287 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 114:
-#line 413 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 116:
+#line 416 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-2].minor.yy418,yymsp[-1].minor.yy62,yymsp[0].minor.yy198.n?&yymsp[0].minor.yy198:0);
+ yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-2].minor.yy174,yymsp[-1].minor.yy172,yymsp[0].minor.yy410.n?&yymsp[0].minor.yy410:0);
}
-#line 2345 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2294 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 115:
-#line 416 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 117:
+#line 419 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-1].minor.yy418, sqlite3Expr(TK_ALL, 0, 0, 0), 0);
+ yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-1].minor.yy174, sqlite3Expr(TK_ALL, 0, 0, 0), 0);
}
-#line 2352 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2301 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 116:
-#line 419 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 118:
+#line 422 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
Expr *pRight = sqlite3Expr(TK_ALL, 0, 0, 0);
- Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy198);
- yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-3].minor.yy418, sqlite3Expr(TK_DOT, pLeft, pRight, 0), 0);
+ Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy410);
+ yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-3].minor.yy174, sqlite3Expr(TK_DOT, pLeft, pRight, 0), 0);
}
-#line 2361 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 119:
-#line 431 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy198.n = 0;}
-#line 2366 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 120:
-#line 443 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy151 = sqliteMalloc(sizeof(*yygotominor.yy151));}
-#line 2371 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2310 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 121:
-#line 444 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy151 = yymsp[0].minor.yy151;}
-#line 2376 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 434 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy410.n = 0;}
+#line 2315 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 122:
-#line 449 "ext/pdo_sqlite/sqlite/src/parse.y"
-{
- yygotominor.yy151 = yymsp[-1].minor.yy151;
- if( yygotominor.yy151 && yygotominor.yy151->nSrc>0 ) yygotominor.yy151->a[yygotominor.yy151->nSrc-1].jointype = yymsp[0].minor.yy280;
-}
-#line 2384 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 446 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy373 = sqliteMalloc(sizeof(*yygotominor.yy373));}
+#line 2320 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 123:
-#line 453 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy151 = 0;}
-#line 2389 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 447 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy373 = yymsp[0].minor.yy373;}
+#line 2325 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 124:
-#line 454 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 452 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy151 = sqlite3SrcListAppend(yymsp[-5].minor.yy151,&yymsp[-4].minor.yy198,&yymsp[-3].minor.yy198);
- if( yymsp[-2].minor.yy198.n ) sqlite3SrcListAddAlias(yygotominor.yy151,&yymsp[-2].minor.yy198);
- if( yymsp[-1].minor.yy62 ){
- if( yygotominor.yy151 && yygotominor.yy151->nSrc>1 ){ yygotominor.yy151->a[yygotominor.yy151->nSrc-2].pOn = yymsp[-1].minor.yy62; }
- else { sqlite3ExprDelete(yymsp[-1].minor.yy62); }
+ yygotominor.yy373 = yymsp[-1].minor.yy373;
+ if( yygotominor.yy373 && yygotominor.yy373->nSrc>0 ) yygotominor.yy373->a[yygotominor.yy373->nSrc-1].jointype = yymsp[0].minor.yy46;
+}
+#line 2333 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 125:
+#line 456 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy373 = 0;}
+#line 2338 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 126:
+#line 457 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{
+ yygotominor.yy373 = sqlite3SrcListAppend(yymsp[-5].minor.yy373,&yymsp[-4].minor.yy410,&yymsp[-3].minor.yy410);
+ if( yymsp[-2].minor.yy410.n ) sqlite3SrcListAddAlias(yygotominor.yy373,&yymsp[-2].minor.yy410);
+ if( yymsp[-1].minor.yy172 ){
+ if( yygotominor.yy373 && yygotominor.yy373->nSrc>1 ){ yygotominor.yy373->a[yygotominor.yy373->nSrc-2].pOn = yymsp[-1].minor.yy172; }
+ else { sqlite3ExprDelete(yymsp[-1].minor.yy172); }
}
- if( yymsp[0].minor.yy240 ){
- if( yygotominor.yy151 && yygotominor.yy151->nSrc>1 ){ yygotominor.yy151->a[yygotominor.yy151->nSrc-2].pUsing = yymsp[0].minor.yy240; }
- else { sqlite3IdListDelete(yymsp[0].minor.yy240); }
+ if( yymsp[0].minor.yy432 ){
+ if( yygotominor.yy373 && yygotominor.yy373->nSrc>1 ){ yygotominor.yy373->a[yygotominor.yy373->nSrc-2].pUsing = yymsp[0].minor.yy432; }
+ else { sqlite3IdListDelete(yymsp[0].minor.yy432); }
}
}
-#line 2405 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2354 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 125:
-#line 468 "ext/pdo_sqlite/sqlite/src/parse.y"
-{
- yygotominor.yy151 = sqlite3SrcListAppend(yymsp[-6].minor.yy151,0,0);
- yygotominor.yy151->a[yygotominor.yy151->nSrc-1].pSelect = yymsp[-4].minor.yy375;
- if( yymsp[-2].minor.yy198.n ) sqlite3SrcListAddAlias(yygotominor.yy151,&yymsp[-2].minor.yy198);
- if( yymsp[-1].minor.yy62 ){
- if( yygotominor.yy151 && yygotominor.yy151->nSrc>1 ){ yygotominor.yy151->a[yygotominor.yy151->nSrc-2].pOn = yymsp[-1].minor.yy62; }
- else { sqlite3ExprDelete(yymsp[-1].minor.yy62); }
+ case 127:
+#line 471 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{
+ yygotominor.yy373 = sqlite3SrcListAppend(yymsp[-6].minor.yy373,0,0);
+ if( yygotominor.yy373 && yygotominor.yy373->nSrc>0 ) yygotominor.yy373->a[yygotominor.yy373->nSrc-1].pSelect = yymsp[-4].minor.yy219;
+ if( yymsp[-2].minor.yy410.n ) sqlite3SrcListAddAlias(yygotominor.yy373,&yymsp[-2].minor.yy410);
+ if( yymsp[-1].minor.yy172 ){
+ if( yygotominor.yy373 && yygotominor.yy373->nSrc>1 ){ yygotominor.yy373->a[yygotominor.yy373->nSrc-2].pOn = yymsp[-1].minor.yy172; }
+ else { sqlite3ExprDelete(yymsp[-1].minor.yy172); }
}
- if( yymsp[0].minor.yy240 ){
- if( yygotominor.yy151 && yygotominor.yy151->nSrc>1 ){ yygotominor.yy151->a[yygotominor.yy151->nSrc-2].pUsing = yymsp[0].minor.yy240; }
- else { sqlite3IdListDelete(yymsp[0].minor.yy240); }
+ if( yymsp[0].minor.yy432 ){
+ if( yygotominor.yy373 && yygotominor.yy373->nSrc>1 ){ yygotominor.yy373->a[yygotominor.yy373->nSrc-2].pUsing = yymsp[0].minor.yy432; }
+ else { sqlite3IdListDelete(yymsp[0].minor.yy432); }
}
}
-#line 2422 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2371 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 127:
-#line 489 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 129:
+#line 492 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy375 = sqlite3SelectNew(0,yymsp[0].minor.yy151,0,0,0,0,0,0,0);
+ yygotominor.yy219 = sqlite3SelectNew(0,yymsp[0].minor.yy373,0,0,0,0,0,0,0);
}
-#line 2429 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 128:
-#line 495 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy198.z=0; yygotominor.yy198.n=0;}
-#line 2434 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2378 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 130:
-#line 500 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy151 = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy198,&yymsp[0].minor.yy198);}
-#line 2439 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 498 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy410.z=0; yygotominor.yy410.n=0;}
+#line 2383 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 131:
case 132:
-#line 504 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = JT_INNER; }
-#line 2445 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 503 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy373 = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410);}
+#line 2388 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 133:
-#line 506 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
-#line 2450 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 507 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = JT_INNER; }
+#line 2393 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 134:
-#line 507 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy198,0); }
-#line 2455 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 508 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
+#line 2398 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 135:
-#line 509 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy198,&yymsp[-1].minor.yy198); }
-#line 2460 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 509 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy410,0); }
+#line 2403 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 136:
- case 144:
- case 153:
- case 160:
- case 174:
- case 211:
- case 236:
- case 238:
- case 242:
-#line 513 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy62 = yymsp[0].minor.yy62;}
-#line 2473 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 511 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy410,&yymsp[-1].minor.yy410); }
+#line 2408 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 137:
- case 152:
- case 159:
- case 212:
- case 237:
- case 239:
- case 243:
-#line 514 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy62 = 0;}
-#line 2484 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 145:
+ case 154:
+ case 161:
+ case 175:
+ case 202:
+ case 225:
+ case 227:
+ case 231:
+#line 515 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy172 = yymsp[0].minor.yy172;}
+#line 2421 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 138:
- case 171:
-#line 518 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy240 = yymsp[-1].minor.yy240;}
-#line 2490 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 153:
+ case 160:
+ case 203:
+ case 226:
+ case 228:
+ case 232:
+#line 516 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy172 = 0;}
+#line 2432 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 139:
- case 170:
-#line 519 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy240 = 0;}
-#line 2496 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 172:
+#line 520 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy432 = yymsp[-1].minor.yy432;}
+#line 2438 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 141:
- case 151:
-#line 530 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy418 = yymsp[0].minor.yy418;}
-#line 2502 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 140:
+ case 171:
+#line 521 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy432 = 0;}
+#line 2444 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 142:
-#line 531 "ext/pdo_sqlite/sqlite/src/parse.y"
-{
- yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-4].minor.yy418,yymsp[-2].minor.yy62,yymsp[-1].minor.yy198.n>0?&yymsp[-1].minor.yy198:0);
- if( yygotominor.yy418 ) yygotominor.yy418->a[yygotominor.yy418->nExpr-1].sortOrder = yymsp[0].minor.yy280;
-}
-#line 2510 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 152:
+#line 532 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy174 = yymsp[0].minor.yy174;}
+#line 2450 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 143:
-#line 535 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 533 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy418 = sqlite3ExprListAppend(0,yymsp[-2].minor.yy62,yymsp[-1].minor.yy198.n>0?&yymsp[-1].minor.yy198:0);
- if( yygotominor.yy418 && yygotominor.yy418->a ) yygotominor.yy418->a[0].sortOrder = yymsp[0].minor.yy280;
+ yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-4].minor.yy174,yymsp[-2].minor.yy172,yymsp[-1].minor.yy410.n>0?&yymsp[-1].minor.yy410:0);
+ if( yygotominor.yy174 ) yygotominor.yy174->a[yygotominor.yy174->nExpr-1].sortOrder = yymsp[0].minor.yy46;
}
-#line 2518 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2458 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 145:
- case 147:
-#line 544 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy280 = SQLITE_SO_ASC;}
-#line 2524 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 144:
+#line 537 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{
+ yygotominor.yy174 = sqlite3ExprListAppend(0,yymsp[-2].minor.yy172,yymsp[-1].minor.yy410.n>0?&yymsp[-1].minor.yy410:0);
+ if( yygotominor.yy174 && yygotominor.yy174->a ) yygotominor.yy174->a[0].sortOrder = yymsp[0].minor.yy46;
+}
+#line 2466 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 146:
-#line 545 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy280 = SQLITE_SO_DESC;}
-#line 2529 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
case 148:
-#line 547 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy198.z = 0; yygotominor.yy198.n = 0;}
-#line 2534 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 546 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy46 = SQLITE_SO_ASC;}
+#line 2472 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 154:
-#line 565 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy220.pLimit = 0; yygotominor.yy220.pOffset = 0;}
-#line 2539 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 147:
+#line 547 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy46 = SQLITE_SO_DESC;}
+#line 2477 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 149:
+#line 549 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy410.z = 0; yygotominor.yy410.n = 0;}
+#line 2482 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 155:
-#line 566 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy220.pLimit = yymsp[0].minor.yy62; yygotominor.yy220.pOffset = 0;}
-#line 2544 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 567 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy234.pLimit = 0; yygotominor.yy234.pOffset = 0;}
+#line 2487 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 156:
-#line 568 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy220.pLimit = yymsp[-2].minor.yy62; yygotominor.yy220.pOffset = yymsp[0].minor.yy62;}
-#line 2549 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 568 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy234.pLimit = yymsp[0].minor.yy172; yygotominor.yy234.pOffset = 0;}
+#line 2492 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 157:
-#line 570 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy220.pOffset = yymsp[-2].minor.yy62; yygotominor.yy220.pLimit = yymsp[0].minor.yy62;}
-#line 2554 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 570 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy234.pLimit = yymsp[-2].minor.yy172; yygotominor.yy234.pOffset = yymsp[0].minor.yy172;}
+#line 2497 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 158:
-#line 574 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3DeleteFrom(pParse,yymsp[-1].minor.yy151,yymsp[0].minor.yy62);}
-#line 2559 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 572 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy234.pOffset = yymsp[-2].minor.yy172; yygotominor.yy234.pLimit = yymsp[0].minor.yy172;}
+#line 2502 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 161:
-#line 585 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Update(pParse,yymsp[-3].minor.yy151,yymsp[-1].minor.yy418,yymsp[0].minor.yy62,yymsp[-4].minor.yy280);}
-#line 2564 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 159:
+#line 576 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3DeleteFrom(pParse,yymsp[-1].minor.yy373,yymsp[0].minor.yy172);}
+#line 2507 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 162:
-#line 591 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-4].minor.yy418,yymsp[0].minor.yy62,&yymsp[-2].minor.yy198);}
-#line 2569 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 587 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Update(pParse,yymsp[-3].minor.yy373,yymsp[-1].minor.yy174,yymsp[0].minor.yy172,yymsp[-4].minor.yy46);}
+#line 2512 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 163:
-#line 592 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy418 = sqlite3ExprListAppend(0,yymsp[0].minor.yy62,&yymsp[-2].minor.yy198);}
-#line 2574 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 593 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-4].minor.yy174,yymsp[0].minor.yy172,&yymsp[-2].minor.yy410);}
+#line 2517 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 164:
-#line 598 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Insert(pParse, yymsp[-5].minor.yy151, yymsp[-1].minor.yy418, 0, yymsp[-4].minor.yy240, yymsp[-7].minor.yy280);}
-#line 2579 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 594 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy174 = sqlite3ExprListAppend(0,yymsp[0].minor.yy172,&yymsp[-2].minor.yy410);}
+#line 2522 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 165:
-#line 600 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Insert(pParse, yymsp[-2].minor.yy151, 0, yymsp[0].minor.yy375, yymsp[-1].minor.yy240, yymsp[-4].minor.yy280);}
-#line 2584 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 600 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Insert(pParse, yymsp[-5].minor.yy373, yymsp[-1].minor.yy174, 0, yymsp[-4].minor.yy432, yymsp[-7].minor.yy46);}
+#line 2527 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 168:
- case 240:
-#line 610 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-2].minor.yy418,yymsp[0].minor.yy62,0);}
-#line 2590 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 166:
+#line 602 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Insert(pParse, yymsp[-2].minor.yy373, 0, yymsp[0].minor.yy219, yymsp[-1].minor.yy432, yymsp[-4].minor.yy46);}
+#line 2532 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 169:
- case 241:
-#line 611 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy418 = sqlite3ExprListAppend(0,yymsp[0].minor.yy62,0);}
-#line 2596 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 229:
+#line 612 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-2].minor.yy174,yymsp[0].minor.yy172,0);}
+#line 2538 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 172:
-#line 620 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy240 = sqlite3IdListAppend(yymsp[-2].minor.yy240,&yymsp[0].minor.yy198);}
-#line 2601 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 170:
+ case 230:
+#line 613 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy174 = sqlite3ExprListAppend(0,yymsp[0].minor.yy172,0);}
+#line 2544 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 173:
-#line 621 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy240 = sqlite3IdListAppend(0,&yymsp[0].minor.yy198);}
-#line 2606 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 622 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy432 = sqlite3IdListAppend(yymsp[-2].minor.yy432,&yymsp[0].minor.yy410);}
+#line 2549 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 175:
-#line 632 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy62 = yymsp[-1].minor.yy62; sqlite3ExprSpan(yygotominor.yy62,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); }
-#line 2611 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 174:
+#line 623 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy432 = sqlite3IdListAppend(0,&yymsp[0].minor.yy410);}
+#line 2554 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 176:
- case 181:
+#line 634 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy172 = yymsp[-1].minor.yy172; sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); }
+#line 2559 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 177:
case 182:
case 183:
- case 184:
-#line 633 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy62 = sqlite3Expr(yymsp[0].major, 0, 0, &yymsp[0].minor.yy0);}
-#line 2620 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 635 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy172 = sqlite3Expr(yymsp[0].major, 0, 0, &yymsp[0].minor.yy0);}
+#line 2566 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 177:
case 178:
-#line 634 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy62 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy0);}
-#line 2626 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
case 179:
-#line 636 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 636 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy172 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy0);}
+#line 2572 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 180:
+#line 638 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy198);
- Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy198);
- yygotominor.yy62 = sqlite3Expr(TK_DOT, temp1, temp2, 0);
+ Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy410);
+ Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy410);
+ yygotominor.yy172 = sqlite3Expr(TK_DOT, temp1, temp2, 0);
}
-#line 2635 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2581 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 180:
-#line 641 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 181:
+#line 643 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-4].minor.yy198);
- Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy198);
- Expr *temp3 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy198);
+ Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-4].minor.yy410);
+ Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy410);
+ Expr *temp3 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy410);
Expr *temp4 = sqlite3Expr(TK_DOT, temp2, temp3, 0);
- yygotominor.yy62 = sqlite3Expr(TK_DOT, temp1, temp4, 0);
+ yygotominor.yy172 = sqlite3Expr(TK_DOT, temp1, temp4, 0);
}
-#line 2646 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2592 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 185:
-#line 652 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy62 = sqlite3RegisterExpr(pParse, &yymsp[0].minor.yy0);}
-#line 2651 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 184:
+#line 652 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy172 = sqlite3RegisterExpr(pParse, &yymsp[0].minor.yy0);}
+#line 2597 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 186:
-#line 653 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 185:
+#line 653 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
Token *pToken = &yymsp[0].minor.yy0;
- Expr *pExpr = yygotominor.yy62 = sqlite3Expr(TK_VARIABLE, 0, 0, pToken);
+ Expr *pExpr = yygotominor.yy172 = sqlite3Expr(TK_VARIABLE, 0, 0, pToken);
sqlite3ExprAssignVarNumber(pParse, pExpr);
}
-#line 2660 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2606 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 187:
-#line 659 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 186:
+#line 659 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy62 = sqlite3Expr(TK_CAST, yymsp[-3].minor.yy62, 0, &yymsp[-1].minor.yy198);
- sqlite3ExprSpan(yygotominor.yy62,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);
+ yygotominor.yy172 = sqlite3Expr(TK_CAST, yymsp[-3].minor.yy172, 0, &yymsp[-1].minor.yy410);
+ sqlite3ExprSpan(yygotominor.yy172,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);
}
-#line 2668 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2614 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 188:
-#line 664 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 187:
+#line 664 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy62 = sqlite3ExprFunction(yymsp[-1].minor.yy418, &yymsp[-4].minor.yy0);
- sqlite3ExprSpan(yygotominor.yy62,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
- if( yymsp[-2].minor.yy280 ){
- yygotominor.yy62->flags |= EP_Distinct;
+ yygotominor.yy172 = sqlite3ExprFunction(yymsp[-1].minor.yy174, &yymsp[-4].minor.yy0);
+ sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
+ if( yymsp[-2].minor.yy46 && yygotominor.yy172 ){
+ yygotominor.yy172->flags |= EP_Distinct;
}
}
-#line 2679 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2625 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 189:
-#line 671 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 188:
+#line 671 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy62 = sqlite3ExprFunction(0, &yymsp[-3].minor.yy0);
- sqlite3ExprSpan(yygotominor.yy62,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
+ yygotominor.yy172 = sqlite3ExprFunction(0, &yymsp[-3].minor.yy0);
+ sqlite3ExprSpan(yygotominor.yy172,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
}
-#line 2687 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2633 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 190:
-#line 675 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 189:
+#line 675 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
/* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are
** treated as functions that return constants */
- yygotominor.yy62 = sqlite3ExprFunction(0,&yymsp[0].minor.yy0);
- if( yygotominor.yy62 ) yygotominor.yy62->op = TK_CONST_FUNC;
+ yygotominor.yy172 = sqlite3ExprFunction(0,&yymsp[0].minor.yy0);
+ if( yygotominor.yy172 ) yygotominor.yy172->op = TK_CONST_FUNC;
}
-#line 2697 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2643 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
+ case 190:
case 191:
case 192:
case 193:
@@ -2701,516 +2647,534 @@ static void yy_reduce(
case 195:
case 196:
case 197:
+#line 681 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy172 = sqlite3Expr(yymsp[-1].major, yymsp[-2].minor.yy172, yymsp[0].minor.yy172, 0);}
+#line 2655 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
case 198:
- case 199:
case 200:
- case 201:
- case 202:
- case 203:
- case 204:
- case 205:
- case 206:
- case 207:
- case 208:
-#line 681 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy62 = sqlite3Expr(yymsp[-1].major, yymsp[-2].minor.yy62, yymsp[0].minor.yy62, 0);}
-#line 2719 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 691 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy72.eOperator = yymsp[0].minor.yy0; yygotominor.yy72.not = 0;}
+#line 2661 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 209:
-#line 700 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy222.operator = yymsp[0].minor.yy0; yygotominor.yy222.not = 0;}
-#line 2724 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 210:
-#line 701 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy222.operator = yymsp[0].minor.yy0; yygotominor.yy222.not = 1;}
-#line 2729 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 199:
+ case 201:
+#line 692 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy72.eOperator = yymsp[0].minor.yy0; yygotominor.yy72.not = 1;}
+#line 2667 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 213:
-#line 705 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 204:
+#line 699 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- ExprList *pList = sqlite3ExprListAppend(0, yymsp[-1].minor.yy62, 0);
- pList = sqlite3ExprListAppend(pList, yymsp[-3].minor.yy62, 0);
- if( yymsp[0].minor.yy62 ){
- pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy62, 0);
+ ExprList *pList;
+ pList = sqlite3ExprListAppend(0, yymsp[-1].minor.yy172, 0);
+ pList = sqlite3ExprListAppend(pList, yymsp[-3].minor.yy172, 0);
+ if( yymsp[0].minor.yy172 ){
+ pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy172, 0);
}
- yygotominor.yy62 = sqlite3ExprFunction(pList, &yymsp[-2].minor.yy222.operator);
- if( yymsp[-2].minor.yy222.not ) yygotominor.yy62 = sqlite3Expr(TK_NOT, yygotominor.yy62, 0, 0);
- sqlite3ExprSpan(yygotominor.yy62, &yymsp[-3].minor.yy62->span, &yymsp[-1].minor.yy62->span);
-}
-#line 2743 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 214:
-#line 716 "ext/pdo_sqlite/sqlite/src/parse.y"
-{
- yygotominor.yy62 = sqlite3Expr(TK_ISNULL, yymsp[-1].minor.yy62, 0, 0);
- sqlite3ExprSpan(yygotominor.yy62,&yymsp[-1].minor.yy62->span,&yymsp[0].minor.yy0);
+ yygotominor.yy172 = sqlite3ExprFunction(pList, &yymsp[-2].minor.yy72.eOperator);
+ if( yymsp[-2].minor.yy72.not ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0);
+ sqlite3ExprSpan(yygotominor.yy172, &yymsp[-3].minor.yy172->span, &yymsp[-1].minor.yy172->span);
+ if( yygotominor.yy172 ) yygotominor.yy172->flags |= EP_InfixFunc;
}
-#line 2751 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2683 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 215:
-#line 720 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 205:
+#line 712 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy62 = sqlite3Expr(TK_ISNULL, yymsp[-2].minor.yy62, 0, 0);
- sqlite3ExprSpan(yygotominor.yy62,&yymsp[-2].minor.yy62->span,&yymsp[0].minor.yy0);
+ yygotominor.yy172 = sqlite3Expr(yymsp[0].major, yymsp[-1].minor.yy172, 0, 0);
+ sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2759 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2691 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 216:
-#line 724 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 206:
+#line 716 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy62 = sqlite3Expr(TK_NOTNULL, yymsp[-1].minor.yy62, 0, 0);
- sqlite3ExprSpan(yygotominor.yy62,&yymsp[-1].minor.yy62->span,&yymsp[0].minor.yy0);
+ yygotominor.yy172 = sqlite3Expr(TK_ISNULL, yymsp[-2].minor.yy172, 0, 0);
+ sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2767 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2699 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 217:
-#line 728 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 207:
+#line 720 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy62 = sqlite3Expr(TK_NOTNULL, yymsp[-2].minor.yy62, 0, 0);
- sqlite3ExprSpan(yygotominor.yy62,&yymsp[-2].minor.yy62->span,&yymsp[0].minor.yy0);
+ yygotominor.yy172 = sqlite3Expr(TK_NOTNULL, yymsp[-2].minor.yy172, 0, 0);
+ sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2775 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2707 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 218:
-#line 732 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 208:
+#line 724 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy62 = sqlite3Expr(TK_NOTNULL, yymsp[-3].minor.yy62, 0, 0);
- sqlite3ExprSpan(yygotominor.yy62,&yymsp[-3].minor.yy62->span,&yymsp[0].minor.yy0);
+ yygotominor.yy172 = sqlite3Expr(TK_NOTNULL, yymsp[-3].minor.yy172, 0, 0);
+ sqlite3ExprSpan(yygotominor.yy172,&yymsp[-3].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2783 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2715 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 219:
- case 220:
-#line 736 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 209:
+#line 728 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy62 = sqlite3Expr(yymsp[-1].major, yymsp[0].minor.yy62, 0, 0);
- sqlite3ExprSpan(yygotominor.yy62,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy62->span);
+ yygotominor.yy172 = sqlite3Expr(yymsp[-1].major, yymsp[0].minor.yy172, 0, 0);
+ sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span);
}
-#line 2792 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2723 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 221:
-#line 744 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 210:
+#line 732 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy62 = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy62, 0, 0);
- sqlite3ExprSpan(yygotominor.yy62,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy62->span);
+ yygotominor.yy172 = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy172, 0, 0);
+ sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span);
}
-#line 2800 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2731 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 222:
-#line 748 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 211:
+#line 736 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy62 = sqlite3Expr(TK_UPLUS, yymsp[0].minor.yy62, 0, 0);
- sqlite3ExprSpan(yygotominor.yy62,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy62->span);
+ yygotominor.yy172 = sqlite3Expr(TK_UPLUS, yymsp[0].minor.yy172, 0, 0);
+ sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span);
}
-#line 2808 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2739 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 225:
-#line 755 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 214:
+#line 743 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- ExprList *pList = sqlite3ExprListAppend(0, yymsp[-2].minor.yy62, 0);
- pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy62, 0);
- yygotominor.yy62 = sqlite3Expr(TK_BETWEEN, yymsp[-4].minor.yy62, 0, 0);
- if( yygotominor.yy62 ){
- yygotominor.yy62->pList = pList;
+ ExprList *pList = sqlite3ExprListAppend(0, yymsp[-2].minor.yy172, 0);
+ pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy172, 0);
+ yygotominor.yy172 = sqlite3Expr(TK_BETWEEN, yymsp[-4].minor.yy172, 0, 0);
+ if( yygotominor.yy172 ){
+ yygotominor.yy172->pList = pList;
}else{
sqlite3ExprListDelete(pList);
}
- if( yymsp[-3].minor.yy280 ) yygotominor.yy62 = sqlite3Expr(TK_NOT, yygotominor.yy62, 0, 0);
- sqlite3ExprSpan(yygotominor.yy62,&yymsp[-4].minor.yy62->span,&yymsp[0].minor.yy62->span);
+ if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0);
+ sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy172->span,&yymsp[0].minor.yy172->span);
}
-#line 2824 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2755 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 228:
-#line 771 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 217:
+#line 759 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy62 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy62, 0, 0);
- if( yygotominor.yy62 ){
- yygotominor.yy62->pList = yymsp[-1].minor.yy418;
+ yygotominor.yy172 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy172, 0, 0);
+ if( yygotominor.yy172 ){
+ yygotominor.yy172->pList = yymsp[-1].minor.yy174;
}else{
- sqlite3ExprListDelete(yymsp[-1].minor.yy418);
+ sqlite3ExprListDelete(yymsp[-1].minor.yy174);
}
- if( yymsp[-3].minor.yy280 ) yygotominor.yy62 = sqlite3Expr(TK_NOT, yygotominor.yy62, 0, 0);
- sqlite3ExprSpan(yygotominor.yy62,&yymsp[-4].minor.yy62->span,&yymsp[0].minor.yy0);
+ if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0);
+ sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2838 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2769 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 229:
-#line 781 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 218:
+#line 769 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy62 = sqlite3Expr(TK_SELECT, 0, 0, 0);
- if( yygotominor.yy62 ){
- yygotominor.yy62->pSelect = yymsp[-1].minor.yy375;
+ yygotominor.yy172 = sqlite3Expr(TK_SELECT, 0, 0, 0);
+ if( yygotominor.yy172 ){
+ yygotominor.yy172->pSelect = yymsp[-1].minor.yy219;
}else{
- sqlite3SelectDelete(yymsp[-1].minor.yy375);
+ sqlite3SelectDelete(yymsp[-1].minor.yy219);
}
- sqlite3ExprSpan(yygotominor.yy62,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
+ sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
}
-#line 2851 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2782 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 230:
-#line 790 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 219:
+#line 778 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy62 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy62, 0, 0);
- if( yygotominor.yy62 ){
- yygotominor.yy62->pSelect = yymsp[-1].minor.yy375;
+ yygotominor.yy172 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy172, 0, 0);
+ if( yygotominor.yy172 ){
+ yygotominor.yy172->pSelect = yymsp[-1].minor.yy219;
}else{
- sqlite3SelectDelete(yymsp[-1].minor.yy375);
+ sqlite3SelectDelete(yymsp[-1].minor.yy219);
}
- if( yymsp[-3].minor.yy280 ) yygotominor.yy62 = sqlite3Expr(TK_NOT, yygotominor.yy62, 0, 0);
- sqlite3ExprSpan(yygotominor.yy62,&yymsp[-4].minor.yy62->span,&yymsp[0].minor.yy0);
+ if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0);
+ sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2865 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2796 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 231:
-#line 800 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 220:
+#line 788 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- SrcList *pSrc = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy198,&yymsp[0].minor.yy198);
- yygotominor.yy62 = sqlite3Expr(TK_IN, yymsp[-3].minor.yy62, 0, 0);
- if( yygotominor.yy62 ){
- yygotominor.yy62->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0);
+ SrcList *pSrc = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410);
+ yygotominor.yy172 = sqlite3Expr(TK_IN, yymsp[-3].minor.yy172, 0, 0);
+ if( yygotominor.yy172 ){
+ yygotominor.yy172->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0);
}else{
sqlite3SrcListDelete(pSrc);
}
- if( yymsp[-2].minor.yy280 ) yygotominor.yy62 = sqlite3Expr(TK_NOT, yygotominor.yy62, 0, 0);
- sqlite3ExprSpan(yygotominor.yy62,&yymsp[-3].minor.yy62->span,yymsp[0].minor.yy198.z?&yymsp[0].minor.yy198:&yymsp[-1].minor.yy198);
+ if( yymsp[-2].minor.yy46 ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0);
+ sqlite3ExprSpan(yygotominor.yy172,&yymsp[-3].minor.yy172->span,yymsp[0].minor.yy410.z?&yymsp[0].minor.yy410:&yymsp[-1].minor.yy410);
}
-#line 2880 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2811 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 232:
-#line 811 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 221:
+#line 799 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- Expr *p = yygotominor.yy62 = sqlite3Expr(TK_EXISTS, 0, 0, 0);
+ Expr *p = yygotominor.yy172 = sqlite3Expr(TK_EXISTS, 0, 0, 0);
if( p ){
- p->pSelect = yymsp[-1].minor.yy375;
+ p->pSelect = yymsp[-1].minor.yy219;
sqlite3ExprSpan(p,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
}else{
- sqlite3SelectDelete(yymsp[-1].minor.yy375);
+ sqlite3SelectDelete(yymsp[-1].minor.yy219);
}
}
-#line 2893 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2824 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 233:
-#line 823 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 222:
+#line 811 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy62 = sqlite3Expr(TK_CASE, yymsp[-3].minor.yy62, yymsp[-1].minor.yy62, 0);
- if( yygotominor.yy62 ){
- yygotominor.yy62->pList = yymsp[-2].minor.yy418;
+ yygotominor.yy172 = sqlite3Expr(TK_CASE, yymsp[-3].minor.yy172, yymsp[-1].minor.yy172, 0);
+ if( yygotominor.yy172 ){
+ yygotominor.yy172->pList = yymsp[-2].minor.yy174;
}else{
- sqlite3ExprListDelete(yymsp[-2].minor.yy418);
+ sqlite3ExprListDelete(yymsp[-2].minor.yy174);
}
- sqlite3ExprSpan(yygotominor.yy62, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0);
+ sqlite3ExprSpan(yygotominor.yy172, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0);
}
-#line 2906 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2837 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 234:
-#line 834 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 223:
+#line 822 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-4].minor.yy418, yymsp[-2].minor.yy62, 0);
- yygotominor.yy418 = sqlite3ExprListAppend(yygotominor.yy418, yymsp[0].minor.yy62, 0);
+ yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-4].minor.yy174, yymsp[-2].minor.yy172, 0);
+ yygotominor.yy174 = sqlite3ExprListAppend(yygotominor.yy174, yymsp[0].minor.yy172, 0);
}
-#line 2914 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2845 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 235:
-#line 838 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 224:
+#line 826 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy418 = sqlite3ExprListAppend(0, yymsp[-2].minor.yy62, 0);
- yygotominor.yy418 = sqlite3ExprListAppend(yygotominor.yy418, yymsp[0].minor.yy62, 0);
+ yygotominor.yy174 = sqlite3ExprListAppend(0, yymsp[-2].minor.yy172, 0);
+ yygotominor.yy174 = sqlite3ExprListAppend(yygotominor.yy174, yymsp[0].minor.yy172, 0);
}
-#line 2922 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2853 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 244:
-#line 863 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 233:
+#line 853 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- if( yymsp[-9].minor.yy280!=OE_None ) yymsp[-9].minor.yy280 = yymsp[0].minor.yy280;
- if( yymsp[-9].minor.yy280==OE_Default) yymsp[-9].minor.yy280 = OE_Abort;
- sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy198, &yymsp[-6].minor.yy198, sqlite3SrcListAppend(0,&yymsp[-4].minor.yy198,0),yymsp[-2].minor.yy418,yymsp[-9].minor.yy280, &yymsp[-10].minor.yy0, &yymsp[-1].minor.yy0);
+ sqlite3CreateIndex(pParse, &yymsp[-6].minor.yy410, &yymsp[-5].minor.yy410, sqlite3SrcListAppend(0,&yymsp[-3].minor.yy410,0), yymsp[-1].minor.yy174, yymsp[-9].minor.yy46,
+ &yymsp[-10].minor.yy0, &yymsp[0].minor.yy0, SQLITE_SO_ASC, yymsp[-7].minor.yy46);
}
-#line 2931 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2861 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 245:
- case 292:
-#line 870 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy280 = OE_Abort;}
-#line 2937 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 234:
+ case 279:
+#line 859 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy46 = OE_Abort;}
+#line 2867 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 246:
-#line 871 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy280 = OE_None;}
-#line 2942 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 235:
+#line 860 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy46 = OE_None;}
+#line 2872 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 249:
-#line 881 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 238:
+#line 870 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
Expr *p = 0;
- if( yymsp[-1].minor.yy198.n>0 ){
+ if( yymsp[-1].minor.yy410.n>0 ){
p = sqlite3Expr(TK_COLUMN, 0, 0, 0);
- if( p ) p->pColl = sqlite3LocateCollSeq(pParse, yymsp[-1].minor.yy198.z, yymsp[-1].minor.yy198.n);
+ if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)yymsp[-1].minor.yy410.z, yymsp[-1].minor.yy410.n);
}
- yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-4].minor.yy418, p, &yymsp[-2].minor.yy198);
+ yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-4].minor.yy174, p, &yymsp[-2].minor.yy410);
+ if( yygotominor.yy174 ) yygotominor.yy174->a[yygotominor.yy174->nExpr-1].sortOrder = yymsp[0].minor.yy46;
}
-#line 2954 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2885 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 250:
-#line 889 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 239:
+#line 879 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
Expr *p = 0;
- if( yymsp[-1].minor.yy198.n>0 ){
+ if( yymsp[-1].minor.yy410.n>0 ){
p = sqlite3Expr(TK_COLUMN, 0, 0, 0);
- if( p ) p->pColl = sqlite3LocateCollSeq(pParse, yymsp[-1].minor.yy198.z, yymsp[-1].minor.yy198.n);
+ if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)yymsp[-1].minor.yy410.z, yymsp[-1].minor.yy410.n);
}
- yygotominor.yy418 = sqlite3ExprListAppend(0, p, &yymsp[-2].minor.yy198);
+ yygotominor.yy174 = sqlite3ExprListAppend(0, p, &yymsp[-2].minor.yy410);
+ if( yygotominor.yy174 ) yygotominor.yy174->a[yygotominor.yy174->nExpr-1].sortOrder = yymsp[0].minor.yy46;
}
-#line 2966 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2898 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 252:
-#line 902 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3DropIndex(pParse, yymsp[0].minor.yy151);}
-#line 2971 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 241:
+#line 893 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3DropIndex(pParse, yymsp[0].minor.yy373, yymsp[-1].minor.yy46);}
+#line 2903 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 253:
- case 254:
-#line 906 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Vacuum(pParse,0);}
-#line 2977 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 242:
+ case 243:
+#line 897 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Vacuum(pParse);}
+#line 2909 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 255:
- case 257:
-#line 912 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Pragma(pParse,&yymsp[-3].minor.yy198,&yymsp[-2].minor.yy198,&yymsp[0].minor.yy198,0);}
-#line 2983 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 244:
+ case 246:
+#line 903 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Pragma(pParse,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,&yymsp[0].minor.yy410,0);}
+#line 2915 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 256:
-#line 913 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Pragma(pParse,&yymsp[-3].minor.yy198,&yymsp[-2].minor.yy198,&yymsp[0].minor.yy0,0);}
-#line 2988 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 245:
+#line 904 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Pragma(pParse,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,&yymsp[0].minor.yy0,0);}
+#line 2920 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 258:
-#line 915 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 247:
+#line 906 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3Pragma(pParse,&yymsp[-3].minor.yy198,&yymsp[-2].minor.yy198,&yymsp[0].minor.yy198,1);
+ sqlite3Pragma(pParse,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,&yymsp[0].minor.yy410,1);
}
-#line 2995 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2927 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 259:
-#line 918 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Pragma(pParse,&yymsp[-4].minor.yy198,&yymsp[-3].minor.yy198,&yymsp[-1].minor.yy198,0);}
-#line 3000 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 248:
+#line 909 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Pragma(pParse,&yymsp[-4].minor.yy410,&yymsp[-3].minor.yy410,&yymsp[-1].minor.yy410,0);}
+#line 2932 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 260:
-#line 919 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Pragma(pParse,&yymsp[-1].minor.yy198,&yymsp[0].minor.yy198,0,0);}
-#line 3005 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 249:
+#line 910 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Pragma(pParse,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410,0,0);}
+#line 2937 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 267:
-#line 932 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 255:
+#line 922 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
Token all;
- all.z = yymsp[-3].minor.yy198.z;
- all.n = (yymsp[0].minor.yy0.z - yymsp[-3].minor.yy198.z) + yymsp[0].minor.yy0.n;
- sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy360, &all);
+ all.z = yymsp[-3].minor.yy410.z;
+ all.n = (yymsp[0].minor.yy0.z - yymsp[-3].minor.yy410.z) + yymsp[0].minor.yy0.n;
+ sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy243, &all);
}
-#line 3015 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2947 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 268:
-#line 941 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 256:
+#line 931 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy198, &yymsp[-6].minor.yy198, yymsp[-5].minor.yy280, yymsp[-4].minor.yy30.a, yymsp[-4].minor.yy30.b, yymsp[-2].minor.yy151, yymsp[-1].minor.yy280, yymsp[0].minor.yy62, yymsp[-9].minor.yy280);
- yygotominor.yy198 = (yymsp[-6].minor.yy198.n==0?yymsp[-7].minor.yy198:yymsp[-6].minor.yy198);
+ sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy410, &yymsp[-6].minor.yy410, yymsp[-5].minor.yy46, yymsp[-4].minor.yy370.a, yymsp[-4].minor.yy370.b, yymsp[-2].minor.yy373, yymsp[-1].minor.yy46, yymsp[0].minor.yy172, yymsp[-9].minor.yy46);
+ yygotominor.yy410 = (yymsp[-6].minor.yy410.n==0?yymsp[-7].minor.yy410:yymsp[-6].minor.yy410);
}
-#line 3023 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2955 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 257:
+ case 260:
+#line 937 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = TK_BEFORE; }
+#line 2961 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 258:
+#line 938 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = TK_AFTER; }
+#line 2966 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 259:
+#line 939 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = TK_INSTEAD;}
+#line 2971 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 261:
+ case 262:
+#line 944 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy370.a = yymsp[0].major; yygotominor.yy370.b = 0;}
+#line 2977 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 263:
+#line 946 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy370.a = TK_UPDATE; yygotominor.yy370.b = yymsp[0].minor.yy432;}
+#line 2982 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 264:
+ case 265:
+#line 949 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = TK_ROW; }
+#line 2988 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 266:
+#line 951 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy46 = TK_STATEMENT; }
+#line 2993 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 267:
+#line 955 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy172 = 0; }
+#line 2998 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 268:
+#line 956 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy172 = yymsp[0].minor.yy172; }
+#line 3003 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 269:
- case 272:
-#line 947 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = TK_BEFORE; }
-#line 3029 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 960 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{
+ if( yymsp[-2].minor.yy243 ){
+ yymsp[-2].minor.yy243->pLast->pNext = yymsp[-1].minor.yy243;
+ }else{
+ yymsp[-2].minor.yy243 = yymsp[-1].minor.yy243;
+ }
+ yymsp[-2].minor.yy243->pLast = yymsp[-1].minor.yy243;
+ yygotominor.yy243 = yymsp[-2].minor.yy243;
+}
+#line 3016 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 270:
-#line 948 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = TK_AFTER; }
-#line 3034 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 969 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy243 = 0; }
+#line 3021 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 271:
-#line 949 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = TK_INSTEAD;}
-#line 3039 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 975 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy243 = sqlite3TriggerUpdateStep(&yymsp[-3].minor.yy410, yymsp[-1].minor.yy174, yymsp[0].minor.yy172, yymsp[-4].minor.yy46); }
+#line 3026 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 272:
+#line 980 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy243 = sqlite3TriggerInsertStep(&yymsp[-5].minor.yy410, yymsp[-4].minor.yy432, yymsp[-1].minor.yy174, 0, yymsp[-7].minor.yy46);}
+#line 3031 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 273:
+#line 983 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy243 = sqlite3TriggerInsertStep(&yymsp[-2].minor.yy410, yymsp[-1].minor.yy432, 0, yymsp[0].minor.yy219, yymsp[-4].minor.yy46);}
+#line 3036 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
case 274:
+#line 987 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy243 = sqlite3TriggerDeleteStep(&yymsp[-1].minor.yy410, yymsp[0].minor.yy172);}
+#line 3041 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
case 275:
-#line 954 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy30.a = yymsp[0].major; yygotominor.yy30.b = 0;}
-#line 3046 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 990 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy243 = sqlite3TriggerSelectStep(yymsp[0].minor.yy219); }
+#line 3046 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 276:
-#line 957 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy30.a = TK_UPDATE; yygotominor.yy30.b = yymsp[0].minor.yy240;}
-#line 3051 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 993 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{
+ yygotominor.yy172 = sqlite3Expr(TK_RAISE, 0, 0, 0);
+ if( yygotominor.yy172 ){
+ yygotominor.yy172->iColumn = OE_Ignore;
+ sqlite3ExprSpan(yygotominor.yy172, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0);
+ }
+}
+#line 3057 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 277:
- case 278:
-#line 960 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = TK_ROW; }
-#line 3057 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1000 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{
+ yygotominor.yy172 = sqlite3Expr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy410);
+ if( yygotominor.yy172 ) {
+ yygotominor.yy172->iColumn = yymsp[-3].minor.yy46;
+ sqlite3ExprSpan(yygotominor.yy172, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0);
+ }
+}
+#line 3068 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 279:
-#line 962 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy280 = TK_STATEMENT; }
-#line 3062 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 278:
+#line 1010 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy46 = OE_Rollback;}
+#line 3073 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 280:
-#line 965 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy62 = 0; }
-#line 3067 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1012 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy46 = OE_Fail;}
+#line 3078 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 281:
-#line 966 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy62 = yymsp[0].minor.yy62; }
-#line 3072 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1017 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{
+ sqlite3DropTrigger(pParse,yymsp[0].minor.yy373);
+}
+#line 3085 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 282:
-#line 970 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 1023 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- yymsp[-2].minor.yy360->pNext = yymsp[0].minor.yy360;
- yygotominor.yy360 = yymsp[-2].minor.yy360;
+ sqlite3Attach(pParse, yymsp[-3].minor.yy172, yymsp[-1].minor.yy172, yymsp[0].minor.yy386);
}
-#line 3080 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3092 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 283:
-#line 974 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy360 = 0; }
-#line 3085 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1028 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy386 = 0; }
+#line 3097 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 284:
-#line 980 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy360 = sqlite3TriggerUpdateStep(&yymsp[-3].minor.yy198, yymsp[-1].minor.yy418, yymsp[0].minor.yy62, yymsp[-4].minor.yy280); }
-#line 3090 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 285:
-#line 985 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy360 = sqlite3TriggerInsertStep(&yymsp[-5].minor.yy198, yymsp[-4].minor.yy240, yymsp[-1].minor.yy418, 0, yymsp[-7].minor.yy280);}
-#line 3095 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 286:
-#line 988 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy360 = sqlite3TriggerInsertStep(&yymsp[-2].minor.yy198, yymsp[-1].minor.yy240, 0, yymsp[0].minor.yy375, yymsp[-4].minor.yy280);}
-#line 3100 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1029 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy386 = yymsp[0].minor.yy172; }
+#line 3102 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 287:
-#line 992 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy360 = sqlite3TriggerDeleteStep(&yymsp[-1].minor.yy198, yymsp[0].minor.yy62);}
-#line 3105 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1035 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{
+ sqlite3Detach(pParse, yymsp[0].minor.yy172);
+}
+#line 3109 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 288:
-#line 995 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy360 = sqlite3TriggerSelectStep(yymsp[0].minor.yy375); }
-#line 3110 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1041 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Reindex(pParse, 0, 0);}
+#line 3114 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 289:
-#line 998 "ext/pdo_sqlite/sqlite/src/parse.y"
-{
- yygotominor.yy62 = sqlite3Expr(TK_RAISE, 0, 0, 0);
- yygotominor.yy62->iColumn = OE_Ignore;
- sqlite3ExprSpan(yygotominor.yy62, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0);
-}
-#line 3119 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1042 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Reindex(pParse, &yymsp[-1].minor.yy410, &yymsp[0].minor.yy410);}
+#line 3119 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 290:
-#line 1003 "ext/pdo_sqlite/sqlite/src/parse.y"
-{
- yygotominor.yy62 = sqlite3Expr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy198);
- yygotominor.yy62->iColumn = yymsp[-3].minor.yy280;
- sqlite3ExprSpan(yygotominor.yy62, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0);
-}
-#line 3128 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1047 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Analyze(pParse, 0, 0);}
+#line 3124 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 291:
-#line 1011 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy280 = OE_Rollback;}
-#line 3133 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1048 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Analyze(pParse, &yymsp[-1].minor.yy410, &yymsp[0].minor.yy410);}
+#line 3129 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 293:
-#line 1013 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy280 = OE_Fail;}
-#line 3138 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 294:
-#line 1018 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 292:
+#line 1053 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3DropTrigger(pParse,yymsp[0].minor.yy151);
+ sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy373,&yymsp[0].minor.yy410);
}
-#line 3145 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3136 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 295:
-#line 1024 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 293:
+#line 1056 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3Attach(pParse, &yymsp[-3].minor.yy198, &yymsp[-1].minor.yy198, yymsp[0].minor.yy361.type, &yymsp[0].minor.yy361.key);
+ sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy410);
}
-#line 3152 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3143 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 296:
-#line 1028 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy361.type = 0; }
-#line 3157 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 294:
+#line 1059 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{
+ sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy373);
+}
+#line 3150 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 297:
-#line 1029 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy361.type=1; yygotominor.yy361.key = yymsp[0].minor.yy198; }
-#line 3162 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1068 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3VtabFinishParse(pParse,0);}
+#line 3155 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 298:
-#line 1030 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy361.type=2; yygotominor.yy361.key = yymsp[0].minor.yy0; }
-#line 3167 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1069 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
+#line 3160 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 301:
-#line 1036 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 299:
+#line 1070 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3Detach(pParse, &yymsp[0].minor.yy198);
+ sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy410, &yymsp[-2].minor.yy410, &yymsp[0].minor.yy410);
}
-#line 3174 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3167 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 302:
-#line 1042 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Reindex(pParse, 0, 0);}
-#line 3179 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 303:
-#line 1043 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Reindex(pParse, &yymsp[-1].minor.yy198, &yymsp[0].minor.yy198);}
-#line 3184 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1075 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3VtabArgInit(pParse);}
+#line 3172 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 304:
-#line 1048 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Analyze(pParse, 0, 0);}
-#line 3189 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
case 305:
-#line 1049 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Analyze(pParse, &yymsp[-1].minor.yy198, &yymsp[0].minor.yy198);}
-#line 3194 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
case 306:
-#line 1054 "ext/pdo_sqlite/sqlite/src/parse.y"
-{
- sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy151,&yymsp[0].minor.yy198);
-}
-#line 3201 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 307:
-#line 1057 "ext/pdo_sqlite/sqlite/src/parse.y"
-{
- sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy198);
-}
-#line 3208 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
case 308:
-#line 1060 "ext/pdo_sqlite/sqlite/src/parse.y"
-{
- sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy151);
-}
-#line 3215 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1077 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
+#line 3180 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
break;
};
yygoto = yyRuleInfo[yyruleno].lhs;
@@ -3267,16 +3231,17 @@ static void yy_syntax_error(
){
sqlite3ParserARG_FETCH;
#define TOKEN (yyminor.yy0)
-#line 34 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 34 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.y"
- if( pParse->zErrMsg==0 ){
+ if( !pParse->parseError ){
if( TOKEN.z[0] ){
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
}else{
sqlite3ErrorMsg(pParse, "incomplete SQL statement");
}
+ pParse->parseError = 1;
}
-#line 3282 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3248 "/home/rei/php_dev/php52/ext/pdo_sqlite/sqlite/src/parse.c"
sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
@@ -3404,7 +3369,9 @@ void sqlite3Parser(
while(
yypParser->yyidx >= 0 &&
yymx != YYERRORSYMBOL &&
- (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
+ (yyact = yy_find_reduce_action(
+ yypParser->yystack[yypParser->yyidx].stateno,
+ YYERRORSYMBOL)) >= YYNSTATE
){
yy_pop_parser_stack(yypParser);
}
diff --git a/ext/pdo_sqlite/sqlite/src/parse.h b/ext/pdo_sqlite/sqlite/src/parse.h
index fcedda5896..65c9a5ce90 100644
--- a/ext/pdo_sqlite/sqlite/src/parse.h
+++ b/ext/pdo_sqlite/sqlite/src/parse.h
@@ -1,145 +1,153 @@
-#define TK_END_OF_FILE 1
-#define TK_ILLEGAL 2
-#define TK_SPACE 3
-#define TK_UNCLOSED_STRING 4
-#define TK_COMMENT 5
-#define TK_FUNCTION 6
-#define TK_COLUMN 7
-#define TK_AGG_FUNCTION 8
-#define TK_AGG_COLUMN 9
-#define TK_CONST_FUNC 10
-#define TK_SEMI 11
-#define TK_EXPLAIN 12
-#define TK_QUERY 13
-#define TK_PLAN 14
-#define TK_BEGIN 15
-#define TK_TRANSACTION 16
-#define TK_DEFERRED 17
-#define TK_IMMEDIATE 18
-#define TK_EXCLUSIVE 19
-#define TK_COMMIT 20
-#define TK_END 21
-#define TK_ROLLBACK 22
-#define TK_CREATE 23
-#define TK_TABLE 24
-#define TK_TEMP 25
-#define TK_LP 26
-#define TK_RP 27
-#define TK_AS 28
-#define TK_COMMA 29
-#define TK_ID 30
-#define TK_ABORT 31
-#define TK_AFTER 32
-#define TK_ANALYZE 33
-#define TK_ASC 34
-#define TK_ATTACH 35
-#define TK_BEFORE 36
-#define TK_CASCADE 37
-#define TK_CAST 38
-#define TK_CONFLICT 39
-#define TK_DATABASE 40
-#define TK_DESC 41
-#define TK_DETACH 42
-#define TK_EACH 43
-#define TK_FAIL 44
-#define TK_FOR 45
-#define TK_IGNORE 46
-#define TK_INITIALLY 47
-#define TK_INSTEAD 48
-#define TK_LIKE_KW 49
-#define TK_MATCH 50
-#define TK_KEY 51
-#define TK_OF 52
-#define TK_OFFSET 53
-#define TK_PRAGMA 54
-#define TK_RAISE 55
-#define TK_REPLACE 56
-#define TK_RESTRICT 57
-#define TK_ROW 58
-#define TK_STATEMENT 59
-#define TK_TRIGGER 60
-#define TK_VACUUM 61
-#define TK_VIEW 62
-#define TK_REINDEX 63
-#define TK_RENAME 64
-#define TK_CTIME_KW 65
-#define TK_ALTER 66
-#define TK_OR 67
-#define TK_AND 68
-#define TK_NOT 69
-#define TK_IS 70
-#define TK_BETWEEN 71
-#define TK_IN 72
-#define TK_ISNULL 73
-#define TK_NOTNULL 74
-#define TK_NE 75
-#define TK_EQ 76
-#define TK_GT 77
-#define TK_LE 78
-#define TK_LT 79
-#define TK_GE 80
-#define TK_ESCAPE 81
-#define TK_BITAND 82
-#define TK_BITOR 83
-#define TK_LSHIFT 84
-#define TK_RSHIFT 85
-#define TK_PLUS 86
-#define TK_MINUS 87
-#define TK_STAR 88
-#define TK_SLASH 89
-#define TK_REM 90
-#define TK_CONCAT 91
-#define TK_UMINUS 92
-#define TK_UPLUS 93
-#define TK_BITNOT 94
-#define TK_STRING 95
-#define TK_JOIN_KW 96
-#define TK_CONSTRAINT 97
-#define TK_DEFAULT 98
-#define TK_NULL 99
-#define TK_PRIMARY 100
-#define TK_UNIQUE 101
-#define TK_CHECK 102
-#define TK_REFERENCES 103
-#define TK_COLLATE 104
-#define TK_AUTOINCR 105
-#define TK_ON 106
-#define TK_DELETE 107
-#define TK_UPDATE 108
-#define TK_INSERT 109
-#define TK_SET 110
-#define TK_DEFERRABLE 111
-#define TK_FOREIGN 112
-#define TK_DROP 113
-#define TK_UNION 114
-#define TK_ALL 115
-#define TK_INTERSECT 116
-#define TK_EXCEPT 117
-#define TK_SELECT 118
-#define TK_DISTINCT 119
-#define TK_DOT 120
-#define TK_FROM 121
-#define TK_JOIN 122
-#define TK_USING 123
-#define TK_ORDER 124
-#define TK_BY 125
-#define TK_GROUP 126
-#define TK_HAVING 127
-#define TK_LIMIT 128
-#define TK_WHERE 129
-#define TK_INTO 130
-#define TK_VALUES 131
-#define TK_INTEGER 132
-#define TK_FLOAT 133
-#define TK_BLOB 134
-#define TK_REGISTER 135
-#define TK_VARIABLE 136
-#define TK_EXISTS 137
-#define TK_CASE 138
-#define TK_WHEN 139
-#define TK_THEN 140
-#define TK_ELSE 141
-#define TK_INDEX 142
-#define TK_TO 143
-#define TK_ADD 144
-#define TK_COLUMNKW 145
+#define TK_SEMI 1
+#define TK_EXPLAIN 2
+#define TK_QUERY 3
+#define TK_PLAN 4
+#define TK_BEGIN 5
+#define TK_TRANSACTION 6
+#define TK_DEFERRED 7
+#define TK_IMMEDIATE 8
+#define TK_EXCLUSIVE 9
+#define TK_COMMIT 10
+#define TK_END 11
+#define TK_ROLLBACK 12
+#define TK_CREATE 13
+#define TK_TABLE 14
+#define TK_IF 15
+#define TK_NOT 16
+#define TK_EXISTS 17
+#define TK_TEMP 18
+#define TK_LP 19
+#define TK_RP 20
+#define TK_AS 21
+#define TK_COMMA 22
+#define TK_ID 23
+#define TK_ABORT 24
+#define TK_AFTER 25
+#define TK_ANALYZE 26
+#define TK_ASC 27
+#define TK_ATTACH 28
+#define TK_BEFORE 29
+#define TK_CASCADE 30
+#define TK_CAST 31
+#define TK_CONFLICT 32
+#define TK_DATABASE 33
+#define TK_DESC 34
+#define TK_DETACH 35
+#define TK_EACH 36
+#define TK_FAIL 37
+#define TK_FOR 38
+#define TK_IGNORE 39
+#define TK_INITIALLY 40
+#define TK_INSTEAD 41
+#define TK_LIKE_KW 42
+#define TK_MATCH 43
+#define TK_KEY 44
+#define TK_OF 45
+#define TK_OFFSET 46
+#define TK_PRAGMA 47
+#define TK_RAISE 48
+#define TK_REPLACE 49
+#define TK_RESTRICT 50
+#define TK_ROW 51
+#define TK_STATEMENT 52
+#define TK_TRIGGER 53
+#define TK_VACUUM 54
+#define TK_VIEW 55
+#define TK_VIRTUAL 56
+#define TK_REINDEX 57
+#define TK_RENAME 58
+#define TK_CTIME_KW 59
+#define TK_ANY 60
+#define TK_OR 61
+#define TK_AND 62
+#define TK_IS 63
+#define TK_BETWEEN 64
+#define TK_IN 65
+#define TK_ISNULL 66
+#define TK_NOTNULL 67
+#define TK_NE 68
+#define TK_EQ 69
+#define TK_GT 70
+#define TK_LE 71
+#define TK_LT 72
+#define TK_GE 73
+#define TK_ESCAPE 74
+#define TK_BITAND 75
+#define TK_BITOR 76
+#define TK_LSHIFT 77
+#define TK_RSHIFT 78
+#define TK_PLUS 79
+#define TK_MINUS 80
+#define TK_STAR 81
+#define TK_SLASH 82
+#define TK_REM 83
+#define TK_CONCAT 84
+#define TK_UMINUS 85
+#define TK_UPLUS 86
+#define TK_BITNOT 87
+#define TK_STRING 88
+#define TK_JOIN_KW 89
+#define TK_CONSTRAINT 90
+#define TK_DEFAULT 91
+#define TK_NULL 92
+#define TK_PRIMARY 93
+#define TK_UNIQUE 94
+#define TK_CHECK 95
+#define TK_REFERENCES 96
+#define TK_COLLATE 97
+#define TK_AUTOINCR 98
+#define TK_ON 99
+#define TK_DELETE 100
+#define TK_UPDATE 101
+#define TK_INSERT 102
+#define TK_SET 103
+#define TK_DEFERRABLE 104
+#define TK_FOREIGN 105
+#define TK_DROP 106
+#define TK_UNION 107
+#define TK_ALL 108
+#define TK_EXCEPT 109
+#define TK_INTERSECT 110
+#define TK_SELECT 111
+#define TK_DISTINCT 112
+#define TK_DOT 113
+#define TK_FROM 114
+#define TK_JOIN 115
+#define TK_USING 116
+#define TK_ORDER 117
+#define TK_BY 118
+#define TK_GROUP 119
+#define TK_HAVING 120
+#define TK_LIMIT 121
+#define TK_WHERE 122
+#define TK_INTO 123
+#define TK_VALUES 124
+#define TK_INTEGER 125
+#define TK_FLOAT 126
+#define TK_BLOB 127
+#define TK_REGISTER 128
+#define TK_VARIABLE 129
+#define TK_CASE 130
+#define TK_WHEN 131
+#define TK_THEN 132
+#define TK_ELSE 133
+#define TK_INDEX 134
+#define TK_ALTER 135
+#define TK_TO 136
+#define TK_ADD 137
+#define TK_COLUMNKW 138
+#define TK_TO_TEXT 139
+#define TK_TO_BLOB 140
+#define TK_TO_NUMERIC 141
+#define TK_TO_INT 142
+#define TK_TO_REAL 143
+#define TK_END_OF_FILE 144
+#define TK_ILLEGAL 145
+#define TK_SPACE 146
+#define TK_UNCLOSED_STRING 147
+#define TK_COMMENT 148
+#define TK_FUNCTION 149
+#define TK_COLUMN 150
+#define TK_AGG_FUNCTION 151
+#define TK_AGG_COLUMN 152
+#define TK_CONST_FUNC 153
diff --git a/ext/pdo_sqlite/sqlite/src/parse.y b/ext/pdo_sqlite/sqlite/src/parse.y
index 1f16c20a8c..301eb9b8e5 100644
--- a/ext/pdo_sqlite/sqlite/src/parse.y
+++ b/ext/pdo_sqlite/sqlite/src/parse.y
@@ -32,14 +32,19 @@
// This code runs whenever there is a syntax error
//
%syntax_error {
- if( pParse->zErrMsg==0 ){
+ if( !pParse->parseError ){
if( TOKEN.z[0] ){
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
}else{
sqlite3ErrorMsg(pParse, "incomplete SQL statement");
}
+ pParse->parseError = 1;
}
}
+%stack_overflow {
+ sqlite3ErrorMsg(pParse, "parser stack overflow");
+ pParse->parseError = 1;
+}
// The name of the generated procedure that implements the parser
// is as follows:
@@ -66,7 +71,7 @@ struct LimitVal {
** GLOB, NOT LIKE, and NOT GLOB operators.
*/
struct LikeOp {
- Token operator; /* "like" or "glob" or "regexp" */
+ Token eOperator; /* "like" or "glob" or "regexp" */
int not; /* True if the NOT keyword is present */
};
@@ -88,13 +93,6 @@ struct AttachKey { int type; Token key; };
} // end %include
-// These are extra tokens used by the lexer but never seen by the
-// parser. We put them in a rule so that the parser generator will
-// add them to the parse.h output file.
-//
-%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
- COLUMN AGG_FUNCTION AGG_COLUMN CONST_FUNC.
-
// Input is a single SQL command
input ::= cmdlist.
cmdlist ::= cmdlist ecmd.
@@ -127,9 +125,12 @@ cmd ::= ROLLBACK trans_opt. {sqlite3RollbackTransaction(pParse);}
///////////////////// The CREATE TABLE statement ////////////////////////////
//
cmd ::= create_table create_table_args.
-create_table ::= CREATE(X) temp(T) TABLE nm(Y) dbnm(Z). {
- sqlite3StartTable(pParse,&X,&Y,&Z,T,0);
+create_table ::= CREATE temp(T) TABLE ifnotexists(E) nm(Y) dbnm(Z). {
+ sqlite3StartTable(pParse,&Y,&Z,T,0,0,E);
}
+%type ifnotexists {int}
+ifnotexists(A) ::= . {A = 0;}
+ifnotexists(A) ::= IF NOT EXISTS. {A = 1;}
%type temp {int}
%ifndef SQLITE_OMIT_TEMPDB
temp(A) ::= TEMP. {A = 1;}
@@ -175,12 +176,13 @@ id(A) ::= ID(X). {A = X;}
DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH PLAN QUERY KEY
OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
- TEMP TRIGGER VACUUM VIEW
+ TEMP TRIGGER VACUUM VIEW VIRTUAL
%ifdef SQLITE_OMIT_COMPOUND_SELECT
EXCEPT INTERSECT UNION
%endif
- REINDEX RENAME CTIME_KW ALTER
+ REINDEX RENAME CTIME_KW IF
.
+%wildcard ANY.
// Define operator precedence early so that this is the first occurance
// of the operator tokens in the grammer. Keeping the operators together
@@ -196,7 +198,7 @@ id(A) ::= ID(X). {A = X;}
%left OR.
%left AND.
%right NOT.
-%left IS LIKE_KW BETWEEN IN ISNULL NOTNULL NE EQ.
+%left IS MATCH LIKE_KW BETWEEN IN ISNULL NOTNULL NE EQ.
%left GT LE LT GE.
%right ESCAPE.
%left BITAND BITOR LSHIFT RSHIFT.
@@ -208,8 +210,7 @@ id(A) ::= ID(X). {A = X;}
// And "ids" is an identifer-or-string.
//
%type ids {Token}
-ids(A) ::= ID(X). {A = X;}
-ids(A) ::= STRING(X). {A = X;}
+ids(A) ::= ID|STRING(X). {A = X;}
// The name of a column or table can be any of the following:
//
@@ -238,8 +239,8 @@ typetoken(A) ::= typename(X) LP signed COMMA signed RP(Y). {
typename(A) ::= ids(X). {A = X;}
typename(A) ::= typename(X) ids(Y). {A.z=X.z; A.n=Y.n+(Y.z-X.z);}
%type signed {int}
-signed(A) ::= plus_num(X). { A = atoi(X.z); }
-signed(A) ::= minus_num(X). { A = -atoi(X.z); }
+signed(A) ::= plus_num(X). { A = atoi((char*)X.z); }
+signed(A) ::= minus_num(X). { A = -atoi((char*)X.z); }
// "carglist" is a list of additional constraints that come after the
// column name and column type in a CREATE TABLE statement.
@@ -265,14 +266,14 @@ carg ::= DEFAULT id(X). {
//
ccons ::= NULL onconf.
ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, 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(X) RP onconf. {sqlite3ExprDelete(X);}
+ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I).
+ {sqlite3AddPrimaryKey(pParse,0,R,I,Z);}
+ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0);}
+ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X);}
ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
{sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);}
-ccons ::= COLLATE id(C). {sqlite3AddCollateType(pParse, C.z, C.n);}
+ccons ::= COLLATE id(C). {sqlite3AddCollateType(pParse, (char*)C.z, C.n);}
// The optional AUTOINCREMENT keyword
%type autoinc {int}
@@ -315,10 +316,10 @@ conslist ::= conslist tcons.
conslist ::= tcons.
tcons ::= CONSTRAINT nm.
tcons ::= PRIMARY KEY LP idxlist(X) autoinc(I) RP onconf(R).
- {sqlite3AddPrimaryKey(pParse,X,R,I);}
+ {sqlite3AddPrimaryKey(pParse,X,R,I,0);}
tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
- {sqlite3CreateIndex(pParse,0,0,0,X,R,0,0);}
-tcons ::= CHECK expr onconf.
+ {sqlite3CreateIndex(pParse,0,0,0,X,R,0,0,0,0);}
+tcons ::= CHECK LP expr(E) RP onconf. {sqlite3AddCheckConstraint(pParse,E);}
tcons ::= FOREIGN KEY LP idxlist(FA) RP
REFERENCES nm(T) idxlist_opt(TA) refargs(R) defer_subclause_opt(D). {
sqlite3CreateForeignKey(pParse, FA, &T, TA, R);
@@ -344,9 +345,12 @@ resolvetype(A) ::= REPLACE. {A = OE_Replace;}
////////////////////////// The DROP TABLE /////////////////////////////////////
//
-cmd ::= DROP TABLE fullname(X). {
- sqlite3DropTable(pParse, X, 0);
+cmd ::= DROP TABLE ifexists(E) fullname(X). {
+ sqlite3DropTable(pParse, X, 0, E);
}
+%type ifexists {int}
+ifexists(A) ::= IF EXISTS. {A = 1;}
+ifexists(A) ::= . {A = 0;}
///////////////////// The CREATE VIEW statement /////////////////////////////
//
@@ -354,8 +358,8 @@ cmd ::= DROP TABLE fullname(X). {
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);
+cmd ::= DROP VIEW ifexists(E) fullname(X). {
+ sqlite3DropTable(pParse, X, 1, E);
}
%endif // SQLITE_OMIT_VIEW
@@ -381,10 +385,9 @@ select(A) ::= select(X) multiselect_op(Y) oneselect(Z). {
A = Z;
}
%type multiselect_op {int}
-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;}
+multiselect_op(A) ::= UNION(OP). {A = @OP;}
+multiselect_op(A) ::= UNION ALL. {A = TK_ALL;}
+multiselect_op(A) ::= EXCEPT|INTERSECT(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). {
@@ -467,7 +470,7 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(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( A && A->nSrc>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; }
@@ -479,7 +482,7 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
}
}
- // A seltablist_paren nonterminal represents anything in a FROM that
+ // 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.
//
@@ -501,8 +504,7 @@ fullname(A) ::= nm(X) dbnm(Y). {A = sqlite3SrcListAppend(0,&X,&Y);}
%type joinop {int}
%type joinop2 {int}
-joinop(X) ::= COMMA. { X = JT_INNER; }
-joinop(X) ::= JOIN. { X = JT_INNER; }
+joinop(X) ::= COMMA|JOIN. { X = JT_INNER; }
joinop(X) ::= JOIN_KW(A) JOIN. { X = sqlite3JoinType(pParse,&A,0,0); }
joinop(X) ::= JOIN_KW(A) nm(B) JOIN. { X = sqlite3JoinType(pParse,&A,&B,0); }
joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN.
@@ -645,10 +647,8 @@ 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);
}
-term(A) ::= INTEGER(X). {A = sqlite3Expr(@X, 0, 0, &X);}
-term(A) ::= FLOAT(X). {A = sqlite3Expr(@X, 0, 0, &X);}
+term(A) ::= INTEGER|FLOAT|BLOB(X). {A = sqlite3Expr(@X, 0, 0, &X);}
term(A) ::= STRING(X). {A = sqlite3Expr(@X, 0, 0, &X);}
-term(A) ::= BLOB(X). {A = sqlite3Expr(@X, 0, 0, &X);}
expr(A) ::= REGISTER(X). {A = sqlite3RegisterExpr(pParse, &X);}
expr(A) ::= VARIABLE(X). {
Token *pToken = &X;
@@ -664,7 +664,7 @@ expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
expr(A) ::= ID(X) LP distinct(D) exprlist(Y) RP(E). {
A = sqlite3ExprFunction(Y, &X);
sqlite3ExprSpan(A,&X,&E);
- if( D ){
+ if( D && A ){
A->flags |= EP_Distinct;
}
}
@@ -678,53 +678,45 @@ term(A) ::= CTIME_KW(OP). {
A = sqlite3ExprFunction(0,&OP);
if( A ) A->op = TK_CONST_FUNC;
}
-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);}
-expr(A) ::= expr(X) GT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
-expr(A) ::= expr(X) LE(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
-expr(A) ::= expr(X) GE(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
-expr(A) ::= expr(X) NE(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
-expr(A) ::= expr(X) EQ(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
-expr(A) ::= expr(X) BITAND(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
-expr(A) ::= expr(X) BITOR(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
-expr(A) ::= expr(X) LSHIFT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
-expr(A) ::= expr(X) RSHIFT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
-expr(A) ::= expr(X) PLUS(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
-expr(A) ::= expr(X) MINUS(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
-expr(A) ::= expr(X) STAR(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
-expr(A) ::= expr(X) SLASH(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
-expr(A) ::= expr(X) REM(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
-expr(A) ::= expr(X) CONCAT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 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|GT|GE|LE(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) EQ|NE(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) BITAND|BITOR|LSHIFT|RSHIFT(OP) expr(Y).
+ {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) PLUS|MINUS(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) STAR|SLASH|REM(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
+expr(A) ::= expr(X) CONCAT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
%type likeop {struct LikeOp}
-likeop(A) ::= LIKE_KW(X). {A.operator = X; A.not = 0;}
-likeop(A) ::= NOT LIKE_KW(X). {A.operator = X; A.not = 1;}
+likeop(A) ::= LIKE_KW(X). {A.eOperator = X; A.not = 0;}
+likeop(A) ::= NOT LIKE_KW(X). {A.eOperator = X; A.not = 1;}
+likeop(A) ::= MATCH(X). {A.eOperator = X; A.not = 0;}
+likeop(A) ::= NOT MATCH(X). {A.eOperator = X; A.not = 1;}
%type escape {Expr*}
+%destructor escape {sqlite3ExprDelete($$);}
escape(X) ::= ESCAPE expr(A). [ESCAPE] {X = A;}
escape(X) ::= . [ESCAPE] {X = 0;}
expr(A) ::= expr(X) likeop(OP) expr(Y) escape(E). [LIKE_KW] {
- ExprList *pList = sqlite3ExprListAppend(0, Y, 0);
+ ExprList *pList;
+ pList = sqlite3ExprListAppend(0, Y, 0);
pList = sqlite3ExprListAppend(pList, X, 0);
if( E ){
pList = sqlite3ExprListAppend(pList, E, 0);
}
- A = sqlite3ExprFunction(pList, &OP.operator);
+ A = sqlite3ExprFunction(pList, &OP.eOperator);
if( OP.not ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A, &X->span, &Y->span);
+ if( A ) A->flags |= EP_InfixFunc;
}
-expr(A) ::= expr(X) ISNULL(E). {
- A = sqlite3Expr(TK_ISNULL, X, 0, 0);
+expr(A) ::= expr(X) ISNULL|NOTNULL(E). {
+ A = sqlite3Expr(@E, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) IS NULL(E). {
A = sqlite3Expr(TK_ISNULL, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
-expr(A) ::= expr(X) NOTNULL(E). {
- A = sqlite3Expr(TK_NOTNULL, X, 0, 0);
- sqlite3ExprSpan(A,&X->span,&E);
-}
expr(A) ::= expr(X) NOT NULL(E). {
A = sqlite3Expr(TK_NOTNULL, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
@@ -733,11 +725,7 @@ expr(A) ::= expr(X) IS NOT NULL(E). {
A = sqlite3Expr(TK_NOTNULL, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
-expr(A) ::= NOT(B) expr(X). {
- A = sqlite3Expr(@B, X, 0, 0);
- sqlite3ExprSpan(A,&B,&X->span);
-}
-expr(A) ::= BITNOT(B) expr(X). {
+expr(A) ::= NOT|BITNOT(B) expr(X). {
A = sqlite3Expr(@B, X, 0, 0);
sqlite3ExprSpan(A,&B,&X->span);
}
@@ -840,9 +828,11 @@ case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). {
A = sqlite3ExprListAppend(A, Z, 0);
}
%type case_else {Expr*}
+%destructor case_else {sqlite3ExprDelete($$);}
case_else(A) ::= ELSE expr(X). {A = X;}
case_else(A) ::= . {A = 0;}
%type case_operand {Expr*}
+%destructor case_operand {sqlite3ExprDelete($$);}
case_operand(A) ::= expr(X). {A = X;}
case_operand(A) ::= . {A = 0;}
@@ -859,11 +849,10 @@ expritem(A) ::= . {A = 0;}
///////////////////////////// The CREATE INDEX command ///////////////////////
//
-cmd ::= CREATE(S) uniqueflag(U) INDEX nm(X) dbnm(D)
- 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, sqlite3SrcListAppend(0,&Y,0),Z,U, &S, &E);
+cmd ::= CREATE(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D)
+ ON nm(Y) LP idxlist(Z) RP(E). {
+ sqlite3CreateIndex(pParse, &X, &D, sqlite3SrcListAppend(0,&Y,0), Z, U,
+ &S, &E, SQLITE_SO_ASC, NE);
}
%type uniqueflag {int}
@@ -878,33 +867,35 @@ uniqueflag(A) ::= . {A = OE_None;}
idxlist_opt(A) ::= . {A = 0;}
idxlist_opt(A) ::= LP idxlist(X) RP. {A = X;}
-idxlist(A) ::= idxlist(X) COMMA idxitem(Y) collate(C) sortorder. {
+idxlist(A) ::= idxlist(X) COMMA idxitem(Y) collate(C) sortorder(Z). {
Expr *p = 0;
if( C.n>0 ){
p = sqlite3Expr(TK_COLUMN, 0, 0, 0);
- if( p ) p->pColl = sqlite3LocateCollSeq(pParse, C.z, C.n);
+ if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)C.z, C.n);
}
A = sqlite3ExprListAppend(X, p, &Y);
+ if( A ) A->a[A->nExpr-1].sortOrder = Z;
}
-idxlist(A) ::= idxitem(Y) collate(C) sortorder. {
+idxlist(A) ::= idxitem(Y) collate(C) sortorder(Z). {
Expr *p = 0;
if( C.n>0 ){
p = sqlite3Expr(TK_COLUMN, 0, 0, 0);
- if( p ) p->pColl = sqlite3LocateCollSeq(pParse, C.z, C.n);
+ if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)C.z, C.n);
}
A = sqlite3ExprListAppend(0, p, &Y);
+ if( A ) A->a[A->nExpr-1].sortOrder = Z;
}
idxitem(A) ::= nm(X). {A = X;}
///////////////////////////// The DROP INDEX command /////////////////////////
//
-cmd ::= DROP INDEX fullname(X). {sqlite3DropIndex(pParse, X);}
+cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);}
///////////////////////////// The VACUUM command /////////////////////////////
//
-cmd ::= VACUUM. {sqlite3Vacuum(pParse,0);}
-cmd ::= VACUUM nm. {sqlite3Vacuum(pParse,0);}
+cmd ::= VACUUM. {sqlite3Vacuum(pParse);}
+cmd ::= VACUUM nm. {sqlite3Vacuum(pParse);}
///////////////////////////// The PRAGMA command /////////////////////////////
//
@@ -920,8 +911,7 @@ 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;}
-number(A) ::= FLOAT(X). {A = X;}
+number(A) ::= INTEGER|FLOAT(X). {A = X;}
plus_opt ::= PLUS.
plus_opt ::= .
@@ -951,8 +941,7 @@ trigger_time(A) ::= . { A = TK_BEFORE; }
%type trigger_event {struct TrigEvent}
%destructor trigger_event {sqlite3IdListDelete($$.b);}
-trigger_event(A) ::= DELETE(OP). {A.a = @OP; A.b = 0;}
-trigger_event(A) ::= INSERT(OP). {A.a = @OP; A.b = 0;}
+trigger_event(A) ::= DELETE|INSERT(OP). {A.a = @OP; A.b = 0;}
trigger_event(A) ::= UPDATE(OP). {A.a = @OP; A.b = 0;}
trigger_event(A) ::= UPDATE OF inscollist(X). {A.a = TK_UPDATE; A.b = X;}
@@ -962,14 +951,20 @@ foreach_clause(A) ::= FOR EACH ROW. { A = TK_ROW; }
foreach_clause(A) ::= FOR EACH STATEMENT. { A = TK_STATEMENT; }
%type when_clause {Expr*}
+%destructor when_clause {sqlite3ExprDelete($$);}
when_clause(A) ::= . { A = 0; }
when_clause(A) ::= WHEN expr(X). { A = X; }
%type trigger_cmd_list {TriggerStep*}
%destructor trigger_cmd_list {sqlite3DeleteTriggerStep($$);}
-trigger_cmd_list(A) ::= trigger_cmd(X) SEMI trigger_cmd_list(Y). {
- X->pNext = Y;
- A = X;
+trigger_cmd_list(A) ::= trigger_cmd_list(Y) trigger_cmd(X) SEMI. {
+ if( Y ){
+ Y->pLast->pNext = X;
+ }else{
+ Y = X;
+ }
+ Y->pLast = X;
+ A = Y;
}
trigger_cmd_list(A) ::= . { A = 0; }
@@ -997,13 +992,17 @@ trigger_cmd(A) ::= select(X). {A = sqlite3TriggerSelectStep(X); }
// The special RAISE expression that may occur in trigger programs
expr(A) ::= RAISE(X) LP IGNORE RP(Y). {
A = sqlite3Expr(TK_RAISE, 0, 0, 0);
- A->iColumn = OE_Ignore;
- sqlite3ExprSpan(A, &X, &Y);
+ if( A ){
+ A->iColumn = OE_Ignore;
+ sqlite3ExprSpan(A, &X, &Y);
+ }
}
expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
A = sqlite3Expr(TK_RAISE, 0, 0, &Z);
- A->iColumn = T;
- sqlite3ExprSpan(A, &X, &Y);
+ if( A ) {
+ A->iColumn = T;
+ sqlite3ExprSpan(A, &X, &Y);
+ }
}
%endif // !SQLITE_OMIT_TRIGGER
@@ -1021,20 +1020,20 @@ cmd ::= DROP TRIGGER fullname(X). {
%endif // !SQLITE_OMIT_TRIGGER
//////////////////////// ATTACH DATABASE file AS name /////////////////////////
-cmd ::= ATTACH database_kw_opt ids(F) AS nm(D) key_opt(K). {
- sqlite3Attach(pParse, &F, &D, K.type, &K.key);
+cmd ::= ATTACH database_kw_opt expr(F) AS expr(D) key_opt(K). {
+ sqlite3Attach(pParse, F, D, K);
}
-%type key_opt {struct AttachKey}
-key_opt(A) ::= . { A.type = 0; }
-key_opt(A) ::= KEY ids(X). { A.type=1; A.key = X; }
-key_opt(A) ::= KEY BLOB(X). { A.type=2; A.key = X; }
+%type key_opt {Expr *}
+%destructor key_opt {sqlite3ExprDelete($$);}
+key_opt(A) ::= . { A = 0; }
+key_opt(A) ::= KEY expr(X). { A = X; }
database_kw_opt ::= DATABASE.
database_kw_opt ::= .
//////////////////////// DETACH DATABASE name /////////////////////////////////
-cmd ::= DETACH database_kw_opt nm(D). {
- sqlite3Detach(pParse, &D);
+cmd ::= DETACH database_kw_opt expr(D). {
+ sqlite3Detach(pParse, D);
}
////////////////////////// REINDEX collation //////////////////////////////////
@@ -1063,3 +1062,21 @@ add_column_fullname ::= fullname(X). {
kwcolumn_opt ::= .
kwcolumn_opt ::= COLUMNKW.
%endif
+
+//////////////////////// CREATE VIRTUAL TABLE ... /////////////////////////////
+%ifndef SQLITE_OMIT_VIRTUALTABLE
+cmd ::= create_vtab. {sqlite3VtabFinishParse(pParse,0);}
+cmd ::= create_vtab LP vtabarglist RP(X). {sqlite3VtabFinishParse(pParse,&X);}
+create_vtab ::= CREATE VIRTUAL TABLE nm(X) dbnm(Y) USING nm(Z). {
+ sqlite3VtabBeginParse(pParse, &X, &Y, &Z);
+}
+vtabarglist ::= vtabarg.
+vtabarglist ::= vtabarglist COMMA vtabarg.
+vtabarg ::= . {sqlite3VtabArgInit(pParse);}
+vtabarg ::= vtabarg vtabargtoken.
+vtabargtoken ::= ANY(X). {sqlite3VtabArgExtend(pParse,&X);}
+vtabargtoken ::= lp anylist RP(X). {sqlite3VtabArgExtend(pParse,&X);}
+lp ::= LP(X). {sqlite3VtabArgExtend(pParse,&X);}
+anylist ::= .
+anylist ::= anylist ANY(X). {sqlite3VtabArgExtend(pParse,&X);}
+%endif
diff --git a/ext/pdo_sqlite/sqlite/src/pragma.c b/ext/pdo_sqlite/sqlite/src/pragma.c
index e366401d26..fbcc1adc01 100644
--- a/ext/pdo_sqlite/sqlite/src/pragma.c
+++ b/ext/pdo_sqlite/sqlite/src/pragma.c
@@ -36,7 +36,7 @@
** 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(const u8 *z){
+static int getSafetyLevel(const char *z){
/* 123456789 123456789 */
static const char zText[] = "onoffalseyestruefull";
static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16};
@@ -58,7 +58,7 @@ static int getSafetyLevel(const u8 *z){
/*
** Interpret the given string as a boolean value.
*/
-static int getBoolean(const u8 *z){
+static int getBoolean(const char *z){
return getSafetyLevel(z)&1;
}
@@ -128,7 +128,7 @@ static void returnSingleInt(Parse *pParse, const char *zLabel, int value){
sqlite3VdbeAddOp(v, OP_Integer, value, 0);
if( pParse->explain==0 ){
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, zLabel, P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, P3_STATIC);
}
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
}
@@ -151,9 +151,18 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
{ "short_column_names", SQLITE_ShortColNames },
{ "count_changes", SQLITE_CountRows },
{ "empty_result_callbacks", SQLITE_NullCallback },
+ { "legacy_file_format", SQLITE_LegacyFileFmt },
+ { "fullfsync", SQLITE_FullFSync },
+#ifndef SQLITE_OMIT_CHECK
+ { "ignore_check_constraints", SQLITE_IgnoreChecks },
+#endif
/* The following is VERY experimental */
{ "writable_schema", SQLITE_WriteSchema },
{ "omit_readlock", SQLITE_NoReadlock },
+
+ /* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
+ ** flag if there are any active statements. */
+ { "read_uncommitted", SQLITE_ReadUncommitted },
};
int i;
const struct sPragmaType *p;
@@ -172,10 +181,6 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
db->flags &= ~p->mask;
}
}
- /* If one of these pragmas is executed, any prepared statements
- ** need to be recompiled.
- */
- sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
}
return 1;
}
@@ -222,6 +227,13 @@ void sqlite3Pragma(
if( iDb<0 ) return;
pDb = &db->aDb[iDb];
+ /* If the temp database has been explicitly named as part of the
+ ** pragma, make sure it is open.
+ */
+ if( iDb==1 && sqlite3OpenTempDatabase(pParse) ){
+ return;
+ }
+
zLeft = sqlite3NameFromToken(pId);
if( !zLeft ) return;
if( minusFlag ){
@@ -266,7 +278,7 @@ void sqlite3Pragma(
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
if( !zRight ){
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, "cache_size", P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", P3_STATIC);
addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
sqlite3VdbeChangeP1(v, addr, iDb);
sqlite3VdbeChangeP1(v, addr+5, MAX_PAGES);
@@ -280,8 +292,8 @@ void sqlite3Pragma(
sqlite3VdbeAddOp(v, OP_Ge, 0, addr+3);
sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 2);
- pDb->cache_size = size;
- sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size);
+ pDb->pSchema->cache_size = size;
+ sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
}
}else
@@ -342,12 +354,12 @@ void sqlite3Pragma(
if( sqlite3StrICmp(zLeft,"cache_size")==0 ){
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
if( !zRight ){
- returnSingleInt(pParse, "cache_size", pDb->cache_size);
+ returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
}else{
int size = atoi(zRight);
if( size<0 ) size = -size;
- pDb->cache_size = size;
- sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size);
+ pDb->pSchema->cache_size = size;
+ sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
}
}else
@@ -384,7 +396,8 @@ void sqlite3Pragma(
if( !zRight ){
if( sqlite3_temp_directory ){
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, "temp_store_directory", P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME,
+ "temp_store_directory", P3_STATIC);
sqlite3VdbeOp3(v, OP_String8, 0, 0, sqlite3_temp_directory, 0);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
}
@@ -428,7 +441,6 @@ void sqlite3Pragma(
"Safety level may not be changed inside a transaction");
}else{
pDb->safety_level = getSafetyLevel(zRight)+1;
- sqlite3BtreeSetSafetyLevel(pDb->pBt, pDb->safety_level);
}
}
}else
@@ -460,22 +472,23 @@ void sqlite3Pragma(
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
int i;
+ Column *pCol;
sqlite3VdbeSetNumCols(v, 6);
- sqlite3VdbeSetColName(v, 0, "cid", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
- sqlite3VdbeSetColName(v, 2, "type", P3_STATIC);
- sqlite3VdbeSetColName(v, 3, "notnull", P3_STATIC);
- sqlite3VdbeSetColName(v, 4, "dflt_value", P3_STATIC);
- sqlite3VdbeSetColName(v, 5, "pk", P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", P3_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", P3_STATIC);
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", P3_STATIC);
+ sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", P3_STATIC);
+ sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", P3_STATIC);
sqlite3ViewGetColumnNames(pParse, pTab);
- for(i=0; i<pTab->nCol; i++){
+ for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[i].zName, 0);
+ sqlite3VdbeOp3(v, OP_String8, 0, 0, pCol->zName, 0);
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);
- sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);
- sqlite3VdbeAddOp(v, OP_Integer, pTab->aCol[i].isPrimKey, 0);
+ pCol->zType ? pCol->zType : "", 0);
+ sqlite3VdbeAddOp(v, OP_Integer, pCol->notNull, 0);
+ sqlite3ExprCode(pParse, pCol->pDflt);
+ sqlite3VdbeAddOp(v, OP_Integer, pCol->isPrimKey, 0);
sqlite3VdbeAddOp(v, OP_Callback, 6, 0);
}
}
@@ -490,9 +503,9 @@ void sqlite3Pragma(
int i;
pTab = pIdx->pTable;
sqlite3VdbeSetNumCols(v, 3);
- sqlite3VdbeSetColName(v, 0, "seqno", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, "cid", P3_STATIC);
- sqlite3VdbeSetColName(v, 2, "name", P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", P3_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", P3_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", P3_STATIC);
for(i=0; i<pIdx->nColumn; i++){
int cnum = pIdx->aiColumn[i];
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
@@ -515,9 +528,9 @@ void sqlite3Pragma(
if( pIdx ){
int i = 0;
sqlite3VdbeSetNumCols(v, 3);
- sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
- sqlite3VdbeSetColName(v, 2, "unique", P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", P3_STATIC);
while(pIdx){
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0);
@@ -534,9 +547,9 @@ void sqlite3Pragma(
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);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", P3_STATIC);
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt==0 ) continue;
assert( db->aDb[i].zName!=0 );
@@ -552,8 +565,8 @@ void sqlite3Pragma(
int i = 0;
HashElem *p;
sqlite3VdbeSetNumCols(v, 2);
- sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){
CollSeq *pColl = (CollSeq *)sqliteHashData(p);
sqlite3VdbeAddOp(v, OP_Integer, i++, 0);
@@ -575,11 +588,11 @@ void sqlite3Pragma(
if( pFK ){
int i = 0;
sqlite3VdbeSetNumCols(v, 5);
- sqlite3VdbeSetColName(v, 0, "id", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, "seq", P3_STATIC);
- sqlite3VdbeSetColName(v, 2, "table", P3_STATIC);
- sqlite3VdbeSetColName(v, 3, "from", P3_STATIC);
- sqlite3VdbeSetColName(v, 4, "to", P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", P3_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", P3_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", P3_STATIC);
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", P3_STATIC);
+ sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", P3_STATIC);
while(pFK){
int j;
for(j=0; j<pFK->nCol; j++){
@@ -641,12 +654,13 @@ void sqlite3Pragma(
/* Initialize the VDBE program */
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, "integrity_check", P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P3_STATIC);
sqlite3VdbeAddOp(v, OP_MemInt, 0, 0); /* Initialize error count to 0 */
/* Do an integrity check on each database file */
for(i=0; i<db->nDb; i++){
HashElem *x;
+ Hash *pTbls;
int cnt = 0;
if( OMIT_TEMPDB && i==1 ) continue;
@@ -655,13 +669,13 @@ void sqlite3Pragma(
/* Do an integrity check of the B-Tree
*/
- for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
+ pTbls = &db->aDb[i].pSchema->tblHash;
+ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
sqlite3VdbeAddOp(v, OP_Integer, pTab->tnum, 0);
cnt++;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto pragma_out;
sqlite3VdbeAddOp(v, OP_Integer, pIdx->tnum, 0);
cnt++;
}
@@ -670,18 +684,19 @@ void sqlite3Pragma(
sqlite3VdbeAddOp(v, OP_IntegrityCk, cnt, i);
sqlite3VdbeAddOp(v, OP_Dup, 0, 1);
addr = sqlite3VdbeOp3(v, OP_String8, 0, 0, "ok", P3_STATIC);
- sqlite3VdbeAddOp(v, OP_Eq, 0, addr+6);
+ sqlite3VdbeAddOp(v, OP_Eq, 0, addr+7);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName),
P3_DYNAMIC);
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
sqlite3VdbeAddOp(v, OP_Concat, 0, 1);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
+ sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
/* Make sure all the indices are constructed correctly.
*/
sqlite3CodeVerifySchema(pParse, i);
- for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
+ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
int loopTop;
@@ -690,11 +705,11 @@ void sqlite3Pragma(
sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
sqlite3VdbeAddOp(v, OP_MemInt, 0, 1);
loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
- sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
+ sqlite3VdbeAddOp(v, OP_MemIncr, 1, 1);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int jmp2;
static const VdbeOpList idxErr[] = {
- { OP_MemIncr, 0, 0, 0},
+ { OP_MemIncr, 1, 0, 0},
{ OP_String8, 0, 0, "rowid "},
{ OP_Rowid, 1, 0, 0},
{ OP_String8, 0, 0, " missing from index "},
@@ -714,12 +729,12 @@ void sqlite3Pragma(
static const VdbeOpList cntIdx[] = {
{ OP_MemInt, 0, 2, 0},
{ OP_Rewind, 0, 0, 0}, /* 1 */
- { OP_MemIncr, 2, 0, 0},
+ { OP_MemIncr, 1, 2, 0},
{ OP_Next, 0, 0, 0}, /* 3 */
{ OP_MemLoad, 1, 0, 0},
{ OP_MemLoad, 2, 0, 0},
{ OP_Eq, 0, 0, 0}, /* 6 */
- { OP_MemIncr, 0, 0, 0},
+ { OP_MemIncr, 1, 0, 0},
{ OP_String8, 0, 0, "wrong # of entries in index "},
{ OP_String8, 0, 0, 0}, /* 9 */
{ OP_Concat, 0, 0, 0},
@@ -765,7 +780,7 @@ void sqlite3Pragma(
** useful if invoked immediately after the main database i
*/
if( sqlite3StrICmp(zLeft, "encoding")==0 ){
- static struct EncName {
+ static const struct EncName {
char *zName;
u8 enc;
} encnames[] = {
@@ -775,19 +790,18 @@ void sqlite3Pragma(
{ "UTF16le", SQLITE_UTF16LE },
{ "UTF-16be", SQLITE_UTF16BE },
{ "UTF16be", SQLITE_UTF16BE },
- { "UTF-16", 0 /* Filled in at run-time */ },
- { "UTF16", 0 /* Filled in at run-time */ },
+ { "UTF-16", 0 }, /* SQLITE_UTF16NATIVE */
+ { "UTF16", 0 }, /* SQLITE_UTF16NATIVE */
{ 0, 0 }
};
- struct EncName *pEnc;
- encnames[6].enc = encnames[7].enc = SQLITE_UTF16NATIVE;
+ const struct EncName *pEnc;
if( !zRight ){ /* "PRAGMA encoding" */
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, "encoding", P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "encoding", P3_STATIC);
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
- if( pEnc->enc==pParse->db->enc ){
+ if( pEnc->enc==ENC(pParse->db) ){
sqlite3VdbeChangeP3(v, -1, pEnc->zName, P3_STATIC);
break;
}
@@ -799,10 +813,13 @@ void sqlite3Pragma(
** will be overwritten when the schema is next loaded. If it does not
** already exists, it will be created to use the new encoding value.
*/
- if( !(pParse->db->flags&SQLITE_Initialized) ){
+ if(
+ !(DbHasProperty(db, 0, DB_SchemaLoaded)) ||
+ DbHasProperty(db, 0, DB_Empty)
+ ){
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
- pParse->db->enc = pEnc->enc;
+ ENC(pParse->db) = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
break;
}
}
@@ -887,8 +904,8 @@ void sqlite3Pragma(
int i;
Vdbe *v = sqlite3GetVdbe(pParse);
sqlite3VdbeSetNumCols(v, 2);
- sqlite3VdbeSetColName(v, 0, "database", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, "status", P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", P3_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", P3_STATIC);
for(i=0; i<db->nDb; i++){
Btree *pBt;
Pager *pPager;
@@ -918,6 +935,12 @@ void sqlite3Pragma(
}else
#endif
+#if SQLITE_HAS_CODEC
+ if( sqlite3StrICmp(zLeft, "key")==0 ){
+ sqlite3_key(db, zRight, strlen(zRight));
+ }else
+#endif
+
{}
if( v ){
@@ -926,6 +949,17 @@ void sqlite3Pragma(
** are only valid for a single execution.
*/
sqlite3VdbeAddOp(v, OP_Expire, 1, 0);
+
+ /*
+ ** Reset the safety level, in case the fullfsync flag or synchronous
+ ** setting changed.
+ */
+#ifndef SQLITE_OMIT_PAGER_PRAGMAS
+ if( db->autoCommit ){
+ sqlite3BtreeSetSafetyLevel(pDb->pBt, pDb->safety_level,
+ (db->flags&SQLITE_FullFSync)!=0);
+ }
+#endif
}
pragma_out:
sqliteFree(zLeft);
diff --git a/ext/pdo_sqlite/sqlite/src/prepare.c b/ext/pdo_sqlite/sqlite/src/prepare.c
index ad7c712789..0eae259889 100644
--- a/ext/pdo_sqlite/sqlite/src/prepare.c
+++ b/ext/pdo_sqlite/sqlite/src/prepare.c
@@ -24,10 +24,11 @@
** that the database is corrupt.
*/
static void corruptSchema(InitData *pData, const char *zExtra){
- if( !sqlite3_malloc_failed ){
+ if( !sqlite3MallocFailed() ){
sqlite3SetString(pData->pzErrMsg, "malformed database schema",
zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0);
}
+ pData->rc = SQLITE_CORRUPT;
}
/*
@@ -38,7 +39,7 @@ static void corruptSchema(InitData *pData, const char *zExtra){
** Each callback contains the following information:
**
** argv[0] = name of thing being created
-** argv[1] = root page number for table or index. NULL for trigger or view.
+** argv[1] = root page number for table or index. 0 for trigger or view.
** argv[2] = SQL text for the CREATE statement.
** argv[3] = "1" for temporary files, "0" for main database, "2" or more
** for auxiliary database files.
@@ -49,6 +50,12 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
sqlite3 *db = pData->db;
int iDb;
+ pData->rc = SQLITE_OK;
+ if( sqlite3MallocFailed() ){
+ corruptSchema(pData, 0);
+ return SQLITE_NOMEM;
+ }
+
assert( argc==4 );
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
if( argv[1]==0 || argv[3]==0 ){
@@ -70,10 +77,16 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
db->init.newTnum = atoi(argv[1]);
rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
db->init.iDb = 0;
+ assert( rc!=SQLITE_OK || zErr==0 );
if( SQLITE_OK!=rc ){
- corruptSchema(pData, zErr);
+ pData->rc = rc;
+ if( rc==SQLITE_NOMEM ){
+ sqlite3FailedMalloc();
+ }else if( rc!=SQLITE_INTERRUPT ){
+ corruptSchema(pData, zErr);
+ }
sqlite3_free(zErr);
- return rc;
+ return 1;
}
}else{
/* If the SQL column is blank it means this is an index that
@@ -111,6 +124,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
BtCursor *curMain;
int size;
Table *pTab;
+ Db *pDb;
char const *azArg[5];
char zDbNum[30];
int meta[10];
@@ -145,6 +159,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
#endif
assert( iDb>=0 && iDb<db->nDb );
+ assert( db->aDb[iDb].pSchema );
/* zMasterSchema and zInitScript are set to point at the master schema
** and initialisation script appropriate for the database being
@@ -168,9 +183,9 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
initData.db = db;
initData.pzErrMsg = pzErrMsg;
rc = sqlite3InitCallback(&initData, 4, (char **)azArg, 0);
- if( rc!=SQLITE_OK ){
+ if( rc ){
sqlite3SafetyOn(db);
- return rc;
+ return initData.rc;
}
pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName);
if( pTab ){
@@ -180,11 +195,14 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
/* Create a cursor to hold the database open
*/
- if( db->aDb[iDb].pBt==0 ){
- if( !OMIT_TEMPDB && iDb==1 ) DbSetProperty(db, 1, DB_SchemaLoaded);
+ pDb = &db->aDb[iDb];
+ if( pDb->pBt==0 ){
+ if( !OMIT_TEMPDB && iDb==1 ){
+ DbSetProperty(db, 1, DB_SchemaLoaded);
+ }
return SQLITE_OK;
}
- rc = sqlite3BtreeCursor(db->aDb[iDb].pBt, MASTER_ROOT, 0, 0, 0, &curMain);
+ rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, 0, &curMain);
if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){
sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
return rc;
@@ -197,20 +215,20 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
** meta[1] File format of schema layer.
** meta[2] Size of the page cache.
** meta[3] Use freelist if 0. Autovacuum if greater than zero.
- ** meta[4] Db text encoding. 1:UTF-8 3:UTF-16 LE 4:UTF-16 BE
+ ** meta[4] Db text encoding. 1:UTF-8 2:UTF-16LE 3:UTF-16BE
** meta[5] The user cookie. Used by the application.
** meta[6]
** meta[7]
** meta[8]
** meta[9]
**
- ** Note: The hash defined SQLITE_UTF* symbols in sqliteInt.h correspond to
+ ** Note: The #defined SQLITE_UTF* symbols in sqliteInt.h correspond to
** the possible values of meta[4].
*/
if( rc==SQLITE_OK ){
int i;
for(i=0; rc==SQLITE_OK && i<sizeof(meta)/sizeof(meta[0]); i++){
- rc = sqlite3BtreeGetMeta(db->aDb[iDb].pBt, i+1, (u32 *)&meta[i]);
+ rc = sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]);
}
if( rc ){
sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
@@ -220,7 +238,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
}else{
memset(meta, 0, sizeof(meta));
}
- db->aDb[iDb].schema_cookie = meta[0];
+ pDb->pSchema->schema_cookie = meta[0];
/* If opening a non-empty database, check the text encoding. For the
** main database, set sqlite3.enc to the encoding of the main database.
@@ -229,55 +247,44 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
*/
if( meta[4] ){ /* text encoding */
if( iDb==0 ){
- /* If opening the main database, set db->enc. */
- db->enc = (u8)meta[4];
- db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0);
+ /* If opening the main database, set ENC(db). */
+ ENC(db) = (u8)meta[4];
+ db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0);
}else{
- /* If opening an attached database, the encoding much match db->enc */
- if( meta[4]!=db->enc ){
+ /* If opening an attached database, the encoding much match ENC(db) */
+ if( meta[4]!=ENC(db) ){
sqlite3BtreeCloseCursor(curMain);
sqlite3SetString(pzErrMsg, "attached databases must use the same"
" text encoding as main database", (char*)0);
return SQLITE_ERROR;
}
}
+ }else{
+ DbSetProperty(db, iDb, DB_Empty);
}
+ pDb->pSchema->enc = ENC(db);
size = meta[2];
if( size==0 ){ size = MAX_PAGES; }
- db->aDb[iDb].cache_size = size;
-
- if( iDb==0 ){
- db->file_format = meta[1];
- if( db->file_format==0 ){
- /* This happens if the database was initially empty */
- db->file_format = 1;
- }
-
- if( db->file_format==2 || db->file_format==3 ){
- /* File format 2 is treated exactly as file format 1. New
- ** databases are created with file format 1.
- */
- db->file_format = 1;
- }
- }
+ pDb->pSchema->cache_size = size;
+ sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
/*
** file_format==1 Version 3.0.0.
- ** file_format==2 Version 3.1.3.
- ** file_format==3 Version 3.1.4.
- **
- ** 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.
- ** Version 3.1.4 can read and write file formats 1, 2 and 3.
+ ** file_format==2 Version 3.1.3. // ALTER TABLE ADD COLUMN
+ ** file_format==3 Version 3.1.4. // ditto but with non-NULL defaults
+ ** file_format==4 Version 3.3.0. // DESC indices. Boolean constants
*/
- if( meta[1]>3 ){
+ pDb->pSchema->file_format = meta[1];
+ if( pDb->pSchema->file_format==0 ){
+ pDb->pSchema->file_format = 1;
+ }
+ if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){
sqlite3BtreeCloseCursor(curMain);
sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0);
return SQLITE_ERROR;
}
- sqlite3BtreeSetCacheSize(db->aDb[iDb].pBt, db->aDb[iDb].cache_size);
/* Read the schema information out of the schema tables
*/
@@ -292,6 +299,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
zDbNum, db->aDb[iDb].zName, zMasterName);
sqlite3SafetyOff(db);
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
+ if( rc==SQLITE_ABORT ) rc = initData.rc;
sqlite3SafetyOn(db);
sqliteFree(zSql);
#ifndef SQLITE_OMIT_ANALYZE
@@ -301,8 +309,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
#endif
sqlite3BtreeCloseCursor(curMain);
}
- if( sqlite3_malloc_failed ){
- sqlite3SetString(pzErrMsg, "out of memory", (char*)0);
+ if( sqlite3MallocFailed() ){
+ /* sqlite3SetString(pzErrMsg, "out of memory", (char*)0); */
rc = SQLITE_NOMEM;
sqlite3ResetInternalSchema(db, 0);
}
@@ -320,14 +328,15 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
** created using ATTACH statements. Return a success code. If an
** error occurs, write an error message into *pzErrMsg.
**
-** After the database is initialized, the SQLITE_Initialized
-** bit is set in the flags field of the sqlite structure.
+** After a database is initialized, the DB_SchemaLoaded bit is set
+** bit is set in the flags field of the Db structure. If the database
+** file was of zero-length, then the DB_Empty flag is also set.
*/
int sqlite3Init(sqlite3 *db, char **pzErrMsg){
int i, rc;
+ int called_initone = 0;
if( db->init.busy ) return SQLITE_OK;
- assert( (db->flags & SQLITE_Initialized)==0 );
rc = SQLITE_OK;
db->init.busy = 1;
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
@@ -336,6 +345,7 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
if( rc ){
sqlite3ResetInternalSchema(db, i);
}
+ called_initone = 1;
}
/* Once all the other databases have been initialised, load the schema
@@ -348,19 +358,16 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
if( rc ){
sqlite3ResetInternalSchema(db, 1);
}
+ called_initone = 1;
}
#endif
db->init.busy = 0;
- if( rc==SQLITE_OK ){
- db->flags |= SQLITE_Initialized;
+ if( rc==SQLITE_OK && called_initone ){
sqlite3CommitInternalChanges(db);
}
- if( rc!=SQLITE_OK ){
- db->flags &= ~SQLITE_Initialized;
- }
- return rc;
+ return rc;
}
/*
@@ -371,11 +378,8 @@ int sqlite3ReadSchema(Parse *pParse){
int rc = SQLITE_OK;
sqlite3 *db = pParse->db;
if( !db->init.busy ){
- if( (db->flags & SQLITE_Initialized)==0 ){
- rc = sqlite3Init(db, &pParse->zErrMsg);
- }
+ rc = sqlite3Init(db, &pParse->zErrMsg);
}
- assert( rc!=SQLITE_OK || (db->flags & SQLITE_Initialized) || db->init.busy );
if( rc!=SQLITE_OK ){
pParse->rc = rc;
pParse->nErr++;
@@ -402,7 +406,7 @@ static int schemaIsValid(sqlite3 *db){
rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, 0, &curTemp);
if( rc==SQLITE_OK ){
rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie);
- if( rc==SQLITE_OK && cookie!=db->aDb[iDb].schema_cookie ){
+ if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){
allOk = 0;
}
sqlite3BtreeCloseCursor(curTemp);
@@ -412,6 +416,37 @@ static int schemaIsValid(sqlite3 *db){
}
/*
+** Convert a schema pointer into the iDb index that indicates
+** which database file in db->aDb[] the schema refers to.
+**
+** If the same database is attached more than once, the first
+** attached database is returned.
+*/
+int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
+ int i = -1000000;
+
+ /* If pSchema is NULL, then return -1000000. This happens when code in
+ ** expr.c is trying to resolve a reference to a transient table (i.e. one
+ ** created by a sub-select). In this case the return value of this
+ ** function should never be used.
+ **
+ ** We return -1000000 instead of the more usual -1 simply because using
+ ** -1000000 as incorrectly using -1000000 index into db->aDb[] is much
+ ** more likely to cause a segfault than -1 (of course there are assert()
+ ** statements too, but it never hurts to play the odds).
+ */
+ if( pSchema ){
+ for(i=0; i<db->nDb; i++){
+ if( db->aDb[i].pSchema==pSchema ){
+ break;
+ }
+ }
+ assert( i>=0 &&i>=0 && i<db->nDb );
+ }
+ return i;
+}
+
+/*
** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
*/
int sqlite3_prepare(
@@ -424,10 +459,10 @@ int sqlite3_prepare(
Parse sParse;
char *zErrMsg = 0;
int rc = SQLITE_OK;
+ int i;
- if( sqlite3_malloc_failed ){
- return SQLITE_NOMEM;
- }
+ /* Assert that malloc() has not failed */
+ assert( !sqlite3MallocFailed() );
assert( ppStmt );
*ppStmt = 0;
@@ -435,24 +470,43 @@ int sqlite3_prepare(
return SQLITE_MISUSE;
}
+ /* If any attached database schemas are locked, do not proceed with
+ ** compilation. Instead return SQLITE_LOCKED immediately.
+ */
+ for(i=0; i<db->nDb; i++) {
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt && sqlite3BtreeSchemaLocked(pBt) ){
+ const char *zDb = db->aDb[i].zName;
+ sqlite3Error(db, SQLITE_LOCKED, "database schema is locked: %s", zDb);
+ sqlite3SafetyOff(db);
+ return SQLITE_LOCKED;
+ }
+ }
+
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
- sqlite3RunParser(&sParse, zSql, &zErrMsg);
+ if( nBytes>=0 && zSql[nBytes]!=0 ){
+ char *zSqlCopy = sqlite3StrNDup(zSql, nBytes);
+ sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
+ sParse.zTail += zSql - zSqlCopy;
+ sqliteFree(zSqlCopy);
+ }else{
+ sqlite3RunParser(&sParse, zSql, &zErrMsg);
+ }
- if( sqlite3_malloc_failed ){
- rc = SQLITE_NOMEM;
- sqlite3RollbackAll(db);
- sqlite3ResetInternalSchema(db, 0);
- db->flags &= ~SQLITE_InTrans;
- goto prepare_out;
+ if( sqlite3MallocFailed() ){
+ sParse.rc = SQLITE_NOMEM;
}
if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
- if( sParse.rc!=SQLITE_OK && sParse.checkSchema && !schemaIsValid(db) ){
+ if( sParse.checkSchema && !schemaIsValid(db) ){
sParse.rc = SQLITE_SCHEMA;
}
if( sParse.rc==SQLITE_SCHEMA ){
sqlite3ResetInternalSchema(db, 0);
}
+ if( sqlite3MallocFailed() ){
+ sParse.rc = SQLITE_NOMEM;
+ }
if( pzTail ) *pzTail = sParse.zTail;
rc = sParse.rc;
@@ -460,21 +514,20 @@ int sqlite3_prepare(
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
if( sParse.explain==2 ){
sqlite3VdbeSetNumCols(sParse.pVdbe, 3);
- sqlite3VdbeSetColName(sParse.pVdbe, 0, "order", P3_STATIC);
- sqlite3VdbeSetColName(sParse.pVdbe, 1, "from", P3_STATIC);
- sqlite3VdbeSetColName(sParse.pVdbe, 2, "detail", P3_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "order", P3_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "from", P3_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "detail", P3_STATIC);
}else{
sqlite3VdbeSetNumCols(sParse.pVdbe, 5);
- sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC);
- sqlite3VdbeSetColName(sParse.pVdbe, 1, "opcode", P3_STATIC);
- sqlite3VdbeSetColName(sParse.pVdbe, 2, "p1", P3_STATIC);
- sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC);
- sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "addr", P3_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "opcode", P3_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "p1", P3_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 3, COLNAME_NAME, "p2", P3_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 4, COLNAME_NAME, "p3", P3_STATIC);
}
}
#endif
-prepare_out:
if( sqlite3SafetyOff(db) ){
rc = SQLITE_MISUSE;
}
@@ -490,6 +543,9 @@ prepare_out:
}else{
sqlite3Error(db, rc, 0);
}
+
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3ReleaseThreadData();
return rc;
}
@@ -508,22 +564,17 @@ int sqlite3_prepare16(
** encoded string to UTF-8, then invoking sqlite3_prepare(). The
** tricky bit is figuring out the pointer to return in *pzTail.
*/
- char const *zSql8 = 0;
- char const *zTail8 = 0;
- int rc;
- sqlite3_value *pTmp;
+ char *zSql8;
+ const char *zTail8 = 0;
+ int rc = SQLITE_OK;
if( sqlite3SafetyCheck(db) ){
return SQLITE_MISUSE;
}
- pTmp = sqlite3GetTransientValue(db);
- sqlite3ValueSetStr(pTmp, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
- zSql8 = sqlite3ValueText(pTmp, SQLITE_UTF8);
- if( !zSql8 ){
- sqlite3Error(db, SQLITE_NOMEM, 0);
- return SQLITE_NOMEM;
+ zSql8 = sqlite3utf16to8(zSql, nBytes);
+ if( zSql8 ){
+ rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8);
}
- rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8);
if( zTail8 && pzTail ){
/* If sqlite3_prepare returns a tail pointer, we calculate the
@@ -534,7 +585,7 @@ int sqlite3_prepare16(
int chars_parsed = sqlite3utf8CharLen(zSql8, zTail8-zSql8);
*pzTail = (u8 *)zSql + sqlite3utf16ByteLen(zSql, chars_parsed);
}
-
- return rc;
+ sqliteFree(zSql8);
+ return sqlite3ApiExit(db, rc);
}
#endif /* SQLITE_OMIT_UTF16 */
diff --git a/ext/pdo_sqlite/sqlite/src/printf.c b/ext/pdo_sqlite/sqlite/src/printf.c
index a669eb8d44..b4c37fb61d 100644
--- a/ext/pdo_sqlite/sqlite/src/printf.c
+++ b/ext/pdo_sqlite/sqlite/src/printf.c
@@ -65,15 +65,14 @@
#define etDYNSTRING 7 /* Dynamically allocated strings. %z */
#define etPERCENT 8 /* Percent symbol. %% */
#define etCHARX 9 /* Characters. %c */
-#define etERROR 10 /* Used to indicate no such conversion type */
/* The rest are extensions, not normally found in printf() */
-#define etCHARLIT 11 /* Literal characters. %' */
-#define etSQLESCAPE 12 /* Strings with '\'' doubled. %q */
-#define etSQLESCAPE2 13 /* Strings with '\'' doubled and enclosed in '',
+#define etCHARLIT 10 /* Literal characters. %' */
+#define etSQLESCAPE 11 /* Strings with '\'' doubled. %q */
+#define etSQLESCAPE2 12 /* Strings with '\'' doubled and enclosed in '',
NULL pointers replaced by SQL NULL. %Q */
-#define etTOKEN 14 /* a pointer to a Token structure */
-#define etSRCLIST 15 /* a pointer to a SrcList */
-#define etPOINTER 16 /* The %p conversion */
+#define etTOKEN 13 /* a pointer to a Token structure */
+#define etSRCLIST 14 /* a pointer to a SrcList */
+#define etPOINTER 15 /* The %p conversion */
/*
@@ -120,10 +119,12 @@ static const et_info fmtinfo[] = {
{ 'u', 10, 0, etRADIX, 0, 0 },
{ 'x', 16, 0, etRADIX, 16, 1 },
{ 'X', 16, 0, etRADIX, 0, 4 },
+#ifndef SQLITE_OMIT_FLOATING_POINT
{ 'f', 0, 1, etFLOAT, 0, 0 },
{ 'e', 0, 1, etEXP, 30, 0 },
{ 'E', 0, 1, etEXP, 14, 0 },
{ 'G', 0, 1, etGENERIC, 14, 0 },
+#endif
{ 'i', 10, 1, etRADIX, 0, 0 },
{ 'n', 0, 0, etSIZE, 0, 0 },
{ '%', 0, 0, etPERCENT, 0, 0 },
@@ -134,10 +135,10 @@ static const et_info fmtinfo[] = {
#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
/*
-** If NOFLOATINGPOINT is defined, then none of the floating point
+** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point
** conversions will work.
*/
-#ifndef etNOFLOATINGPOINT
+#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** "*val" is a double such that 0.1 <= *val < 10.0
** Return the ascii code for the leading digit of *val, then
@@ -161,7 +162,7 @@ static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
*val = (*val - d)*10.0;
return digit;
}
-#endif
+#endif /* SQLITE_OMIT_FLOATING_POINT */
/*
** On machines with a small stack size, you can redefine the
@@ -223,7 +224,7 @@ static int vxprintf(
etByte flag_long; /* True if "l" flag is present */
etByte flag_longlong; /* True if the "ll" flag is present */
etByte done; /* Loop termination flag */
- UINT64_TYPE longvalue; /* Value for integer types */
+ sqlite_uint64 longvalue; /* Value for integer types */
LONGDOUBLE_TYPE realvalue; /* Value for real types */
const et_info *infop; /* Pointer to the appropriate info structure */
char buf[etBUFSIZE]; /* Conversion buffer */
@@ -234,7 +235,7 @@ static int vxprintf(
static const char spaces[] =
" ";
#define etSPACESIZE (sizeof(spaces)-1)
-#ifndef etNOFLOATINGPOINT
+#ifndef SQLITE_OMIT_FLOATING_POINT
int exp, e2; /* exponent of real numbers */
double rounder; /* Used for rounding floating point values */
etByte flag_dp; /* True if decimal point should be shown */
@@ -327,17 +328,22 @@ static int vxprintf(
}
/* Fetch the info entry for the field */
infop = 0;
- xtype = etERROR;
for(idx=0; idx<etNINFO; idx++){
if( c==fmtinfo[idx].fmttype ){
infop = &fmtinfo[idx];
if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
xtype = infop->type;
+ }else{
+ return -1;
}
break;
}
}
zExtra = 0;
+ if( infop==0 ){
+ return -1;
+ }
+
/* Limit the precision to prevent overflowing buf[] during conversion */
if( precision>etBUFSIZE-40 && (infop->flags & FLAG_STRING)==0 ){
@@ -425,7 +431,7 @@ static int vxprintf(
case etEXP:
case etGENERIC:
realvalue = va_arg(ap,double);
-#ifndef etNOFLOATINGPOINT
+#ifndef SQLITE_OMIT_FLOATING_POINT
if( precision<0 ) precision = 6; /* Set default precision */
if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10;
if( realvalue<0.0 ){
@@ -442,7 +448,7 @@ static int vxprintf(
for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
#else
/* It makes more sense to use 0.5 */
- for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1);
+ for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1){}
#endif
if( xtype==etFLOAT ) realvalue += rounder;
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
@@ -594,13 +600,13 @@ static int vxprintf(
break;
case etSQLESCAPE:
case etSQLESCAPE2: {
- int i, j, n, c, isnull;
+ int i, j, n, ch, 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++;
+ char *escarg = va_arg(ap,char*);
+ isnull = escarg==0;
+ if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
+ for(i=n=0; (ch=escarg[i])!=0; i++){
+ if( ch=='\'' ) n++;
}
needQuote = !isnull && xtype==etSQLESCAPE2;
n += i + 1 + needQuote*2;
@@ -612,20 +618,21 @@ static int vxprintf(
}
j = 0;
if( needQuote ) bufpt[j++] = '\'';
- for(i=0; (c=arg[i])!=0; i++){
- bufpt[j++] = c;
- if( c=='\'' ) bufpt[j++] = c;
+ for(i=0; (ch=escarg[i])!=0; i++){
+ bufpt[j++] = ch;
+ if( ch=='\'' ) bufpt[j++] = ch;
}
if( needQuote ) bufpt[j++] = '\'';
bufpt[j] = 0;
length = j;
- if( precision>=0 && precision<length ) length = precision;
+ /* The precision is ignored on %q and %Q */
+ /* if( precision>=0 && precision<length ) length = precision; */
break;
}
case etTOKEN: {
Token *pToken = va_arg(ap, Token*);
if( pToken && pToken->z ){
- (*func)(arg, pToken->z, pToken->n);
+ (*func)(arg, (char*)pToken->z, pToken->n);
}
length = width = 0;
break;
@@ -643,15 +650,6 @@ static int vxprintf(
length = width = 0;
break;
}
- case etERROR:
- buf[0] = '%';
- buf[1] = c;
- errorflag = 0;
- idx = 1+(c!=0);
- (*func)(arg,"%",idx);
- count += idx;
- if( c==0 ) fmt--;
- break;
}/* End switch over the format type */
/*
** The text of the conversion is pointed to by "bufpt" and is
@@ -808,29 +806,28 @@ char *sqlite3MPrintf(const char *zFormat, ...){
}
/*
-** Print into memory obtained from malloc(). Do not use the internal
-** %-conversion extensions. This routine is for use by external users.
+** Print into memory obtained from sqlite3_malloc(). Omit the internal
+** %-conversion extensions.
+*/
+char *sqlite3_vmprintf(const char *zFormat, va_list ap){
+ char zBase[SQLITE_PRINT_BUF_SIZE];
+ return base_vprintf(sqlite3_realloc, 0, zBase, sizeof(zBase), zFormat, ap);
+}
+
+/*
+** Print into memory obtained from sqlite3_malloc()(). Omit the internal
+** %-conversion extensions.
*/
char *sqlite3_mprintf(const char *zFormat, ...){
va_list ap;
char *z;
- char zBuf[200];
-
- va_start(ap,zFormat);
- z = base_vprintf((void*(*)(void*,int))realloc, 0,
- zBuf, sizeof(zBuf), zFormat, ap);
+ char zBase[SQLITE_PRINT_BUF_SIZE];
+ va_start(ap, zFormat);
+ z = base_vprintf(sqlite3_realloc, 0, zBase, sizeof(zBase), zFormat, ap);
va_end(ap);
return z;
}
-/* This is the varargs version of sqlite3_mprintf.
-*/
-char *sqlite3_vmprintf(const char *zFormat, va_list ap){
- char zBuf[200];
- return base_vprintf((void*(*)(void*,int))realloc, 0,
- zBuf, sizeof(zBuf), zFormat, ap);
-}
-
/*
** sqlite3_snprintf() works like snprintf() except that it ignores the
** current locale settings. This is important for SQLite because we
diff --git a/ext/pdo_sqlite/sqlite/src/select.c b/ext/pdo_sqlite/sqlite/src/select.c
index 8a51208d79..57b415bf58 100644
--- a/ext/pdo_sqlite/sqlite/src/select.c
+++ b/ext/pdo_sqlite/sqlite/src/select.c
@@ -16,6 +16,21 @@
*/
#include "sqliteInt.h"
+/*
+** Delete all the content of a Select structure but do not deallocate
+** the select structure itself.
+*/
+static void clearSelect(Select *p){
+ sqlite3ExprListDelete(p->pEList);
+ sqlite3SrcListDelete(p->pSrc);
+ sqlite3ExprDelete(p->pWhere);
+ sqlite3ExprListDelete(p->pGroupBy);
+ sqlite3ExprDelete(p->pHaving);
+ sqlite3ExprListDelete(p->pOrderBy);
+ sqlite3SelectDelete(p->pPrior);
+ sqlite3ExprDelete(p->pLimit);
+ sqlite3ExprDelete(p->pOffset);
+}
/*
** Allocate a new Select structure and return a pointer to that
@@ -33,41 +48,49 @@ Select *sqlite3SelectNew(
Expr *pOffset /* OFFSET value. NULL means no offset */
){
Select *pNew;
+ Select standin;
pNew = sqliteMalloc( sizeof(*pNew) );
assert( !pOffset || pLimit ); /* Can't have OFFSET without LIMIT. */
if( pNew==0 ){
- sqlite3ExprListDelete(pEList);
- sqlite3SrcListDelete(pSrc);
- sqlite3ExprDelete(pWhere);
- sqlite3ExprListDelete(pGroupBy);
- sqlite3ExprDelete(pHaving);
- sqlite3ExprListDelete(pOrderBy);
- sqlite3ExprDelete(pLimit);
- sqlite3ExprDelete(pOffset);
- }else{
- if( pEList==0 ){
- pEList = sqlite3ExprListAppend(0, sqlite3Expr(TK_ALL,0,0,0), 0);
- }
- pNew->pEList = pEList;
- pNew->pSrc = pSrc;
- pNew->pWhere = pWhere;
- pNew->pGroupBy = pGroupBy;
- pNew->pHaving = pHaving;
- pNew->pOrderBy = pOrderBy;
- pNew->isDistinct = isDistinct;
- pNew->op = TK_SELECT;
- pNew->pLimit = pLimit;
- pNew->pOffset = pOffset;
- pNew->iLimit = -1;
- pNew->iOffset = -1;
- pNew->addrOpenVirt[0] = -1;
- pNew->addrOpenVirt[1] = -1;
- pNew->addrOpenVirt[2] = -1;
+ pNew = &standin;
+ memset(pNew, 0, sizeof(*pNew));
+ }
+ if( pEList==0 ){
+ pEList = sqlite3ExprListAppend(0, sqlite3Expr(TK_ALL,0,0,0), 0);
+ }
+ pNew->pEList = pEList;
+ pNew->pSrc = pSrc;
+ pNew->pWhere = pWhere;
+ pNew->pGroupBy = pGroupBy;
+ pNew->pHaving = pHaving;
+ pNew->pOrderBy = pOrderBy;
+ pNew->isDistinct = isDistinct;
+ pNew->op = TK_SELECT;
+ pNew->pLimit = pLimit;
+ pNew->pOffset = pOffset;
+ pNew->iLimit = -1;
+ pNew->iOffset = -1;
+ pNew->addrOpenEphm[0] = -1;
+ pNew->addrOpenEphm[1] = -1;
+ pNew->addrOpenEphm[2] = -1;
+ if( pNew==&standin) {
+ clearSelect(pNew);
+ pNew = 0;
}
return pNew;
}
/*
+** Delete the given Select structure and all of its substructures.
+*/
+void sqlite3SelectDelete(Select *p){
+ if( p ){
+ clearSelect(p);
+ sqliteFree(p);
+ }
+}
+
+/*
** Given 1 to 3 identifiers preceeding the JOIN keyword, determine the
** type of join. Return an integer constant that expresses that type
** in terms of the following bit values:
@@ -109,7 +132,7 @@ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
p = apAll[i];
for(j=0; j<sizeof(keywords)/sizeof(keywords[0]); j++){
if( p->n==keywords[j].nChar
- && sqlite3StrNICmp(p->z, keywords[j].zKeyword, p->n)==0 ){
+ && sqlite3StrNICmp((char*)p->z, keywords[j].zKeyword, p->n)==0 ){
jointype |= keywords[j].code;
break;
}
@@ -154,15 +177,15 @@ static int columnIndex(Table *pTab, const char *zCol){
** Set the value of a token to a '\000'-terminated string.
*/
static void setToken(Token *p, const char *z){
- p->z = z;
- p->n = strlen(z);
+ p->z = (u8*)z;
+ p->n = z ? strlen(z) : 0;
p->dyn = 0;
}
/*
** Create an expression node for an identifier with the name of zName
*/
-static Expr *createIdExpr(const char *zName){
+Expr *sqlite3CreateIdExpr(const char *zName){
Token dummy;
setToken(&dummy, zName);
return sqlite3Expr(TK_ID, 0, 0, &dummy);
@@ -186,22 +209,27 @@ static void addWhereTerm(
Expr *pE2a, *pE2b, *pE2c;
Expr *pE;
- pE1a = createIdExpr(zCol);
- pE2a = createIdExpr(zCol);
+ pE1a = sqlite3CreateIdExpr(zCol);
+ pE2a = sqlite3CreateIdExpr(zCol);
if( zAlias1==0 ){
zAlias1 = pTab1->zName;
}
- pE1b = createIdExpr(zAlias1);
+ pE1b = sqlite3CreateIdExpr(zAlias1);
if( zAlias2==0 ){
zAlias2 = pTab2->zName;
}
- pE2b = createIdExpr(zAlias2);
- pE1c = sqlite3Expr(TK_DOT, pE1b, pE1a, 0);
- pE2c = sqlite3Expr(TK_DOT, pE2b, pE2a, 0);
- pE = sqlite3Expr(TK_EQ, pE1c, pE2c, 0);
- ExprSetProperty(pE, EP_FromJoin);
- pE->iRightJoinTable = iRightJoinTable;
- *ppExpr = sqlite3ExprAnd(*ppExpr, pE);
+ pE2b = sqlite3CreateIdExpr(zAlias2);
+ pE1c = sqlite3ExprOrFree(TK_DOT, pE1b, pE1a, 0);
+ pE2c = sqlite3ExprOrFree(TK_DOT, pE2b, pE2a, 0);
+ pE = sqlite3ExprOrFree(TK_EQ, pE1c, pE2c, 0);
+ if( pE ){
+ ExprSetProperty(pE, EP_FromJoin);
+ pE->iRightJoinTable = iRightJoinTable;
+ }
+ pE = sqlite3ExprAnd(*ppExpr, pE);
+ if( pE ){
+ *ppExpr = pE;
+ }
}
/*
@@ -331,58 +359,52 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
}
/*
-** Delete the given Select structure and all of its substructures.
-*/
-void sqlite3SelectDelete(Select *p){
- if( p==0 ) return;
- sqlite3ExprListDelete(p->pEList);
- sqlite3SrcListDelete(p->pSrc);
- sqlite3ExprDelete(p->pWhere);
- sqlite3ExprListDelete(p->pGroupBy);
- sqlite3ExprDelete(p->pHaving);
- sqlite3ExprListDelete(p->pOrderBy);
- sqlite3SelectDelete(p->pPrior);
- sqlite3ExprDelete(p->pLimit);
- sqlite3ExprDelete(p->pOffset);
- sqliteFree(p);
-}
-
-/*
** Insert code into "v" that will push the record on the top of the
** stack into the sorter.
*/
-static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){
+static void pushOntoSorter(
+ Parse *pParse, /* Parser context */
+ ExprList *pOrderBy, /* The ORDER BY clause */
+ Select *pSelect /* The whole SELECT statement */
+){
+ Vdbe *v = pParse->pVdbe;
sqlite3ExprCodeExprList(pParse, pOrderBy);
sqlite3VdbeAddOp(v, OP_Sequence, pOrderBy->iECursor, 0);
sqlite3VdbeAddOp(v, OP_Pull, pOrderBy->nExpr + 1, 0);
sqlite3VdbeAddOp(v, OP_MakeRecord, pOrderBy->nExpr + 2, 0);
sqlite3VdbeAddOp(v, OP_IdxInsert, pOrderBy->iECursor, 0);
+ if( pSelect->iLimit>=0 ){
+ int addr1, addr2;
+ addr1 = sqlite3VdbeAddOp(v, OP_IfMemZero, pSelect->iLimit+1, 0);
+ sqlite3VdbeAddOp(v, OP_MemIncr, -1, pSelect->iLimit+1);
+ addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
+ sqlite3VdbeJumpHere(v, addr1);
+ sqlite3VdbeAddOp(v, OP_Last, pOrderBy->iECursor, 0);
+ sqlite3VdbeAddOp(v, OP_Delete, pOrderBy->iECursor, 0);
+ sqlite3VdbeJumpHere(v, addr2);
+ pSelect->iLimit = -1;
+ }
}
/*
-** Add code to implement the OFFSET and LIMIT
+** Add code to implement the OFFSET
*/
-static void codeLimiter(
+static void codeOffset(
Vdbe *v, /* Generate code into this VM */
Select *p, /* The SELECT statement being coded */
int iContinue, /* Jump here to skip the current record */
- int iBreak, /* Jump here to end the loop */
int nPop /* Number of times to pop stack when jumping */
){
if( p->iOffset>=0 && iContinue!=0 ){
- int addr = sqlite3VdbeCurrentAddr(v) + 3;
- if( nPop>0 ) addr++;
- sqlite3VdbeAddOp(v, OP_MemIncr, p->iOffset, 0);
- sqlite3VdbeAddOp(v, OP_IfMemPos, p->iOffset, addr);
+ int addr;
+ sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iOffset);
+ addr = sqlite3VdbeAddOp(v, OP_IfMemNeg, p->iOffset, 0);
if( nPop>0 ){
sqlite3VdbeAddOp(v, OP_Pop, nPop, 0);
}
sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue);
VdbeComment((v, "# skip OFFSET records"));
- }
- if( p->iLimit>=0 && iBreak!=0 ){
- sqlite3VdbeAddOp(v, OP_MemIncr, p->iLimit, iBreak);
- VdbeComment((v, "# exit when LIMIT reached"));
+ sqlite3VdbeJumpHere(v, addr);
}
}
@@ -392,22 +414,18 @@ static void codeLimiter(
** seen combinations of the N values. A new entry is made in iTab
** if the current N values are new.
**
-** A jump to addrRepeat is made and the K values are popped from the
+** A jump to addrRepeat is made and the N+1 values are popped from the
** stack if the top N elements are not distinct.
*/
static void codeDistinct(
Vdbe *v, /* Generate code into this VM */
int iTab, /* A sorting index used to test for distinctness */
int addrRepeat, /* Jump to here if not distinct */
- int N, /* The top N elements of the stack must be distinct */
- int K /* Pop K elements from the stack if indistinct */
+ int N /* The top N elements of the stack must be distinct */
){
-#if NULL_ALWAYS_DISTINCT
- sqlite3VdbeAddOp(v, OP_IsNull, -N, sqlite3VdbeCurrentAddr(v)+6);
-#endif
sqlite3VdbeAddOp(v, OP_MakeRecord, -N, 0);
sqlite3VdbeAddOp(v, OP_Distinct, iTab, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Pop, K, 0);
+ sqlite3VdbeAddOp(v, OP_Pop, N+1, 0);
sqlite3VdbeAddOp(v, OP_Goto, 0, addrRepeat);
VdbeComment((v, "# skip indistinct records"));
sqlite3VdbeAddOp(v, OP_IdxInsert, iTab, 0);
@@ -447,9 +465,9 @@ static int selectInnerLoop(
/* If there was a LIMIT clause on the SELECT statement, then do the check
** to see if this row should be output.
*/
- hasDistinct = distinct>=0 && pEList && pEList->nExpr>0;
+ hasDistinct = distinct>=0 && pEList->nExpr>0;
if( pOrderBy==0 && !hasDistinct ){
- codeLimiter(v, p, iContinue, iBreak, 0);
+ codeOffset(v, p, iContinue, 0);
}
/* Pull the requested columns.
@@ -468,10 +486,11 @@ static int selectInnerLoop(
** part of the result.
*/
if( hasDistinct ){
- int n = pEList->nExpr;
- codeDistinct(v, distinct, iContinue, n, n+1);
+ assert( pEList!=0 );
+ assert( pEList->nExpr==nColumn );
+ codeDistinct(v, distinct, iContinue, nColumn);
if( pOrderBy==0 ){
- codeLimiter(v, p, iContinue, iBreak, nColumn);
+ codeOffset(v, p, iContinue, nColumn);
}
}
@@ -481,7 +500,7 @@ static int selectInnerLoop(
*/
#ifndef SQLITE_OMIT_COMPOUND_SELECT
case SRT_Union: {
- sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT);
+ sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
if( aff ){
sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC);
}
@@ -495,7 +514,7 @@ static int selectInnerLoop(
*/
case SRT_Except: {
int addr;
- addr = sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT);
+ addr = sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC);
sqlite3VdbeAddOp(v, OP_NotFound, iParm, addr+3);
sqlite3VdbeAddOp(v, OP_Delete, iParm, 0);
@@ -506,10 +525,10 @@ static int selectInnerLoop(
/* Store the result as data using a unique key.
*/
case SRT_Table:
- case SRT_VirtualTab: {
+ case SRT_EphemTab: {
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
if( pOrderBy ){
- pushOntoSorter(pParse, v, pOrderBy);
+ pushOntoSorter(pParse, pOrderBy, p);
}else{
sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0);
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
@@ -536,29 +555,37 @@ static int selectInnerLoop(
** ORDER BY in this case since the order of entries in the set
** does not matter. But there might be a LIMIT clause, in which
** case the order does matter */
- pushOntoSorter(pParse, v, pOrderBy);
+ pushOntoSorter(pParse, pOrderBy, p);
}else{
- char aff = (iParm>>16)&0xFF;
- aff = sqlite3CompareAffinity(pEList->a[0].pExpr, aff);
- sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &aff, 1);
+ char affinity = (iParm>>16)&0xFF;
+ affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, affinity);
+ sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1);
sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0);
}
sqlite3VdbeJumpHere(v, addr2);
break;
}
+ /* If any row exist in the result set, record that fact and abort.
+ */
+ case SRT_Exists: {
+ sqlite3VdbeAddOp(v, OP_MemInt, 1, iParm);
+ sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0);
+ /* The LIMIT clause will terminate the loop for us */
+ break;
+ }
+
/* If this is a scalar select that is part of an expression, then
** store the results in the appropriate memory cell and break out
** of the scan loop.
*/
- case SRT_Exists:
case SRT_Mem: {
assert( nColumn==1 );
if( pOrderBy ){
- pushOntoSorter(pParse, v, pOrderBy);
+ pushOntoSorter(pParse, pOrderBy, p);
}else{
sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1);
- sqlite3VdbeAddOp(v, OP_Goto, 0, iBreak);
+ /* The LIMIT clause will jump out of the loop for us */
}
break;
}
@@ -572,7 +599,7 @@ static int selectInnerLoop(
case SRT_Callback: {
if( pOrderBy ){
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
- pushOntoSorter(pParse, v, pOrderBy);
+ pushOntoSorter(pParse, pOrderBy, p);
}else if( eDest==SRT_Subroutine ){
sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm);
}else{
@@ -594,6 +621,13 @@ static int selectInnerLoop(
}
#endif
}
+
+ /* Jump to the end of the loop if the LIMIT is reached.
+ */
+ if( p->iLimit>=0 && pOrderBy==0 ){
+ sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit);
+ sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, iBreak);
+ }
return 0;
}
@@ -622,9 +656,9 @@ static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){
nExpr = pList->nExpr;
pInfo = sqliteMalloc( sizeof(*pInfo) + nExpr*(sizeof(CollSeq*)+1) );
if( pInfo ){
- pInfo->aSortOrder = (char*)&pInfo->aColl[nExpr];
+ pInfo->aSortOrder = (u8*)&pInfo->aColl[nExpr];
pInfo->nField = nExpr;
- pInfo->enc = db->enc;
+ pInfo->enc = ENC(db);
for(i=0, pItem=pList->a; i<nExpr; i++, pItem++){
CollSeq *pColl;
pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
@@ -646,7 +680,7 @@ static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){
** routine generates the code needed to do that.
*/
static void generateSortTail(
- Parse *pParse, /* The parsing context */
+ Parse *pParse, /* Parsing context */
Select *p, /* The SELECT statement */
Vdbe *v, /* Generate code into this VDBE */
int nColumn, /* Number of columns of data */
@@ -657,15 +691,24 @@ static void generateSortTail(
int cont = sqlite3VdbeMakeLabel(v);
int addr;
int iTab;
+ int pseudoTab;
ExprList *pOrderBy = p->pOrderBy;
iTab = pOrderBy->iECursor;
+ if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
+ pseudoTab = pParse->nTab++;
+ sqlite3VdbeAddOp(v, OP_OpenPseudo, pseudoTab, 0);
+ sqlite3VdbeAddOp(v, OP_SetNumColumns, pseudoTab, nColumn);
+ }
addr = 1 + sqlite3VdbeAddOp(v, OP_Sort, iTab, brk);
- codeLimiter(v, p, cont, brk, 0);
+ codeOffset(v, p, cont, 0);
+ if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
+ sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
+ }
sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr + 1);
switch( eDest ){
case SRT_Table:
- case SRT_VirtualTab: {
+ case SRT_EphemTab: {
sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0);
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
sqlite3VdbeAddOp(v, OP_Insert, iParm, 0);
@@ -677,32 +720,29 @@ static void generateSortTail(
sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
sqlite3VdbeAddOp(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, "n", P3_STATIC);
+ sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, "c", P3_STATIC);
sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0);
break;
}
- case SRT_Exists:
case SRT_Mem: {
assert( nColumn==1 );
sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1);
- sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
+ /* The LIMIT clause will terminate the loop for us */
break;
}
#endif
case SRT_Callback:
case SRT_Subroutine: {
int i;
- sqlite3VdbeAddOp(v, OP_Integer, p->pEList->nExpr, 0);
- sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
+ sqlite3VdbeAddOp(v, OP_Insert, pseudoTab, 0);
for(i=0; i<nColumn; i++){
- sqlite3VdbeAddOp(v, OP_Column, -1-i, i);
+ sqlite3VdbeAddOp(v, OP_Column, pseudoTab, i);
}
if( eDest==SRT_Callback ){
sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0);
}else{
sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm);
}
- sqlite3VdbeAddOp(v, OP_Pop, 2, 0);
break;
}
default: {
@@ -710,23 +750,54 @@ static void generateSortTail(
break;
}
}
+
+ /* Jump to the end of the loop when the LIMIT is reached
+ */
+ if( p->iLimit>=0 ){
+ sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit);
+ sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, brk);
+ }
+
+ /* The bottom of the loop
+ */
sqlite3VdbeResolveLabel(v, cont);
sqlite3VdbeAddOp(v, OP_Next, iTab, addr);
sqlite3VdbeResolveLabel(v, brk);
+ if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
+ sqlite3VdbeAddOp(v, OP_Close, pseudoTab, 0);
+ }
+
}
/*
** Return a pointer to a string containing the 'declaration type' of the
** expression pExpr. The string may be treated as static by the caller.
**
-** If the declaration type is the exact datatype definition extracted from
-** the original CREATE TABLE statement if the expression is a column.
+** The declaration type is the exact datatype definition extracted from the
+** original CREATE TABLE statement if the expression is a column. The
+** declaration type for a ROWID field is INTEGER. Exactly when an expression
+** is considered a column can be complex in the presence of subqueries. The
+** result-set expression in all of the following SELECT statements is
+** considered a column by this function.
+**
+** SELECT col FROM tbl;
+** SELECT (SELECT col FROM tbl;
+** SELECT (SELECT col FROM tbl);
+** SELECT abc FROM (SELECT col AS abc FROM tbl);
**
-** The declaration type for an expression is either TEXT, NUMERIC or ANY.
-** The declaration type for a ROWID field is INTEGER.
+** The declaration type for any expression other than a column is NULL.
*/
-static const char *columnType(NameContext *pNC, Expr *pExpr){
- char const *zType;
+static const char *columnType(
+ NameContext *pNC,
+ Expr *pExpr,
+ const char **pzOriginDb,
+ const char **pzOriginTab,
+ const char **pzOriginCol
+){
+ char const *zType = 0;
+ char const *zOriginDb = 0;
+ char const *zOriginTab = 0;
+ char const *zOriginCol = 0;
int j;
if( pExpr==0 || pNC->pSrcList==0 ) return 0;
@@ -737,18 +808,26 @@ static const char *columnType(NameContext *pNC, Expr *pExpr){
assert( pExpr->op!=TK_AS );
switch( pExpr->op ){
+ case TK_AGG_COLUMN:
case TK_COLUMN: {
- Table *pTab = 0;
- int iCol = pExpr->iColumn;
+ /* The expression is a column. Locate the table the column is being
+ ** extracted from in NameContext.pSrcList. This table may be real
+ ** database table or a subquery.
+ */
+ Table *pTab = 0; /* Table structure column is extracted from */
+ Select *pS = 0; /* Select the column is extracted from */
+ int iCol = pExpr->iColumn; /* Index of column in pTab */
while( pNC && !pTab ){
SrcList *pTabList = pNC->pSrcList;
for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
if( j<pTabList->nSrc ){
pTab = pTabList->a[j].pTab;
+ pS = pTabList->a[j].pSelect;
}else{
pNC = pNC->pNext;
}
}
+
if( pTab==0 ){
/* FIX ME:
** This can occurs if you have something like "SELECT new.x;" inside
@@ -763,30 +842,69 @@ static const char *columnType(NameContext *pNC, Expr *pExpr){
zType = "TEXT";
break;
}
+
assert( pTab );
- if( iCol<0 ) iCol = pTab->iPKey;
- assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
- if( iCol<0 ){
- zType = "INTEGER";
- }else{
- zType = pTab->aCol[iCol].zType;
+ if( pS ){
+ /* The "table" is actually a sub-select or a view in the FROM clause
+ ** of the SELECT statement. Return the declaration type and origin
+ ** data for the result-set column of the sub-select.
+ */
+ if( iCol>=0 && iCol<pS->pEList->nExpr ){
+ /* If iCol is less than zero, then the expression requests the
+ ** rowid of the sub-select or view. This expression is legal (see
+ ** test case misc2.2.2) - it always evaluates to NULL.
+ */
+ NameContext sNC;
+ Expr *p = pS->pEList->a[iCol].pExpr;
+ sNC.pSrcList = pS->pSrc;
+ sNC.pNext = 0;
+ sNC.pParse = pNC->pParse;
+ zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol);
+ }
+ }else if( pTab->pSchema ){
+ /* A real table */
+ assert( !pS );
+ if( iCol<0 ) iCol = pTab->iPKey;
+ assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
+ if( iCol<0 ){
+ zType = "INTEGER";
+ zOriginCol = "rowid";
+ }else{
+ zType = pTab->aCol[iCol].zType;
+ zOriginCol = pTab->aCol[iCol].zName;
+ }
+ zOriginTab = pTab->zName;
+ if( pNC->pParse ){
+ int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
+ zOriginDb = pNC->pParse->db->aDb[iDb].zName;
+ }
}
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
case TK_SELECT: {
+ /* The expression is a sub-select. Return the declaration type and
+ ** origin info for the single column in the result set of the SELECT
+ ** statement.
+ */
NameContext sNC;
Select *pS = pExpr->pSelect;
- sNC.pSrcList = pExpr->pSelect->pSrc;
+ Expr *p = pS->pEList->a[0].pExpr;
+ sNC.pSrcList = pS->pSrc;
sNC.pNext = pNC;
- zType = columnType(&sNC, pS->pEList->a[0].pExpr);
+ sNC.pParse = pNC->pParse;
+ zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol);
break;
}
#endif
- default:
- zType = 0;
}
+ if( pzOriginDb ){
+ assert( pzOriginTab && pzOriginCol );
+ *pzOriginDb = zOriginDb;
+ *pzOriginTab = zOriginTab;
+ *pzOriginCol = zOriginCol;
+ }
return zType;
}
@@ -803,14 +921,22 @@ static void generateColumnTypes(
int i;
NameContext sNC;
sNC.pSrcList = pTabList;
+ sNC.pParse = pParse;
for(i=0; i<pEList->nExpr; i++){
Expr *p = pEList->a[i].pExpr;
- const char *zType = columnType(&sNC, p);
- if( zType==0 ) continue;
- /* The vdbe must make it's own copy of the column-type, in case the
- ** schema is reset before this virtual machine is deleted.
+ const char *zOrigDb = 0;
+ const char *zOrigTab = 0;
+ const char *zOrigCol = 0;
+ const char *zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
+
+ /* The vdbe must make it's own copy of the column-type and other
+ ** column specific strings, in case the schema is reset before this
+ ** virtual machine is deleted.
*/
- sqlite3VdbeSetColName(v, i+pEList->nExpr, zType, strlen(zType));
+ sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, P3_TRANSIENT);
+ sqlite3VdbeSetColName(v, i, COLNAME_DATABASE, zOrigDb, P3_TRANSIENT);
+ sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, P3_TRANSIENT);
+ sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, P3_TRANSIENT);
}
}
@@ -837,7 +963,7 @@ static void generateColumnNames(
#endif
assert( v!=0 );
- if( pParse->colNamesSet || v==0 || sqlite3_malloc_failed ) return;
+ if( pParse->colNamesSet || v==0 || sqlite3MallocFailed() ) return;
pParse->colNamesSet = 1;
fullNames = (db->flags & SQLITE_FullColNames)!=0;
shortNames = (db->flags & SQLITE_ShortColNames)!=0;
@@ -848,7 +974,7 @@ static void generateColumnNames(
if( p==0 ) continue;
if( pEList->a[i].zName ){
char *zName = pEList->a[i].zName;
- sqlite3VdbeSetColName(v, i, zName, strlen(zName));
+ sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, strlen(zName));
continue;
}
if( p->op==TK_COLUMN && pTabList ){
@@ -866,26 +992,26 @@ static void generateColumnNames(
zCol = pTab->aCol[iCol].zName;
}
if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){
- sqlite3VdbeSetColName(v, i, p->span.z, p->span.n);
+ sqlite3VdbeSetColName(v, i, COLNAME_NAME, (char*)p->span.z, p->span.n);
}else if( fullNames || (!shortNames && pTabList->nSrc>1) ){
char *zName = 0;
char *zTab;
zTab = pTabList->a[j].zAlias;
if( fullNames || zTab==0 ) zTab = pTab->zName;
- sqlite3SetString(&zName, zTab, ".", zCol, 0);
- sqlite3VdbeSetColName(v, i, zName, P3_DYNAMIC);
+ sqlite3SetString(&zName, zTab, ".", zCol, (char*)0);
+ sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, P3_DYNAMIC);
}else{
- sqlite3VdbeSetColName(v, i, zCol, strlen(zCol));
+ sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, strlen(zCol));
}
}else if( p->span.z && p->span.z[0] ){
- sqlite3VdbeSetColName(v, i, p->span.z, p->span.n);
+ sqlite3VdbeSetColName(v, i, COLNAME_NAME, (char*)p->span.z, p->span.n);
/* sqlite3VdbeCompressSpace(v, addr); */
}else{
char zName[30];
assert( p->op!=TK_COLUMN || pTabList==0 );
sprintf(zName, "column%d", i+1);
- sqlite3VdbeSetColName(v, i, zName, 0);
+ sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, 0);
}
}
generateColumnTypes(pParse, pTabList, pEList);
@@ -922,6 +1048,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
ExprList *pEList;
Column *aCol, *pCol;
+ while( pSelect->pPrior ) pSelect = pSelect->pPrior;
if( prepSelectStmt(pParse, pSelect) ){
return 0;
}
@@ -943,6 +1070,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
char *zType;
char *zName;
char *zBasename;
+ CollSeq *pColl;
int cnt;
NameContext sNC;
@@ -965,7 +1093,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
zName = sqlite3MPrintf("column%d", i+1);
}
sqlite3Dequote(zName);
- if( sqlite3_malloc_failed ){
+ if( sqlite3MallocFailed() ){
sqliteFree(zName);
sqlite3DeleteTable(0, pTab);
return 0;
@@ -992,12 +1120,12 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
*/
memset(&sNC, 0, sizeof(sNC));
sNC.pSrcList = pSelect->pSrc;
- zType = sqliteStrDup(columnType(&sNC, p));
+ zType = sqliteStrDup(columnType(&sNC, p, 0, 0, 0));
pCol->zType = zType;
pCol->affinity = sqlite3ExprAffinity(p);
- pCol->pColl = sqlite3ExprCollSeq(pParse, p);
- if( !pCol->pColl ){
- pCol->pColl = pParse->db->pDfltColl;
+ pColl = sqlite3ExprCollSeq(pParse, p);
+ if( pColl ){
+ pCol->zColl = sqliteStrDup(pColl->zName);
}
}
pTab->iPKey = -1;
@@ -1034,10 +1162,11 @@ static int prepSelectStmt(Parse *pParse, Select *p){
int i, j, k, rc;
SrcList *pTabList;
ExprList *pEList;
- Table *pTab;
struct SrcList_item *pFrom;
- if( p==0 || p->pSrc==0 || sqlite3_malloc_failed ) return 1;
+ if( p==0 || p->pSrc==0 || sqlite3MallocFailed() ){
+ return 1;
+ }
pTabList = p->pSrc;
pEList = p->pEList;
@@ -1051,6 +1180,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){
** then create a transient table structure to describe the subquery.
*/
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
+ Table *pTab;
if( pFrom->pTab!=0 ){
/* This statement has already been prepared. There is no need
** to go further. */
@@ -1071,11 +1201,11 @@ static int prepSelectStmt(Parse *pParse, Select *p){
if( pTab==0 ){
return 1;
}
- /* The isTransient flag indicates that the Table structure has been
+ /* The isEphem flag indicates that the Table structure has been
** dynamically allocated and may be freed at any time. In other words,
** pTab is not pointing to a persistent table structure that defines
** part of the schema. */
- pTab->isTransient = 1;
+ pTab->isEphem = 1;
#endif
}else{
/* An ordinary table or view name in the FROM clause */
@@ -1086,8 +1216,8 @@ static int prepSelectStmt(Parse *pParse, Select *p){
return 1;
}
pTab->nRef++;
-#ifndef SQLITE_OMIT_VIEW
- if( pTab->pSelect ){
+#if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
+ if( pTab->pSelect || IsVirtual(pTab) ){
/* We reach here if the named table is a really a view */
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
return 1;
@@ -1145,7 +1275,11 @@ static int prepSelectStmt(Parse *pParse, Select *p){
/* This particular expression does not need to be expanded.
*/
pNew = sqlite3ExprListAppend(pNew, a[k].pExpr, 0);
- pNew->a[pNew->nExpr-1].zName = a[k].zName;
+ if( pNew ){
+ pNew->a[pNew->nExpr-1].zName = a[k].zName;
+ }else{
+ rc = 1;
+ }
a[k].pExpr = 0;
a[k].zName = 0;
}else{
@@ -1170,7 +1304,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){
}
tableSeen = 1;
for(j=0; j<pTab->nCol; j++){
- Expr *pExpr, *pLeft, *pRight;
+ Expr *pExpr, *pRight;
char *zName = pTab->aCol[j].zName;
if( i>0 ){
@@ -1191,7 +1325,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){
if( pRight==0 ) break;
setToken(&pRight->token, zName);
if( zTabName && (longNames || pTabList->nSrc>1) ){
- pLeft = sqlite3Expr(TK_ID, 0, 0, 0);
+ Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, 0);
pExpr = sqlite3Expr(TK_DOT, pLeft, pRight, 0);
if( pExpr==0 ) break;
setToken(&pLeft->token, zTabName);
@@ -1326,25 +1460,31 @@ Vdbe *sqlite3GetVdbe(Parse *pParse){
return v;
}
+
/*
** Compute the iLimit and iOffset fields of the SELECT based on the
-** pLimit and pOffset expressions. nLimit and nOffset hold the expressions
+** pLimit and pOffset expressions. pLimit and pOffset hold the expressions
** that appear in the original SQL statement after the LIMIT and OFFSET
** keywords. Or NULL if those keywords are omitted. iLimit and iOffset
** are the integer memory register numbers for counters used to compute
** the limit and offset. If there is no limit and/or offset, then
** iLimit and iOffset are negative.
**
-** This routine changes the values if iLimit and iOffset only if
-** a limit or offset is defined by nLimit and nOffset. iLimit and
+** This routine changes the values of iLimit and iOffset only if
+** a limit or offset is defined by pLimit and pOffset. iLimit and
** iOffset should have been preset to appropriate default values
** (usually but not always -1) prior to calling this routine.
-** Only if nLimit>=0 or nOffset>0 do the limit registers get
+** Only if pLimit!=0 or pOffset!=0 do the limit registers get
** redefined. The UNION ALL operator uses this property to force
** the reuse of the same limit and offset registers across multiple
** SELECT statements.
*/
-static void computeLimitRegisters(Parse *pParse, Select *p){
+static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
+ Vdbe *v = 0;
+ int iLimit = 0;
+ int iOffset;
+ int addr1, addr2;
+
/*
** "LIMIT -1" always shows all rows. There is some
** contraversy about what the correct behavior should be.
@@ -1352,26 +1492,41 @@ static void computeLimitRegisters(Parse *pParse, Select *p){
** no rows.
*/
if( p->pLimit ){
- int iMem = pParse->nMem++;
- Vdbe *v = sqlite3GetVdbe(pParse);
+ p->iLimit = iLimit = pParse->nMem;
+ pParse->nMem += 2;
+ v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
sqlite3ExprCode(pParse, p->pLimit);
sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
- sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1);
+ sqlite3VdbeAddOp(v, OP_MemStore, iLimit, 0);
VdbeComment((v, "# LIMIT counter"));
- p->iLimit = iMem;
+ sqlite3VdbeAddOp(v, OP_IfMemZero, iLimit, iBreak);
}
if( p->pOffset ){
- int iMem = pParse->nMem++;
- Vdbe *v = sqlite3GetVdbe(pParse);
+ p->iOffset = iOffset = pParse->nMem++;
+ v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
sqlite3ExprCode(pParse, p->pOffset);
sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
- sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1);
+ sqlite3VdbeAddOp(v, OP_MemStore, iOffset, p->pLimit==0);
VdbeComment((v, "# OFFSET counter"));
- p->iOffset = iMem;
+ addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iOffset, 0);
+ sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
+ sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
+ sqlite3VdbeJumpHere(v, addr1);
+ if( p->pLimit ){
+ sqlite3VdbeAddOp(v, OP_Add, 0, 0);
+ }
+ }
+ if( p->pLimit ){
+ addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iLimit, 0);
+ sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
+ sqlite3VdbeAddOp(v, OP_MemInt, -1, iLimit+1);
+ addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
+ sqlite3VdbeJumpHere(v, addr1);
+ sqlite3VdbeAddOp(v, OP_MemStore, iLimit+1, 1);
+ VdbeComment((v, "# LIMIT+OFFSET"));
+ sqlite3VdbeJumpHere(v, addr2);
}
}
@@ -1383,27 +1538,13 @@ static void createSortingIndex(Parse *pParse, Select *p, ExprList *pOrderBy){
int addr;
assert( pOrderBy->iECursor==0 );
pOrderBy->iECursor = pParse->nTab++;
- addr = sqlite3VdbeAddOp(pParse->pVdbe, OP_OpenVirtual,
+ addr = sqlite3VdbeAddOp(pParse->pVdbe, OP_OpenEphemeral,
pOrderBy->iECursor, pOrderBy->nExpr+1);
- assert( p->addrOpenVirt[2] == -1 );
- p->addrOpenVirt[2] = addr;
+ assert( p->addrOpenEphm[2] == -1 );
+ p->addrOpenEphm[2] = addr;
}
}
-/*
-** The opcode at addr is an OP_OpenVirtual that created a sorting
-** index tha we ended up not needing. This routine changes that
-** opcode to OP_Noop.
-*/
-static void uncreateSortingIndex(Parse *pParse, int addr){
- Vdbe *v = pParse->pVdbe;
- VdbeOp *pOp = sqlite3VdbeGetOp(v, addr);
- sqlite3VdbeChangeP3(v, addr, 0, 0);
- pOp->opcode = OP_Noop;
- pOp->p1 = 0;
- pOp->p2 = 0;
-}
-
#ifndef SQLITE_OMIT_COMPOUND_SELECT
/*
** Return the appropriate collating sequence for the iCol-th column of
@@ -1506,10 +1647,10 @@ static int multiSelect(
/* Create the destination temporary table if necessary
*/
- if( eDest==SRT_VirtualTab ){
+ if( eDest==SRT_EphemTab ){
assert( p->pEList );
assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) );
- aSetP2[nSetP2++] = sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 0);
+ aSetP2[nSetP2++] = sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, 0);
eDest = SRT_Table;
}
@@ -1519,23 +1660,31 @@ static int multiSelect(
switch( p->op ){
case TK_ALL: {
if( pOrderBy==0 ){
+ int addr = 0;
assert( !pPrior->pLimit );
pPrior->pLimit = p->pLimit;
pPrior->pOffset = p->pOffset;
rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff);
+ p->pLimit = 0;
+ p->pOffset = 0;
if( rc ){
goto multi_select_end;
}
p->pPrior = 0;
p->iLimit = pPrior->iLimit;
p->iOffset = pPrior->iOffset;
- p->pLimit = 0;
- p->pOffset = 0;
+ if( p->iLimit>=0 ){
+ addr = sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, 0);
+ VdbeComment((v, "# Jump ahead if LIMIT reached"));
+ }
rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff);
p->pPrior = pPrior;
if( rc ){
goto multi_select_end;
}
+ if( addr ){
+ sqlite3VdbeJumpHere(v, addr);
+ }
break;
}
/* For UNION ALL ... ORDER BY fall through to the next case */
@@ -1563,14 +1712,14 @@ static int multiSelect(
rc = 1;
goto multi_select_end;
}
- addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, unionTab, 0);
+ addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, unionTab, 0);
if( priorOp==SRT_Table ){
assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) );
aSetP2[nSetP2++] = addr;
}else{
- assert( p->addrOpenVirt[0] == -1 );
- p->addrOpenVirt[0] = addr;
- p->pRightmost->usesVirt = 1;
+ assert( p->addrOpenEphm[0] == -1 );
+ p->addrOpenEphm[0] = addr;
+ p->pRightmost->usesEphm = 1;
}
createSortingIndex(pParse, p, pOrderBy);
assert( p->pEList );
@@ -1618,12 +1767,14 @@ static int multiSelect(
int iCont, iBreak, iStart;
assert( p->pEList );
if( eDest==SRT_Callback ){
- generateColumnNames(pParse, 0, p->pEList);
+ Select *pFirst = p;
+ while( pFirst->pPrior ) pFirst = pFirst->pPrior;
+ generateColumnNames(pParse, 0, pFirst->pEList);
}
iBreak = sqlite3VdbeMakeLabel(v);
iCont = sqlite3VdbeMakeLabel(v);
+ computeLimitRegisters(pParse, p, iBreak);
sqlite3VdbeAddOp(v, OP_Rewind, unionTab, iBreak);
- computeLimitRegisters(pParse, p);
iStart = sqlite3VdbeCurrentAddr(v);
rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,
pOrderBy, -1, eDest, iParm,
@@ -1657,10 +1808,10 @@ static int multiSelect(
}
createSortingIndex(pParse, p, pOrderBy);
- addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab1, 0);
- assert( p->addrOpenVirt[0] == -1 );
- p->addrOpenVirt[0] = addr;
- p->pRightmost->usesVirt = 1;
+ addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, tab1, 0);
+ assert( p->addrOpenEphm[0] == -1 );
+ p->addrOpenEphm[0] = addr;
+ p->pRightmost->usesEphm = 1;
assert( p->pEList );
/* Code the SELECTs to our left into temporary table "tab1".
@@ -1672,9 +1823,9 @@ static int multiSelect(
/* Code the current SELECT into temporary table "tab2"
*/
- addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab2, 0);
- assert( p->addrOpenVirt[1] == -1 );
- p->addrOpenVirt[1] = addr;
+ addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, tab2, 0);
+ assert( p->addrOpenEphm[1] == -1 );
+ p->addrOpenEphm[1] = addr;
p->pPrior = 0;
pLimit = p->pLimit;
p->pLimit = 0;
@@ -1694,12 +1845,14 @@ static int multiSelect(
*/
assert( p->pEList );
if( eDest==SRT_Callback ){
- generateColumnNames(pParse, 0, p->pEList);
+ Select *pFirst = p;
+ while( pFirst->pPrior ) pFirst = pFirst->pPrior;
+ generateColumnNames(pParse, 0, pFirst->pEList);
}
iBreak = sqlite3VdbeMakeLabel(v);
iCont = sqlite3VdbeMakeLabel(v);
+ computeLimitRegisters(pParse, p, iBreak);
sqlite3VdbeAddOp(v, OP_Rewind, tab1, iBreak);
- computeLimitRegisters(pParse, p);
iStart = sqlite3VdbeAddOp(v, OP_RowKey, tab1, 0);
sqlite3VdbeAddOp(v, OP_NotFound, tab2, iCont);
rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
@@ -1746,21 +1899,23 @@ static int multiSelect(
** SELECT might also skip this part if it has no ORDER BY clause and
** no temp tables are required.
*/
- if( pOrderBy || p->usesVirt ){
+ if( pOrderBy || p->usesEphm ){
int i; /* Loop counter */
KeyInfo *pKeyInfo; /* Collating sequence for the result set */
Select *pLoop; /* For looping through SELECT statements */
+ int nKeyCol; /* Number of entries in pKeyInfo->aCol[] */
CollSeq **apColl;
CollSeq **aCopy;
assert( p->pRightmost==p );
- pKeyInfo = sqliteMalloc(sizeof(*pKeyInfo)+nCol*2*sizeof(CollSeq*) + nCol);
+ nKeyCol = nCol + (pOrderBy ? pOrderBy->nExpr : 0);
+ pKeyInfo = sqliteMalloc(sizeof(*pKeyInfo)+nKeyCol*(sizeof(CollSeq*) + 1));
if( !pKeyInfo ){
rc = SQLITE_NOMEM;
goto multi_select_end;
}
- pKeyInfo->enc = pParse->db->enc;
+ pKeyInfo->enc = ENC(pParse->db);
pKeyInfo->nField = nCol;
for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){
@@ -1772,11 +1927,11 @@ static int multiSelect(
for(pLoop=p; pLoop; pLoop=pLoop->pPrior){
for(i=0; i<2; i++){
- int addr = pLoop->addrOpenVirt[i];
+ int addr = pLoop->addrOpenEphm[i];
if( addr<0 ){
/* If [0] is unused then [1] is also unused. So we can
** always safely abort as soon as the first unused slot is found */
- assert( pLoop->addrOpenVirt[1]<0 );
+ assert( pLoop->addrOpenEphm[1]<0 );
break;
}
sqlite3VdbeChangeP2(v, addr, nCol);
@@ -1786,15 +1941,15 @@ static int multiSelect(
if( pOrderBy ){
struct ExprList_item *pOTerm = pOrderBy->a;
- int nExpr = pOrderBy->nExpr;
+ int nOrderByExpr = pOrderBy->nExpr;
int addr;
u8 *pSortOrder;
- aCopy = (CollSeq**)&pKeyInfo[1];
- pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nExpr];
+ aCopy = &pKeyInfo->aColl[nOrderByExpr];
+ pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nCol];
memcpy(aCopy, pKeyInfo->aColl, nCol*sizeof(CollSeq*));
apColl = pKeyInfo->aColl;
- for(i=0; i<pOrderBy->nExpr; i++, pOTerm++, apColl++, pSortOrder++){
+ for(i=0; i<nOrderByExpr; i++, pOTerm++, apColl++, pSortOrder++){
Expr *pExpr = pOTerm->pExpr;
char *zName = pOTerm->zName;
assert( pExpr->op==TK_COLUMN && pExpr->iColumn<nCol );
@@ -1806,10 +1961,10 @@ static int multiSelect(
*pSortOrder = pOTerm->sortOrder;
}
assert( p->pRightmost==p );
- assert( p->addrOpenVirt[2]>=0 );
- addr = p->addrOpenVirt[2];
+ assert( p->addrOpenEphm[2]>=0 );
+ addr = p->addrOpenEphm[2];
sqlite3VdbeChangeP2(v, addr, p->pEList->nExpr+2);
- pKeyInfo->nField = pOrderBy->nExpr;
+ pKeyInfo->nField = nOrderByExpr;
sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
pKeyInfo = 0;
generateSortTail(pParse, p, v, p->pEList->nExpr, eDest, iParm);
@@ -1858,6 +2013,7 @@ static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){
assert( pExpr->pList==0 );
pExpr->pList = sqlite3ExprListDup(pNew->pList);
pExpr->iTable = pNew->iTable;
+ pExpr->pTab = pNew->pTab;
pExpr->iColumn = pNew->iColumn;
pExpr->iAgg = pNew->iAgg;
sqlite3TokenCopy(&pExpr->token, &pNew->token);
@@ -1949,6 +2105,10 @@ static void substSelect(Select *p, int iTable, ExprList *pEList){
** (12) The subquery is not the right term of a LEFT OUTER JOIN or the
** subquery has no WHERE clause. (added by ticket #350)
**
+** (13) The subquery and outer query do not both use LIMIT
+**
+** (14) The subquery does not use OFFSET
+**
** In this routine, the "p" parameter is a pointer to the outer query.
** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.
@@ -1960,7 +2120,6 @@ static void substSelect(Select *p, int iTable, ExprList *pEList){
** the subquery before this routine runs.
*/
static int flattenSubquery(
- Parse *pParse, /* The parsing context */
Select *p, /* The parent or outer SELECT statement */
int iFrom, /* Index in p->pSrc->a[] of the inner subquery */
int isAgg, /* True if outer SELECT uses aggregate functions */
@@ -1983,18 +2142,26 @@ static int flattenSubquery(
pSubitem = &pSrc->a[iFrom];
pSub = pSubitem->pSelect;
assert( pSub!=0 );
- if( isAgg && subqueryIsAgg ) return 0;
- if( subqueryIsAgg && pSrc->nSrc>1 ) return 0;
+ if( isAgg && subqueryIsAgg ) return 0; /* Restriction (1) */
+ if( subqueryIsAgg && pSrc->nSrc>1 ) return 0; /* Restriction (2) */
pSubSrc = pSub->pSrc;
assert( pSubSrc );
- if( (pSub->pLimit && p->pLimit) || pSub->pOffset ||
- (pSub->pLimit && isAgg) ) return 0;
- if( pSubSrc->nSrc==0 ) return 0;
- if( pSub->isDistinct && (pSrc->nSrc>1 || isAgg) ){
- return 0;
+ /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
+ ** not arbitrary expresssions, we allowed some combining of LIMIT and OFFSET
+ ** because they could be computed at compile-time. But when LIMIT and OFFSET
+ ** became arbitrary expressions, we were forced to add restrictions (13)
+ ** and (14). */
+ if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */
+ if( pSub->pOffset ) return 0; /* Restriction (14) */
+ if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */
+ if( (pSub->isDistinct || pSub->pLimit)
+ && (pSrc->nSrc>1 || isAgg) ){ /* Restrictions (4)(5)(8)(9) */
+ return 0;
+ }
+ if( p->isDistinct && subqueryIsAgg ) return 0; /* Restriction (6) */
+ if( (p->disallowOrderBy || p->pOrderBy) && pSub->pOrderBy ){
+ return 0; /* Restriction (11) */
}
- if( p->isDistinct && subqueryIsAgg ) return 0;
- if( (p->disallowOrderBy || p->pOrderBy) && pSub->pOrderBy ) return 0;
/* Restriction 3: If the subquery is a join, make sure the subquery is
** not used as the right operand of an outer join. Examples of why this
@@ -2080,14 +2247,14 @@ static int flattenSubquery(
** We look at every expression in the outer query and every place we see
** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
*/
- substExprList(p->pEList, iParent, pSub->pEList);
pList = p->pEList;
for(i=0; i<pList->nExpr; i++){
Expr *pExpr;
if( pList->a[i].zName==0 && (pExpr = pList->a[i].pExpr)->span.z!=0 ){
- pList->a[i].zName = sqliteStrNDup(pExpr->span.z, pExpr->span.n);
+ pList->a[i].zName = sqliteStrNDup((char*)pExpr->span.z, pExpr->span.n);
}
}
+ substExprList(p->pEList, iParent, pSub->pEList);
if( isAgg ){
substExprList(p->pGroupBy, iParent, pSub->pEList);
substExpr(p->pHaving, iParent, pSub->pEList);
@@ -2124,6 +2291,9 @@ static int flattenSubquery(
/*
** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y;
+ **
+ ** One is tempted to try to add a and b to combine the limits. But this
+ ** does not work if either limit is negative.
*/
if( pSub->pLimit ){
p->pLimit = pSub->pLimit;
@@ -2166,10 +2336,11 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
int base;
Vdbe *v;
int seekOp;
- int cont;
ExprList *pEList, *pList, eList;
struct ExprList_item eListItem;
SrcList *pSrc;
+ int brk;
+ int iDb;
/* Check to see if this query is a simple min() or max() query. Return
** zero if it is not.
@@ -2184,9 +2355,9 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
pList = pExpr->pList;
if( pList==0 || pList->nExpr!=1 ) return 0;
if( pExpr->token.n!=3 ) return 0;
- if( sqlite3StrNICmp(pExpr->token.z,"min",3)==0 ){
+ if( sqlite3StrNICmp((char*)pExpr->token.z,"min",3)==0 ){
seekOp = OP_Rewind;
- }else if( sqlite3StrNICmp(pExpr->token.z,"max",3)==0 ){
+ }else if( sqlite3StrNICmp((char*)pExpr->token.z,"max",3)==0 ){
seekOp = OP_Last;
}else{
return 0;
@@ -2196,6 +2367,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
iCol = pExpr->iColumn;
pTab = pSrc->a[0].pTab;
+
/* If we get to here, it means the query is of the correct form.
** Check to make sure we have an index and make pIdx point to the
** appropriate index. If the min() or max() is on an INTEGER PRIMARY
@@ -2206,9 +2378,13 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
pIdx = 0;
}else{
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr);
+ if( pColl==0 ) return 0;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pIdx->nColumn>=1 );
- if( pIdx->aiColumn[0]==iCol && pIdx->keyInfo.aColl[0]==pColl ) break;
+ if( pIdx->aiColumn[0]==iCol &&
+ 0==sqlite3StrICmp(pIdx->azColl[0], pColl->zName) ){
+ break;
+ }
}
if( pIdx==0 ) return 0;
}
@@ -2222,8 +2398,8 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
/* If the output is destined for a temporary table, open that table.
*/
- if( eDest==SRT_VirtualTab ){
- sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 1);
+ if( eDest==SRT_EphemTab ){
+ sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, 1);
}
/* Generating code to find the min or the max. Basically all we have
@@ -2231,13 +2407,16 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
** the min() or max() is on the INTEGER PRIMARY KEY, then find the first
** or last entry in the main table.
*/
- sqlite3CodeVerifySchema(pParse, pTab->iDb);
+ iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ assert( iDb>=0 || pTab->isEphem );
+ sqlite3CodeVerifySchema(pParse, iDb);
+ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
base = pSrc->a[0].iCursor;
- computeLimitRegisters(pParse, p);
+ brk = sqlite3VdbeMakeLabel(v);
+ computeLimitRegisters(pParse, p, brk);
if( pSrc->a[0].pSelect==0 ){
- sqlite3OpenTableForReading(v, base, pTab);
+ sqlite3OpenTable(pParse, base, iDb, pTab, OP_OpenRead);
}
- cont = sqlite3VdbeMakeLabel(v);
if( pIdx==0 ){
sqlite3VdbeAddOp(v, seekOp, base, 0);
}else{
@@ -2248,10 +2427,12 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
** "INSERT INTO x SELECT max() FROM x".
*/
int iIdx;
+ KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
iIdx = pParse->nTab++;
- sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
- sqlite3VdbeOp3(v, OP_OpenRead, iIdx, pIdx->tnum,
- (char*)&pIdx->keyInfo, P3_KEYINFO);
+ assert( pIdx->pSchema==pTab->pSchema );
+ sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
+ sqlite3VdbeOp3(v, OP_OpenRead, iIdx, pIdx->tnum,
+ (char*)pKey, P3_KEYINFO_HANDOFF);
if( seekOp==OP_Rewind ){
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
sqlite3VdbeAddOp(v, OP_MakeRecord, 1, 0);
@@ -2266,8 +2447,8 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
memset(&eListItem, 0, sizeof(eListItem));
eList.a = &eListItem;
eList.a[0].pExpr = pExpr;
- selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, cont, cont, 0);
- sqlite3VdbeResolveLabel(v, cont);
+ selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, brk, brk, 0);
+ sqlite3VdbeResolveLabel(v, brk);
sqlite3VdbeAddOp(v, OP_Close, base, 0);
return 1;
@@ -2309,11 +2490,6 @@ static int processOrderGroupBy(
if( sqlite3ExprResolveNames(pNC, pE) ){
return 1;
}
- if( sqlite3ExprIsConstant(pE) ){
- sqlite3ErrorMsg(pParse,
- "%s BY terms must not be non-integer constants", zType);
- return 1;
- }
}
return 0;
}
@@ -2356,14 +2532,8 @@ int sqlite3SelectResolve(
/* Resolve the expressions in the LIMIT and OFFSET clauses. These
** are not allowed to refer to any names, so pass an empty NameContext.
*/
+ memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
- sNC.hasAgg = 0;
- sNC.nErr = 0;
- sNC.nRef = 0;
- sNC.pEList = 0;
- sNC.allowAgg = 0;
- sNC.pSrcList = 0;
- sNC.pNext = 0;
if( sqlite3ExprResolveNames(&sNC, p->pLimit) ||
sqlite3ExprResolveNames(&sNC, p->pOffset) ){
return SQLITE_ERROR;
@@ -2465,7 +2635,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
pFunc->iDistinct = -1;
}else{
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->pList);
- sqlite3VdbeOp3(v, OP_OpenVirtual, pFunc->iDistinct, 0,
+ sqlite3VdbeOp3(v, OP_OpenEphemeral, pFunc->iDistinct, 0,
(char*)pKeyInfo, P3_KEYINFO_HANDOFF);
}
}
@@ -2511,13 +2681,14 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
if( pF->iDistinct>=0 ){
addrNext = sqlite3VdbeMakeLabel(v);
assert( nArg==1 );
- codeDistinct(v, pF->iDistinct, addrNext, 1, 2);
+ codeDistinct(v, pF->iDistinct, addrNext, 1);
}
if( pF->pFunc->needCollSeq ){
CollSeq *pColl = 0;
struct ExprList_item *pItem;
int j;
- for(j=0, pItem=pList->a; !pColl && j<pList->nExpr; j++, pItem++){
+ assert( pList!=0 ); /* pList!=0 if pF->pFunc->needCollSeq is true */
+ for(j=0, pItem=pList->a; !pColl && j<nArg; j++, pItem++){
pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
}
if( !pColl ){
@@ -2613,10 +2784,13 @@ int sqlite3Select(
int isDistinct; /* True if the DISTINCT keyword is present */
int distinct; /* Table to use for the distinct set */
int rc = 1; /* Value to return from this function */
- int addrSortIndex; /* Address of an OP_OpenVirtual instruction */
+ int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */
AggInfo sAggInfo; /* Information used by aggregate queries */
+ int iEnd; /* Address of the end of the query */
- if( sqlite3_malloc_failed || pParse->nErr || p==0 ) return 1;
+ if( p==0 || sqlite3MallocFailed() || pParse->nErr ){
+ return 1;
+ }
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
memset(&sAggInfo, 0, sizeof(sAggInfo));
@@ -2663,7 +2837,6 @@ int sqlite3Select(
/* If writing to memory or generating a set
** only a single column may be output.
*/
- assert( eDest!=SRT_Exists || pEList->nExpr==1 );
#ifndef SQLITE_OMIT_SUBQUERY
if( (eDest==SRT_Mem || eDest==SRT_Set) && pEList->nExpr>1 ){
sqlite3ErrorMsg(pParse, "only a single result allowed for "
@@ -2683,13 +2856,6 @@ int sqlite3Select(
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto select_end;
- /* Identify column names if we will be using them in a callback. This
- ** step is skipped if the output is going to some other destination.
- */
- if( eDest==SRT_Callback ){
- generateColumnNames(pParse, pTabList, pEList);
- }
-
/* Generate code for all sub-queries in the FROM clause
*/
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
@@ -2698,7 +2864,7 @@ int sqlite3Select(
int needRestoreContext;
struct SrcList_item *pItem = &pTabList->a[i];
- if( pItem->pSelect==0 ) continue;
+ if( pItem->pSelect==0 || pItem->isPopulated ) continue;
if( pItem->zName!=0 ){
zSavedAuthContext = pParse->zAuthContext;
pParse->zAuthContext = pItem->zName;
@@ -2706,7 +2872,7 @@ int sqlite3Select(
}else{
needRestoreContext = 0;
}
- sqlite3Select(pParse, pItem->pSelect, SRT_VirtualTab,
+ sqlite3Select(pParse, pItem->pSelect, SRT_EphemTab,
pItem->iCursor, p, i, &isAgg, 0);
if( needRestoreContext ){
pParse->zAuthContext = zSavedAuthContext;
@@ -2735,7 +2901,7 @@ int sqlite3Select(
*/
#ifndef SQLITE_OMIT_VIEW
if( pParent && pParentAgg &&
- flattenSubquery(pParse, pParent, parentTab, *pParentAgg, isAgg) ){
+ flattenSubquery(pParent, parentTab, *pParentAgg, isAgg) ){
if( isAgg ) *pParentAgg = 1;
goto select_end;
}
@@ -2746,7 +2912,7 @@ int sqlite3Select(
**
** This sorting index might end up being unused if the data can be
** extracted in pre-sorted order. If that is the case, then the
- ** OP_OpenVirtual instruction will be changed to an OP_Noop once
+ ** OP_OpenEphemeral instruction will be changed to an OP_Noop once
** we figure out that the sorting index is not needed. The addrSortIndex
** variable is used to facilitate that change.
*/
@@ -2763,31 +2929,22 @@ int sqlite3Select(
}
pKeyInfo = keyInfoFromExprList(pParse, pOrderBy);
pOrderBy->iECursor = pParse->nTab++;
- p->addrOpenVirt[2] = addrSortIndex =
- sqlite3VdbeOp3(v, OP_OpenVirtual, pOrderBy->iECursor, pOrderBy->nExpr+2,
- (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
+ p->addrOpenEphm[2] = addrSortIndex =
+ sqlite3VdbeOp3(v, OP_OpenEphemeral, pOrderBy->iECursor, pOrderBy->nExpr+2, (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
}else{
addrSortIndex = -1;
}
- /* Set the limiter.
- */
- computeLimitRegisters(pParse, p);
-
/* If the output is destined for a temporary table, open that table.
*/
- if( eDest==SRT_VirtualTab ){
- sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, pEList->nExpr);
+ if( eDest==SRT_EphemTab ){
+ sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, pEList->nExpr);
}
-
- /* Initialize the memory cell to NULL for SRT_Mem or 0 for SRT_Exists
+ /* Set the limiter.
*/
- if( eDest==SRT_Mem ){
- sqlite3VdbeAddOp(v, OP_MemNull, iParm, 0);
- }else if( eDest==SRT_Exists ){
- sqlite3VdbeAddOp(v, OP_MemInt, 0, iParm);
- }
+ iEnd = sqlite3VdbeMakeLabel(v);
+ computeLimitRegisters(pParse, p, iEnd);
/* Open a virtual index to use for the distinct set.
*/
@@ -2795,7 +2952,7 @@ int sqlite3Select(
KeyInfo *pKeyInfo;
distinct = pParse->nTab++;
pKeyInfo = keyInfoFromExprList(pParse, p->pEList);
- sqlite3VdbeOp3(v, OP_OpenVirtual, distinct, 0,
+ sqlite3VdbeOp3(v, OP_OpenEphemeral, distinct, 0,
(char*)pKeyInfo, P3_KEYINFO_HANDOFF);
}else{
distinct = -1;
@@ -2809,13 +2966,13 @@ int sqlite3Select(
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy);
if( pWInfo==0 ) goto select_end;
- /* If sorting index that was created by a prior OP_OpenVirtual
- ** instruction ended up not being needed, then change the OP_OpenVirtual
+ /* If sorting index that was created by a prior OP_OpenEphemeral
+ ** instruction ended up not being needed, then change the OP_OpenEphemeral
** into an OP_Noop.
*/
if( addrSortIndex>=0 && pOrderBy==0 ){
- uncreateSortingIndex(pParse, addrSortIndex);
- p->addrOpenVirt[2] = -1;
+ sqlite3VdbeChangeToNoop(v, addrSortIndex, 1);
+ p->addrOpenEphm[2] = -1;
}
/* Use the standard inner loop
@@ -2849,7 +3006,7 @@ int sqlite3Select(
int addrGroupByChange; /* Code that runs when any GROUP BY term changes */
int addrProcessRow; /* Code to process a single input row */
int addrEnd; /* End of all processing */
- int addrSortingIdx; /* The OP_OpenVirtual for the sorting index */
+ int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */
int addrReset; /* Subroutine for resetting the accumulator */
addrEnd = sqlite3VdbeMakeLabel(v);
@@ -2879,7 +3036,7 @@ int sqlite3Select(
goto select_end;
}
}
- if( sqlite3_malloc_failed ) goto select_end;
+ if( sqlite3MallocFailed() ) goto select_end;
/* Processing for aggregates with GROUP BY is very different and
** much more complex tha aggregates without a GROUP BY.
@@ -2896,13 +3053,13 @@ int sqlite3Select(
/* If there is a GROUP BY clause we might need a sorting index to
** implement it. Allocate that sorting index now. If it turns out
- ** that we do not need it after all, the OpenVirtual instruction
+ ** that we do not need it after all, the OpenEphemeral instruction
** will be converted into a Noop.
*/
sAggInfo.sortingIdx = pParse->nTab++;
pKeyInfo = keyInfoFromExprList(pParse, pGroupBy);
addrSortingIdx =
- sqlite3VdbeOp3(v, OP_OpenVirtual, sAggInfo.sortingIdx,
+ sqlite3VdbeOp3(v, OP_OpenEphemeral, sAggInfo.sortingIdx,
sAggInfo.nSortingColumn,
(char*)pKeyInfo, P3_KEYINFO_HANDOFF);
@@ -2965,7 +3122,7 @@ int sqlite3Select(
if( pWInfo==0 ) goto select_end;
if( pGroupBy==0 ){
/* The optimizer is able to deliver rows in group by order so
- ** we do not have to sort. The OP_OpenVirtual table will be
+ ** we do not have to sort. The OP_OpenEphemeral table will be
** cancelled later because we still need to use the pKeyInfo
*/
pGroupBy = p->pGroupBy;
@@ -3060,7 +3217,7 @@ int sqlite3Select(
sqlite3VdbeAddOp(v, OP_Next, sAggInfo.sortingIdx, addrTopOfLoop);
}else{
sqlite3WhereEnd(pWInfo);
- uncreateSortingIndex(pParse, addrSortingIdx);
+ sqlite3VdbeChangeToNoop(v, addrSortingIdx, 1);
}
/* Output the final row of result
@@ -3100,18 +3257,21 @@ int sqlite3Select(
#ifndef SQLITE_OMIT_SUBQUERY
/* If this was a subquery, we have now converted the subquery into a
- ** temporary table. So delete the subquery structure from the parent
- ** to prevent this subquery from being evaluated again and to force the
- ** the use of the temporary table.
+ ** temporary table. So set the SrcList_item.isPopulated flag to prevent
+ ** this subquery from being evaluated again and to force the use of
+ ** the temporary table.
*/
if( pParent ){
assert( pParent->pSrc->nSrc>parentTab );
assert( pParent->pSrc->a[parentTab].pSelect==p );
- sqlite3SelectDelete(p);
- pParent->pSrc->a[parentTab].pSelect = 0;
+ pParent->pSrc->a[parentTab].isPopulated = 1;
}
#endif
+ /* Jump here to skip this query
+ */
+ sqlite3VdbeResolveLabel(v, iEnd);
+
/* The SELECT was successfully coded. Set the return code to 0
** to indicate no errors.
*/
@@ -3121,6 +3281,14 @@ int sqlite3Select(
** successful coding of the SELECT.
*/
select_end:
+
+ /* Identify column names if we will be using them in a callback. This
+ ** step is skipped if the output is going to some other destination.
+ */
+ if( rc==SQLITE_OK && eDest==SRT_Callback ){
+ generateColumnNames(pParse, pTabList, pEList);
+ }
+
sqliteFree(sAggInfo.aCol);
sqliteFree(sAggInfo.aFunc);
return rc;
diff --git a/ext/pdo_sqlite/sqlite/src/shell.c b/ext/pdo_sqlite/sqlite/src/shell.c
index 61ff2482d5..6058bc195e 100644
--- a/ext/pdo_sqlite/sqlite/src/shell.c
+++ b/ext/pdo_sqlite/sqlite/src/shell.c
@@ -21,7 +21,7 @@
#include "sqlite3.h"
#include <ctype.h>
-#if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__)
+#if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__) && !defined(__OS2__)
# include <signal.h>
# include <pwd.h>
# include <unistd.h>
@@ -37,6 +37,10 @@
# include <Folders.h>
#endif
+#ifdef __OS2__
+# include <unistd.h>
+#endif
+
#if defined(HAVE_READLINE) && HAVE_READLINE==1
# include <readline/readline.h>
# include <readline/history.h>
@@ -62,7 +66,7 @@ static sqlite3 *db = 0;
/*
** True if an interrupt (Control-C) has been received.
*/
-static int seenInterrupt = 0;
+static volatile int seenInterrupt = 0;
/*
** This is the name of our program. It is set in main(), used
@@ -81,7 +85,7 @@ static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
/*
** Determines if a string is a number of not.
*/
-static int isNumber(const unsigned char *z, int *realnum){
+static int isNumber(const char *z, int *realnum){
if( *z=='-' || *z=='+' ) z++;
if( !isdigit(*z) ){
return 0;
@@ -197,7 +201,7 @@ static char *one_input_line(const char *zPrior, FILE *in){
}
zResult = readline(zPrompt);
#if defined(HAVE_READLINE) && HAVE_READLINE==1
- if( zResult ) add_history(zResult);
+ if( zResult && *zResult ) add_history(zResult);
#endif
return zResult;
}
@@ -247,7 +251,7 @@ struct callback_data {
#define MODE_Csv 7 /* Quote strings, numbers are plain */
#define MODE_NUM_OF 8 /* The number of modes (not a mode itself) */
-char *modeDescr[MODE_NUM_OF] = {
+static const char *modeDescr[MODE_NUM_OF] = {
"line",
"column",
"list",
@@ -384,12 +388,12 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
int w = 5;
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
- int len = strlen(azCol[i]);
+ int len = strlen(azCol[i] ? azCol[i] : "");
if( len>w ) w = len;
}
if( p->cnt++>0 ) fprintf(p->out,"\n");
for(i=0; i<nArg; i++){
- fprintf(p->out,"%*s = %s\n", w, azCol[i],
+ fprintf(p->out,"%*s = %s\n", w, azCol[i],
azArg[i] ? azArg[i] : p->nullvalue);
}
break;
@@ -486,7 +490,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
case MODE_Tcl: {
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
- output_c_string(p->out,azCol[i]);
+ output_c_string(p->out,azCol[i] ? azCol[i] : "");
fprintf(p->out, "%s", p->separator);
}
fprintf(p->out,"\n");
@@ -502,7 +506,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
case MODE_Csv: {
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
- output_csv(p, azCol[i], i<nArg-1);
+ output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
}
fprintf(p->out,"\n");
}
@@ -690,8 +694,9 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
rc = sqlite3_step(pTableInfo);
while( rc==SQLITE_ROW ){
+ const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
zSelect = appendText(zSelect, "quote(", 0);
- zSelect = appendText(zSelect, sqlite3_column_text(pTableInfo, 1), '"');
+ zSelect = appendText(zSelect, zText, '"');
rc = sqlite3_step(pTableInfo);
if( rc==SQLITE_ROW ){
zSelect = appendText(zSelect, ") || ', ' || ", 0);
@@ -758,6 +763,9 @@ 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"
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ ".load FILE ?ENTRY? Load an extension library\n"
+#endif
".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
" csv Comma-separated values\n"
" column Left-aligned columns. (See .width)\n"
@@ -773,9 +781,6 @@ static char zHelp[] =
".prompt MAIN CONTINUE Replace the standard prompts\n"
".quit Exit this program\n"
".read FILENAME Execute SQL in FILENAME\n"
-#ifdef SQLITE_HAS_CODEC
- ".rekey OLD NEW NEW Change the encryption key\n"
-#endif
".schema ?TABLE? Show the CREATE statements\n"
".separator STRING Change separator used by output mode and .import\n"
".show Show the current values for various settings\n"
@@ -795,9 +800,6 @@ static void open_db(struct callback_data *p){
if( p->db==0 ){
sqlite3_open(p->zDbFilename, &p->db);
db = p->db;
-#ifdef SQLITE_HAS_CODEC
- sqlite3_key(p->db, p->zKey, p->zKey ? strlen(p->zKey) : 0);
-#endif
sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
shellstaticFunc, 0, 0);
if( SQLITE_OK!=sqlite3_errcode(db) ){
@@ -805,6 +807,9 @@ static void open_db(struct callback_data *p){
p->zDbFilename, sqlite3_errmsg(db));
exit(1);
}
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ sqlite3_enable_load_extension(p->db, 1);
+#endif
}
}
@@ -829,7 +834,7 @@ static void resolve_backslashes(char *z){
}else if( c=='r' ){
c = '\r';
}else if( c>='0' && c<='7' ){
- c =- '0';
+ c -= '0';
if( z[i+1]>='0' && z[i+1]<='7' ){
i++;
c = (c<<3) + z[i] - '0';
@@ -1037,6 +1042,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
FILE *in; /* The input file */
int lineno = 0; /* Line number of input file */
+ open_db(p);
nSep = strlen(p->separator);
if( nSep==0 ){
fprintf(stderr, "non-null separator required for import\n");
@@ -1045,7 +1051,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
if( zSql==0 ) return 0;
nByte = strlen(zSql);
- rc = sqlite3_prepare(p->db, zSql, 0, &pStmt, 0);
+ rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc ){
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
@@ -1065,7 +1071,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}
zSql[j++] = ')';
zSql[j] = 0;
- rc = sqlite3_prepare(p->db, zSql, 0, &pStmt, 0);
+ rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
free(zSql);
if( rc ){
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
@@ -1079,7 +1085,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
return 0;
}
azCol = malloc( sizeof(azCol[0])*(nCol+1) );
- if( azCol==0 ) return 0;
+ if( azCol==0 ){
+ fclose(in);
+ return 0;
+ }
sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
zCommit = "COMMIT";
while( (zLine = local_getline(0, in))!=0 ){
@@ -1146,6 +1155,22 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}
}else
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
+ const char *zFile, *zProc;
+ char *zErrMsg = 0;
+ int rc;
+ zFile = azArg[1];
+ zProc = nArg>=3 ? azArg[2] : 0;
+ open_db(p);
+ rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
+ if( rc!=SQLITE_OK ){
+ fprintf(stderr, "%s\n", zErrMsg);
+ sqlite3_free(zErrMsg);
+ }
+ }else
+#endif
+
if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){
int n2 = strlen(azArg[1]);
if( strncmp(azArg[1],"line",n2)==0
@@ -1226,22 +1251,6 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}
}else
-#ifdef SQLITE_HAS_CODEC
- if( c=='r' && strncmp(azArg[0],"rekey", n)==0 && nArg==4 ){
- char *zOld = p->zKey;
- if( zOld==0 ) zOld = "";
- if( strcmp(azArg[1],zOld) ){
- fprintf(stderr,"old key is incorrect\n");
- }else if( strcmp(azArg[2], azArg[3]) ){
- fprintf(stderr,"2nd copy of new key does not match the 1st\n");
- }else{
- sqlite3_free(p->zKey);
- p->zKey = sqlite3_mprintf("%s", azArg[2]);
- sqlite3_rekey(p->db, p->zKey, strlen(p->zKey));
- }
- }else
-#endif
-
if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
struct callback_data data;
char *zErrMsg = 0;
@@ -1392,6 +1401,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
int j;
+ assert( nArg<=ArraySize(azArg) );
for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
p->colWidth[j-1] = atoi(azArg[j]);
}
@@ -1488,6 +1498,10 @@ static void process_input(struct callback_data *p, FILE *in){
if( zLine[i]!=0 ){
nSql = strlen(zLine);
zSql = malloc( nSql+1 );
+ if( zSql==0 ){
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
strcpy(zSql, zLine);
}
}else{
@@ -1507,7 +1521,7 @@ static void process_input(struct callback_data *p, FILE *in){
open_db(p);
rc = sqlite3_exec(p->db, zSql, callback, p, &zErrMsg);
if( rc || zErrMsg ){
- if( in!=0 && !p->echoOn ) printf("%s\n",zSql);
+ /* if( in!=0 && !p->echoOn ) printf("%s\n",zSql); */
if( zErrMsg!=0 ){
printf("SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
@@ -1536,7 +1550,7 @@ static void process_input(struct callback_data *p, FILE *in){
static char *find_home_dir(void){
char *home_dir = NULL;
-#if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__)
+#if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__) && !defined(__OS2__)
struct passwd *pwent;
uid_t uid = getuid();
if( (pwent=getpwuid(uid)) != NULL) {
@@ -1556,7 +1570,7 @@ static char *find_home_dir(void){
}
}
-#if defined(_WIN32) || defined(WIN32)
+#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
if (!home_dir) {
home_dir = "c:";
}
@@ -1581,7 +1595,7 @@ static void process_sqliterc(
){
char *home_dir = NULL;
const char *sqliterc = sqliterc_override;
- char *zBuf;
+ char *zBuf = 0;
FILE *in = NULL;
if (sqliterc == NULL) {
@@ -1607,6 +1621,7 @@ static void process_sqliterc(
process_input(p,in);
fclose(in);
}
+ free(zBuf);
return;
}
@@ -1619,9 +1634,6 @@ static const char zOptions[] =
" -[no]header turn headers on or off\n"
" -column set output mode to 'column'\n"
" -html set output mode to HTML\n"
-#ifdef SQLITE_HAS_CODEC
- " -key KEY encryption key\n"
-#endif
" -line set output mode to 'line'\n"
" -list set output mode to 'list'\n"
" -separator 'x' set output field separator (|)\n"
@@ -1642,7 +1654,7 @@ static void usage(int showDetail){
/*
** Initialize the state information in data
*/
-void main_init(struct callback_data *data) {
+static void main_init(struct callback_data *data) {
memset(data, 0, sizeof(*data));
data->mode = MODE_List;
strcpy(data->separator,"|");
@@ -1755,7 +1767,7 @@ int main(int argc, char **argv){
data.echoOn = 1;
}else if( strcmp(z,"-version")==0 ){
printf("%s\n", sqlite3_libversion());
- return 1;
+ return 0;
}else if( strcmp(z,"-help")==0 ){
usage(1);
}else{
@@ -1802,12 +1814,18 @@ int main(int argc, char **argv){
if( zHistory ){
stifle_history(100);
write_history(zHistory);
+ free(zHistory);
}
+ free(zHome);
}else{
process_input(&data, stdin);
}
}
set_table_name(&data, 0);
- if( db ) sqlite3_close(db);
+ if( db ){
+ if( sqlite3_close(db)!=SQLITE_OK ){
+ fprintf(stderr,"error closing database: %s\n", sqlite3_errmsg(db));
+ }
+ }
return 0;
}
diff --git a/ext/pdo_sqlite/sqlite/src/sqlite.h.in b/ext/pdo_sqlite/sqlite/src/sqlite.h.in
index 6b2dd551d6..a1b4759f84 100644
--- a/ext/pdo_sqlite/sqlite/src/sqlite.h.in
+++ b/ext/pdo_sqlite/sqlite/src/sqlite.h.in
@@ -78,7 +78,10 @@ typedef struct sqlite3 sqlite3;
** to do a typedef that for 64-bit integers that depends on what compiler
** is being used.
*/
-#if defined(_MSC_VER) || defined(__BORLANDC__)
+#ifdef SQLITE_INT64_TYPE
+ typedef SQLITE_INT64_TYPE sqlite_int64;
+ typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
+#elif defined(_MSC_VER) || defined(__BORLANDC__)
typedef __int64 sqlite_int64;
typedef unsigned __int64 sqlite_uint64;
#else
@@ -86,6 +89,13 @@ typedef struct sqlite3 sqlite3;
typedef unsigned long long int sqlite_uint64;
#endif
+/*
+** If compiling for a processor that lacks floating point support,
+** substitute integer for floating-point
+*/
+#ifdef SQLITE_OMIT_FLOATING_POINT
+# define double sqlite_int64
+#endif
/*
** A function to close the database.
@@ -157,6 +167,7 @@ int sqlite3_exec(
** Return values for sqlite3_exec() and sqlite3_step()
*/
#define SQLITE_OK 0 /* Successful result */
+/* beginning-of-error-codes */
#define SQLITE_ERROR 1 /* SQL error or missing database */
#define SQLITE_INTERNAL 2 /* NOT USED. Internal logic error in SQLite */
#define SQLITE_PERM 3 /* Access permission denied */
@@ -185,6 +196,7 @@ int sqlite3_exec(
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
+/* end-of-error-codes */
/*
** Each entry in an SQLite table has a unique integer key. (The key is
@@ -393,9 +405,19 @@ void sqlite3_free_table(char **result);
*/
char *sqlite3_mprintf(const char*,...);
char *sqlite3_vmprintf(const char*, va_list);
-void sqlite3_free(char *z);
char *sqlite3_snprintf(int,char*,const char*, ...);
+/*
+** SQLite uses its own memory allocator. On many installations, this
+** memory allocator is identical to the standard malloc()/realloc()/free()
+** and can be used interchangable. On others, the implementations are
+** different. For maximum portability, it is best not to mix calls
+** to the standard malloc/realloc/free with the sqlite versions.
+*/
+void *sqlite3_malloc(int);
+void *sqlite3_realloc(void*, int);
+void sqlite3_free(void*);
+
#ifndef SQLITE_OMIT_AUTHORIZATION
/*
** This routine registers a callback with the SQLite library. The
@@ -454,7 +476,8 @@ int sqlite3_set_authorizer(
#define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */
#define SQLITE_REINDEX 27 /* Index Name NULL */
#define SQLITE_ANALYZE 28 /* Table Name NULL */
-
+#define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */
+#define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */
/*
** The return value of the authorization function should be one of the
@@ -717,6 +740,30 @@ const char *sqlite3_column_name(sqlite3_stmt*,int);
const void *sqlite3_column_name16(sqlite3_stmt*,int);
/*
+** The first parameter to the following calls is a compiled SQL statement.
+** These functions return information about the Nth column returned by
+** the statement, where N is the second function argument.
+**
+** If the Nth column returned by the statement is not a column value,
+** then all of the functions return NULL. Otherwise, the return the
+** name of the attached database, table and column that the expression
+** extracts a value from.
+**
+** As with all other SQLite APIs, those postfixed with "16" return UTF-16
+** encoded strings, the other functions return UTF-8. The memory containing
+** the returned strings is valid until the statement handle is finalized().
+**
+** These APIs are only available if the library was compiled with the
+** SQLITE_ENABLE_COLUMN_METADATA preprocessor symbol defined.
+*/
+const char *sqlite3_column_database_name(sqlite3_stmt*,int);
+const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
+const char *sqlite3_column_table_name(sqlite3_stmt*,int);
+const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
+const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
+const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
+
+/*
** The first parameter is a compiled SQL statement. If this statement
** is a SELECT statement, the Nth column of the returned result set
** of the SELECT is a table column then the declared type of the table
@@ -728,7 +775,7 @@ const void *sqlite3_column_name16(sqlite3_stmt*,int);
**
** And the following statement compiled:
**
-** SELECT c1 + 1, 0 FROM t1;
+** SELECT c1 + 1, c1 FROM t1;
**
** Then this routine would return the string "VARIANT" for the second
** result column (i==1), and a NULL pointer for the first result column
@@ -748,7 +795,7 @@ const char *sqlite3_column_decltype(sqlite3_stmt *, int i);
**
** And the following statement compiled:
**
-** SELECT c1 + 1, 0 FROM t1;
+** SELECT c1 + 1, c1 FROM t1;
**
** Then this routine would return the string "INTEGER" for the second
** result column (i==1), and a NULL pointer for the first result column
@@ -889,6 +936,8 @@ sqlite_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
int sqlite3_column_type(sqlite3_stmt*, int iCol);
+int sqlite3_column_numeric_type(sqlite3_stmt*, int iCol);
+sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
/*
** The sqlite3_finalize() function is called to delete a compiled
@@ -972,9 +1021,8 @@ int sqlite3_create_function16(
);
/*
-** The next routine returns the number of calls to xStep for a particular
-** aggregate function instance. The current call to xStep counts so this
-** routine always returns at least 1.
+** This function is deprecated. Do not use it. It continues to exist
+** so as not to break legacy code. But new code should avoid using it.
*/
int sqlite3_aggregate_count(sqlite3_context*);
@@ -997,6 +1045,7 @@ const void *sqlite3_value_text16(sqlite3_value*);
const void *sqlite3_value_text16le(sqlite3_value*);
const void *sqlite3_value_text16be(sqlite3_value*);
int sqlite3_value_type(sqlite3_value*);
+int sqlite3_value_numeric_type(sqlite3_value*);
/*
** Aggregate functions use the following routine to allocate
@@ -1080,11 +1129,12 @@ void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
** These are the allowed values for the eTextRep argument to
** sqlite3_create_collation and sqlite3_create_function.
*/
-#define SQLITE_UTF8 1
-#define SQLITE_UTF16LE 2
-#define SQLITE_UTF16BE 3
-#define SQLITE_UTF16 4 /* Use native byte order */
-#define SQLITE_ANY 5 /* sqlite3_create_function only */
+#define SQLITE_UTF8 1
+#define SQLITE_UTF16LE 2
+#define SQLITE_UTF16BE 3
+#define SQLITE_UTF16 4 /* Use native byte order */
+#define SQLITE_ANY 5 /* sqlite3_create_function only */
+#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */
/*
** These two functions are used to add new collation sequences to the
@@ -1251,7 +1301,7 @@ extern char *sqlite3_temp_directory;
** This functionality can be omitted from a build by defining the
** SQLITE_OMIT_GLOBALRECOVER at compile time.
*/
-int sqlite3_global_recover();
+int sqlite3_global_recover(void);
/*
** Test to see whether or not the database connection is in autocommit
@@ -1269,6 +1319,403 @@ int sqlite3_get_autocommit(sqlite3*);
*/
sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
+/*
+** Register a callback function with the database connection identified by the
+** first argument to be invoked whenever a row is updated, inserted or deleted.
+** Any callback set by a previous call to this function for the same
+** database connection is overridden.
+**
+** The second argument is a pointer to the function to invoke when a
+** row is updated, inserted or deleted. The first argument to the callback is
+** a copy of the third argument to sqlite3_update_hook. The second callback
+** argument is one of SQLITE_INSERT, SQLITE_DELETE or SQLITE_UPDATE, depending
+** on the operation that caused the callback to be invoked. The third and
+** fourth arguments to the callback contain pointers to the database and
+** table name containing the affected row. The final callback parameter is
+** the rowid of the row. In the case of an update, this is the rowid after
+** the update takes place.
+**
+** The update hook is not invoked when internal system tables are
+** modified (i.e. sqlite_master and sqlite_sequence).
+**
+** If another function was previously registered, its pArg value is returned.
+** Otherwise NULL is returned.
+*/
+void *sqlite3_update_hook(
+ sqlite3*,
+ void(*)(void *,int ,char const *,char const *,sqlite_int64),
+ void*
+);
+
+/*
+** Register a callback to be invoked whenever a transaction is rolled
+** back.
+**
+** The new callback function overrides any existing rollback-hook
+** callback. If there was an existing callback, then it's pArg value
+** (the third argument to sqlite3_rollback_hook() when it was registered)
+** is returned. Otherwise, NULL is returned.
+**
+** For the purposes of this API, a transaction is said to have been
+** rolled back if an explicit "ROLLBACK" statement is executed, or
+** an error or constraint causes an implicit rollback to occur. The
+** callback is not invoked if a transaction is automatically rolled
+** back because the database connection is closed.
+*/
+void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
+
+/*
+** This function is only available if the library is compiled without
+** the SQLITE_OMIT_SHARED_CACHE macro defined. It is used to enable or
+** disable (if the argument is true or false, respectively) the
+** "shared pager" feature.
+*/
+int sqlite3_enable_shared_cache(int);
+
+/*
+** Attempt to free N bytes of heap memory by deallocating non-essential
+** memory allocations held by the database library (example: memory
+** used to cache database pages to improve performance).
+**
+** This function is not a part of standard builds. It is only created
+** if SQLite is compiled with the SQLITE_ENABLE_MEMORY_MANAGEMENT macro.
+*/
+int sqlite3_release_memory(int);
+
+/*
+** Place a "soft" limit on the amount of heap memory that may be allocated by
+** SQLite within the current thread. If an internal allocation is requested
+** that would exceed the specified limit, sqlite3_release_memory() is invoked
+** one or more times to free up some space before the allocation is made.
+**
+** The limit is called "soft", because if sqlite3_release_memory() cannot free
+** sufficient memory to prevent the limit from being exceeded, the memory is
+** allocated anyway and the current operation proceeds.
+**
+** This function is only available if the library was compiled with the
+** SQLITE_ENABLE_MEMORY_MANAGEMENT option set.
+** memory-management has been enabled.
+*/
+void sqlite3_soft_heap_limit(int);
+
+/*
+** This routine makes sure that all thread-local storage has been
+** deallocated for the current thread.
+**
+** This routine is not technically necessary. All thread-local storage
+** will be automatically deallocated once memory-management and
+** shared-cache are disabled and the soft heap limit has been set
+** to zero. This routine is provided as a convenience for users who
+** want to make absolutely sure they have not forgotten something
+** prior to killing off a thread.
+*/
+void sqlite3_thread_cleanup(void);
+
+/*
+** Return meta information about a specific column of a specific database
+** table accessible using the connection handle passed as the first function
+** argument.
+**
+** The column is identified by the second, third and fourth parameters to
+** this function. The second parameter is either the name of the database
+** (i.e. "main", "temp" or an attached database) containing the specified
+** table or NULL. If it is NULL, then all attached databases are searched
+** for the table using the same algorithm as the database engine uses to
+** resolve unqualified table references.
+**
+** The third and fourth parameters to this function are the table and column
+** name of the desired column, respectively. Neither of these parameters
+** may be NULL.
+**
+** Meta information is returned by writing to the memory locations passed as
+** the 5th and subsequent parameters to this function. Any of these
+** arguments may be NULL, in which case the corresponding element of meta
+** information is ommitted.
+**
+** Parameter Output Type Description
+** -----------------------------------
+**
+** 5th const char* Data type
+** 6th const char* Name of the default collation sequence
+** 7th int True if the column has a NOT NULL constraint
+** 8th int True if the column is part of the PRIMARY KEY
+** 9th int True if the column is AUTOINCREMENT
+**
+**
+** The memory pointed to by the character pointers returned for the
+** declaration type and collation sequence is valid only until the next
+** call to any sqlite API function.
+**
+** If the specified table is actually a view, then an error is returned.
+**
+** If the specified column is "rowid", "oid" or "_rowid_" and an
+** INTEGER PRIMARY KEY column has been explicitly declared, then the output
+** parameters are set for the explicitly declared column. If there is no
+** explicitly declared IPK column, then the output parameters are set as
+** follows:
+**
+** data type: "INTEGER"
+** collation sequence: "BINARY"
+** not null: 0
+** primary key: 1
+** auto increment: 0
+**
+** This function may load one or more schemas from database files. If an
+** error occurs during this process, or if the requested table or column
+** cannot be found, an SQLITE error code is returned and an error message
+** left in the database handle (to be retrieved using sqlite3_errmsg()).
+**
+** This API is only available if the library was compiled with the
+** SQLITE_ENABLE_COLUMN_METADATA preprocessor symbol defined.
+*/
+int sqlite3_table_column_metadata(
+ sqlite3 *db, /* Connection handle */
+ const char *zDbName, /* Database name or NULL */
+ const char *zTableName, /* Table name */
+ const char *zColumnName, /* Column name */
+ char const **pzDataType, /* OUTPUT: Declared data type */
+ char const **pzCollSeq, /* OUTPUT: Collation sequence name */
+ int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */
+ int *pPrimaryKey, /* OUTPUT: True if column part of PK */
+ int *pAutoinc /* OUTPUT: True if colums is auto-increment */
+);
+
+/*
+****** EXPERIMENTAL - subject to change without notice **************
+**
+** Attempt to load an SQLite extension library contained in the file
+** zFile. The entry point is zProc. zProc may be 0 in which case the
+** name of the entry point defaults to "sqlite3_extension_init".
+**
+** Return SQLITE_OK on success and SQLITE_ERROR if something goes wrong.
+**
+** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with
+** error message text. The calling function should free this memory
+** by calling sqlite3_free().
+**
+** Extension loading must be enabled using sqlite3_enable_load_extension()
+** prior to calling this API or an error will be returned.
+**
+****** EXPERIMENTAL - subject to change without notice **************
+*/
+int sqlite3_load_extension(
+ sqlite3 *db, /* Load the extension into this database connection */
+ const char *zFile, /* Name of the shared library containing extension */
+ const char *zProc, /* Entry point. Derived from zFile if 0 */
+ char **pzErrMsg /* Put error message here if not 0 */
+);
+
+/*
+** So as not to open security holes in older applications that are
+** unprepared to deal with extension load, and as a means of disabling
+** extension loading while executing user-entered SQL, the following
+** API is provided to turn the extension loading mechanism on and
+** off. It is off by default. See ticket #1863.
+**
+** Call this routine with onoff==1 to turn extension loading on
+** and call it with onoff==0 to turn it back off again.
+*/
+int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
+
+/*
+****** EXPERIMENTAL - subject to change without notice **************
+**
+** The interface to the virtual-table mechanism is currently considered
+** to be experimental. The interface might change in incompatible ways.
+** If this is a problem for you, do not use the interface at this time.
+**
+** When the virtual-table mechanism stablizes, we will declare the
+** interface fixed, support it indefinitely, and remove this comment.
+*/
+
+/*
+** Structures used by the virtual table interface
+*/
+typedef struct sqlite3_vtab sqlite3_vtab;
+typedef struct sqlite3_index_info sqlite3_index_info;
+typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor;
+typedef struct sqlite3_module sqlite3_module;
+
+/*
+** A module is a class of virtual tables. Each module is defined
+** by an instance of the following structure. This structure consists
+** mostly of methods for the module.
+*/
+struct sqlite3_module {
+ int iVersion;
+ int (*xCreate)(sqlite3*, void *pAux,
+ int argc, char **argv,
+ sqlite3_vtab **ppVTab);
+ int (*xConnect)(sqlite3*, void *pAux,
+ int argc, char **argv,
+ sqlite3_vtab **ppVTab);
+ int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);
+ int (*xDisconnect)(sqlite3_vtab *pVTab);
+ int (*xDestroy)(sqlite3_vtab *pVTab);
+ int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
+ int (*xClose)(sqlite3_vtab_cursor*);
+ int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv);
+ int (*xNext)(sqlite3_vtab_cursor*);
+ int (*xEof)(sqlite3_vtab_cursor*);
+ int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int);
+ int (*xRowid)(sqlite3_vtab_cursor*, sqlite_int64 *pRowid);
+ int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite_int64 *);
+ int (*xBegin)(sqlite3_vtab *pVTab);
+ int (*xSync)(sqlite3_vtab *pVTab);
+ int (*xCommit)(sqlite3_vtab *pVTab);
+ int (*xRollback)(sqlite3_vtab *pVTab);
+ int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName,
+ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
+ void **ppArg);
+};
+
+/*
+** The sqlite3_index_info structure and its substructures is used to
+** pass information into and receive the reply from the xBestIndex
+** method of an sqlite3_module. The fields under **Inputs** are the
+** inputs to xBestIndex and are read-only. xBestIndex inserts its
+** results into the **Outputs** fields.
+**
+** The aConstraint[] array records WHERE clause constraints of the
+** form:
+**
+** column OP expr
+**
+** Where OP is =, <, <=, >, or >=. The particular operator is stored
+** in aConstraint[].op. The index of the column is stored in
+** aConstraint[].iColumn. aConstraint[].usable is TRUE if the
+** expr on the right-hand side can be evaluated (and thus the constraint
+** is usable) and false if it cannot.
+**
+** The optimizer automatically inverts terms of the form "expr OP column"
+** and makes other simplificatinos to the WHERE clause in an attempt to
+** get as many WHERE clause terms into the form shown above as possible.
+** The aConstraint[] array only reports WHERE clause terms in the correct
+** form that refer to the particular virtual table being queried.
+**
+** Information about the ORDER BY clause is stored in aOrderBy[].
+** Each term of aOrderBy records a column of the ORDER BY clause.
+**
+** The xBestIndex method must fill aConstraintUsage[] with information
+** about what parameters to pass to xFilter. If argvIndex>0 then
+** the right-hand side of the corresponding aConstraint[] is evaluated
+** and becomes the argvIndex-th entry in argv. If aConstraintUsage[].omit
+** is true, then the constraint is assumed to be fully handled by the
+** virtual table and is not checked again by SQLite.
+**
+** The idxNum and idxPtr values are recorded and passed into xFilter.
+** sqlite3_free() is used to free idxPtr if needToFreeIdxPtr is true.
+**
+** The orderByConsumed means that output from xFilter will occur in
+** the correct order to satisfy the ORDER BY clause so that no separate
+** sorting step is required.
+**
+** The estimatedCost value is an estimate of the cost of doing the
+** particular lookup. A full scan of a table with N entries should have
+** a cost of N. A binary search of a table of N entries should have a
+** cost of approximately log(N).
+*/
+struct sqlite3_index_info {
+ /* Inputs */
+ const int nConstraint; /* Number of entries in aConstraint */
+ const struct sqlite3_index_constraint {
+ int iColumn; /* Column on left-hand side of constraint */
+ unsigned char op; /* Constraint operator */
+ unsigned char usable; /* True if this constraint is usable */
+ int iTermOffset; /* Used internally - xBestIndex should ignore */
+ } *const aConstraint; /* Table of WHERE clause constraints */
+ const int nOrderBy; /* Number of terms in the ORDER BY clause */
+ const struct sqlite3_index_orderby {
+ int iColumn; /* Column number */
+ unsigned char desc; /* True for DESC. False for ASC. */
+ } *const aOrderBy; /* The ORDER BY clause */
+
+ /* Outputs */
+ struct sqlite3_index_constraint_usage {
+ int argvIndex; /* if >0, constraint is part of argv to xFilter */
+ unsigned char omit; /* Do not code a test for this constraint */
+ } *const aConstraintUsage;
+ int idxNum; /* Number used to identify the index */
+ char *idxStr; /* String, possibly obtained from sqlite3_malloc */
+ int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */
+ int orderByConsumed; /* True if output is already ordered */
+ double estimatedCost; /* Estimated cost of using this index */
+};
+#define SQLITE_INDEX_CONSTRAINT_EQ 2
+#define SQLITE_INDEX_CONSTRAINT_GT 4
+#define SQLITE_INDEX_CONSTRAINT_LE 8
+#define SQLITE_INDEX_CONSTRAINT_LT 16
+#define SQLITE_INDEX_CONSTRAINT_GE 32
+#define SQLITE_INDEX_CONSTRAINT_MATCH 64
+
+/*
+** This routine is used to register a new module name with an SQLite
+** connection. Module names must be registered before creating new
+** virtual tables on the module, or before using preexisting virtual
+** tables of the module.
+*/
+int sqlite3_create_module(
+ sqlite3 *db, /* SQLite connection to register module with */
+ const char *zName, /* Name of the module */
+ const sqlite3_module *, /* Methods for the module */
+ void * /* Client data for xCreate/xConnect */
+);
+
+/*
+** Every module implementation uses a subclass of the following structure
+** to describe a particular instance of the module. Each subclass will
+** be taylored to the specific needs of the module implementation. The
+** purpose of this superclass is to define certain fields that are common
+** to all module implementations.
+*/
+struct sqlite3_vtab {
+ const sqlite3_module *pModule; /* The module for this virtual table */
+ int nRef; /* Used internally */
+ /* Virtual table implementations will typically add additional fields */
+};
+
+/* Every module implementation uses a subclass of the following structure
+** to describe cursors that point into the virtual table and are used
+** to loop through the virtual table. Cursors are created using the
+** xOpen method of the module. Each module implementation will define
+** the content of a cursor structure to suit its own needs.
+**
+** This superclass exists in order to define fields of the cursor that
+** are common to all implementations.
+*/
+struct sqlite3_vtab_cursor {
+ sqlite3_vtab *pVtab; /* Virtual table of this cursor */
+ /* Virtual table implementations will typically add additional fields */
+};
+
+/*
+** The xCreate and xConnect methods of a module use the following API
+** to declare the format (the names and datatypes of the columns) of
+** the virtual tables they implement.
+*/
+int sqlite3_declare_vtab(sqlite3*, const char *zCreateTable);
+
+/*
+** The interface to the virtual-table mechanism defined above (back up
+** to a comment remarkably similar to this one) is currently considered
+** to be experimental. The interface might change in incompatible ways.
+** If this is a problem for you, do not use the interface at this time.
+**
+** When the virtual-table mechanism stablizes, we will declare the
+** interface fixed, support it indefinitely, and remove this comment.
+**
+****** EXPERIMENTAL - subject to change without notice **************
+*/
+
+/*
+** Undo the hack that converts floating point types to integer for
+** builds on processors without floating point support.
+*/
+#ifdef SQLITE_OMIT_FLOATING_POINT
+# undef double
+#endif
+
#ifdef __cplusplus
} /* End of the 'extern "C"' block */
#endif
diff --git a/ext/pdo_sqlite/sqlite/src/sqlite3ext.h b/ext/pdo_sqlite/sqlite/src/sqlite3ext.h
new file mode 100644
index 0000000000..9b3dae7407
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/sqlite3ext.h
@@ -0,0 +1,280 @@
+/*
+** 2006 June 7
+**
+** 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 header file defines the SQLite interface for use by
+** shared libraries that want to be imported as extensions into
+** an SQLite instance. Shared libraries that intend to be loaded
+** as extensions by SQLite should #include this file instead of
+** sqlite3.h.
+**
+** @(#) $Id$
+*/
+#ifndef _SQLITE3EXT_H_
+#define _SQLITE3EXT_H_
+#include <sqlite3.h>
+
+typedef struct sqlite3_api_routines sqlite3_api_routines;
+
+/*
+** The following structure hold pointers to all of the SQLite API
+** routines.
+*/
+struct sqlite3_api_routines {
+ void * (*aggregate_context)(sqlite3_context*,int nBytes);
+ int (*aggregate_count)(sqlite3_context*);
+ int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
+ int (*bind_double)(sqlite3_stmt*,int,double);
+ int (*bind_int)(sqlite3_stmt*,int,int);
+ int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
+ int (*bind_null)(sqlite3_stmt*,int);
+ int (*bind_parameter_count)(sqlite3_stmt*);
+ int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
+ const char * (*bind_parameter_name)(sqlite3_stmt*,int);
+ int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
+ int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
+ int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
+ int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
+ int (*busy_timeout)(sqlite3*,int ms);
+ int (*changes)(sqlite3*);
+ int (*close)(sqlite3*);
+ int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const char*));
+ int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const void*));
+ const void * (*column_blob)(sqlite3_stmt*,int iCol);
+ int (*column_bytes)(sqlite3_stmt*,int iCol);
+ int (*column_bytes16)(sqlite3_stmt*,int iCol);
+ int (*column_count)(sqlite3_stmt*pStmt);
+ const char * (*column_database_name)(sqlite3_stmt*,int);
+ const void * (*column_database_name16)(sqlite3_stmt*,int);
+ const char * (*column_decltype)(sqlite3_stmt*,int i);
+ const void * (*column_decltype16)(sqlite3_stmt*,int);
+ double (*column_double)(sqlite3_stmt*,int iCol);
+ int (*column_int)(sqlite3_stmt*,int iCol);
+ sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
+ const char * (*column_name)(sqlite3_stmt*,int);
+ const void * (*column_name16)(sqlite3_stmt*,int);
+ const char * (*column_origin_name)(sqlite3_stmt*,int);
+ const void * (*column_origin_name16)(sqlite3_stmt*,int);
+ const char * (*column_table_name)(sqlite3_stmt*,int);
+ const void * (*column_table_name16)(sqlite3_stmt*,int);
+ const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
+ const void * (*column_text16)(sqlite3_stmt*,int iCol);
+ int (*column_type)(sqlite3_stmt*,int iCol);
+ sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
+ void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
+ int (*complete)(const char*sql);
+ int (*complete16)(const void*sql);
+ int (*create_collation)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*));
+ int (*create_collation16)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*));
+ int (*create_function)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
+ int (*create_function16)(sqlite3*,const void*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
+ int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
+ int (*data_count)(sqlite3_stmt*pStmt);
+ sqlite3 * (*db_handle)(sqlite3_stmt*);
+ int (*declare_vtab)(sqlite3*,const char*);
+ int (*enable_shared_cache)(int);
+ int (*errcode)(sqlite3*db);
+ const char * (*errmsg)(sqlite3*);
+ const void * (*errmsg16)(sqlite3*);
+ int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
+ int (*expired)(sqlite3_stmt*);
+ int (*finalize)(sqlite3_stmt*pStmt);
+ void (*free)(void*);
+ void (*free_table)(char**result);
+ int (*get_autocommit)(sqlite3*);
+ void * (*get_auxdata)(sqlite3_context*,int);
+ int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
+ int (*global_recover)(void);
+ void (*interrupt)(sqlite3*);
+ sqlite_int64 (*last_insert_rowid)(sqlite3*);
+ const char * (*libversion)(void);
+ int (*libversion_number)(void);
+ void *(*malloc)(int);
+ char * (*mprintf)(const char*,...);
+ int (*open)(const char*,sqlite3**);
+ int (*open16)(const void*,sqlite3**);
+ int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
+ int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
+ void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
+ void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
+ void *(*realloc)(void*,int);
+ int (*reset)(sqlite3_stmt*pStmt);
+ void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
+ void (*result_double)(sqlite3_context*,double);
+ void (*result_error)(sqlite3_context*,const char*,int);
+ void (*result_error16)(sqlite3_context*,const void*,int);
+ void (*result_int)(sqlite3_context*,int);
+ void (*result_int64)(sqlite3_context*,sqlite_int64);
+ void (*result_null)(sqlite3_context*);
+ void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
+ void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
+ void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
+ void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
+ void (*result_value)(sqlite3_context*,sqlite3_value*);
+ void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
+ int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,const char*,const char*),void*);
+ void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
+ char * (*snprintf)(int,char*,const char*,...);
+ int (*step)(sqlite3_stmt*);
+ int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,char const**,char const**,int*,int*,int*);
+ void (*thread_cleanup)(void);
+ int (*total_changes)(sqlite3*);
+ void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
+ int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
+ void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,sqlite_int64),void*);
+ void * (*user_data)(sqlite3_context*);
+ const void * (*value_blob)(sqlite3_value*);
+ int (*value_bytes)(sqlite3_value*);
+ int (*value_bytes16)(sqlite3_value*);
+ double (*value_double)(sqlite3_value*);
+ int (*value_int)(sqlite3_value*);
+ sqlite_int64 (*value_int64)(sqlite3_value*);
+ int (*value_numeric_type)(sqlite3_value*);
+ const unsigned char * (*value_text)(sqlite3_value*);
+ const void * (*value_text16)(sqlite3_value*);
+ const void * (*value_text16be)(sqlite3_value*);
+ const void * (*value_text16le)(sqlite3_value*);
+ int (*value_type)(sqlite3_value*);
+ char * (*vmprintf)(const char*,va_list);
+};
+
+/*
+** The following macros redefine the API routines so that they are
+** redirected throught the global sqlite3_api structure.
+**
+** This header file is also used by the loadext.c source file
+** (part of the main SQLite library - not an extension) so that
+** it can get access to the sqlite3_api_routines structure
+** definition. But the main library does not want to redefine
+** the API. So the redefinition macros are only valid if the
+** SQLITE_CORE macros is undefined.
+*/
+#ifndef SQLITE_CORE
+#define sqlite3_aggregate_context sqlite3_api->aggregate_context
+#define sqlite3_aggregate_count sqlite3_api->aggregate_count
+#define sqlite3_bind_blob sqlite3_api->bind_blob
+#define sqlite3_bind_double sqlite3_api->bind_double
+#define sqlite3_bind_int sqlite3_api->bind_int
+#define sqlite3_bind_int64 sqlite3_api->bind_int64
+#define sqlite3_bind_null sqlite3_api->bind_null
+#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
+#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
+#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
+#define sqlite3_bind_text sqlite3_api->bind_text
+#define sqlite3_bind_text16 sqlite3_api->bind_text16
+#define sqlite3_bind_value sqlite3_api->bind_value
+#define sqlite3_busy_handler sqlite3_api->busy_handler
+#define sqlite3_busy_timeout sqlite3_api->busy_timeout
+#define sqlite3_changes sqlite3_api->changes
+#define sqlite3_close sqlite3_api->close
+#define sqlite3_collation_needed sqlite3_api->collation_needed
+#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
+#define sqlite3_column_blob sqlite3_api->column_blob
+#define sqlite3_column_bytes sqlite3_api->column_bytes
+#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
+#define sqlite3_column_count sqlite3_api->column_count
+#define sqlite3_column_database_name sqlite3_api->column_database_name
+#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
+#define sqlite3_column_decltype sqlite3_api->column_decltype
+#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
+#define sqlite3_column_double sqlite3_api->column_double
+#define sqlite3_column_int sqlite3_api->column_int
+#define sqlite3_column_int64 sqlite3_api->column_int64
+#define sqlite3_column_name sqlite3_api->column_name
+#define sqlite3_column_name16 sqlite3_api->column_name16
+#define sqlite3_column_origin_name sqlite3_api->column_origin_name
+#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
+#define sqlite3_column_table_name sqlite3_api->column_table_name
+#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
+#define sqlite3_column_text sqlite3_api->column_text
+#define sqlite3_column_text16 sqlite3_api->column_text16
+#define sqlite3_column_type sqlite3_api->column_type
+#define sqlite3_column_value sqlite3_api->column_value
+#define sqlite3_commit_hook sqlite3_api->commit_hook
+#define sqlite3_complete sqlite3_api->complete
+#define sqlite3_complete16 sqlite3_api->complete16
+#define sqlite3_create_collation sqlite3_api->create_collation
+#define sqlite3_create_collation16 sqlite3_api->create_collation16
+#define sqlite3_create_function sqlite3_api->create_function
+#define sqlite3_create_function16 sqlite3_api->create_function16
+#define sqlite3_create_module sqlite3_api->create_module
+#define sqlite3_data_count sqlite3_api->data_count
+#define sqlite3_db_handle sqlite3_api->db_handle
+#define sqlite3_declare_vtab sqlite3_api->declare_vtab
+#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
+#define sqlite3_errcode sqlite3_api->errcode
+#define sqlite3_errmsg sqlite3_api->errmsg
+#define sqlite3_errmsg16 sqlite3_api->errmsg16
+#define sqlite3_exec sqlite3_api->exec
+#define sqlite3_expired sqlite3_api->expired
+#define sqlite3_finalize sqlite3_api->finalize
+#define sqlite3_free sqlite3_api->free
+#define sqlite3_free_table sqlite3_api->free_table
+#define sqlite3_get_autocommit sqlite3_api->get_autocommit
+#define sqlite3_get_auxdata sqlite3_api->get_auxdata
+#define sqlite3_get_table sqlite3_api->get_table
+#define sqlite3_global_recover sqlite3_api->global_recover
+#define sqlite3_interrupt sqlite3_api->interrupt
+#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
+#define sqlite3_libversion sqlite3_api->libversion
+#define sqlite3_libversion_number sqlite3_api->libversion_number
+#define sqlite3_malloc sqlite3_api->malloc
+#define sqlite3_mprintf sqlite3_api->mprintf
+#define sqlite3_open sqlite3_api->open
+#define sqlite3_open16 sqlite3_api->open16
+#define sqlite3_prepare sqlite3_api->prepare
+#define sqlite3_prepare16 sqlite3_api->prepare16
+#define sqlite3_profile sqlite3_api->profile
+#define sqlite3_progress_handler sqlite3_api->progress_handler
+#define sqlite3_realloc sqlite3_api->realloc
+#define sqlite3_reset sqlite3_api->reset
+#define sqlite3_result_blob sqlite3_api->result_blob
+#define sqlite3_result_double sqlite3_api->result_double
+#define sqlite3_result_error sqlite3_api->result_error
+#define sqlite3_result_error16 sqlite3_api->result_error16
+#define sqlite3_result_int sqlite3_api->result_int
+#define sqlite3_result_int64 sqlite3_api->result_int64
+#define sqlite3_result_null sqlite3_api->result_null
+#define sqlite3_result_text sqlite3_api->result_text
+#define sqlite3_result_text16 sqlite3_api->result_text16
+#define sqlite3_result_text16be sqlite3_api->result_text16be
+#define sqlite3_result_text16le sqlite3_api->result_text16le
+#define sqlite3_result_value sqlite3_api->result_value
+#define sqlite3_rollback_hook sqlite3_api->rollback_hook
+#define sqlite3_set_authorizer sqlite3_api->set_authorizer
+#define sqlite3_set_auxdata sqlite3_api->set_auxdata
+#define sqlite3_snprintf sqlite3_api->snprintf
+#define sqlite3_step sqlite3_api->step
+#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
+#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
+#define sqlite3_total_changes sqlite3_api->total_changes
+#define sqlite3_trace sqlite3_api->trace
+#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
+#define sqlite3_update_hook sqlite3_api->update_hook
+#define sqlite3_user_data sqlite3_api->user_data
+#define sqlite3_value_blob sqlite3_api->value_blob
+#define sqlite3_value_bytes sqlite3_api->value_bytes
+#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
+#define sqlite3_value_double sqlite3_api->value_double
+#define sqlite3_value_int sqlite3_api->value_int
+#define sqlite3_value_int64 sqlite3_api->value_int64
+#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
+#define sqlite3_value_text sqlite3_api->value_text
+#define sqlite3_value_text16 sqlite3_api->value_text16
+#define sqlite3_value_text16be sqlite3_api->value_text16be
+#define sqlite3_value_text16le sqlite3_api->value_text16le
+#define sqlite3_value_type sqlite3_api->value_type
+#define sqlite3_vmprintf sqlite3_api->vmprintf
+#endif /* SQLITE_CORE */
+
+#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api;
+#define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v;
+
+#endif /* _SQLITE3EXT_H_ */
diff --git a/ext/pdo_sqlite/sqlite/src/sqliteInt.h b/ext/pdo_sqlite/sqlite/src/sqliteInt.h
index 1635369c4a..58e21c4f3c 100644
--- a/ext/pdo_sqlite/sqlite/src/sqliteInt.h
+++ b/ext/pdo_sqlite/sqlite/src/sqliteInt.h
@@ -17,6 +17,13 @@
#define _SQLITEINT_H_
/*
+** Extra interface definitions for those who need them
+*/
+#ifdef SQLITE_EXTRA
+# include "sqliteExtra.h"
+#endif
+
+/*
** Many people are failing to set -DNDEBUG=1 when compiling SQLite.
** Setting NDEBUG makes the code smaller and run faster. So the following
** lines are added to automatically set NDEBUG unless the -DSQLITE_DEBUG=1
@@ -60,6 +67,23 @@
#include <stddef.h>
/*
+** If compiling for a processor that lacks floating point support,
+** substitute integer for floating-point
+*/
+#ifdef SQLITE_OMIT_FLOATING_POINT
+# define double sqlite_int64
+# define LONGDOUBLE_TYPE sqlite_int64
+# ifndef SQLITE_BIG_DBL
+# define SQLITE_BIG_DBL (0x7fffffffffffffff)
+# endif
+# define SQLITE_OMIT_DATETIME_FUNCS 1
+# define SQLITE_OMIT_TRACE 1
+#endif
+#ifndef SQLITE_BIG_DBL
+# define SQLITE_BIG_DBL (1e99)
+#endif
+
+/*
** The maximum number of in-memory pages to use for the main database
** table and for temporary tables. Internally, the MAX_PAGES and
** TEMP_PAGES macros are used. To override the default values at
@@ -90,18 +114,6 @@
/*
** If the following macro is set to 1, then NULL values are considered
-** distinct for the SELECT DISTINCT statement and for UNION or EXCEPT
-** compound queries. No other SQL database engine (among those tested)
-** works this way except for OCELOT. But the SQL92 spec implies that
-** this is how things should work.
-**
-** If the following macro is set to 0, then NULLs are indistinct for
-** SELECT DISTINCT and for UNION.
-*/
-#define NULL_ALWAYS_DISTINCT 0
-
-/*
-** If the following macro is set to 1, then NULL values are considered
** distinct when determining whether or not two entries are the same
** in a UNIQUE index. This is the way PostgreSQL, Oracle, DB2, MySQL,
** OCELOT, and Firebird all work. The SQL92 spec explicitly says this
@@ -129,18 +141,15 @@
#define SQLITE_MAX_VARIABLE_NUMBER 999
/*
-** When building SQLite for embedded systems where memory is scarce,
-** you can define one or more of the following macros to omit extra
-** features of the library and thus keep the size of the library to
-** a minimum.
+** The "file format" number is an integer that is incremented whenever
+** the VDBE-level file format changes. The following macros define the
+** the default file format for new databases and the maximum file format
+** that the library can read.
*/
-/* #define SQLITE_OMIT_AUTHORIZATION 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 */
+#define SQLITE_MAX_FILE_FORMAT 4
+#ifndef SQLITE_DEFAULT_FILE_FORMAT
+# define SQLITE_DEFAULT_FILE_FORMAT 1
+#endif
/*
** Provide a default value for TEMP_STORE in case it is not specified
@@ -159,19 +168,22 @@
#endif
/*
+** Check to see if this machine uses EBCDIC. (Yes, believe it or
+** not, there are still machines out there that use EBCDIC.)
+*/
+#if 'A' == '\301'
+# define SQLITE_EBCDIC 1
+#else
+# define SQLITE_ASCII 1
+#endif
+
+/*
** Integers of known sizes. These typedefs might change for architectures
** where the sizes very. Preprocessor macros are available so that the
** types can be conveniently redefined at compile-type. Like this:
**
** cc '-DUINTPTR_TYPE=long long int' ...
*/
-#ifndef UINT64_TYPE
-# if defined(_MSC_VER) || defined(__BORLANDC__)
-# define UINT64_TYPE unsigned __int64
-# else
-# define UINT64_TYPE unsigned long long int
-# endif
-#endif
#ifndef UINT32_TYPE
# define UINT32_TYPE unsigned int
#endif
@@ -191,7 +203,7 @@
# define LONGDOUBLE_TYPE long double
#endif
typedef sqlite_int64 i64; /* 8-byte signed integer */
-typedef UINT64_TYPE u64; /* 8-byte unsigned integer */
+typedef sqlite_uint64 u64; /* 8-byte unsigned integer */
typedef UINT32_TYPE u32; /* 4-byte unsigned integer */
typedef UINT16_TYPE u16; /* 2-byte unsigned integer */
typedef INT16_TYPE i16; /* 2-byte signed integer */
@@ -228,59 +240,67 @@ struct BusyHandler {
*/
#include "vdbe.h"
#include "btree.h"
+#include "pager.h"
+#ifdef SQLITE_MEMDEBUG
/*
-** This macro casts a pointer to an integer. Useful for doing
-** pointer arithmetic.
+** The following global variables are used for testing and debugging
+** only. They only work if SQLITE_MEMDEBUG is defined.
*/
-#define Addr(X) ((uptr)X)
+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 */
+
+extern void *sqlite3_pFirst; /* Pointer to linked list of allocations */
+extern int sqlite3_nMaxAlloc; /* High water mark of ThreadData.nAlloc */
+extern int sqlite3_mallocDisallowed; /* assert() in sqlite3Malloc() if set */
+extern int sqlite3_isFail; /* True if all malloc calls should fail */
+extern const char *sqlite3_zFile; /* Filename to associate debug info with */
+extern int sqlite3_iLine; /* Line number for debug info */
+
+#define ENTER_MALLOC (sqlite3_zFile = __FILE__, sqlite3_iLine = __LINE__)
+#define sqliteMalloc(x) (ENTER_MALLOC, sqlite3Malloc(x,1))
+#define sqliteMallocRaw(x) (ENTER_MALLOC, sqlite3MallocRaw(x,1))
+#define sqliteRealloc(x,y) (ENTER_MALLOC, sqlite3Realloc(x,y))
+#define sqliteStrDup(x) (ENTER_MALLOC, sqlite3StrDup(x))
+#define sqliteStrNDup(x,y) (ENTER_MALLOC, sqlite3StrNDup(x,y))
+#define sqliteReallocOrFree(x,y) (ENTER_MALLOC, sqlite3ReallocOrFree(x,y))
-/*
-** If memory allocation problems are found, recompile with
-**
-** -DSQLITE_DEBUG=1
-**
-** to enable some sanity checking on malloc() and free(). To
-** check for memory leaks, recompile with
-**
-** -DSQLITE_DEBUG=2
-**
-** and a line of text will be written to standard error for
-** each malloc() and free(). This output can be analyzed
-** by an AWK script to determine if there are any leaks.
-*/
-#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__)
-# define sqliteRealloc(X,Y) sqlite3Realloc_(X,Y,__FILE__,__LINE__)
-# define sqliteStrDup(X) sqlite3StrDup_(X,__FILE__,__LINE__)
-# define sqliteStrNDup(X,Y) sqlite3StrNDup_(X,Y,__FILE__,__LINE__)
#else
-# define sqliteFree sqlite3FreeX
-# define sqliteMalloc sqlite3Malloc
-# define sqliteMallocRaw sqlite3MallocRaw
-# define sqliteRealloc sqlite3Realloc
-# define sqliteStrDup sqlite3StrDup
-# define sqliteStrNDup sqlite3StrNDup
+
+#define ENTER_MALLOC 0
+#define sqliteMalloc(x) sqlite3Malloc(x,1)
+#define sqliteMallocRaw(x) sqlite3MallocRaw(x,1)
+#define sqliteRealloc(x,y) sqlite3Realloc(x,y)
+#define sqliteStrDup(x) sqlite3StrDup(x)
+#define sqliteStrNDup(x,y) sqlite3StrNDup(x,y)
+#define sqliteReallocOrFree(x,y) sqlite3ReallocOrFree(x,y)
+
#endif
-/*
-** This variable gets set if malloc() ever fails. After it gets set,
-** the SQLite library shuts down permanently.
-*/
-extern int sqlite3_malloc_failed;
+#define sqliteFree(x) sqlite3FreeX(x)
+#define sqliteAllocSize(x) sqlite3AllocSize(x)
+
/*
-** The following global variables are used for testing and debugging
-** only. They only work if SQLITE_DEBUG is defined.
+** An instance of this structure might be allocated to store information
+** specific to a single thread.
*/
-#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 */
+struct ThreadData {
+ int dummy; /* So that this structure is never empty */
+
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ int nSoftHeapLimit; /* Suggested max mem allocation. No limit if <0 */
+ int nAlloc; /* Number of bytes currently allocated */
+ Pager *pPager; /* Linked list of all pagers in this thread */
+#endif
+
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ u8 useSharedData; /* True if shared pagers and schemas are enabled */
+ BtShared *pBtree; /* Linked list of all currently open BTrees */
#endif
+};
/*
** Name of the master database table. The master database table
@@ -314,6 +334,7 @@ typedef struct AuthContext AuthContext;
typedef struct CollSeq CollSeq;
typedef struct Column Column;
typedef struct Db Db;
+typedef struct Schema Schema;
typedef struct Expr Expr;
typedef struct ExprList ExprList;
typedef struct FKey FKey;
@@ -322,11 +343,14 @@ typedef struct IdList IdList;
typedef struct Index Index;
typedef struct KeyClass KeyClass;
typedef struct KeyInfo KeyInfo;
+typedef struct Module Module;
typedef struct NameContext NameContext;
typedef struct Parse Parse;
typedef struct Select Select;
typedef struct SrcList SrcList;
+typedef struct ThreadData ThreadData;
typedef struct Table Table;
+typedef struct TableLock TableLock;
typedef struct Token Token;
typedef struct TriggerStack TriggerStack;
typedef struct TriggerStep TriggerStep;
@@ -344,28 +368,37 @@ typedef struct WhereLevel WhereLevel;
struct Db {
char *zName; /* Name of this database */
Btree *pBt; /* The B*Tree structure for this database file */
+ u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */
+ u8 safety_level; /* How aggressive at synching data to disk */
+ void *pAux; /* Auxiliary data. Usually NULL */
+ void (*xFreeAux)(void*); /* Routine to free pAux */
+ Schema *pSchema; /* Pointer to database schema (possibly shared) */
+};
+
+/*
+** An instance of the following structure stores a database schema.
+*/
+struct Schema {
int schema_cookie; /* Database schema version number for this file */
Hash tblHash; /* All tables indexed by name */
Hash idxHash; /* All (named) indices indexed by name */
Hash trigHash; /* All triggers indexed by name */
Hash aFKey; /* Foreign keys indexed by to-table */
- u16 flags; /* Flags associated with this database */
- 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 */
Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */
- void *pAux; /* Auxiliary data. Usually NULL */
- void (*xFreeAux)(void*); /* Routine to free pAux */
+ u8 file_format; /* Schema format version for this file */
+ u8 enc; /* Text encoding used by this database */
+ u16 flags; /* Flags associated with this schema */
+ int cache_size; /* Number of pages to use in the cache */
};
/*
** These macros can be used to test, set, or clear bits in the
** Db.flags field.
*/
-#define DbHasProperty(D,I,P) (((D)->aDb[I].flags&(P))==(P))
-#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].flags&(P))!=0)
-#define DbSetProperty(D,I,P) (D)->aDb[I].flags|=(P)
-#define DbClearProperty(D,I,P) (D)->aDb[I].flags&=~(P)
+#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))==(P))
+#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))!=0)
+#define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->flags|=(P)
+#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->flags&=~(P)
/*
** Allowed values for the DB.flags field.
@@ -379,6 +412,7 @@ struct Db {
*/
#define DB_SchemaLoaded 0x0001 /* The schema has been loaded */
#define DB_UnresetViews 0x0002 /* Some views have defined column names */
+#define DB_Empty 0x0004 /* The file is empty (length 0 bytes) */
#define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
@@ -413,9 +447,7 @@ struct sqlite3 {
Db *aDb; /* All backends */
int flags; /* Miscellanous flags. See below */
int errCode; /* Most recent error code (SQLITE_*) */
- u8 enc; /* Text encoding for this database. */
u8 autoCommit; /* The auto-commit flag. */
- u8 file_format; /* What file format version is this database? */
u8 temp_store; /* 1: file 2: memory 0: default */
int nTable; /* Number of tables in the database */
CollSeq *pDfltColl; /* The default collating sequence (BINARY) */
@@ -429,21 +461,30 @@ struct sqlite3 {
int newTnum; /* Rootpage of table being initialized */
u8 busy; /* TRUE if currently initializing */
} init;
+ int nExtension; /* Number of loaded extensions */
+ void *aExtension; /* Array of shared libraray handles */
struct Vdbe *pVdbe; /* List of active virtual machines */
int activeVdbeCnt; /* Number of vdbes currently executing */
void (*xTrace)(void*,const char*); /* Trace function */
void *pTraceArg; /* Argument to the trace function */
void (*xProfile)(void*,const char*,u64); /* Profiling function */
void *pProfileArg; /* Argument to profile function */
- void *pCommitArg; /* Argument to xCommitCallback() */
- int (*xCommitCallback)(void*);/* Invoked at every commit. */
+ void *pCommitArg; /* Argument to xCommitCallback() */
+ int (*xCommitCallback)(void*); /* Invoked at every commit. */
+ void *pRollbackArg; /* Argument to xRollbackCallback() */
+ void (*xRollbackCallback)(void*); /* Invoked at every commit. */
+ void *pUpdateArg;
+ void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64);
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*);
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-16 encoded) */
+ union {
+ int isInterrupted; /* True if sqlite3_interrupt has been called */
+ double notUsed1; /* Spacer */
+ } u1;
#ifndef SQLITE_OMIT_AUTHORIZATION
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
/* Access authorization function */
@@ -454,13 +495,16 @@ struct sqlite3 {
void *pProgressArg; /* Argument to the progress callback */
int nProgressOps; /* Number of opcodes for progress callback */
#endif
-#ifndef SQLITE_OMIT_GLOBALRECOVER
- sqlite3 *pNext; /* Linked list of open db handles. */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ Hash aModule; /* populated by sqlite3_create_module() */
+ Table *pVTab; /* vtab with active Connect/Create method */
+ sqlite3_vtab **aVTrans; /* Virtual tables with open transactions */
+ int nVTrans; /* Allocated size of aVTrans */
#endif
Hash aFunc; /* All functions that can be in SQL exprs */
Hash aCollSeq; /* All collating sequences */
BusyHandler busyHandler; /* Busy callback */
- int busyTimeout; /* Busy handler timeout, in msec */
+ int busyTimeout; /* Busy handler timeout, in msec */
Db aDbStatic[2]; /* Static space for the 2 default backends */
#ifdef SQLITE_SSE
sqlite3_stmt *pFetch; /* Used by SSE to fetch stored statements */
@@ -468,6 +512,11 @@ struct sqlite3 {
};
/*
+** A macro to discover the encoding of a database.
+*/
+#define ENC(db) ((db)->aDb[0].pSchema->enc)
+
+/*
** Possible values for the sqlite.flags and or Db.flags fields.
**
** On sqlite.flags, the SQLITE_InTrans value means that we have
@@ -475,8 +524,6 @@ struct sqlite3 {
** transaction is active on that particular database file.
*/
#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
-#define SQLITE_Initialized 0x00000002 /* True after initialization */
-#define SQLITE_Interrupt 0x00000004 /* Cancel current operation */
#define SQLITE_InTrans 0x00000008 /* True if in a transaction */
#define SQLITE_InternChanges 0x00000010 /* Uncommitted Hash table changes */
#define SQLITE_FullColNames 0x00000020 /* Show full column names on SELECT */
@@ -491,6 +538,11 @@ struct sqlite3 {
#define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */
#define SQLITE_NoReadlock 0x00001000 /* Readlocks are omitted when
** accessing read-only databases */
+#define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */
+#define SQLITE_ReadUncommitted 0x00004000 /* For shared-cache mode */
+#define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */
+#define SQLITE_FullFSync 0x00010000 /* Use full fsync on the backend */
+#define SQLITE_LoadExtension 0x00020000 /* Enable load_extension */
/*
** Possible values for the sqlite.magic field.
@@ -522,10 +574,22 @@ struct FuncDef {
};
/*
+** Each SQLite module (virtual table definition) is defined by an
+** instance of the following structure, stored in the sqlite3.aModule
+** hash table.
+*/
+struct Module {
+ const sqlite3_module *pModule; /* Callback pointers */
+ const char *zName; /* Name passed to create_module() */
+ void *pAux; /* pAux passed to create_module() */
+};
+
+/*
** Possible values for FuncDef.flags
*/
#define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */
#define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */
+#define SQLITE_FUNC_EPHEM 0x04 /* Ephermeral. Delete with VDBE */
/*
** information about each column of an SQL table is held in an instance
@@ -535,7 +599,7 @@ struct Column {
char *zName; /* Name 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 */
+ char *zColl; /* Collating sequence. If NULL, use the default */
u8 notNull; /* True if there is a NOT NULL constraint */
u8 isPrimKey; /* True if this column is part of the PRIMARY KEY */
char affinity; /* One of the SQLITE_AFF_... values */
@@ -551,7 +615,7 @@ struct Column {
** processes text encoded in UTF-16 (CollSeq.xCmp16), using the machine
** native byte order. When a collation sequence is invoked, SQLite selects
** the version that will require the least expensive encoding
-** transalations, if any.
+** translations, if any.
**
** The CollSeq.pUser member variable is an extra parameter that passed in
** as the first argument to the UTF-8 comparison function, xCmp.
@@ -586,12 +650,25 @@ struct CollSeq {
/*
** Column affinity types.
+**
+** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and
+** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve
+** the speed a little by number the values consecutively.
+**
+** But rather than start with 0 or 1, we begin with 'a'. That way,
+** when multiple affinity types are concatenated into a string and
+** used as the P3 operand, they will be more readable.
+**
+** Note also that the numeric types are grouped together so that testing
+** for a numeric type is a single comparison.
*/
-#define SQLITE_AFF_INTEGER 'i'
-#define SQLITE_AFF_NUMERIC 'n'
-#define SQLITE_AFF_TEXT 't'
-#define SQLITE_AFF_NONE 'o'
+#define SQLITE_AFF_TEXT 'a'
+#define SQLITE_AFF_NONE 'b'
+#define SQLITE_AFF_NUMERIC 'c'
+#define SQLITE_AFF_INTEGER 'd'
+#define SQLITE_AFF_REAL 'e'
+#define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC)
/*
** Each SQL table is represented in memory by an instance of the
@@ -615,7 +692,7 @@ struct CollSeq {
** Table.tnum is the page number for the root BTree page of the table in the
** database file. If Table.iDb is the index of the database table backend
** in sqlite.aDb[]. 0 is for the main database and 1 is for the file that
-** holds temporary tables and indices. If Table.isTransient
+** holds temporary tables and indices. If Table.isEphem
** is true, then the table is stored in a file that is automatically deleted
** when the VDBE cursor to the table is closed. In this case Table.tnum
** refers VDBE cursor number that holds the table open, not to the root
@@ -631,22 +708,44 @@ struct Table {
Index *pIndex; /* List of SQL indexes on this table. */
int tnum; /* Root BTree node for this table (see note above) */
Select *pSelect; /* NULL for tables. Points to definition if a view. */
- u8 readOnly; /* True if this table should not be written by the user */
- u8 iDb; /* Index into sqlite.aDb[] of the backend for this 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 */
int nRef; /* Number of pointers to this Table */
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 */
+#ifndef SQLITE_OMIT_CHECK
+ Expr *pCheck; /* The AND of all CHECK constraints */
+#endif
#ifndef SQLITE_OMIT_ALTERTABLE
int addColOffset; /* Offset in CREATE TABLE statement to add a new column */
#endif
+ u8 readOnly; /* True if this table should not be written by the user */
+ u8 isEphem; /* True if created using OP_OpenEphermeral */
+ 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 */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ u8 isVirtual; /* True if this is a virtual table */
+ u8 isCommit; /* True once the CREATE TABLE has been committed */
+ Module *pMod; /* Pointer to the implementation of the module */
+ sqlite3_vtab *pVtab; /* Pointer to the module instance */
+ int nModuleArg; /* Number of arguments to the module */
+ char **azModuleArg; /* Text of all module args. [0] is module name */
+#endif
+ Schema *pSchema;
};
/*
+** Test to see whether or not a table is a virtual table. This is
+** done as a macro so that it will be optimized out when virtual
+** table support is omitted from the build.
+*/
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+# define IsVirtual(X) ((X)->isVirtual)
+#else
+# define IsVirtual(X) 0
+#endif
+
+/*
** Each foreign key constraint is an instance of the following structure.
**
** A foreign key is associated with two tables. The "from" table is
@@ -779,10 +878,11 @@ struct Index {
int tnum; /* Page containing root of this index in database file */
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */
- u8 iDb; /* Index in sqlite.aDb[] of where this index is stored */
char *zColAff; /* String defining the affinity of each column */
Index *pNext; /* The next index associated with the same table */
- KeyInfo keyInfo; /* Info on how to order keys. MUST BE LAST */
+ Schema *pSchema; /* Schema containing this index */
+ u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */
+ char **azColl; /* Array of collation sequence names for index */
};
/*
@@ -836,7 +936,7 @@ struct AggInfo {
Expr *pExpr; /* Expression encoding the function */
FuncDef *pFunc; /* The aggregate function implementation */
int iMem; /* Memory location that acts as accumulator */
- int iDistinct; /* Virtual table used to enforce DISTINCT */
+ int iDistinct; /* Ephermeral table used to enforce DISTINCT */
} *aFunc;
int nFunc; /* Number of entries in aFunc[] */
int nFuncAlloc; /* Number of slots allocated for aFunc[] */
@@ -891,8 +991,7 @@ struct AggInfo {
struct Expr {
u8 op; /* Operation performed by this node */
char affinity; /* The affinity of the column or 0 if not a column */
- u8 iDb; /* Database referenced by this expression */
- u8 flags; /* Various flags. See below */
+ u16 flags; /* Various flags. See below */
CollSeq *pColl; /* The collation type of the column or 0 */
Expr *pLeft, *pRight; /* Left and right subnodes */
ExprList *pList; /* A list of expressions used as function arguments
@@ -907,6 +1006,7 @@ struct Expr {
Select *pSelect; /* When the expression is a sub-select. Also the
** right side of "<expr> IN (<select>)" */
Table *pTab; /* Table for OP_Column expressions. */
+ Schema *pSchema;
};
/*
@@ -919,6 +1019,7 @@ struct Expr {
#define EP_Distinct 0x10 /* Aggregate function with DISTINCT keyword */
#define EP_VarSelect 0x20 /* pSelect is correlated, not constant */
#define EP_Dequoted 0x40 /* True if the string has been dequoted */
+#define EP_InfixFunc 0x80 /* True for an infix function: LIKE, GLOB, etc */
/*
** These macros can be used to test, set, or clear bits in the
@@ -999,6 +1100,7 @@ struct SrcList {
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
Table *pTab; /* An SQL table corresponding to zName */
Select *pSelect; /* A SELECT statement used in place of a table name */
+ u8 isPopulated; /* Temporary table associated with SELECT is populated */
u8 jointype; /* Type of join between this table and the next */
i16 iCursor; /* The VDBE cursor number used to access this table */
Expr *pOn; /* The ON clause of a join */
@@ -1023,6 +1125,19 @@ struct SrcList {
** structure contains a single instance of this structure. This structure
** is intended to be private the the where.c module and should not be
** access or modified by other modules.
+**
+** The pIdxInfo and pBestIdx fields are used to help pick the best
+** index on a virtual table. The pIdxInfo pointer contains indexing
+** information for the i-th table in the FROM clause before reordering.
+** All the pIdxInfo pointers are freed by whereInfoFree() in where.c.
+** The pBestIdx pointer is a copy of pIdxInfo for the i-th table after
+** FROM clause ordering. This is a little confusing so I will repeat
+** it in different words. WhereInfo.a[i].pIdxInfo is index information
+** for WhereInfo.pTabList.a[i]. WhereInfo.a[i].pBestInfo is the
+** index information for the i-th loop of the join. pBestInfo is always
+** either NULL or a copy of some pIdxInfo. So for cleanup it is
+** sufficient to free all of the pIdxInfo pointers.
+**
*/
struct WhereLevel {
int iFrom; /* Which entry in the FROM clause */
@@ -1039,6 +1154,13 @@ struct WhereLevel {
int nEq; /* Number of == or IN constraints on this loop */
int nIn; /* Number of IN operators constraining this loop */
int *aInLoop; /* Loop terminators for IN operators */
+ sqlite3_index_info *pBestIdx; /* Index information for this level */
+
+ /* The following field is really not part of the current level. But
+ ** we need a place to cache index information for each table in the
+ ** FROM clause and the WhereLevel structure is a convenient place.
+ */
+ sqlite3_index_info *pIdxInfo; /* Index info for n-th source table */
};
/*
@@ -1055,6 +1177,7 @@ struct WhereInfo {
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 */
+ sqlite3_index_info **apInfo; /* Array of pointers to index info structures */
WhereLevel a[1]; /* Information about each nest loop in the WHERE */
};
@@ -1087,6 +1210,7 @@ struct NameContext {
int nErr; /* Number of errors encountered while resolving names */
u8 allowAgg; /* Aggregate functions allowed here */
u8 hasAgg; /* True if aggregates are seen */
+ u8 isCheck; /* True if resolving names in a CHECK constraint */
int nDepth; /* Depth of subquery recursion. 1 for no recursion */
AggInfo *pAggInfo; /* Information about aggregates at this level */
NameContext *pNext; /* Next outer name context. NULL for outermost */
@@ -1102,14 +1226,14 @@ struct NameContext {
** offset). But later on, nLimit and nOffset become the memory locations
** in the VDBE that record the limit and offset counters.
**
-** addrOpenVirt[] entries contain the address of OP_OpenVirtual opcodes.
+** addrOpenEphm[] entries contain the address of OP_OpenEphemeral opcodes.
** These addresses must be stored so that we can go back and fill in
** the P3_KEYINFO and P2 parameters later. Neither the KeyInfo nor
** the number of columns in P2 can be computed at the same time
-** as the OP_OpenVirtual instruction is coded because not
+** as the OP_OpenEphm instruction is coded because not
** enough information about the compound query is known at that point.
-** The KeyInfo for addrOpenVirt[0] and [1] contains collating sequences
-** for the result set. The KeyInfo for addrOpenVirt[2] contains collating
+** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences
+** for the result set. The KeyInfo for addrOpenTran[2] contains collating
** sequences for the ORDER BY clause.
*/
struct Select {
@@ -1118,7 +1242,7 @@ struct Select {
u8 isDistinct; /* True if the DISTINCT keyword is present */
u8 isResolved; /* True once sqlite3SelectResolve() has run. */
u8 isAgg; /* True if this is an aggregate query */
- u8 usesVirt; /* True if uses an OpenVirtual opcode */
+ u8 usesEphm; /* True if uses an OpenEphemeral opcode */
u8 disallowOrderBy; /* Do not allow an ORDER BY to be attached if TRUE */
SrcList *pSrc; /* The FROM clause */
Expr *pWhere; /* The WHERE clause */
@@ -1130,7 +1254,7 @@ struct Select {
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 */
- int addrOpenVirt[3]; /* OP_OpenVirtual opcodes related to this select */
+ int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */
};
/*
@@ -1147,9 +1271,9 @@ struct Select {
#define SRT_Mem 5 /* Store result in a memory cell */
#define SRT_Set 6 /* Store non-null results as keys in an index */
#define SRT_Table 7 /* Store result as data with an automatic rowid */
-#define SRT_VirtualTab 8 /* Create virtual table and store like SRT_Table */
+#define SRT_EphemTab 8 /* Create transient tab and store like SRT_Table */
#define SRT_Subroutine 9 /* Call a subroutine to handle results */
-#define SRT_Exists 10 /* Put 0 or 1 in a memory cell */
+#define SRT_Exists 10 /* Store 1 if the result is not empty */
/*
** An SQL parser context. A copy of this structure is passed through
@@ -1160,6 +1284,12 @@ struct Select {
** 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.
+**
+** The nTableLock and aTableLock variables are only used if the shared-cache
+** feature is enabled (if sqlite3Tsd()->useSharedData is true). They are
+** used to store the set of table-locks required by the statement being
+** compiled. Function sqlite3TableLock() is used to add entries to the
+** list.
*/
struct Parse {
sqlite3 *db; /* The main database structure */
@@ -1170,14 +1300,20 @@ struct Parse {
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 */
+ u8 parseError; /* True if a parsing error has been seen */
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 ckOffset; /* Stack offset to data used by CHECK constraints */
u32 writeMask; /* Start a write transaction on these databases */
u32 cookieMask; /* Bitmask of schema verified databases */
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
int cookieValue[MAX_ATTACHED+2]; /* Values of cookies to verify */
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ int nTableLock; /* Number of locks in aTableLock */
+ TableLock *aTableLock; /* Required table locks for shared-cache mode */
+#endif
/* Above is constant between recursions. Below is reset before and after
** each recursion */
@@ -1196,8 +1332,19 @@ struct Parse {
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
TriggerStack *trigStack; /* Trigger actions being coded */
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ Token sArg; /* Complete text of a module argument */
+ u8 declareVtab; /* True if inside sqlite3_declare_vtab() */
+ Table *pVirtualLock; /* Require virtual table lock on this table */
+#endif
};
+#ifdef SQLITE_OMIT_VIRTUALTABLE
+ #define IN_DECLARE_VTAB 0
+#else
+ #define IN_DECLARE_VTAB (pParse->declareVtab)
+#endif
+
/*
** An instance of the following structure can be declared on a stack and used
** to save the Parse.zAuthContext value so that it can be restored later.
@@ -1212,6 +1359,7 @@ struct AuthContext {
*/
#define OPFLAG_NCHANGE 1 /* Set to update db->nChange */
#define OPFLAG_LASTROWID 2 /* Set to update db->lastRowid */
+#define OPFLAG_ISUPDATE 4 /* This OP_Insert is an sql UPDATE */
/*
* Each trigger present in the database schema is stored as an instance of
@@ -1231,8 +1379,6 @@ struct AuthContext {
struct Trigger {
char *name; /* The name of the trigger */
char *table; /* The table or view to which the trigger applies */
- 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 TRIGGER_BEFORE, TRIGGER_AFTER */
Expr *pWhen; /* The WHEN clause of the expresion (may be NULL) */
@@ -1240,7 +1386,8 @@ struct Trigger {
the <column-list> is stored here */
int foreach; /* One of TK_ROW or TK_STATEMENT */
Token nameToken; /* Token containing zName. Use during parsing only */
-
+ Schema *pSchema; /* Schema containing the trigger */
+ Schema *pTabSchema; /* Schema containing the table */
TriggerStep *step_list; /* Link list of trigger program steps */
Trigger *pNext; /* Next trigger associated with the table */
};
@@ -1305,8 +1452,8 @@ struct TriggerStep {
ExprList *pExprList; /* Valid for UPDATE statements and sometimes
INSERT steps (when pSelect == 0) */
IdList *pIdList; /* Valid for INSERT statements only */
-
- TriggerStep * pNext; /* Next in the link-list */
+ TriggerStep *pNext; /* Next in the link-list */
+ TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */
};
/*
@@ -1366,6 +1513,7 @@ struct DbFixer {
typedef struct {
sqlite3 *db; /* The database being initialized */
char **pzErrMsg; /* Error message stored here */
+ int rc; /* Result code stored here */
} InitData;
/*
@@ -1398,38 +1546,33 @@ 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_MEMDEBUG
- void *sqlite3Malloc_(int,int,char*,int);
- void sqlite3Free_(void*,char*,int);
- void *sqlite3Realloc_(void*,int,char*,int);
- char *sqlite3StrDup_(const char*,char*,int);
- char *sqlite3StrNDup_(const char*, int,char*,int);
- void sqlite3CheckMemory(void*,int);
-#else
- void *sqlite3Malloc(int);
- void *sqlite3MallocRaw(int);
- void sqlite3Free(void*);
- void *sqlite3Realloc(void*,int);
- char *sqlite3StrDup(const char*);
- char *sqlite3StrNDup(const char*, int);
+
+void *sqlite3Malloc(int,int);
+void *sqlite3MallocRaw(int,int);
+void sqlite3Free(void*);
+void *sqlite3Realloc(void*,int);
+char *sqlite3StrDup(const char*);
+char *sqlite3StrNDup(const char*, int);
# define sqlite3CheckMemory(a,b)
-# define sqlite3MallocX sqlite3Malloc
-#endif
void sqlite3ReallocOrFree(void**,int);
void sqlite3FreeX(void*);
void *sqlite3MallocX(int);
+int sqlite3AllocSize(void *);
+
char *sqlite3MPrintf(const char*, ...);
char *sqlite3VMPrintf(const char*, va_list);
void sqlite3DebugPrintf(const char*, ...);
void *sqlite3TextToPtr(const char*);
void sqlite3SetString(char **, ...);
void sqlite3ErrorMsg(Parse*, const char*, ...);
+void sqlite3ErrorClear(Parse*);
void sqlite3Dequote(char*);
void sqlite3DequoteExpr(Expr*);
-int sqlite3KeywordCode(const char*, int);
+int sqlite3KeywordCode(const unsigned char*, int);
int sqlite3RunParser(Parse*, const char*, char **);
void sqlite3FinishCoding(Parse*);
Expr *sqlite3Expr(int, Expr*, Expr*, const Token*);
+Expr *sqlite3ExprOrFree(int, Expr*, Expr*, const Token*);
Expr *sqlite3RegisterExpr(Parse*,Token*);
Expr *sqlite3ExprAnd(Expr*, Expr*);
void sqlite3ExprSpan(Expr*,Token*,Token*);
@@ -1446,24 +1589,26 @@ void sqlite3BeginParse(Parse*,int);
void sqlite3RollbackInternalChanges(sqlite3*);
void sqlite3CommitInternalChanges(sqlite3*);
Table *sqlite3ResultSetOfSelect(Parse*,char*,Select*);
-void sqlite3OpenMasterTable(Vdbe *v, int);
-void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int);
+void sqlite3OpenMasterTable(Parse *, int);
+void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int);
void sqlite3AddColumn(Parse*,Token*);
void sqlite3AddNotNull(Parse*, int);
-void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int);
+void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
+void sqlite3AddCheckConstraint(Parse*, Expr*);
void sqlite3AddColumnType(Parse*,Token*);
void sqlite3AddDefaultValue(Parse*,Expr*);
void sqlite3AddCollateType(Parse*, const char*, int);
void sqlite3EndTable(Parse*,Token*,Token*,Select*);
-#ifndef SQLITE_OMIT_VIEW
- void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int);
+void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int);
+
+#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
int sqlite3ViewGetColumnNames(Parse*,Table*);
#else
# define sqlite3ViewGetColumnNames(A,B) 0
#endif
-void sqlite3DropTable(Parse*, SrcList*, int);
+void sqlite3DropTable(Parse*, SrcList*, int, int);
void sqlite3DeleteTable(sqlite3*, Table*);
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
int sqlite3ArrayAllocate(void**,int,int);
@@ -1475,8 +1620,8 @@ void sqlite3SrcListAssignCursors(Parse*, SrcList*);
void sqlite3IdListDelete(IdList*);
void sqlite3SrcListDelete(SrcList*);
void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
- Token*);
-void sqlite3DropIndex(Parse*, SrcList*);
+ Token*, int, int);
+void sqlite3DropIndex(Parse*, SrcList*, int);
void sqlite3AddKeyType(Vdbe*, ExprList*);
void sqlite3AddIdxKeyType(Vdbe*, Index*);
int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*, char *aff);
@@ -1486,8 +1631,7 @@ 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 sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**);
@@ -1503,7 +1647,7 @@ 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 sqlite3Vacuum(Parse*, Token*);
+void sqlite3Vacuum(Parse*);
int sqlite3RunVacuum(char**, sqlite3*);
char *sqlite3NameFromToken(Token*);
int sqlite3ExprCheck(Parse*, Expr*, int, int*);
@@ -1513,6 +1657,7 @@ int sqlite3ExprResolveNames(NameContext *, Expr *);
int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
int sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
Vdbe *sqlite3GetVdbe(Parse*);
+Expr *sqlite3CreateIdExpr(const char*);
void sqlite3Randomness(int, void*);
void sqlite3RollbackAll(sqlite3*);
void sqlite3CodeVerifySchema(Parse*, int);
@@ -1524,7 +1669,7 @@ int sqlite3ExprIsConstantOrFunction(Expr*);
int sqlite3ExprIsInteger(Expr*, int*);
int sqlite3IsRowid(const char*);
void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int);
-void sqlite3GenerateRowIndexDelete(sqlite3*, Vdbe*, Table*, int, char*);
+void sqlite3GenerateRowIndexDelete(Vdbe*, Table*, int, char*);
void sqlite3GenerateIndexKey(Vdbe*, Index*, int);
void sqlite3GenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
void sqlite3CompleteInsertion(Parse*, Table*, int, char*, int, int, int);
@@ -1549,7 +1694,7 @@ void sqlite3ChangeCookie(sqlite3*, Vdbe*, int);
int,Expr*,int);
void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
void sqlite3DropTrigger(Parse*, SrcList*);
- void sqlite3DropTriggerPtr(Parse*, Trigger*, int);
+ void sqlite3DropTriggerPtr(Parse*, Trigger*);
int sqlite3TriggersExist(Parse*, Table*, int, ExprList*);
int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
int, int);
@@ -1564,7 +1709,7 @@ void sqlite3ChangeCookie(sqlite3*, Vdbe*, int);
#else
# define sqlite3TriggersExist(A,B,C,D,E,F) 0
# define sqlite3DeleteTrigger(A)
-# define sqlite3DropTriggerPtr(A,B,C)
+# define sqlite3DropTriggerPtr(A,B)
# define sqlite3UnlinkAndDeleteTrigger(A,B,C)
# define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I) 0
#endif
@@ -1583,8 +1728,8 @@ void sqlite3DeferForeignKey(Parse*, int);
# define sqlite3AuthContextPush(a,b,c)
# define sqlite3AuthContextPop(a) ((void)(a))
#endif
-void sqlite3Attach(Parse*, Token*, Token*, int, Token*);
-void sqlite3Detach(Parse*, Token*);
+void sqlite3Attach(Parse*, Expr*, Expr*, Expr*);
+void sqlite3Detach(Parse*, Expr*);
int sqlite3BtreeFactory(const sqlite3 *db, const char *zFilename,
int omitJournal, int nCache, Btree **ppBtree);
int sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
@@ -1630,7 +1775,7 @@ int sqlite3ValueBytes(sqlite3_value*, u8);
void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*));
void sqlite3ValueFree(sqlite3_value*);
sqlite3_value *sqlite3ValueNew(void);
-sqlite3_value *sqlite3GetTransientValue(sqlite3*db);
+char *sqlite3utf16to8(const void*, int);
int sqlite3ValueFromExpr(Expr *, u8, u8, sqlite3_value **);
void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
extern const unsigned char sqlite3UpperToLower[];
@@ -1656,6 +1801,74 @@ void sqlite3AnalysisLoad(sqlite3*,int iDB);
void sqlite3DefaultRowEst(Index*);
void sqlite3RegisterLikeFunctions(sqlite3*, int);
int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
+ThreadData *sqlite3ThreadData(void);
+const ThreadData *sqlite3ThreadDataReadOnly(void);
+void sqlite3ReleaseThreadData(void);
+void sqlite3AttachFunctions(sqlite3 *);
+void sqlite3MinimumFileFormat(Parse*, int, int);
+void sqlite3SchemaFree(void *);
+Schema *sqlite3SchemaGet(Btree *);
+int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
+KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *);
+int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
+ void (*)(sqlite3_context*,int,sqlite3_value **),
+ void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*));
+int sqlite3ApiExit(sqlite3 *db, int);
+int sqlite3MallocFailed(void);
+void sqlite3FailedMalloc(void);
+void sqlite3AbortOtherActiveVdbes(sqlite3 *, Vdbe *);
+int sqlite3OpenTempDatabase(Parse *);
+
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ void sqlite3CloseExtensions(sqlite3*);
+#else
+# define sqlite3CloseExtensions(X)
+#endif
+
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ void sqlite3TableLock(Parse *, int, int, u8, const char *);
+#else
+ #define sqlite3TableLock(v,w,x,y,z)
+#endif
+
+#ifdef SQLITE_MEMDEBUG
+ void sqlite3MallocDisallow(void);
+ void sqlite3MallocAllow(void);
+ int sqlite3TestMallocFail(void);
+#else
+ #define sqlite3TestMallocFail() 0
+ #define sqlite3MallocDisallow()
+ #define sqlite3MallocAllow()
+#endif
+
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ void *sqlite3ThreadSafeMalloc(int);
+ void sqlite3ThreadSafeFree(void *);
+#else
+ #define sqlite3ThreadSafeMalloc sqlite3MallocX
+ #define sqlite3ThreadSafeFree sqlite3FreeX
+#endif
+
+#ifdef SQLITE_OMIT_VIRTUALTABLE
+# define sqlite3VtabClear(X)
+# define sqlite3VtabSync(X,Y) (Y)
+# define sqlite3VtabRollback(X)
+# define sqlite3VtabCommit(X)
+#else
+ void sqlite3VtabClear(Table*);
+ int sqlite3VtabSync(sqlite3 *db, int rc);
+ int sqlite3VtabRollback(sqlite3 *db);
+ int sqlite3VtabCommit(sqlite3 *db);
+#endif
+void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*);
+void sqlite3VtabFinishParse(Parse*, Token*);
+void sqlite3VtabArgInit(Parse*);
+void sqlite3VtabArgExtend(Parse*, Token*);
+int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
+int sqlite3VtabCallConnect(Parse*, Table*);
+int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
+int sqlite3VtabBegin(sqlite3 *, sqlite3_vtab *);
+FuncDef *sqlite3VtabOverloadFunction(FuncDef*, int nArg, Expr*);
#ifdef SQLITE_SSE
#include "sseInt.h"
diff --git a/ext/pdo_sqlite/sqlite/src/table.c b/ext/pdo_sqlite/sqlite/src/table.c
index d4ef2c8a78..c4e228361f 100644
--- a/ext/pdo_sqlite/sqlite/src/table.c
+++ b/ext/pdo_sqlite/sqlite/src/table.c
@@ -16,9 +16,11 @@
** These routines are in a separate files so that they will not be linked
** if they are not used.
*/
+#include "sqliteInt.h"
#include <stdlib.h>
#include <string.h>
-#include "sqliteInt.h"
+
+#ifndef SQLITE_OMIT_GET_TABLE
/*
** This structure is used to pass data from sqlite3_get_table() through
@@ -57,7 +59,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
if( p->nData + need >= p->nAlloc ){
char **azNew;
p->nAlloc = p->nAlloc*2 + need + 1;
- azNew = realloc( p->azResult, sizeof(char*)*p->nAlloc );
+ azNew = sqlite3_realloc( p->azResult, sizeof(char*)*p->nAlloc );
if( azNew==0 ) goto malloc_failed;
p->azResult = azNew;
}
@@ -69,11 +71,9 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
p->nColumn = nCol;
for(i=0; i<nCol; i++){
if( colv[i]==0 ){
- z = 0;
+ z = sqlite3_mprintf("");
}else{
- z = malloc( strlen(colv[i])+1 );
- if( z==0 ) goto malloc_failed;
- strcpy(z, colv[i]);
+ z = sqlite3_mprintf("%s", colv[i]);
}
p->azResult[p->nData++] = z;
}
@@ -92,7 +92,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
if( argv[i]==0 ){
z = 0;
}else{
- z = malloc( strlen(argv[i])+1 );
+ z = sqlite3_malloc( strlen(argv[i])+1 );
if( z==0 ) goto malloc_failed;
strcpy(z, argv[i]);
}
@@ -138,18 +138,19 @@ int sqlite3_get_table(
res.nData = 1;
res.nAlloc = 20;
res.rc = SQLITE_OK;
- res.azResult = malloc( sizeof(char*)*res.nAlloc );
+ res.azResult = sqlite3_malloc( sizeof(char*)*res.nAlloc );
if( res.azResult==0 ) return SQLITE_NOMEM;
res.azResult[0] = 0;
rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
if( res.azResult ){
+ assert( sizeof(res.azResult[0])>= sizeof(res.nData) );
res.azResult[0] = (char*)res.nData;
}
if( rc==SQLITE_ABORT ){
sqlite3_free_table(&res.azResult[1]);
if( res.zErrMsg ){
if( pzErrMsg ){
- free(*pzErrMsg);
+ sqlite3_free(*pzErrMsg);
*pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg);
}
sqliteFree(res.zErrMsg);
@@ -164,7 +165,7 @@ int sqlite3_get_table(
}
if( res.nAlloc>res.nData ){
char **azNew;
- azNew = realloc( res.azResult, sizeof(char*)*(res.nData+1) );
+ azNew = sqlite3_realloc( res.azResult, sizeof(char*)*(res.nData+1) );
if( azNew==0 ){
sqlite3_free_table(&res.azResult[1]);
return SQLITE_NOMEM;
@@ -189,7 +190,9 @@ void sqlite3_free_table(
azResult--;
if( azResult==0 ) return;
n = (int)azResult[0];
- for(i=1; i<n; i++){ if( azResult[i] ) free(azResult[i]); }
- free(azResult);
+ for(i=1; i<n; i++){ if( azResult[i] ) sqlite3_free(azResult[i]); }
+ sqlite3_free(azResult);
}
}
+
+#endif /* SQLITE_OMIT_GET_TABLE */
diff --git a/ext/pdo_sqlite/sqlite/src/tclsqlite.c b/ext/pdo_sqlite/sqlite/src/tclsqlite.c
index 9a8b823b7e..8572b7cf65 100644
--- a/ext/pdo_sqlite/sqlite/src/tclsqlite.c
+++ b/ext/pdo_sqlite/sqlite/src/tclsqlite.c
@@ -23,6 +23,15 @@
#include <assert.h>
#include <ctype.h>
+/*
+ * Windows needs to know which symbols to export. Unix does not.
+ * BUILD_sqlite should be undefined for Unix.
+ */
+#ifdef BUILD_sqlite
+#undef TCL_STORAGE_CLASS
+#define TCL_STORAGE_CLASS DLLEXPORT
+#endif /* BUILD_sqlite */
+
#define NUM_PREPARED_STMTS 10
#define MAX_PREPARED_STMTS 100
@@ -79,7 +88,7 @@ struct SqlPreparedStmt {
*/
typedef struct SqliteDb SqliteDb;
struct SqliteDb {
- sqlite3 *db; /* The "real" database structure */
+ sqlite3 *db; /* The "real" database structure. MUST BE FIRST */
Tcl_Interp *interp; /* The interpreter used for this database */
char *zBusy; /* The busy callback routine */
char *zCommit; /* The commit hook callback routine */
@@ -89,6 +98,8 @@ struct SqliteDb {
char *zAuth; /* The authorization callback routine */
char *zNull; /* Text to substitute for an SQL NULL value */
SqlFunc *pFunc; /* List of SQL functions */
+ Tcl_Obj *pUpdateHook; /* Update hook script (if any) */
+ Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */
SqlCollate *pCollate; /* List of SQL collation functions */
int rc; /* Return code of most recent sqlite3_exec() */
Tcl_Obj *pCollateNeeded; /* Collation needed script */
@@ -200,6 +211,15 @@ static void DbDeleteCmd(void *db){
if( pDb->zNull ){
Tcl_Free(pDb->zNull);
}
+ if( pDb->pUpdateHook ){
+ Tcl_DecrRefCount(pDb->pUpdateHook);
+ }
+ if( pDb->pRollbackHook ){
+ Tcl_DecrRefCount(pDb->pRollbackHook);
+ }
+ if( pDb->pCollateNeeded ){
+ Tcl_DecrRefCount(pDb->pCollateNeeded);
+ }
Tcl_Free((char*)pDb);
}
@@ -235,6 +255,7 @@ static int DbProgressHandler(void *cd){
return 0;
}
+#ifndef SQLITE_OMIT_TRACE
/*
** This routine is called by the SQLite trace handler whenever a new
** block of SQL is executed. The TCL script in pDb->zTrace is executed.
@@ -250,7 +271,9 @@ static void DbTraceHandler(void *cd, const char *zSql){
Tcl_DStringFree(&str);
Tcl_ResetResult(pDb->interp);
}
+#endif
+#ifndef SQLITE_OMIT_TRACE
/*
** This routine is called by the SQLite profile handler after a statement
** SQL has executed. The TCL script in pDb->zProfile is evaluated.
@@ -269,6 +292,7 @@ static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){
Tcl_DStringFree(&str);
Tcl_ResetResult(pDb->interp);
}
+#endif
/*
** This routine is called when a transaction is committed. The
@@ -287,6 +311,37 @@ static int DbCommitHandler(void *cd){
return 0;
}
+static void DbRollbackHandler(void *clientData){
+ SqliteDb *pDb = (SqliteDb*)clientData;
+ assert(pDb->pRollbackHook);
+ if( TCL_OK!=Tcl_EvalObjEx(pDb->interp, pDb->pRollbackHook, 0) ){
+ Tcl_BackgroundError(pDb->interp);
+ }
+}
+
+static void DbUpdateHandler(
+ void *p,
+ int op,
+ const char *zDb,
+ const char *zTbl,
+ sqlite_int64 rowid
+){
+ SqliteDb *pDb = (SqliteDb *)p;
+ Tcl_Obj *pCmd;
+
+ assert( pDb->pUpdateHook );
+ assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
+
+ pCmd = Tcl_DuplicateObj(pDb->pUpdateHook);
+ Tcl_IncrRefCount(pCmd);
+ Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(
+ ( (op==SQLITE_INSERT)?"INSERT":(op==SQLITE_UPDATE)?"UPDATE":"DELETE"), -1));
+ Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zDb, -1));
+ Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zTbl, -1));
+ Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(rowid));
+ Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
+}
+
static void tclCollateNeeded(
void *pCtx,
sqlite3 *db,
@@ -392,7 +447,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
}
default: {
int bytes = sqlite3_value_bytes(pIn);
- pVal = Tcl_NewStringObj(sqlite3_value_text(pIn), bytes);
+ pVal = Tcl_NewStringObj((char *)sqlite3_value_text(pIn), bytes);
break;
}
}
@@ -439,8 +494,8 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
Tcl_GetWideIntFromObj(0, pVar, &v);
sqlite3_result_int64(context, v);
}else{
- data = Tcl_GetStringFromObj(pVar, &n);
- sqlite3_result_text(context, data, n, SQLITE_TRANSIENT);
+ data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
+ sqlite3_result_text(context, (char *)data, n, SQLITE_TRANSIENT);
}
}
}
@@ -496,6 +551,8 @@ static int auth_callback(
case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break;
case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break;
case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break;
+ case SQLITE_CREATE_VTABLE : zCode="SQLITE_CREATE_VTABLE"; break;
+ case SQLITE_DROP_VTABLE : zCode="SQLITE_DROP_VTABLE"; break;
default : zCode="????"; break;
}
Tcl_DStringInit(&str);
@@ -610,22 +667,25 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
"authorizer", "busy", "cache",
"changes", "close", "collate",
"collation_needed", "commit_hook", "complete",
- "copy", "errorcode", "eval",
- "function", "last_insert_rowid", "nullvalue",
+ "copy", "enable_load_extension","errorcode",
+ "eval", "exists", "function",
+ "interrupt", "last_insert_rowid", "nullvalue",
"onecolumn", "profile", "progress",
- "rekey", "timeout", "total_changes",
- "trace", "transaction", "version",
- 0
+ "rekey", "rollback_hook", "timeout",
+ "total_changes", "trace", "transaction",
+ "update_hook", "version", 0
};
enum DB_enum {
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_NULLVALUE,
+ DB_COPY, DB_ENABLE_LOAD_EXTENSION,DB_ERRORCODE,
+ DB_EVAL, DB_EXISTS, DB_FUNCTION,
+ DB_INTERRUPT, DB_LAST_INSERT_ROWID,DB_NULLVALUE,
DB_ONECOLUMN, DB_PROFILE, DB_PROGRESS,
- DB_REKEY, DB_TIMEOUT, DB_TOTAL_CHANGES,
- DB_TRACE, DB_TRANSACTION, DB_VERSION
+ DB_REKEY, DB_ROLLBACK_HOOK, DB_TIMEOUT,
+ DB_TOTAL_CHANGES, DB_TRACE, DB_TRANSACTION,
+ DB_UPDATE_HOOK, DB_VERSION,
};
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
@@ -1036,9 +1096,10 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
azCol = malloc( sizeof(azCol[0])*(nCol+1) );
if( azCol==0 ) {
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
+ fclose(in);
return TCL_ERROR;
}
- sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0);
+ (void)sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0);
zCommit = "COMMIT";
while( (zLine = local_getline(0, in))!=0 ){
char *z;
@@ -1058,10 +1119,13 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
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);
+ if( zErr ){
+ 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;
}
@@ -1085,7 +1149,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
free(azCol);
fclose(in);
sqlite3_finalize(pStmt);
- sqlite3_exec(pDb->db, zCommit, 0, 0, 0);
+ (void)sqlite3_exec(pDb->db, zCommit, 0, 0, 0);
if( zCommit[0] == 'C' ){
/* success, set result as number of lines processed */
@@ -1102,6 +1166,25 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
/*
+ ** $db enable_load_extension BOOLEAN
+ **
+ ** Turn the extension loading feature on or off. It if off by
+ ** default.
+ */
+ case DB_ENABLE_LOAD_EXTENSION: {
+ int onoff;
+ if( objc!=3 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "BOOLEAN");
+ return TCL_ERROR;
+ }
+ if( Tcl_GetBooleanFromObj(interp, objv[2], &onoff) ){
+ return TCL_ERROR;
+ }
+ sqlite3_enable_load_extension(pDb->db, onoff);
+ break;
+ }
+
+ /*
** $db errorcode
**
** Return the numeric error code that was returned by the most recent
@@ -1126,7 +1209,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** lindex [$db eval $sql] 0
*/
case DB_ONECOLUMN:
- case DB_EVAL: {
+ case DB_EVAL:
+ case DB_EXISTS: {
char const *zSql; /* Next SQL statement to execute */
char const *zLeft; /* What is left after first stmt in zSql */
sqlite3_stmt *pStmt; /* Compiled SQL statment */
@@ -1139,19 +1223,24 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
SqlPreparedStmt *pPreStmt; /* Pointer to a prepared statement */
int rc2;
- if( choice==DB_ONECOLUMN ){
- if( objc!=3 ){
- Tcl_WrongNumArgs(interp, 2, objv, "SQL");
- return TCL_ERROR;
- }
- pRet = 0;
- }else{
+ if( choice==DB_EVAL ){
if( objc<3 || objc>5 ){
Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?");
return TCL_ERROR;
}
pRet = Tcl_NewObj();
Tcl_IncrRefCount(pRet);
+ }else{
+ if( objc!=3 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "SQL");
+ return TCL_ERROR;
+ }
+ if( choice==DB_EXISTS ){
+ pRet = Tcl_NewBooleanObj(0);
+ Tcl_IncrRefCount(pRet);
+ }else{
+ pRet = 0;
+ }
}
if( objc==3 ){
pArray = pScript = 0;
@@ -1275,8 +1364,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_GetWideIntFromObj(interp, pVar, &v);
sqlite3_bind_int64(pStmt, i, v);
}else{
- data = Tcl_GetStringFromObj(pVar, &n);
- sqlite3_bind_text(pStmt, i, data, n, SQLITE_STATIC);
+ data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
+ sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC);
Tcl_IncrRefCount(pVar);
apParm[nParm++] = pVar;
}
@@ -1344,7 +1433,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break;
}
default: {
- pVal = dbTextToObj(sqlite3_column_text(pStmt, i));
+ pVal = dbTextToObj((char *)sqlite3_column_text(pStmt, i));
break;
}
}
@@ -1356,11 +1445,19 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_ObjSetVar2(interp, pArray, apColName[i], pVal, 0);
}
}else if( choice==DB_ONECOLUMN ){
+ assert( pRet==0 );
if( pRet==0 ){
pRet = pVal;
Tcl_IncrRefCount(pRet);
}
rc = TCL_BREAK;
+ i = nCol;
+ }else if( choice==DB_EXISTS ){
+ Tcl_DecrRefCount(pRet);
+ pRet = Tcl_NewBooleanObj(1);
+ Tcl_IncrRefCount(pRet);
+ rc = TCL_BREAK;
+ i = nCol;
}else{
Tcl_ListObjAppendElement(interp, pRet, pVal);
}
@@ -1471,6 +1568,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_SetObjResult(interp, pRet);
}
Tcl_DecrRefCount(pRet);
+ }else if( rc==TCL_OK ){
+ Tcl_ResetResult(interp);
}
break;
}
@@ -1512,6 +1611,17 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
/*
+ ** $db interrupt
+ **
+ ** Interrupt the execution of the inner-most SQL interpreter. This
+ ** causes the SQL statement to return an error of SQLITE_INTERRUPT.
+ */
+ case DB_INTERRUPT: {
+ sqlite3_interrupt(pDb->db);
+ break;
+ }
+
+ /*
** $db nullvalue ?STRING?
**
** Change text used when a NULL comes back from the database. If ?STRING?
@@ -1549,14 +1659,14 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
*/
case DB_LAST_INSERT_ROWID: {
Tcl_Obj *pResult;
- int rowid;
+ Tcl_WideInt rowid;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 2, objv, "");
return TCL_ERROR;
}
rowid = sqlite3_last_insert_rowid(pDb->db);
pResult = Tcl_GetObjResult(interp);
- Tcl_SetIntObj(pResult, rowid);
+ Tcl_SetWideIntObj(pResult, rowid);
break;
}
@@ -1782,7 +1892,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
inTrans = !sqlite3_get_autocommit(pDb->db);
if( !inTrans ){
- sqlite3_exec(pDb->db, zBegin, 0, 0, 0);
+ (void)sqlite3_exec(pDb->db, zBegin, 0, 0, 0);
}
rc = Tcl_EvalObjEx(interp, pScript, 0);
if( !inTrans ){
@@ -1792,8 +1902,50 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
} else {
zEnd = "COMMIT";
}
- sqlite3_exec(pDb->db, zEnd, 0, 0, 0);
+ (void)sqlite3_exec(pDb->db, zEnd, 0, 0, 0);
+ }
+ break;
+ }
+
+ /*
+ ** $db update_hook ?script?
+ ** $db rollback_hook ?script?
+ */
+ case DB_UPDATE_HOOK:
+ case DB_ROLLBACK_HOOK: {
+
+ /* set ppHook to point at pUpdateHook or pRollbackHook, depending on
+ ** whether [$db update_hook] or [$db rollback_hook] was invoked.
+ */
+ Tcl_Obj **ppHook;
+ if( choice==DB_UPDATE_HOOK ){
+ ppHook = &pDb->pUpdateHook;
+ }else{
+ ppHook = &pDb->pRollbackHook;
+ }
+
+ if( objc!=2 && objc!=3 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?");
+ return TCL_ERROR;
+ }
+ if( *ppHook ){
+ Tcl_SetObjResult(interp, *ppHook);
+ if( objc==3 ){
+ Tcl_DecrRefCount(*ppHook);
+ *ppHook = 0;
+ }
}
+ if( objc==3 ){
+ assert( !(*ppHook) );
+ if( Tcl_GetCharLength(objv[2])>0 ){
+ *ppHook = objv[2];
+ Tcl_IncrRefCount(*ppHook);
+ }
+ }
+
+ sqlite3_update_hook(pDb->db, (pDb->pUpdateHook?DbUpdateHandler:0), pDb);
+ sqlite3_rollback_hook(pDb->db,(pDb->pRollbackHook?DbRollbackHandler:0),pDb);
+
break;
}
@@ -1849,7 +2001,6 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
const char *zArg;
char *zErrMsg;
const char *zFile;
- char zBuf[80];
if( objc==2 ){
zArg = Tcl_GetStringFromObj(objv[1], 0);
if( strcmp(zArg,"-version")==0 ){
@@ -1917,14 +2068,6 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
zArg = Tcl_GetStringFromObj(objv[1], 0);
Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
- /* The return value is the value of the sqlite* pointer
- */
- sprintf(zBuf, "%p", p->db);
- if( strncmp(zBuf,"0x",2) ){
- sprintf(zBuf, "0x%p", p->db);
- }
- Tcl_AppendResult(interp, zBuf, 0);
-
/* If compiled with SQLITE_TEST turned on, then register the "md5sum"
** SQL function.
*/
@@ -1939,7 +2082,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
#ifdef SQLITE_MEMDEBUG
sqlite3_iMallocFail = mallocfail;
#endif
- }
+ }
#endif
p->interp = interp;
return TCL_OK;
@@ -1955,6 +2098,15 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
#endif
/*
+** Make sure we have a PACKAGE_VERSION macro defined. This will be
+** defined automatically by the TEA makefile. But other makefiles
+** do not define it.
+*/
+#ifndef PACKAGE_VERSION
+# define PACKAGE_VERSION SQLITE_VERSION
+#endif
+
+/*
** Initialize this module.
**
** This Tcl module contains only a single new Tcl command named "sqlite".
@@ -1963,23 +2115,23 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** used to open a new SQLite database. See the DbMain() routine above
** for additional information.
*/
-int Sqlite3_Init(Tcl_Interp *interp){
+EXTERN 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_PkgProvide(interp, "sqlite3", PACKAGE_VERSION);
Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
- Tcl_PkgProvide(interp, "sqlite", "3.0");
+ Tcl_PkgProvide(interp, "sqlite", PACKAGE_VERSION);
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; }
+EXTERN int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
+EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
+EXTERN 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; }
+EXTERN int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
+EXTERN int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
+EXTERN int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
+EXTERN int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
#endif
#ifdef TCLSH
@@ -2040,14 +2192,26 @@ int TCLSH_MAIN(int argc, char **argv){
extern int Sqlitetest3_Init(Tcl_Interp*);
extern int Sqlitetest4_Init(Tcl_Interp*);
extern int Sqlitetest5_Init(Tcl_Interp*);
+ extern int Sqlitetest6_Init(Tcl_Interp*);
+ extern int Sqlitetest7_Init(Tcl_Interp*);
+ extern int Sqlitetest8_Init(Tcl_Interp*);
extern int Md5_Init(Tcl_Interp*);
extern int Sqlitetestsse_Init(Tcl_Interp*);
+ extern int Sqlitetestasync_Init(Tcl_Interp*);
+ extern int Sqlitetesttclvar_Init(Tcl_Interp*);
+ extern int Sqlitetestschema_Init(Tcl_Interp*);
Sqlitetest1_Init(interp);
Sqlitetest2_Init(interp);
Sqlitetest3_Init(interp);
Sqlitetest4_Init(interp);
Sqlitetest5_Init(interp);
+ Sqlitetest6_Init(interp);
+ Sqlitetest7_Init(interp);
+ Sqlitetest8_Init(interp);
+ Sqlitetestasync_Init(interp);
+ Sqlitetesttclvar_Init(interp);
+ Sqlitetestschema_Init(interp);
Md5_Init(interp);
#ifdef SQLITE_SSE
Sqlitetestsse_Init(interp);
diff --git a/ext/pdo_sqlite/sqlite/src/test1.c b/ext/pdo_sqlite/sqlite/src/test1.c
index ceac5cd6da..fd474b2763 100644
--- a/ext/pdo_sqlite/sqlite/src/test1.c
+++ b/ext/pdo_sqlite/sqlite/src/test1.c
@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
-** Code for testing the printf() interface to SQLite. This code
+** Code for testing all sorts of SQLite interfaces. This code
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
@@ -21,6 +21,48 @@
#include <stdlib.h>
#include <string.h>
+/*
+** This is a copy of the first part of the SqliteDb structure in
+** tclsqlite.c. We need it here so that the get_sqlite_pointer routine
+** can extract the sqlite3* pointer from an existing Tcl SQLite
+** connection.
+*/
+struct SqliteDb {
+ sqlite3 *db;
+};
+
+/*
+** A TCL command that returns the address of the sqlite* pointer
+** for an sqlite connection instance. Bad things happen if the
+** input is not an sqlite connection.
+*/
+static int get_sqlite_pointer(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ struct SqliteDb *p;
+ Tcl_CmdInfo cmdInfo;
+ char zBuf[100];
+ if( objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "SQLITE-CONNECTION");
+ return TCL_ERROR;
+ }
+ if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){
+ Tcl_AppendResult(interp, "command not found: ",
+ Tcl_GetString(objv[1]), (char*)0);
+ return TCL_ERROR;
+ }
+ p = (struct SqliteDb*)cmdInfo.objClientData;
+ sprintf(zBuf, "%p", p->db);
+ if( strncmp(zBuf,"0x",2) ){
+ sprintf(zBuf, "0x%p", p->db);
+ }
+ Tcl_AppendResult(interp, zBuf, 0);
+ return TCL_OK;
+}
+
const char *sqlite3TestErrorName(int rc){
const char *zName = 0;
switch( rc ){
@@ -124,7 +166,7 @@ static int getFilePointer(
** understood by scanf, and if not, try prepending an "0x" to see if
** that helps. If nothing works, a fatal error is generated.
*/
-static int makePointerStr(Tcl_Interp *interp, char *zPtr, void *p){
+int sqlite3TestMakePointerStr(Tcl_Interp *interp, char *zPtr, void *p){
sqlite3_snprintf(100, zPtr, "%p", p);
return TCL_OK;
}
@@ -180,7 +222,7 @@ static int test_exec_printf(
Tcl_AppendElement(interp, zBuf);
Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
Tcl_DStringFree(&str);
- if( zErr ) free(zErr);
+ if( zErr ) sqlite3_free(zErr);
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
return TCL_OK;
}
@@ -188,7 +230,7 @@ static int test_exec_printf(
/*
** Usage: sqlite3_mprintf_z_test SEPARATOR ARG0 ARG1 ...
**
-** Test the %z format of mprintf(). Use multiple mprintf() calls to
+** Test the %z format of sqliteMPrintf(). Use multiple mprintf() calls to
** concatenate arg0 through argn using separator as the separator.
** Return the result.
*/
@@ -210,6 +252,26 @@ static int test_mprintf_z(
}
/*
+** Usage: sqlite3_mprintf_n_test STRING
+**
+** Test the %n format of sqliteMPrintf(). Return the length of the
+** input string.
+*/
+static int test_mprintf_n(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ char **argv /* Text of each argument */
+){
+ char *zStr;
+ int n = 0;
+ zStr = sqlite3MPrintf("%s%n", argv[1], &n);
+ sqliteFree(zStr);
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(n));
+ return TCL_OK;
+}
+
+/*
** Usage: sqlite3_get_table_printf DB FORMAT STRING
**
** Invoke the sqlite3_get_table_printf() interface using the open database
@@ -255,7 +317,7 @@ static int test_get_table_printf(
Tcl_AppendElement(interp, zErr);
}
sqlite3_free_table(aResult);
- if( zErr ) free(zErr);
+ if( zErr ) sqlite3_free(zErr);
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
return TCL_OK;
}
@@ -373,8 +435,8 @@ static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv)
int i;
for(i=0; i<argc; i++){
if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
- sqlite3_result_text(context, sqlite3_value_text(argv[i]), -1,
- SQLITE_TRANSIENT);
+ sqlite3_result_text(context, (char*)sqlite3_value_text(argv[i]),
+ sqlite3_value_bytes(argv[i]), SQLITE_TRANSIENT);
break;
}
}
@@ -446,8 +508,8 @@ static void sqlite3ExecFunc(
){
struct dstr x;
memset(&x, 0, sizeof(x));
- sqlite3_exec((sqlite3*)sqlite3_user_data(context),
- sqlite3_value_text(argv[0]),
+ (void)sqlite3_exec((sqlite3*)sqlite3_user_data(context),
+ (char*)sqlite3_value_text(argv[0]),
execFuncCallback, &x, 0);
sqlite3_result_text(context, x.z, x.nUsed, SQLITE_TRANSIENT);
sqliteFree(x.z);
@@ -492,6 +554,11 @@ static int test_create_function(
** because it is not tested anywhere else. */
if( rc==SQLITE_OK ){
sqlite3_value *pVal;
+#ifdef SQLITE_MEMDEBUG
+ if( sqlite3_iMallocFail>0 ){
+ sqlite3_iMallocFail++;
+ }
+#endif
pVal = sqlite3ValueNew();
sqlite3ValueSetStr(pVal, -1, "x_sqlite_exec", SQLITE_UTF8, SQLITE_STATIC);
rc = sqlite3_create_function16(db,
@@ -508,6 +575,14 @@ static int test_create_function(
/*
** Routines to implement the x_count() aggregate function.
+**
+** x_count() counts the number of non-null arguments. But there are
+** some twists for testing purposes.
+**
+** If the argument to x_count() is 40 then a UTF-8 error is reported
+** on the step function. If x_count(41) is seen, then a UTF-16 error
+** is reported on the step function. If the total count is 42, then
+** a UTF-8 error is reported on the finalize function.
*/
typedef struct CountCtx CountCtx;
struct CountCtx {
@@ -519,11 +594,28 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0]) ) && p ){
p->n++;
}
+ if( argc>0 ){
+ int v = sqlite3_value_int(argv[0]);
+ if( v==40 ){
+ sqlite3_result_error(context, "value of 40 handed to x_count", -1);
+#ifndef SQLITE_OMIT_UTF16
+ }else if( v==41 ){
+ const char zUtf16ErrMsg[] = { 0, 0x61, 0, 0x62, 0, 0x63, 0, 0, 0};
+ sqlite3_result_error16(context, &zUtf16ErrMsg[1-SQLITE_BIGENDIAN], -1);
+#endif
+ }
+ }
}
static void countFinalize(sqlite3_context *context){
CountCtx *p;
p = sqlite3_aggregate_context(context, sizeof(*p));
- sqlite3_result_int(context, p ? p->n : 0);
+ if( p ){
+ if( p->n==42 ){
+ sqlite3_result_error(context, "x_count totals to 42", -1);
+ }else{
+ sqlite3_result_int(context, p ? p->n : 0);
+ }
+ }
}
/*
@@ -535,7 +627,10 @@ static void countFinalize(sqlite3_context *context){
**
** The original motivation for this routine was to be able to call the
** sqlite3_create_aggregate function while a query is in progress in order
-** to test the SQLITE_MISUSE detection logic.
+** to test the SQLITE_MISUSE detection logic. See misuse.test.
+**
+** This routine was later extended to test the use of sqlite3_result_error()
+** within aggregate functions.
*/
static int test_create_aggregate(
void *NotUsed,
@@ -787,7 +882,8 @@ static int sqlite3_mprintf_hexdouble(
** 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.
+** Turn off this mechanism and reset the sqlite3ThreadData()->mallocFailed
+** variable if N==0.
*/
#ifdef SQLITE_MEMDEBUG
static int sqlite_malloc_fail(
@@ -810,7 +906,6 @@ static int sqlite_malloc_fail(
}
sqlite3_iMallocFail = n;
sqlite3_iMallocReset = rep;
- sqlite3_malloc_failed = 0;
return TCL_OK;
}
#endif
@@ -828,13 +923,277 @@ static int sqlite_malloc_stat(
char **argv /* Text of each argument */
){
char zBuf[200];
- sprintf(zBuf, "%d %d %d", sqlite3_nMalloc, sqlite3_nFree, sqlite3_iMallocFail);
+ sprintf(zBuf, "%d %d %d", sqlite3_nMalloc,sqlite3_nFree,sqlite3_iMallocFail);
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
+
+/*
+** This function implements a Tcl command that may be invoked using any of
+** the four forms enumerated below.
+**
+** sqlite_malloc_outstanding
+** Return a summary of all unfreed blocks of memory allocated by the
+** current thread. See comments above function sqlite3OutstandingMallocs()
+** in util.c for a description of the returned value.
+**
+** sqlite_malloc_outstanding -bytes
+** Return the total amount of unfreed memory (in bytes) allocated by
+** this thread.
+**
+** sqlite_malloc_outstanding -maxbytes
+** Return the maximum amount of dynamic memory in use at one time
+** by this thread.
+**
+** sqlite_malloc_outstanding -clearmaxbytes
+** Set the value returned by [sqlite_malloc_outstanding -maxbytes]
+** to the current value of [sqlite_malloc_outstanding -bytes].
+*/
+static int sqlite_malloc_outstanding(
+ ClientData clientData,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int objc, /* Number of arguments */
+ Tcl_Obj *CONST objv[] /* Command arguments */
+){
+ extern int sqlite3OutstandingMallocs(Tcl_Interp *interp);
+
+#if defined(SQLITE_DEBUG) && defined(SQLITE_MEMDEBUG) && SQLITE_MEMDEBUG>1
+ if( objc==2 ){
+ const char *zArg = Tcl_GetString(objv[1]);
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ ThreadData const *pTd = sqlite3ThreadDataReadOnly();
+ if( 0==strcmp(zArg, "-bytes") ){
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(pTd->nAlloc));
+ }else if( 0==strcmp(zArg, "-clearmaxbytes") ){
+ sqlite3_nMaxAlloc = pTd->nAlloc;
+ }else
+#endif
+ if( 0==strcmp(zArg, "-maxbytes") ){
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_nMaxAlloc));
+ }else{
+ Tcl_AppendResult(interp, "bad option \"", zArg,
+ "\": must be -bytes, -maxbytes or -clearmaxbytes", 0
+ );
+ return TCL_ERROR;
+ }
+
+ return TCL_OK;
+ }
+
+ if( objc!=1 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "?-bytes?");
+ return TCL_ERROR;
+ }
+
+ return sqlite3OutstandingMallocs(interp);
+#else
+ return TCL_OK;
+#endif
+}
#endif
/*
+** Usage: sqlite3_enable_shared_cache BOOLEAN
+**
+*/
+#if !defined(SQLITE_OMIT_SHARED_CACHE)
+static int test_enable_shared(
+ ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int objc, /* Number of arguments */
+ Tcl_Obj *CONST objv[] /* Command arguments */
+){
+ int rc;
+ int enable;
+ int ret = 0;
+
+ if( objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
+ return TCL_ERROR;
+ }
+ if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ){
+ return TCL_ERROR;
+ }
+ ret = sqlite3ThreadDataReadOnly()->useSharedData;
+ rc = sqlite3_enable_shared_cache(enable);
+ if( rc!=SQLITE_OK ){
+ Tcl_SetResult(interp, (char *)sqlite3ErrStr(rc), TCL_STATIC);
+ return TCL_ERROR;
+ }
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(ret));
+ return TCL_OK;
+}
+#endif
+
+/*
+** Usage: sqlite3_libversion_number
+**
+*/
+static int test_libversion_number(
+ ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int objc, /* Number of arguments */
+ Tcl_Obj *CONST objv[] /* Command arguments */
+){
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_libversion_number()));
+ return TCL_OK;
+}
+
+/*
+** Usage: sqlite3_table_column_metadata DB dbname tblname colname
+**
+*/
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
+static int test_table_column_metadata(
+ ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int objc, /* Number of arguments */
+ Tcl_Obj *CONST objv[] /* Command arguments */
+){
+ sqlite3 *db;
+ const char *zDb;
+ const char *zTbl;
+ const char *zCol;
+ int rc;
+ Tcl_Obj *pRet;
+
+ const char *zDatatype;
+ const char *zCollseq;
+ int notnull;
+ int primarykey;
+ int autoincrement;
+
+ if( objc!=5 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB dbname tblname colname");
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ zDb = Tcl_GetString(objv[2]);
+ zTbl = Tcl_GetString(objv[3]);
+ zCol = Tcl_GetString(objv[4]);
+
+ if( strlen(zDb)==0 ) zDb = 0;
+
+ rc = sqlite3_table_column_metadata(db, zDb, zTbl, zCol,
+ &zDatatype, &zCollseq, &notnull, &primarykey, &autoincrement);
+
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp, sqlite3_errmsg(db), 0);
+ return TCL_ERROR;
+ }
+
+ pRet = Tcl_NewObj();
+ Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zDatatype, -1));
+ Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zCollseq, -1));
+ Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(notnull));
+ Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(primarykey));
+ Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(autoincrement));
+ Tcl_SetObjResult(interp, pRet);
+
+ return TCL_OK;
+}
+#endif
+
+
+/*
+** Usage: sqlite3_load_extension DB-HANDLE FILE ?PROC?
+*/
+static int test_load_extension(
+ ClientData clientData, /* Not used */
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int objc, /* Number of arguments */
+ Tcl_Obj *CONST objv[] /* Command arguments */
+){
+ Tcl_CmdInfo cmdInfo;
+ sqlite3 *db;
+ int rc;
+ char *zDb;
+ char *zFile;
+ char *zProc = 0;
+ char *zErr = 0;
+
+ if( objc!=4 && objc!=3 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB-HANDLE FILE ?PROC?");
+ return TCL_ERROR;
+ }
+ zDb = Tcl_GetString(objv[1]);
+ zFile = Tcl_GetString(objv[2]);
+ if( objc==4 ){
+ zProc = Tcl_GetString(objv[3]);
+ }
+
+ /* Extract the C database handle from the Tcl command name */
+ if( !Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
+ Tcl_AppendResult(interp, "command not found: ", zDb, (char*)0);
+ return TCL_ERROR;
+ }
+ db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
+ assert(db);
+
+ /* Call the underlying C function. If an error occurs, set rc to
+ ** TCL_ERROR and load any error string into the interpreter. If no
+ ** error occurs, set rc to TCL_OK.
+ */
+#ifdef SQLITE_OMIT_LOAD_EXTENSION
+ rc = SQLITE_ERROR;
+ zErr = sqlite3_mprintf("this build omits sqlite3_load_extension()");
+#else
+ rc = sqlite3_load_extension(db, zFile, zProc, &zErr);
+#endif
+ if( rc!=SQLITE_OK ){
+ Tcl_SetResult(interp, zErr ? zErr : "", TCL_VOLATILE);
+ rc = TCL_ERROR;
+ }else{
+ rc = TCL_OK;
+ }
+ sqlite3_free(zErr);
+
+ return rc;
+}
+
+/*
+** Usage: sqlite3_enable_load_extension DB-HANDLE ONOFF
+*/
+static int test_enable_load(
+ ClientData clientData, /* Not used */
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int objc, /* Number of arguments */
+ Tcl_Obj *CONST objv[] /* Command arguments */
+){
+ Tcl_CmdInfo cmdInfo;
+ sqlite3 *db;
+ char *zDb;
+ int onoff;
+
+ if( objc!=3 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB-HANDLE ONOFF");
+ return TCL_ERROR;
+ }
+ zDb = Tcl_GetString(objv[1]);
+
+ /* Extract the C database handle from the Tcl command name */
+ if( !Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
+ Tcl_AppendResult(interp, "command not found: ", zDb, (char*)0);
+ return TCL_ERROR;
+ }
+ db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
+ assert(db);
+
+ /* Get the onoff parameter */
+ if( Tcl_GetBooleanFromObj(interp, objv[2], &onoff) ){
+ return TCL_ERROR;
+ }
+
+#ifdef SQLITE_OMIT_LOAD_EXTENSION
+ Tcl_AppendResult(interp, "this build omits sqlite3_load_extension()");
+ return TCL_ERROR;
+#else
+ sqlite3_enable_load_extension(db, onoff);
+ return TCL_OK;
+#endif
+}
+
+/*
** Usage: sqlite_abort
**
** Shutdown the process immediately. This is not a clean shutdown.
@@ -857,14 +1216,14 @@ static int sqlite_abort(
*/
static void testFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
while( argc>=2 ){
- const char *zArg0 = sqlite3_value_text(argv[0]);
+ const char *zArg0 = (char*)sqlite3_value_text(argv[0]);
if( zArg0 ){
if( 0==sqlite3StrICmp(zArg0, "int") ){
sqlite3_result_int(context, sqlite3_value_int(argv[1]));
}else if( sqlite3StrICmp(zArg0,"int64")==0 ){
sqlite3_result_int64(context, sqlite3_value_int64(argv[1]));
}else if( sqlite3StrICmp(zArg0,"string")==0 ){
- sqlite3_result_text(context, sqlite3_value_text(argv[1]), -1,
+ sqlite3_result_text(context, (char*)sqlite3_value_text(argv[1]), -1,
SQLITE_TRANSIENT);
}else if( sqlite3StrICmp(zArg0,"double")==0 ){
sqlite3_result_double(context, sqlite3_value_double(argv[1]));
@@ -952,7 +1311,7 @@ static int test_finalize(
/*
** Usage: sqlite3_reset STMT
**
-** Finalize a statement handle.
+** Reset a statement handle.
*/
static int test_reset(
void * clientData,
@@ -972,12 +1331,15 @@ static int test_reset(
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
rc = sqlite3_reset(pStmt);
- if( pStmt &&
- 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;
}
@@ -1064,7 +1426,8 @@ static char *sqlite_static_bind_value = 0;
** ignored and the value is set to NULL. If FLAGS=="static" then
** the value is set to the value of a static variable named
** "sqlite_static_bind_value". If FLAGS=="normal" then a copy
-** of the VALUE is made.
+** of the VALUE is made. If FLAGS=="blob10" then a VALUE is ignored
+** an a 10-byte blob "abc\000xyz\000pq" is inserted.
*/
static int test_bind(
void *NotUsed,
@@ -1088,6 +1451,8 @@ static int test_bind(
rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0);
}else if( strcmp(argv[4],"normal")==0 ){
rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, SQLITE_TRANSIENT);
+ }else if( strcmp(argv[4],"blob10")==0 ){
+ rc = sqlite3_bind_text(pStmt, idx, "abc\000xyz\000pq", 10, SQLITE_STATIC);
}else{
Tcl_AppendResult(interp, "4th argument should be "
"\"null\" or \"static\" or \"normal\"", 0);
@@ -1166,10 +1531,12 @@ static int test_collate_func(
pVal = sqlite3ValueNew();
sqlite3ValueSetStr(pVal, nA, zA, encin, SQLITE_STATIC);
n = sqlite3_value_bytes(pVal);
- Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),n));
+ Tcl_ListObjAppendElement(i,pX,
+ Tcl_NewStringObj((char*)sqlite3_value_text(pVal),n));
sqlite3ValueSetStr(pVal, nB, zB, encin, SQLITE_STATIC);
n = sqlite3_value_bytes(pVal);
- Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),n));
+ Tcl_ListObjAppendElement(i,pX,
+ Tcl_NewStringObj((char*)sqlite3_value_text(pVal),n));
sqlite3ValueFree(pVal);
Tcl_EvalObjEx(i, pX, 0);
@@ -1201,13 +1568,24 @@ static int test_collate(
(void *)SQLITE_UTF16LE, val?test_collate_func:0);
if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR;
+#ifdef SQLITE_MEMDEBUG
+ if( sqlite3_iMallocFail>0 ){
+ sqlite3_iMallocFail++;
+ }
+#endif
pVal = sqlite3ValueNew();
sqlite3ValueSetStr(pVal, -1, "test_collate", SQLITE_UTF8, SQLITE_STATIC);
- sqlite3_create_collation16(db, sqlite3ValueText(pVal, SQLITE_UTF16NATIVE),
- SQLITE_UTF16BE, (void *)SQLITE_UTF16BE, val?test_collate_func:0);
+ rc = sqlite3_create_collation16(db,
+ sqlite3ValueText(pVal, SQLITE_UTF16NATIVE), SQLITE_UTF16BE,
+ (void *)SQLITE_UTF16BE, val?test_collate_func:0);
sqlite3ValueFree(pVal);
}
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
+
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
+ return TCL_ERROR;
+ }
return TCL_OK;
bad_args:
@@ -1216,15 +1594,35 @@ bad_args:
return TCL_ERROR;
}
+/*
+** When the collation needed callback is invoked, record the name of
+** the requested collating function here. The recorded name is linked
+** to a TCL variable and used to make sure that the requested collation
+** name is correct.
+*/
+static char zNeededCollation[200];
+static char *pzNeededCollation = zNeededCollation;
+
+
+/*
+** Called when a collating sequence is needed. Registered using
+** sqlite3_collation_needed16().
+*/
static void test_collate_needed_cb(
void *pCtx,
sqlite3 *db,
int eTextRep,
- const void *notUsed
+ const void *pName
){
- int enc = db->enc;
+ int enc = ENC(db);
+ int i;
+ char *z;
+ for(z = (char*)pName, i=0; *z || z[1]; z++){
+ if( *z ) zNeededCollation[i++] = *z;
+ }
+ zNeededCollation[i] = 0;
sqlite3_create_collation(
- db, "test_collate", db->enc, (void *)enc, test_collate_func);
+ db, "test_collate", ENC(db), (void *)enc, test_collate_func);
}
/*
@@ -1242,6 +1640,7 @@ static int test_collate_needed(
if( objc!=2 ) goto bad_args;
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
rc = sqlite3_collation_needed16(db, 0, test_collate_needed_cb);
+ zNeededCollation[0] = 0;
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
return TCL_OK;
@@ -1249,7 +1648,56 @@ bad_args:
Tcl_WrongNumArgs(interp, 1, objv, "DB");
return TCL_ERROR;
}
-#endif /* SQLITE_OMIT_UTF16 */
+
+/*
+** tclcmd: add_alignment_test_collations DB
+**
+** Add two new collating sequences to the database DB
+**
+** utf16_aligned
+** utf16_unaligned
+**
+** Both collating sequences use the same sort order as BINARY.
+** The only difference is that the utf16_aligned collating
+** sequence is declared with the SQLITE_UTF16_ALIGNED flag.
+** Both collating functions increment the unaligned utf16 counter
+** whenever they see a string that begins on an odd byte boundary.
+*/
+static int unaligned_string_counter = 0;
+static int alignmentCollFunc(
+ void *NotUsed,
+ int nKey1, const void *pKey1,
+ int nKey2, const void *pKey2
+){
+ int rc, n;
+ n = nKey1<nKey2 ? nKey1 : nKey2;
+ if( nKey1>0 && 1==(1&(int)pKey1) ) unaligned_string_counter++;
+ if( nKey2>0 && 1==(1&(int)pKey2) ) unaligned_string_counter++;
+ rc = memcmp(pKey1, pKey2, n);
+ if( rc==0 ){
+ rc = nKey1 - nKey2;
+ }
+ return rc;
+}
+static int add_alignment_test_collations(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3 *db;
+ if( objc>=2 ){
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ sqlite3_create_collation(db, "utf16_unaligned",
+ SQLITE_UTF16,
+ 0, alignmentCollFunc);
+ sqlite3_create_collation(db, "utf16_aligned",
+ SQLITE_UTF16 | SQLITE_UTF16_ALIGNED,
+ 0, alignmentCollFunc);
+ }
+ return SQLITE_OK;
+}
+#endif /* !defined(SQLITE_OMIT_UTF16) */
/*
** Usage: add_test_function <db ptr> <utf8> <utf16le> <utf16be>
@@ -1290,7 +1738,7 @@ static void test_function_utf8(
Tcl_IncrRefCount(pX);
Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-8", -1));
Tcl_ListObjAppendElement(interp, pX,
- Tcl_NewStringObj(sqlite3_value_text(argv[0]), -1));
+ Tcl_NewStringObj((char*)sqlite3_value_text(argv[0]), -1));
Tcl_EvalObjEx(interp, pX, 0);
Tcl_DecrRefCount(pX);
sqlite3_result_text(pCtx, Tcl_GetStringResult(interp), -1, SQLITE_TRANSIENT);
@@ -1314,13 +1762,13 @@ static void test_function_utf16le(
Tcl_IncrRefCount(pX);
Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-16LE", -1));
Tcl_ListObjAppendElement(interp, pX,
- Tcl_NewStringObj(sqlite3_value_text(argv[0]), -1));
+ Tcl_NewStringObj((char*)sqlite3_value_text(argv[0]), -1));
Tcl_EvalObjEx(interp, pX, 0);
Tcl_DecrRefCount(pX);
pVal = sqlite3ValueNew();
sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp),
SQLITE_UTF8, SQLITE_STATIC);
- sqlite3_result_text(pCtx,sqlite3_value_text(pVal),-1,SQLITE_TRANSIENT);
+ sqlite3_result_text(pCtx,(char*)sqlite3_value_text(pVal),-1,SQLITE_TRANSIENT);
sqlite3ValueFree(pVal);
}
static void test_function_utf16be(
@@ -1336,7 +1784,7 @@ static void test_function_utf16be(
Tcl_IncrRefCount(pX);
Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-16BE", -1));
Tcl_ListObjAppendElement(interp, pX,
- Tcl_NewStringObj(sqlite3_value_text(argv[0]), -1));
+ Tcl_NewStringObj((char*)sqlite3_value_text(argv[0]), -1));
Tcl_EvalObjEx(interp, pX, 0);
Tcl_DecrRefCount(pX);
pVal = sqlite3ValueNew();
@@ -1412,29 +1860,6 @@ static int test_errstr(
return TCL_OK;
}
-static int sqlite3_crashparams(
- void * clientData,
- Tcl_Interp *interp,
- int objc,
- Tcl_Obj *CONST objv[]
-){
-#ifdef OS_TEST
- int delay;
- if( objc!=3 ) goto bad_args;
- if( Tcl_GetIntFromObj(interp, objv[1], &delay) ) return TCL_ERROR;
- sqlite3SetCrashParams(delay, Tcl_GetString(objv[2]));
-#endif
- return TCL_OK;
-
-#ifdef OS_TEST
-bad_args:
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- Tcl_GetStringFromObj(objv[0], 0), "<delay> <filename>", 0);
- return TCL_ERROR;
-#endif
-}
-
-
/*
** Usage: breakpoint
**
@@ -1647,7 +2072,7 @@ static int test_bind_text(
}
/*
-** Usage: sqlite3_bind_text16 STMT N STRING BYTES
+** Usage: sqlite3_bind_text16 ?-static? STMT N STRING BYTES
**
** Test the sqlite3_bind_text16 interface. STMT is a prepared statement.
** N is the index of a wildcard in the prepared statement. This command
@@ -1667,18 +2092,24 @@ static int test_bind_text16(
char *value;
int rc;
- if( objc!=5 ){
+ void (*xDel)() = (objc==6?SQLITE_STATIC:SQLITE_TRANSIENT);
+ Tcl_Obj *oStmt = objv[objc-4];
+ Tcl_Obj *oN = objv[objc-3];
+ Tcl_Obj *oString = objv[objc-2];
+ Tcl_Obj *oBytes = objv[objc-1];
+
+ if( objc!=5 && objc!=6){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0);
return TCL_ERROR;
}
- if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
- if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
- value = Tcl_GetByteArrayFromObj(objv[3], 0);
- if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
+ if( getStmtPointer(interp, Tcl_GetString(oStmt), &pStmt) ) return TCL_ERROR;
+ if( Tcl_GetIntFromObj(interp, oN, &idx) ) return TCL_ERROR;
+ value = (char*)Tcl_GetByteArrayFromObj(oString, 0);
+ if( Tcl_GetIntFromObj(interp, oBytes, &bytes) ) return TCL_ERROR;
- rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, SQLITE_TRANSIENT);
+ rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, xDel);
if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
if( rc!=SQLITE_OK ){
return TCL_ERROR;
@@ -1808,7 +2239,6 @@ static int test_bind_parameter_index(
** Usage: sqlite3_clear_bindings STMT
**
*/
-#if 0
static int test_clear_bindings(
void * clientData,
Tcl_Interp *interp,
@@ -1825,7 +2255,28 @@ static int test_clear_bindings(
Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_clear_bindings(pStmt)));
return TCL_OK;
}
-#endif
+
+/*
+** Usage: sqlite3_sleep MILLISECONDS
+*/
+static int test_sleep(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ int ms;
+
+ if( objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "MILLISECONDS");
+ return TCL_ERROR;
+ }
+ if( Tcl_GetIntFromObj(interp, objv[1], &ms) ){
+ return TCL_ERROR;
+ }
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_sleep(ms)));
+ return TCL_OK;
+}
/*
** Usage: sqlite3_errcode DB
@@ -1895,7 +2346,7 @@ static int test_errmsg16(
#ifndef SQLITE_OMIT_UTF16
sqlite3 *db;
const void *zErr;
- int bytes;
+ int bytes = 0;
if( objc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
@@ -1905,7 +2356,9 @@ static int test_errmsg16(
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
zErr = sqlite3_errmsg16(db);
- bytes = sqlite3utf16ByteLen(zErr, -1);
+ if( zErr ){
+ bytes = sqlite3utf16ByteLen(zErr, -1);
+ }
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes));
#endif /* SQLITE_OMIT_UTF16 */
return TCL_OK;
@@ -1958,7 +2411,7 @@ static int test_prepare(
}
if( pStmt ){
- if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
+ if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
Tcl_AppendResult(interp, zBuf, 0);
}
return TCL_OK;
@@ -2015,7 +2468,7 @@ static int test_prepare16(
Tcl_DecrRefCount(pTail);
if( pStmt ){
- if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
+ if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
}
Tcl_AppendResult(interp, zBuf, 0);
#endif /* SQLITE_OMIT_UTF16 */
@@ -2045,7 +2498,7 @@ static int test_open(
zFilename = Tcl_GetString(objv[1]);
rc = sqlite3_open(zFilename, &db);
- if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
+ if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR;
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
@@ -2074,7 +2527,7 @@ static int test_open16(
zFilename = Tcl_GetByteArrayFromObj(objv[1], 0);
rc = sqlite3_open16(zFilename, &db);
- if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
+ if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR;
Tcl_AppendResult(interp, zBuf, 0);
#endif /* SQLITE_OMIT_UTF16 */
return TCL_OK;
@@ -2100,7 +2553,7 @@ static int test_complete16(
return TCL_ERROR;
}
- zBuf = Tcl_GetByteArrayFromObj(objv[1], 0);
+ zBuf = (char*)Tcl_GetByteArrayFromObj(objv[1], 0);
Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_complete16(zBuf)));
#endif /* SQLITE_OMIT_COMPLETE && SQLITE_OMIT_UTF16 */
return TCL_OK;
@@ -2452,7 +2905,7 @@ static int test_sqlite3OsOpenReadWrite(
int objc,
Tcl_Obj *CONST objv[]
){
- OsFile * pFile;
+ OsFile *pFile;
int rc;
int dummy;
char zBuf[100];
@@ -2463,14 +2916,12 @@ static int test_sqlite3OsOpenReadWrite(
return TCL_ERROR;
}
- pFile = sqliteMalloc(sizeof(OsFile));
- rc = sqlite3OsOpenReadWrite(Tcl_GetString(objv[1]), pFile, &dummy);
+ rc = sqlite3OsOpenReadWrite(Tcl_GetString(objv[1]), &pFile, &dummy);
if( rc!=SQLITE_OK ){
- sqliteFree(pFile);
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
return TCL_ERROR;
}
- makePointerStr(interp, zBuf, pFile);
+ sqlite3TestMakePointerStr(interp, zBuf, pFile);
Tcl_SetResult(interp, zBuf, 0);
return TCL_ERROR;
}
@@ -2484,7 +2935,7 @@ static int test_sqlite3OsClose(
int objc,
Tcl_Obj *CONST objv[]
){
- OsFile * pFile;
+ OsFile *pFile;
int rc;
if( objc!=2 ){
@@ -2496,12 +2947,11 @@ static int test_sqlite3OsClose(
if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
return TCL_ERROR;
}
- rc = sqlite3OsClose(pFile);
+ rc = sqlite3OsClose(&pFile);
if( rc!=SQLITE_OK ){
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
return TCL_ERROR;
}
- sqliteFree(pFile);
return TCL_OK;
}
@@ -2697,7 +3147,7 @@ static int test_stack_used(
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
prepStack();
- sqlite3_exec(db, argv[2], 0, 0, 0);
+ (void)sqlite3_exec(db, argv[2], 0, 0, 0);
for(i=65535; i>=0 && ((u32*)sqlite3_stack_baseline)[-i]==0xdeadbeef; i--){}
Tcl_SetObjResult(interp, Tcl_NewIntObj(i*4));
return TCL_OK;
@@ -2781,6 +3231,33 @@ static int get_autocommit(
}
/*
+** Usage: sqlite3_busy_timeout DB MS
+**
+** Set the busy timeout. This is more easily done using the timeout
+** method of the TCL interface. But we need a way to test the case
+** where it returns SQLITE_MISUSE.
+*/
+static int test_busy_timeout(
+ void * clientData,
+ Tcl_Interp *interp,
+ int argc,
+ char **argv
+){
+ int rc, ms;
+ sqlite3 *db;
+ if( argc!=3 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " DB", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
+ if( Tcl_GetInt(interp, argv[2], &ms) ) return TCL_ERROR;
+ rc = sqlite3_busy_timeout(db, ms);
+ Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0);
+ return TCL_OK;
+}
+
+/*
** Usage: tcl_variable_type VARIABLENAME
**
** Return the name of the internal representation for the
@@ -2806,6 +3283,115 @@ static int tcl_variable_type(
}
/*
+** Usage: sqlite3_release_memory ?N?
+**
+** Attempt to release memory currently held but not actually required.
+** The integer N is the number of bytes we are trying to release. The
+** return value is the amount of memory actually released.
+*/
+static int test_release_memory(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO)
+ int N;
+ int amt;
+ if( objc!=1 && objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "?N?");
+ return TCL_ERROR;
+ }
+ if( objc==2 ){
+ if( Tcl_GetIntFromObj(interp, objv[1], &N) ) return TCL_ERROR;
+ }else{
+ N = -1;
+ }
+ amt = sqlite3_release_memory(N);
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(amt));
+#endif
+ return TCL_OK;
+}
+
+/*
+** Usage: sqlite3_soft_heap_limit ?N?
+**
+** Query or set the soft heap limit for the current thread. The
+** limit is only changed if the N is present. The previous limit
+** is returned.
+*/
+static int test_soft_heap_limit(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO)
+ int amt;
+ if( objc!=1 && objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "?N?");
+ return TCL_ERROR;
+ }
+ amt = sqlite3ThreadDataReadOnly()->nSoftHeapLimit;
+ if( objc==2 ){
+ int N;
+ if( Tcl_GetIntFromObj(interp, objv[1], &N) ) return TCL_ERROR;
+ sqlite3_soft_heap_limit(N);
+ }
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(amt));
+#endif
+ return TCL_OK;
+}
+
+/*
+** Usage: sqlite3_clear_tsd_memdebug
+**
+** Clear all of the MEMDEBUG information out of thread-specific data.
+** This will allow it to be deallocated.
+*/
+static int test_clear_tsd_memdebug(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ return TCL_OK;
+}
+
+/*
+** Usage: sqlite3_tsd_release
+**
+** Call sqlite3ReleaseThreadData.
+*/
+static int test_tsd_release(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+#if defined(SQLITE_MEMDEBUG)
+ sqlite3ReleaseThreadData();
+#endif
+ return TCL_OK;
+}
+
+/*
+** Usage: sqlite3_thread_cleanup
+**
+** Call the sqlite3_thread_cleanup API.
+*/
+static int test_thread_cleanup(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3_thread_cleanup();
+ 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.
@@ -2823,6 +3409,18 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","0",TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_DISABLE_DIRSYNC
+ Tcl_SetVar2(interp, "sqlite_options", "dirsync", "0", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "dirsync", "1", TCL_GLOBAL_ONLY);
+#endif
+
+#ifdef SQLITE_DISABLE_LFS
+ Tcl_SetVar2(interp, "sqlite_options", "lfs", "0", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "lfs", "1", TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_OMIT_ALTERTABLE
Tcl_SetVar2(interp, "sqlite_options", "altertable", "0", TCL_GLOBAL_ONLY);
#else
@@ -2876,6 +3474,18 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "cast", "1", TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_OMIT_CHECK
+ Tcl_SetVar2(interp, "sqlite_options", "check", "0", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "check", "1", TCL_GLOBAL_ONLY);
+#endif
+
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
+ Tcl_SetVar2(interp, "sqlite_options", "columnmetadata", "1", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "columnmetadata", "0", TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_OMIT_COMPLETE
Tcl_SetVar2(interp, "sqlite_options", "complete", "0", TCL_GLOBAL_ONLY);
#else
@@ -2894,6 +3504,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "conflict", "1", TCL_GLOBAL_ONLY);
#endif
+#if OS_UNIX
+ Tcl_SetVar2(interp, "sqlite_options", "crashtest", "1", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "crashtest", "0", TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_OMIT_DATETIME_FUNCS
Tcl_SetVar2(interp, "sqlite_options", "datetime", "0", TCL_GLOBAL_ONLY);
#else
@@ -2936,6 +3552,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "integrityck", "1", TCL_GLOBAL_ONLY);
#endif
+#if defined(SQLITE_DEFAULT_FILE_FORMAT) && SQLITE_DEFAULT_FILE_FORMAT==1
+ Tcl_SetVar2(interp, "sqlite_options", "legacyformat", "1", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "legacyformat", "0", TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION
Tcl_SetVar2(interp, "sqlite_options", "like_opt", "0", TCL_GLOBAL_ONLY);
#else
@@ -2948,6 +3570,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "memorydb", "1", TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "1", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "0", TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_OMIT_OR_OPTIMIZATION
Tcl_SetVar2(interp, "sqlite_options", "or_opt", "0", TCL_GLOBAL_ONLY);
#else
@@ -2979,6 +3607,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "progress", "1", TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_ENABLE_REDEF_IO
+ Tcl_SetVar2(interp, "sqlite_options", "redefio", "1", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "redefio", "0", TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_OMIT_REINDEX
Tcl_SetVar2(interp, "sqlite_options", "reindex", "0", TCL_GLOBAL_ONLY);
#else
@@ -2997,6 +3631,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "schema_version", "1", TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_OMIT_SHARED_CACHE
+ Tcl_SetVar2(interp, "sqlite_options", "shared_cache", "0", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "shared_cache", "1", TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_OMIT_SUBQUERY
Tcl_SetVar2(interp, "sqlite_options", "subquery", "0", TCL_GLOBAL_ONLY);
#else
@@ -3050,6 +3690,12 @@ static void set_options(Tcl_Interp *interp){
#else
Tcl_SetVar2(interp, "sqlite_options", "view", "1", TCL_GLOBAL_ONLY);
#endif
+
+#ifdef SQLITE_OMIT_VIRTUALTABLE
+ Tcl_SetVar2(interp, "sqlite_options", "vtab", "0", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "vtab", "1", TCL_GLOBAL_ONLY);
+#endif
}
/*
@@ -3073,6 +3719,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_mprintf_scaled", (Tcl_CmdProc*)sqlite3_mprintf_scaled },
{ "sqlite3_mprintf_hexdouble", (Tcl_CmdProc*)sqlite3_mprintf_hexdouble},
{ "sqlite3_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z },
+ { "sqlite3_mprintf_n_test", (Tcl_CmdProc*)test_mprintf_n },
{ "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid },
{ "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf },
{ "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf },
@@ -3091,19 +3738,18 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "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 },
{ "sqlite3_get_autocommit", (Tcl_CmdProc*)get_autocommit },
{ "sqlite3_stack_used", (Tcl_CmdProc*)test_stack_used },
+ { "sqlite3_busy_timeout", (Tcl_CmdProc*)test_busy_timeout },
};
static struct {
char *zName;
Tcl_ObjCmdProc *xProc;
void *clientData;
} aObjCmd[] = {
+ { "sqlite3_connection_pointer", get_sqlite_pointer, 0 },
{ "sqlite3_bind_int", test_bind_int, 0 },
{ "sqlite3_bind_int64", test_bind_int64, 0 },
{ "sqlite3_bind_double", test_bind_double, 0 },
@@ -3114,9 +3760,8 @@ 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_sleep", test_sleep, 0},
{ "sqlite3_errcode", test_errcode ,0 },
{ "sqlite3_errmsg", test_errmsg ,0 },
{ "sqlite3_errmsg16", test_errmsg16 ,0 },
@@ -3133,6 +3778,15 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_changes", test_changes ,0 },
{ "sqlite3_step", test_step ,0 },
+ { "sqlite3_release_memory", test_release_memory, 0},
+ { "sqlite3_soft_heap_limit", test_soft_heap_limit, 0},
+ { "sqlite3_clear_tsd_memdebug", test_clear_tsd_memdebug, 0},
+ { "sqlite3_tsd_release", test_tsd_release, 0},
+ { "sqlite3_thread_cleanup", test_thread_cleanup, 0},
+
+ { "sqlite3_load_extension", test_load_extension, 0},
+ { "sqlite3_enable_load_extension", test_enable_load, 0},
+
/* sqlite3_column_*() API */
{ "sqlite3_column_count", test_column_count ,0 },
{ "sqlite3_data_count", test_data_count ,0 },
@@ -3145,11 +3799,24 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "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 },
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
+{ "sqlite3_column_database_name", test_stmt_utf8, sqlite3_column_database_name},
+{ "sqlite3_column_table_name", test_stmt_utf8, sqlite3_column_table_name},
+{ "sqlite3_column_origin_name", test_stmt_utf8, sqlite3_column_origin_name},
+#endif
+
#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 },
+ { "add_alignment_test_collations", add_alignment_test_collations, 0 },
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
+{"sqlite3_column_database_name16",
+ test_stmt_utf16, sqlite3_column_database_name16},
+{"sqlite3_column_table_name16", test_stmt_utf16, sqlite3_column_table_name16},
+{"sqlite3_column_origin_name16", test_stmt_utf16, sqlite3_column_origin_name16},
+#endif
#endif
{ "sqlite3_global_recover", test_global_recover, 0 },
@@ -3168,9 +3835,18 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "add_test_collate_needed", test_collate_needed, 0 },
{ "add_test_function", test_function, 0 },
#endif
- { "sqlite3_crashparams", sqlite3_crashparams, 0 },
+#ifdef SQLITE_MEMDEBUG
+ { "sqlite_malloc_outstanding", sqlite_malloc_outstanding, 0},
+#endif
{ "sqlite3_test_errstr", test_errstr, 0 },
{ "tcl_variable_type", tcl_variable_type, 0 },
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ { "sqlite3_enable_shared_cache", test_enable_shared, 0 },
+#endif
+ { "sqlite3_libversion_number", test_libversion_number, 0 },
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
+ { "sqlite3_table_column_metadata", test_table_column_metadata, 0 },
+#endif
};
static int bitmask_size = sizeof(Bitmask)*8;
int i;
@@ -3179,8 +3855,13 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
extern int sqlite3_sync_count, sqlite3_fullsync_count;
extern int sqlite3_opentemp_count;
extern int sqlite3_memUsed;
+ extern int sqlite3_malloc_id;
extern int sqlite3_memMax;
extern int sqlite3_like_count;
+ extern int sqlite3_tsd_count;
+#if OS_UNIX && defined(SQLITE_TEST) && defined(THREADSAFE) && THREADSAFE
+ extern int threadsOverrideEachOthersLocks;
+#endif
#if OS_WIN
extern int sqlite3_os_type;
#endif
@@ -3213,6 +3894,24 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
(char*)&sqlite3_current_time, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_os_trace",
(char*)&sqlite3_os_trace, TCL_LINK_INT);
+ Tcl_LinkVar(interp, "sqlite3_tsd_count",
+ (char*)&sqlite3_tsd_count, TCL_LINK_INT);
+#ifndef SQLITE_OMIT_UTF16
+ Tcl_LinkVar(interp, "unaligned_string_counter",
+ (char*)&unaligned_string_counter, TCL_LINK_INT);
+#endif
+#if OS_UNIX && defined(SQLITE_TEST) && defined(THREADSAFE) && THREADSAFE
+ Tcl_LinkVar(interp, "threadsOverrideEachOthersLocks",
+ (char*)&threadsOverrideEachOthersLocks, TCL_LINK_INT);
+#endif
+#ifndef SQLITE_OMIT_UTF16
+ Tcl_LinkVar(interp, "sqlite_last_needed_collation",
+ (char*)&pzNeededCollation, TCL_LINK_STRING|TCL_LINK_READ_ONLY);
+#endif
+#ifdef SQLITE_MEMDEBUG
+ Tcl_LinkVar(interp, "sqlite_malloc_id",
+ (char*)&sqlite3_malloc_id, TCL_LINK_STRING);
+#endif
#if OS_WIN
Tcl_LinkVar(interp, "sqlite_os_type",
(char*)&sqlite3_os_type, TCL_LINK_INT);
@@ -3250,5 +3949,14 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
(char*)&sqlite3_fullsync_count, TCL_LINK_INT);
#endif /* OS_UNIX */
set_options(interp);
+
+ {
+#ifdef SQLITE_DEBUG
+ extern int sqlite3_shared_cache_report(void *, Tcl_Interp *,
+ int, Tcl_Obj *CONST[]);
+ Tcl_CreateObjCommand(interp, "sqlite_shared_cache_report",
+ sqlite3_shared_cache_report, 0, 0);
+#endif
+ }
return TCL_OK;
}
diff --git a/ext/pdo_sqlite/sqlite/src/test2.c b/ext/pdo_sqlite/sqlite/src/test2.c
index d4c5544b63..80e57cd87e 100644
--- a/ext/pdo_sqlite/sqlite/src/test2.c
+++ b/ext/pdo_sqlite/sqlite/src/test2.c
@@ -524,7 +524,7 @@ static int fake_big_file(
int rc;
int n;
i64 offset;
- OsFile fd;
+ OsFile *fd = 0;
int readOnly = 0;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
@@ -532,7 +532,6 @@ static int fake_big_file(
return TCL_ERROR;
}
if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
- memset(&fd, 0, sizeof(fd));
rc = sqlite3OsOpenReadWrite(argv[2], &fd, &readOnly);
if( rc ){
Tcl_AppendResult(interp, "open failed: ", errorName(rc), 0);
@@ -540,12 +539,12 @@ static int fake_big_file(
}
offset = n;
offset *= 1024*1024;
- rc = sqlite3OsSeek(&fd, offset);
+ rc = sqlite3OsSeek(fd, offset);
if( rc ){
Tcl_AppendResult(interp, "seek failed: ", errorName(rc), 0);
return TCL_ERROR;
}
- rc = sqlite3OsWrite(&fd, "Hello, World!", 14);
+ rc = sqlite3OsWrite(fd, "Hello, World!", 14);
sqlite3OsClose(&fd);
if( rc ){
Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0);
@@ -560,6 +559,7 @@ static int fake_big_file(
*/
int Sqlitetest2_Init(Tcl_Interp *interp){
extern int sqlite3_io_error_pending;
+ extern int sqlite3_io_error_hit;
extern int sqlite3_diskfull_pending;
extern int sqlite3_diskfull;
static struct {
@@ -592,6 +592,8 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
}
Tcl_LinkVar(interp, "sqlite_io_error_pending",
(char*)&sqlite3_io_error_pending, TCL_LINK_INT);
+ Tcl_LinkVar(interp, "sqlite_io_error_hit",
+ (char*)&sqlite3_io_error_hit, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_diskfull_pending",
(char*)&sqlite3_diskfull_pending, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_diskfull",
diff --git a/ext/pdo_sqlite/sqlite/src/test3.c b/ext/pdo_sqlite/sqlite/src/test3.c
index 6b973a1478..6557fb4f4d 100644
--- a/ext/pdo_sqlite/sqlite/src/test3.c
+++ b/ext/pdo_sqlite/sqlite/src/test3.c
@@ -69,7 +69,7 @@ static int btree_open(
}
if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
if( Tcl_GetInt(interp, argv[3], &flags) ) return TCL_ERROR;
- rc = sqlite3BtreeOpen(argv[1], &pBt, flags);
+ rc = sqlite3BtreeOpen(argv[1], 0, &pBt, flags);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -585,6 +585,7 @@ static int btree_integrity_check(
#else
zResult = 0;
#endif
+ free(aRoot);
if( zResult ){
Tcl_AppendResult(interp, zResult, 0);
sqliteFree(zResult);
@@ -597,6 +598,7 @@ static int btree_integrity_check(
**
** Print information about all cursors to standard output for debugging.
*/
+#ifdef SQLITE_DEBUG
static int btree_cursor_list(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
@@ -614,6 +616,7 @@ static int btree_cursor_list(
sqlite3BtreeCursorList(pBt);
return SQLITE_OK;
}
+#endif
/*
** Usage: btree_cursor ID TABLENUM WRITEABLE
@@ -972,7 +975,7 @@ static int btree_keysize(
return TCL_ERROR;
}
pCur = sqlite3TextToPtr(argv[1]);
- sqlite3BtreeKeySize(pCur, &n);
+ sqlite3BtreeKeySize(pCur, (i64*)&n);
sqlite3_snprintf(sizeof(zBuf),zBuf, "%llu", n);
Tcl_AppendResult(interp, zBuf, 0);
return SQLITE_OK;
@@ -1000,7 +1003,7 @@ static int btree_key(
return TCL_ERROR;
}
pCur = sqlite3TextToPtr(argv[1]);
- sqlite3BtreeKeySize(pCur, &n);
+ sqlite3BtreeKeySize(pCur, (i64*)&n);
if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
char zBuf2[60];
sqlite3_snprintf(sizeof(zBuf2),zBuf2, "%llu", n);
@@ -1084,7 +1087,7 @@ static int btree_fetch_key(
}
pCur = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
- sqlite3BtreeKeySize(pCur, &nKey);
+ sqlite3BtreeKeySize(pCur, (i64*)&nKey);
zBuf = sqlite3BtreeKeyFetch(pCur, &amt);
if( zBuf && amt>=n ){
assert( nKey<sizeof(zStatic) );
@@ -1159,9 +1162,9 @@ static int btree_payload_size(
if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
n1 = 0;
}else{
- sqlite3BtreeKeySize(pCur, &n1);
+ sqlite3BtreeKeySize(pCur, (i64*)&n1);
}
- sqlite3BtreeDataSize(pCur, &n2);
+ sqlite3BtreeDataSize(pCur, (u32*)&n2);
sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2));
Tcl_AppendResult(interp, zBuf, 0);
return SQLITE_OK;
@@ -1184,6 +1187,7 @@ static int btree_payload_size(
** aResult[8] = Local payload size
** aResult[9] = Parent page number
*/
+#ifdef SQLITE_DEBUG
static int btree_cursor_info(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
@@ -1221,6 +1225,7 @@ static int btree_cursor_info(
Tcl_AppendResult(interp, &zBuf[1], 0);
return SQLITE_OK;
}
+#endif
/*
** The command is provided for the purpose of setting breakpoints.
@@ -1428,8 +1433,6 @@ int Sqlitetest3_Init(Tcl_Interp *interp){
{ "btree_payload_size", (Tcl_CmdProc*)btree_payload_size },
{ "btree_first", (Tcl_CmdProc*)btree_first },
{ "btree_last", (Tcl_CmdProc*)btree_last },
- { "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info },
- { "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list },
{ "btree_integrity_check", (Tcl_CmdProc*)btree_integrity_check },
{ "btree_breakpoint", (Tcl_CmdProc*)btree_breakpoint },
{ "btree_varint_test", (Tcl_CmdProc*)btree_varint_test },
@@ -1438,6 +1441,10 @@ int Sqlitetest3_Init(Tcl_Interp *interp){
{ "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 },
+#ifdef SQLITE_DEBUG
+ { "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info },
+ { "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list },
+#endif
};
int i;
diff --git a/ext/pdo_sqlite/sqlite/src/test4.c b/ext/pdo_sqlite/sqlite/src/test4.c
index 45991ba3a3..a7af482993 100644
--- a/ext/pdo_sqlite/sqlite/src/test4.c
+++ b/ext/pdo_sqlite/sqlite/src/test4.c
@@ -97,6 +97,7 @@ static void *thread_main(void *pArg){
p->zErr = 0;
}
p->completed++;
+ sqlite3_thread_cleanup();
return 0;
}
@@ -495,7 +496,7 @@ static void do_step(Thread *p){
if( p->rc==SQLITE_ROW ){
p->argc = sqlite3_column_count(p->pStmt);
for(i=0; i<sqlite3_data_count(p->pStmt); i++){
- p->argv[i] = sqlite3_column_text(p->pStmt, i);
+ p->argv[i] = (char*)sqlite3_column_text(p->pStmt, i);
}
for(i=0; i<p->argc; i++){
p->colv[i] = sqlite3_column_name(p->pStmt, i);
@@ -615,6 +616,73 @@ static int tcl_thread_swap(
}
/*
+** Usage: thread_db_get ID
+**
+** Return the database connection pointer for the given thread. Then
+** remove the pointer from the thread itself. Afterwards, the thread
+** can be stopped and the connection can be used by the main thread.
+*/
+static int tcl_thread_db_get(
+ 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 i;
+ char zBuf[100];
+ extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*);
+ if( argc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ID", 0);
+ return TCL_ERROR;
+ }
+ i = parse_thread_id(interp, argv[1]);
+ if( i<0 ) return TCL_ERROR;
+ if( !threadset[i].busy ){
+ Tcl_AppendResult(interp, "no such thread", 0);
+ return TCL_ERROR;
+ }
+ thread_wait(&threadset[i]);
+ sqlite3TestMakePointerStr(interp, zBuf, threadset[i].db);
+ threadset[i].db = 0;
+ Tcl_AppendResult(interp, zBuf, (char*)0);
+ return TCL_OK;
+}
+
+/*
+** Usage: thread_stmt_get ID
+**
+** Return the database stmt pointer for the given thread. Then
+** remove the pointer from the thread itself.
+*/
+static int tcl_thread_stmt_get(
+ 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 i;
+ char zBuf[100];
+ extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*);
+ if( argc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ID", 0);
+ return TCL_ERROR;
+ }
+ i = parse_thread_id(interp, argv[1]);
+ if( i<0 ) return TCL_ERROR;
+ if( !threadset[i].busy ){
+ Tcl_AppendResult(interp, "no such thread", 0);
+ return TCL_ERROR;
+ }
+ thread_wait(&threadset[i]);
+ sqlite3TestMakePointerStr(interp, zBuf, threadset[i].pStmt);
+ threadset[i].pStmt = 0;
+ Tcl_AppendResult(interp, zBuf, (char*)0);
+ return TCL_OK;
+}
+
+/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest4_Init(Tcl_Interp *interp){
@@ -634,6 +702,8 @@ int Sqlitetest4_Init(Tcl_Interp *interp){
{ "thread_step", (Tcl_CmdProc*)tcl_thread_step },
{ "thread_finalize", (Tcl_CmdProc*)tcl_thread_finalize },
{ "thread_swap", (Tcl_CmdProc*)tcl_thread_swap },
+ { "thread_db_get", (Tcl_CmdProc*)tcl_thread_db_get },
+ { "thread_stmt_get", (Tcl_CmdProc*)tcl_thread_stmt_get },
};
int i;
diff --git a/ext/pdo_sqlite/sqlite/src/test5.c b/ext/pdo_sqlite/sqlite/src/test5.c
index 28f546f608..aaa7979a92 100644
--- a/ext/pdo_sqlite/sqlite/src/test5.c
+++ b/ext/pdo_sqlite/sqlite/src/test5.c
@@ -41,7 +41,7 @@ static int binarize(
assert(objc==2);
bytes = Tcl_GetStringFromObj(objv[1], &len);
- pRet = Tcl_NewByteArrayObj(bytes, len+1);
+ pRet = Tcl_NewByteArrayObj((u8*)bytes, len+1);
Tcl_SetObjResult(interp, pRet);
return TCL_OK;
}
@@ -85,7 +85,7 @@ static int test_value_overhead(
for(i=0; i<repeat_count; i++){
if( do_calls ){
- zVal = sqlite3_value_text(&val);
+ zVal = (char*)sqlite3_value_text(&val);
}
}
@@ -159,7 +159,7 @@ static int test_translate(
}
sqlite3ValueSetStr(pVal, -1, z, enc_from, xDel);
}else{
- z = Tcl_GetByteArrayFromObj(objv[1], &len);
+ z = (char*)Tcl_GetByteArrayFromObj(objv[1], &len);
if( objc==5 ){
char *zTmp = z;
z = sqliteMalloc(len);
@@ -170,7 +170,7 @@ static int test_translate(
z = (char *)sqlite3ValueText(pVal, enc_to);
len = sqlite3ValueBytes(pVal, enc_to) + (enc_to==SQLITE_UTF8?1:2);
- Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(z, len));
+ Tcl_SetObjResult(interp, Tcl_NewByteArrayObj((u8*)z, len));
sqlite3ValueFree(pVal);
diff --git a/ext/pdo_sqlite/sqlite/src/tokenize.c b/ext/pdo_sqlite/sqlite/src/tokenize.c
index 7346f5b54c..69db09aa4f 100644
--- a/ext/pdo_sqlite/sqlite/src/tokenize.c
+++ b/ext/pdo_sqlite/sqlite/src/tokenize.c
@@ -23,6 +23,39 @@
#include <stdlib.h>
/*
+** The charMap() macro maps alphabetic characters into their
+** lower-case ASCII equivalent. On ASCII machines, this is just
+** an upper-to-lower case map. On EBCDIC machines we also need
+** to adjust the encoding. Only alphabetic characters and underscores
+** need to be translated.
+*/
+#ifdef SQLITE_ASCII
+# define charMap(X) sqlite3UpperToLower[(unsigned char)X]
+#endif
+#ifdef SQLITE_EBCDIC
+# define charMap(X) ebcdicToAscii[(unsigned char)X]
+const unsigned char ebcdicToAscii[] = {
+/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3x */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4x */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5x */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, /* 6x */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7x */
+ 0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* 8x */
+ 0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* 9x */
+ 0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ax */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */
+ 0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* Cx */
+ 0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* Dx */
+ 0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ex */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Fx */
+};
+#endif
+
+/*
** 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.
@@ -37,24 +70,22 @@
/*
-** If X is a character that can be used in an identifier and
-** X&0x80==0 then sqlite3IsIdChar[X] will be 1. If X&0x80==0x80 then
-** X is always an identifier character. (Hence all UTF-8
-** characters can be part of an identifier). sqlite3IsIdChar[X] will
-** be 0 for every character in the lower 128 ASCII characters
-** that cannot be used as part of an identifier.
+** If X is a character that can be used in an identifier then
+** IdChar(X) will be true. Otherwise it is false.
**
-** In this implementation, an identifier can be a string of
-** alphabetic characters, digits, and "_" plus any character
-** 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.
+** For ASCII, any character with the high-order bit set is
+** allowed in an identifier. For 7-bit characters,
+** sqlite3IsIdChar[X] must be 1.
+**
+** For EBCDIC, the rules are more complex but have the same
+** end result.
**
** 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.
*/
+#ifdef SQLITE_ASCII
const char sqlite3IsIdChar[] = {
/* 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 */
@@ -64,8 +95,27 @@ const char sqlite3IsIdChar[] = {
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */
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>0x1f && sqlite3IsIdChar[c-0x20]))
+#endif
+#ifdef SQLITE_EBCDIC
+const char sqlite3IsIdChar[] = {
+/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 4x */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, /* 5x */
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 6x */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, /* 7x */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, /* 8x */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, /* 9x */
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, /* Ax */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Cx */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Dx */
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Ex */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, /* Fx */
+};
+#define IdChar(C) (((c=C)>=0x42 && sqlite3IsIdChar[c-0x40]))
+#endif
+
/*
** Return the length of the token that begins at z[0].
@@ -196,9 +246,13 @@ static int getToken(const unsigned char *z, int *tokenType){
}
}
}
- if( c ) i++;
- *tokenType = TK_STRING;
- return i;
+ if( c ){
+ *tokenType = TK_STRING;
+ return i+1;
+ }else{
+ *tokenType = TK_ILLEGAL;
+ return i;
+ }
}
case '.': {
#ifndef SQLITE_OMIT_FLOATING_POINT
@@ -231,6 +285,10 @@ static int getToken(const unsigned char *z, int *tokenType){
*tokenType = TK_FLOAT;
}
#endif
+ while( IdChar(z[i]) ){
+ *tokenType = TK_ILLEGAL;
+ i++;
+ }
return i;
}
case '[': {
@@ -257,6 +315,7 @@ static int getToken(const unsigned char *z, int *tokenType){
#ifndef SQLITE_OMIT_TCL_VARIABLE
case '$':
#endif
+ case '@': /* For compatibility with MS SQL Server */
case ':': {
int n = 0;
*tokenType = TK_VARIABLE;
@@ -339,12 +398,13 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
extern void sqlite3ParserFree(void*, void(*)(void*));
extern int sqlite3Parser(void*, int, Token, Parse*);
- db->flags &= ~SQLITE_Interrupt;
+ if( db->activeVdbeCnt==0 ){
+ db->u1.isInterrupted = 0;
+ }
pParse->rc = SQLITE_OK;
i = 0;
pEngine = sqlite3ParserAlloc((void*(*)(int))sqlite3MallocX);
if( pEngine==0 ){
- sqlite3SetString(pzErrMsg, "out of memory", (char*)0);
return SQLITE_NOMEM;
}
assert( pParse->sLastToken.dyn==0 );
@@ -355,16 +415,16 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
assert( pParse->nVarExprAlloc==0 );
assert( pParse->apVarExpr==0 );
pParse->zTail = pParse->zSql = zSql;
- while( sqlite3_malloc_failed==0 && zSql[i]!=0 ){
+ while( !sqlite3MallocFailed() && zSql[i]!=0 ){
assert( i>=0 );
- pParse->sLastToken.z = &zSql[i];
+ pParse->sLastToken.z = (u8*)&zSql[i];
assert( pParse->sLastToken.dyn==0 );
pParse->sLastToken.n = getToken((unsigned char*)&zSql[i],&tokenType);
i += pParse->sLastToken.n;
switch( tokenType ){
case TK_SPACE:
case TK_COMMENT: {
- if( (db->flags & SQLITE_Interrupt)!=0 ){
+ if( db->u1.isInterrupted ){
pParse->rc = SQLITE_INTERRUPT;
sqlite3SetString(pzErrMsg, "interrupt", (char*)0);
goto abort_parse;
@@ -403,12 +463,11 @@ abort_parse:
sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
}
sqlite3ParserFree(pEngine, sqlite3FreeX);
- if( sqlite3_malloc_failed ){
+ if( sqlite3MallocFailed() ){
pParse->rc = SQLITE_NOMEM;
}
if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
- sqlite3SetString(&pParse->zErrMsg, sqlite3ErrStr(pParse->rc),
- (char*)0);
+ sqlite3SetString(&pParse->zErrMsg, sqlite3ErrStr(pParse->rc), (char*)0);
}
if( pParse->zErrMsg ){
if( pzErrMsg && *pzErrMsg==0 ){
@@ -423,7 +482,22 @@ abort_parse:
sqlite3VdbeDelete(pParse->pVdbe);
pParse->pVdbe = 0;
}
- sqlite3DeleteTable(pParse->db, pParse->pNewTable);
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ if( pParse->nested==0 ){
+ sqliteFree(pParse->aTableLock);
+ pParse->aTableLock = 0;
+ pParse->nTableLock = 0;
+ }
+#endif
+
+ if( !IN_DECLARE_VTAB ){
+ /* If the pParse->declareVtab flag is set, do not delete any table
+ ** structure built up in pParse->pNewTable. The calling code (see vtab.c)
+ ** will take responsibility for freeing the Table structure.
+ */
+ sqlite3DeleteTable(pParse->db, pParse->pNewTable);
+ }
+
sqlite3DeleteTrigger(pParse->pNewTrigger);
sqliteFree(pParse->apVarExpr);
if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){
diff --git a/ext/pdo_sqlite/sqlite/src/trigger.c b/ext/pdo_sqlite/sqlite/src/trigger.c
index 348dfdd572..15992df381 100644
--- a/ext/pdo_sqlite/sqlite/src/trigger.c
+++ b/ext/pdo_sqlite/sqlite/src/trigger.c
@@ -11,7 +11,6 @@
*
*/
#include "sqliteInt.h"
-#include "vdbe.h"
#ifndef SQLITE_OMIT_TRIGGER
/*
@@ -59,10 +58,13 @@ void sqlite3BeginTrigger(
int iDb; /* The database to store the trigger in */
Token *pName; /* The unqualified db name */
DbFixer sFix;
+ int iTabDb;
+ assert( pName1!=0 ); /* pName1->z might be NULL, but not pName1 itself */
+ assert( pName2!=0 );
if( isTemp ){
/* If TEMP was specified, then the trigger name may not be qualified. */
- if( pName2 && pName2->n>0 ){
+ if( pName2->n>0 ){
sqlite3ErrorMsg(pParse, "temporary trigger may not have qualified name");
goto trigger_cleanup;
}
@@ -81,14 +83,16 @@ void sqlite3BeginTrigger(
** If sqlite3SrcListLookup() returns 0, indicating the table does not
** exist, the error is caught by the block below.
*/
- if( !pTableName || sqlite3_malloc_failed ) goto trigger_cleanup;
+ if( !pTableName || sqlite3MallocFailed() ){
+ goto trigger_cleanup;
+ }
pTab = sqlite3SrcListLookup(pParse, pTableName);
- if( pName2->n==0 && pTab && pTab->iDb==1 ){
+ if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){
iDb = 1;
}
/* Ensure the table name matches database name and that the table exists */
- if( sqlite3_malloc_failed ) goto trigger_cleanup;
+ if( sqlite3MallocFailed() ) goto trigger_cleanup;
assert( pTableName->nSrc==1 );
if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) &&
sqlite3FixSrcList(&sFix, pTableName) ){
@@ -99,6 +103,10 @@ void sqlite3BeginTrigger(
/* The table does not exist. */
goto trigger_cleanup;
}
+ if( IsVirtual(pTab) ){
+ sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables");
+ goto trigger_cleanup;
+ }
/* Check that the trigger name is not reserved and that no trigger of the
** specified name exists */
@@ -106,7 +114,7 @@ void sqlite3BeginTrigger(
if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
goto trigger_cleanup;
}
- if( sqlite3HashFind(&(db->aDb[iDb].trigHash), zName,pName->n+1) ){
+ if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), zName,strlen(zName)) ){
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
goto trigger_cleanup;
}
@@ -131,17 +139,18 @@ void sqlite3BeginTrigger(
" trigger on table: %S", pTableName, 0);
goto trigger_cleanup;
}
+ iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code = SQLITE_CREATE_TRIGGER;
- const char *zDb = db->aDb[pTab->iDb].zName;
+ const char *zDb = db->aDb[iTabDb].zName;
const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb;
- if( pTab->iDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
+ if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){
goto trigger_cleanup;
}
- if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(pTab->iDb),0,zDb)){
+ if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb),0,zDb)){
goto trigger_cleanup;
}
}
@@ -162,8 +171,8 @@ void sqlite3BeginTrigger(
pTrigger->name = zName;
zName = 0;
pTrigger->table = sqliteStrDup(pTableName->a[0].zName);
- pTrigger->iDb = iDb;
- pTrigger->iTabDb = pTab->iDb;
+ pTrigger->pSchema = db->aDb[iDb].pSchema;
+ pTrigger->pTabSchema = pTab->pSchema;
pTrigger->op = op;
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
pTrigger->pWhen = sqlite3ExprDup(pWhen);
@@ -197,16 +206,18 @@ void sqlite3FinishTrigger(
Trigger *pTrig = 0; /* The trigger whose construction is finishing up */
sqlite3 *db = pParse->db; /* The database */
DbFixer sFix;
+ int iDb; /* Database containing the trigger */
pTrig = pParse->pNewTrigger;
pParse->pNewTrigger = 0;
- if( pParse->nErr || pTrig==0 ) goto triggerfinish_cleanup;
+ if( pParse->nErr || !pTrig ) goto triggerfinish_cleanup;
+ iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
pTrig->step_list = pStepList;
while( pStepList ){
pStepList->pTrig = pTrig;
pStepList = pStepList->pNext;
}
- if( sqlite3FixInit(&sFix, pParse, pTrig->iDb, "trigger", &pTrig->nameToken)
+ if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", &pTrig->nameToken)
&& sqlite3FixTriggerStep(&sFix, pTrig->step_list) ){
goto triggerfinish_cleanup;
}
@@ -224,7 +235,7 @@ void sqlite3FinishTrigger(
{ OP_String8, 0, 0, "CREATE TRIGGER "},
{ OP_String8, 0, 0, 0 }, /* 6: SQL */
{ OP_Concat, 0, 0, 0 },
- { OP_MakeRecord, 5, 0, "tttit" },
+ { OP_MakeRecord, 5, 0, "aaada" },
{ OP_Insert, 0, 0, 0 },
};
int addr;
@@ -233,28 +244,30 @@ void sqlite3FinishTrigger(
/* Make an entry in the sqlite_master table */
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto triggerfinish_cleanup;
- sqlite3BeginWriteOperation(pParse, 0, pTrig->iDb);
- sqlite3OpenMasterTable(v, pTrig->iDb);
+ sqlite3BeginWriteOperation(pParse, 0, iDb);
+ sqlite3OpenMasterTable(pParse, iDb);
addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
sqlite3VdbeChangeP3(v, addr+2, pTrig->name, 0);
sqlite3VdbeChangeP3(v, addr+3, pTrig->table, 0);
- sqlite3VdbeChangeP3(v, addr+6, pAll->z, pAll->n);
- sqlite3ChangeCookie(db, v, pTrig->iDb);
+ sqlite3VdbeChangeP3(v, addr+6, (char*)pAll->z, pAll->n);
+ sqlite3ChangeCookie(db, v, iDb);
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
- sqlite3VdbeOp3(v, OP_ParseSchema, pTrig->iDb, 0,
+ sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0,
sqlite3MPrintf("type='trigger' AND name='%q'", pTrig->name), P3_DYNAMIC);
}
if( db->init.busy ){
+ int n;
Table *pTab;
Trigger *pDel;
- pDel = sqlite3HashInsert(&db->aDb[pTrig->iDb].trigHash,
- pTrig->name, strlen(pTrig->name)+1, pTrig);
+ pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash,
+ pTrig->name, strlen(pTrig->name), pTrig);
if( pDel ){
- assert( sqlite3_malloc_failed && pDel==pTrig );
+ assert( sqlite3MallocFailed() && pDel==pTrig );
goto triggerfinish_cleanup;
}
- pTab = sqlite3LocateTable(pParse,pTrig->table,db->aDb[pTrig->iTabDb].zName);
+ n = strlen(pTrig->table) + 1;
+ pTab = sqlite3HashFind(&pTrig->pTabSchema->tblHash, pTrig->table, n);
assert( pTab!=0 );
pTrig->pNext = pTab->pTrigger;
pTab->pTrigger = pTrig;
@@ -279,7 +292,7 @@ triggerfinish_cleanup:
*/
static void sqlitePersistTriggerStep(TriggerStep *p){
if( p->target.z ){
- p->target.z = sqliteStrNDup(p->target.z, p->target.n);
+ p->target.z = (u8*)sqliteStrNDup((char*)p->target.z, p->target.n);
p->target.dyn = 1;
}
if( p->pSelect ){
@@ -313,7 +326,10 @@ static void sqlitePersistTriggerStep(TriggerStep *p){
*/
TriggerStep *sqlite3TriggerSelectStep(Select *pSelect){
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
- if( pTriggerStep==0 ) return 0;
+ if( pTriggerStep==0 ) {
+ sqlite3SelectDelete(pSelect);
+ return 0;
+ }
pTriggerStep->op = TK_SELECT;
pTriggerStep->pSelect = pSelect;
@@ -431,7 +447,7 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
int nName;
sqlite3 *db = pParse->db;
- if( sqlite3_malloc_failed ) goto drop_trigger_cleanup;
+ if( sqlite3MallocFailed() ) goto drop_trigger_cleanup;
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto drop_trigger_cleanup;
}
@@ -443,14 +459,14 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;
- pTrigger = sqlite3HashFind(&(db->aDb[j].trigHash), zName, nName+1);
+ pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName, nName);
if( pTrigger ) break;
}
if( !pTrigger ){
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
goto drop_trigger_cleanup;
}
- sqlite3DropTriggerPtr(pParse, pTrigger, 0);
+ sqlite3DropTriggerPtr(pParse, pTrigger);
drop_trigger_cleanup:
sqlite3SrcListDelete(pName);
@@ -460,27 +476,26 @@ drop_trigger_cleanup:
** Return a pointer to the Table structure for the table that a trigger
** is set on.
*/
-static Table *tableOfTrigger(sqlite3 *db, Trigger *pTrigger){
- return sqlite3FindTable(db,pTrigger->table,db->aDb[pTrigger->iTabDb].zName);
+static Table *tableOfTrigger(Trigger *pTrigger){
+ int n = strlen(pTrigger->table) + 1;
+ return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table, n);
}
/*
-** Drop a trigger given a pointer to that trigger. If nested is false,
-** then also generate code to remove the trigger from the SQLITE_MASTER
-** table.
+** Drop a trigger given a pointer to that trigger.
*/
-void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
+void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
Table *pTable;
Vdbe *v;
sqlite3 *db = pParse->db;
int iDb;
- iDb = pTrigger->iDb;
+ iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema);
assert( iDb>=0 && iDb<db->nDb );
- pTable = tableOfTrigger(db, pTrigger);
- assert(pTable);
- assert( pTable->iDb==iDb || iDb==1 );
+ pTable = tableOfTrigger(pTrigger);
+ assert( pTable );
+ assert( pTable->pSchema==pTrigger->pSchema || iDb==1 );
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code = SQLITE_DROP_TRIGGER;
@@ -496,7 +511,8 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
/* Generate code to destroy the database record of the trigger.
*/
- if( pTable!=0 && (v = sqlite3GetVdbe(pParse))!=0 ){
+ assert( pTable!=0 );
+ if( (v = sqlite3GetVdbe(pParse))!=0 ){
int base;
static const VdbeOpList dropTrigger[] = {
{ OP_Rewind, 0, ADDR(9), 0},
@@ -511,7 +527,7 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
};
sqlite3BeginWriteOperation(pParse, 0, iDb);
- sqlite3OpenMasterTable(v, iDb);
+ sqlite3OpenMasterTable(pParse, iDb);
base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0);
sqlite3ChangeCookie(db, v, iDb);
@@ -526,9 +542,10 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
Trigger *pTrigger;
int nName = strlen(zName);
- pTrigger = sqlite3HashInsert(&(db->aDb[iDb].trigHash), zName, nName+1, 0);
+ pTrigger = sqlite3HashInsert(&(db->aDb[iDb].pSchema->trigHash),
+ zName, nName, 0);
if( pTrigger ){
- Table *pTable = tableOfTrigger(db, pTrigger);
+ Table *pTable = tableOfTrigger(pTrigger);
assert( pTable!=0 );
if( pTable->pTrigger == pTrigger ){
pTable->pTrigger = pTrigger->pNext;
@@ -581,19 +598,13 @@ int sqlite3TriggersExist(
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
ExprList *pChanges /* Columns that change in an UPDATE statement */
){
- Trigger *pTrigger = pTab->pTrigger;
+ Trigger *pTrigger;
int mask = 0;
+ pTrigger = IsVirtual(pTab) ? 0 : pTab->pTrigger;
while( pTrigger ){
if( pTrigger->op==op && checkColumnOverLap(pTrigger->pColumns, pChanges) ){
- TriggerStack *ss;
- ss = pParse->trigStack;
- while( ss && ss->pTrigger!=pTab->pTrigger ){
- ss = ss->pNext;
- }
- if( ss==0 ){
- mask |= pTrigger->tr_tm;
- }
+ mask |= pTrigger->tr_tm;
}
pTrigger = pTrigger->pNext;
}
@@ -618,11 +629,11 @@ static SrcList *targetSrcList(
int iDb; /* Index of the database to use */
SrcList *pSrc; /* SrcList to be returned */
- iDb = pStep->pTrig->iDb;
+ iDb = sqlite3SchemaToIndex(pParse->db, pStep->pTrig->pSchema);
if( iDb==0 || iDb>=2 ){
assert( iDb<pParse->db->nDb );
- sDb.z = pParse->db->aDb[iDb].zName;
- sDb.n = strlen(sDb.z);
+ sDb.z = (u8*)pParse->db->aDb[iDb].zName;
+ sDb.n = strlen((char*)sDb.z);
pSrc = sqlite3SrcListAppend(0, &sDb, &pStep->target);
} else {
pSrc = sqlite3SrcListAppend(0, &pStep->target, 0);
@@ -731,8 +742,7 @@ int sqlite3CodeRowTrigger(
int orconf, /* ON CONFLICT policy */
int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */
){
- Trigger *pTrigger;
- TriggerStack *pStack;
+ Trigger *p;
TriggerStack trigStackEntry;
assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
@@ -740,22 +750,28 @@ int sqlite3CodeRowTrigger(
assert(newIdx != -1 || oldIdx != -1);
- pTrigger = pTab->pTrigger;
- while( pTrigger ){
+ for(p=pTab->pTrigger; p; p=p->pNext){
int fire_this = 0;
- /* determine whether we should code this trigger */
- if( pTrigger->op == op && pTrigger->tr_tm == tr_tm ){
- fire_this = 1;
- for(pStack=pParse->trigStack; pStack; pStack=pStack->pNext){
- if( pStack->pTrigger==pTrigger ){
- fire_this = 0;
- }
+ /* Determine whether we should code this trigger */
+ if(
+ p->op==op &&
+ p->tr_tm==tr_tm &&
+ (p->pSchema==p->pTabSchema || p->pSchema==pParse->db->aDb[1].pSchema) &&
+ (op!=TK_UPDATE||!p->pColumns||checkColumnOverLap(p->pColumns,pChanges))
+ ){
+ TriggerStack *pS; /* Pointer to trigger-stack entry */
+ for(pS=pParse->trigStack; pS && p!=pS->pTrigger; pS=pS->pNext){}
+ if( !pS ){
+ fire_this = 1;
}
- if( op == TK_UPDATE && pTrigger->pColumns &&
- !checkColumnOverLap(pTrigger->pColumns, pChanges) ){
- fire_this = 0;
+#if 0 /* Give no warning for recursive triggers. Just do not do them */
+ else{
+ sqlite3ErrorMsg(pParse, "recursive triggers not supported (%s)",
+ p->name);
+ return SQLITE_ERROR;
}
+#endif
}
if( fire_this ){
@@ -768,18 +784,18 @@ int sqlite3CodeRowTrigger(
sNC.pParse = pParse;
/* Push an entry on to the trigger stack */
- trigStackEntry.pTrigger = pTrigger;
+ trigStackEntry.pTrigger = p;
trigStackEntry.newIdx = newIdx;
trigStackEntry.oldIdx = oldIdx;
trigStackEntry.pTab = pTab;
trigStackEntry.pNext = pParse->trigStack;
trigStackEntry.ignoreJump = ignoreJump;
pParse->trigStack = &trigStackEntry;
- sqlite3AuthContextPush(pParse, &sContext, pTrigger->name);
+ sqlite3AuthContextPush(pParse, &sContext, p->name);
/* code the WHEN clause */
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
- whenExpr = sqlite3ExprDup(pTrigger->pWhen);
+ whenExpr = sqlite3ExprDup(p->pWhen);
if( sqlite3ExprResolveNames(&sNC, whenExpr) ){
pParse->trigStack = trigStackEntry.pNext;
sqlite3ExprDelete(whenExpr);
@@ -788,7 +804,7 @@ int sqlite3CodeRowTrigger(
sqlite3ExprIfFalse(pParse, whenExpr, endTrigger, 1);
sqlite3ExprDelete(whenExpr);
- codeTriggerProgram(pParse, pTrigger->step_list, orconf);
+ codeTriggerProgram(pParse, p->step_list, orconf);
/* Pop the entry off the trigger stack */
pParse->trigStack = trigStackEntry.pNext;
@@ -796,7 +812,6 @@ int sqlite3CodeRowTrigger(
sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger);
}
- pTrigger = pTrigger->pNext;
}
return 0;
}
diff --git a/ext/pdo_sqlite/sqlite/src/update.c b/ext/pdo_sqlite/sqlite/src/update.c
index b6c6b8b1ed..2565787f04 100644
--- a/ext/pdo_sqlite/sqlite/src/update.c
+++ b/ext/pdo_sqlite/sqlite/src/update.c
@@ -16,9 +16,22 @@
*/
#include "sqliteInt.h"
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Forward declaration */
+static void updateVirtualTable(
+ Parse *pParse, /* The parsing context */
+ SrcList *pSrc, /* The virtual table to be modified */
+ Table *pTab, /* The virtual table */
+ ExprList *pChanges, /* The columns to change in the UPDATE statement */
+ Expr *pRowidExpr, /* Expression used to recompute the rowid */
+ int *aXRef, /* Mapping from columns of pTab to entries in pChanges */
+ Expr *pWhere /* WHERE clause of the UPDATE statement */
+);
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
/*
-** The most recently coded instruction was an OP_Column to retrieve column
-** 'i' of table pTab. This routine sets the P3 parameter of the
+** The most recently coded instruction was an OP_Column to retrieve the
+** i-th column of table pTab. This routine sets the P3 parameter of the
** OP_Column to the default value, if any.
**
** The default value of a column is specified by a DEFAULT clause in the
@@ -44,7 +57,7 @@
void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i){
if( pTab && !pTab->pSelect ){
sqlite3_value *pValue;
- u8 enc = sqlite3VdbeDb(v)->enc;
+ u8 enc = ENC(sqlite3VdbeDb(v));
Column *pCol = &pTab->aCol[i];
sqlite3ValueFromExpr(pCol->pDflt, enc, pCol->affinity, &pValue);
if( pValue ){
@@ -89,6 +102,7 @@ void sqlite3Update(
int openAll = 0; /* True if all indices need to be opened */
AuthContext sContext; /* The authorization context */
NameContext sNC; /* The name-context to resolve expressions in */
+ int iDb; /* Database containing the table being updated */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* Trying to update a view */
@@ -99,7 +113,9 @@ void sqlite3Update(
int oldIdx = -1; /* index of trigger "old" temp table */
sContext.pParse = 0;
- if( pParse->nErr || sqlite3_malloc_failed ) goto update_cleanup;
+ if( pParse->nErr || sqlite3MallocFailed() ){
+ goto update_cleanup;
+ }
db = pParse->db;
assert( pTabList->nSrc==1 );
@@ -107,6 +123,7 @@ void sqlite3Update(
*/
pTab = sqlite3SrcListLookup(pParse, pTabList);
if( pTab==0 ) goto update_cleanup;
+ iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
/* Figure out if we have any triggers and if the table being
** updated is a view
@@ -126,10 +143,8 @@ void sqlite3Update(
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
goto update_cleanup;
}
- if( isView ){
- if( sqlite3ViewGetColumnNames(pParse, pTab) ){
- goto update_cleanup;
- }
+ if( sqlite3ViewGetColumnNames(pParse, pTab) ){
+ goto update_cleanup;
}
aXRef = sqliteMallocRaw( sizeof(int) * pTab->nCol );
if( aXRef==0 ) goto update_cleanup;
@@ -192,7 +207,7 @@ void sqlite3Update(
{
int rc;
rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
- pTab->aCol[j].zName, db->aDb[pTab->iDb].zName);
+ pTab->aCol[j].zName, db->aDb[iDb].zName);
if( rc==SQLITE_DENY ){
goto update_cleanup;
}else if( rc==SQLITE_IGNORE ){
@@ -231,7 +246,6 @@ void sqlite3Update(
}
}
if( i<pIdx->nColumn ){
- if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto update_cleanup;
apIdx[nIdx++] = pIdx;
aIdxUsed[j] = 1;
}else{
@@ -239,6 +253,24 @@ void sqlite3Update(
}
}
+ /* Begin generating code.
+ */
+ v = sqlite3GetVdbe(pParse);
+ if( v==0 ) goto update_cleanup;
+ if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
+ sqlite3BeginWriteOperation(pParse, 1, iDb);
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ /* Virtual tables must be handled separately */
+ if( IsVirtual(pTab) ){
+ updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
+ pWhere);
+ pWhere = 0;
+ pTabList = 0;
+ goto update_cleanup;
+ }
+#endif
+
/* Resolve the column names in all the expressions in the
** WHERE clause.
*/
@@ -252,20 +284,13 @@ void sqlite3Update(
sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
}
- /* Begin generating code.
- */
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) goto update_cleanup;
- if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
- sqlite3BeginWriteOperation(pParse, 1, pTab->iDb);
-
/* If we are trying to update a view, realize that view into
** a ephemeral table.
*/
if( isView ){
Select *pView;
pView = sqlite3SelectDup(pTab->pSelect);
- sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0);
+ sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0);
sqlite3SelectDelete(pView);
}
@@ -274,9 +299,9 @@ void sqlite3Update(
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
if( pWInfo==0 ) goto update_cleanup;
- /* Remember the index of every item to be updated.
+ /* Remember the rowid of every item to be updated.
*/
- sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
+ sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
/* End the database scan loop.
@@ -307,7 +332,7 @@ void sqlite3Update(
/* Open a cursor and make it point to the record that is
** being updated.
*/
- sqlite3OpenTableForReading(v, iCur, pTab);
+ sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
}
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
@@ -355,16 +380,14 @@ void sqlite3Update(
}
}
- if( !isView ){
+ if( !isView && !IsVirtual(pTab) ){
/*
** Open every index that needs updating. Note that if any
** index could potentially invoke a REPLACE conflict resolution
** action, then we need to open all indices because we might need
** to be deleting some records.
*/
- sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
- sqlite3VdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
+ sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
if( onError==OE_Replace ){
openAll = 1;
}else{
@@ -378,9 +401,10 @@ void sqlite3Update(
}
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
if( openAll || aIdxUsed[i] ){
- sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
+ KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
+ sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum,
- (char*)&pIdx->keyInfo, P3_KEYINFO);
+ (char*)pKey, P3_KEYINFO_HANDOFF);
assert( pParse->nTab>iCur+i+1 );
}
}
@@ -388,7 +412,7 @@ void sqlite3Update(
/* Loop over every record that needs updating. We have to load
** the old data for each record to be updated because some columns
** might not change and we will need to copy the old value.
- ** Also, the old data is needed to delete the old index entires.
+ ** Also, the old data is needed to delete the old index entries.
** So make the cursor point at the old record.
*/
if( !triggers_exist ){
@@ -429,7 +453,7 @@ void sqlite3Update(
/* Delete the old indices for the current record.
*/
- sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, aIdxUsed);
+ sqlite3GenerateRowIndexDelete(v, pTab, iCur, aIdxUsed);
/* If changing the record number, delete the old record.
*/
@@ -492,7 +516,7 @@ void sqlite3Update(
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);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P3_STATIC);
}
update_cleanup:
@@ -504,3 +528,95 @@ update_cleanup:
sqlite3ExprDelete(pWhere);
return;
}
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/*
+** Generate code for an UPDATE of a virtual table.
+**
+** The strategy is that we create an ephemerial table that contains
+** for each row to be changed:
+**
+** (A) The original rowid of that row.
+** (B) The revised rowid for the row. (note1)
+** (C) The content of every column in the row.
+**
+** Then we loop over this ephemeral table and for each row in
+** the ephermeral table call VUpdate.
+**
+** When finished, drop the ephemeral table.
+**
+** (note1) Actually, if we know in advance that (A) is always the same
+** as (B) we only store (A), then duplicate (A) when pulling
+** it out of the ephemeral table before calling VUpdate.
+*/
+static void updateVirtualTable(
+ Parse *pParse, /* The parsing context */
+ SrcList *pSrc, /* The virtual table to be modified */
+ Table *pTab, /* The virtual table */
+ ExprList *pChanges, /* The columns to change in the UPDATE statement */
+ Expr *pRowid, /* Expression used to recompute the rowid */
+ int *aXRef, /* Mapping from columns of pTab to entries in pChanges */
+ Expr *pWhere /* WHERE clause of the UPDATE statement */
+){
+ Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */
+ ExprList *pEList = 0; /* The result set of the SELECT statement */
+ Select *pSelect = 0; /* The SELECT statement */
+ Expr *pExpr; /* Temporary expression */
+ int ephemTab; /* Table holding the result of the SELECT */
+ int i; /* Loop counter */
+ int addr; /* Address of top of loop */
+
+ /* Construct the SELECT statement that will find the new values for
+ ** all updated rows.
+ */
+ pEList = sqlite3ExprListAppend(0, sqlite3CreateIdExpr("_rowid_"), 0);
+ if( pRowid ){
+ pEList = sqlite3ExprListAppend(pEList, sqlite3ExprDup(pRowid), 0);
+ }
+ assert( pTab->iPKey<0 );
+ for(i=0; i<pTab->nCol; i++){
+ if( aXRef[i]>=0 ){
+ pExpr = sqlite3ExprDup(pChanges->a[aXRef[i]].pExpr);
+ }else{
+ pExpr = sqlite3CreateIdExpr(pTab->aCol[i].zName);
+ }
+ pEList = sqlite3ExprListAppend(pEList, pExpr, 0);
+ }
+ pSelect = sqlite3SelectNew(pEList, pSrc, pWhere, 0, 0, 0, 0, 0, 0);
+
+ /* Create the ephemeral table into which the update results will
+ ** be stored.
+ */
+ assert( v );
+ ephemTab = pParse->nTab++;
+ sqlite3VdbeAddOp(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0));
+
+ /* fill the ephemeral table
+ */
+ sqlite3Select(pParse, pSelect, SRT_Table, ephemTab, 0, 0, 0, 0);
+
+ /*
+ ** Generate code to scan the ephemeral table and call VDelete and
+ ** VInsert
+ */
+ sqlite3VdbeAddOp(v, OP_Rewind, ephemTab, 0);
+ addr = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp(v, OP_Column, ephemTab, 0);
+ if( pRowid ){
+ sqlite3VdbeAddOp(v, OP_Column, ephemTab, 1);
+ }else{
+ sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
+ }
+ for(i=0; i<pTab->nCol; i++){
+ sqlite3VdbeAddOp(v, OP_Column, ephemTab, i+1+(pRowid!=0));
+ }
+ pParse->pVirtualLock = pTab;
+ sqlite3VdbeOp3(v, OP_VUpdate, 0, pTab->nCol+2,
+ (const char*)pTab->pVtab, P3_VTAB);
+ sqlite3VdbeAddOp(v, OP_Next, ephemTab, addr);
+ sqlite3VdbeAddOp(v, OP_Close, ephemTab, 0);
+
+ /* Cleanup */
+ sqlite3SelectDelete(pSelect);
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
diff --git a/ext/pdo_sqlite/sqlite/src/utf.c b/ext/pdo_sqlite/sqlite/src/utf.c
index a96b36c6db..05d238433a 100644
--- a/ext/pdo_sqlite/sqlite/src/utf.c
+++ b/ext/pdo_sqlite/sqlite/src/utf.c
@@ -255,7 +255,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
{
char zBuf[100];
- sqlite3VdbeMemPrettyPrint(pMem, zBuf, 100);
+ sqlite3VdbeMemPrettyPrint(pMem, zBuf);
fprintf(stderr, "INPUT: %s\n", zBuf);
}
#endif
@@ -272,7 +272,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
assert( rc==SQLITE_NOMEM );
return SQLITE_NOMEM;
}
- zIn = pMem->z;
+ zIn = (u8*)pMem->z;
zTerm = &zIn[pMem->n];
while( zIn<zTerm ){
temp = *zIn;
@@ -287,11 +287,11 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
/* Set len to the maximum number of bytes required in the output buffer. */
if( desiredEnc==SQLITE_UTF8 ){
/* When converting from UTF-16, the maximum growth results from
- ** translating a 2-byte character to a 3-byte UTF-8 character (i.e.
- ** code-point 0xFFFC). A single byte is required for the output string
+ ** translating a 2-byte character to a 4-byte UTF-8 character.
+ ** A single byte is required for the output string
** nul-terminator.
*/
- len = (pMem->n/2) * 3 + 1;
+ len = pMem->n * 2 + 1;
}else{
/* When converting from UTF-8 to UTF-16 the maximum growth is caused
** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16
@@ -308,7 +308,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
** obtained from malloc(), or Mem.zShort, if it large enough and not in
** use, or the zShort array on the stack (see above).
*/
- zIn = pMem->z;
+ zIn = (u8*)pMem->z;
zTerm = &zIn[pMem->n];
if( len>NBFS ){
zOut = sqliteMallocRaw(len);
@@ -360,18 +360,18 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
pMem->enc = desiredEnc;
if( zOut==zShort ){
memcpy(pMem->zShort, zOut, len);
- zOut = pMem->zShort;
+ zOut = (u8*)pMem->zShort;
pMem->flags |= (MEM_Term|MEM_Short);
}else{
pMem->flags |= (MEM_Term|MEM_Dyn);
}
- pMem->z = zOut;
+ pMem->z = (char*)zOut;
translate_out:
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
{
char zBuf[100];
- sqlite3VdbeMemPrettyPrint(pMem, zBuf, 100);
+ sqlite3VdbeMemPrettyPrint(pMem, zBuf);
fprintf(stderr, "OUTPUT: %s\n", zBuf);
}
#endif
@@ -451,6 +451,23 @@ int sqlite3utf8CharLen(const char *z, int nByte){
#ifndef SQLITE_OMIT_UTF16
/*
+** Convert a UTF-16 string in the native encoding into a UTF-8 string.
+** Memory to hold the UTF-8 string is obtained from malloc and must be
+** freed by the calling function.
+**
+** NULL is returned if there is an allocation error.
+*/
+char *sqlite3utf16to8(const void *z, int nByte){
+ Mem m;
+ memset(&m, 0, sizeof(m));
+ sqlite3VdbeMemSetStr(&m, z, nByte, SQLITE_UTF16NATIVE, SQLITE_STATIC);
+ sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8);
+ assert( (m.flags & MEM_Term)!=0 || sqlite3MallocFailed() );
+ assert( (m.flags & MEM_Str)!=0 || sqlite3MallocFailed() );
+ return (m.flags & MEM_Dyn)!=0 ? m.z : sqliteStrDup(m.z);
+}
+
+/*
** 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
** of consecutive 0x00 bytes in pZ. If nChar is not less than zero,
@@ -462,6 +479,15 @@ int sqlite3utf16ByteLen(const void *zIn, int nChar){
char const *z = zIn;
int n = 0;
if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
+ /* Using an "if (SQLITE_UTF16NATIVE==SQLITE_UTF16BE)" construct here
+ ** and in other parts of this file means that at one branch will
+ ** not be covered by coverage testing on any single host. But coverage
+ ** will be complete if the tests are run on both a little-endian and
+ ** big-endian host. Because both the UTF16NATIVE and SQLITE_UTF16BE
+ ** macros are constant at compile time the compiler can determine
+ ** which branch will be followed. It is therefore assumed that no runtime
+ ** penalty is paid for this "if" statement.
+ */
while( c && ((nChar<0) || n<nChar) ){
READ_UTF16BE(z, c);
n++;
diff --git a/ext/pdo_sqlite/sqlite/src/util.c b/ext/pdo_sqlite/sqlite/src/util.c
index de716d9820..5ca9ec4086 100644
--- a/ext/pdo_sqlite/sqlite/src/util.c
+++ b/ext/pdo_sqlite/sqlite/src/util.c
@@ -17,37 +17,173 @@
** $Id$
*/
#include "sqliteInt.h"
+#include "os.h"
#include <stdarg.h>
#include <ctype.h>
-#if SQLITE_MEMDEBUG>2 && defined(__GLIBC__)
-#include <execinfo.h>
-void print_stack_trace(){
- void *bt[30];
- int i;
- int n = backtrace(bt, 30);
+/*
+** MALLOC WRAPPER ARCHITECTURE
+**
+** The sqlite code accesses dynamic memory allocation/deallocation by invoking
+** the following six APIs (which may be implemented as macros).
+**
+** sqlite3Malloc()
+** sqlite3MallocRaw()
+** sqlite3Realloc()
+** sqlite3ReallocOrFree()
+** sqlite3Free()
+** sqlite3AllocSize()
+**
+** The function sqlite3FreeX performs the same task as sqlite3Free and is
+** guaranteed to be a real function. The same holds for sqlite3MallocX
+**
+** The above APIs are implemented in terms of the functions provided in the
+** operating-system interface. The OS interface is never accessed directly
+** by code outside of this file.
+**
+** sqlite3OsMalloc()
+** sqlite3OsRealloc()
+** sqlite3OsFree()
+** sqlite3OsAllocationSize()
+**
+** Functions sqlite3MallocRaw() and sqlite3Realloc() may invoke
+** sqlite3_release_memory() if a call to sqlite3OsMalloc() or
+** sqlite3OsRealloc() fails (or if the soft-heap-limit for the thread is
+** exceeded). Function sqlite3Malloc() usually invokes
+** sqlite3MallocRaw().
+**
+** MALLOC TEST WRAPPER ARCHITECTURE
+**
+** The test wrapper provides extra test facilities to ensure the library
+** does not leak memory and handles the failure of the underlying OS level
+** allocation system correctly. It is only present if the library is
+** compiled with the SQLITE_MEMDEBUG macro set.
+**
+** * Guardposts to detect overwrites.
+** * Ability to cause a specific Malloc() or Realloc() to fail.
+** * Audit outstanding memory allocations (i.e check for leaks).
+*/
+
+#define MAX(x,y) ((x)>(y)?(x):(y))
- fprintf(stderr, "STACK: ");
- for(i=0; i<n;i++){
- fprintf(stderr, "%p ", bt[i]);
+#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO)
+/*
+** Set the soft heap-size limit for the current thread. Passing a negative
+** value indicates no limit.
+*/
+void sqlite3_soft_heap_limit(int n){
+ ThreadData *pTd = sqlite3ThreadData();
+ if( pTd ){
+ pTd->nSoftHeapLimit = n;
}
- fprintf(stderr, "\n");
+ sqlite3ReleaseThreadData();
+}
+
+/*
+** Release memory held by SQLite instances created by the current thread.
+*/
+int sqlite3_release_memory(int n){
+ return sqlite3pager_release_memory(n);
}
#else
-#define print_stack_trace()
+/* If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, then define a version
+** of sqlite3_release_memory() to be used by other code in this file.
+** This is done for no better reason than to reduce the number of
+** pre-processor #ifndef statements.
+*/
+#define sqlite3_release_memory(x) 0 /* 0 == no memory freed */
+#endif
+
+#ifdef SQLITE_MEMDEBUG
+/*--------------------------------------------------------------------------
+** Begin code for memory allocation system test layer.
+**
+** Memory debugging is turned on by defining the SQLITE_MEMDEBUG macro.
+**
+** SQLITE_MEMDEBUG==1 -> Fence-posting only (thread safe)
+** SQLITE_MEMDEBUG==2 -> Fence-posting + linked list of allocations (not ts)
+** SQLITE_MEMDEBUG==3 -> Above + backtraces (not thread safe, req. glibc)
+*/
+
+/* Figure out whether or not to store backtrace() information for each malloc.
+** The backtrace() function is only used if SQLITE_MEMDEBUG is set to 2 or
+** greater and glibc is in use. If we don't want to use backtrace(), then just
+** define it as an empty macro and set the amount of space reserved to 0.
+*/
+#if defined(__GLIBC__) && SQLITE_MEMDEBUG>2
+ extern int backtrace(void **, int);
+ #define TESTALLOC_STACKSIZE 128
+ #define TESTALLOC_STACKFRAMES ((TESTALLOC_STACKSIZE-8)/sizeof(void*))
+#else
+ #define backtrace(x, y)
+ #define TESTALLOC_STACKSIZE 0
+ #define TESTALLOC_STACKFRAMES 0
#endif
/*
-** If malloc() ever fails, this global variable gets set to 1.
-** This causes the library to abort and never again function.
+** Number of 32-bit guard words. This should probably be a multiple of
+** 2 since on 64-bit machines we want the value returned by sqliteMalloc()
+** to be 8-byte aligned.
*/
-int sqlite3_malloc_failed = 0;
+#ifndef TESTALLOC_NGUARD
+# define TESTALLOC_NGUARD 2
+#endif
/*
-** If SQLITE_MEMDEBUG is defined, then use versions of malloc() and
-** free() that track memory usage and check for buffer overruns.
+** Size reserved for storing file-name along with each malloc()ed blob.
*/
-#ifdef SQLITE_MEMDEBUG
+#define TESTALLOC_FILESIZE 64
+
+/*
+** Size reserved for storing the user string. Each time a Malloc() or Realloc()
+** call succeeds, up to TESTALLOC_USERSIZE bytes of the string pointed to by
+** sqlite3_malloc_id are stored along with the other test system metadata.
+*/
+#define TESTALLOC_USERSIZE 64
+const char *sqlite3_malloc_id = 0;
+
+/*
+** Blocks used by the test layer have the following format:
+**
+** <sizeof(void *) pNext pointer>
+** <sizeof(void *) pPrev pointer>
+** <TESTALLOC_NGUARD 32-bit guard words>
+** <The application level allocation>
+** <TESTALLOC_NGUARD 32-bit guard words>
+** <32-bit line number>
+** <TESTALLOC_FILESIZE bytes containing null-terminated file name>
+** <TESTALLOC_STACKSIZE bytes of backtrace() output>
+*/
+
+#define TESTALLOC_OFFSET_GUARD1(p) (sizeof(void *) * 2)
+#define TESTALLOC_OFFSET_DATA(p) ( \
+ TESTALLOC_OFFSET_GUARD1(p) + sizeof(u32) * TESTALLOC_NGUARD \
+)
+#define TESTALLOC_OFFSET_GUARD2(p) ( \
+ TESTALLOC_OFFSET_DATA(p) + sqlite3OsAllocationSize(p) - TESTALLOC_OVERHEAD \
+)
+#define TESTALLOC_OFFSET_LINENUMBER(p) ( \
+ TESTALLOC_OFFSET_GUARD2(p) + sizeof(u32) * TESTALLOC_NGUARD \
+)
+#define TESTALLOC_OFFSET_FILENAME(p) ( \
+ TESTALLOC_OFFSET_LINENUMBER(p) + sizeof(u32) \
+)
+#define TESTALLOC_OFFSET_USER(p) ( \
+ TESTALLOC_OFFSET_FILENAME(p) + TESTALLOC_FILESIZE \
+)
+#define TESTALLOC_OFFSET_STACK(p) ( \
+ TESTALLOC_OFFSET_USER(p) + TESTALLOC_USERSIZE + 8 - \
+ (TESTALLOC_OFFSET_USER(p) % 8) \
+)
+
+#define TESTALLOC_OVERHEAD ( \
+ sizeof(void *)*2 + /* pPrev and pNext pointers */ \
+ TESTALLOC_NGUARD*sizeof(u32)*2 + /* Guard words */ \
+ sizeof(u32) + TESTALLOC_FILESIZE + /* File and line number */ \
+ TESTALLOC_USERSIZE + /* User string */ \
+ TESTALLOC_STACKSIZE /* backtrace() stack */ \
+)
+
/*
** For keeping track of the number of mallocs and frees. This
@@ -58,35 +194,31 @@ int sqlite3_malloc_failed = 0;
*/
int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */
int sqlite3_nFree; /* Number of sqliteFree() calls */
-int sqlite3_memUsed; /* Total memory obtained from malloc */
-int sqlite3_memMax; /* Mem usage high-water mark */
+int sqlite3_memUsed; /* TODO Total memory obtained from malloc */
+int sqlite3_memMax; /* TODO Mem usage high-water mark */
int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */
int sqlite3_iMallocReset = -1; /* When iMallocFail reaches 0, set to this */
-#if SQLITE_MEMDEBUG>1
-static int memcnt = 0;
-#endif
-/*
-** Number of 32-bit guard words. This should probably be a multiple of
-** 2 since on 64-bit machines we want the value returned by sqliteMalloc()
-** to be 8-byte aligned.
-*/
-#define N_GUARD 2
+void *sqlite3_pFirst = 0; /* Pointer to linked list of allocations */
+int sqlite3_nMaxAlloc = 0; /* High water mark of ThreadData.nAlloc */
+int sqlite3_mallocDisallowed = 0; /* assert() in sqlite3Malloc() if set */
+int sqlite3_isFail = 0; /* True if all malloc calls should fail */
+const char *sqlite3_zFile = 0; /* Filename to associate debug info with */
+int sqlite3_iLine = 0; /* Line number for debug info */
/*
** Check for a simulated memory allocation failure. Return true if
** the failure should be simulated. Return false to proceed as normal.
*/
-static int simulatedMallocFailure(int n, char *zFile, int line){
+int sqlite3TestMallocFail(){
+ if( sqlite3_isFail ){
+ return 1;
+ }
if( sqlite3_iMallocFail>=0 ){
sqlite3_iMallocFail--;
if( sqlite3_iMallocFail==0 ){
- sqlite3_malloc_failed++;
-#if SQLITE_MEMDEBUG>1
- fprintf(stderr,"**** failed to allocate %d bytes at %s:%d\n",
- n, zFile,line);
-#endif
sqlite3_iMallocFail = sqlite3_iMallocReset;
+ sqlite3_isFail = 1;
return 1;
}
}
@@ -94,290 +226,516 @@ static int simulatedMallocFailure(int n, char *zFile, int line){
}
/*
-** Allocate new memory and set it to zero. Return NULL if
-** no memory is available.
+** The argument is a pointer returned by sqlite3OsMalloc() or xRealloc().
+** assert() that the first and last (TESTALLOC_NGUARD*4) bytes are set to the
+** values set by the applyGuards() function.
*/
-void *sqlite3Malloc_(int n, int bZero, char *zFile, int line){
- void *p;
- int *pi;
- int i, k;
- if( n==0 ){
- return 0;
+static void checkGuards(u32 *p)
+{
+ int i;
+ char *zAlloc = (char *)p;
+ char *z;
+
+ /* First set of guard words */
+ z = &zAlloc[TESTALLOC_OFFSET_GUARD1(p)];
+ for(i=0; i<TESTALLOC_NGUARD; i++){
+ assert(((u32 *)z)[i]==0xdead1122);
}
- if( simulatedMallocFailure(n, zFile, line) ){
- return 0;
+
+ /* Second set of guard words */
+ z = &zAlloc[TESTALLOC_OFFSET_GUARD2(p)];
+ for(i=0; i<TESTALLOC_NGUARD; i++){
+ u32 guard = 0;
+ memcpy(&guard, &z[i*sizeof(u32)], sizeof(u32));
+ assert(guard==0xdead3344);
}
- sqlite3_memUsed += n;
- if( sqlite3_memMax<sqlite3_memUsed ) sqlite3_memMax = sqlite3_memUsed;
- k = (n+sizeof(int)-1)/sizeof(int);
- pi = malloc( (N_GUARD*2+1+k)*sizeof(int));
- if( pi==0 ){
- if( n>0 ) sqlite3_malloc_failed++;
- return 0;
+}
+
+/*
+** The argument is a pointer returned by sqlite3OsMalloc() or Realloc(). The
+** first and last (TESTALLOC_NGUARD*4) bytes are set to known values for use as
+** guard-posts.
+*/
+static void applyGuards(u32 *p)
+{
+ int i;
+ char *z;
+ char *zAlloc = (char *)p;
+
+ /* First set of guard words */
+ z = &zAlloc[TESTALLOC_OFFSET_GUARD1(p)];
+ for(i=0; i<TESTALLOC_NGUARD; i++){
+ ((u32 *)z)[i] = 0xdead1122;
}
- sqlite3_nMalloc++;
- for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122;
- pi[N_GUARD] = n;
- 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_MEMDEBUG>1
- print_stack_trace();
- fprintf(stderr,"%06d malloc %d bytes at 0x%x from %s:%d\n",
- ++memcnt, n, (int)p, zFile,line);
-#endif
- return p;
+
+ /* Second set of guard words */
+ z = &zAlloc[TESTALLOC_OFFSET_GUARD2(p)];
+ for(i=0; i<TESTALLOC_NGUARD; i++){
+ static const int guard = 0xdead3344;
+ memcpy(&z[i*sizeof(u32)], &guard, sizeof(u32));
+ }
+
+ /* Line number */
+ z = &((char *)z)[TESTALLOC_NGUARD*sizeof(u32)]; /* Guard words */
+ z = &zAlloc[TESTALLOC_OFFSET_LINENUMBER(p)];
+ memcpy(z, &sqlite3_iLine, sizeof(u32));
+
+ /* File name */
+ z = &zAlloc[TESTALLOC_OFFSET_FILENAME(p)];
+ strncpy(z, sqlite3_zFile, TESTALLOC_FILESIZE);
+ z[TESTALLOC_FILESIZE - 1] = '\0';
+
+ /* User string */
+ z = &zAlloc[TESTALLOC_OFFSET_USER(p)];
+ z[0] = 0;
+ if( sqlite3_malloc_id ){
+ strncpy(z, sqlite3_malloc_id, TESTALLOC_USERSIZE);
+ z[TESTALLOC_USERSIZE-1] = 0;
+ }
+
+ /* backtrace() stack */
+ z = &zAlloc[TESTALLOC_OFFSET_STACK(p)];
+ backtrace((void **)z, TESTALLOC_STACKFRAMES);
+
+ /* Sanity check to make sure checkGuards() is working */
+ checkGuards(p);
}
/*
-** This version of malloc is always a real function, never a macro
+** The argument is a malloc()ed pointer as returned by the test-wrapper.
+** Return a pointer to the Os level allocation.
*/
-void *sqlite3MallocX(int n){
- return sqlite3Malloc_(n, 0, __FILE__, __LINE__);
+static void *getOsPointer(void *p)
+{
+ char *z = (char *)p;
+ return (void *)(&z[-1 * TESTALLOC_OFFSET_DATA(p)]);
}
+
+#if SQLITE_MEMDEBUG>1
/*
-** Check to see if the given pointer was obtained from sqliteMalloc()
-** and is able to hold at least N bytes. Raise an exception if this
-** is not the case.
-**
-** This routine is used for testing purposes only.
+** The argument points to an Os level allocation. Link it into the threads list
+** of allocations.
*/
-void sqlite3CheckMemory(void *p, int N){
- int *pi = p;
- int n, i, k;
- pi -= N_GUARD+1;
- for(i=0; i<N_GUARD; i++){
- assert( pi[i]==0xdead1122 );
- }
- n = pi[N_GUARD];
- assert( N>=0 && N<n );
- k = (n+sizeof(int)-1)/sizeof(int);
- for(i=0; i<N_GUARD; i++){
- assert( pi[k+N_GUARD+1+i]==0xdead3344 );
+static void linkAlloc(void *p){
+ void **pp = (void **)p;
+ pp[0] = 0;
+ pp[1] = sqlite3_pFirst;
+ if( sqlite3_pFirst ){
+ ((void **)sqlite3_pFirst)[0] = p;
}
+ sqlite3_pFirst = p;
}
/*
-** Free memory previously obtained from sqliteMalloc()
+** The argument points to an Os level allocation. Unlinke it from the threads
+** list of allocations.
*/
-void sqlite3Free_(void *p, char *zFile, int line){
- if( p ){
- int *pi, i, k, n;
- pi = p;
- pi -= N_GUARD+1;
- sqlite3_nFree++;
- for(i=0; i<N_GUARD; i++){
- if( pi[i]!=0xdead1122 ){
- fprintf(stderr,"Low-end memory corruption at 0x%x\n", (int)p);
- return;
- }
+static void unlinkAlloc(void *p)
+{
+ void **pp = (void **)p;
+ if( p==sqlite3_pFirst ){
+ assert(!pp[0]);
+ assert(!pp[1] || ((void **)(pp[1]))[0]==p);
+ sqlite3_pFirst = pp[1];
+ if( sqlite3_pFirst ){
+ ((void **)sqlite3_pFirst)[0] = 0;
}
- n = pi[N_GUARD];
- sqlite3_memUsed -= n;
- k = (n+sizeof(int)-1)/sizeof(int);
- for(i=0; i<N_GUARD; i++){
- if( pi[k+N_GUARD+1+i]!=0xdead3344 ){
- fprintf(stderr,"High-end memory corruption at 0x%x\n", (int)p);
- return;
- }
+ }else{
+ void **pprev = pp[0];
+ void **pnext = pp[1];
+ assert(pprev);
+ assert(pprev[1]==p);
+ pprev[1] = (void *)pnext;
+ if( pnext ){
+ assert(pnext[0]==p);
+ pnext[0] = (void *)pprev;
}
- memset(pi, 0xff, (k+N_GUARD*2+1)*sizeof(int));
-#if SQLITE_MEMDEBUG>1
- fprintf(stderr,"%06d free %d bytes at 0x%x from %s:%d\n",
- ++memcnt, n, (int)p, zFile,line);
-#endif
- free(pi);
}
}
/*
-** Resize a prior allocation. If p==0, then this routine
-** works just like sqliteMalloc(). If n==0, then this routine
-** works just like sqliteFree().
+** Pointer p is a pointer to an OS level allocation that has just been
+** realloc()ed. Set the list pointers that point to this entry to it's new
+** location.
*/
-void *sqlite3Realloc_(void *oldP, int n, char *zFile, int line){
- int *oldPi, *pi, i, k, oldN, oldK;
- void *p;
- if( oldP==0 ){
- return sqlite3Malloc_(n,1,zFile,line);
- }
- if( n==0 ){
- sqlite3Free_(oldP,zFile,line);
- return 0;
- }
- if( simulatedMallocFailure(n, zFile, line) ){
- return 0;
+static void relinkAlloc(void *p)
+{
+ void **pp = (void **)p;
+ if( pp[0] ){
+ ((void **)(pp[0]))[1] = p;
+ }else{
+ sqlite3_pFirst = p;
}
- oldPi = oldP;
- oldPi -= N_GUARD+1;
- if( oldPi[0]!=0xdead1122 ){
- fprintf(stderr,"Low-end memory corruption in realloc at 0x%x\n", (int)oldP);
- return 0;
+ if( pp[1] ){
+ ((void **)(pp[1]))[0] = p;
}
- oldN = oldPi[N_GUARD];
- sqlite3_memUsed -= oldN;
- oldK = (oldN+sizeof(int)-1)/sizeof(int);
- for(i=0; i<N_GUARD; i++){
- if( oldPi[oldK+N_GUARD+1+i]!=0xdead3344 ){
- fprintf(stderr,"High-end memory corruption in realloc at 0x%x\n",
- (int)oldP);
- return 0;
+}
+#else
+#define linkAlloc(x)
+#define relinkAlloc(x)
+#define unlinkAlloc(x)
+#endif
+
+/*
+** This function sets the result of the Tcl interpreter passed as an argument
+** to a list containing an entry for each currently outstanding call made to
+** sqliteMalloc and friends by the current thread. Each list entry is itself a
+** list, consisting of the following (in order):
+**
+** * The number of bytes allocated
+** * The __FILE__ macro at the time of the sqliteMalloc() call.
+** * The __LINE__ macro ...
+** * The value of the sqlite3_malloc_id variable ...
+** * The output of backtrace() (if available) ...
+**
+** Todo: We could have a version of this function that outputs to stdout,
+** to debug memory leaks when Tcl is not available.
+*/
+#if defined(TCLSH) && defined(SQLITE_DEBUG) && SQLITE_MEMDEBUG>1
+#include <tcl.h>
+int sqlite3OutstandingMallocs(Tcl_Interp *interp){
+ void *p;
+ Tcl_Obj *pRes = Tcl_NewObj();
+ Tcl_IncrRefCount(pRes);
+
+
+ for(p=sqlite3_pFirst; p; p=((void **)p)[1]){
+ Tcl_Obj *pEntry = Tcl_NewObj();
+ Tcl_Obj *pStack = Tcl_NewObj();
+ char *z;
+ u32 iLine;
+ int nBytes = sqlite3OsAllocationSize(p) - TESTALLOC_OVERHEAD;
+ char *zAlloc = (char *)p;
+ int i;
+
+ Tcl_ListObjAppendElement(0, pEntry, Tcl_NewIntObj(nBytes));
+
+ z = &zAlloc[TESTALLOC_OFFSET_FILENAME(p)];
+ Tcl_ListObjAppendElement(0, pEntry, Tcl_NewStringObj(z, -1));
+
+ z = &zAlloc[TESTALLOC_OFFSET_LINENUMBER(p)];
+ memcpy(&iLine, z, sizeof(u32));
+ Tcl_ListObjAppendElement(0, pEntry, Tcl_NewIntObj(iLine));
+
+ z = &zAlloc[TESTALLOC_OFFSET_USER(p)];
+ Tcl_ListObjAppendElement(0, pEntry, Tcl_NewStringObj(z, -1));
+
+ z = &zAlloc[TESTALLOC_OFFSET_STACK(p)];
+ for(i=0; i<TESTALLOC_STACKFRAMES; i++){
+ char zHex[128];
+ sprintf(zHex, "%p", ((void **)z)[i]);
+ Tcl_ListObjAppendElement(0, pStack, Tcl_NewStringObj(zHex, -1));
}
+
+ Tcl_ListObjAppendElement(0, pEntry, pStack);
+ Tcl_ListObjAppendElement(0, pRes, pEntry);
}
- k = (n + sizeof(int) - 1)/sizeof(int);
- pi = malloc( (k+N_GUARD*2+1)*sizeof(int) );
- if( pi==0 ){
- if( n>0 ) sqlite3_malloc_failed++;
- return 0;
- }
- for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122;
- pi[N_GUARD] = n;
- sqlite3_memUsed += n;
- if( sqlite3_memMax<sqlite3_memUsed ) sqlite3_memMax = sqlite3_memUsed;
- for(i=0; i<N_GUARD; i++) pi[k+N_GUARD+1+i] = 0xdead3344;
- p = &pi[N_GUARD+1];
- memcpy(p, oldP, n>oldN ? oldN : n);
- if( n>oldN ){
- memset(&((char*)p)[oldN], 0x55, n-oldN);
- }
- memset(oldPi, 0xab, (oldK+N_GUARD+2)*sizeof(int));
- free(oldPi);
-#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);
-#endif
- return p;
+
+ Tcl_ResetResult(interp);
+ Tcl_SetObjResult(interp, pRes);
+ Tcl_DecrRefCount(pRes);
+ return TCL_OK;
}
+#endif
/*
-** Make a copy of a string in memory obtained from sqliteMalloc()
+** This is the test layer's wrapper around sqlite3OsMalloc().
*/
-char *sqlite3StrDup_(const char *z, char *zFile, int line){
- char *zNew;
- if( z==0 ) return 0;
- zNew = sqlite3Malloc_(strlen(z)+1, 0, zFile, line);
- if( zNew ) strcpy(zNew, z);
- return zNew;
+static void * OSMALLOC(int n){
+ sqlite3OsEnterMutex();
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ sqlite3_nMaxAlloc =
+ MAX(sqlite3_nMaxAlloc, sqlite3ThreadDataReadOnly()->nAlloc);
+#endif
+ assert( !sqlite3_mallocDisallowed );
+ if( !sqlite3TestMallocFail() ){
+ u32 *p;
+ p = (u32 *)sqlite3OsMalloc(n + TESTALLOC_OVERHEAD);
+ assert(p);
+ sqlite3_nMalloc++;
+ applyGuards(p);
+ linkAlloc(p);
+ sqlite3OsLeaveMutex();
+ return (void *)(&p[TESTALLOC_NGUARD + 2*sizeof(void *)/sizeof(u32)]);
+ }
+ sqlite3OsLeaveMutex();
+ return 0;
}
-char *sqlite3StrNDup_(const char *z, int n, char *zFile, int line){
- char *zNew;
- if( z==0 ) return 0;
- zNew = sqlite3Malloc_(n+1, 0, zFile, line);
- if( zNew ){
- memcpy(zNew, z, n);
- zNew[n] = 0;
+
+static int OSSIZEOF(void *p){
+ if( p ){
+ u32 *pOs = (u32 *)getOsPointer(p);
+ return sqlite3OsAllocationSize(pOs) - TESTALLOC_OVERHEAD;
}
- return zNew;
+ return 0;
}
/*
-** A version of sqliteFree that is always a function, not a macro.
+** This is the test layer's wrapper around sqlite3OsFree(). The argument is a
+** pointer to the space allocated for the application to use.
*/
-void sqlite3FreeX(void *p){
- sqliteFree(p);
+static void OSFREE(void *pFree){
+ u32 *p; /* Pointer to the OS-layer allocation */
+ sqlite3OsEnterMutex();
+ p = (u32 *)getOsPointer(pFree);
+ checkGuards(p);
+ unlinkAlloc(p);
+ memset(pFree, 0x55, OSSIZEOF(pFree));
+ sqlite3OsFree(p);
+ sqlite3_nFree++;
+ sqlite3OsLeaveMutex();
}
-#endif /* SQLITE_MEMDEBUG */
/*
-** The following versions of malloc() and free() are for use in a
-** normal build.
+** This is the test layer's wrapper around sqlite3OsRealloc().
*/
-#if !defined(SQLITE_MEMDEBUG)
+static void * OSREALLOC(void *pRealloc, int n){
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ sqlite3_nMaxAlloc =
+ MAX(sqlite3_nMaxAlloc, sqlite3ThreadDataReadOnly()->nAlloc);
+#endif
+ assert( !sqlite3_mallocDisallowed );
+ if( !sqlite3TestMallocFail() ){
+ u32 *p = (u32 *)getOsPointer(pRealloc);
+ checkGuards(p);
+ p = sqlite3OsRealloc(p, n + TESTALLOC_OVERHEAD);
+ applyGuards(p);
+ relinkAlloc(p);
+ return (void *)(&p[TESTALLOC_NGUARD + 2*sizeof(void *)/sizeof(u32)]);
+ }
+ return 0;
+}
+static void OSMALLOC_FAILED(){
+ sqlite3_isFail = 0;
+}
+
+#else
+/* Define macros to call the sqlite3OsXXX interface directly if
+** the SQLITE_MEMDEBUG macro is not defined.
+*/
+#define OSMALLOC(x) sqlite3OsMalloc(x)
+#define OSREALLOC(x,y) sqlite3OsRealloc(x,y)
+#define OSFREE(x) sqlite3OsFree(x)
+#define OSSIZEOF(x) sqlite3OsAllocationSize(x)
+#define OSMALLOC_FAILED()
+
+#endif /* SQLITE_MEMDEBUG */
/*
-** Allocate new memory and set it to zero. Return NULL if
-** no memory is available. See also sqliteMallocRaw().
+** End code for memory allocation system test layer.
+**--------------------------------------------------------------------------*/
+
+/*
+** This routine is called when we are about to allocate n additional bytes
+** of memory. If the new allocation will put is over the soft allocation
+** limit, then invoke sqlite3_release_memory() to try to release some
+** memory before continuing with the allocation.
+**
+** This routine also makes sure that the thread-specific-data (TSD) has
+** be allocated. If it has not and can not be allocated, then return
+** false. The updateMemoryUsedCount() routine below will deallocate
+** the TSD if it ought to be.
+**
+** If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, this routine is
+** a no-op
+*/
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+static int enforceSoftLimit(int n){
+ ThreadData *pTsd = sqlite3ThreadData();
+ if( pTsd==0 ){
+ return 0;
+ }
+ assert( pTsd->nAlloc>=0 );
+ if( n>0 && pTsd->nSoftHeapLimit>0 ){
+ while( pTsd->nAlloc+n>pTsd->nSoftHeapLimit && sqlite3_release_memory(n) ){}
+ }
+ return 1;
+}
+#else
+# define enforceSoftLimit(X) 1
+#endif
+
+/*
+** Update the count of total outstanding memory that is held in
+** thread-specific-data (TSD). If after this update the TSD is
+** no longer being used, then deallocate it.
+**
+** If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, this routine is
+** a no-op
*/
-void *sqlite3Malloc(int n){
- void *p;
- if( n==0 ) return 0;
- if( (p = malloc(n))==0 ){
- if( n>0 ) sqlite3_malloc_failed++;
- }else{
- memset(p, 0, n);
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+static void updateMemoryUsedCount(int n){
+ ThreadData *pTsd = sqlite3ThreadData();
+ if( pTsd ){
+ pTsd->nAlloc += n;
+ assert( pTsd->nAlloc>=0 );
+ if( pTsd->nAlloc==0 && pTsd->nSoftHeapLimit==0 ){
+ sqlite3ReleaseThreadData();
+ }
}
- return p;
}
+#else
+#define updateMemoryUsedCount(x) /* no-op */
+#endif
/*
-** Allocate new memory but do not set it to zero. Return NULL if
-** no memory is available. See also sqliteMalloc().
+** Allocate and return N bytes of uninitialised memory by calling
+** sqlite3OsMalloc(). If the Malloc() call fails, attempt to free memory
+** by calling sqlite3_release_memory().
*/
-void *sqlite3MallocRaw(int n){
- void *p;
- if( n==0 ) return 0;
- if( (p = malloc(n))==0 ){
- if( n>0 ) sqlite3_malloc_failed++;
+void *sqlite3MallocRaw(int n, int doMemManage){
+ void *p = 0;
+ if( n>0 && !sqlite3MallocFailed() && (!doMemManage || enforceSoftLimit(n)) ){
+ while( (p = OSMALLOC(n))==0 && sqlite3_release_memory(n) ){}
+ if( !p ){
+ sqlite3FailedMalloc();
+ OSMALLOC_FAILED();
+ }else if( doMemManage ){
+ updateMemoryUsedCount(OSSIZEOF(p));
+ }
}
return p;
}
/*
-** Free memory previously obtained from sqliteMalloc()
+** Resize the allocation at p to n bytes by calling sqlite3OsRealloc(). The
+** pointer to the new allocation is returned. If the Realloc() call fails,
+** attempt to free memory by calling sqlite3_release_memory().
+*/
+void *sqlite3Realloc(void *p, int n){
+ if( sqlite3MallocFailed() ){
+ return 0;
+ }
+
+ if( !p ){
+ return sqlite3Malloc(n, 1);
+ }else{
+ void *np = 0;
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ int origSize = OSSIZEOF(p);
+#endif
+ if( enforceSoftLimit(n - origSize) ){
+ while( (np = OSREALLOC(p, n))==0 && sqlite3_release_memory(n) ){}
+ if( !np ){
+ sqlite3FailedMalloc();
+ OSMALLOC_FAILED();
+ }else{
+ updateMemoryUsedCount(OSSIZEOF(np) - origSize);
+ }
+ }
+ return np;
+ }
+}
+
+/*
+** Free the memory pointed to by p. p must be either a NULL pointer or a
+** value returned by a previous call to sqlite3Malloc() or sqlite3Realloc().
*/
void sqlite3FreeX(void *p){
if( p ){
- free(p);
+ updateMemoryUsedCount(0 - OSSIZEOF(p));
+ OSFREE(p);
}
}
/*
-** Resize a prior allocation. If p==0, then this routine
-** works just like sqliteMalloc(). If n==0, then this routine
-** works just like sqliteFree().
+** A version of sqliteMalloc() that is always a function, not a macro.
+** Currently, this is used only to alloc to allocate the parser engine.
*/
-void *sqlite3Realloc(void *p, int n){
- void *p2;
- if( p==0 ){
- return sqliteMalloc(n);
+void *sqlite3MallocX(int n){
+ return sqliteMalloc(n);
+}
+
+/*
+** sqlite3Malloc
+** sqlite3ReallocOrFree
+**
+** These two are implemented as wrappers around sqlite3MallocRaw(),
+** sqlite3Realloc() and sqlite3Free().
+*/
+void *sqlite3Malloc(int n, int doMemManage){
+ void *p = sqlite3MallocRaw(n, doMemManage);
+ if( p ){
+ memset(p, 0, n);
}
- if( n==0 ){
- sqliteFree(p);
- return 0;
+ return p;
+}
+void sqlite3ReallocOrFree(void **pp, int n){
+ void *p = sqlite3Realloc(*pp, n);
+ if( !p ){
+ sqlite3FreeX(*pp);
}
- p2 = realloc(p, n);
- if( p2==0 ){
- if( n>0 ) sqlite3_malloc_failed++;
+ *pp = p;
+}
+
+/*
+** sqlite3ThreadSafeMalloc() and sqlite3ThreadSafeFree() are used in those
+** rare scenarios where sqlite may allocate memory in one thread and free
+** it in another. They are exactly the same as sqlite3Malloc() and
+** sqlite3Free() except that:
+**
+** * The allocated memory is not included in any calculations with
+** respect to the soft-heap-limit, and
+**
+** * sqlite3ThreadSafeMalloc() must be matched with ThreadSafeFree(),
+** not sqlite3Free(). Calling sqlite3Free() on memory obtained from
+** ThreadSafeMalloc() will cause an error somewhere down the line.
+*/
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+void *sqlite3ThreadSafeMalloc(int n){
+ (void)ENTER_MALLOC;
+ return sqlite3Malloc(n, 0);
+}
+void sqlite3ThreadSafeFree(void *p){
+ (void)ENTER_MALLOC;
+ if( p ){
+ OSFREE(p);
}
- return p2;
}
+#endif
+
/*
-** Make a copy of a string in memory obtained from sqliteMalloc()
+** Return the number of bytes allocated at location p. p must be either
+** a NULL pointer (in which case 0 is returned) or a pointer returned by
+** sqlite3Malloc(), sqlite3Realloc() or sqlite3ReallocOrFree().
+**
+** The number of bytes allocated does not include any overhead inserted by
+** any malloc() wrapper functions that may be called. So the value returned
+** is the number of bytes that were available to SQLite using pointer p,
+** regardless of how much memory was actually allocated.
+*/
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+int sqlite3AllocSize(void *p){
+ return OSSIZEOF(p);
+}
+#endif
+
+/*
+** Make a copy of a string in memory obtained from sqliteMalloc(). These
+** functions call sqlite3MallocRaw() directly instead of sqliteMalloc(). This
+** is because when memory debugging is turned on, these two functions are
+** called via macros that record the current file and line number in the
+** ThreadData structure.
*/
char *sqlite3StrDup(const char *z){
char *zNew;
if( z==0 ) return 0;
- zNew = sqliteMallocRaw(strlen(z)+1);
+ zNew = sqlite3MallocRaw(strlen(z)+1, 1);
if( zNew ) strcpy(zNew, z);
return zNew;
}
char *sqlite3StrNDup(const char *z, int n){
char *zNew;
if( z==0 ) return 0;
- zNew = sqliteMallocRaw(n+1);
+ zNew = sqlite3MallocRaw(n+1, 1);
if( zNew ){
memcpy(zNew, z, n);
zNew[n] = 0;
}
return zNew;
}
-#endif /* !defined(SQLITE_MEMDEBUG) */
-
-/*
-** Reallocate a buffer to a different size. This is similar to
-** sqliteRealloc() except that if the allocation fails the buffer
-** is freed.
-*/
-void sqlite3ReallocOrFree(void **ppBuf, int newSize){
- void *pNew = sqliteRealloc(*ppBuf, newSize);
- if( pNew==0 ){
- sqliteFree(*ppBuf);
- }
- *ppBuf = pNew;
-}
/*
** Create a string from the 2nd and subsequent arguments (up to the
@@ -411,11 +769,6 @@ void sqlite3SetString(char **pz, ...){
zResult += strlen(zResult);
}
va_end(ap);
-#ifdef SQLITE_MEMDEBUG
-#if SQLITE_MEMDEBUG>1
- fprintf(stderr,"string at 0x%x is %s\n", (int)*pz, *pz);
-#endif
-#endif
}
/*
@@ -440,7 +793,7 @@ void sqlite3SetString(char **pz, ...){
** to NULL.
*/
void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
- if( db && (db->pErr || (db->pErr = sqlite3ValueNew())) ){
+ if( db && (db->pErr || (db->pErr = sqlite3ValueNew())!=0) ){
db->errCode = err_code;
if( zFormat ){
char *z;
@@ -482,6 +835,15 @@ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
}
/*
+** Clear the error message in pParse, if any
+*/
+void sqlite3ErrorClear(Parse *pParse){
+ sqliteFree(pParse->zErrMsg);
+ pParse->zErrMsg = 0;
+ pParse->nErr = 0;
+}
+
+/*
** Convert an SQL-style quoted string into a normal string by removing
** the quote characters. The conversion is done in-place. If the
** input does not begin with a quote character, then this routine
@@ -522,6 +884,7 @@ void sqlite3Dequote(char *z){
** lower-case character.
*/
const unsigned char sqlite3UpperToLower[] = {
+#ifdef SQLITE_ASCII
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
@@ -537,6 +900,25 @@ const unsigned char sqlite3UpperToLower[] = {
216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
252,253,254,255
+#endif
+#ifdef SQLITE_EBCDIC
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 0x */
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 1x */
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 2x */
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */
+ 96, 97, 66, 67, 68, 69, 70, 71, 72, 73,106,107,108,109,110,111, /* 6x */
+ 112, 81, 82, 83, 84, 85, 86, 87, 88, 89,122,123,124,125,126,127, /* 7x */
+ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */
+ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,156,159, /* 9x */
+ 160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */
+ 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */
+ 192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */
+ 208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */
+ 224,225,162,163,164,165,166,167,168,169,232,203,204,205,206,207, /* Ex */
+ 239,240,241,242,243,244,245,246,247,248,249,219,220,221,222,255, /* Fx */
+#endif
};
#define UpperToLower sqlite3UpperToLower
@@ -606,9 +988,11 @@ int sqlite3IsNumber(const char *z, int *realnum, u8 enc){
** for SQL. So this routine always uses "." regardless of locale.
*/
int sqlite3AtoF(const char *z, double *pResult){
+#ifndef SQLITE_OMIT_FLOATING_POINT
int sign = 1;
const char *zBegin = z;
LONGDOUBLE_TYPE v1 = 0.0;
+ while( isspace(*z) ) z++;
if( *z=='-' ){
sign = -1;
z++;
@@ -656,6 +1040,9 @@ int sqlite3AtoF(const char *z, double *pResult){
}
*pResult = sign<0 ? -v1 : v1;
return z - zBegin;
+#else
+ return sqlite3atoi64(z, pResult);
+#endif /* SQLITE_OMIT_FLOATING_POINT */
}
/*
@@ -673,6 +1060,7 @@ int sqlite3atoi64(const char *zNum, i64 *pNum){
i64 v = 0;
int neg;
int i, c;
+ while( isspace(*zNum) ) zNum++;
if( *zNum=='-' ){
neg = 1;
zNum++;
@@ -763,7 +1151,7 @@ int sqlite3SafetyOn(sqlite3 *db){
return 0;
}else if( db->magic==SQLITE_MAGIC_BUSY ){
db->magic = SQLITE_MAGIC_ERROR;
- db->flags |= SQLITE_Interrupt;
+ db->u1.isInterrupted = 1;
}
return 1;
}
@@ -779,7 +1167,7 @@ int sqlite3SafetyOff(sqlite3 *db){
return 0;
}else if( db->magic==SQLITE_MAGIC_OPEN ){
db->magic = SQLITE_MAGIC_ERROR;
- db->flags |= SQLITE_Interrupt;
+ db->u1.isInterrupted = 1;
}
return 1;
}
@@ -969,8 +1357,10 @@ void *sqlite3HexToBlob(const char *z){
if( n%2 ) return 0;
zBlob = (char *)sqliteMalloc(n/2);
- for(i=0; i<n; i+=2){
- zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]);
+ if( zBlob ){
+ for(i=0; i<n; i+=2){
+ zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]);
+ }
}
return zBlob;
}
@@ -1003,3 +1393,95 @@ void *sqlite3TextToPtr(const char *z){
return p;
}
#endif
+
+/*
+** Return a pointer to the ThreadData associated with the calling thread.
+*/
+ThreadData *sqlite3ThreadData(){
+ ThreadData *p = (ThreadData*)sqlite3OsThreadSpecificData(1);
+ if( !p ){
+ sqlite3FailedMalloc();
+ }
+ return p;
+}
+
+/*
+** Return a pointer to the ThreadData associated with the calling thread.
+** If no ThreadData has been allocated to this thread yet, return a pointer
+** to a substitute ThreadData structure that is all zeros.
+*/
+const ThreadData *sqlite3ThreadDataReadOnly(){
+ static const ThreadData zeroData = {0}; /* Initializer to silence warnings
+ ** from broken compilers */
+ const ThreadData *pTd = sqlite3OsThreadSpecificData(0);
+ return pTd ? pTd : &zeroData;
+}
+
+/*
+** Check to see if the ThreadData for this thread is all zero. If it
+** is, then deallocate it.
+*/
+void sqlite3ReleaseThreadData(){
+ sqlite3OsThreadSpecificData(-1);
+}
+
+/*
+** This function must be called before exiting any API function (i.e.
+** returning control to the user) that has called sqlite3Malloc or
+** sqlite3Realloc.
+**
+** The returned value is normally a copy of the second argument to this
+** function. However, if a malloc() failure has occured since the previous
+** invocation SQLITE_NOMEM is returned instead.
+**
+** If the first argument, db, is not NULL and a malloc() error has occured,
+** then the connection error-code (the value returned by sqlite3_errcode())
+** is set to SQLITE_NOMEM.
+*/
+static int mallocHasFailed = 0;
+int sqlite3ApiExit(sqlite3* db, int rc){
+ if( sqlite3MallocFailed() ){
+ mallocHasFailed = 0;
+ sqlite3OsLeaveMutex();
+ sqlite3Error(db, SQLITE_NOMEM, 0);
+ rc = SQLITE_NOMEM;
+ }
+ return rc;
+}
+
+/*
+** Return true is a malloc has failed in this thread since the last call
+** to sqlite3ApiExit(), or false otherwise.
+*/
+int sqlite3MallocFailed(){
+ return (mallocHasFailed && sqlite3OsInMutex(1));
+}
+
+/*
+** Set the "malloc has failed" condition to true for this thread.
+*/
+void sqlite3FailedMalloc(){
+ sqlite3OsEnterMutex();
+ assert( mallocHasFailed==0 );
+ mallocHasFailed = 1;
+}
+
+#ifdef SQLITE_MEMDEBUG
+/*
+** This function sets a flag in the thread-specific-data structure that will
+** cause an assert to fail if sqliteMalloc() or sqliteRealloc() is called.
+*/
+void sqlite3MallocDisallow(){
+ assert( sqlite3_mallocDisallowed>=0 );
+ sqlite3_mallocDisallowed++;
+}
+
+/*
+** This function clears the flag set in the thread-specific-data structure set
+** by sqlite3MallocDisallow().
+*/
+void sqlite3MallocAllow(){
+ assert( sqlite3_mallocDisallowed>0 );
+ sqlite3_mallocDisallowed--;
+}
+#endif
diff --git a/ext/pdo_sqlite/sqlite/src/vacuum.c b/ext/pdo_sqlite/sqlite/src/vacuum.c
index 8254528d9d..336df67ccb 100644
--- a/ext/pdo_sqlite/sqlite/src/vacuum.c
+++ b/ext/pdo_sqlite/sqlite/src/vacuum.c
@@ -17,6 +17,7 @@
** $Id$
*/
#include "sqliteInt.h"
+#include "vdbeInt.h"
#include "os.h"
#ifndef SQLITE_OMIT_VACUUM
@@ -42,7 +43,7 @@ static int execSql(sqlite3 *db, const char *zSql){
if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
return sqlite3_errcode(db);
}
- while( SQLITE_ROW==sqlite3_step(pStmt) );
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){}
return sqlite3_finalize(pStmt);
}
@@ -58,7 +59,7 @@ static int execExecSql(sqlite3 *db, const char *zSql){
if( rc!=SQLITE_OK ) return rc;
while( SQLITE_ROW==sqlite3_step(pStmt) ){
- rc = execSql(db, sqlite3_column_text(pStmt, 0));
+ rc = execSql(db, (char*)sqlite3_column_text(pStmt, 0));
if( rc!=SQLITE_OK ){
sqlite3_finalize(pStmt);
return rc;
@@ -80,7 +81,7 @@ static int execExecSql(sqlite3 *db, const char *zSql){
** with 2.0.0, SQLite no longer uses GDBM so this command has
** become a no-op.
*/
-void sqlite3Vacuum(Parse *pParse, Token *pTableName){
+void sqlite3Vacuum(Parse *pParse){
Vdbe *v = sqlite3GetVdbe(pParse);
if( v ){
sqlite3VdbeAddOp(v, OP_Vacuum, 0, 0);
@@ -100,11 +101,12 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
Btree *pMain; /* The database being vacuumed */
Btree *pTemp;
char *zSql = 0;
- int writeschema_flag; /* Saved value of the write-schema flag */
+ int saved_flags; /* Saved value of the db->flags */
+ Db *pDb = 0; /* Database to detach at end of vacuum */
/* Save the current value of the write-schema flag before setting it. */
- writeschema_flag = db->flags&SQLITE_WriteSchema;
- db->flags |= SQLITE_WriteSchema;
+ saved_flags = db->flags;
+ db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction",
@@ -164,19 +166,23 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
sqliteFree(zSql);
zSql = 0;
if( rc!=SQLITE_OK ) goto end_of_vacuum;
+ pDb = &db->aDb[db->nDb-1];
assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
pTemp = db->aDb[db->nDb-1].pBt;
sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain),
sqlite3BtreeGetReserve(pMain));
assert( sqlite3BtreeGetPageSize(pTemp)==sqlite3BtreeGetPageSize(pMain) );
- execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
+ rc = execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
+ if( rc!=SQLITE_OK ){
+ goto end_of_vacuum;
+ }
#ifndef SQLITE_OMIT_AUTOVACUUM
sqlite3BtreeSetAutoVacuum(pTemp, sqlite3BtreeGetAutoVacuum(pMain));
#endif
/* Begin a transaction */
- rc = execSql(db, "BEGIN;");
+ rc = execSql(db, "BEGIN EXCLUSIVE;");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Query the schema of the main database. Create a mirror schema
@@ -247,7 +253,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
** opened for writing. This way, the SQL transaction used to create the
** temporary database never needs to be committed.
*/
- if( sqlite3BtreeIsInTrans(pTemp) ){
+ if( rc==SQLITE_OK ){
u32 meta;
int i;
@@ -264,26 +270,27 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
6, 0, /* Preserve the user version */
};
- assert( 0==sqlite3BtreeIsInTrans(pMain) );
- rc = sqlite3BtreeBeginTrans(pMain, 1);
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
+ assert( 1==sqlite3BtreeIsInTrans(pTemp) );
+ assert( 1==sqlite3BtreeIsInTrans(pMain) );
/* 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]);
+ if( rc!=SQLITE_OK ) goto end_of_vacuum;
}
rc = sqlite3BtreeCopyFile(pMain, pTemp);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
+ rc = sqlite3BtreeCommit(pTemp);
+ if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = sqlite3BtreeCommit(pMain);
}
end_of_vacuum:
- /* Restore the original value of the write-schema flag. */
- db->flags &= ~SQLITE_WriteSchema;
- db->flags |= writeschema_flag;
+ /* Restore the original value of db->flags */
+ db->flags = saved_flags;
/* Currently there is an SQL level transaction open on the vacuum
** database. No locks are held on any other files (since the main file
@@ -293,16 +300,28 @@ end_of_vacuum:
** is closed by the DETACH.
*/
db->autoCommit = 1;
- if( rc==SQLITE_OK ){
- rc = execSql(db, "DETACH vacuum_db;");
- }else{
- execSql(db, "DETACH vacuum_db;");
+
+ if( pDb ){
+ sqlite3MallocDisallow();
+ sqlite3BtreeClose(pDb->pBt);
+ sqlite3MallocAllow();
+ pDb->pBt = 0;
+ pDb->pSchema = 0;
+ }
+
+ /* If one of the execSql() calls above returned SQLITE_NOMEM, then the
+ ** mallocFailed flag will be clear (because execSql() calls sqlite3_exec()).
+ ** Fix this so the flag and return code match.
+ */
+ if( rc==SQLITE_NOMEM ){
+ sqlite3MallocFailed();
}
+
if( zTemp ){
sqlite3OsDelete(zTemp);
sqliteFree(zTemp);
}
- if( zSql ) sqliteFree( zSql );
+ sqliteFree( zSql );
sqlite3ResetInternalSchema(db, 0);
#endif
diff --git a/ext/pdo_sqlite/sqlite/src/vdbe.c b/ext/pdo_sqlite/sqlite/src/vdbe.c
index a3c3cd11f0..98b9916abe 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbe.c
+++ b/ext/pdo_sqlite/sqlite/src/vdbe.c
@@ -57,17 +57,21 @@
** working correctly. This variable has no function other than to
** help verify the correct operation of the library.
*/
+#ifdef SQLITE_TEST
int sqlite3_search_count = 0;
+#endif
/*
** When this global variable is positive, it gets decremented once before
-** each instruction in the VDBE. When reaches zero, the SQLITE_Interrupt
-** of the db.flags field is set in order to simulate and interrupt.
+** each instruction in the VDBE. When reaches zero, the u1.isInterrupted
+** field of the sqlite3 structure is set in order to simulate and interrupt.
**
** This facility is used for testing purposes only. It does not function
** in an ordinary build.
*/
+#ifdef SQLITE_TEST
int sqlite3_interrupt_count = 0;
+#endif
/*
** The next global variable is incremented each type the OP_Sort opcode
@@ -76,7 +80,9 @@ int sqlite3_interrupt_count = 0;
** has no function other than to help verify the correct operation of the
** library.
*/
+#ifdef SQLITE_TEST
int sqlite3_sort_count = 0;
+#endif
/*
** Release the memory associated with the given stack level. This
@@ -101,6 +107,22 @@ int sqlite3_sort_count = 0;
*/
#define Dynamicify(P,enc) sqlite3VdbeMemDynamicify(P)
+/*
+** The header of a record consists of a sequence variable-length integers.
+** These integers are almost always small and are encoded as a single byte.
+** The following macro takes advantage this fact to provide a fast decode
+** of the integers in a record header. It is faster for the common case
+** where the integer is a single byte. It is a little slower when the
+** integer is two or more bytes. But overall it is faster.
+**
+** The following expressions are equivalent:
+**
+** x = sqlite3GetVarint32( A, &B );
+**
+** x = GetVarint( A, B );
+**
+*/
+#define GetVarint(A,B) ((B = *(A))<=0x7f ? 1 : sqlite3GetVarint32(A, &B))
/*
** An ephemeral string value (signified by the MEM_Ephem flag) contains
@@ -118,23 +140,6 @@ int sqlite3_sort_count = 0;
&& sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;}
/*
-** Convert the given stack entity into a integer if it isn't one
-** already.
-**
-** Any prior string or real representation is invalidated.
-** NULLs are converted into 0.
-*/
-#define Integerify(P) sqlite3VdbeMemIntegerify(P)
-
-/*
-** Convert P so that it has type MEM_Real.
-**
-** Any prior string or integer representation is invalidated.
-** NULLs are converted into 0.0.
-*/
-#define Realify(P) sqlite3VdbeMemRealify(P)
-
-/*
** Argument pMem points at a memory cell that will be passed to a
** user-defined function or returned to the user as the result of a query.
** The second argument, 'db_enc' is the text encoding used by the vdbe for
@@ -177,30 +182,64 @@ static void popStack(Mem **ppTos, int N){
** Allocate cursor number iCur. Return a pointer to it. Return NULL
** if we run out of memory.
*/
-static Cursor *allocateCursor(Vdbe *p, int iCur){
+static Cursor *allocateCursor(Vdbe *p, int iCur, int iDb){
Cursor *pCx;
assert( iCur<p->nCursor );
if( p->apCsr[iCur] ){
- sqlite3VdbeFreeCursor(p->apCsr[iCur]);
+ sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
}
p->apCsr[iCur] = pCx = sqliteMalloc( sizeof(Cursor) );
+ if( pCx ){
+ pCx->iDb = iDb;
+ }
return pCx;
}
/*
-** Apply any conversion required by the supplied column affinity to
-** memory cell pRec. affinity may be one of:
+** Try to convert a value into a numeric representation if we can
+** do so without loss of information. In other words, if the string
+** looks like a number, convert it into a number. If it does not
+** look like a number, leave it alone.
+*/
+static void applyNumericAffinity(Mem *pRec){
+ if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){
+ int realnum;
+ sqlite3VdbeMemNulTerminate(pRec);
+ if( (pRec->flags&MEM_Str)
+ && sqlite3IsNumber(pRec->z, &realnum, pRec->enc) ){
+ i64 value;
+ sqlite3VdbeChangeEncoding(pRec, SQLITE_UTF8);
+ if( !realnum && sqlite3atoi64(pRec->z, &value) ){
+ sqlite3VdbeMemRelease(pRec);
+ pRec->i = value;
+ pRec->flags = MEM_Int;
+ }else{
+ sqlite3VdbeMemRealify(pRec);
+ }
+ }
+ }
+}
+
+/*
+** Processing is determine by the affinity parameter:
+**
+** SQLITE_AFF_INTEGER:
+** SQLITE_AFF_REAL:
+** SQLITE_AFF_NUMERIC:
+** Try to convert pRec to an integer representation or a
+** floating-point representation if an integer representation
+** is not possible. Note that the integer representation is
+** always preferred, even if the affinity is REAL, because
+** an integer representation is more space efficient on disk.
**
-** SQLITE_AFF_NUMERIC
-** SQLITE_AFF_TEXT
-** SQLITE_AFF_NONE
-** SQLITE_AFF_INTEGER
+** SQLITE_AFF_TEXT:
+** Convert pRec to a text representation.
**
+** SQLITE_AFF_NONE:
+** No-op. pRec is unchanged.
*/
static void applyAffinity(Mem *pRec, char affinity, u8 enc){
- if( affinity==SQLITE_AFF_NONE ){
- /* do nothing */
- }else if( affinity==SQLITE_AFF_TEXT ){
+ if( affinity==SQLITE_AFF_TEXT ){
/* Only attempt the conversion to TEXT if there is an integer or real
** representation (blob and NULL do not get converted) but no string
** representation.
@@ -209,36 +248,32 @@ static void applyAffinity(Mem *pRec, char affinity, u8 enc){
sqlite3VdbeMemStringify(pRec, enc);
}
pRec->flags &= ~(MEM_Real|MEM_Int);
- }else{
- if( 0==(pRec->flags&(MEM_Real|MEM_Int)) ){
- /* pRec does not have a valid integer or real representation.
- ** Attempt a conversion if pRec has a string representation and
- ** it looks like a number.
- */
- int realnum;
- sqlite3VdbeMemNulTerminate(pRec);
- if( pRec->flags&MEM_Str && sqlite3IsNumber(pRec->z, &realnum, enc) ){
- if( realnum ){
- Realify(pRec);
- }else{
- Integerify(pRec);
- }
- }
- }
-
- if( affinity==SQLITE_AFF_INTEGER ){
- /* For INTEGER affinity, try to convert a real value to an int */
- if( (pRec->flags&MEM_Real) && !(pRec->flags&MEM_Int) ){
- pRec->i = pRec->r;
- if( ((double)pRec->i)==pRec->r ){
- pRec->flags |= MEM_Int;
- }
- }
+ }else if( affinity!=SQLITE_AFF_NONE ){
+ assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
+ || affinity==SQLITE_AFF_NUMERIC );
+ applyNumericAffinity(pRec);
+ if( pRec->flags & MEM_Real ){
+ sqlite3VdbeIntegerAffinity(pRec);
}
}
}
/*
+** Try to convert the type of a function argument or a result column
+** into a numeric representation. Use either INTEGER or REAL whichever
+** is appropriate. But only do the conversion if it is possible without
+** loss of information and return the revised type of the argument.
+**
+** This is an EXPERIMENTAL api and is subject to change or removal.
+*/
+int sqlite3_value_numeric_type(sqlite3_value *pVal){
+ Mem *pMem = (Mem*)pVal;
+ applyNumericAffinity(pMem);
+ storeTypeInfo(pMem, 0);
+ return pMem->type;
+}
+
+/*
** Exported version of applyAffinity(). This one works on sqlite3_value*,
** not the internal Mem* type.
*/
@@ -251,7 +286,7 @@ void sqlite3ValueApplyAffinity(sqlite3_value *pVal, u8 affinity, u8 enc){
** Write a nice string representation of the contents of cell pMem
** into buffer zBuf, length nBuf.
*/
-void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf, int nBuf){
+void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
char *zCsr = zBuf;
int f = pMem->flags;
@@ -347,7 +382,7 @@ __inline__ unsigned long long int hwtime(void){
** flag on jump instructions, we get a (small) speed improvement.
*/
#define CHECK_FOR_INTERRUPT \
- if( db->flags & SQLITE_Interrupt ) goto abort_due_to_interrupt;
+ if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
/*
@@ -388,6 +423,7 @@ int sqlite3VdbeExec(
Op *pOp; /* Current operation */
int rc = SQLITE_OK; /* Value to return */
sqlite3 *db = p->db; /* The database */
+ u8 encoding = ENC(db); /* The database encoding */
Mem *pTos; /* Top entry in the operand stack */
#ifdef VDBE_PROFILE
unsigned long long start; /* CPU clock count at start of opcode */
@@ -402,11 +438,15 @@ int sqlite3VdbeExec(
if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
assert( db->magic==SQLITE_MAGIC_BUSY );
+ pTos = p->pTos;
+ if( p->rc==SQLITE_NOMEM ){
+ /* This happens if a malloc() inside a call to sqlite3_column_text() or
+ ** sqlite3_column_text16() failed. */
+ goto no_mem;
+ }
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY );
p->rc = SQLITE_OK;
assert( p->explain==0 );
- pTos = p->pTos;
- if( sqlite3_malloc_failed ) goto no_mem;
if( p->popStack ){
popStack(&pTos, p->popStack);
p->popStack = 0;
@@ -417,7 +457,7 @@ int sqlite3VdbeExec(
for(pc=p->pc; rc==SQLITE_OK; pc++){
assert( pc>=0 && pc<p->nOp );
assert( pTos<=&p->aStack[pc] );
- if( sqlite3_malloc_failed ) goto no_mem;
+ if( sqlite3MallocFailed() ) goto no_mem;
#ifdef VDBE_PROFILE
origPc = pc;
start = hwtime();
@@ -461,11 +501,14 @@ int sqlite3VdbeExec(
*/
if( db->xProgress ){
if( db->nProgressOps==nProgressOps ){
+ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
if( db->xProgress(db->pProgressArg)!=0 ){
+ sqlite3SafetyOn(db);
rc = SQLITE_ABORT;
continue; /* skip to the next iteration of the for loop */
}
nProgressOps = 0;
+ if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
}
nProgressOps++;
}
@@ -644,24 +687,25 @@ case OP_Real: { /* same as TK_FLOAT, */
pTos->enc = SQLITE_UTF8;
pTos->r = sqlite3VdbeRealValue(pTos);
pTos->flags |= MEM_Real;
- sqlite3VdbeChangeEncoding(pTos, db->enc);
+ sqlite3VdbeChangeEncoding(pTos, encoding);
break;
}
/* Opcode: String8 * * P3
**
-** P3 points to a nul terminated UTF-8 string. This opcode is transformed
+** P3 points to a nul terminated UTF-8 string. This opcode is transformed
** into an OP_String before it is executed for the first time.
*/
case OP_String8: { /* same as TK_STRING */
-#ifndef SQLITE_OMIT_UTF16
+ assert( pOp->p3!=0 );
pOp->opcode = OP_String;
+ pOp->p1 = strlen(pOp->p3);
- assert( pOp->p3!=0 );
- if( db->enc!=SQLITE_UTF8 ){
+#ifndef SQLITE_OMIT_UTF16
+ if( encoding!=SQLITE_UTF8 ){
pTos++;
sqlite3VdbeMemSetStr(pTos, pOp->p3, -1, SQLITE_UTF8, SQLITE_STATIC);
- if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pTos, db->enc) ) goto no_mem;
+ if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pTos, encoding) ) goto no_mem;
if( SQLITE_OK!=sqlite3VdbeMemDynamicify(pTos) ) goto no_mem;
pTos->flags &= ~(MEM_Dyn);
pTos->flags |= MEM_Static;
@@ -670,34 +714,24 @@ case OP_String8: { /* same as TK_STRING */
}
pOp->p3type = P3_DYNAMIC;
pOp->p3 = pTos->z;
+ pOp->p1 = pTos->n;
break;
}
#endif
/* Otherwise fall through to the next case, OP_String */
}
-/* Opcode: String * * P3
+/* Opcode: String P1 * P3
**
-** The string value P3 is pushed onto the stack. If P3==0 then a
-** NULL is pushed onto the stack. P3 is assumed to be a nul terminated
-** string encoded with the database native encoding.
+** The string value P3 of length P1 (bytes) is pushed onto the stack.
*/
case OP_String: {
pTos++;
assert( pOp->p3!=0 );
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;
+ pTos->n = pOp->p1;
+ pTos->enc = encoding;
break;
}
@@ -868,20 +902,45 @@ case OP_Push: { /* no-push */
/* Opcode: Callback P1 * *
**
-** Pop P1 values off the stack and form them into an array. Then
-** invoke the callback function using the newly formed array as the
-** 3rd parameter.
+** The top P1 values on the stack represent a single result row from
+** a query. This opcode causes the sqlite3_step() call to terminate
+** with an SQLITE_ROW return code and it sets up the sqlite3_stmt
+** structure to provide access to the top P1 values as the result
+** row. When the sqlite3_step() function is run again, the top P1
+** values will be automatically popped from the stack before the next
+** instruction executes.
*/
case OP_Callback: { /* no-push */
- int i;
+ Mem *pMem;
+ Mem *pFirstColumn;
assert( p->nResColumn==pOp->p1 );
- for(i=0; i<pOp->p1; i++){
- Mem *pVal = &pTos[0-i];
- sqlite3VdbeMemNulTerminate(pVal);
- storeTypeInfo(pVal, db->enc);
+ /* Data in the pager might be moved or changed out from under us
+ ** in between the return from this sqlite3_step() call and the
+ ** next call to sqlite3_step(). So deephermeralize everything on
+ ** the stack. Note that ephemeral data is never stored in memory
+ ** cells so we do not have to worry about them.
+ */
+ pFirstColumn = &pTos[0-pOp->p1];
+ for(pMem = p->aStack; pMem<pFirstColumn; pMem++){
+ Deephemeralize(pMem);
}
+ /* Invalidate all ephemeral cursor row caches */
+ p->cacheCtr = (p->cacheCtr + 2)|1;
+
+ /* Make sure the results of the current row are \000 terminated
+ ** and have an assigned type. The results are deephemeralized as
+ ** as side effect.
+ */
+ for(; pMem<=pTos; pMem++ ){
+ sqlite3VdbeMemNulTerminate(pMem);
+ storeTypeInfo(pMem, encoding);
+ }
+
+ /* Set up the statement structure so that it will pop the current
+ ** results from the stack when the statement returns.
+ */
p->resOnStack = 1;
p->nCallback++;
p->popStack = pOp->p1;
@@ -917,7 +976,7 @@ case OP_Concat: { /* same as TK_CONCAT */
nByte = -1;
break;
}
- Stringify(pTerm, db->enc);
+ Stringify(pTerm, encoding);
nByte += pTerm->n;
}
@@ -956,7 +1015,7 @@ case OP_Concat: { /* same as TK_CONCAT */
pTos->n = j;
pTos->flags = MEM_Str|MEM_Dyn|MEM_Term;
pTos->xDel = 0;
- pTos->enc = db->enc;
+ pTos->enc = encoding;
pTos->z = zNew;
}
break;
@@ -1014,8 +1073,10 @@ case OP_Multiply: /* same as TK_STAR, no-push */
case OP_Divide: /* same as TK_SLASH, no-push */
case OP_Remainder: { /* same as TK_REM, no-push */
Mem *pNos = &pTos[-1];
+ int flags;
assert( pNos>=p->aStack );
- if( ((pTos->flags | pNos->flags) & MEM_Null)!=0 ){
+ flags = pTos->flags | pNos->flags;
+ if( (flags & MEM_Null)!=0 ){
Release(pTos);
pTos--;
Release(pTos);
@@ -1070,6 +1131,9 @@ case OP_Remainder: { /* same as TK_REM, no-push */
Release(pTos);
pTos->r = b;
pTos->flags = MEM_Real;
+ if( (flags & MEM_Real)==0 ){
+ sqlite3VdbeIntegerAffinity(pTos);
+ }
}
break;
@@ -1125,7 +1189,7 @@ case OP_Function: {
pArg = &pTos[1-n];
for(i=0; i<n; i++, pArg++){
apVal[i] = pArg;
- storeTypeInfo(pArg, db->enc);
+ storeTypeInfo(pArg, encoding);
}
assert( pOp->p3type==P3_FUNCDEF || pOp->p3type==P3_VDBEFUNC );
@@ -1150,7 +1214,7 @@ case OP_Function: {
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
(*ctx.pFunc->xFunc)(&ctx, n, apVal);
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
- if( sqlite3_malloc_failed ) goto no_mem;
+ if( sqlite3MallocFailed() ) goto no_mem;
popStack(&pTos, n);
/* If any auxilary data functions have been called by this user function,
@@ -1162,22 +1226,17 @@ case OP_Function: {
pOp->p3type = P3_VDBEFUNC;
}
- /* Copy the result of the function to the top of the stack */
- sqlite3VdbeChangeEncoding(&ctx.s, db->enc);
- pTos++;
- pTos->flags = 0;
- sqlite3VdbeMemMove(pTos, &ctx.s);
-
/* If the function returned an error, throw an exception */
if( ctx.isError ){
- if( !(pTos->flags&MEM_Str) ){
- sqlite3SetString(&p->zErrMsg, "user function error", (char*)0);
- }else{
- sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pTos), (char*)0);
- sqlite3VdbeChangeEncoding(pTos, db->enc);
- }
+ sqlite3SetString(&p->zErrMsg, sqlite3_value_text(&ctx.s), (char*)0);
rc = SQLITE_ERROR;
}
+
+ /* Copy the result of the function to the top of the stack */
+ sqlite3VdbeChangeEncoding(&ctx.s, encoding);
+ pTos++;
+ pTos->flags = 0;
+ sqlite3VdbeMemMove(pTos, &ctx.s);
break;
}
@@ -1214,7 +1273,7 @@ case OP_BitOr: /* same as TK_BITOR, no-push */
case OP_ShiftLeft: /* same as TK_LSHIFT, no-push */
case OP_ShiftRight: { /* same as TK_RSHIFT, no-push */
Mem *pNos = &pTos[-1];
- int a, b;
+ i64 a, b;
assert( pNos>=p->aStack );
if( (pTos->flags | pNos->flags) & MEM_Null ){
@@ -1249,7 +1308,7 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, no-push */
*/
case OP_AddImm: { /* no-push */
assert( pTos>=p->aStack );
- Integerify(pTos);
+ sqlite3VdbeMemIntegerify(pTos);
pTos->i += pOp->p1;
break;
}
@@ -1267,7 +1326,7 @@ case OP_AddImm: { /* no-push */
case OP_ForceInt: { /* no-push */
i64 v;
assert( pTos>=p->aStack );
- applyAffinity(pTos, SQLITE_AFF_INTEGER, db->enc);
+ applyAffinity(pTos, SQLITE_AFF_NUMERIC, encoding);
if( (pTos->flags & (MEM_Int|MEM_Real))==0 ){
Release(pTos);
pTos--;
@@ -1277,7 +1336,8 @@ case OP_ForceInt: { /* no-push */
if( pTos->flags & MEM_Int ){
v = pTos->i + (pOp->p1!=0);
}else{
- Realify(pTos);
+ /* FIX ME: should this not be assert( pTos->flags & MEM_Real ) ??? */
+ sqlite3VdbeMemRealify(pTos);
v = (int)pTos->r;
if( pTos->r>(double)v ) v++;
if( pOp->p1 && pTos->r==(double)v ) v++;
@@ -1301,7 +1361,7 @@ case OP_ForceInt: { /* no-push */
*/
case OP_MustBeInt: { /* no-push */
assert( pTos>=p->aStack );
- applyAffinity(pTos, SQLITE_AFF_INTEGER, db->enc);
+ applyAffinity(pTos, SQLITE_AFF_NUMERIC, encoding);
if( (pTos->flags & MEM_Int)==0 ){
if( pOp->p2==0 ){
rc = SQLITE_MISMATCH;
@@ -1317,67 +1377,39 @@ case OP_MustBeInt: { /* no-push */
break;
}
-#ifndef SQLITE_OMIT_CAST
-/* Opcode: ToInt * * *
+/* Opcode: RealAffinity * * *
**
-** Force the value on the top of the stack to be an integer. If
-** The value is currently a real number, drop its fractional part.
-** If the value is text or blob, try to convert it to an integer using the
-** equivalent of atoi() and store 0 if no such conversion is possible.
-**
-** A NULL value is not changed by this routine. It remains NULL.
-*/
-case OP_ToInt: { /* no-push */
- assert( pTos>=p->aStack );
- if( pTos->flags & MEM_Null ) break;
- assert( MEM_Str==(MEM_Blob>>3) );
- pTos->flags |= (pTos->flags&MEM_Blob)>>3;
- applyAffinity(pTos, SQLITE_AFF_INTEGER, db->enc);
- sqlite3VdbeMemIntegerify(pTos);
- break;
-}
-
-/* Opcode: ToNumeric * * *
-**
-** Force the value on the top of the stack to be numeric (either an
-** integer or a floating-point number.
-** If the value is text or blob, try to convert it to an using the
-** equivalent of atoi() or atof() and store 0 if no such conversion
-** is possible.
+** If the top of the stack is an integer, convert it to a real value.
**
-** A NULL value is not changed by this routine. It remains NULL.
+** This opcode is used when extracting information from a column that
+** has REAL affinity. Such column values may still be stored as
+** integers, for space efficiency, but after extraction we want them
+** to have only a real value.
*/
-case OP_ToNumeric: { /* no-push */
+case OP_RealAffinity: { /* no-push */
assert( pTos>=p->aStack );
- if( pTos->flags & MEM_Null ) break;
- assert( MEM_Str==(MEM_Blob>>3) );
- pTos->flags |= (pTos->flags&MEM_Blob)>>3;
- applyAffinity(pTos, SQLITE_AFF_NUMERIC, db->enc);
- if( (pTos->flags & (MEM_Int|MEM_Real))==0 ){
+ if( pTos->flags & MEM_Int ){
sqlite3VdbeMemRealify(pTos);
- }else{
- sqlite3VdbeMemRelease(pTos);
}
- assert( (pTos->flags & MEM_Dyn)==0 );
- pTos->flags &= (MEM_Int|MEM_Real);
break;
}
+#ifndef SQLITE_OMIT_CAST
/* Opcode: ToText * * *
**
** Force the value on the top of the stack to be text.
-** If the value is numeric, convert it to an using the
+** If the value is numeric, convert it to a string using the
** equivalent of printf(). Blob values are unchanged and
** are afterwards simply interpreted as text.
**
** A NULL value is not changed by this routine. It remains NULL.
*/
-case OP_ToText: { /* no-push */
+case OP_ToText: { /* same as TK_TO_TEXT, no-push */
assert( pTos>=p->aStack );
if( pTos->flags & MEM_Null ) break;
assert( MEM_Str==(MEM_Blob>>3) );
pTos->flags |= (pTos->flags&MEM_Blob)>>3;
- applyAffinity(pTos, SQLITE_AFF_TEXT, db->enc);
+ applyAffinity(pTos, SQLITE_AFF_TEXT, encoding);
assert( pTos->flags & MEM_Str );
pTos->flags &= ~(MEM_Int|MEM_Real|MEM_Blob);
break;
@@ -1392,17 +1424,71 @@ case OP_ToText: { /* no-push */
**
** A NULL value is not changed by this routine. It remains NULL.
*/
-case OP_ToBlob: { /* no-push */
+case OP_ToBlob: { /* same as TK_TO_BLOB, no-push */
assert( pTos>=p->aStack );
if( pTos->flags & MEM_Null ) break;
if( (pTos->flags & MEM_Blob)==0 ){
- applyAffinity(pTos, SQLITE_AFF_TEXT, db->enc);
+ applyAffinity(pTos, SQLITE_AFF_TEXT, encoding);
assert( pTos->flags & MEM_Str );
pTos->flags |= MEM_Blob;
}
pTos->flags &= ~(MEM_Int|MEM_Real|MEM_Str);
break;
}
+
+/* Opcode: ToNumeric * * *
+**
+** Force the value on the top of the stack to be numeric (either an
+** integer or a floating-point number.)
+** If the value is text or blob, try to convert it to an using the
+** equivalent of atoi() or atof() and store 0 if no such conversion
+** is possible.
+**
+** A NULL value is not changed by this routine. It remains NULL.
+*/
+case OP_ToNumeric: { /* same as TK_TO_NUMERIC, no-push */
+ assert( pTos>=p->aStack );
+ if( (pTos->flags & MEM_Null)==0 ){
+ sqlite3VdbeMemNumerify(pTos);
+ }
+ break;
+}
+#endif /* SQLITE_OMIT_CAST */
+
+/* Opcode: ToInt * * *
+**
+** Force the value on the top of the stack to be an integer. If
+** The value is currently a real number, drop its fractional part.
+** If the value is text or blob, try to convert it to an integer using the
+** equivalent of atoi() and store 0 if no such conversion is possible.
+**
+** A NULL value is not changed by this routine. It remains NULL.
+*/
+case OP_ToInt: { /* same as TK_TO_INT, no-push */
+ assert( pTos>=p->aStack );
+ if( (pTos->flags & MEM_Null)==0 ){
+ sqlite3VdbeMemIntegerify(pTos);
+ }
+ break;
+}
+
+#ifndef SQLITE_OMIT_CAST
+/* Opcode: ToReal * * *
+**
+** Force the value on the top of the stack to be a floating point number.
+** If The value is currently an integer, convert it.
+** If the value is text or blob, try to convert it to an integer using the
+** equivalent of atoi() and store 0 if no such conversion is possible.
+**
+** A NULL value is not changed by this routine. It remains NULL.
+*/
+case OP_ToReal: { /* same as TK_TO_REAL, no-push */
+ assert( pTos>=p->aStack );
+ if( (pTos->flags & MEM_Null)==0 ){
+ sqlite3VdbeMemRealify(pTos);
+ }
+ break;
+}
#endif /* SQLITE_OMIT_CAST */
/* Opcode: Eq P1 P2 P3
@@ -1422,7 +1508,8 @@ case OP_ToBlob: { /* no-push */
** 0x200 is set but is NULL when the 0x200 bit of P1 is clear.
**
** The least significant byte of P1 (mask 0xff) must be an affinity character -
-** 'n', 't', 'i' or 'o' - or 0x00. An attempt is made to coerce both values
+** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made
+** to coerce both values
** according to the affinity before the comparison is made. If the byte is
** 0x00, then numeric affinity is used.
**
@@ -1522,8 +1609,8 @@ case OP_Ge: { /* same as TK_GE, no-push */
affinity = pOp->p1 & 0xFF;
if( affinity ){
- applyAffinity(pNos, affinity, db->enc);
- applyAffinity(pTos, affinity, db->enc);
+ applyAffinity(pNos, affinity, encoding);
+ applyAffinity(pTos, affinity, encoding);
}
assert( pOp->p3type==P3_COLLSEQ || pOp->p3==0 );
@@ -1571,13 +1658,13 @@ case OP_Or: { /* same as TK_OR, no-push */
if( pTos->flags & MEM_Null ){
v1 = 2;
}else{
- Integerify(pTos);
+ sqlite3VdbeMemIntegerify(pTos);
v1 = pTos->i==0;
}
if( pNos->flags & MEM_Null ){
v2 = 2;
}else{
- Integerify(pNos);
+ sqlite3VdbeMemIntegerify(pNos);
v2 = pNos->i==0;
}
if( pOp->opcode==OP_And ){
@@ -1614,6 +1701,7 @@ case OP_Negative: /* same as TK_UMINUS, no-push */
case OP_AbsValue: {
assert( pTos>=p->aStack );
if( pTos->flags & MEM_Real ){
+ neg_abs_real_case:
Release(pTos);
if( pOp->opcode==OP_Negative || pTos->r<0.0 ){
pTos->r = -pTos->r;
@@ -1628,11 +1716,8 @@ case OP_AbsValue: {
}else if( pTos->flags & MEM_Null ){
/* Do nothing */
}else{
- Realify(pTos);
- if( pOp->opcode==OP_Negative || pTos->r<0.0 ){
- pTos->r = -pTos->r;
- }
- pTos->flags = MEM_Real;
+ sqlite3VdbeMemNumerify(pTos);
+ goto neg_abs_real_case;
}
break;
}
@@ -1646,7 +1731,7 @@ case OP_AbsValue: {
case OP_Not: { /* same as TK_NOT, no-push */
assert( pTos>=p->aStack );
if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */
- Integerify(pTos);
+ sqlite3VdbeMemIntegerify(pTos);
assert( (pTos->flags & MEM_Dyn)==0 );
pTos->i = !pTos->i;
pTos->flags = MEM_Int;
@@ -1662,7 +1747,7 @@ case OP_Not: { /* same as TK_NOT, no-push */
case OP_BitNot: { /* same as TK_BITNOT, no-push */
assert( pTos>=p->aStack );
if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */
- Integerify(pTos);
+ sqlite3VdbeMemIntegerify(pTos);
assert( (pTos->flags & MEM_Dyn)==0 );
pTos->i = ~pTos->i;
pTos->flags = MEM_Int;
@@ -1795,13 +1880,6 @@ case OP_SetNumColumns: { /* no-push */
** If the KeyAsData opcode has previously executed on this cursor, then the
** field might be extracted from the key rather than the data.
**
-** If P1 is negative, then the record is stored on the stack rather than in
-** a table. For P1==-1, the top of the stack is used. For P1==-2, the
-** next on the stack is used. And so forth. The value pushed is always
-** just a pointer into the record which is stored further down on the
-** stack. The column value is not copied. The number of columns in the
-** record is stored on the stack just above the record itself.
-**
** If the column contains fewer than P2 fields, then push a NULL. Or
** if P3 is of type P3_MEM, then push the P3 value. The P3 value will
** be default value for a column that has been added using the ALTER TABLE
@@ -1819,10 +1897,7 @@ case OP_Column: {
u32 *aType; /* aType[i] holds the numeric type of the i-th column */
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
u32 nField; /* number of fields in the record */
- u32 szHdr; /* Number of bytes in the record header */
int len; /* The length of the serialized data for the column */
- int offset = 0; /* Offset into the data */
- int idx; /* Index into the header */
int i; /* Loop counter */
char *zData; /* Part of the record being decoded */
Mem sMem; /* For storing the record being decoded */
@@ -1836,31 +1911,19 @@ case OP_Column: {
** bytes in the record.
**
** zRec is set to be the complete text of the record if it is available.
- ** The complete record text is always available for pseudo-tables and
- ** when we are decoded a record from the stack. If the record is stored
- ** in a cursor, the complete record text might be available in the
- ** pC->aRow cache. Or it might not be. If the data is unavailable,
- ** zRec is set to NULL.
+ ** The complete record text is always available for pseudo-tables
+ ** If the record is stored in a cursor, the complete record text
+ ** might be available in the pC->aRow cache. Or it might not be.
+ ** If the data is unavailable, zRec is set to NULL.
**
** We also compute the number of columns in the record. For cursors,
** the number of columns is stored in the Cursor.nField element. For
** records on the stack, the next entry down on the stack is an integer
** which is the number of records.
*/
- assert( p1<0 || p->apCsr[p1]!=0 );
- if( p1<0 ){
- /* Take the record off of the stack */
- Mem *pRec = &pTos[p1];
- Mem *pCnt = &pRec[-1];
- assert( pRec>=p->aStack );
- assert( pRec->flags & MEM_Blob );
- payloadSize = pRec->n;
- zRec = pRec->z;
- assert( pCnt>=p->aStack );
- assert( pCnt->flags & MEM_Int );
- nField = pCnt->i;
- pCrsr = 0;
- }else if( (pC = p->apCsr[p1])->pCursor!=0 ){
+ pC = p->apCsr[p1];
+ assert( pC!=0 );
+ if( pC->pCursor!=0 ){
/* The record is stored in a B-Tree */
rc = sqlite3VdbeCursorMoveto(pC);
if( rc ) goto abort_due_to_error;
@@ -1868,9 +1931,9 @@ case OP_Column: {
pCrsr = pC->pCursor;
if( pC->nullRow ){
payloadSize = 0;
- }else if( pC->cacheValid ){
+ }else if( pC->cacheStatus==p->cacheCtr ){
payloadSize = pC->payloadSize;
- zRec = pC->aRow;
+ zRec = (char*)pC->aRow;
}else if( pC->isIndex ){
i64 payloadSize64;
sqlite3BtreeKeySize(pCrsr, &payloadSize64);
@@ -1879,16 +1942,14 @@ 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;
zRec = pC->pData;
- pC->cacheValid = 0;
+ pC->cacheStatus = CACHE_STALE;
assert( payloadSize==0 || zRec!=0 );
nField = pC->nField;
pCrsr = 0;
-#endif
}else{
zRec = 0;
payloadSize = 0;
@@ -1898,7 +1959,7 @@ case OP_Column: {
/* If payloadSize is 0, then just push a NULL onto the stack. */
if( payloadSize==0 ){
- pTos->flags = MEM_Null;
+ assert( pTos->flags==MEM_Null );
break;
}
@@ -1907,20 +1968,26 @@ case OP_Column: {
/* Read and parse the table header. Store the results of the parse
** into the record header cache fields of the cursor.
*/
- if( pC && pC->cacheValid ){
+ if( pC && pC->cacheStatus==p->cacheCtr ){
aType = pC->aType;
aOffset = pC->aOffset;
}else{
- int avail; /* Number of bytes of available data */
- if( pC && pC->aType ){
- aType = pC->aType;
- }else{
- aType = sqliteMallocRaw( 2*nField*sizeof(aType) );
+ u8 *zIdx; /* Index into header */
+ u8 *zEndHdr; /* Pointer to first byte after the header */
+ u32 offset; /* Offset into the data */
+ int szHdrSz; /* Size of the header size field at start of record */
+ int avail; /* Number of bytes of available data */
+
+ aType = pC->aType;
+ if( aType==0 ){
+ pC->aType = aType = sqliteMallocRaw( 2*nField*sizeof(aType) );
}
- aOffset = &aType[nField];
if( aType==0 ){
goto no_mem;
}
+ pC->aOffset = aOffset = &aType[nField];
+ pC->payloadSize = payloadSize;
+ pC->cacheStatus = p->cacheCtr;
/* Figure out how many bytes are in the header */
if( zRec ){
@@ -1937,13 +2004,14 @@ case OP_Column: {
** the record.
*/
if( avail>=payloadSize ){
- zRec = pC->aRow = zData;
+ zRec = zData;
+ pC->aRow = (u8*)zData;
}else{
pC->aRow = 0;
}
}
- idx = sqlite3GetVarint32(zData, &szHdr);
-
+ assert( zRec!=0 || avail>=payloadSize || avail>=9 );
+ szHdrSz = GetVarint((u8*)zData, offset);
/* The KeyFetch() or DataFetch() above are fast and will get the entire
** record header in most cases. But they will fail to get the complete
@@ -1951,58 +2019,47 @@ case OP_Column: {
** in the B-Tree. When that happens, use sqlite3VdbeMemFromBtree() to
** acquire the complete header text.
*/
- if( !zRec && avail<szHdr ){
- rc = sqlite3VdbeMemFromBtree(pCrsr, 0, szHdr, pC->isIndex, &sMem);
+ if( !zRec && avail<offset ){
+ rc = sqlite3VdbeMemFromBtree(pCrsr, 0, offset, pC->isIndex, &sMem);
if( rc!=SQLITE_OK ){
goto op_column_out;
}
zData = sMem.z;
}
+ zEndHdr = (u8 *)&zData[offset];
+ zIdx = (u8 *)&zData[szHdrSz];
/* Scan the header and use it to fill in the aType[] and aOffset[]
** arrays. aType[i] will contain the type integer for the i-th
** column and aOffset[i] will contain the offset from the beginning
** 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;
- idx += sqlite3GetVarint32(&zData[idx], &aType[i]);
- offset += sqlite3VdbeSerialTypeLen(aType[i]);
- i++;
+ for(i=0; i<nField; i++){
+ if( zIdx<zEndHdr ){
+ aOffset[i] = offset;
+ zIdx += GetVarint(zIdx, aType[i]);
+ offset += sqlite3VdbeSerialTypeLen(aType[i]);
+ }else{
+ /* 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.
+ */
+ aOffset[i] = 0;
+ }
}
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 we have read more header data than was contained in the header,
+ ** or if the end of the last field appears to be past the end of the
+ ** record, then we must be dealing with a corrupt database.
*/
- if( idx!=szHdr || offset!=payloadSize ){
+ if( zIdx>zEndHdr || offset>payloadSize ){
rc = SQLITE_CORRUPT_BKPT;
goto op_column_out;
}
-
- /* Remember all aType and aColumn information if we have a cursor
- ** to remember it in. */
- if( pC ){
- pC->payloadSize = payloadSize;
- pC->aType = aType;
- pC->aOffset = aOffset;
- pC->cacheValid = 1;
- }
}
/* Get the column information. If aOffset[p2] is non-zero, then
@@ -2023,8 +2080,8 @@ case OP_Column: {
}
zData = sMem.z;
}
- sqlite3VdbeSerialGet(zData, aType[p2], pTos);
- pTos->enc = db->enc;
+ sqlite3VdbeSerialGet((u8*)zData, aType[p2], pTos);
+ pTos->enc = encoding;
}else{
if( pOp->p3type==P3_MEM ){
sqlite3VdbeMemShallowCopy(pTos, (Mem *)(pOp->p3), MEM_Static);
@@ -2035,7 +2092,7 @@ case OP_Column: {
/* If we dynamically allocated space to hold the data (in the
** sqlite3VdbeMemFromBtree() call above) then transfer control of that
- ** dynamically allocated space over to the pTos structure rather.
+ ** dynamically allocated space over to the pTos structure.
** This prevents a memory copy.
*/
if( (sMem.flags & MEM_Dyn)!=0 ){
@@ -2052,10 +2109,6 @@ case OP_Column: {
rc = sqlite3VdbeMemMakeWriteable(pTos);
op_column_out:
- /* Release the aType[] memory if we are not dealing with cursor */
- if( !pC || !pC->aType ){
- sqliteFree(aType);
- }
break;
}
@@ -2081,17 +2134,14 @@ op_column_out:
** field of the index key (i.e. the first character of P3 corresponds to the
** lowest element on the stack).
**
-** The mapping from character to affinity is as follows:
-** 'n' = NUMERIC.
-** 'i' = INTEGER.
-** 't' = TEXT.
-** 'o' = NONE.
+** The mapping from character to affinity is given by the SQLITE_AFF_
+** macros defined in sqliteInt.h.
**
** If P3 is NULL then all index fields have the affinity NONE.
**
** See also OP_MakeIdxRec
*/
-/* Opcode: MakeRecordI P1 P2 P3
+/* Opcode: MakeIdxRec P1 P2 P3
**
** This opcode works just OP_MakeRecord except that it reads an extra
** integer from the stack (thus reading a total of abs(P1+1) entries)
@@ -2133,6 +2183,7 @@ case OP_MakeRecord: {
int jumpIfNull; /* Jump here if non-zero and any entries are NULL. */
int addRowid; /* True to append a rowid column at the end */
char *zAffinity; /* The affinity string for the record */
+ int file_format; /* File format to use for encoding */
leaveOnStack = ((pOp->p1<0)?1:0);
nField = pOp->p1 * (leaveOnStack?-1:1);
@@ -2143,18 +2194,19 @@ case OP_MakeRecord: {
pData0 = &pTos[1-nField];
assert( pData0>=p->aStack );
containsNull = 0;
+ file_format = p->minWriteFileFormat;
/* Loop through the elements that will make up the record to figure
** out how much space is required for the new record.
*/
for(pRec=pData0; pRec<=pTos; pRec++){
if( zAffinity ){
- applyAffinity(pRec, zAffinity[pRec-pData0], db->enc);
+ applyAffinity(pRec, zAffinity[pRec-pData0], encoding);
}
if( pRec->flags&MEM_Null ){
containsNull = 1;
}
- serial_type = sqlite3VdbeSerialType(pRec);
+ serial_type = sqlite3VdbeSerialType(pRec, file_format);
nData += sqlite3VdbeSerialTypeLen(serial_type);
nHdr += sqlite3VarintLen(serial_type);
}
@@ -2166,8 +2218,8 @@ case OP_MakeRecord: {
if( addRowid ){
pRowid = &pTos[0-nField];
assert( pRowid>=p->aStack );
- Integerify(pRowid);
- serial_type = sqlite3VdbeSerialType(pRowid);
+ sqlite3VdbeMemIntegerify(pRowid);
+ serial_type = sqlite3VdbeSerialType(pRowid, 0);
nData += sqlite3VdbeSerialTypeLen(serial_type);
nHdr += sqlite3VarintLen(serial_type);
}
@@ -2186,24 +2238,24 @@ case OP_MakeRecord: {
goto no_mem;
}
}else{
- zNewRecord = zTemp;
+ zNewRecord = (u8*)zTemp;
}
/* Write the record */
zCsr = zNewRecord;
zCsr += sqlite3PutVarint(zCsr, nHdr);
for(pRec=pData0; pRec<=pTos; pRec++){
- serial_type = sqlite3VdbeSerialType(pRec);
+ serial_type = sqlite3VdbeSerialType(pRec, file_format);
zCsr += sqlite3PutVarint(zCsr, serial_type); /* serial type */
}
if( addRowid ){
- zCsr += sqlite3PutVarint(zCsr, sqlite3VdbeSerialType(pRowid));
+ zCsr += sqlite3PutVarint(zCsr, sqlite3VdbeSerialType(pRowid, 0));
}
for(pRec=pData0; pRec<=pTos; pRec++){
- zCsr += sqlite3VdbeSerialPut(zCsr, pRec); /* serial data */
+ zCsr += sqlite3VdbeSerialPut(zCsr, pRec, file_format); /* serial data */
}
if( addRowid ){
- zCsr += sqlite3VdbeSerialPut(zCsr, pRowid);
+ zCsr += sqlite3VdbeSerialPut(zCsr, pRowid, 0);
}
assert( zCsr==(zNewRecord+nByte) );
@@ -2220,7 +2272,7 @@ case OP_MakeRecord: {
pTos->flags = MEM_Blob | MEM_Short;
}else{
assert( zNewRecord!=(unsigned char *)zTemp );
- pTos->z = zNewRecord;
+ pTos->z = (char*)zNewRecord;
pTos->flags = MEM_Blob | MEM_Dyn;
pTos->xDel = 0;
}
@@ -2248,7 +2300,7 @@ case OP_MakeRecord: {
case OP_Statement: { /* no-push */
int i = pOp->p1;
Btree *pBt;
- if( i>=0 && i<db->nDb && (pBt = db->aDb[i].pBt) && !(db->autoCommit) ){
+ if( i>=0 && i<db->nDb && (pBt = db->aDb[i].pBt)!=0 && !(db->autoCommit) ){
assert( sqlite3BtreeIsInTrans(pBt) );
if( !sqlite3BtreeIsInStmt(pBt) ){
rc = sqlite3BtreeBeginStmt(pBt);
@@ -2280,26 +2332,29 @@ case OP_AutoCommit: { /* no-push */
** that the other VMs must complete first.
*/
sqlite3SetString(&p->zErrMsg, "cannot ", rollback?"rollback":"commit",
- " transaction - SQL statements in progress", 0);
+ " transaction - SQL statements in progress", (char*)0);
rc = SQLITE_ERROR;
}else if( i!=db->autoCommit ){
- db->autoCommit = i;
if( pOp->p2 ){
assert( i==1 );
sqlite3RollbackAll(db);
- }else if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
- p->pTos = pTos;
- p->pc = pc;
- db->autoCommit = 1-i;
- p->rc = SQLITE_BUSY;
- return SQLITE_BUSY;
+ db->autoCommit = 1;
+ }else{
+ db->autoCommit = i;
+ if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
+ p->pTos = pTos;
+ p->pc = pc;
+ db->autoCommit = 1-i;
+ p->rc = SQLITE_BUSY;
+ return SQLITE_BUSY;
+ }
}
return SQLITE_DONE;
}else{
sqlite3SetString(&p->zErrMsg,
(!i)?"cannot start a transaction within a transaction":(
(rollback)?"cannot rollback - no transaction is active":
- "cannot commit - no transaction is active"), 0);
+ "cannot commit - no transaction is active"), (char*)0);
rc = SQLITE_ERROR;
}
@@ -2396,16 +2451,24 @@ case OP_SetCookie: { /* no-push */
pDb = &db->aDb[pOp->p1];
assert( pDb->pBt!=0 );
assert( pTos>=p->aStack );
- Integerify(pTos);
+ sqlite3VdbeMemIntegerify(pTos);
/* See note about index shifting on OP_ReadCookie */
rc = sqlite3BtreeUpdateMeta(pDb->pBt, 1+pOp->p2, (int)pTos->i);
if( pOp->p2==0 ){
/* When the schema cookie changes, record the new cookie internally */
- pDb->schema_cookie = pTos->i;
+ pDb->pSchema->schema_cookie = pTos->i;
db->flags |= SQLITE_InternChanges;
+ }else if( pOp->p2==1 ){
+ /* Record changes in the file format */
+ pDb->pSchema->file_format = pTos->i;
}
assert( (pTos->flags & MEM_Dyn)==0 );
pTos--;
+ if( pOp->p1==1 ){
+ /* Invalidate all prepared statements whenever the TEMP database
+ ** schema is changed. Ticket #1644 */
+ sqlite3ExpirePreparedStatements(db);
+ }
break;
}
@@ -2493,26 +2556,35 @@ case OP_OpenWrite: { /* no-push */
Btree *pX;
int iDb;
Cursor *pCur;
+ Db *pDb;
assert( pTos>=p->aStack );
- Integerify(pTos);
+ sqlite3VdbeMemIntegerify(pTos);
iDb = pTos->i;
assert( (pTos->flags & MEM_Dyn)==0 );
pTos--;
assert( iDb>=0 && iDb<db->nDb );
- pX = db->aDb[iDb].pBt;
+ pDb = &db->aDb[iDb];
+ pX = pDb->pBt;
assert( pX!=0 );
- wrFlag = pOp->opcode==OP_OpenWrite;
+ if( pOp->opcode==OP_OpenWrite ){
+ wrFlag = 1;
+ if( pDb->pSchema->file_format < p->minWriteFileFormat ){
+ p->minWriteFileFormat = pDb->pSchema->file_format;
+ }
+ }else{
+ wrFlag = 0;
+ }
if( p2<=0 ){
assert( pTos>=p->aStack );
- Integerify(pTos);
+ sqlite3VdbeMemIntegerify(pTos);
p2 = pTos->i;
assert( (pTos->flags & MEM_Dyn)==0 );
pTos--;
assert( p2>=2 );
}
assert( i>=0 );
- pCur = allocateCursor(p, i);
+ pCur = allocateCursor(p, i, iDb);
if( pCur==0 ) goto no_mem;
pCur->nullRow = 1;
if( pX==0 ) break;
@@ -2524,7 +2596,7 @@ case OP_OpenWrite: { /* no-push */
if( pOp->p3type==P3_KEYINFO ){
pCur->pKeyInfo = (KeyInfo*)pOp->p3;
pCur->pIncrKey = &pCur->pKeyInfo->incrKey;
- pCur->pKeyInfo->enc = p->db->enc;
+ pCur->pKeyInfo->enc = ENC(p->db);
}else{
pCur->pKeyInfo = 0;
pCur->pIncrKey = &pCur->bogusIncrKey;
@@ -2574,9 +2646,9 @@ case OP_OpenWrite: { /* no-push */
break;
}
-/* Opcode: OpenVirtual P1 P2 P3
+/* Opcode: OpenEphemeral P1 P2 P3
**
-** Open a new cursor P1 to a transient or virtual table.
+** Open a new cursor P1 to a transient table.
** The cursor is always opened read/write even if
** the main database is read-only. The transient or virtual
** table is deleted automatically when the cursor is closed.
@@ -2585,12 +2657,18 @@ case OP_OpenWrite: { /* no-push */
** The cursor points to a BTree table if P3==0 and to a BTree index
** if P3 is not 0. If P3 is not NULL, it points to a KeyInfo structure
** that defines the format of keys in the index.
+**
+** This opcode was once called OpenTemp. But that created
+** confusion because the term "temp table", might refer either
+** to a TEMP table at the SQL level, or to a table opened by
+** this opcode. Then this opcode was call OpenVirtual. But
+** that created confusion with the whole virtual-table idea.
*/
-case OP_OpenVirtual: { /* no-push */
+case OP_OpenEphemeral: { /* no-push */
int i = pOp->p1;
Cursor *pCx;
assert( i>=0 );
- pCx = allocateCursor(p, i);
+ pCx = allocateCursor(p, i, -1);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
rc = sqlite3BtreeFactory(db, 0, 1, TEMP_PAGES, &pCx->pBt);
@@ -2612,7 +2690,7 @@ case OP_OpenVirtual: { /* no-push */
rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, sqlite3VdbeRecordCompare,
pOp->p3, &pCx->pCursor);
pCx->pKeyInfo = (KeyInfo*)pOp->p3;
- pCx->pKeyInfo->enc = p->db->enc;
+ pCx->pKeyInfo->enc = ENC(p->db);
pCx->pIncrKey = &pCx->pKeyInfo->incrKey;
}
pCx->isTable = 0;
@@ -2627,7 +2705,6 @@ case OP_OpenVirtual: { /* no-push */
break;
}
-#ifndef SQLITE_OMIT_TRIGGER
/* Opcode: OpenPseudo P1 * *
**
** Open a new cursor that points to a fake table that contains a single
@@ -2636,13 +2713,15 @@ case OP_OpenVirtual: { /* no-push */
** closed.
**
** A pseudo-table created by this opcode is useful for holding the
-** NEW or OLD tables in a trigger.
+** NEW or OLD tables in a trigger. Also used to hold the a single
+** row output from the sorter so that the row can be decomposed into
+** individual columns using the OP_Column opcode.
*/
case OP_OpenPseudo: { /* no-push */
int i = pOp->p1;
Cursor *pCx;
assert( i>=0 );
- pCx = allocateCursor(p, i);
+ pCx = allocateCursor(p, i, -1);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
pCx->pseudoTable = 1;
@@ -2651,7 +2730,6 @@ case OP_OpenPseudo: { /* no-push */
pCx->isIndex = 0;
break;
}
-#endif
/* Opcode: Close P1 * *
**
@@ -2661,7 +2739,7 @@ case OP_OpenPseudo: { /* no-push */
case OP_Close: { /* no-push */
int i = pOp->p1;
if( i>=0 && i<p->nCursor ){
- sqlite3VdbeFreeCursor(p->apCsr[i]);
+ sqlite3VdbeFreeCursor(p, p->apCsr[i]);
p->apCsr[i] = 0;
}
break;
@@ -2725,7 +2803,7 @@ case OP_MoveGt: { /* no-push */
*pC->pIncrKey = oc==OP_MoveGt || oc==OP_MoveLe;
if( pC->isTable ){
i64 iKey;
- Integerify(pTos);
+ sqlite3VdbeMemIntegerify(pTos);
iKey = intToKey(pTos->i);
if( pOp->p2==0 && pOp->opcode==OP_MoveGe ){
pC->movetoTarget = iKey;
@@ -2741,7 +2819,8 @@ case OP_MoveGt: { /* no-push */
pC->lastRowid = pTos->i;
pC->rowidIsValid = res==0;
}else{
- Stringify(pTos, db->enc);
+ assert( pTos->flags & MEM_Blob );
+ /* Stringify(pTos, encoding); */
rc = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
@@ -2749,9 +2828,11 @@ case OP_MoveGt: { /* no-push */
pC->rowidIsValid = 0;
}
pC->deferredMoveto = 0;
- pC->cacheValid = 0;
+ pC->cacheStatus = CACHE_STALE;
*pC->pIncrKey = 0;
+#ifdef SQLITE_TEST
sqlite3_search_count++;
+#endif
if( oc==OP_MoveGe || oc==OP_MoveGt ){
if( res<0 ){
rc = sqlite3BtreeNext(pC->pCursor, &res);
@@ -2846,11 +2927,11 @@ case OP_Found: { /* no-push */
if( (pC = p->apCsr[i])->pCursor!=0 ){
int res, rx;
assert( pC->isTable==0 );
- Stringify(pTos, db->enc);
+ Stringify(pTos, encoding);
rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
alreadyExists = rx==SQLITE_OK && res==0;
pC->deferredMoveto = 0;
- pC->cacheValid = 0;
+ pC->cacheStatus = CACHE_STALE;
}
if( pOp->opcode==OP_Found ){
if( alreadyExists ) pc = pOp->p2 - 1;
@@ -2868,7 +2949,7 @@ case OP_Found: { /* no-push */
**
** The top of the stack is an integer record number. Call this
** record number R. The next on the stack is an index key created
-** using MakeIdxKey. Call it K. This instruction pops R from the
+** using MakeIdxRec. Call it K. This instruction pops R from the
** stack but it leaves K unchanged.
**
** P1 is an index. So it has no data and its key consists of a
@@ -2895,7 +2976,7 @@ case OP_IsUnique: { /* no-push */
/* Pop the value R off the top of the stack
*/
assert( pNos>=p->aStack );
- Integerify(pTos);
+ sqlite3VdbeMemIntegerify(pTos);
R = pTos->i;
assert( (pTos->flags & MEM_Dyn)==0 );
pTos--;
@@ -2904,7 +2985,7 @@ case OP_IsUnique: { /* no-push */
assert( pCx!=0 );
pCrsr = pCx->pCursor;
if( pCrsr!=0 ){
- int res, rc;
+ int res;
i64 v; /* The record number on the P1 entry that matches K */
char *zKey; /* The value of K */
int nKey; /* Number of bytes in K */
@@ -2913,20 +2994,22 @@ case OP_IsUnique: { /* no-push */
/* Make sure K is a string and make zKey point to K
*/
- Stringify(pNos, db->enc);
+ Stringify(pNos, encoding);
zKey = pNos->z;
nKey = pNos->n;
- szRowid = sqlite3VdbeIdxRowidLen(nKey, zKey);
+ szRowid = sqlite3VdbeIdxRowidLen((u8*)zKey);
len = nKey-szRowid;
/* Search for an entry in P1 where all but the last four bytes match K.
** If there is no such entry, jump immediately to P2.
*/
assert( pCx->deferredMoveto==0 );
- pCx->cacheValid = 0;
+ pCx->cacheStatus = CACHE_STALE;
rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
+ if( rc!=SQLITE_OK ){
+ goto abort_due_to_error;
+ }
if( res<0 ){
rc = sqlite3BtreeNext(pCrsr, &res);
if( res ){
@@ -2934,7 +3017,7 @@ case OP_IsUnique: { /* no-push */
break;
}
}
- rc = sqlite3VdbeIdxKeyCompare(pCx, len, zKey, &res);
+ rc = sqlite3VdbeIdxKeyCompare(pCx, len, (u8*)zKey, &res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
if( res>0 ){
pc = pOp->p2 - 1;
@@ -2997,7 +3080,7 @@ case OP_NotExists: { /* no-push */
pC->lastRowid = pTos->i;
pC->rowidIsValid = res==0;
pC->nullRow = 0;
- pC->cacheValid = 0;
+ pC->cacheStatus = CACHE_STALE;
if( res!=0 ){
pc = pOp->p2 - 1;
pC->rowidIsValid = 0;
@@ -3105,7 +3188,10 @@ case OP_NewRowid: {
if( pC->nextRowidValid ){
v = pC->nextRowid;
}else{
- rx = sqlite3BtreeLast(pC->pCursor, &res);
+ rc = sqlite3BtreeLast(pC->pCursor, &res);
+ if( rc!=SQLITE_OK ){
+ goto abort_due_to_error;
+ }
if( res ){
v = 1;
}else{
@@ -3124,7 +3210,7 @@ case OP_NewRowid: {
Mem *pMem;
assert( pOp->p2>0 && pOp->p2<p->nMem ); /* P2 is a valid memory cell */
pMem = &p->aMem[pOp->p2];
- Integerify(pMem);
+ sqlite3VdbeMemIntegerify(pMem);
assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P2) holds an integer */
if( pMem->i==MAX_ROWID || pC->useRandomRowid ){
rc = SQLITE_FULL;
@@ -3170,7 +3256,7 @@ case OP_NewRowid: {
}
pC->rowidIsValid = 0;
pC->deferredMoveto = 0;
- pC->cacheValid = 0;
+ pC->cacheStatus = CACHE_STALE;
}
pTos++;
pTos->i = v;
@@ -3178,7 +3264,7 @@ case OP_NewRowid: {
break;
}
-/* Opcode: Insert P1 P2 *
+/* Opcode: Insert P1 P2 P3
**
** Write an entry into the table of cursor P1. A new entry is
** created if it doesn't already exist or the data for an existing
@@ -3191,6 +3277,10 @@ case OP_NewRowid: {
** then rowid is stored for subsequent return by the
** sqlite3_last_insert_rowid() function (otherwise it's unmodified).
**
+** Parameter P3 may point to a string containing the table-name, or
+** may be NULL. If it is not NULL, then the update-hook
+** (sqlite3.xUpdateCallback) is invoked following a successful insert.
+**
** This instruction only works on tables. The equivalent instruction
** for indices is OP_IdxInsert.
*/
@@ -3210,7 +3300,7 @@ case OP_Insert: { /* no-push */
if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
if( pOp->p2 & OPFLAG_LASTROWID ) db->lastRowid = pNos->i;
- if( pC->nextRowidValid && pTos->i>=pC->nextRowid ){
+ if( pC->nextRowidValid && pNos->i>=pC->nextRowid ){
pC->nextRowidValid = 0;
}
if( pTos->flags & MEM_Null ){
@@ -3219,7 +3309,6 @@ case OP_Insert: { /* no-push */
}else{
assert( pTos->flags & (MEM_Blob|MEM_Str) );
}
-#ifndef SQLITE_OMIT_TRIGGER
if( pC->pseudoTable ){
sqliteFree(pC->pData);
pC->iKey = iKey;
@@ -3236,21 +3325,29 @@ case OP_Insert: { /* no-push */
}
pC->nullRow = 0;
}else{
-#endif
rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, pTos->z, pTos->n);
-#ifndef SQLITE_OMIT_TRIGGER
}
-#endif
pC->rowidIsValid = 0;
pC->deferredMoveto = 0;
- pC->cacheValid = 0;
+ pC->cacheStatus = CACHE_STALE;
+
+ /* Invoke the update-hook if required. */
+ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p3 ){
+ const char *zDb = db->aDb[pC->iDb].zName;
+ const char *zTbl = pOp->p3;
+ int op = ((pOp->p2 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
+ assert( pC->isTable );
+ db->xUpdateCallback(db->pUpdateArg, op, zDb, zTbl, iKey);
+ assert( pC->iDb>=0 );
+ }
}
popStack(&pTos, 2);
+
break;
}
-/* Opcode: Delete P1 P2 *
+/* Opcode: Delete P1 P2 P3
**
** Delete the record at which the P1 cursor is currently pointing.
**
@@ -3271,11 +3368,37 @@ case OP_Delete: { /* no-push */
pC = p->apCsr[i];
assert( pC!=0 );
if( pC->pCursor!=0 ){
+ i64 iKey;
+
+ /* If the update-hook will be invoked, set iKey to the rowid of the
+ ** row being deleted.
+ */
+ if( db->xUpdateCallback && pOp->p3 ){
+ assert( pC->isTable );
+ if( pC->rowidIsValid ){
+ iKey = pC->lastRowid;
+ }else{
+ rc = sqlite3BtreeKeySize(pC->pCursor, &iKey);
+ if( rc ){
+ goto abort_due_to_error;
+ }
+ iKey = keyToInt(iKey);
+ }
+ }
+
rc = sqlite3VdbeCursorMoveto(pC);
if( rc ) goto abort_due_to_error;
rc = sqlite3BtreeDelete(pC->pCursor);
pC->nextRowidValid = 0;
- pC->cacheValid = 0;
+ pC->cacheStatus = CACHE_STALE;
+
+ /* Invoke the update-hook if required. */
+ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p3 ){
+ const char *zDb = db->aDb[pC->iDb].zName;
+ const char *zTbl = pOp->p3;
+ db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey);
+ assert( pC->iDb>=0 );
+ }
}
if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
break;
@@ -3360,12 +3483,10 @@ 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;
}
@@ -3445,7 +3566,7 @@ case OP_Last: { /* no-push */
rc = sqlite3BtreeLast(pCrsr, &res);
pC->nullRow = res;
pC->deferredMoveto = 0;
- pC->cacheValid = 0;
+ pC->cacheStatus = CACHE_STALE;
if( res && pOp->p2>0 ){
pc = pOp->p2 - 1;
}
@@ -3469,8 +3590,10 @@ case OP_Last: { /* no-push */
** correctly optimizing out sorts.
*/
case OP_Sort: { /* no-push */
+#ifdef SQLITE_TEST
sqlite3_sort_count++;
sqlite3_search_count--;
+#endif
/* Fall through into OP_Rewind */
}
/* Opcode: Rewind P1 P2 *
@@ -3494,7 +3617,7 @@ case OP_Rewind: { /* no-push */
rc = sqlite3BtreeFirst(pCrsr, &res);
pC->atFirst = res==0;
pC->deferredMoveto = 0;
- pC->cacheValid = 0;
+ pC->cacheStatus = CACHE_STALE;
}else{
res = 1;
}
@@ -3539,11 +3662,13 @@ case OP_Next: { /* no-push */
rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) :
sqlite3BtreePrevious(pCrsr, &res);
pC->nullRow = res;
- pC->cacheValid = 0;
+ pC->cacheStatus = CACHE_STALE;
}
if( res==0 ){
pc = pOp->p2 - 1;
+#ifdef SQLITE_TEST
sqlite3_search_count++;
+#endif
}
}else{
pC->nullRow = 1;
@@ -3554,9 +3679,9 @@ case OP_Next: { /* no-push */
/* Opcode: IdxInsert P1 * *
**
-** The top of the stack holds a SQL index key made using the
-** MakeIdxKey instruction. This opcode writes that key into the
-** index P1. Data for the entry is nil.
+** The top of the stack holds a SQL index key made using either the
+** MakeIdxRec or MakeRecord instructions. This opcode writes that key
+** into the index P1. Data for the entry is nil.
**
** This instruction only works for indices. The equivalent instruction
** for tables is OP_Insert.
@@ -3576,7 +3701,7 @@ case OP_IdxInsert: { /* no-push */
assert( pC->isTable==0 );
rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0);
assert( pC->deferredMoveto==0 );
- pC->cacheValid = 0;
+ pC->cacheStatus = CACHE_STALE;
}
Release(pTos);
pTos--;
@@ -3585,7 +3710,8 @@ case OP_IdxInsert: { /* no-push */
/* Opcode: IdxDelete P1 * *
**
-** The top of the stack is an index key built using the MakeIdxKey opcode.
+** The top of the stack is an index key built using the either the
+** MakeIdxRec or MakeRecord opcodes.
** This opcode removes that entry from the index.
*/
case OP_IdxDelete: { /* no-push */
@@ -3597,13 +3723,13 @@ case OP_IdxDelete: { /* no-push */
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
- int rx, res;
- rx = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res);
- if( rx==SQLITE_OK && res==0 ){
+ int res;
+ rc = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res);
+ if( rc==SQLITE_OK && res==0 ){
rc = sqlite3BtreeDelete(pCrsr);
}
assert( pC->deferredMoveto==0 );
- pC->cacheValid = 0;
+ pC->cacheStatus = CACHE_STALE;
}
Release(pTos);
pTos--;
@@ -3616,7 +3742,7 @@ case OP_IdxDelete: { /* no-push */
** the end of the index key pointed to by cursor P1. This integer should be
** the rowid of the table entry to which this index entry points.
**
-** See also: Rowid, MakeIdxKey.
+** See also: Rowid, MakeIdxRec.
*/
case OP_IdxRowid: {
int i = pOp->p1;
@@ -3700,14 +3826,14 @@ case OP_IdxGE: { /* no-push */
assert( p->apCsr[i]!=0 );
assert( pTos>=p->aStack );
if( (pC = p->apCsr[i])->pCursor!=0 ){
- int res, rc;
+ int res;
assert( pTos->flags & MEM_Blob ); /* Created using OP_Make*Key */
- Stringify(pTos, db->enc);
+ Stringify(pTos, encoding);
assert( pC->deferredMoveto==0 );
*pC->pIncrKey = pOp->p3!=0;
assert( pOp->p3==0 || pOp->opcode!=OP_IdxGT );
- rc = sqlite3VdbeIdxKeyCompare(pC, pTos->n, pTos->z, &res);
+ rc = sqlite3VdbeIdxKeyCompare(pC, pTos->n, (u8*)pTos->z, &res);
*pC->pIncrKey = 0;
if( rc!=SQLITE_OK ){
break;
@@ -3729,7 +3855,7 @@ case OP_IdxGE: { /* no-push */
/* Opcode: IdxIsNull P1 P2 *
**
** The top of the stack contains an index entry such as might be generated
-** by the MakeIdxKey opcode. This routine looks at the first P1 fields of
+** by the MakeIdxRec opcode. This routine looks at the first P1 fields of
** that key. If any of the first P1 fields are NULL, then a jump is made
** to address P2. Otherwise we fall straight through.
**
@@ -3745,9 +3871,9 @@ case OP_IdxIsNull: { /* no-push */
assert( pTos->flags & MEM_Blob );
z = pTos->z;
n = pTos->n;
- k = sqlite3GetVarint32(z, &serial_type);
+ k = sqlite3GetVarint32((u8*)z, &serial_type);
for(; k<n && i>0; i--){
- k += sqlite3GetVarint32(&z[k], &serial_type);
+ k += sqlite3GetVarint32((u8*)&z[k], &serial_type);
if( serial_type==0 ){ /* Serial type 0 is a NULL */
pc = pOp->p2-1;
break;
@@ -3780,19 +3906,31 @@ case OP_IdxIsNull: { /* no-push */
*/
case OP_Destroy: {
int iMoved;
- if( db->activeVdbeCnt>1 ){
+ Vdbe *pVdbe;
+ int iCnt;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ iCnt = 0;
+ for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
+ if( pVdbe->magic==VDBE_MAGIC_RUN && pVdbe->inVtabMethod<2 && pVdbe->pc>=0 ){
+ iCnt++;
+ }
+ }
+#else
+ iCnt = db->activeVdbeCnt;
+#endif
+ if( iCnt>1 ){
rc = SQLITE_LOCKED;
}else{
- assert( db->activeVdbeCnt==1 );
+ assert( iCnt==1 );
rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1, &iMoved);
pTos++;
pTos->flags = MEM_Int;
pTos->i = iMoved;
- #ifndef SQLITE_OMIT_AUTOVACUUM
+#ifndef SQLITE_OMIT_AUTOVACUUM
if( rc==SQLITE_OK && iMoved!=0 ){
sqlite3RootPageMoved(&db->aDb[pOp->p2], iMoved, pOp->p1);
}
- #endif
+#endif
}
break;
}
@@ -3810,6 +3948,41 @@ case OP_Destroy: {
** See also: Destroy
*/
case OP_Clear: { /* no-push */
+
+ /* For consistency with the way other features of SQLite operate
+ ** with a truncate, we will also skip the update callback.
+ */
+#if 0
+ Btree *pBt = db->aDb[pOp->p2].pBt;
+ if( db->xUpdateCallback && pOp->p3 ){
+ const char *zDb = db->aDb[pOp->p2].zName;
+ const char *zTbl = pOp->p3;
+ BtCursor *pCur = 0;
+ int fin = 0;
+
+ rc = sqlite3BtreeCursor(pBt, pOp->p1, 0, 0, 0, &pCur);
+ if( rc!=SQLITE_OK ){
+ goto abort_due_to_error;
+ }
+ for(
+ rc=sqlite3BtreeFirst(pCur, &fin);
+ rc==SQLITE_OK && !fin;
+ rc=sqlite3BtreeNext(pCur, &fin)
+ ){
+ i64 iKey;
+ rc = sqlite3BtreeKeySize(pCur, &iKey);
+ if( rc ){
+ break;
+ }
+ iKey = keyToInt(iKey);
+ db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey);
+ }
+ sqlite3BtreeCloseCursor(pCur);
+ if( rc!=SQLITE_OK ){
+ goto abort_due_to_error;
+ }
+ }
+#endif
rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
break;
}
@@ -3885,14 +4058,20 @@ case OP_ParseSchema: { /* no-push */
sqlite3SafetyOff(db);
assert( db->init.busy==0 );
db->init.busy = 1;
+ assert( !sqlite3MallocFailed() );
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
+ if( rc==SQLITE_ABORT ) rc = initData.rc;
+ sqliteFree(zSql);
db->init.busy = 0;
sqlite3SafetyOn(db);
- sqliteFree(zSql);
+ if( rc==SQLITE_NOMEM ){
+ sqlite3FailedMalloc();
+ goto no_mem;
+ }
break;
}
-#ifndef SQLITE_OMIT_ANALYZE
+#if !defined(SQLITE_OMIT_ANALYZE) && !defined(SQLITE_OMIT_PARSER)
/* Opcode: LoadAnalysis P1 * *
**
** Read the sqlite_stat1 table for database P1 and load the content
@@ -3905,7 +4084,7 @@ case OP_LoadAnalysis: { /* no-push */
sqlite3AnalysisLoad(db, iDb);
break;
}
-#endif /* SQLITE_OMIT_ANALYZE */
+#endif /* !defined(SQLITE_OMIT_ANALYZE) && !defined(SQLITE_OMIT_PARSER) */
/* Opcode: DropTable P1 * P3
**
@@ -3992,7 +4171,7 @@ case OP_IntegrityCk: {
pTos->xDel = 0;
}
pTos->enc = SQLITE_UTF8;
- sqlite3VdbeChangeEncoding(pTos, db->enc);
+ sqlite3VdbeChangeEncoding(pTos, encoding);
sqliteFree(aRoot);
break;
}
@@ -4005,7 +4184,7 @@ case OP_IntegrityCk: {
*/
case OP_FifoWrite: { /* no-push */
assert( pTos>=p->aStack );
- Integerify(pTos);
+ sqlite3VdbeMemIntegerify(pTos);
sqlite3VdbeFifoPush(&p->sFifo, pTos->i);
assert( (pTos->flags & MEM_Dyn)==0 );
pTos--;
@@ -4046,7 +4225,7 @@ case OP_ContextPush: { /* no-push */
/* FIX ME: This should be allocated as part of the vdbe at compile-time */
if( i>=p->contextStackDepth ){
p->contextStackDepth = i+1;
- sqlite3ReallocOrFree((void**)&p->contextStack, sizeof(Context)*(i+1));
+ sqliteReallocOrFree((void**)&p->contextStack, sizeof(Context)*(i+1));
if( p->contextStack==0 ) goto no_mem;
}
pContext = &p->contextStack[i];
@@ -4129,8 +4308,8 @@ case OP_MemMax: { /* no-push */
assert( pTos>=p->aStack );
assert( i>=0 && i<p->nMem );
pMem = &p->aMem[i];
- Integerify(pMem);
- Integerify(pTos);
+ sqlite3VdbeMemIntegerify(pMem);
+ sqlite3VdbeMemIntegerify(pTos);
if( pMem->i<pTos->i){
pMem->i = pTos->i;
}
@@ -4140,30 +4319,27 @@ case OP_MemMax: { /* no-push */
/* 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 exactly 1, then jump
-** to P2.
+** Increment the integer valued memory cell P2 by the value in P1.
**
-** This instruction throws an error if the memory cell is not initially
-** an integer.
+** It is illegal to use this instruction on a memory cell that does
+** not contain an integer. An assertion fault will result if you try.
*/
case OP_MemIncr: { /* no-push */
- int i = pOp->p1;
+ int i = pOp->p2;
Mem *pMem;
assert( i>=0 && i<p->nMem );
pMem = &p->aMem[i];
assert( pMem->flags==MEM_Int );
- pMem->i++;
- if( pOp->p2>0 && pMem->i==1 ){
- pc = pOp->p2 - 1;
- }
+ pMem->i += pOp->p1;
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.
+** If the value of memory cell P1 is 1 or greater, jump to P2.
+**
+** It is illegal to use this instruction on a memory cell that does
+** not contain an integer. An assertion fault will result if you try.
*/
case OP_IfMemPos: { /* no-push */
int i = pOp->p1;
@@ -4177,6 +4353,44 @@ case OP_IfMemPos: { /* no-push */
break;
}
+/* Opcode: IfMemNeg P1 P2 *
+**
+** If the value of memory cell P1 is less than zero, jump to P2.
+**
+** It is illegal to use this instruction on a memory cell that does
+** not contain an integer. An assertion fault will result if you try.
+*/
+case OP_IfMemNeg: { /* no-push */
+ 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;
+}
+
+/* Opcode: IfMemZero P1 P2 *
+**
+** If the value of memory cell P1 is exactly 0, jump to P2.
+**
+** It is illegal to use this instruction on a memory cell that does
+** not contain an integer. An assertion fault will result if you try.
+*/
+case OP_IfMemZero: { /* no-push */
+ 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;
+}
+
/* Opcode: MemNull P1 * *
**
** Store a NULL in memory cell P1
@@ -4233,12 +4447,15 @@ case OP_AggStep: { /* no-push */
assert( apVal || n==0 );
for(i=0; i<n; i++, pRec++){
apVal[i] = pRec;
- storeTypeInfo(pRec, db->enc);
+ storeTypeInfo(pRec, encoding);
}
ctx.pFunc = (FuncDef*)pOp->p3;
assert( pOp->p1>=0 && pOp->p1<p->nMem );
ctx.pMem = pMem = &p->aMem[pOp->p1];
pMem->n++;
+ ctx.s.flags = MEM_Null;
+ ctx.s.z = 0;
+ ctx.s.xDel = 0;
ctx.isError = 0;
ctx.pColl = 0;
if( ctx.pFunc->needCollSeq ){
@@ -4250,8 +4467,10 @@ case OP_AggStep: { /* no-push */
(ctx.pFunc->xStep)(&ctx, n, apVal);
popStack(&pTos, n);
if( ctx.isError ){
+ sqlite3SetString(&p->zErrMsg, sqlite3_value_text(&ctx.s), (char*)0);
rc = SQLITE_ERROR;
}
+ sqlite3VdbeMemRelease(&ctx.s);
break;
}
@@ -4272,7 +4491,10 @@ case OP_AggFinal: { /* no-push */
assert( pOp->p1>=0 && pOp->p1<p->nMem );
pMem = &p->aMem[pOp->p1];
assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
- sqlite3VdbeMemFinalize(pMem, (FuncDef*)pOp->p3);
+ rc = sqlite3VdbeMemFinalize(pMem, (FuncDef*)pOp->p3);
+ if( rc==SQLITE_ERROR ){
+ sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pMem), (char*)0);
+ }
break;
}
@@ -4308,6 +4530,344 @@ case OP_Expire: { /* no-push */
break;
}
+#ifndef SQLITE_OMIT_SHARED_CACHE
+/* Opcode: TableLock P1 P2 P3
+**
+** Obtain a lock on a particular table. This instruction is only used when
+** the shared-cache feature is enabled.
+**
+** If P1 is not negative, then it is the index of the database
+** in sqlite3.aDb[] and a read-lock is required. If P1 is negative, a
+** write-lock is required. In this case the index of the database is the
+** absolute value of P1 minus one (iDb = abs(P1) - 1;) and a write-lock is
+** required.
+**
+** P2 contains the root-page of the table to lock.
+**
+** P3 contains a pointer to the name of the table being locked. This is only
+** used to generate an error message if the lock cannot be obtained.
+*/
+case OP_TableLock: { /* no-push */
+ int p1 = pOp->p1;
+ u8 isWriteLock = (p1<0);
+ if( isWriteLock ){
+ p1 = (-1*p1)-1;
+ }
+ rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock);
+ if( rc==SQLITE_LOCKED ){
+ const char *z = (const char *)pOp->p3;
+ sqlite3SetString(&p->zErrMsg, "database table is locked: ", z, (char*)0);
+ }
+ break;
+}
+#endif /* SQLITE_OMIT_SHARED_CACHE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VBegin * * P3
+**
+** P3 a pointer to an sqlite3_vtab structure. Call the xBegin method
+** for that table.
+*/
+case OP_VBegin: { /* no-push */
+ rc = sqlite3VtabBegin(db, (sqlite3_vtab *)pOp->p3);
+ break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VCreate P1 * P3
+**
+** P3 is the name of a virtual table in database P1. Call the xCreate method
+** for that table.
+*/
+case OP_VCreate: { /* no-push */
+ rc = sqlite3VtabCallCreate(db, pOp->p1, pOp->p3, &p->zErrMsg);
+ break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VDestroy P1 * P3
+**
+** P3 is the name of a virtual table in database P1. Call the xDestroy method
+** of that table.
+*/
+case OP_VDestroy: { /* no-push */
+ p->inVtabMethod = 2;
+ rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p3);
+ p->inVtabMethod = 0;
+ break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VOpen P1 * P3
+**
+** P3 is a pointer to a virtual table object, an sqlite3_vtab structure.
+** P1 is a cursor number. This opcode opens a cursor to the virtual
+** table and stores that cursor in P1.
+*/
+case OP_VOpen: { /* no-push */
+ Cursor *pCur = 0;
+ sqlite3_vtab_cursor *pVtabCursor = 0;
+
+ sqlite3_vtab *pVtab = (sqlite3_vtab *)(pOp->p3);
+ sqlite3_module *pModule = (sqlite3_module *)pVtab->pModule;
+
+ assert(pVtab && pModule);
+ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+ rc = pModule->xOpen(pVtab, &pVtabCursor);
+ if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+ if( SQLITE_OK==rc ){
+ /* Initialise sqlite3_vtab_cursor base class */
+ pVtabCursor->pVtab = pVtab;
+
+ /* Initialise vdbe cursor object */
+ pCur = allocateCursor(p, pOp->p1, -1);
+ if( pCur ){
+ pCur->pVtabCursor = pVtabCursor;
+ pCur->pModule = pVtabCursor->pVtab->pModule;
+ }else{
+ pModule->xClose(pVtabCursor);
+ }
+ }
+ break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VFilter P1 P2 P3
+**
+** P1 is a cursor opened using VOpen. P2 is an address to jump to if
+** the filtered result set is empty.
+**
+** P3 is either NULL or a string that was generated by the xBestIndex
+** method of the module. The interpretation of the P3 string is left
+** to the module implementation.
+**
+** This opcode invokes the xFilter method on the virtual table specified
+** by P1. The integer query plan parameter to xFilter is the top of the
+** stack. Next down on the stack is the argc parameter. Beneath the
+** next of stack are argc additional parameters which are passed to
+** xFilter as argv. The topmost parameter (i.e. 3rd element popped from
+** the stack) becomes argv[argc-1] when passed to xFilter.
+**
+** The integer query plan parameter, argc, and all argv stack values
+** are popped from the stack before this instruction completes.
+**
+** A jump is made to P2 if the result set after filtering would be
+** empty.
+*/
+case OP_VFilter: { /* no-push */
+ int nArg;
+
+ const sqlite3_module *pModule;
+
+ Cursor *pCur = p->apCsr[pOp->p1];
+ assert( pCur->pVtabCursor );
+ pModule = pCur->pVtabCursor->pVtab->pModule;
+
+ /* Grab the index number and argc parameters off the top of the stack. */
+ assert( (&pTos[-1])>=p->aStack );
+ assert( (pTos[0].flags&MEM_Int)!=0 && pTos[-1].flags==MEM_Int );
+ nArg = pTos[-1].i;
+
+ /* Invoke the xFilter method if one is defined. */
+ if( pModule->xFilter ){
+ int res;
+ int i;
+ Mem **apArg = p->apArg;
+ for(i = 0; i<nArg; i++){
+ apArg[i] = &pTos[i+1-2-nArg];
+ storeTypeInfo(apArg[i], 0);
+ }
+
+ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+ p->inVtabMethod = 1;
+ rc = pModule->xFilter(pCur->pVtabCursor, pTos->i, pOp->p3, nArg, apArg);
+ p->inVtabMethod = 0;
+ if( rc==SQLITE_OK ){
+ res = pModule->xEof(pCur->pVtabCursor);
+ }
+ if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+
+ if( res ){
+ pc = pOp->p2 - 1;
+ }
+ }
+
+ /* Pop the index number, argc value and parameters off the stack */
+ popStack(&pTos, 2+nArg);
+ break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VRowid P1 * *
+**
+** Push an integer onto the stack which is the rowid of
+** the virtual-table that the P1 cursor is pointing to.
+*/
+case OP_VRowid: {
+ const sqlite3_module *pModule;
+
+ Cursor *pCur = p->apCsr[pOp->p1];
+ assert( pCur->pVtabCursor );
+ pModule = pCur->pVtabCursor->pVtab->pModule;
+ if( pModule->xRowid==0 ){
+ sqlite3SetString(&p->zErrMsg, "Unsupported module operation: xRowid", 0);
+ rc = SQLITE_ERROR;
+ } else {
+ sqlite_int64 iRow;
+
+ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+ rc = pModule->xRowid(pCur->pVtabCursor, &iRow);
+ if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+
+ pTos++;
+ pTos->flags = MEM_Int;
+ pTos->i = iRow;
+ }
+
+ break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VColumn P1 P2 *
+**
+** Push onto the stack the value of the P2-th column of
+** the row of the virtual-table that the P1 cursor is pointing to.
+*/
+case OP_VColumn: {
+ const sqlite3_module *pModule;
+
+ Cursor *pCur = p->apCsr[pOp->p1];
+ assert( pCur->pVtabCursor );
+ pModule = pCur->pVtabCursor->pVtab->pModule;
+ if( pModule->xColumn==0 ){
+ sqlite3SetString(&p->zErrMsg, "Unsupported module operation: xColumn", 0);
+ rc = SQLITE_ERROR;
+ } else {
+ sqlite3_context sContext;
+ memset(&sContext, 0, sizeof(sContext));
+ sContext.s.flags = MEM_Null;
+ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+ rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2);
+
+ /* Copy the result of the function to the top of the stack. We
+ ** do this regardless of whether or not an error occured to ensure any
+ ** dynamic allocation in sContext.s (a Mem struct) is released.
+ */
+ sqlite3VdbeChangeEncoding(&sContext.s, encoding);
+ pTos++;
+ pTos->flags = 0;
+ sqlite3VdbeMemMove(pTos, &sContext.s);
+
+ if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+ }
+
+ break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VNext P1 P2 *
+**
+** Advance virtual table P1 to the next row in its result set and
+** jump to instruction P2. Or, if the virtual table has reached
+** the end of its result set, then fall through to the next instruction.
+*/
+case OP_VNext: { /* no-push */
+ const sqlite3_module *pModule;
+ int res = 0;
+
+ Cursor *pCur = p->apCsr[pOp->p1];
+ assert( pCur->pVtabCursor );
+ pModule = pCur->pVtabCursor->pVtab->pModule;
+ if( pModule->xNext==0 ){
+ sqlite3SetString(&p->zErrMsg, "Unsupported module operation: xNext", 0);
+ rc = SQLITE_ERROR;
+ } else {
+ /* Invoke the xNext() method of the module. There is no way for the
+ ** underlying implementation to return an error if one occurs during
+ ** xNext(). Instead, if an error occurs, true is returned (indicating that
+ ** data is available) and the error code returned when xColumn or
+ ** some other method is next invoked on the save virtual table cursor.
+ */
+ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+ p->inVtabMethod = 1;
+ rc = pModule->xNext(pCur->pVtabCursor);
+ p->inVtabMethod = 0;
+ if( rc==SQLITE_OK ){
+ res = pModule->xEof(pCur->pVtabCursor);
+ }
+ if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+
+ if( !res ){
+ /* If there is data, jump to P2 */
+ pc = pOp->p2 - 1;
+ }
+ }
+
+ break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VUpdate P1 P2 P3
+**
+** P3 is a pointer to a virtual table object, an sqlite3_vtab structure.
+** This opcode invokes the corresponding xUpdate method. P2 values
+** are taken from the stack to pass to the xUpdate invocation. The
+** value on the top of the stack corresponds to the p2th element
+** of the argv array passed to xUpdate.
+**
+** The xUpdate method will do a DELETE or an INSERT or both.
+** The argv[0] element (which corresponds to the P2-th element down
+** on the stack) is the rowid of a row to delete. If argv[0] is
+** NULL then no deletion occurs. The argv[1] element is the rowid
+** of the new row. This can be NULL to have the virtual table
+** select the new rowid for itself. The higher elements in the
+** stack are the values of columns in the new row.
+**
+** If P2==1 then no insert is performed. argv[0] is the rowid of
+** a row to delete.
+**
+** P1 is a boolean flag. If it is set to true and the xUpdate call
+** is successful, then the value returned by sqlite3_last_insert_rowid()
+** is set to the value of the rowid for the row just inserted.
+*/
+case OP_VUpdate: { /* no-push */
+ sqlite3_vtab *pVtab = (sqlite3_vtab *)(pOp->p3);
+ sqlite3_module *pModule = (sqlite3_module *)pVtab->pModule;
+ int nArg = pOp->p2;
+ assert( pOp->p3type==P3_VTAB );
+ if( pModule->xUpdate==0 ){
+ sqlite3SetString(&p->zErrMsg, "read-only table", 0);
+ rc = SQLITE_ERROR;
+ }else{
+ int i;
+ sqlite_int64 rowid;
+ Mem **apArg = p->apArg;
+ Mem *pX = &pTos[1-nArg];
+ for(i = 0; i<nArg; i++, pX++){
+ storeTypeInfo(pX, 0);
+ apArg[i] = pX;
+ }
+ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+ rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
+ if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+ if( pOp->p1 && rc==SQLITE_OK ){
+ assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
+ db->lastRowid = rowid;
+ }
+ }
+ popStack(&pTos, nArg);
+ break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
/* An other opcode is illegal...
*/
@@ -4345,9 +4905,13 @@ default: {
** the evaluator loop. So we can leave it out when NDEBUG is defined.
*/
#ifndef NDEBUG
- /* Sanity checking on the top element of the stack */
- if( pTos>=p->aStack ){
- sqlite3VdbeMemSanity(pTos, db->enc);
+ /* Sanity checking on the top element of the stack. If the previous
+ ** instruction was VNoChange, then the flags field of the top
+ ** of the stack is set to 0. This is technically invalid for a memory
+ ** cell, so avoid calling MemSanity() in this case.
+ */
+ if( pTos>=p->aStack && pTos->flags ){
+ sqlite3VdbeMemSanity(pTos);
}
assert( pc>=-1 && pc<p->nOp );
#ifdef SQLITE_DEBUG
@@ -4366,7 +4930,7 @@ default: {
fprintf(p->trace, " r:%g", pTos[i].r);
}else{
char zBuf[100];
- sqlite3VdbeMemPrettyPrint(&pTos[i], zBuf, 100);
+ sqlite3VdbeMemPrettyPrint(&pTos[i], zBuf);
fprintf(p->trace, " ");
fprintf(p->trace, "%s", zBuf);
}
@@ -4410,7 +4974,7 @@ abort_due_to_misuse:
*/
abort_due_to_error:
if( p->zErrMsg==0 ){
- if( sqlite3_malloc_failed ) rc = SQLITE_NOMEM;
+ if( sqlite3MallocFailed() ) rc = SQLITE_NOMEM;
sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0);
}
goto vdbe_halt;
@@ -4419,8 +4983,7 @@ abort_due_to_error:
** flag.
*/
abort_due_to_interrupt:
- assert( db->flags & SQLITE_Interrupt );
- db->flags &= ~SQLITE_Interrupt;
+ assert( db->u1.isInterrupted );
if( db->magic!=SQLITE_MAGIC_BUSY ){
rc = SQLITE_MISUSE;
}else{
diff --git a/ext/pdo_sqlite/sqlite/src/vdbe.h b/ext/pdo_sqlite/sqlite/src/vdbe.h
index 06932503fc..903a18dcd2 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbe.h
+++ b/ext/pdo_sqlite/sqlite/src/vdbe.h
@@ -69,6 +69,9 @@ typedef struct VdbeOpList VdbeOpList;
#define P3_KEYINFO (-6) /* P3 is a pointer to a KeyInfo structure */
#define P3_VDBEFUNC (-7) /* P3 is a pointer to a VdbeFunc structure */
#define P3_MEM (-8) /* P3 is a pointer to a Mem* structure */
+#define P3_TRANSIENT (-9) /* P3 is a pointer to a transient string */
+#define P3_VTAB (-10) /* P3 is a pointer to an sqlite3_vtab structure */
+#define P3_MPRINTF (-11) /* P3 is a string obtained from sqlite3_mprintf() */
/* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure
** is made. That copy is freed when the Vdbe is finalized. But if the
@@ -80,6 +83,17 @@ typedef struct VdbeOpList VdbeOpList;
#define P3_KEYINFO_HANDOFF (-9)
/*
+** The Vdbe.aColName array contains 5n Mem structures, where n is the
+** number of columns of data returned by the statement.
+*/
+#define COLNAME_NAME 0
+#define COLNAME_DECLTYPE 1
+#define COLNAME_DATABASE 2
+#define COLNAME_TABLE 3
+#define COLNAME_COLUMN 4
+#define COLNAME_N 5 /* Number of COLNAME_xxx symbols */
+
+/*
** The following macro converts a relative address in the p2 field
** of a VdbeOp structure into a negative number so that
** sqlite3VdbeAddOpList() knows that the address is relative. Calling
@@ -105,6 +119,7 @@ int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
void sqlite3VdbeJumpHere(Vdbe*, int addr);
+void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N);
void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
int sqlite3VdbeMakeLabel(Vdbe*);
@@ -117,7 +132,7 @@ void sqlite3VdbeTrace(Vdbe*,FILE*);
int sqlite3VdbeReset(Vdbe*);
int sqliteVdbeSetVariables(Vdbe*,int,const char**);
void sqlite3VdbeSetNumCols(Vdbe*,int);
-int sqlite3VdbeSetColName(Vdbe*, int, const char *, int);
+int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int);
void sqlite3VdbeCountChanges(Vdbe*);
sqlite3 *sqlite3VdbeDb(Vdbe*);
diff --git a/ext/pdo_sqlite/sqlite/src/vdbeInt.h b/ext/pdo_sqlite/sqlite/src/vdbeInt.h
index 1746ee561f..db8034061b 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbeInt.h
+++ b/ext/pdo_sqlite/sqlite/src/vdbeInt.h
@@ -60,6 +60,7 @@ typedef unsigned char Bool;
*/
struct Cursor {
BtCursor *pCursor; /* The cursor structure of the backend */
+ int iDb; /* Index of cursor database in db->aDb[] (or -1) */
i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
i64 nextRowid; /* Next rowid returned by OP_NewRowid */
Bool zeroed; /* True if zeroed out and ready for reuse */
@@ -82,12 +83,15 @@ struct Cursor {
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
int nField; /* Number of fields in the header */
i64 seqCount; /* Sequence counter */
+ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
+ const sqlite3_module *pModule; /* Module for cursor pVtabCursor */
/* Cached information about the header for the data record that the
** cursor is currently pointing to. Only valid if cacheValid is true.
- ** zRow might point to (ephemeral) data for the current row, or it might
- ** be NULL. */
- Bool cacheValid; /* True if the cache is valid */
+ ** aRow might point to (ephemeral) data for the current row, or it might
+ ** be NULL.
+ */
+ int cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
int payloadSize; /* Total number of bytes in the record */
u32 *aType; /* Type values for all entries in the record */
u32 *aOffset; /* Cached offsets to the start of each columns data */
@@ -103,6 +107,11 @@ typedef struct Cursor Cursor;
#define NBFS 32
/*
+** A value for Cursor.cacheValid that means the cache is always invalid.
+*/
+#define CACHE_STALE 0
+
+/*
** Internally, the vdbe manipulates nearly all SQL values as Mem
** structures. Each Mem struct may cache multiple representations (string,
** integer etc.) of the same value. A value (and therefore Mem structure)
@@ -250,7 +259,7 @@ struct Fifo {
*/
typedef struct Context Context;
struct Context {
- int lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
+ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
int nChange; /* Statement changes (Vdbe.nChanges) */
Fifo sFifo; /* Records that will participate in a DELETE or UPDATE */
};
@@ -261,6 +270,14 @@ struct Context {
**
** The "sqlite3_stmt" structure pointer that is returned by sqlite3_compile()
** is really a pointer to an instance of this structure.
+**
+** The Vdbe.inVtabMethod variable is set to non-zero for the duration of
+** any virtual table method invocations made by the vdbe program. It is
+** set to 2 for xDestroy method calls and 1 for all other methods. This
+** variable is used for two purposes: to allow xDestroy methods to execute
+** "DROP TABLE" statements and to prevent some nasty side effects of
+** malloc failure when SQLite is invoked recursively by a virtual table
+** method function.
*/
struct Vdbe {
sqlite3 *db; /* The whole database */
@@ -286,6 +303,7 @@ struct Vdbe {
int nMem; /* Number of memory locations currently allocated */
Mem *aMem; /* The memory locations */
int nCallback; /* Number of callbacks invoked so far */
+ int cacheCtr; /* Cursor row cache generation counter */
Fifo sFifo; /* A list of ROWIDs */
int contextStackTop; /* Index of top element in the context stack */
int contextStackDepth; /* The size of the "context" stack */
@@ -306,8 +324,14 @@ struct Vdbe {
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 */
+ u8 minWriteFileFormat; /* Minimum file format for writable database files */
+ u8 inVtabMethod; /* See comments above */
int nChange; /* Number of db changes made since last reset */
i64 startTime; /* Time when query started - used for profiling */
+#ifdef SQLITE_SSE
+ int fetchId; /* Statement number used by sqlite3_fetch_statement */
+ int lru; /* Counter used for LRU cache replacement */
+#endif
};
/*
@@ -321,7 +345,7 @@ struct Vdbe {
/*
** Function prototypes
*/
-void sqlite3VdbeFreeCursor(Cursor*);
+void sqlite3VdbeFreeCursor(Vdbe *, Cursor*);
void sqliteVdbePopStack(Vdbe*,int);
int sqlite3VdbeCursorMoveto(Cursor*);
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
@@ -331,8 +355,8 @@ void sqlite3VdbePrintOp(FILE*, int, Op*);
void sqlite3VdbePrintSql(Vdbe*);
#endif
int sqlite3VdbeSerialTypeLen(u32);
-u32 sqlite3VdbeSerialType(Mem*);
-int sqlite3VdbeSerialPut(unsigned char*, Mem*);
+u32 sqlite3VdbeSerialType(Mem*, int);
+int sqlite3VdbeSerialPut(unsigned char*, Mem*, int);
int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
@@ -341,7 +365,7 @@ int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int*);
int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
int sqlite3VdbeRecordCompare(void*,int,const void*,int, const void*);
-int sqlite3VdbeIdxRowidLen(int,const u8*);
+int sqlite3VdbeIdxRowidLen(const u8*);
int sqlite3VdbeExec(Vdbe*);
int sqlite3VdbeList(Vdbe*);
int sqlite3VdbeHalt(Vdbe*);
@@ -360,16 +384,18 @@ int sqlite3VdbeMemStringify(Mem*, int);
i64 sqlite3VdbeIntValue(Mem*);
int sqlite3VdbeMemIntegerify(Mem*);
double sqlite3VdbeRealValue(Mem*);
+void sqlite3VdbeIntegerAffinity(Mem*);
int sqlite3VdbeMemRealify(Mem*);
+int sqlite3VdbeMemNumerify(Mem*);
int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
void sqlite3VdbeMemRelease(Mem *p);
-void sqlite3VdbeMemFinalize(Mem*, FuncDef*);
+int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
#ifndef NDEBUG
-void sqlite3VdbeMemSanity(Mem*, u8);
+void sqlite3VdbeMemSanity(Mem*);
int sqlite3VdbeOpcodeNoPush(u8);
#endif
int sqlite3VdbeMemTranslate(Mem*, u8);
-void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf, int nBuf);
+void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf);
int sqlite3VdbeMemHandleBom(Mem *pMem);
void sqlite3VdbeFifoInit(Fifo*);
int sqlite3VdbeFifoPush(Fifo*, i64);
diff --git a/ext/pdo_sqlite/sqlite/src/vdbeapi.c b/ext/pdo_sqlite/sqlite/src/vdbeapi.c
index 2fd54f38e3..a0ced3d791 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbeapi.c
+++ b/ext/pdo_sqlite/sqlite/src/vdbeapi.c
@@ -58,7 +58,7 @@ sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){
return sqlite3VdbeIntValue((Mem*)pVal);
}
const unsigned char *sqlite3_value_text(sqlite3_value *pVal){
- return (const char *)sqlite3ValueText(pVal, SQLITE_UTF8);
+ return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8);
}
#ifndef SQLITE_OMIT_UTF16
const void *sqlite3_value_text16(sqlite3_value* pVal){
@@ -74,6 +74,7 @@ const void *sqlite3_value_text16le(sqlite3_value *pVal){
int sqlite3_value_type(sqlite3_value* pVal){
return pVal->type;
}
+/* sqlite3_value_numeric_type() defined in vdbe.c */
/**************************** sqlite3_result_ *******************************
** The following routines are used by user-defined functions to specify
@@ -95,10 +96,12 @@ void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
pCtx->isError = 1;
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
}
+#ifndef SQLITE_OMIT_UTF16
void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
pCtx->isError = 1;
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
}
+#endif
void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal);
}
@@ -156,6 +159,9 @@ int sqlite3_step(sqlite3_stmt *pStmt){
sqlite3 *db;
int rc;
+ /* Assert that malloc() has not failed */
+ assert( !sqlite3MallocFailed() );
+
if( p==0 || p->magic!=VDBE_MAGIC_RUN ){
return SQLITE_MISUSE;
}
@@ -174,6 +180,14 @@ int sqlite3_step(sqlite3_stmt *pStmt){
return SQLITE_MISUSE;
}
if( p->pc<0 ){
+ /* If there are no other statements currently running, then
+ ** reset the interrupt flag. This prevents a call to sqlite3_interrupt
+ ** from interrupting a statement that has not yet started.
+ */
+ if( db->activeVdbeCnt==0 ){
+ db->u1.isInterrupted = 0;
+ }
+
#ifndef SQLITE_OMIT_TRACE
/* Invoke the trace callback if there is one
*/
@@ -238,7 +252,8 @@ int sqlite3_step(sqlite3_stmt *pStmt){
}
#endif
- sqlite3Error(p->db, rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
+ sqlite3Error(p->db, rc, 0);
+ p->rc = sqlite3ApiExit(p->db, p->rc);
return rc;
}
@@ -329,9 +344,10 @@ void sqlite3_set_auxdata(
** Return the number of times the Step function of a aggregate has been
** called.
**
-** This routine is defined here in vdbe.c because it depends on knowing
-** the internals of the sqlite3_context structure which is only defined in
-** this source file.
+** This function is deprecated. Do not use it for new code. It is
+** provide only to avoid breaking legacy code. New aggregate function
+** implementations should keep their own counts within their aggregate
+** context.
*/
int sqlite3_aggregate_count(sqlite3_context *p){
assert( p && p->pFunc && p->pFunc->xStep );
@@ -367,53 +383,105 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
Vdbe *pVm = (Vdbe *)pStmt;
int vals = sqlite3_data_count(pStmt);
if( i>=vals || i<0 ){
- static Mem nullMem;
- if( nullMem.flags==0 ){ nullMem.flags = MEM_Null; }
+ static const Mem nullMem = {0, 0.0, "", 0, MEM_Null, MEM_Null };
sqlite3Error(pVm->db, SQLITE_RANGE, 0);
- return &nullMem;
+ return (Mem*)&nullMem;
}
return &pVm->pTos[(1-vals)+i];
}
+/*
+** This function is called after invoking an sqlite3_value_XXX function on a
+** column value (i.e. a value returned by evaluating an SQL expression in the
+** select list of a SELECT statement) that may cause a malloc() failure. If
+** malloc() has failed, the threads mallocFailed flag is cleared and the result
+** code of statement pStmt set to SQLITE_NOMEM.
+**
+** Specificly, this is called from within:
+**
+** sqlite3_column_int()
+** sqlite3_column_int64()
+** sqlite3_column_text()
+** sqlite3_column_text16()
+** sqlite3_column_real()
+** sqlite3_column_bytes()
+** sqlite3_column_bytes16()
+**
+** But not for sqlite3_column_blob(), which never calls malloc().
+*/
+static void columnMallocFailure(sqlite3_stmt *pStmt)
+{
+ /* If malloc() failed during an encoding conversion within an
+ ** sqlite3_column_XXX API, then set the return code of the statement to
+ ** SQLITE_NOMEM. The next call to _step() (if any) will return SQLITE_ERROR
+ ** and _finalize() will return NOMEM.
+ */
+ Vdbe *p = (Vdbe *)pStmt;
+ p->rc = sqlite3ApiExit(0, p->rc);
+}
+
/**************************** sqlite3_column_ *******************************
** The following routines are used to access elements of the current row
** in the result set.
*/
const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_blob( columnMem(pStmt,i) );
+ const void *val;
+ sqlite3MallocDisallow();
+ val = sqlite3_value_blob( columnMem(pStmt,i) );
+ sqlite3MallocAllow();
+ return val;
}
int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_bytes( columnMem(pStmt,i) );
+ int val = sqlite3_value_bytes( columnMem(pStmt,i) );
+ columnMallocFailure(pStmt);
+ return val;
}
int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_bytes16( columnMem(pStmt,i) );
+ int val = sqlite3_value_bytes16( columnMem(pStmt,i) );
+ columnMallocFailure(pStmt);
+ return val;
}
double sqlite3_column_double(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_double( columnMem(pStmt,i) );
+ double val = sqlite3_value_double( columnMem(pStmt,i) );
+ columnMallocFailure(pStmt);
+ return val;
}
int sqlite3_column_int(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_int( columnMem(pStmt,i) );
+ int val = sqlite3_value_int( columnMem(pStmt,i) );
+ columnMallocFailure(pStmt);
+ return val;
}
sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_int64( columnMem(pStmt,i) );
+ sqlite_int64 val = sqlite3_value_int64( columnMem(pStmt,i) );
+ columnMallocFailure(pStmt);
+ return val;
}
const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_text( columnMem(pStmt,i) );
+ const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) );
+ columnMallocFailure(pStmt);
+ return val;
}
-#if 0
sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
return columnMem(pStmt, i);
}
-#endif
#ifndef SQLITE_OMIT_UTF16
const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_text16( columnMem(pStmt,i) );
+ const void *val = sqlite3_value_text16( columnMem(pStmt,i) );
+ columnMallocFailure(pStmt);
+ return val;
}
#endif /* SQLITE_OMIT_UTF16 */
int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
return sqlite3_value_type( columnMem(pStmt,i) );
}
+/* The following function is experimental and subject to change or
+** removal */
+/*int sqlite3_column_numeric_type(sqlite3_stmt *pStmt, int i){
+** return sqlite3_value_numeric_type( columnMem(pStmt,i) );
+**}
+*/
+
/*
** Convert the N-th element of pStmt->pColName[] into a string using
** xFunc() then return that string. If N is out of range, return 0.
@@ -436,6 +504,7 @@ static const void *columnName(
const void *(*xFunc)(Mem*),
int useType
){
+ const void *ret;
Vdbe *p = (Vdbe *)pStmt;
int n = sqlite3_column_count(pStmt);
@@ -443,20 +512,27 @@ static const void *columnName(
return 0;
}
N += useType*n;
- return xFunc(&p->aColName[N]);
-}
+ ret = xFunc(&p->aColName[N]);
+ /* A malloc may have failed inside of the xFunc() call. If this is the case,
+ ** clear the mallocFailed flag and return NULL.
+ */
+ sqlite3ApiExit(0, 0);
+ return ret;
+}
/*
** Return the name of the Nth column of the result set returned by SQL
** statement pStmt.
*/
const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){
- return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 0);
+ return columnName(
+ pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_NAME);
}
#ifndef SQLITE_OMIT_UTF16
const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
- return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 0);
+ return columnName(
+ pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_NAME);
}
#endif
@@ -465,26 +541,30 @@ const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
** of the result set of SQL statement pStmt.
*/
const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
- return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 1);
+ return columnName(
+ pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DECLTYPE);
}
#ifndef SQLITE_OMIT_UTF16
const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
- return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 1);
+ return columnName(
+ pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DECLTYPE);
}
#endif /* SQLITE_OMIT_UTF16 */
-#if !defined(SQLITE_OMIT_ORIGIN_NAMES) && 0
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
/*
** Return the name of the database from which a result column derives.
** NULL is returned if the result column is an expression or constant or
** anything else which is not an unabiguous reference to a database column.
*/
const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){
- return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 2);
+ return columnName(
+ pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DATABASE);
}
#ifndef SQLITE_OMIT_UTF16
const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
- return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 2);
+ return columnName(
+ pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DATABASE);
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -494,11 +574,13 @@ const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
** anything else which is not an unabiguous reference to a database column.
*/
const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){
- return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 3);
+ return columnName(
+ pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_TABLE);
}
#ifndef SQLITE_OMIT_UTF16
const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
- return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 3);
+ return columnName(
+ pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_TABLE);
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -508,16 +590,16 @@ const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
** anything else which is not an unabiguous reference to a database column.
*/
const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){
- return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 4);
+ return columnName(
+ pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_COLUMN);
}
#ifndef SQLITE_OMIT_UTF16
const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
- return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 4);
+ return columnName(
+ pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_COLUMN);
}
#endif /* SQLITE_OMIT_UTF16 */
-#endif /* SQLITE_OMIT_ORIGIN_NAMES */
-
-
+#endif /* SQLITE_ENABLE_COLUMN_METADATA */
/******************************* sqlite3_bind_ ***************************
@@ -571,13 +653,12 @@ static int bindText(
}
pVar = &p->aVar[i-1];
rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel);
- if( rc ){
- return rc;
- }
if( rc==SQLITE_OK && encoding!=0 ){
- rc = sqlite3VdbeChangeEncoding(pVar, p->db->enc);
+ rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db));
}
- return rc;
+
+ sqlite3Error(((Vdbe *)pStmt)->db, rc, 0);
+ return sqlite3ApiExit(((Vdbe *)pStmt)->db, rc);
}
@@ -637,6 +718,15 @@ int sqlite3_bind_text16(
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
}
#endif /* SQLITE_OMIT_UTF16 */
+int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
+ int rc;
+ Vdbe *p = (Vdbe *)pStmt;
+ rc = vdbeUnbind(p, i);
+ if( rc==SQLITE_OK ){
+ sqlite3VdbeMemCopy(&p->aVar[i-1], pValue);
+ }
+ return rc;
+}
/*
** Return the number of wildcards that can be potentially bound to.
@@ -721,7 +811,9 @@ int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
return SQLITE_ERROR;
}
for(i=0; rc==SQLITE_OK && i<pFrom->nVar; i++){
+ sqlite3MallocDisallow();
rc = sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]);
+ sqlite3MallocAllow();
}
return rc;
}
diff --git a/ext/pdo_sqlite/sqlite/src/vdbeaux.c b/ext/pdo_sqlite/sqlite/src/vdbeaux.c
index cba9c096d6..35bf07f422 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbeaux.c
+++ b/ext/pdo_sqlite/sqlite/src/vdbeaux.c
@@ -58,8 +58,14 @@ void sqlite3VdbeTrace(Vdbe *p, FILE *trace){
/*
** Resize the Vdbe.aOp array so that it contains at least N
** elements. If the Vdbe is in VDBE_MAGIC_RUN state, then
-** the Vdbe.aOp array will be sized to contain exactly N
-** elements.
+** the Vdbe.aOp array will be sized to contain exactly N
+** elements. Vdbe.nOpAlloc is set to reflect the new size of
+** the array.
+**
+** If an out-of-memory error occurs while resizing the array,
+** Vdbe.aOp and Vdbe.nOpAlloc remain unchanged (this is so that
+** any opcodes already allocated can be correctly deallocated
+** along with the rest of the Vdbe).
*/
static void resizeOpArray(Vdbe *p, int N){
int runMode = p->magic==VDBE_MAGIC_RUN;
@@ -101,9 +107,11 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
i = p->nOp;
p->nOp++;
assert( p->magic==VDBE_MAGIC_INIT );
- resizeOpArray(p, i+1);
- if( sqlite3_malloc_failed ){
- return 0;
+ if( p->nOpAlloc<=i ){
+ resizeOpArray(p, i+1);
+ if( sqlite3MallocFailed() ){
+ return 0;
+ }
}
pOp = &p->aOp[i];
pOp->opcode = op;
@@ -147,7 +155,7 @@ int sqlite3VdbeMakeLabel(Vdbe *p){
assert( p->magic==VDBE_MAGIC_INIT );
if( i>=p->nLabelAlloc ){
p->nLabelAlloc = p->nLabelAlloc*2 + 10;
- sqlite3ReallocOrFree((void**)&p->aLabel,
+ sqliteReallocOrFree((void**)&p->aLabel,
p->nLabelAlloc*sizeof(p->aLabel[0]));
}
if( p->aLabel ){
@@ -196,12 +204,13 @@ static int opcodeNoPush(u8 op){
** IEEE floats.
*/
static const u32 masks[5] = {
- NOPUSH_MASK_0 + (NOPUSH_MASK_1<<16),
- NOPUSH_MASK_2 + (NOPUSH_MASK_3<<16),
- NOPUSH_MASK_4 + (NOPUSH_MASK_5<<16),
- NOPUSH_MASK_6 + (NOPUSH_MASK_7<<16),
- NOPUSH_MASK_8 + (NOPUSH_MASK_9<<16)
+ NOPUSH_MASK_0 + (((unsigned)NOPUSH_MASK_1)<<16),
+ NOPUSH_MASK_2 + (((unsigned)NOPUSH_MASK_3)<<16),
+ NOPUSH_MASK_4 + (((unsigned)NOPUSH_MASK_5)<<16),
+ NOPUSH_MASK_6 + (((unsigned)NOPUSH_MASK_7)<<16),
+ NOPUSH_MASK_8 + (((unsigned)NOPUSH_MASK_9)<<16)
};
+ assert( op<32*5 );
return (masks[op>>5] & (1<<(op&0x1F)));
}
@@ -219,7 +228,7 @@ int sqlite3VdbeOpcodeNoPush(u8 op){
** This routine is called once after all opcodes have been inserted.
**
** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument
-** to an OP_Function or OP_AggStep opcode. This is used by
+** to an OP_Function, OP_AggStep or OP_VFilter opcode. This is used by
** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array.
**
** The integer *pMaxStack is set to the maximum number of vdbe stack
@@ -242,20 +251,25 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
u8 opcode = pOp->opcode;
- if( opcode==OP_Function || opcode==OP_AggStep ){
+ if( opcode==OP_Function || opcode==OP_AggStep
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ || opcode==OP_VUpdate
+#endif
+ ){
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
}else if( opcode==OP_Halt ){
if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){
doesStatementRollback = 1;
}
- }else if( opcode==OP_IdxInsert ){
- if( pOp->p2 ){
- doesStatementRollback = 1;
- }
}else if( opcode==OP_Statement ){
hasStatementBegin = 1;
+ }else if( opcode==OP_VFilter ){
+ int n;
+ assert( p->nOp - i >= 3 );
+ assert( pOp[-2].opcode==OP_Integer );
+ n = pOp[-2].p1;
+ if( n>nMaxArgs ) nMaxArgs = n;
}
-
if( opcodeNoPush(opcode) ){
nMaxStack--;
}
@@ -300,7 +314,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
int addr;
assert( p->magic==VDBE_MAGIC_INIT );
resizeOpArray(p, p->nOp + nOp);
- if( sqlite3_malloc_failed ){
+ if( sqlite3MallocFailed() ){
return 0;
}
addr = p->nOp;
@@ -333,7 +347,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
** few minor changes to the program.
*/
void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
- assert( p->magic==VDBE_MAGIC_INIT );
+ assert( p==0 || p->magic==VDBE_MAGIC_INIT );
if( p && addr>=0 && p->nOp>addr && p->aOp ){
p->aOp[addr].p1 = val;
}
@@ -345,20 +359,31 @@ void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
*/
void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
assert( val>=0 );
- assert( p->magic==VDBE_MAGIC_INIT );
+ assert( p==0 || p->magic==VDBE_MAGIC_INIT );
if( p && addr>=0 && p->nOp>addr && p->aOp ){
p->aOp[addr].p2 = val;
}
}
/*
-** Change teh P2 operand of instruction addr so that it points to
+** Change the P2 operand of instruction addr so that it points to
** the address of the next instruction to be coded.
*/
void sqlite3VdbeJumpHere(Vdbe *p, int addr){
sqlite3VdbeChangeP2(p, addr, p->nOp);
}
+
+/*
+** If the input FuncDef structure is ephemeral, then free it. If
+** the FuncDef is not ephermal, then do nothing.
+*/
+static void freeEphemeralFunction(FuncDef *pDef){
+ if( pDef && (pDef->flags & SQLITE_FUNC_EPHEM)!=0 ){
+ sqliteFree(pDef);
+ }
+}
+
/*
** Delete a P3 value if necessary.
*/
@@ -371,12 +396,21 @@ static void freeP3(int p3type, void *p3){
sqliteFree(p3);
break;
}
+ case P3_MPRINTF: {
+ sqlite3_free(p3);
+ break;
+ }
case P3_VDBEFUNC: {
VdbeFunc *pVdbeFunc = (VdbeFunc *)p3;
+ freeEphemeralFunction(pVdbeFunc->pFunc);
sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
sqliteFree(pVdbeFunc);
break;
}
+ case P3_FUNCDEF: {
+ freeEphemeralFunction((FuncDef*)p3);
+ break;
+ }
case P3_MEM: {
sqlite3ValueFree((sqlite3_value*)p3);
break;
@@ -387,6 +421,19 @@ static void freeP3(int p3type, void *p3){
/*
+** Change N opcodes starting at addr to No-ops.
+*/
+void sqlite3VdbeChangeToNoop(Vdbe *p, int addr, int N){
+ VdbeOp *pOp = &p->aOp[addr];
+ while( N-- ){
+ freeP3(pOp->p3type, pOp->p3);
+ memset(pOp, 0, sizeof(pOp[0]));
+ pOp->opcode = OP_Noop;
+ pOp++;
+ }
+}
+
+/*
** Change the value of the P3 operand for a specific instruction.
** This routine is useful when a large program is loaded from a
** static array using sqlite3VdbeAddOpList but we want to make a
@@ -413,9 +460,11 @@ static void freeP3(int p3type, void *p3){
*/
void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
Op *pOp;
- assert( p->magic==VDBE_MAGIC_INIT );
- if( p==0 || p->aOp==0 ){
- freeP3(n, (void*)*(char**)&zP3);
+ assert( p==0 || p->magic==VDBE_MAGIC_INIT );
+ if( p==0 || p->aOp==0 || sqlite3MallocFailed() ){
+ if (n != P3_KEYINFO) {
+ freeP3(n, (void*)*(char**)&zP3);
+ }
return;
}
if( addr<0 || addr>=p->nOp ){
@@ -432,16 +481,18 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
KeyInfo *pKeyInfo;
int nField, nByte;
- /* KeyInfo structures that include an KeyInfo.aSortOrder are always
- ** sent in using P3_KEYINFO_HANDOFF. The KeyInfo.aSortOrder array
- ** is not duplicated when P3_KEYINFO is used. */
- /* assert( pKeyInfo->aSortOrder==0 ); */
nField = ((KeyInfo*)zP3)->nField;
- nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]);
+ nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]) + nField;
pKeyInfo = sqliteMallocRaw( nByte );
pOp->p3 = (char*)pKeyInfo;
if( pKeyInfo ){
+ unsigned char *aSortOrder;
memcpy(pKeyInfo, zP3, nByte);
+ aSortOrder = pKeyInfo->aSortOrder;
+ if( aSortOrder ){
+ pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
+ memcpy(pKeyInfo->aSortOrder, aSortOrder, nField);
+ }
pOp->p3type = P3_KEYINFO;
}else{
pOp->p3type = P3_NOTUSED;
@@ -467,7 +518,8 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){
va_list ap;
assert( p->nOp>0 );
- assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 );
+ assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0
+ || sqlite3MallocFailed() );
va_start(ap, zFormat);
sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC);
va_end(ap);
@@ -531,15 +583,18 @@ static char *displayP3(Op *pOp, char *zTemp, int nTemp){
}
case P3_FUNCDEF: {
FuncDef *pDef = (FuncDef*)pOp->p3;
- char zNum[30];
- sprintf(zTemp, "%.*s", nTemp, pDef->zName);
- sprintf(zNum,"(%d)", pDef->nArg);
- if( strlen(zTemp)+strlen(zNum)+1<=nTemp ){
- strcat(zTemp, zNum);
- }
+ sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg);
+ zP3 = zTemp;
+ break;
+ }
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ case P3_VTAB: {
+ sqlite3_vtab *pVtab = (sqlite3_vtab*)pOp->p3;
+ sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule);
zP3 = zTemp;
break;
}
+#endif
default: {
zP3 = pOp->p3;
if( zP3==0 || pOp->opcode==OP_Noop ){
@@ -547,6 +602,7 @@ static char *displayP3(Op *pOp, char *zTemp, int nTemp){
}
}
}
+ assert( zP3!=0 );
return zP3;
}
#endif
@@ -614,8 +670,7 @@ int sqlite3VdbeList(
if( i>=p->nOp ){
p->rc = SQLITE_OK;
rc = SQLITE_DONE;
- }else if( db->flags & SQLITE_Interrupt ){
- db->flags &= ~SQLITE_Interrupt;
+ }else if( db->u1.isInterrupted ){
p->rc = SQLITE_INTERRUPT;
rc = SQLITE_ERROR;
sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(p->rc), (char*)0);
@@ -629,6 +684,7 @@ int sqlite3VdbeList(
pMem->flags = MEM_Static|MEM_Str|MEM_Term;
pMem->z = sqlite3OpcodeNames[pOp->opcode]; /* Opcode */
+ assert( pMem->z!=0 );
pMem->n = strlen(pMem->z);
pMem->type = SQLITE_TEXT;
pMem->enc = SQLITE_UTF8;
@@ -644,8 +700,10 @@ int sqlite3VdbeList(
pMem->type = SQLITE_INTEGER;
pMem++;
- pMem->flags = MEM_Short|MEM_Str|MEM_Term; /* P3 */
+ pMem->flags = MEM_Ephem|MEM_Str|MEM_Term; /* P3 */
pMem->z = displayP3(pOp, pMem->zShort, sizeof(pMem->zShort));
+ assert( pMem->z!=0 );
+ pMem->n = strlen(pMem->z);
pMem->type = SQLITE_TEXT;
pMem->enc = SQLITE_UTF8;
@@ -724,7 +782,9 @@ void sqlite3VdbeMakeReady(
resizeOpArray(p, p->nOp);
assert( nVar>=0 );
assert( nStack<p->nOp );
- nStack = isExplain ? 10 : nStack;
+ if( isExplain ){
+ nStack = 10;
+ }
p->aStack = sqliteMalloc(
nStack*sizeof(p->aStack[0]) /* aStack */
+ nArg*sizeof(Mem*) /* apArg */
@@ -733,7 +793,7 @@ void sqlite3VdbeMakeReady(
+ nMem*sizeof(Mem) /* aMem */
+ nCursor*sizeof(Cursor*) /* apCsr */
);
- if( !sqlite3_malloc_failed ){
+ if( !sqlite3MallocFailed() ){
p->aMem = &p->aStack[nStack];
p->nMem = nMem;
p->aVar = &p->aMem[nMem];
@@ -777,6 +837,8 @@ void sqlite3VdbeMakeReady(
p->explain |= isExplain;
p->magic = VDBE_MAGIC_RUN;
p->nChange = 0;
+ p->cacheCtr = 1;
+ p->minWriteFileFormat = 255;
#ifdef VDBE_PROFILE
{
int i;
@@ -792,7 +854,7 @@ void sqlite3VdbeMakeReady(
** Close a cursor and release all the resources that cursor happens
** to hold.
*/
-void sqlite3VdbeFreeCursor(Cursor *pCx){
+void sqlite3VdbeFreeCursor(Vdbe *p, Cursor *pCx){
if( pCx==0 ){
return;
}
@@ -802,6 +864,17 @@ void sqlite3VdbeFreeCursor(Cursor *pCx){
if( pCx->pBt ){
sqlite3BtreeClose(pCx->pBt);
}
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( pCx->pVtabCursor ){
+ sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
+ const sqlite3_module *pModule = pCx->pModule;
+ p->inVtabMethod = 1;
+ sqlite3SafetyOff(p->db);
+ pModule->xClose(pVtabCursor);
+ sqlite3SafetyOn(p->db);
+ p->inVtabMethod = 0;
+ }
+#endif
sqliteFree(pCx->pData);
sqliteFree(pCx->aType);
sqliteFree(pCx);
@@ -814,8 +887,10 @@ static void closeAllCursors(Vdbe *p){
int i;
if( p->apCsr==0 ) return;
for(i=0; i<p->nCursor; i++){
- sqlite3VdbeFreeCursor(p->apCsr[i]);
- p->apCsr[i] = 0;
+ if( !p->inVtabMethod || (p->apCsr[i] && !p->apCsr[i]->pVtabCursor) ){
+ sqlite3VdbeFreeCursor(p, p->apCsr[i]);
+ p->apCsr[i] = 0;
+ }
}
}
@@ -857,9 +932,10 @@ static void Cleanup(Vdbe *p){
void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
Mem *pColName;
int n;
- assert( 0==p->nResColumn );
+ releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
+ sqliteFree(p->aColName);
+ n = nResColumn*COLNAME_N;
p->nResColumn = nResColumn;
- n = nResColumn*2;
p->aColName = pColName = (Mem*)sqliteMalloc( sizeof(Mem)*n );
if( p->aColName==0 ) return;
while( n-- > 0 ){
@@ -878,13 +954,14 @@ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
** the string is freed using sqliteFree() when the vdbe is finished with
** it. Otherwise, N bytes of zName are copied.
*/
-int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){
+int sqlite3VdbeSetColName(Vdbe *p, int idx, int var, const char *zName, int N){
int rc;
Mem *pColName;
- assert( idx<(2*p->nResColumn) );
- if( sqlite3_malloc_failed ) return SQLITE_NOMEM;
+ assert( idx<p->nResColumn );
+ assert( var<COLNAME_N );
+ if( sqlite3MallocFailed() ) return SQLITE_NOMEM;
assert( p->aColName!=0 );
- pColName = &(p->aColName[idx]);
+ pColName = &(p->aColName[idx+var*p->nResColumn]);
if( N==P3_DYNAMIC || N==P3_STATIC ){
rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, SQLITE_STATIC);
}else{
@@ -909,6 +986,23 @@ static int vdbeCommit(sqlite3 *db){
int rc = SQLITE_OK;
int needXcommit = 0;
+ /* Before doing anything else, call the xSync() callback for any
+ ** virtual module tables written in this transaction. This has to
+ ** be done before determining whether a master journal file is
+ ** required, as an xSync() callback may add an attached database
+ ** to the transaction.
+ */
+ rc = sqlite3VtabSync(db, rc);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+
+ /* This loop determines (a) if the commit hook should be invoked and
+ ** (b) how many database files have open write transactions, not
+ ** including the temp database. (b) is important because if more than
+ ** one database file has an open write transaction, a master journal
+ ** file is required for an atomic commit.
+ */
for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt && sqlite3BtreeIsInTrans(pBt) ){
@@ -919,7 +1013,6 @@ static int vdbeCommit(sqlite3 *db){
/* If there are any write-transactions at all, invoke the commit hook */
if( needXcommit && db->xCommitCallback ){
- int rc;
sqlite3SafetyOff(db);
rc = db->xCommitCallback(db->pCommitArg);
sqlite3SafetyOn(db);
@@ -953,6 +1046,7 @@ static int vdbeCommit(sqlite3 *db){
sqlite3BtreeCommit(pBt);
}
}
+ sqlite3VtabCommit(db);
}
}
@@ -965,7 +1059,7 @@ static int vdbeCommit(sqlite3 *db){
int needSync = 0;
char *zMaster = 0; /* File-name for the master journal */
char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
- OsFile master;
+ OsFile *master = 0;
/* Select a master journal file name */
do {
@@ -979,7 +1073,6 @@ static int vdbeCommit(sqlite3 *db){
}while( sqlite3OsFileExists(zMaster) );
/* Open the master journal. */
- memset(&master, 0, sizeof(master));
rc = sqlite3OsOpenExclusive(zMaster, &master, 0);
if( rc!=SQLITE_OK ){
sqliteFree(zMaster);
@@ -1001,7 +1094,7 @@ static int vdbeCommit(sqlite3 *db){
if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
needSync = 1;
}
- rc = sqlite3OsWrite(&master, zFile, strlen(zFile)+1);
+ rc = sqlite3OsWrite(master, zFile, strlen(zFile)+1);
if( rc!=SQLITE_OK ){
sqlite3OsClose(&master);
sqlite3OsDelete(zMaster);
@@ -1016,9 +1109,9 @@ static int vdbeCommit(sqlite3 *db){
** the master journal file is store in so that it gets synced too.
*/
zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
- rc = sqlite3OsOpenDirectory(zMainFile, &master);
+ rc = sqlite3OsOpenDirectory(master, zMainFile);
if( rc!=SQLITE_OK ||
- (needSync && (rc=sqlite3OsSync(&master,0))!=SQLITE_OK) ){
+ (needSync && (rc=sqlite3OsSync(master,0))!=SQLITE_OK) ){
sqlite3OsClose(&master);
sqlite3OsDelete(zMaster);
sqliteFree(zMaster);
@@ -1035,18 +1128,17 @@ static int vdbeCommit(sqlite3 *db){
** file name was written into the journal file before the failure
** occured.
*/
- for(i=0; i<db->nDb; i++){
+ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt && sqlite3BtreeIsInTrans(pBt) ){
rc = sqlite3BtreeSync(pBt, zMaster);
- if( rc!=SQLITE_OK ){
- sqlite3OsClose(&master);
- sqliteFree(zMaster);
- return rc;
- }
}
}
sqlite3OsClose(&master);
+ if( rc!=SQLITE_OK ){
+ sqliteFree(zMaster);
+ return rc;
+ }
/* Delete the master journal file. This commits the transaction. After
** doing this the directory is synced again before any individual
@@ -1081,29 +1173,13 @@ static int vdbeCommit(sqlite3 *db){
sqlite3BtreeCommit(pBt);
}
}
+ sqlite3VtabCommit(db);
}
#endif
return rc;
}
-/*
-** Find every active VM other than pVdbe and change its status to
-** aborted. This happens when one VM causes a rollback due to an
-** ON CONFLICT ROLLBACK clause (for example). The other VMs must be
-** aborted so that they do not have data rolled out from underneath
-** them leading to a segfault.
-*/
-static void abortOtherActiveVdbes(Vdbe *pVdbe){
- Vdbe *pOther;
- for(pOther=pVdbe->db->pVdbe; pOther; pOther=pOther->pNext){
- if( pOther==pVdbe ) continue;
- if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue;
- closeAllCursors(pOther);
- pOther->aborted = 1;
- }
-}
-
/*
** This routine checks that the sqlite3.activeVdbeCnt count variable
** matches the number of vdbe's in the list sqlite3.pVdbe that are
@@ -1131,6 +1207,25 @@ static void checkActiveVdbeCnt(sqlite3 *db){
#endif
/*
+** Find every active VM other than pVdbe and change its status to
+** aborted. This happens when one VM causes a rollback due to an
+** ON CONFLICT ROLLBACK clause (for example). The other VMs must be
+** aborted so that they do not have data rolled out from underneath
+** them leading to a segfault.
+*/
+void sqlite3AbortOtherActiveVdbes(sqlite3 *db, Vdbe *pExcept){
+ Vdbe *pOther;
+ for(pOther=db->pVdbe; pOther; pOther=pOther->pNext){
+ if( pOther==pExcept ) continue;
+ if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue;
+ checkActiveVdbeCnt(db);
+ closeAllCursors(pOther);
+ checkActiveVdbeCnt(db);
+ pOther->aborted = 1;
+ }
+}
+
+/*
** This routine is called the when a VDBE tries to halt. If the VDBE
** has made changes and is in autocommit mode, then commit those
** changes. If a rollback is needed, then do the rollback.
@@ -1146,73 +1241,174 @@ int sqlite3VdbeHalt(Vdbe *p){
sqlite3 *db = p->db;
int i;
int (*xFunc)(Btree *pBt) = 0; /* Function to call on each btree backend */
+ int isSpecialError; /* Set to true if SQLITE_NOMEM or IOERR */
+
+ /* This function contains the logic that determines if a statement or
+ ** transaction will be committed or rolled back as a result of the
+ ** execution of this virtual machine.
+ **
+ ** Special errors:
+ **
+ ** If an SQLITE_NOMEM error has occured in a statement that writes to
+ ** the database, then either a statement or transaction must be rolled
+ ** back to ensure the tree-structures are in a consistent state. A
+ ** statement transaction is rolled back if one is open, otherwise the
+ ** entire transaction must be rolled back.
+ **
+ ** If an SQLITE_IOERR error has occured in a statement that writes to
+ ** the database, then the entire transaction must be rolled back. The
+ ** I/O error may have caused garbage to be written to the journal
+ ** file. Were the transaction to continue and eventually be rolled
+ ** back that garbage might end up in the database file.
+ **
+ ** In both of the above cases, the Vdbe.errorAction variable is
+ ** ignored. If the sqlite3.autoCommit flag is false and a transaction
+ ** is rolled back, it will be set to true.
+ **
+ ** Other errors:
+ **
+ ** No error:
+ **
+ */
+ if( sqlite3MallocFailed() ){
+ p->rc = SQLITE_NOMEM;
+ }
if( p->magic!=VDBE_MAGIC_RUN ){
/* Already halted. Nothing to do. */
assert( p->magic==VDBE_MAGIC_HALT );
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ closeAllCursors(p);
+#endif
return SQLITE_OK;
}
closeAllCursors(p);
checkActiveVdbeCnt(db);
- 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
- ** 'OR FAIL' constraint. This means a commit is required.
+
+ /* No commit or rollback needed if the program never started */
+ if( p->pc>=0 ){
+
+ /* Check for one of the special errors - SQLITE_NOMEM or SQLITE_IOERR */
+ isSpecialError = ((p->rc==SQLITE_NOMEM || p->rc==SQLITE_IOERR)?1:0);
+ if( isSpecialError ){
+ /* This loop does static analysis of the query to see which of the
+ ** following three categories it falls into:
+ **
+ ** Read-only
+ ** Query with statement journal
+ ** Query without statement journal
+ **
+ ** We could do something more elegant than this static analysis (i.e.
+ ** store the type of query as part of the compliation phase), but
+ ** handling malloc() or IO failure is a fairly obscure edge case so
+ ** this is probably easier. Todo: Might be an opportunity to reduce
+ ** code size a very small amount though...
*/
- int rc = vdbeCommit(db);
- if( rc==SQLITE_BUSY ){
- return SQLITE_BUSY;
- }else if( rc!=SQLITE_OK ){
- p->rc = rc;
- xFunc = sqlite3BtreeRollback;
+ int isReadOnly = 1;
+ int isStatement = 0;
+ assert(p->aOp || p->nOp==0);
+ for(i=0; i<p->nOp; i++){
+ switch( p->aOp[i].opcode ){
+ case OP_Transaction:
+ isReadOnly = 0;
+ break;
+ case OP_Statement:
+ isStatement = 1;
+ break;
+ }
+ }
+
+ /* If the query was read-only, we need do no rollback at all. Otherwise,
+ ** proceed with the special handling.
+ */
+ if( !isReadOnly ){
+ if( p->rc==SQLITE_NOMEM && isStatement ){
+ xFunc = sqlite3BtreeRollbackStmt;
+ }else{
+ /* We are forced to roll back the active transaction. Before doing
+ ** so, abort any other statements this handle currently has active.
+ */
+ sqlite3AbortOtherActiveVdbes(db, p);
+ sqlite3RollbackAll(db);
+ db->autoCommit = 1;
+ }
}
- }else{
- xFunc = sqlite3BtreeRollback;
}
- }else{
- if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
- xFunc = sqlite3BtreeCommitStmt;
- }else if( p->errorAction==OE_Abort ){
- xFunc = sqlite3BtreeRollbackStmt;
- }else{
- xFunc = sqlite3BtreeRollback;
- db->autoCommit = 1;
- abortOtherActiveVdbes(p);
+
+ /* If the auto-commit flag is set and this is the only active vdbe, then
+ ** we do either a commit or rollback of the current transaction.
+ **
+ ** Note: This block also runs if one of the special errors handled
+ ** above has occured.
+ */
+ if( db->autoCommit && db->activeVdbeCnt==1 ){
+ if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
+ /* The auto-commit flag is true, and the vdbe program was
+ ** successful or hit an 'OR FAIL' constraint. This means a commit
+ ** is required.
+ */
+ int rc = vdbeCommit(db);
+ if( rc==SQLITE_BUSY ){
+ return SQLITE_BUSY;
+ }else if( rc!=SQLITE_OK ){
+ p->rc = rc;
+ sqlite3RollbackAll(db);
+ }else{
+ sqlite3CommitInternalChanges(db);
+ }
+ }else{
+ sqlite3RollbackAll(db);
+ }
+ }else if( !xFunc ){
+ if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
+ xFunc = sqlite3BtreeCommitStmt;
+ }else if( p->errorAction==OE_Abort ){
+ xFunc = sqlite3BtreeRollbackStmt;
+ }else{
+ sqlite3AbortOtherActiveVdbes(db, p);
+ sqlite3RollbackAll(db);
+ db->autoCommit = 1;
+ }
}
- }
-
- /* If xFunc is not NULL, then it is one of sqlite3BtreeRollback,
- ** sqlite3BtreeRollbackStmt or sqlite3BtreeCommitStmt. Call it once on
- ** each backend. If an error occurs and the return code is still
- ** SQLITE_OK, set the return code to the new error value.
- */
- for(i=0; xFunc && i<db->nDb; i++){
- int rc;
- Btree *pBt = db->aDb[i].pBt;
- if( pBt ){
- rc = xFunc(pBt);
- if( p->rc==SQLITE_OK ) p->rc = rc;
+
+ /* If xFunc is not NULL, then it is one of sqlite3BtreeRollbackStmt or
+ ** sqlite3BtreeCommitStmt. Call it once on each backend. If an error occurs
+ ** and the return code is still SQLITE_OK, set the return code to the new
+ ** error value.
+ */
+ assert(!xFunc ||
+ xFunc==sqlite3BtreeCommitStmt ||
+ xFunc==sqlite3BtreeRollbackStmt
+ );
+ for(i=0; xFunc && i<db->nDb; i++){
+ int rc;
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ rc = xFunc(pBt);
+ if( rc && (p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT) ){
+ p->rc = rc;
+ sqlite3SetString(&p->zErrMsg, 0);
+ }
+ }
}
- }
-
- /* If this was an INSERT, UPDATE or DELETE, set the change counter. */
- if( p->changeCntOn && p->pc>=0 ){
- if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){
- sqlite3VdbeSetChanges(db, p->nChange);
- }else{
- sqlite3VdbeSetChanges(db, 0);
+
+ /* If this was an INSERT, UPDATE or DELETE and the statement was committed,
+ ** set the change counter.
+ */
+ if( p->changeCntOn && p->pc>=0 ){
+ if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){
+ sqlite3VdbeSetChanges(db, p->nChange);
+ }else{
+ sqlite3VdbeSetChanges(db, 0);
+ }
+ p->nChange = 0;
+ }
+
+ /* Rollback or commit any schema changes that occurred. */
+ if( p->rc!=SQLITE_OK && db->flags&SQLITE_InternChanges ){
+ sqlite3ResetInternalSchema(db, 0);
+ db->flags = (db->flags | SQLITE_InternChanges);
}
- p->nChange = 0;
- }
-
- /* Rollback or commit any schema changes that occurred. */
- if( p->rc!=SQLITE_OK ){
- sqlite3RollbackInternalChanges(db);
- }else if( db->flags & SQLITE_InternChanges ){
- sqlite3CommitInternalChanges(db);
}
/* We have successfully halted and closed the VM. Record this fact. */
@@ -1246,7 +1442,9 @@ int sqlite3VdbeReset(Vdbe *p){
** error, then it might not have been halted properly. So halt
** it now.
*/
+ sqlite3SafetyOn(p->db);
sqlite3VdbeHalt(p);
+ sqlite3SafetyOff(p->db);
/* 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
@@ -1255,8 +1453,9 @@ int sqlite3VdbeReset(Vdbe *p){
*/
if( p->pc>=0 ){
if( p->zErrMsg ){
- sqlite3Error(p->db, p->rc, "%s", p->zErrMsg);
- sqliteFree(p->zErrMsg);
+ sqlite3* db = p->db;
+ sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, sqlite3FreeX);
+ db->errCode = p->rc;
p->zErrMsg = 0;
}else if( p->rc ){
sqlite3Error(p->db, p->rc, 0);
@@ -1277,7 +1476,7 @@ int sqlite3VdbeReset(Vdbe *p){
/* Save profiling information from this VDBE run.
*/
- assert( p->pTos<&p->aStack[p->pc<0?0:p->pc] || sqlite3_malloc_failed==1 );
+ assert( p->pTos<&p->aStack[p->pc<0?0:p->pc] || !p->aStack );
#ifdef VDBE_PROFILE
{
FILE *out = fopen("vdbe_profile.out", "a");
@@ -1314,7 +1513,6 @@ int sqlite3VdbeReset(Vdbe *p){
*/
int sqlite3VdbeFinalize(Vdbe *p){
int rc = SQLITE_OK;
-
if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){
rc = sqlite3VdbeReset(p);
}else if( p->magic!=VDBE_MAGIC_INIT ){
@@ -1369,7 +1567,7 @@ void sqlite3VdbeDelete(Vdbe *p){
releaseMemArray(p->aVar, p->nVar);
sqliteFree(p->aLabel);
sqliteFree(p->aStack);
- releaseMemArray(p->aColName, p->nResColumn*2);
+ releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
sqliteFree(p->aColName);
p->magic = VDBE_MAGIC_DEAD;
sqliteFree(p);
@@ -1399,9 +1597,11 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
rc = sqlite3BtreeNext(p->pCursor, &res);
if( rc ) return rc;
}
+#ifdef SQLITE_TEST
sqlite3_search_count++;
+#endif
p->deferredMoveto = 0;
- p->cacheValid = 0;
+ p->cacheStatus = CACHE_STALE;
}
return SQLITE_OK;
}
@@ -1438,16 +1638,20 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
** 5 6 signed integer
** 6 8 signed integer
** 7 8 IEEE float
-** 8-11 reserved for expansion
+** 8 0 Integer constant 0
+** 9 0 Integer constant 1
+** 10,11 reserved for expansion
** N>=12 and even (N-12)/2 BLOB
** N>=13 and odd (N-13)/2 text
**
+** The 8 and 9 types were added in 3.3.0, file format 4. Prior versions
+** of SQLite will not understand those serial types.
*/
/*
** Return the serial-type for the value stored in pMem.
*/
-u32 sqlite3VdbeSerialType(Mem *pMem){
+u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
int flags = pMem->flags;
if( flags&MEM_Null ){
@@ -1457,7 +1661,11 @@ u32 sqlite3VdbeSerialType(Mem *pMem){
/* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
# define MAX_6BYTE ((((i64)0x00001000)<<32)-1)
i64 i = pMem->i;
- u64 u = i<0 ? -i : i;
+ u64 u;
+ if( file_format>=4 && (i&1)==i ){
+ return 8+i;
+ }
+ u = i<0 ? -i : i;
if( u<=127 ) return 1;
if( u<=32767 ) return 2;
if( u<=8388607 ) return 3;
@@ -1496,17 +1704,12 @@ int sqlite3VdbeSerialTypeLen(u32 serial_type){
** buf. It is assumed that the caller has allocated sufficient space.
** Return the number of bytes written.
*/
-int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem){
- u32 serial_type = sqlite3VdbeSerialType(pMem);
+int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem, int file_format){
+ u32 serial_type = sqlite3VdbeSerialType(pMem, file_format);
int len;
- /* NULL */
- if( serial_type==0 ){
- return 0;
- }
-
/* Integer and Real */
- if( serial_type<=7 ){
+ if( serial_type<=7 && serial_type>0 ){
u64 v;
int i;
if( serial_type==7 ){
@@ -1521,12 +1724,16 @@ int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem){
}
return len;
}
-
+
/* String or blob */
- assert( serial_type>=12 );
- len = sqlite3VdbeSerialTypeLen(serial_type);
- memcpy(buf, pMem->z, len);
- return len;
+ if( serial_type>=12 ){
+ len = sqlite3VdbeSerialTypeLen(serial_type);
+ memcpy(buf, pMem->z, len);
+ return len;
+ }
+
+ /* NULL or constants 0 or 1 */
+ return 0;
}
/*
@@ -1539,8 +1746,6 @@ int sqlite3VdbeSerialGet(
Mem *pMem /* Memory cell to write value into */
){
switch( serial_type ){
- case 8: /* Reserved for future use */
- case 9: /* Reserved for future use */
case 10: /* Reserved for future use */
case 11: /* Reserved for future use */
case 0: { /* NULL */
@@ -1579,7 +1784,7 @@ int sqlite3VdbeSerialGet(
case 7: { /* IEEE floating point */
u64 x;
u32 y;
-#ifndef NDEBUG
+#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT)
/* Verify that integers and floating point values use the same
** byte order. The byte order differs on some (broken) architectures.
*/
@@ -1599,6 +1804,12 @@ int sqlite3VdbeSerialGet(
}
return 8;
}
+ case 8: /* Integer 0 */
+ case 9: { /* Integer 1 */
+ pMem->i = serial_type-8;
+ pMem->flags = MEM_Int;
+ return 0;
+ }
default: {
int len = (serial_type-12)/2;
pMem->z = (char *)buf;
@@ -1616,6 +1827,23 @@ int sqlite3VdbeSerialGet(
}
/*
+** The header of a record consists of a sequence variable-length integers.
+** These integers are almost always small and are encoded as a single byte.
+** The following macro takes advantage this fact to provide a fast decode
+** of the integers in a record header. It is faster for the common case
+** where the integer is a single byte. It is a little slower when the
+** integer is two or more bytes. But overall it is faster.
+**
+** The following expressions are equivalent:
+**
+** x = sqlite3GetVarint32( A, &B );
+**
+** x = GetVarint( A, B );
+**
+*/
+#define GetVarint(A,B) ((B = *(A))<=0x7f ? 1 : sqlite3GetVarint32(A, &B))
+
+/*
** This function compares the two table rows or index records specified by
** {nKey1, pKey1} and {nKey2, pKey2}, returning a negative, zero
** or positive integer if {nKey1, pKey1} is less than, equal to or
@@ -1642,9 +1870,9 @@ int sqlite3VdbeRecordCompare(
mem1.enc = pKeyInfo->enc;
mem2.enc = pKeyInfo->enc;
- idx1 = sqlite3GetVarint32(pKey1, &szHdr1);
+ idx1 = GetVarint(aKey1, szHdr1);
d1 = szHdr1;
- idx2 = sqlite3GetVarint32(pKey2, &szHdr2);
+ idx2 = GetVarint(aKey2, szHdr2);
d2 = szHdr2;
nField = pKeyInfo->nField;
while( idx1<szHdr1 && idx2<szHdr2 ){
@@ -1652,9 +1880,9 @@ int sqlite3VdbeRecordCompare(
u32 serial_type2;
/* Read the serial types for the next element in each key. */
- idx1 += sqlite3GetVarint32(&aKey1[idx1], &serial_type1);
+ idx1 += GetVarint( aKey1+idx1, serial_type1 );
if( d1>=nKey1 && sqlite3VdbeSerialTypeLen(serial_type1)>0 ) break;
- idx2 += sqlite3GetVarint32(&aKey2[idx2], &serial_type2);
+ idx2 += GetVarint( aKey2+idx2, serial_type2 );
if( d2>=nKey2 && sqlite3VdbeSerialTypeLen(serial_type2)>0 ) break;
/* Assert that there is enough space left in each key for the blob of
@@ -1686,9 +1914,8 @@ int sqlite3VdbeRecordCompare(
}else if( d2<nKey2 ){
rc = -1;
}
- }
-
- if( pKeyInfo->aSortOrder && i<pKeyInfo->nField && pKeyInfo->aSortOrder[i] ){
+ }else if( pKeyInfo->aSortOrder && i<pKeyInfo->nField
+ && pKeyInfo->aSortOrder[i] ){
rc = -rc;
}
@@ -1701,7 +1928,7 @@ int sqlite3VdbeRecordCompare(
** an integer rowid). This routine returns the number of bytes in
** that integer.
*/
-int sqlite3VdbeIdxRowidLen(int nKey, const u8 *aKey){
+int sqlite3VdbeIdxRowidLen(const u8 *aKey){
u32 szHdr; /* Size of the header */
u32 typeRowid; /* Serial type of the rowid */
@@ -1732,10 +1959,10 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
if( rc ){
return rc;
}
- sqlite3GetVarint32(m.z, &szHdr);
- sqlite3GetVarint32(&m.z[szHdr-1], &typeRowid);
+ sqlite3GetVarint32((u8*)m.z, &szHdr);
+ sqlite3GetVarint32((u8*)&m.z[szHdr-1], &typeRowid);
lenRowid = sqlite3VdbeSerialTypeLen(typeRowid);
- sqlite3VdbeSerialGet(&m.z[m.n-lenRowid], typeRowid, &v);
+ sqlite3VdbeSerialGet((u8*)&m.z[m.n-lenRowid], typeRowid, &v);
*rowid = v.i;
sqlite3VdbeMemRelease(&m);
return SQLITE_OK;
@@ -1771,7 +1998,7 @@ int sqlite3VdbeIdxKeyCompare(
if( rc ){
return rc;
}
- lenRowid = sqlite3VdbeIdxRowidLen(m.n, m.z);
+ lenRowid = sqlite3VdbeIdxRowidLen((u8*)m.z);
*res = sqlite3VdbeRecordCompare(pC->pKeyInfo, m.n-lenRowid, m.z, nKey, pKey);
sqlite3VdbeMemRelease(&m);
return SQLITE_OK;
diff --git a/ext/pdo_sqlite/sqlite/src/vdbemem.c b/ext/pdo_sqlite/sqlite/src/vdbemem.c
index 0b7e193bec..51cd6827fa 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbemem.c
+++ b/ext/pdo_sqlite/sqlite/src/vdbemem.c
@@ -41,11 +41,22 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
#ifdef SQLITE_OMIT_UTF16
return SQLITE_ERROR;
#else
+
+
+ /* MemTranslate() may return SQLITE_OK or SQLITE_NOMEM. If NOMEM is returned,
+ ** then the encoding of the value may not have changed.
+ */
rc = sqlite3VdbeMemTranslate(pMem, desiredEnc);
+ assert(rc==SQLITE_OK || rc==SQLITE_NOMEM);
+ assert(rc==SQLITE_OK || pMem->enc!=desiredEnc);
+ assert(rc==SQLITE_NOMEM || pMem->enc==desiredEnc);
+
if( rc==SQLITE_NOMEM ){
+/*
sqlite3VdbeMemRelease(pMem);
pMem->flags = MEM_Null;
pMem->z = 0;
+*/
}
return rc;
#endif
@@ -73,7 +84,7 @@ int sqlite3VdbeMemDynamicify(Mem *pMem){
memcpy(z, pMem->z, n );
z[n] = 0;
z[n+1] = 0;
- pMem->z = z;
+ pMem->z = (char*)z;
pMem->flags &= ~(MEM_Ephem|MEM_Static|MEM_Short);
return SQLITE_OK;
}
@@ -93,7 +104,7 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
assert( (pMem->flags & MEM_Dyn)==0 );
assert( pMem->flags & (MEM_Str|MEM_Blob) );
if( (n = pMem->n)+2<sizeof(pMem->zShort) ){
- z = pMem->zShort;
+ z = (u8*)pMem->zShort;
pMem->flags |= MEM_Short|MEM_Term;
}else{
z = sqliteMallocRaw( n+2 );
@@ -106,8 +117,9 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
memcpy(z, pMem->z, n );
z[n] = 0;
z[n+1] = 0;
- pMem->z = z;
+ pMem->z = (char*)z;
pMem->flags &= ~(MEM_Ephem|MEM_Static);
+ assert(0==(1&(int)pMem->z));
return SQLITE_OK;
}
@@ -162,7 +174,7 @@ int sqlite3VdbeMemNulTerminate(Mem *pMem){
int sqlite3VdbeMemStringify(Mem *pMem, int enc){
int rc = SQLITE_OK;
int fg = pMem->flags;
- u8 *z = pMem->zShort;
+ char *z = pMem->zShort;
assert( !(fg&(MEM_Str|MEM_Blob)) );
assert( fg&(MEM_Int|MEM_Real) );
@@ -173,11 +185,11 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
**
** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16.
*/
- if( fg & MEM_Real ){
- sqlite3_snprintf(NBFS, z, "%!.15g", pMem->r);
- }else{
- assert( fg & MEM_Int );
+ if( fg & MEM_Int ){
sqlite3_snprintf(NBFS, z, "%lld", pMem->i);
+ }else{
+ assert( fg & MEM_Real );
+ sqlite3_snprintf(NBFS, z, "%!.15g", pMem->r);
}
pMem->n = strlen(z);
pMem->z = z;
@@ -191,8 +203,12 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
** Memory cell pMem contains the context of an aggregate function.
** This routine calls the finalize method for that function. The
** result of the aggregate is stored back into pMem.
+**
+** Return SQLITE_ERROR if the finalizer reports an error. SQLITE_OK
+** otherwise.
*/
-void sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
+int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
+ int rc = SQLITE_OK;
if( pFunc && pFunc->xFinalize ){
sqlite3_context ctx;
assert( (pMem->flags & MEM_Null)!=0 || pFunc==*(FuncDef**)&pMem->i );
@@ -200,6 +216,7 @@ void sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
ctx.s.z = pMem->zShort;
ctx.pMem = pMem;
ctx.pFunc = pFunc;
+ ctx.isError = 0;
pFunc->xFinalize(&ctx);
if( pMem->z && pMem->z!=pMem->zShort ){
sqliteFree( pMem->z );
@@ -208,7 +225,11 @@ void sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
if( pMem->flags & MEM_Short ){
pMem->z = pMem->zShort;
}
+ if( ctx.isError ){
+ rc = SQLITE_ERROR;
+ }
}
+ return rc;
}
/*
@@ -254,7 +275,7 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
i64 value;
if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
|| sqlite3VdbeMemNulTerminate(pMem) ){
- return SQLITE_NOMEM;
+ return 0;
}
assert( pMem->z );
sqlite3atoi64(pMem->z, &value);
@@ -265,16 +286,6 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
}
/*
-** Convert pMem to type integer. Invalidate any prior representations.
-*/
-int sqlite3VdbeMemIntegerify(Mem *pMem){
- pMem->i = sqlite3VdbeIntValue(pMem);
- sqlite3VdbeMemRelease(pMem);
- pMem->flags = MEM_Int;
- return SQLITE_OK;
-}
-
-/*
** Return the best representation of pMem that we can get into a
** double. If pMem is already a double or an integer, return its
** value. If it is a string or blob, try to convert it to a double.
@@ -289,7 +300,7 @@ double sqlite3VdbeRealValue(Mem *pMem){
double val = 0.0;
if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
|| sqlite3VdbeMemNulTerminate(pMem) ){
- return SQLITE_NOMEM;
+ return 0.0;
}
assert( pMem->z );
sqlite3AtoF(pMem->z, &val);
@@ -300,8 +311,30 @@ double sqlite3VdbeRealValue(Mem *pMem){
}
/*
-** Convert pMem so that it is of type MEM_Real. Invalidate any
-** prior representations.
+** The MEM structure is already a MEM_Real. Try to also make it a
+** MEM_Int if we can.
+*/
+void sqlite3VdbeIntegerAffinity(Mem *pMem){
+ assert( pMem->flags & MEM_Real );
+ pMem->i = pMem->r;
+ if( ((double)pMem->i)==pMem->r ){
+ pMem->flags |= MEM_Int;
+ }
+}
+
+/*
+** Convert pMem to type integer. Invalidate any prior representations.
+*/
+int sqlite3VdbeMemIntegerify(Mem *pMem){
+ pMem->i = sqlite3VdbeIntValue(pMem);
+ sqlite3VdbeMemRelease(pMem);
+ pMem->flags = MEM_Int;
+ return SQLITE_OK;
+}
+
+/*
+** Convert pMem so that it is of type MEM_Real.
+** Invalidate any prior representations.
*/
int sqlite3VdbeMemRealify(Mem *pMem){
pMem->r = sqlite3VdbeRealValue(pMem);
@@ -311,6 +344,16 @@ int sqlite3VdbeMemRealify(Mem *pMem){
}
/*
+** Convert pMem so that it has types MEM_Real or MEM_Int or both.
+** Invalidate any prior representations.
+*/
+int sqlite3VdbeMemNumerify(Mem *pMem){
+ sqlite3VdbeMemRealify(pMem);
+ sqlite3VdbeIntegerAffinity(pMem);
+ return SQLITE_OK;
+}
+
+/*
** Delete any previous value and set the value stored in *pMem to NULL.
*/
void sqlite3VdbeMemSetNull(Mem *pMem){
@@ -547,27 +590,33 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
assert( pMem1->enc==SQLITE_UTF8 ||
pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE );
- /* This assert may fail if the collation sequence is deleted after this
- ** vdbe program is compiled. The documentation defines this as an
- ** undefined condition. A crash is usual result.
+ /* The collation sequence must be defined at this point, even if
+ ** the user deletes the collation sequence after the vdbe program is
+ ** compiled (this was not always the case).
*/
assert( !pColl || pColl->xCmp );
if( pColl ){
if( pMem1->enc==pColl->enc ){
+ /* The strings are already in the correct encoding. Call the
+ ** comparison function directly */
return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z);
}else{
u8 origEnc = pMem1->enc;
- rc = pColl->xCmp(
- pColl->pUser,
- sqlite3ValueBytes((sqlite3_value*)pMem1, pColl->enc),
- sqlite3ValueText((sqlite3_value*)pMem1, pColl->enc),
- sqlite3ValueBytes((sqlite3_value*)pMem2, pColl->enc),
- sqlite3ValueText((sqlite3_value*)pMem2, pColl->enc)
- );
- sqlite3ValueBytes((sqlite3_value*)pMem1, origEnc);
+ const void *v1, *v2;
+ int n1, n2;
+ /* Convert the strings into the encoding that the comparison
+ ** function expects */
+ v1 = sqlite3ValueText((sqlite3_value*)pMem1, pColl->enc);
+ n1 = v1==0 ? 0 : pMem1->n;
+ assert( n1==sqlite3ValueBytes((sqlite3_value*)pMem1, pColl->enc) );
+ v2 = sqlite3ValueText((sqlite3_value*)pMem2, pColl->enc);
+ n2 = v2==0 ? 0 : pMem2->n;
+ assert( n2==sqlite3ValueBytes((sqlite3_value*)pMem2, pColl->enc) );
+ /* Do the comparison */
+ rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
+ /* Convert the strings back into the database encoding */
sqlite3ValueText((sqlite3_value*)pMem1, origEnc);
- sqlite3ValueBytes((sqlite3_value*)pMem2, origEnc);
sqlite3ValueText((sqlite3_value*)pMem2, origEnc);
return rc;
}
@@ -662,7 +711,7 @@ int sqlite3VdbeMemFromBtree(
** Perform various checks on the memory cell pMem. An assert() will
** fail if pMem is internally inconsistent.
*/
-void sqlite3VdbeMemSanity(Mem *pMem, u8 db_enc){
+void sqlite3VdbeMemSanity(Mem *pMem){
int flags = pMem->flags;
assert( flags!=0 ); /* Must define some type */
if( pMem->flags & (MEM_Str|MEM_Blob) ){
@@ -711,20 +760,38 @@ void sqlite3VdbeMemSanity(Mem *pMem, u8 db_enc){
** except the data returned is in the encoding specified by the second
** parameter, which must be one of SQLITE_UTF16BE, SQLITE_UTF16LE or
** SQLITE_UTF8.
+**
+** (2006-02-16:) The enc value can be or-ed with SQLITE_UTF16_ALIGNED.
+** If that is the case, then the result must be aligned on an even byte
+** boundary.
*/
const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
if( !pVal ) return 0;
- assert( enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE || enc==SQLITE_UTF8);
+ assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) );
if( pVal->flags&MEM_Null ){
return 0;
}
+ assert( (MEM_Blob>>3) == MEM_Str );
+ pVal->flags |= (pVal->flags & MEM_Blob)>>3;
if( pVal->flags&MEM_Str ){
- sqlite3VdbeChangeEncoding(pVal, enc);
+ sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED);
+ if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&(int)pVal->z) ){
+ assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 );
+ if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){
+ return 0;
+ }
+ }
}else if( !(pVal->flags&MEM_Blob) ){
sqlite3VdbeMemStringify(pVal, enc);
+ assert( 0==(1&(int)pVal->z) );
+ }
+ assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || sqlite3MallocFailed() );
+ if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){
+ return pVal->z;
+ }else{
+ return 0;
}
- return (const void *)(pVal->z);
}
/*
@@ -766,7 +833,7 @@ int sqlite3ValueFromExpr(
op = pExpr->op;
if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
- zVal = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
+ zVal = sqliteStrNDup((char*)pExpr->token.z, pExpr->token.n);
pVal = sqlite3ValueNew();
if( !zVal || !pVal ) goto no_mem;
sqlite3Dequote(zVal);
@@ -786,7 +853,7 @@ int sqlite3ValueFromExpr(
else if( op==TK_BLOB ){
int nVal;
pVal = sqlite3ValueNew();
- zVal = sqliteStrNDup(pExpr->token.z+1, pExpr->token.n-1);
+ zVal = sqliteStrNDup((char*)pExpr->token.z+1, pExpr->token.n-1);
if( !zVal || !pVal ) goto no_mem;
sqlite3Dequote(zVal);
nVal = strlen(zVal)/2;
diff --git a/ext/pdo_sqlite/sqlite/src/vtab.c b/ext/pdo_sqlite/sqlite/src/vtab.c
new file mode 100644
index 0000000000..e00a1ebc69
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/vtab.c
@@ -0,0 +1,659 @@
+/*
+** 2006 June 10
+**
+** 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 code used to help implement virtual tables.
+**
+** $Id$
+*/
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+#include "sqliteInt.h"
+
+/*
+** External API function used to create a new virtual-table module.
+*/
+int sqlite3_create_module(
+ sqlite3 *db, /* Database in which module is registered */
+ const char *zName, /* Name assigned to this module */
+ const sqlite3_module *pModule, /* The definition of the module */
+ void *pAux /* Context pointer for xCreate/xConnect */
+){
+ int nName = strlen(zName);
+ Module *pMod = (Module *)sqliteMallocRaw(sizeof(Module) + nName + 1);
+ if( pMod ){
+ char *zCopy = (char *)(&pMod[1]);
+ strcpy(zCopy, zName);
+ pMod->zName = zCopy;
+ pMod->pModule = pModule;
+ pMod->pAux = pAux;
+ pMod = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod);
+ sqliteFree(pMod);
+ sqlite3ResetInternalSchema(db, 0);
+ }
+ return sqlite3ApiExit(db, SQLITE_OK);
+}
+
+/*
+** Clear any and all virtual-table information from the Table record.
+** This routine is called, for example, just before deleting the Table
+** record.
+*/
+void sqlite3VtabClear(Table *p){
+ sqlite3_vtab *pVtab = p->pVtab;
+ if( pVtab ){
+ assert( p->pMod && p->pMod->pModule );
+ pVtab->nRef--;
+ if( pVtab->nRef==0 ){
+ pVtab->pModule->xDisconnect(pVtab);
+ }
+ p->pVtab = 0;
+ }
+ if( p->azModuleArg ){
+ int i;
+ for(i=0; i<p->nModuleArg; i++){
+ sqliteFree(p->azModuleArg[i]);
+ }
+ sqliteFree(p->azModuleArg);
+ }
+}
+
+/*
+** Add a new module argument to pTable->azModuleArg[].
+** The string is not copied - the pointer is stored. The
+** string will be freed automatically when the table is
+** deleted.
+*/
+static void addModuleArgument(Table *pTable, char *zArg){
+ int i = pTable->nModuleArg++;
+ int nBytes = sizeof(char *)*(1+pTable->nModuleArg);
+ char **azModuleArg;
+ azModuleArg = sqliteRealloc(pTable->azModuleArg, nBytes);
+ if( azModuleArg==0 ){
+ int j;
+ for(j=0; j<i; j++){
+ sqliteFree(pTable->azModuleArg[j]);
+ }
+ sqliteFree(zArg);
+ sqliteFree(pTable->azModuleArg);
+ pTable->nModuleArg = 0;
+ }else{
+ azModuleArg[i] = zArg;
+ azModuleArg[i+1] = 0;
+ }
+ pTable->azModuleArg = azModuleArg;
+}
+
+/*
+** The parser calls this routine when it first sees a CREATE VIRTUAL TABLE
+** statement. The module name has been parsed, but the optional list
+** of parameters that follow the module name are still pending.
+*/
+void sqlite3VtabBeginParse(
+ Parse *pParse, /* Parsing context */
+ Token *pName1, /* Name of new table, or database name */
+ Token *pName2, /* Name of new table or NULL */
+ Token *pModuleName /* Name of the module for the virtual table */
+){
+ int iDb; /* The database the table is being created in */
+ Table *pTable; /* The new virtual table */
+
+ sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0);
+ pTable = pParse->pNewTable;
+ if( pTable==0 || pParse->nErr ) return;
+ assert( 0==pTable->pIndex );
+
+ iDb = sqlite3SchemaToIndex(pParse->db, pTable->pSchema);
+ assert( iDb>=0 );
+
+ pTable->isVirtual = 1;
+ pTable->nModuleArg = 0;
+ addModuleArgument(pTable, sqlite3NameFromToken(pModuleName));
+ addModuleArgument(pTable, sqlite3StrDup(pParse->db->aDb[iDb].zName));
+ addModuleArgument(pTable, sqlite3StrDup(pTable->zName));
+ pParse->sNameToken.n = pModuleName->z + pModuleName->n - pName1->z;
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ /* Creating a virtual table invokes the authorization callback twice.
+ ** The first invocation, to obtain permission to INSERT a row into the
+ ** sqlite_master table, has already been made by sqlite3StartTable().
+ ** The second call, to obtain permission to create the table, is made now.
+ */
+ if( pTable->azModuleArg ){
+ sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName,
+ pTable->azModuleArg[0], pParse->db->aDb[iDb].zName);
+ }
+#endif
+}
+
+/*
+** This routine takes the module argument that has been accumulating
+** in pParse->zArg[] and appends it to the list of arguments on the
+** virtual table currently under construction in pParse->pTable.
+*/
+static void addArgumentToVtab(Parse *pParse){
+ if( pParse->sArg.z && pParse->pNewTable ){
+ const char *z = pParse->sArg.z;
+ int n = pParse->sArg.n;
+ addModuleArgument(pParse->pNewTable, sqliteStrNDup(z, n));
+ }
+}
+
+/*
+** The parser calls this routine after the CREATE VIRTUAL TABLE statement
+** has been completely parsed.
+*/
+void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
+ Table *pTab; /* The table being constructed */
+ sqlite3 *db; /* The database connection */
+ char *zModule; /* The module name of the table: USING modulename */
+ Module *pMod = 0;
+
+ addArgumentToVtab(pParse);
+ pParse->sArg.z = 0;
+
+ /* Lookup the module name. */
+ pTab = pParse->pNewTable;
+ if( pTab==0 ) return;
+ db = pParse->db;
+ if( pTab->nModuleArg<1 ) return;
+ zModule = pTab->azModuleArg[0];
+ pMod = (Module *)sqlite3HashFind(&db->aModule, zModule, strlen(zModule));
+ pTab->pMod = pMod;
+
+ /* If the CREATE VIRTUAL TABLE statement is being entered for the
+ ** first time (in other words if the virtual table is actually being
+ ** created now instead of just being read out of sqlite_master) then
+ ** do additional initialization work and store the statement text
+ ** in the sqlite_master table.
+ */
+ if( !db->init.busy ){
+ char *zStmt;
+ char *zWhere;
+ int iDb;
+ Vdbe *v;
+
+ /* Compute the complete text of the CREATE VIRTUAL TABLE statement */
+ if( pEnd ){
+ pParse->sNameToken.n = pEnd->z - pParse->sNameToken.z + pEnd->n;
+ }
+ zStmt = sqlite3MPrintf("CREATE VIRTUAL TABLE %T", &pParse->sNameToken);
+
+ /* A slot for the record has already been allocated in the
+ ** SQLITE_MASTER table. We just need to update that slot with all
+ ** the information we've collected.
+ **
+ ** The top of the stack is the rootpage allocated by sqlite3StartTable().
+ ** This value is always 0 and is ignored, a virtual table does not have a
+ ** rootpage. The next entry on the stack is the rowid of the record
+ ** in the sqlite_master table.
+ */
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ sqlite3NestedParse(pParse,
+ "UPDATE %Q.%s "
+ "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
+ "WHERE rowid=#1",
+ db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
+ pTab->zName,
+ pTab->zName,
+ zStmt
+ );
+ sqliteFree(zStmt);
+ v = sqlite3GetVdbe(pParse);
+ sqlite3ChangeCookie(db, v, iDb);
+
+ sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
+ zWhere = sqlite3MPrintf("name='%q'", pTab->zName);
+ sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC);
+ sqlite3VdbeOp3(v, OP_VCreate, iDb, 0, pTab->zName, strlen(pTab->zName) + 1);
+ }
+
+ /* If we are rereading the sqlite_master table create the in-memory
+ ** record of the table. If the module has already been registered,
+ ** also call the xConnect method here.
+ */
+ else {
+ Table *pOld;
+ Schema *pSchema = pTab->pSchema;
+ const char *zName = pTab->zName;
+ int nName = strlen(zName) + 1;
+ pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab);
+ if( pOld ){
+ assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */
+ return;
+ }
+ pParse->pNewTable = 0;
+ }
+}
+
+/*
+** The parser calls this routine when it sees the first token
+** of an argument to the module name in a CREATE VIRTUAL TABLE statement.
+*/
+void sqlite3VtabArgInit(Parse *pParse){
+ addArgumentToVtab(pParse);
+ pParse->sArg.z = 0;
+ pParse->sArg.n = 0;
+}
+
+/*
+** The parser calls this routine for each token after the first token
+** in an argument to the module name in a CREATE VIRTUAL TABLE statement.
+*/
+void sqlite3VtabArgExtend(Parse *pParse, Token *p){
+ Token *pArg = &pParse->sArg;
+ if( pArg->z==0 ){
+ pArg->z = p->z;
+ pArg->n = p->n;
+ }else{
+ assert(pArg->z < p->z);
+ pArg->n = (p->z + p->n - pArg->z);
+ }
+}
+
+/*
+** Invoke a virtual table constructor (either xCreate or xConnect). The
+** pointer to the function to invoke is passed as the fourth parameter
+** to this procedure.
+*/
+static int vtabCallConstructor(
+ sqlite3 *db,
+ Table *pTab,
+ Module *pMod,
+ int (*xConstruct)(sqlite3*, void *, int, char **, sqlite3_vtab **),
+ char **pzErr
+){
+ int rc;
+ int rc2;
+ char **azArg = pTab->azModuleArg;
+ int nArg = pTab->nModuleArg;
+ char *zErr = sqlite3MPrintf("vtable constructor failed: %s", pTab->zName);
+
+ assert( !db->pVTab );
+ assert( xConstruct );
+
+ db->pVTab = pTab;
+ rc = sqlite3SafetyOff(db);
+ assert( rc==SQLITE_OK );
+ rc = xConstruct(db, pMod->pAux, nArg, azArg, &pTab->pVtab);
+ rc2 = sqlite3SafetyOn(db);
+ if( rc==SQLITE_OK && pTab->pVtab ){
+ pTab->pVtab->pModule = pMod->pModule;
+ pTab->pVtab->nRef = 1;
+ }
+
+ if( SQLITE_OK!=rc ){
+ *pzErr = zErr;
+ zErr = 0;
+ } else if( db->pVTab ){
+ const char *zFormat = "vtable constructor did not declare schema: %s";
+ *pzErr = sqlite3MPrintf(zFormat, pTab->zName);
+ rc = SQLITE_ERROR;
+ }
+ if( rc==SQLITE_OK ){
+ rc = rc2;
+ }
+ db->pVTab = 0;
+ sqliteFree(zErr);
+ return rc;
+}
+
+/*
+** This function is invoked by the parser to call the xConnect() method
+** of the virtual table pTab. If an error occurs, an error code is returned
+** and an error left in pParse.
+**
+** This call is a no-op if table pTab is not a virtual table.
+*/
+int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
+ Module *pMod;
+ const char *zModule;
+ int rc = SQLITE_OK;
+
+ if( !pTab || !pTab->isVirtual || pTab->pVtab ){
+ return SQLITE_OK;
+ }
+
+ pMod = pTab->pMod;
+ zModule = pTab->azModuleArg[0];
+ if( !pMod ){
+ const char *zModule = pTab->azModuleArg[0];
+ sqlite3ErrorMsg(pParse, "no such module: %s", zModule);
+ rc = SQLITE_ERROR;
+ } else {
+ char *zErr = 0;
+ sqlite3 *db = pParse->db;
+ rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr);
+ if( rc!=SQLITE_OK ){
+ sqlite3ErrorMsg(pParse, "%s", zErr);
+ }
+ sqliteFree(zErr);
+ }
+
+ return rc;
+}
+
+/*
+** Add the virtual table pVtab to the array sqlite3.aVTrans[].
+*/
+static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
+ const int ARRAY_INCR = 5;
+
+ /* Grow the sqlite3.aVTrans array if required */
+ if( (db->nVTrans%ARRAY_INCR)==0 ){
+ sqlite3_vtab **aVTrans;
+ int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR);
+ aVTrans = sqliteRealloc((void *)db->aVTrans, nBytes);
+ if( !aVTrans ){
+ return SQLITE_NOMEM;
+ }
+ memset(&aVTrans[db->nVTrans], 0, sizeof(sqlite3_vtab *)*ARRAY_INCR);
+ db->aVTrans = aVTrans;
+ }
+
+ /* Add pVtab to the end of sqlite3.aVTrans */
+ db->aVTrans[db->nVTrans++] = pVtab;
+ pVtab->nRef++;
+ return SQLITE_OK;
+}
+
+/*
+** This function is invoked by the vdbe to call the xCreate method
+** of the virtual table named zTab in database iDb.
+**
+** If an error occurs, *pzErr is set to point an an English language
+** description of the error and an SQLITE_XXX error code is returned.
+** In this case the caller must call sqliteFree() on *pzErr.
+*/
+int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
+ int rc = SQLITE_OK;
+ Table *pTab;
+ Module *pMod;
+ const char *zModule;
+
+ pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
+ assert(pTab && pTab->isVirtual && !pTab->pVtab);
+ pMod = pTab->pMod;
+ zModule = pTab->azModuleArg[0];
+
+ /* If the module has been registered and includes a Create method,
+ ** invoke it now. If the module has not been registered, return an
+ ** error. Otherwise, do nothing.
+ */
+ if( !pMod ){
+ *pzErr = sqlite3MPrintf("no such module: %s", zModule);
+ rc = SQLITE_ERROR;
+ }else{
+ rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr);
+ }
+
+ if( rc==SQLITE_OK && pTab->pVtab ){
+ rc = addToVTrans(db, pTab->pVtab);
+ }
+
+ return rc;
+}
+
+/*
+** This function is used to set the schema of a virtual table. It is only
+** valid to call this function from within the xCreate() or xConnect() of a
+** virtual table module.
+*/
+int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
+ Parse sParse;
+
+ int rc = SQLITE_OK;
+ Table *pTab = db->pVTab;
+ char *zErr = 0;
+
+ if( !pTab ){
+ sqlite3Error(db, SQLITE_MISUSE, 0);
+ return SQLITE_MISUSE;
+ }
+ assert(pTab->isVirtual && pTab->nCol==0 && pTab->aCol==0);
+
+ memset(&sParse, 0, sizeof(Parse));
+ sParse.declareVtab = 1;
+ sParse.db = db;
+
+ if(
+ SQLITE_OK == sqlite3RunParser(&sParse, zCreateTable, &zErr) &&
+ sParse.pNewTable &&
+ !sParse.pNewTable->pSelect &&
+ !sParse.pNewTable->isVirtual
+ ){
+ pTab->aCol = sParse.pNewTable->aCol;
+ pTab->nCol = sParse.pNewTable->nCol;
+ sParse.pNewTable->nCol = 0;
+ sParse.pNewTable->aCol = 0;
+ } else {
+ sqlite3Error(db, SQLITE_ERROR, zErr);
+ sqliteFree(zErr);
+ rc = SQLITE_ERROR;
+ }
+ sParse.declareVtab = 0;
+
+ sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
+ sqlite3DeleteTable(0, sParse.pNewTable);
+ sParse.pNewTable = 0;
+ db->pVTab = 0;
+
+ return rc;
+}
+
+/*
+** This function is invoked by the vdbe to call the xDestroy method
+** of the virtual table named zTab in database iDb. This occurs
+** when a DROP TABLE is mentioned.
+**
+** This call is a no-op if zTab is not a virtual table.
+*/
+int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab)
+{
+ int rc = SQLITE_OK;
+ Table *pTab;
+
+ pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
+ assert(pTab);
+ if( pTab->pVtab ){
+ int (*xDestroy)(sqlite3_vtab *pVTab) = pTab->pMod->pModule->xDestroy;
+ rc = sqlite3SafetyOff(db);
+ assert( rc==SQLITE_OK );
+ if( xDestroy ){
+ rc = xDestroy(pTab->pVtab);
+ }
+ sqlite3SafetyOn(db);
+ if( rc==SQLITE_OK ){
+ pTab->pVtab = 0;
+ }
+ }
+
+ return rc;
+}
+
+/*
+** This function invokes either the xRollback or xCommit method
+** of each of the virtual tables in the sqlite3.aVTrans array. The method
+** called is identified by the second argument, "offset", which is
+** the offset of the method to call in the sqlite3_module structure.
+**
+** The array is cleared after invoking the callbacks.
+*/
+static void callFinaliser(sqlite3 *db, int offset){
+ int i;
+ for(i=0; i<db->nVTrans && db->aVTrans[i]; i++){
+ sqlite3_vtab *pVtab = db->aVTrans[i];
+ int (*x)(sqlite3_vtab *);
+ x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset);
+ if( x ) x(pVtab);
+ pVtab->nRef--;
+ if( pVtab->nRef==0 ){
+ pVtab->pModule->xDisconnect(pVtab);
+ }
+ }
+ sqliteFree(db->aVTrans);
+ db->nVTrans = 0;
+ db->aVTrans = 0;
+}
+
+/*
+** If argument rc2 is not SQLITE_OK, then return it and do nothing.
+** Otherwise, invoke the xSync method of all virtual tables in the
+** sqlite3.aVTrans array. Return the error code for the first error
+** that occurs, or SQLITE_OK if all xSync operations are successful.
+*/
+int sqlite3VtabSync(sqlite3 *db, int rc2){
+ int i;
+ int rc = SQLITE_OK;
+ int rcsafety;
+ sqlite3_vtab **aVTrans = db->aVTrans;
+ if( rc2!=SQLITE_OK ) return rc2;
+
+ rc = sqlite3SafetyOff(db);
+ db->aVTrans = 0;
+ for(i=0; rc==SQLITE_OK && i<db->nVTrans && aVTrans[i]; i++){
+ sqlite3_vtab *pVtab = aVTrans[i];
+ int (*x)(sqlite3_vtab *);
+ x = pVtab->pModule->xSync;
+ if( x ){
+ rc = x(pVtab);
+ }
+ }
+ db->aVTrans = aVTrans;
+ rcsafety = sqlite3SafetyOn(db);
+
+ if( rc==SQLITE_OK ){
+ rc = rcsafety;
+ }
+ return rc;
+}
+
+/*
+** Invoke the xRollback method of all virtual tables in the
+** sqlite3.aVTrans array. Then clear the array itself.
+*/
+int sqlite3VtabRollback(sqlite3 *db){
+ callFinaliser(db, (int)(&((sqlite3_module *)0)->xRollback));
+ return SQLITE_OK;
+}
+
+/*
+** Invoke the xCommit method of all virtual tables in the
+** sqlite3.aVTrans array. Then clear the array itself.
+*/
+int sqlite3VtabCommit(sqlite3 *db){
+ callFinaliser(db, (int)(&((sqlite3_module *)0)->xCommit));
+ return SQLITE_OK;
+}
+
+/*
+** If the virtual table pVtab supports the transaction interface
+** (xBegin/xRollback/xCommit and optionally xSync) and a transaction is
+** not currently open, invoke the xBegin method now.
+**
+** If the xBegin call is successful, place the sqlite3_vtab pointer
+** in the sqlite3.aVTrans array.
+*/
+int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
+ int rc = SQLITE_OK;
+ const sqlite3_module *pModule;
+
+ /* Special case: If db->aVTrans is NULL and db->nVTrans is greater
+ ** than zero, then this function is being called from within a
+ ** virtual module xSync() callback. It is illegal to write to
+ ** virtual module tables in this case, so return SQLITE_LOCKED.
+ */
+ if( 0==db->aVTrans && db->nVTrans>0 ){
+ return SQLITE_LOCKED;
+ }
+ if( !pVtab ){
+ return SQLITE_OK;
+ }
+ pModule = pVtab->pModule;
+
+ if( pModule->xBegin ){
+ int i;
+
+
+ /* If pVtab is already in the aVTrans array, return early */
+ for(i=0; (i<db->nVTrans) && 0!=db->aVTrans[i]; i++){
+ if( db->aVTrans[i]==pVtab ){
+ return SQLITE_OK;
+ }
+ }
+
+ /* Invoke the xBegin method */
+ rc = pModule->xBegin(pVtab);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+
+ rc = addToVTrans(db, pVtab);
+ }
+ return rc;
+}
+
+/*
+** The first parameter (pDef) is a function implementation. The
+** second parameter (pExpr) is the first argument to this function.
+** If pExpr is a column in a virtual table, then let the virtual
+** table implementation have an opportunity to overload the function.
+**
+** This routine is used to allow virtual table implementations to
+** overload MATCH, LIKE, GLOB, and REGEXP operators.
+**
+** Return either the pDef argument (indicating no change) or a
+** new FuncDef structure that is marked as ephemeral using the
+** SQLITE_FUNC_EPHEM flag.
+*/
+FuncDef *sqlite3VtabOverloadFunction(
+ FuncDef *pDef, /* Function to possibly overload */
+ int nArg, /* Number of arguments to the function */
+ Expr *pExpr /* First argument to the function */
+){
+ Table *pTab;
+ sqlite3_vtab *pVtab;
+ sqlite3_module *pMod;
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
+ void *pArg;
+ FuncDef *pNew;
+
+ /* Check to see the left operand is a column in a virtual table */
+ if( pExpr==0 ) return pDef;
+ if( pExpr->op!=TK_COLUMN ) return pDef;
+ pTab = pExpr->pTab;
+ if( pTab==0 ) return pDef;
+ if( !pTab->isVirtual ) return pDef;
+ pVtab = pTab->pVtab;
+ assert( pVtab!=0 );
+ assert( pVtab->pModule!=0 );
+ pMod = (sqlite3_module *)pVtab->pModule;
+ if( pMod->xFindFunction==0 ) return pDef;
+
+ /* Call the xFuncFunction method on the virtual table implementation
+ ** to see if the implementation wants to overload this function */
+ if( pMod->xFindFunction(pVtab, nArg, pDef->zName, &xFunc, &pArg)==0 ){
+ return pDef;
+ }
+
+ /* Create a new ephemeral function definition for the overloaded
+ ** function */
+ pNew = sqliteMalloc( sizeof(*pNew) + strlen(pDef->zName) );
+ if( pNew==0 ){
+ return pDef;
+ }
+ *pNew = *pDef;
+ strcpy(pNew->zName, pDef->zName);
+ pNew->xFunc = xFunc;
+ pNew->pUserData = pArg;
+ pNew->flags |= SQLITE_FUNC_EPHEM;
+ return pNew;
+}
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
diff --git a/ext/pdo_sqlite/sqlite/src/where.c b/ext/pdo_sqlite/sqlite/src/where.c
index d057acd0fe..bdbac8112c 100644
--- a/ext/pdo_sqlite/sqlite/src/where.c
+++ b/ext/pdo_sqlite/sqlite/src/where.c
@@ -83,7 +83,7 @@ struct WhereTerm {
i16 iParent; /* Disable pWC->a[iParent] when this term disabled */
i16 leftCursor; /* Cursor number of X in "X <op> <expr>" */
i16 leftColumn; /* Column number of X in "X <op> <expr>" */
- u16 operator; /* A WO_xx value describing <op> */
+ u16 eOperator; /* A WO_xx value describing <op> */
u8 flags; /* Bit flags. See below */
u8 nChild; /* Number of children that must disable us */
WhereClause *pWC; /* The clause this term is part of */
@@ -156,6 +156,7 @@ struct ExprMaskSet {
#define WO_LE (WO_EQ<<(TK_LE-TK_EQ))
#define WO_GT (WO_EQ<<(TK_GT-TK_EQ))
#define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
+#define WO_MATCH 64
/*
** Value for flags returned by bestIndex()
@@ -171,6 +172,7 @@ struct ExprMaskSet {
#define WHERE_ORDERBY 0x1000 /* Output will appear in correct order */
#define WHERE_REVERSE 0x2000 /* Scan in reverse order */
#define WHERE_UNIQUE 0x4000 /* Selects no more than one row */
+#define WHERE_VIRTUALTABLE 0x8000 /* Use virtual-table processing */
/*
** Initialize a preallocated WhereClause structure.
@@ -418,13 +420,13 @@ static WhereTerm *findTerm(
if( pTerm->leftCursor==iCur
&& (pTerm->prereqRight & notReady)==0
&& pTerm->leftColumn==iColumn
- && (pTerm->operator & op)!=0
+ && (pTerm->eOperator & op)!=0
){
if( iCur>=0 && pIdx ){
Expr *pX = pTerm->pExpr;
CollSeq *pColl;
char idxaff;
- int k;
+ int j;
Parse *pParse = pWC->pParse;
idxaff = pIdx->pTable->aCol[iColumn].affinity;
@@ -438,9 +440,9 @@ static WhereTerm *findTerm(
pColl = pParse->db->pDfltColl;
}
}
- for(k=0; k<pIdx->nColumn && pIdx->aiColumn[k]!=iColumn; k++){}
- assert( k<pIdx->nColumn );
- if( pColl!=pIdx->keyInfo.aColl[k] ) continue;
+ for(j=0; j<pIdx->nColumn && pIdx->aiColumn[j]!=iColumn; j++){}
+ assert( j<pIdx->nColumn );
+ if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue;
}
return pTerm;
}
@@ -511,7 +513,7 @@ static int isLikeOrGlob(
return 0;
}
sqlite3DequoteExpr(pRight);
- z = pRight->token.z;
+ z = (char *)pRight->token.z;
for(cnt=0; (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2]; cnt++){}
if( cnt==0 || 255==(u8)z[cnt] ){
return 0;
@@ -522,6 +524,48 @@ static int isLikeOrGlob(
}
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/*
+** Check to see if the given expression is of the form
+**
+** column MATCH expr
+**
+** If it is then return TRUE. If not, return FALSE.
+*/
+static int isMatchOfColumn(
+ Expr *pExpr /* Test this expression */
+){
+ ExprList *pList;
+
+ if( pExpr->op!=TK_FUNCTION ){
+ return 0;
+ }
+ if( pExpr->token.n!=5 ||
+ sqlite3StrNICmp((const char*)pExpr->token.z,"match",5)!=0 ){
+ return 0;
+ }
+ pList = pExpr->pList;
+ if( pList->nExpr!=2 ){
+ return 0;
+ }
+ if( pList->a[1].pExpr->op != TK_COLUMN ){
+ return 0;
+ }
+ return 1;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+/*
+** If the pBase expression originated in the ON or USING clause of
+** a join, then transfer the appropriate markings over to derived.
+*/
+static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
+ pDerived->flags |= pBase->flags & EP_FromJoin;
+ pDerived->iRightJoinTable = pBase->iRightJoinTable;
+}
+
+
/*
** The input to this routine is an WhereTerm structure with only the
** "pExpr" field filled in. The job of this routine is to analyze the
@@ -547,7 +591,7 @@ static void exprAnalyze(
int nPattern;
int isComplete;
- if( sqlite3_malloc_failed ) return;
+ if( sqlite3MallocFailed() ) return;
prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
if( pExpr->op==TK_IN ){
assert( pExpr->pRight==0 );
@@ -563,14 +607,14 @@ static void exprAnalyze(
pTerm->prereqAll = prereqAll;
pTerm->leftCursor = -1;
pTerm->iParent = -1;
- pTerm->operator = 0;
+ pTerm->eOperator = 0;
if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){
Expr *pLeft = pExpr->pLeft;
Expr *pRight = pExpr->pRight;
if( pLeft->op==TK_COLUMN ){
pTerm->leftCursor = pLeft->iTable;
pTerm->leftColumn = pLeft->iColumn;
- pTerm->operator = operatorMask(pExpr->op);
+ pTerm->eOperator = operatorMask(pExpr->op);
}
if( pRight && pRight->op==TK_COLUMN ){
WhereTerm *pNew;
@@ -595,7 +639,7 @@ static void exprAnalyze(
pNew->leftColumn = pLeft->iColumn;
pNew->prereqRight = prereqLeft;
pNew->prereqAll = prereqAll;
- pNew->operator = operatorMask(pDup->op);
+ pNew->eOperator = operatorMask(pDup->op);
}
}
@@ -623,7 +667,7 @@ static void exprAnalyze(
}
#endif /* SQLITE_OMIT_BETWEEN_OPTIMIZATION */
-#ifndef SQLITE_OMIT_OR_OPTIMIZATION
+#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY)
/* Attempt to convert OR-connected terms into an IN operator so that
** they can make use of indices. Example:
**
@@ -632,6 +676,9 @@ static void exprAnalyze(
** is converted into
**
** x IN (expr1,expr2,expr3)
+ **
+ ** This optimization must be omitted if OMIT_SUBQUERY is defined because
+ ** the compiler for the the IN operator is part of sub-queries.
*/
else if( pExpr->op==TK_OR ){
int ok;
@@ -651,7 +698,7 @@ static void exprAnalyze(
iCursor = sOr.a[j].leftCursor;
ok = iCursor>=0;
for(i=sOr.nTerm-1, pOrTerm=sOr.a; i>=0 && ok; i--, pOrTerm++){
- if( pOrTerm->operator!=WO_EQ ){
+ if( pOrTerm->eOperator!=WO_EQ ){
goto or_not_possible;
}
if( pOrTerm->leftCursor==iCursor && pOrTerm->leftColumn==iColumn ){
@@ -680,14 +727,17 @@ static void exprAnalyze(
}
pNew = sqlite3Expr(TK_IN, pDup, 0, 0);
if( pNew ){
+ int idxNew;
+ transferJoinMarkings(pNew, pExpr);
pNew->pList = pList;
+ idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
+ exprAnalyze(pSrc, pMaskSet, pWC, idxNew);
+ pTerm = &pWC->a[idxTerm];
+ pWC->a[idxNew].iParent = idxTerm;
+ pTerm->nChild = 1;
}else{
sqlite3ExprListDelete(pList);
}
- pTerm->pExpr = pNew;
- pTerm->flags |= TERM_DYNAMIC;
- exprAnalyze(pSrc, pMaskSet, pWC, idxTerm);
- pTerm = &pWC->a[idxTerm];
}
or_not_possible:
whereClauseClear(&sOr);
@@ -730,6 +780,41 @@ or_not_possible:
}
}
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ /* Add a WO_MATCH auxiliary term to the constraint set if the
+ ** current expression is of the form: column MATCH expr.
+ ** This information is used by the xBestIndex methods of
+ ** virtual tables. The native query optimizer does not attempt
+ ** to do anything with MATCH functions.
+ */
+ if( isMatchOfColumn(pExpr) ){
+ int idxNew;
+ Expr *pRight, *pLeft;
+ WhereTerm *pNewTerm;
+ Bitmask prereqColumn, prereqExpr;
+
+ pRight = pExpr->pList->a[0].pExpr;
+ pLeft = pExpr->pList->a[1].pExpr;
+ prereqExpr = exprTableUsage(pMaskSet, pRight);
+ prereqColumn = exprTableUsage(pMaskSet, pLeft);
+ if( (prereqExpr & prereqColumn)==0 ){
+ Expr *pNewExpr;
+ pNewExpr = sqlite3Expr(TK_MATCH, 0, sqlite3ExprDup(pRight), 0);
+ idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
+ pNewTerm = &pWC->a[idxNew];
+ pNewTerm->prereqRight = prereqExpr;
+ pNewTerm->leftCursor = pLeft->iTable;
+ pNewTerm->leftColumn = pLeft->iColumn;
+ pNewTerm->eOperator = WO_MATCH;
+ pNewTerm->iParent = idxTerm;
+ pTerm = &pWC->a[idxTerm];
+ pTerm->nChild = 1;
+ pTerm->flags |= TERM_COPIED;
+ pNewTerm->prereqAll = pTerm->prereqAll;
+ }
+ }
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
}
@@ -755,14 +840,13 @@ or_not_possible:
static int isSortingIndex(
Parse *pParse, /* Parsing context */
Index *pIdx, /* The index we are testing */
- Table *pTab, /* The table to be sorted */
- int base, /* Cursor number for pTab */
+ int base, /* Cursor number for the table to be sorted */
ExprList *pOrderBy, /* The ORDER BY clause */
int nEqCol, /* Number of index columns with == constraints */
int *pbRev /* Set to 1 if ORDER BY is DESC */
){
int i, j; /* Loop counters */
- int sortOrder = SQLITE_SO_ASC; /* Which direction we are sorting */
+ int sortOrder = 0; /* XOR of index and ORDER BY sort direction */
int nTerm; /* Number of ORDER BY terms */
struct ExprList_item *pTerm; /* A term of the ORDER BY clause */
sqlite3 *db = pParse->db;
@@ -777,6 +861,7 @@ static int isSortingIndex(
for(i=j=0, pTerm=pOrderBy->a; j<nTerm && i<pIdx->nColumn; i++){
Expr *pExpr; /* The expression of the ORDER BY pTerm */
CollSeq *pColl; /* The collating sequence of pExpr */
+ int termSortOrder; /* Sort order for this term */
pExpr = pTerm->pExpr;
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){
@@ -786,7 +871,8 @@ static int isSortingIndex(
}
pColl = sqlite3ExprCollSeq(pParse, pExpr);
if( !pColl ) pColl = db->pDfltColl;
- if( pExpr->iColumn!=pIdx->aiColumn[i] || pColl!=pIdx->keyInfo.aColl[i] ){
+ if( pExpr->iColumn!=pIdx->aiColumn[i] ||
+ sqlite3StrICmp(pColl->zName, pIdx->azColl[i]) ){
/* Term j of the ORDER BY clause does not match column i of the index */
if( i<nEqCol ){
/* If an index column that is constrained by == fails to match an
@@ -800,14 +886,18 @@ static int isSortingIndex(
return 0;
}
}
+ assert( pIdx->aSortOrder!=0 );
+ assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 );
+ assert( pIdx->aSortOrder[i]==0 || pIdx->aSortOrder[i]==1 );
+ termSortOrder = pIdx->aSortOrder[i] ^ pTerm->sortOrder;
if( i>nEqCol ){
- if( pTerm->sortOrder!=sortOrder ){
+ if( termSortOrder!=sortOrder ){
/* Indices can only be used if all ORDER BY terms past the
** equality constraints are all either DESC or ASC. */
return 0;
}
}else{
- sortOrder = pTerm->sortOrder;
+ sortOrder = termSortOrder;
}
j++;
pTerm++;
@@ -817,7 +907,7 @@ static int isSortingIndex(
** are covered.
*/
if( j>=nTerm ){
- *pbRev = sortOrder==SQLITE_SO_DESC;
+ *pbRev = sortOrder!=0;
return 1;
}
return 0;
@@ -854,16 +944,257 @@ static int sortableByRowid(
** logN is a little off.
*/
static double estLog(double N){
- double logN = 1.0;
- double x = 10.0;
+ double logN = 1;
+ double x = 10;
while( N>x ){
- logN += 1.0;
+ logN += 1;
x *= 10;
}
return logN;
}
/*
+** Two routines for printing the content of an sqlite3_index_info
+** structure. Used for testing and debugging only. If neither
+** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines
+** are no-ops.
+*/
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && \
+ (defined(SQLITE_TEST) || defined(SQLITE_DEBUG))
+static void TRACE_IDX_INPUTS(sqlite3_index_info *p){
+ int i;
+ if( !sqlite3_where_trace ) return;
+ for(i=0; i<p->nConstraint; i++){
+ sqlite3DebugPrintf(" constraint[%d]: col=%d termid=%d op=%d usabled=%d\n",
+ i,
+ p->aConstraint[i].iColumn,
+ p->aConstraint[i].iTermOffset,
+ p->aConstraint[i].op,
+ p->aConstraint[i].usable);
+ }
+ for(i=0; i<p->nOrderBy; i++){
+ sqlite3DebugPrintf(" orderby[%d]: col=%d desc=%d\n",
+ i,
+ p->aOrderBy[i].iColumn,
+ p->aOrderBy[i].desc);
+ }
+}
+static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){
+ int i;
+ if( !sqlite3_where_trace ) return;
+ for(i=0; i<p->nConstraint; i++){
+ sqlite3DebugPrintf(" usage[%d]: argvIdx=%d omit=%d\n",
+ i,
+ p->aConstraintUsage[i].argvIndex,
+ p->aConstraintUsage[i].omit);
+ }
+ sqlite3DebugPrintf(" idxNum=%d\n", p->idxNum);
+ sqlite3DebugPrintf(" idxStr=%s\n", p->idxStr);
+ sqlite3DebugPrintf(" orderByConsumed=%d\n", p->orderByConsumed);
+ sqlite3DebugPrintf(" estimatedCost=%g\n", p->estimatedCost);
+}
+#else
+#define TRACE_IDX_INPUTS(A)
+#define TRACE_IDX_OUTPUTS(A)
+#endif
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/*
+** Compute the best index for a virtual table.
+**
+** The best index is computed by the xBestIndex method of the virtual
+** table module. This routine is really just a wrapper that sets up
+** the sqlite3_index_info structure that is used to communicate with
+** xBestIndex.
+**
+** In a join, this routine might be called multiple times for the
+** same virtual table. The sqlite3_index_info structure is created
+** and initialized on the first invocation and reused on all subsequent
+** invocations. The sqlite3_index_info structure is also used when
+** code is generated to access the virtual table. The whereInfoDelete()
+** routine takes care of freeing the sqlite3_index_info structure after
+** everybody has finished with it.
+*/
+static double bestVirtualIndex(
+ Parse *pParse, /* The parsing context */
+ WhereClause *pWC, /* The WHERE clause */
+ struct SrcList_item *pSrc, /* The FROM clause term to search */
+ Bitmask notReady, /* Mask of cursors that are not available */
+ ExprList *pOrderBy, /* The order by clause */
+ int orderByUsable, /* True if we can potential sort */
+ sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */
+){
+ Table *pTab = pSrc->pTab;
+ sqlite3_index_info *pIdxInfo;
+ struct sqlite3_index_constraint *pIdxCons;
+ struct sqlite3_index_orderby *pIdxOrderBy;
+ struct sqlite3_index_constraint_usage *pUsage;
+ WhereTerm *pTerm;
+ int i, j;
+ int nOrderBy;
+ int rc;
+
+ /* If the sqlite3_index_info structure has not been previously
+ ** allocated and initialized for this virtual table, then allocate
+ ** and initialize it now
+ */
+ pIdxInfo = *ppIdxInfo;
+ if( pIdxInfo==0 ){
+ WhereTerm *pTerm;
+ int nTerm;
+ TRACE(("Recomputing index info for %s...\n", pTab->zName));
+
+ /* Count the number of possible WHERE clause constraints referring
+ ** to this virtual table */
+ for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
+ if( pTerm->leftCursor != pSrc->iCursor ) continue;
+ if( pTerm->eOperator==WO_IN ) continue;
+ nTerm++;
+ }
+
+ /* If the ORDER BY clause contains only columns in the current
+ ** virtual table then allocate space for the aOrderBy part of
+ ** the sqlite3_index_info structure.
+ */
+ nOrderBy = 0;
+ if( pOrderBy ){
+ for(i=0; i<pOrderBy->nExpr; i++){
+ Expr *pExpr = pOrderBy->a[i].pExpr;
+ if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break;
+ }
+ if( i==pOrderBy->nExpr ){
+ nOrderBy = pOrderBy->nExpr;
+ }
+ }
+
+ /* Allocate the sqlite3_index_info structure
+ */
+ pIdxInfo = sqliteMalloc( sizeof(*pIdxInfo)
+ + (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
+ + sizeof(*pIdxOrderBy)*nOrderBy );
+ if( pIdxInfo==0 ){
+ sqlite3ErrorMsg(pParse, "out of memory");
+ return 0.0;
+ }
+ *ppIdxInfo = pIdxInfo;
+
+ /* Initialize the structure. The sqlite3_index_info structure contains
+ ** many fields that are declared "const" to prevent xBestIndex from
+ ** changing them. We have to do some funky casting in order to
+ ** initialize those fields.
+ */
+ pIdxCons = (struct sqlite3_index_constraint*)&pIdxInfo[1];
+ pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm];
+ pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy];
+ *(int*)&pIdxInfo->nConstraint = nTerm;
+ *(int*)&pIdxInfo->nOrderBy = nOrderBy;
+ *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint = pIdxCons;
+ *(struct sqlite3_index_orderby**)&pIdxInfo->aOrderBy = pIdxOrderBy;
+ *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage =
+ pUsage;
+
+ for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
+ if( pTerm->leftCursor != pSrc->iCursor ) continue;
+ if( pTerm->eOperator==WO_IN ) continue;
+ pIdxCons[j].iColumn = pTerm->leftColumn;
+ pIdxCons[j].iTermOffset = i;
+ pIdxCons[j].op = pTerm->eOperator;
+ /* The direct assignment in the previous line is possible only because
+ ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
+ ** following asserts verify this fact. */
+ assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
+ assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT );
+ assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE );
+ assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
+ assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
+ assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH );
+ assert( pTerm->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) );
+ j++;
+ }
+ for(i=0; i<nOrderBy; i++){
+ Expr *pExpr = pOrderBy->a[i].pExpr;
+ pIdxOrderBy[i].iColumn = pExpr->iColumn;
+ pIdxOrderBy[i].desc = pOrderBy->a[i].sortOrder;
+ }
+ }
+
+ /* At this point, the sqlite3_index_info structure that pIdxInfo points
+ ** to will have been initialized, either during the current invocation or
+ ** during some prior invocation. Now we just have to customize the
+ ** details of pIdxInfo for the current invocation and pass it to
+ ** xBestIndex.
+ */
+
+ /* The module name must be defined */
+ assert( pTab->azModuleArg && pTab->azModuleArg[0] );
+ if( pTab->pVtab==0 ){
+ sqlite3ErrorMsg(pParse, "undefined module %s for table %s",
+ pTab->azModuleArg[0], pTab->zName);
+ return 0.0;
+ }
+
+ /* Set the aConstraint[].usable fields and initialize all
+ ** output variables to zero.
+ **
+ ** aConstraint[].usable is true for constraints where the right-hand
+ ** side contains only references to tables to the left of the current
+ ** table. In other words, if the constraint is of the form:
+ **
+ ** column = expr
+ **
+ ** and we are evaluating a join, then the constraint on column is
+ ** only valid if all tables referenced in expr occur to the left
+ ** of the table containing column.
+ **
+ ** The aConstraints[] array contains entries for all constraints
+ ** on the current table. That way we only have to compute it once
+ ** even though we might try to pick the best index multiple times.
+ ** For each attempt at picking an index, the order of tables in the
+ ** join might be different so we have to recompute the usable flag
+ ** each time.
+ */
+ pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
+ pUsage = pIdxInfo->aConstraintUsage;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
+ j = pIdxCons->iTermOffset;
+ pTerm = &pWC->a[j];
+ pIdxCons->usable = (pTerm->prereqRight & notReady)==0;
+ }
+ memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
+ if( pIdxInfo->needToFreeIdxStr ){
+ sqlite3_free(pIdxInfo->idxStr);
+ }
+ pIdxInfo->idxStr = 0;
+ pIdxInfo->idxNum = 0;
+ pIdxInfo->needToFreeIdxStr = 0;
+ pIdxInfo->orderByConsumed = 0;
+ pIdxInfo->estimatedCost = SQLITE_BIG_DBL / 2.0;
+ nOrderBy = pIdxInfo->nOrderBy;
+ if( pIdxInfo->nOrderBy && !orderByUsable ){
+ *(int*)&pIdxInfo->nOrderBy = 0;
+ }
+
+ sqlite3SafetyOff(pParse->db);
+ TRACE(("xBestIndex for %s\n", pTab->zName));
+ TRACE_IDX_INPUTS(pIdxInfo);
+ rc = pTab->pVtab->pModule->xBestIndex(pTab->pVtab, pIdxInfo);
+ TRACE_IDX_OUTPUTS(pIdxInfo);
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_NOMEM ){
+ sqlite3FailedMalloc();
+ }else {
+ sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc));
+ }
+ sqlite3SafetyOn(pParse->db);
+ }else{
+ rc = sqlite3SafetyOn(pParse->db);
+ }
+ *(int*)&pIdxInfo->nOrderBy = nOrderBy;
+ return pIdxInfo->estimatedCost;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+/*
** Find the best index for accessing a particular table. Return a pointer
** to the index, flags that describe how the index should be used, the
** number of equality constraints, and the "cost" for this index.
@@ -893,7 +1224,7 @@ static double bestIndex(
){
WhereTerm *pTerm;
Index *bestIdx = 0; /* Index that gives the lowest cost */
- double lowestCost = 1.0e99; /* The cost of using bestIdx */
+ double lowestCost; /* The cost of using bestIdx */
int bestFlags = 0; /* Flags associated with bestIdx */
int bestNEq = 0; /* Best value for nEq */
int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */
@@ -904,6 +1235,23 @@ static double bestIndex(
double cost; /* Cost of using pProbe */
TRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady));
+ lowestCost = SQLITE_BIG_DBL;
+ pProbe = pSrc->pTab->pIndex;
+
+ /* If the table has no indices and there are no terms in the where
+ ** clause that refer to the ROWID, then we will never be able to do
+ ** anything other than a full table scan on this table. We might as
+ ** well put it first in the join order. That way, perhaps it can be
+ ** referenced by other tables in the join.
+ */
+ if( pProbe==0 &&
+ findTerm(pWC, iCur, -1, 0, WO_EQ|WO_IN|WO_LT|WO_LE|WO_GT|WO_GE,0)==0 &&
+ (pOrderBy==0 || !sortableByRowid(iCur, pOrderBy, &rev)) ){
+ *pFlags = 0;
+ *ppIndex = 0;
+ *pnEq = 0;
+ return 0.0;
+ }
/* Check for a rowid=EXPR or rowid IN (...) constraints
*/
@@ -912,7 +1260,7 @@ static double bestIndex(
Expr *pExpr;
*ppIndex = 0;
bestFlags = WHERE_ROWID_EQ;
- if( pTerm->operator & WO_EQ ){
+ if( pTerm->eOperator & WO_EQ ){
/* Rowid== is always the best pick. Look no further. Because only
** a single row is generated, output is always in sorted order */
*pFlags = WHERE_ROWID_EQ | WHERE_UNIQUE;
@@ -928,7 +1276,7 @@ static double bestIndex(
/* Rowid IN (SELECT): cost is NlogN where N is the number of rows
** in the result of the inner select. We have no way to estimate
** that value so make a wild guess. */
- lowestCost = 200.0;
+ lowestCost = 200;
}
TRACE(("... rowid IN cost: %.9g\n", lowestCost));
}
@@ -936,8 +1284,7 @@ static double bestIndex(
/* Estimate the cost of a table scan. If we do not know how many
** entries are in the table, use 1 million as a guess.
*/
- pProbe = pSrc->pTab->pIndex;
- cost = pProbe ? pProbe->aiRowEst[0] : 1000000.0;
+ cost = pProbe ? pProbe->aiRowEst[0] : 1000000;
TRACE(("... table scan base cost: %.9g\n", cost));
flags = WHERE_ROWID_RANGE;
@@ -947,11 +1294,11 @@ static double bestIndex(
if( pTerm ){
if( findTerm(pWC, iCur, -1, notReady, WO_LT|WO_LE, 0) ){
flags |= WHERE_TOP_LIMIT;
- cost *= 0.333; /* Guess that rowid<EXPR eliminates two-thirds or rows */
+ cost /= 3; /* Guess that rowid<EXPR eliminates two-thirds or rows */
}
if( findTerm(pWC, iCur, -1, notReady, WO_GT|WO_GE, 0) ){
flags |= WHERE_BTM_LIMIT;
- cost *= 0.333; /* Guess that rowid>EXPR eliminates two-thirds of rows */
+ cost /= 3; /* Guess that rowid>EXPR eliminates two-thirds of rows */
}
TRACE(("... rowid range reduces cost to %.9g\n", cost));
}else{
@@ -980,7 +1327,7 @@ static double bestIndex(
*/
for(; pProbe; pProbe=pProbe->pNext){
int i; /* Loop counter */
- double inMultiplier = 1.0;
+ double inMultiplier = 1;
TRACE(("... index %s:\n", pProbe->zName));
@@ -993,13 +1340,13 @@ static double bestIndex(
pTerm = findTerm(pWC, iCur, j, notReady, WO_EQ|WO_IN, pProbe);
if( pTerm==0 ) break;
flags |= WHERE_COLUMN_EQ;
- if( pTerm->operator & WO_IN ){
+ if( pTerm->eOperator & WO_IN ){
Expr *pExpr = pTerm->pExpr;
flags |= WHERE_COLUMN_IN;
if( pExpr->pSelect!=0 ){
- inMultiplier *= 100.0;
+ inMultiplier *= 25;
}else if( pExpr->pList!=0 ){
- inMultiplier *= pExpr->pList->nExpr + 1.0;
+ inMultiplier *= pExpr->pList->nExpr + 1;
}
}
}
@@ -1020,11 +1367,11 @@ static double bestIndex(
flags |= WHERE_COLUMN_RANGE;
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pProbe) ){
flags |= WHERE_TOP_LIMIT;
- cost *= 0.333;
+ cost /= 3;
}
if( findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pProbe) ){
flags |= WHERE_BTM_LIMIT;
- cost *= 0.333;
+ cost /= 3;
}
TRACE(("...... range reduces cost to %.9g\n", cost));
}
@@ -1034,7 +1381,7 @@ static double bestIndex(
*/
if( pOrderBy ){
if( (flags & WHERE_COLUMN_IN)==0 &&
- isSortingIndex(pParse,pProbe,pSrc->pTab,iCur,pOrderBy,nEq,&rev) ){
+ isSortingIndex(pParse,pProbe,iCur,pOrderBy,nEq,&rev) ){
if( flags==0 ){
flags = WHERE_COLUMN_RANGE;
}
@@ -1063,7 +1410,7 @@ static double bestIndex(
}
if( m==0 ){
flags |= WHERE_IDX_ONLY;
- cost *= 0.5;
+ cost /= 2;
TRACE(("...... idx-only reduces cost to %.9g\n", cost));
}
}
@@ -1134,14 +1481,24 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
** * Check the top nColumn entries on the stack. If any
** of those entries are NULL, jump immediately to brk,
** which is the loop exit, since no index entry will match
-** if any part of the key is NULL.
+** if any part of the key is NULL. Pop (nColumn+nExtra)
+** elements from the stack.
**
** * Construct a probe entry from the top nColumn entries in
-** the stack with affinities appropriate for index pIdx.
+** the stack with affinities appropriate for index pIdx.
+** Only nColumn elements are popped from the stack in this case
+** (by OP_MakeRecord).
+**
*/
-static void buildIndexProbe(Vdbe *v, int nColumn, int brk, Index *pIdx){
+static void buildIndexProbe(
+ Vdbe *v,
+ int nColumn,
+ int nExtra,
+ int brk,
+ Index *pIdx
+){
sqlite3VdbeAddOp(v, OP_NotNull, -nColumn, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0);
+ sqlite3VdbeAddOp(v, OP_Pop, nColumn+nExtra, 0);
sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
sqlite3IndexAffinityStr(v, pIdx);
@@ -1177,17 +1534,16 @@ static void codeEqualityTerm(
sqlite3CodeSubselect(pParse, pX);
iTab = pX->iTable;
- sqlite3VdbeAddOp(v, OP_Rewind, iTab, brk);
+ sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0);
VdbeComment((v, "# %.*s", pX->span.n, pX->span.z));
pLevel->nIn++;
- sqlite3ReallocOrFree((void**)&pLevel->aInLoop,
- sizeof(pLevel->aInLoop[0])*3*pLevel->nIn);
+ sqliteReallocOrFree((void**)&pLevel->aInLoop,
+ sizeof(pLevel->aInLoop[0])*2*pLevel->nIn);
aIn = pLevel->aInLoop;
if( aIn ){
- aIn += pLevel->nIn*3 - 3;
- aIn[0] = OP_Next;
- aIn[1] = iTab;
- aIn[2] = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
+ aIn += pLevel->nIn*2 - 2;
+ aIn[0] = iTab;
+ aIn[1] = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
}else{
pLevel->nIn = 0;
}
@@ -1281,6 +1637,25 @@ static int nQPlan = 0; /* Next free slow in _query_plan[] */
#endif /* SQLITE_TEST */
+/*
+** Free a WhereInfo structure
+*/
+static void whereInfoFree(WhereInfo *pWInfo){
+ if( pWInfo ){
+ int i;
+ for(i=0; i<pWInfo->nLevel; i++){
+ sqlite3_index_info *pInfo = pWInfo->a[i].pIdxInfo;
+ if( pInfo ){
+ if( pInfo->needToFreeIdxStr ){
+ sqlite3_free(pInfo->idxStr);
+ }
+ sqliteFree(pInfo);
+ }
+ }
+ sqliteFree(pWInfo);
+ }
+}
+
/*
** Generate the beginning of the loop used for WHERE clause processing.
@@ -1408,9 +1783,10 @@ WhereInfo *sqlite3WhereBegin(
** return value.
*/
pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));
- if( sqlite3_malloc_failed ){
+ if( sqlite3MallocFailed() ){
goto whereBeginNoMem;
}
+ pWInfo->nLevel = pTabList->nSrc;
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
@@ -1432,7 +1808,7 @@ WhereInfo *sqlite3WhereBegin(
createMask(&maskSet, pTabList->a[i].iCursor);
}
exprAnalyzeAll(pTabList, &maskSet, &wc);
- if( sqlite3_malloc_failed ){
+ if( sqlite3MallocFailed() ){
goto whereBeginNoMem;
}
@@ -1464,31 +1840,56 @@ WhereInfo *sqlite3WhereBegin(
Index *pBest = 0; /* The best index seen so far */
int bestFlags = 0; /* Flags associated with pBest */
int bestNEq = 0; /* nEq associated with pBest */
- double lowestCost = 1.0e99; /* Cost of the pBest */
- int bestJ; /* The value of j */
+ double lowestCost; /* Cost of the pBest */
+ int bestJ = 0; /* The value of j */
Bitmask m; /* Bitmask value for j or bestJ */
+ int once = 0; /* True when first table is seen */
+ sqlite3_index_info *pIndex; /* Current virtual index */
+ lowestCost = SQLITE_BIG_DBL;
for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){
+ int doNotReorder; /* True if this table should not be reordered */
+
+ doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0
+ || (j>0 && (pTabItem[-1].jointype & (JT_LEFT|JT_CROSS))!=0);
+ if( once && doNotReorder ) break;
m = getMask(&maskSet, pTabItem->iCursor);
if( (m & notReady)==0 ){
if( j==iFrom ) iFrom++;
continue;
}
- cost = bestIndex(pParse, &wc, pTabItem, notReady,
- (i==0 && ppOrderBy) ? *ppOrderBy : 0,
- &pIdx, &flags, &nEq);
+ assert( pTabItem->pTab );
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTabItem->pTab) ){
+ sqlite3_index_info **ppIdxInfo = &pWInfo->a[j].pIdxInfo;
+ cost = bestVirtualIndex(pParse, &wc, pTabItem, notReady,
+ ppOrderBy ? *ppOrderBy : 0, i==0,
+ ppIdxInfo);
+ flags = WHERE_VIRTUALTABLE;
+ pIndex = *ppIdxInfo;
+ if( pIndex && pIndex->orderByConsumed ){
+ flags = WHERE_VIRTUALTABLE | WHERE_ORDERBY;
+ }
+ pIdx = 0;
+ nEq = 0;
+ }else
+#endif
+ {
+ cost = bestIndex(pParse, &wc, pTabItem, notReady,
+ (i==0 && ppOrderBy) ? *ppOrderBy : 0,
+ &pIdx, &flags, &nEq);
+ pIndex = 0;
+ }
if( cost<lowestCost ){
+ once = 1;
lowestCost = cost;
pBest = pIdx;
bestFlags = flags;
bestNEq = nEq;
bestJ = j;
+ pLevel->pBestIdx = pIndex;
}
- if( (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0
- || (j>0 && (pTabItem[-1].jointype & (JT_LEFT|JT_CROSS))!=0)
- ){
- break;
- }
+ if( doNotReorder ) break;
}
TRACE(("*** Optimizer choose table %d for loop %d\n", bestJ,
pLevel-pWInfo->a));
@@ -1522,10 +1923,10 @@ WhereInfo *sqlite3WhereBegin(
** searching those tables.
*/
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
- pLevel = pWInfo->a;
for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
- Table *pTab;
- Index *pIx;
+ Table *pTab; /* Table to open */
+ Index *pIx; /* Index used to access pTab (if any) */
+ int iDb; /* Index of database containing table/index */
int iIdxCur = pLevel->iIdxCur;
#ifndef SQLITE_OMIT_EXPLAIN
@@ -1538,27 +1939,57 @@ WhereInfo *sqlite3WhereBegin(
}
if( (pIx = pLevel->pIdx)!=0 ){
zMsg = sqlite3MPrintf("%z WITH INDEX %s", zMsg, pIx->zName);
+ }else if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
+ zMsg = sqlite3MPrintf("%z USING PRIMARY KEY", zMsg);
+ }
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ else if( pLevel->pBestIdx ){
+ sqlite3_index_info *pBestIdx = pLevel->pBestIdx;
+ zMsg = sqlite3MPrintf("%z VIRTUAL TABLE INDEX %d:%s", zMsg,
+ pBestIdx->idxNum, pBestIdx->idxStr);
+ }
+#endif
+ if( pLevel->flags & WHERE_ORDERBY ){
+ zMsg = sqlite3MPrintf("%z ORDER BY", zMsg);
}
sqlite3VdbeOp3(v, OP_Explain, i, pLevel->iFrom, zMsg, P3_DYNAMIC);
}
#endif /* SQLITE_OMIT_EXPLAIN */
pTabItem = &pTabList->a[pLevel->iFrom];
pTab = pTabItem->pTab;
- if( pTab->isTransient || pTab->pSelect ) continue;
+ iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ if( pTab->isEphem || pTab->pSelect ) continue;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( pLevel->pBestIdx ){
+ int iCur = pTabItem->iCursor;
+ sqlite3VdbeOp3(v, OP_VOpen, iCur, 0, (const char*)pTab->pVtab, P3_VTAB);
+ }else
+#endif
if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){
- sqlite3OpenTableForReading(v, pTabItem->iCursor, pTab);
+ sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, OP_OpenRead);
+ if( pTab->nCol<(sizeof(Bitmask)*8) ){
+ Bitmask b = pTabItem->colUsed;
+ int n = 0;
+ for(; b; b=b>>1, n++){}
+ sqlite3VdbeChangeP2(v, sqlite3VdbeCurrentAddr(v)-1, n);
+ assert( n<=pTab->nCol );
+ }
+ }else{
+ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
}
pLevel->iTabCur = pTabItem->iCursor;
if( (pIx = pLevel->pIdx)!=0 ){
- sqlite3VdbeAddOp(v, OP_Integer, pIx->iDb, 0);
+ KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx);
+ assert( pIx->pSchema==pTab->pSchema );
+ sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
VdbeComment((v, "# %s", pIx->zName));
sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIx->tnum,
- (char*)&pIx->keyInfo, P3_KEYINFO);
+ (char*)pKey, P3_KEYINFO_HANDOFF);
}
if( (pLevel->flags & WHERE_IDX_ONLY)!=0 ){
sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1);
}
- sqlite3CodeVerifySchema(pParse, pTab->iDb);
+ sqlite3CodeVerifySchema(pParse, iDb);
}
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
@@ -1601,6 +2032,47 @@ WhereInfo *sqlite3WhereBegin(
VdbeComment((v, "# init LEFT JOIN no-match flag"));
}
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( pLevel->pBestIdx ){
+ /* Case 0: The table is a virtual-table. Use the VFilter and VNext
+ ** to access the data.
+ */
+ int j;
+ sqlite3_index_info *pBestIdx = pLevel->pBestIdx;
+ int nConstraint = pBestIdx->nConstraint;
+ struct sqlite3_index_constraint_usage *aUsage =
+ pBestIdx->aConstraintUsage;
+ const struct sqlite3_index_constraint *aConstraint =
+ pBestIdx->aConstraint;
+
+ for(j=1; j<=nConstraint; j++){
+ int k;
+ for(k=0; k<nConstraint; k++){
+ if( aUsage[k].argvIndex==j ){
+ int iTerm = aConstraint[k].iTermOffset;
+ sqlite3ExprCode(pParse, wc.a[iTerm].pExpr->pRight);
+ break;
+ }
+ }
+ if( k==nConstraint ) break;
+ }
+ sqlite3VdbeAddOp(v, OP_Integer, j-1, 0);
+ sqlite3VdbeAddOp(v, OP_Integer, pBestIdx->idxNum, 0);
+ sqlite3VdbeOp3(v, OP_VFilter, iCur, brk, pBestIdx->idxStr,
+ pBestIdx->needToFreeIdxStr ? P3_MPRINTF : P3_STATIC);
+ pBestIdx->needToFreeIdxStr = 0;
+ for(j=0; j<pBestIdx->nConstraint; j++){
+ if( aUsage[j].omit ){
+ int iTerm = aConstraint[j].iTermOffset;
+ disableTerm(pLevel, &wc.a[iTerm]);
+ }
+ }
+ pLevel->op = OP_VNext;
+ pLevel->p1 = iCur;
+ pLevel->p2 = sqlite3VdbeCurrentAddr(v);
+ }else
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
if( pLevel->flags & WHERE_ROWID_EQ ){
/* Case 1: We can directly reference a single row using an
** equality comparison against the ROWID field. Or
@@ -1667,7 +2139,7 @@ WhereInfo *sqlite3WhereBegin(
if( testOp!=OP_Noop ){
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeAddOp(v, testOp, 'n', brk);
+ sqlite3VdbeAddOp(v, testOp, SQLITE_AFF_NUMERIC, brk);
}
}else if( pLevel->flags & WHERE_COLUMN_RANGE ){
/* Case 3: The WHERE clause term that refers to the right-most
@@ -1683,8 +2155,11 @@ WhereInfo *sqlite3WhereBegin(
*/
int start;
int nEq = pLevel->nEq;
- int leFlag=0, geFlag=0;
+ int topEq=0; /* True if top limit uses ==. False is strictly < */
+ int btmEq=0; /* True if btm limit uses ==. False if strictly > */
+ int topOp, btmOp; /* Operators for the top and bottom search bounds */
int testOp;
+ int nNotNull; /* Number of rows of index that must be non-NULL */
int topLimit = (pLevel->flags & WHERE_TOP_LIMIT)!=0;
int btmLimit = (pLevel->flags & WHERE_BTM_LIMIT)!=0;
@@ -1701,6 +2176,21 @@ WhereInfo *sqlite3WhereBegin(
sqlite3VdbeAddOp(v, OP_Dup, nEq-1, 0);
}
+ /* Figure out what comparison operators to use for top and bottom
+ ** search bounds. For an ascending index, the bottom bound is a > or >=
+ ** operator and the top bound is a < or <= operator. For a descending
+ ** index the operators are reversed.
+ */
+ nNotNull = nEq + topLimit;
+ if( pIdx->aSortOrder[nEq]==SQLITE_SO_ASC ){
+ topOp = WO_LT|WO_LE;
+ btmOp = WO_GT|WO_GE;
+ }else{
+ topOp = WO_GT|WO_GE;
+ btmOp = WO_LT|WO_LE;
+ SWAP(int, topLimit, btmLimit);
+ }
+
/* Generate the termination key. This is the key value that
** will end the search. There is no termination key if there
** are no equality terms and no "X<..." term.
@@ -1711,24 +2201,24 @@ WhereInfo *sqlite3WhereBegin(
if( topLimit ){
Expr *pX;
int k = pIdx->aiColumn[j];
- pTerm = findTerm(&wc, iCur, k, notReady, WO_LT|WO_LE, pIdx);
+ pTerm = findTerm(&wc, iCur, k, notReady, topOp, pIdx);
assert( pTerm!=0 );
pX = pTerm->pExpr;
assert( (pTerm->flags & TERM_CODED)==0 );
sqlite3ExprCode(pParse, pX->pRight);
- leFlag = pX->op==TK_LE;
+ topEq = pTerm->eOperator & (WO_LE|WO_GE);
disableTerm(pLevel, pTerm);
testOp = OP_IdxGE;
}else{
testOp = nEq>0 ? OP_IdxGE : OP_Noop;
- leFlag = 1;
+ topEq = 1;
}
if( testOp!=OP_Noop ){
int nCol = nEq + topLimit;
pLevel->iMem = pParse->nMem++;
- buildIndexProbe(v, nCol, brk, pIdx);
+ buildIndexProbe(v, nCol, nEq, brk, pIdx);
if( bRev ){
- int op = leFlag ? OP_MoveLe : OP_MoveLt;
+ int op = topEq ? OP_MoveLe : OP_MoveLt;
sqlite3VdbeAddOp(v, op, iIdxCur, brk);
}else{
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
@@ -1749,25 +2239,25 @@ WhereInfo *sqlite3WhereBegin(
if( btmLimit ){
Expr *pX;
int k = pIdx->aiColumn[j];
- pTerm = findTerm(&wc, iCur, k, notReady, WO_GT|WO_GE, pIdx);
+ pTerm = findTerm(&wc, iCur, k, notReady, btmOp, pIdx);
assert( pTerm!=0 );
pX = pTerm->pExpr;
assert( (pTerm->flags & TERM_CODED)==0 );
sqlite3ExprCode(pParse, pX->pRight);
- geFlag = pX->op==TK_GE;
+ btmEq = pTerm->eOperator & (WO_LE|WO_GE);
disableTerm(pLevel, pTerm);
}else{
- geFlag = 1;
+ btmEq = 1;
}
if( nEq>0 || btmLimit ){
int nCol = nEq + btmLimit;
- buildIndexProbe(v, nCol, brk, pIdx);
+ buildIndexProbe(v, nCol, 0, brk, pIdx);
if( bRev ){
pLevel->iMem = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
testOp = OP_IdxLT;
}else{
- int op = geFlag ? OP_MoveGe : OP_MoveGt;
+ int op = btmEq ? OP_MoveGe : OP_MoveGt;
sqlite3VdbeAddOp(v, op, iIdxCur, brk);
}
}else if( bRev ){
@@ -1784,12 +2274,12 @@ WhereInfo *sqlite3WhereBegin(
if( testOp!=OP_Noop ){
sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
sqlite3VdbeAddOp(v, testOp, iIdxCur, brk);
- if( (leFlag && !bRev) || (!geFlag && bRev) ){
+ if( (topEq && !bRev) || (!btmEq && bRev) ){
sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
}
}
sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0);
- sqlite3VdbeAddOp(v, OP_IdxIsNull, nEq + topLimit, cont);
+ sqlite3VdbeAddOp(v, OP_IdxIsNull, nNotNull, cont);
if( !omitTable ){
sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0);
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
@@ -1815,7 +2305,7 @@ WhereInfo *sqlite3WhereBegin(
/* Generate a single key that will be used to both start and terminate
** the search
*/
- buildIndexProbe(v, nEq, brk, pIdx);
+ buildIndexProbe(v, nEq, 0, brk, pIdx);
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
/* Generate code (1) to move to the first matching element of the table.
@@ -1946,7 +2436,7 @@ WhereInfo *sqlite3WhereBegin(
/* Jump here if malloc fails */
whereBeginNoMem:
whereClauseClear(&wc);
- sqliteFree(pWInfo);
+ whereInfoFree(pWInfo);
return 0;
}
@@ -1972,8 +2462,9 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
if( pLevel->nIn ){
int *a;
int j;
- for(j=pLevel->nIn, a=&pLevel->aInLoop[j*3-3]; j>0; j--, a-=3){
- sqlite3VdbeAddOp(v, a[0], a[1], a[2]);
+ for(j=pLevel->nIn, a=&pLevel->aInLoop[j*2-2]; j>0; j--, a-=2){
+ sqlite3VdbeAddOp(v, OP_Next, a[0], a[1]);
+ sqlite3VdbeJumpHere(v, a[1]-1);
}
sqliteFree(pLevel->aInLoop);
}
@@ -2000,7 +2491,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
Table *pTab = pTabItem->pTab;
assert( pTab!=0 );
- if( pTab->isTransient || pTab->pSelect ) continue;
+ if( pTab->isEphem || pTab->pSelect ) continue;
if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){
sqlite3VdbeAddOp(v, OP_Close, pTabItem->iCursor, 0);
}
@@ -2018,14 +2509,14 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
** reference the index.
*/
if( pLevel->flags & WHERE_IDX_ONLY ){
- int i, j, last;
+ int k, j, last;
VdbeOp *pOp;
Index *pIdx = pLevel->pIdx;
assert( pIdx!=0 );
pOp = sqlite3VdbeGetOp(v, pWInfo->iTop);
last = sqlite3VdbeCurrentAddr(v);
- for(i=pWInfo->iTop; i<last; i++, pOp++){
+ for(k=pWInfo->iTop; k<last; k++, pOp++){
if( pOp->p1!=pLevel->iTabCur ) continue;
if( pOp->opcode==OP_Column ){
pOp->p1 = pLevel->iIdxCur;
@@ -2047,6 +2538,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
/* Final cleanup
*/
- sqliteFree(pWInfo);
+ whereInfoFree(pWInfo);
return;
}
diff --git a/ext/pdo_sqlite/sqlite/tool/lemon.c b/ext/pdo_sqlite/sqlite/tool/lemon.c
index 8f6e87330a..759e1c3786 100644
--- a/ext/pdo_sqlite/sqlite/tool/lemon.c
+++ b/ext/pdo_sqlite/sqlite/tool/lemon.c
@@ -94,6 +94,7 @@ void ReportOutput(/* struct lemon * */);
void ReportTable(/* struct lemon * */);
void ReportHeader(/* struct lemon * */);
void CompressTables(/* struct lemon * */);
+void ResortStates(/* struct lemon * */);
/********** From the file "set.h" ****************************************/
void SetSize(/* int N */); /* All sets will be of size N */
@@ -119,7 +120,8 @@ struct symbol {
int index; /* Index number for this symbol */
enum {
TERMINAL,
- NONTERMINAL
+ NONTERMINAL,
+ MULTITERMINAL
} type; /* Symbols are all either TERMINALS or NTs */
struct rule *rule; /* Linked list of rules of this (if an NT) */
struct symbol *fallback; /* fallback token in case this token doesn't parse */
@@ -140,6 +142,9 @@ struct symbol {
int dtnum; /* The data type number. In the parser, the value
** stack is a union. The .yy%d element of this
** union is the correct data type for this object */
+ /* The following fields are used by MULTITERMINALs only */
+ int nsubsym; /* Number of constituent symbols in the MULTI */
+ struct symbol **subsym; /* Array of constituent symbols */
};
/* Each production rule in the grammar is stored in the following
@@ -206,7 +211,7 @@ struct action {
struct state {
struct config *bp; /* The basis configurations for this state */
struct config *cfp; /* All configurations in this set */
- int index; /* Sequencial number for this state */
+ int statenum; /* Sequencial number for this state */
struct action *ap; /* Array of actions for this state */
int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */
int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */
@@ -236,6 +241,7 @@ struct lemon {
struct symbol **symbols; /* Sorted array of pointers to symbols */
int errorcnt; /* Number of errors */
struct symbol *errsym; /* The error symbol */
+ struct symbol *wildcard; /* Token that matches anything */
char *name; /* Name of the generated parser */
char *arg; /* Declaration of the 3th argument to parser */
char *tokentype; /* Type of terminal symbols in the parser stack */
@@ -584,11 +590,18 @@ struct lemon *xp;
struct rule *rp;
for(rp=xp->rule; rp; rp=rp->next){
if( rp->precsym==0 ){
- int i;
- for(i=0; i<rp->nrhs; i++){
- if( rp->rhs[i]->prec>=0 ){
+ int i, j;
+ for(i=0; i<rp->nrhs && rp->precsym==0; i++){
+ struct symbol *sp = rp->rhs[i];
+ if( sp->type==MULTITERMINAL ){
+ for(j=0; j<sp->nsubsym; j++){
+ if( sp->subsym[j]->prec>=0 ){
+ rp->precsym = sp->subsym[j];
+ break;
+ }
+ }
+ }else if( sp->prec>=0 ){
rp->precsym = rp->rhs[i];
- break;
}
}
}
@@ -604,7 +617,7 @@ struct lemon *xp;
void FindFirstSets(lemp)
struct lemon *lemp;
{
- int i;
+ int i, j;
struct rule *rp;
int progress;
@@ -621,7 +634,8 @@ struct lemon *lemp;
for(rp=lemp->rule; rp; rp=rp->next){
if( rp->lhs->lambda ) continue;
for(i=0; i<rp->nrhs; i++){
- if( rp->rhs[i]->lambda==B_FALSE ) break;
+ struct symbol *sp = rp->rhs[i];
+ if( sp->type!=TERMINAL || sp->lambda==B_FALSE ) break;
}
if( i==rp->nrhs ){
rp->lhs->lambda = B_TRUE;
@@ -641,6 +655,11 @@ struct lemon *lemp;
if( s2->type==TERMINAL ){
progress += SetAdd(s1->firstset,s2->index);
break;
+ }else if( s2->type==MULTITERMINAL ){
+ for(j=0; j<s2->nsubsym; j++){
+ progress += SetAdd(s1->firstset,s2->subsym[j]->index);
+ }
+ break;
}else if( s1==s2 ){
if( s1->lambda==B_FALSE ) break;
}else{
@@ -687,7 +706,7 @@ symbol instead.",lemp->start,lemp->rule->lhs->name);
for(rp=lemp->rule; rp; rp=rp->next){
int i;
for(i=0; i<rp->nrhs; i++){
- if( rp->rhs[i]==sp ){
+ if( rp->rhs[i]==sp ){ /* FIX ME: Deal with multiterminals */
ErrorMsg(lemp->filename,0,
"The start symbol \"%s\" occurs on the \
right-hand side of a rule. This will result in a parser which \
@@ -751,7 +770,7 @@ struct lemon *lemp;
MemoryCheck(stp);
stp->bp = bp; /* Remember the configuration basis */
stp->cfp = cfp; /* Remember the configuration closure */
- stp->index = lemp->nstate++; /* Every state gets a sequence number */
+ stp->statenum = lemp->nstate++; /* Every state gets a sequence number */
stp->ap = 0; /* No actions, yet. */
State_insert(stp,stp->bp); /* Add to the state table */
buildshifts(lemp,stp); /* Recursively compute successor states */
@@ -759,6 +778,24 @@ struct lemon *lemp;
return stp;
}
+/*
+** Return true if two symbols are the same.
+*/
+int same_symbol(a,b)
+struct symbol *a;
+struct symbol *b;
+{
+ int i;
+ if( a==b ) return 1;
+ if( a->type!=MULTITERMINAL ) return 0;
+ if( b->type!=MULTITERMINAL ) return 0;
+ if( a->nsubsym!=b->nsubsym ) return 0;
+ for(i=0; i<a->nsubsym; i++){
+ if( a->subsym[i]!=b->subsym[i] ) return 0;
+ }
+ return 1;
+}
+
/* Construct all successor states to the given state. A "successor"
** state is any state which can be reached by a shift action.
*/
@@ -791,7 +828,7 @@ struct state *stp; /* The state from which successors are computed */
if( bcfp->status==COMPLETE ) continue; /* Already used */
if( bcfp->dot>=bcfp->rp->nrhs ) continue; /* Can't shift this one */
bsp = bcfp->rp->rhs[bcfp->dot]; /* Get symbol after dot */
- if( bsp!=sp ) continue; /* Must be same as for "cfp" */
+ if( !same_symbol(bsp,sp) ) continue; /* Must be same as for "cfp" */
bcfp->status = COMPLETE; /* Mark this config as used */
new = Configlist_addbasis(bcfp->rp,bcfp->dot+1);
Plink_add(&new->bplp,bcfp);
@@ -803,7 +840,14 @@ struct state *stp; /* The state from which successors are computed */
/* The state "newstp" is reached from the state "stp" by a shift action
** on the symbol "sp" */
- Action_add(&stp->ap,SHIFT,sp,(char *)newstp);
+ if( sp->type==MULTITERMINAL ){
+ int i;
+ for(i=0; i<sp->nsubsym; i++){
+ Action_add(&stp->ap,SHIFT,sp->subsym[i],(char*)newstp);
+ }
+ }else{
+ Action_add(&stp->ap,SHIFT,sp,(char *)newstp);
+ }
}
}
@@ -1166,6 +1210,12 @@ struct lemon *lemp;
if( xsp->type==TERMINAL ){
SetAdd(newcfp->fws,xsp->index);
break;
+ }else if( xsp->type==MULTITERMINAL ){
+ int k;
+ for(k=0; k<xsp->nsubsym; k++){
+ SetAdd(newcfp->fws, xsp->subsym[k]->index);
+ }
+ break;
}else{
SetUnion(newcfp->fws,xsp->firstset);
if( xsp->lambda==B_FALSE ) break;
@@ -1373,6 +1423,7 @@ char **argv;
fprintf(stderr,"Exactly one filename argument is required.\n");
exit(1);
}
+ memset(&lem, 0, sizeof(lem));
lem.errorcnt = 0;
/* Initialize the machine */
@@ -1382,22 +1433,13 @@ char **argv;
lem.argv0 = argv[0];
lem.filename = OptArg(0);
lem.basisflag = basisflag;
- lem.has_fallback = 0;
- lem.nconflict = 0;
- lem.name = lem.include = lem.arg = lem.tokentype = lem.start = 0;
- lem.vartype = 0;
- lem.stacksize = 0;
- lem.error = lem.overflow = lem.failure = lem.accept = lem.tokendest =
- lem.tokenprefix = lem.outname = lem.extracode = 0;
- lem.vardest = 0;
- lem.tablesize = 0;
Symbol_new("$");
lem.errsym = Symbol_new("error");
/* Parse the input file */
Parse(&lem);
if( lem.errorcnt ) exit(lem.errorcnt);
- if( lem.rule==0 ){
+ if( lem.nrule==0 ){
fprintf(stderr,"Empty grammar.\n");
exit(1);
}
@@ -1445,6 +1487,10 @@ char **argv;
/* Compress the action tables */
if( compress==0 ) CompressTables(&lem);
+ /* Reorder and renumber the states so that states with fewer choices
+ ** occur at the end. */
+ ResortStates(&lem);
+
/* Generate a report of the parser generated. (the "y.output" file) */
if( !quiet ) ReportOutput(&lem);
@@ -1694,6 +1740,7 @@ FILE *err;
int j;
int errcnt = 0;
cp = strchr(argv[i],'=');
+ assert( cp!=0 );
*cp = 0;
for(j=0; op[j].label; j++){
if( strcmp(argv[i],op[j].label)==0 ) break;
@@ -1906,7 +1953,8 @@ struct pstate {
RESYNC_AFTER_DECL_ERROR,
WAITING_FOR_DESTRUCTOR_SYMBOL,
WAITING_FOR_DATATYPE_SYMBOL,
- WAITING_FOR_FALLBACK_ID
+ WAITING_FOR_FALLBACK_ID,
+ WAITING_FOR_WILDCARD_ID
} state; /* The state of the parser */
struct symbol *fallback; /* The fallback token */
struct symbol *lhs; /* Left-hand side of current rule */
@@ -2086,7 +2134,7 @@ to follow the previous rule.");
}else if( isalpha(x[0]) ){
if( psp->nrhs>=MAXRHS ){
ErrorMsg(psp->filename,psp->tokenlineno,
- "Too many symbol on RHS or rule beginning at \"%s\".",
+ "Too many symbols on RHS or rule beginning at \"%s\".",
x);
psp->errorcnt++;
psp->state = RESYNC_AFTER_RULE_ERROR;
@@ -2095,6 +2143,27 @@ to follow the previous rule.");
psp->alias[psp->nrhs] = 0;
psp->nrhs++;
}
+ }else if( (x[0]=='|' || x[0]=='/') && psp->nrhs>0 ){
+ struct symbol *msp = psp->rhs[psp->nrhs-1];
+ if( msp->type!=MULTITERMINAL ){
+ struct symbol *origsp = msp;
+ msp = malloc(sizeof(*msp));
+ memset(msp, 0, sizeof(*msp));
+ msp->type = MULTITERMINAL;
+ msp->nsubsym = 1;
+ msp->subsym = malloc(sizeof(struct symbol*));
+ msp->subsym[0] = origsp;
+ msp->name = origsp->name;
+ psp->rhs[psp->nrhs-1] = msp;
+ }
+ msp->nsubsym++;
+ msp->subsym = realloc(msp->subsym, sizeof(struct symbol*)*msp->nsubsym);
+ msp->subsym[msp->nsubsym-1] = Symbol_new(&x[1]);
+ if( islower(x[1]) || islower(msp->subsym[0]->name[0]) ){
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Cannot form a compound containing a non-terminal");
+ psp->errorcnt++;
+ }
}else if( x[0]=='(' && psp->nrhs>0 ){
psp->state = RHS_ALIAS_1;
}else{
@@ -2189,6 +2258,8 @@ to follow the previous rule.");
}else if( strcmp(x,"fallback")==0 ){
psp->fallback = 0;
psp->state = WAITING_FOR_FALLBACK_ID;
+ }else if( strcmp(x,"wildcard")==0 ){
+ psp->state = WAITING_FOR_WILDCARD_ID;
}else{
ErrorMsg(psp->filename,psp->tokenlineno,
"Unknown declaration keyword: \"%%%s\".",x);
@@ -2289,6 +2360,24 @@ to follow the previous rule.");
}
}
break;
+ case WAITING_FOR_WILDCARD_ID:
+ if( x[0]=='.' ){
+ psp->state = WAITING_FOR_DECL_OR_RULE;
+ }else if( !isupper(x[0]) ){
+ ErrorMsg(psp->filename, psp->tokenlineno,
+ "%%wildcard argument \"%s\" should be a token", x);
+ psp->errorcnt++;
+ }else{
+ struct symbol *sp = Symbol_new(x);
+ if( psp->gp->wildcard==0 ){
+ psp->gp->wildcard = sp;
+ }else{
+ ErrorMsg(psp->filename, psp->tokenlineno,
+ "Extra wildcard to token: %s", x);
+ psp->errorcnt++;
+ }
+ }
+ break;
case RESYNC_AFTER_RULE_ERROR:
/* if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE;
** break; */
@@ -2482,6 +2571,10 @@ struct lemon *gp;
}else if( c==':' && cp[1]==':' && cp[2]=='=' ){ /* The operator "::=" */
cp += 3;
nextcp = cp;
+ }else if( (c=='/' || c=='|') && isalpha(cp[1]) ){
+ cp += 2;
+ while( (c = *cp)!=0 && (isalnum(c) || c=='_') ) cp++;
+ nextcp = cp;
}else{ /* All other (one character) operators */
cp++;
nextcp = cp;
@@ -2641,15 +2734,21 @@ struct lemon *lemp;
}
for(rp=lemp->rule; rp; rp=rp->next){
printf("%s",rp->lhs->name);
-/* if( rp->lhsalias ) printf("(%s)",rp->lhsalias); */
+ /* if( rp->lhsalias ) printf("(%s)",rp->lhsalias); */
printf(" ::=");
for(i=0; i<rp->nrhs; i++){
- printf(" %s",rp->rhs[i]->name);
-/* if( rp->rhsalias[i] ) printf("(%s)",rp->rhsalias[i]); */
+ sp = rp->rhs[i];
+ printf(" %s", sp->name);
+ if( sp->type==MULTITERMINAL ){
+ for(j=1; j<sp->nsubsym; j++){
+ printf("|%s", sp->subsym[j]->name);
+ }
+ }
+ /* if( rp->rhsalias[i] ) printf("(%s)",rp->rhsalias[i]); */
}
printf(".");
if( rp->precsym ) printf(" [%s]",rp->precsym->name);
-/* if( rp->code ) printf("\n %s",rp->code); */
+ /* if( rp->code ) printf("\n %s",rp->code); */
printf("\n");
}
}
@@ -2659,18 +2758,25 @@ FILE *fp;
struct config *cfp;
{
struct rule *rp;
- int i;
+ struct symbol *sp;
+ int i, j;
rp = cfp->rp;
fprintf(fp,"%s ::=",rp->lhs->name);
for(i=0; i<=rp->nrhs; i++){
if( i==cfp->dot ) fprintf(fp," *");
if( i==rp->nrhs ) break;
- fprintf(fp," %s",rp->rhs[i]->name);
+ sp = rp->rhs[i];
+ fprintf(fp," %s", sp->name);
+ if( sp->type==MULTITERMINAL ){
+ for(j=1; j<sp->nsubsym; j++){
+ fprintf(fp,"|%s",sp->subsym[j]->name);
+ }
+ }
}
}
/* #define TEST */
-#ifdef TEST
+#if 0
/* Print a set */
PRIVATE void SetPrint(out,set,lemp)
FILE *out;
@@ -2697,7 +2803,7 @@ struct plink *plp;
char *tag;
{
while( plp ){
- fprintf(out,"%12s%s (state %2d) ","",tag,plp->cfp->stp->index);
+ fprintf(out,"%12s%s (state %2d) ","",tag,plp->cfp->stp->statenum);
ConfigPrint(out,plp->cfp);
fprintf(out,"\n");
plp = plp->next;
@@ -2712,7 +2818,7 @@ int PrintAction(struct action *ap, FILE *fp, int indent){
int result = 1;
switch( ap->type ){
case SHIFT:
- fprintf(fp,"%*s shift %d",indent,ap->sp->name,ap->x.stp->index);
+ fprintf(fp,"%*s shift %d",indent,ap->sp->name,ap->x.stp->statenum);
break;
case REDUCE:
fprintf(fp,"%*s reduce %d",indent,ap->sp->name,ap->x.rp->index);
@@ -2751,7 +2857,7 @@ struct lemon *lemp;
fprintf(fp," \b");
for(i=0; i<lemp->nstate; i++){
stp = lemp->sorted[i];
- fprintf(fp,"State %d:\n",stp->index);
+ fprintf(fp,"State %d:\n",stp->statenum);
if( lemp->basisflag ) cfp=stp->bp;
else cfp=stp->cfp;
while( cfp ){
@@ -2764,7 +2870,7 @@ struct lemon *lemp;
}
ConfigPrint(fp,cfp);
fprintf(fp,"\n");
-#ifdef TEST
+#if 0
SetPrint(fp,cfp->fws,lemp);
PlinkPrint(fp,cfp->fplp,"To ");
PlinkPrint(fp,cfp->bplp,"From");
@@ -2837,7 +2943,7 @@ struct action *ap;
{
int act;
switch( ap->type ){
- case SHIFT: act = ap->x.stp->index; break;
+ case SHIFT: act = ap->x.stp->statenum; break;
case REDUCE: act = ap->x.rp->index + lemp->nstate; break;
case ERROR: act = lemp->nstate + lemp->nrule; break;
case ACCEPT: act = lemp->nstate + lemp->nrule + 1; break;
@@ -3108,8 +3214,14 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){
** the token number of X, not the value of X */
append_str("yymsp[%d].major",-1,i-rp->nrhs+1,0);
}else{
- append_str("yymsp[%d].minor.yy%d",0,
- i-rp->nrhs+1,rp->rhs[i]->dtnum);
+ struct symbol *sp = rp->rhs[i];
+ int dtnum;
+ if( sp->type==MULTITERMINAL ){
+ dtnum = sp->subsym[0]->dtnum;
+ }else{
+ dtnum = sp->dtnum;
+ }
+ append_str("yymsp[%d].minor.yy%d",0,i-rp->nrhs+1, dtnum);
}
cp = xp;
used[i] = 1;
@@ -3391,6 +3503,10 @@ int mhflag; /* Output in makeheaders format if true */
fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1); lineno++;
fprintf(out,"#define YYACTIONTYPE %s\n",
minimum_size_type(0, lemp->nstate+lemp->nrule+5)); lineno++;
+ if( lemp->wildcard ){
+ fprintf(out,"#define YYWILDCARD %d\n",
+ lemp->wildcard->index); lineno++;
+ }
print_stack_union(out,lemp,&lineno,mhflag);
if( lemp->stacksize ){
if( atoi(lemp->stacksize)<=0 ){
@@ -3457,21 +3573,6 @@ int mhflag; /* Output in makeheaders format if true */
}
for(i=0; i<lemp->nstate; i++){
stp = lemp->sorted[i];
- stp->nTknAct = stp->nNtAct = 0;
- stp->iDflt = lemp->nstate + lemp->nrule;
- stp->iTknOfst = NO_OFFSET;
- stp->iNtOfst = NO_OFFSET;
- for(ap=stp->ap; ap; ap=ap->next){
- if( compute_action(lemp,ap)>=0 ){
- if( ap->sp->index<lemp->nterminal ){
- stp->nTknAct++;
- }else if( ap->sp->index<lemp->nsymbol ){
- stp->nNtAct++;
- }else{
- stp->iDflt = compute_action(lemp, ap);
- }
- }
- }
ax[i*2].stp = stp;
ax[i*2].isTkn = 1;
ax[i*2].nAction = stp->nTknAct;
@@ -3552,9 +3653,11 @@ int mhflag; /* Output in makeheaders format if true */
/* Output the yy_shift_ofst[] table */
fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++;
+ n = lemp->nstate;
+ while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--;
+ fprintf(out, "#define YY_SHIFT_MAX %d\n", n-1); lineno++;
fprintf(out, "static const %s yy_shift_ofst[] = {\n",
minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++;
- n = lemp->nstate;
for(i=j=0; i<n; i++){
int ofst;
stp = lemp->sorted[i];
@@ -3573,9 +3676,11 @@ int mhflag; /* Output in makeheaders format if true */
/* Output the yy_reduce_ofst[] table */
fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
+ n = lemp->nstate;
+ while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--;
+ fprintf(out, "#define YY_REDUCE_MAX %d\n", n-1); lineno++;
fprintf(out, "static const %s yy_reduce_ofst[] = {\n",
minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++;
- n = lemp->nstate;
for(i=j=0; i<n; i++){
int ofst;
stp = lemp->sorted[i];
@@ -3642,7 +3747,16 @@ int mhflag; /* Output in makeheaders format if true */
for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){
assert( rp->index==i );
fprintf(out," /* %3d */ \"%s ::=", i, rp->lhs->name);
- for(j=0; j<rp->nrhs; j++) fprintf(out," %s",rp->rhs[j]->name);
+ for(j=0; j<rp->nrhs; j++){
+ struct symbol *sp = rp->rhs[j];
+ fprintf(out," %s", sp->name);
+ if( sp->type==MULTITERMINAL ){
+ int k;
+ for(k=1; k<sp->nsubsym; k++){
+ fprintf(out,"|%s",sp->subsym[k]->name);
+ }
+ }
+ }
fprintf(out,"\",\n"); lineno++;
}
tplt_xfer(lemp->name,in,out,&lineno);
@@ -3789,7 +3903,8 @@ struct lemon *lemp;
** of defaults.
**
** In this version, we take the most frequent REDUCE action and make
-** it the default. Only default a reduce if there are more than one.
+** it the default. Except, there is no default if the wildcard token
+** is a possible look-ahead.
*/
void CompressTables(lemp)
struct lemon *lemp;
@@ -3799,13 +3914,18 @@ struct lemon *lemp;
struct rule *rp, *rp2, *rbest;
int nbest, n;
int i;
+ int usesWildcard;
for(i=0; i<lemp->nstate; i++){
stp = lemp->sorted[i];
nbest = 0;
rbest = 0;
+ usesWildcard = 0;
for(ap=stp->ap; ap; ap=ap->next){
+ if( ap->type==SHIFT && ap->sp==lemp->wildcard ){
+ usesWildcard = 1;
+ }
if( ap->type!=REDUCE ) continue;
rp = ap->x.rp;
if( rp==rbest ) continue;
@@ -3823,8 +3943,10 @@ struct lemon *lemp;
}
/* Do not make a default if the number of rules to default
- ** is not at least 2 */
- if( nbest<2 ) continue;
+ ** is not at least 1 or if the wildcard token is a possible
+ ** lookahead.
+ */
+ if( nbest<1 || usesWildcard ) continue;
/* Combine matching REDUCE actions into a single default */
@@ -3840,6 +3962,63 @@ struct lemon *lemp;
}
}
+
+/*
+** Compare two states for sorting purposes. The smaller state is the
+** one with the most non-terminal actions. If they have the same number
+** of non-terminal actions, then the smaller is the one with the most
+** token actions.
+*/
+static int stateResortCompare(const void *a, const void *b){
+ const struct state *pA = *(const struct state**)a;
+ const struct state *pB = *(const struct state**)b;
+ int n;
+
+ n = pB->nNtAct - pA->nNtAct;
+ if( n==0 ){
+ n = pB->nTknAct - pA->nTknAct;
+ }
+ return n;
+}
+
+
+/*
+** Renumber and resort states so that states with fewer choices
+** occur at the end. Except, keep state 0 as the first state.
+*/
+void ResortStates(lemp)
+struct lemon *lemp;
+{
+ int i;
+ struct state *stp;
+ struct action *ap;
+
+ for(i=0; i<lemp->nstate; i++){
+ stp = lemp->sorted[i];
+ stp->nTknAct = stp->nNtAct = 0;
+ stp->iDflt = lemp->nstate + lemp->nrule;
+ stp->iTknOfst = NO_OFFSET;
+ stp->iNtOfst = NO_OFFSET;
+ for(ap=stp->ap; ap; ap=ap->next){
+ if( compute_action(lemp,ap)>=0 ){
+ if( ap->sp->index<lemp->nterminal ){
+ stp->nTknAct++;
+ }else if( ap->sp->index<lemp->nsymbol ){
+ stp->nNtAct++;
+ }else{
+ stp->iDflt = compute_action(lemp, ap);
+ }
+ }
+ }
+ }
+ qsort(&lemp->sorted[1], lemp->nstate-1, sizeof(lemp->sorted[0]),
+ stateResortCompare);
+ for(i=0; i<lemp->nstate; i++){
+ lemp->sorted[i]->statenum = i;
+ }
+}
+
+
/***************** From the file "set.c" ************************************/
/*
** Set manipulation routines for the LEMON parser generator.
@@ -3932,6 +4111,7 @@ char *y;
{
char *z;
+ if( y==0 ) return 0;
z = Strsafe_find(y);
if( z==0 && (z=malloc( strlen(y)+1 ))!=0 ){
strcpy(z,y);
diff --git a/ext/pdo_sqlite/sqlite/tool/lempar.c b/ext/pdo_sqlite/sqlite/tool/lempar.c
index 57ec97f6a8..a18c43a24d 100644
--- a/ext/pdo_sqlite/sqlite/tool/lempar.c
+++ b/ext/pdo_sqlite/sqlite/tool/lempar.c
@@ -107,7 +107,7 @@
** yy_default[] Default action for each state.
*/
%%
-#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
+#define YY_SZ_ACTTAB (int)(sizeof(yy_action)/sizeof(yy_action[0]))
/* The next table maps tokens into fallback tokens. If a construct
** like the following:
@@ -321,14 +321,12 @@ void ParseFree(
*/
static int yy_find_shift_action(
yyParser *pParser, /* The parser */
- int iLookAhead /* The look-ahead token */
+ YYCODETYPE iLookAhead /* The look-ahead token */
){
int i;
int stateno = pParser->yystack[pParser->yyidx].stateno;
- /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
- i = yy_shift_ofst[stateno];
- if( i==YY_SHIFT_USE_DFLT ){
+ if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
return yy_default[stateno];
}
if( iLookAhead==YYNOCODE ){
@@ -336,19 +334,35 @@ static int yy_find_shift_action(
}
i += iLookAhead;
if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
+ if( iLookAhead>0 ){
#ifdef YYFALLBACK
- int iFallback; /* Fallback token */
- if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
- && (iFallback = yyFallback[iLookAhead])!=0 ){
+ int iFallback; /* Fallback token */
+ if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
+ && (iFallback = yyFallback[iLookAhead])!=0 ){
#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
- yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
+ }
+#endif
+ return yy_find_shift_action(pParser, iFallback);
}
#endif
- return yy_find_shift_action(pParser, iFallback);
+#ifdef YYWILDCARD
+ {
+ int j = i - iLookAhead + YYWILDCARD;
+ if( j>=0 && j<YY_SZ_ACTTAB && yy_lookahead[j]==YYWILDCARD ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]);
+ }
+#endif /* NDEBUG */
+ return yy_action[j];
+ }
+ }
+#endif /* YYWILDCARD */
}
-#endif
return yy_default[stateno];
}else{
return yy_action[i];
@@ -365,13 +379,13 @@ static int yy_find_shift_action(
*/
static int yy_find_reduce_action(
int stateno, /* Current state number */
- int iLookAhead /* The look-ahead token */
+ YYCODETYPE iLookAhead /* The look-ahead token */
){
int i;
/* int stateno = pParser->yystack[pParser->yyidx].stateno; */
- i = yy_reduce_ofst[stateno];
- if( i==YY_REDUCE_USE_DFLT ){
+ if( stateno>YY_REDUCE_MAX ||
+ (i = yy_reduce_ofst[stateno])==YY_REDUCE_USE_DFLT ){
return yy_default[stateno];
}
if( iLookAhead==YYNOCODE ){
@@ -456,7 +470,7 @@ static void yy_reduce(
yymsp = &yypParser->yystack[yypParser->yyidx];
#ifndef NDEBUG
if( yyTraceFILE && yyruleno>=0
- && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
+ && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
yyRuleName[yyruleno]);
}
@@ -669,7 +683,9 @@ void Parse(
while(
yypParser->yyidx >= 0 &&
yymx != YYERRORSYMBOL &&
- (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
+ (yyact = yy_find_reduce_action(
+ yypParser->yystack[yypParser->yyidx].stateno,
+ YYERRORSYMBOL)) >= YYNSTATE
){
yy_pop_parser_stack(yypParser);
}
diff --git a/ext/pdo_sqlite/sqlite/tool/memleak3.tcl b/ext/pdo_sqlite/sqlite/tool/memleak3.tcl
index 2e3f43bc13..3c6e9b9c56 100644
--- a/ext/pdo_sqlite/sqlite/tool/memleak3.tcl
+++ b/ext/pdo_sqlite/sqlite/tool/memleak3.tcl
@@ -198,6 +198,7 @@ proc report {} {
lappend summarymap($stack) $bytes
}
+ set sorted [list]
foreach stack [array names summarymap] {
set allocs $summarymap($stack)
set sum 0
diff --git a/ext/pdo_sqlite/sqlite/tool/mkkeywordhash.c b/ext/pdo_sqlite/sqlite/tool/mkkeywordhash.c
index 58d4b9cb78..3301a40e97 100644
--- a/ext/pdo_sqlite/sqlite/tool/mkkeywordhash.c
+++ b/ext/pdo_sqlite/sqlite/tool/mkkeywordhash.c
@@ -105,7 +105,11 @@ struct Keyword {
#else
# define VIEW 0x00008000
#endif
-
+#ifdef SQLITE_OMIT_VIRTUALTABLE
+# define VTAB 0
+#else
+# define VTAB 0x00010000
+#endif
/*
** These are the keywords
@@ -155,7 +159,7 @@ static Keyword aKeywordTable[] = {
{ "ESCAPE", "TK_ESCAPE", ALWAYS },
{ "EXCEPT", "TK_EXCEPT", COMPOUND },
{ "EXCLUSIVE", "TK_EXCLUSIVE", ALWAYS },
- { "EXISTS", "TK_EXISTS", SUBQUERY },
+ { "EXISTS", "TK_EXISTS", ALWAYS },
{ "EXPLAIN", "TK_EXPLAIN", EXPLAIN },
{ "FAIL", "TK_FAIL", CONFLICT|TRIGGER },
{ "FOR", "TK_FOR", TRIGGER },
@@ -165,6 +169,7 @@ static Keyword aKeywordTable[] = {
{ "GLOB", "TK_LIKE_KW", ALWAYS },
{ "GROUP", "TK_GROUP", ALWAYS },
{ "HAVING", "TK_HAVING", ALWAYS },
+ { "IF", "TK_IF", ALWAYS },
{ "IGNORE", "TK_IGNORE", CONFLICT|TRIGGER },
{ "IMMEDIATE", "TK_IMMEDIATE", ALWAYS },
{ "IN", "TK_IN", ALWAYS },
@@ -222,6 +227,7 @@ static Keyword aKeywordTable[] = {
{ "VACUUM", "TK_VACUUM", VACUUM },
{ "VALUES", "TK_VALUES", ALWAYS },
{ "VIEW", "TK_VIEW", VIEW },
+ { "VIRTUAL", "TK_VIRTUAL", VTAB },
{ "WHEN", "TK_WHEN", ALWAYS },
{ "WHERE", "TK_WHERE", ALWAYS },
};
@@ -482,8 +488,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]]*4) ^\n"
- " (sqlite3UpperToLower[((unsigned char*)z)[n-1]]*3) ^\n"
+ printf(" h = ((charMap(z[0])*4) ^\n"
+ " (charMap(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 &&"
@@ -493,8 +499,8 @@ 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("int sqlite3KeywordCode(const unsigned char *z, int n){\n");
+ printf(" return keywordCode((char*)z, n);\n");
printf("}\n");
return 0;
diff --git a/ext/pdo_sqlite/sqlite/tool/showdb.c b/ext/pdo_sqlite/sqlite/tool/showdb.c
index fe105c7bb2..b2ed562e95 100644
--- a/ext/pdo_sqlite/sqlite/tool/showdb.c
+++ b/ext/pdo_sqlite/sqlite/tool/showdb.c
@@ -13,6 +13,7 @@
static int pagesize = 1024;
static int db = -1;
static int mxPage = 0;
+static int perLine = 32;
static void out_of_memory(void){
fprintf(stderr,"Out of memory...\n");
@@ -27,12 +28,12 @@ static print_page(int iPg){
lseek(db, (iPg-1)*pagesize, SEEK_SET);
read(db, aData, pagesize);
fprintf(stdout, "Page %d:\n", iPg);
- for(i=0; i<pagesize; i += 16){
+ for(i=0; i<pagesize; i += perLine){
fprintf(stdout, " %03x: ",i);
- for(j=0; j<16; j++){
+ for(j=0; j<perLine; j++){
fprintf(stdout,"%02x ", aData[i+j]);
}
- for(j=0; j<16; j++){
+ for(j=0; j<perLine; j++){
fprintf(stdout,"%c", isprint(aData[i+j]) ? aData[i+j] : '.');
}
fprintf(stdout,"\n");
diff --git a/ext/pdo_sqlite/sqlite/tool/spaceanal.tcl b/ext/pdo_sqlite/sqlite/tool/spaceanal.tcl
index c9b8f92e25..c0fe5b5d87 100644
--- a/ext/pdo_sqlite/sqlite/tool/spaceanal.tcl
+++ b/ext/pdo_sqlite/sqlite/tool/spaceanal.tcl
@@ -3,6 +3,8 @@
# versus how much space is unused.
#
+if {[catch {
+
# Get the name of the database to analyze
#
#set argv $argv0
@@ -122,6 +124,7 @@ set sql {
SELECT 'sqlite_master', 1
ORDER BY 1
}
+set wideZero [expr {10000000000 - 10000000000}]
foreach {name rootpage} [db eval $sql] {
puts stderr "Analyzing table $name..."
@@ -129,18 +132,18 @@ foreach {name rootpage} [db eval $sql] {
# btree cursor $cursor. Statistics related to table $name are accumulated in
# the following variables:
#
- set total_payload 0 ;# Payload space used by all entries
- set total_ovfl 0 ;# Payload space on overflow pages
- set unused_int 0 ;# Unused space on interior nodes
- set unused_leaf 0 ;# Unused space on leaf nodes
- set unused_ovfl 0 ;# Unused space on overflow pages
- set cnt_ovfl 0 ;# Number of entries that use overflows
- set cnt_leaf_entry 0 ;# Number of leaf entries
- set cnt_int_entry 0 ;# Number of interor entries
- set mx_payload 0 ;# Maximum payload size
- set ovfl_pages 0 ;# Number of overflow pages used
- set leaf_pages 0 ;# Number of leaf pages
- set int_pages 0 ;# Number of interior pages
+ set total_payload $wideZero ;# Payload space used by all entries
+ set total_ovfl $wideZero ;# Payload space on overflow pages
+ set unused_int $wideZero ;# Unused space on interior nodes
+ set unused_leaf $wideZero ;# Unused space on leaf nodes
+ set unused_ovfl $wideZero ;# Unused space on overflow pages
+ set cnt_ovfl $wideZero ;# Number of entries that use overflows
+ set cnt_leaf_entry $wideZero ;# Number of leaf entries
+ set cnt_int_entry $wideZero ;# Number of interor entries
+ set mx_payload $wideZero ;# Maximum payload size
+ set ovfl_pages $wideZero ;# Number of overflow pages used
+ set leaf_pages $wideZero ;# Number of leaf pages
+ set int_pages $wideZero ;# Number of interior pages
# As the btree is traversed, the array variable $seen($pgno) is set to 1
# the first time page $pgno is encountered.
@@ -266,15 +269,15 @@ foreach {name tbl_name rootpage} [db eval $sql] {
# btree cursor $cursor. Statistics related to index $name are accumulated in
# the following variables:
#
- set total_payload 0 ;# Payload space used by all entries
- set total_ovfl 0 ;# Payload space on overflow pages
- set unused_leaf 0 ;# Unused space on leaf nodes
- set unused_ovfl 0 ;# Unused space on overflow pages
- set cnt_ovfl 0 ;# Number of entries that use overflows
- set cnt_leaf_entry 0 ;# Number of leaf entries
- set mx_payload 0 ;# Maximum payload size
- set ovfl_pages 0 ;# Number of overflow pages used
- set leaf_pages 0 ;# Number of leaf pages
+ set total_payload $wideZero ;# Payload space used by all entries
+ set total_ovfl $wideZero ;# Payload space on overflow pages
+ set unused_leaf $wideZero ;# Unused space on leaf nodes
+ set unused_ovfl $wideZero ;# Unused space on overflow pages
+ set cnt_ovfl $wideZero ;# Number of entries that use overflows
+ set cnt_leaf_entry $wideZero ;# Number of leaf entries
+ set mx_payload $wideZero ;# Maximum payload size
+ set ovfl_pages $wideZero ;# Number of overflow pages used
+ set leaf_pages $wideZero ;# Number of leaf pages
# As the btree is traversed, the array variable $seen($pgno) is set to 1
# the first time page $pgno is encountered.
@@ -799,3 +802,9 @@ mem eval {SELECT * FROM space_used} x {
puts ");"
}
puts "COMMIT;"
+
+} err]} {
+ puts "ERROR: $err"
+ puts $errorInfo
+ exit 1
+}