summaryrefslogtreecommitdiff
path: root/ext/pdo_sqlite
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pdo_sqlite')
-rw-r--r--ext/pdo_sqlite/config.m45
-rw-r--r--ext/pdo_sqlite/config.w327
-rwxr-xr-xext/pdo_sqlite/package.xml360
-rw-r--r--ext/pdo_sqlite/sqlite/Makefile.in331
-rw-r--r--ext/pdo_sqlite/sqlite/Makefile.linux-gcc10
-rw-r--r--ext/pdo_sqlite/sqlite/VERSION2
-rw-r--r--ext/pdo_sqlite/sqlite/aclocal.m41723
-rw-r--r--ext/pdo_sqlite/sqlite/addopcodes.awk32
-rw-r--r--ext/pdo_sqlite/sqlite/config.guess720
-rw-r--r--ext/pdo_sqlite/sqlite/config.sub219
-rwxr-xr-xext/pdo_sqlite/sqlite/configure6547
-rw-r--r--ext/pdo_sqlite/sqlite/configure.ac259
-rw-r--r--ext/pdo_sqlite/sqlite/ltmain.sh1890
-rw-r--r--ext/pdo_sqlite/sqlite/main.mk578
-rw-r--r--ext/pdo_sqlite/sqlite/mkdll.sh42
-rw-r--r--ext/pdo_sqlite/sqlite/mkopcodec.awk9
-rw-r--r--ext/pdo_sqlite/sqlite/mkopcodeh.awk90
-rw-r--r--ext/pdo_sqlite/sqlite/mkso.sh2
-rw-r--r--ext/pdo_sqlite/sqlite/publish.sh69
-rw-r--r--ext/pdo_sqlite/sqlite/sqlite3.def4
-rw-r--r--ext/pdo_sqlite/sqlite/sqlite3.pc.in1
-rw-r--r--ext/pdo_sqlite/sqlite/src/alter.c161
-rw-r--r--ext/pdo_sqlite/sqlite/src/analyze.c166
-rw-r--r--ext/pdo_sqlite/sqlite/src/attach.c83
-rw-r--r--ext/pdo_sqlite/sqlite/src/auth.c12
-rw-r--r--ext/pdo_sqlite/sqlite/src/btmutex.c317
-rw-r--r--ext/pdo_sqlite/sqlite/src/btree.c3966
-rw-r--r--ext/pdo_sqlite/sqlite/src/btree.h84
-rw-r--r--ext/pdo_sqlite/sqlite/src/btreeInt.h650
-rw-r--r--ext/pdo_sqlite/sqlite/src/build.c793
-rw-r--r--ext/pdo_sqlite/sqlite/src/callback.c40
-rw-r--r--ext/pdo_sqlite/sqlite/src/complete.c16
-rw-r--r--ext/pdo_sqlite/sqlite/src/date.c202
-rw-r--r--ext/pdo_sqlite/sqlite/src/delete.c234
-rw-r--r--ext/pdo_sqlite/sqlite/src/expr.c1544
-rw-r--r--ext/pdo_sqlite/sqlite/src/fault.c147
-rw-r--r--ext/pdo_sqlite/sqlite/src/func.c797
-rw-r--r--ext/pdo_sqlite/sqlite/src/hash.c61
-rw-r--r--ext/pdo_sqlite/sqlite/src/hash.h5
-rw-r--r--ext/pdo_sqlite/sqlite/src/insert.c1145
-rw-r--r--ext/pdo_sqlite/sqlite/src/journal.c238
-rw-r--r--ext/pdo_sqlite/sqlite/src/keywordhash.h166
-rw-r--r--ext/pdo_sqlite/sqlite/src/legacy.c23
-rw-r--r--ext/pdo_sqlite/sqlite/src/limits.h158
-rw-r--r--ext/pdo_sqlite/sqlite/src/loadext.c299
-rw-r--r--ext/pdo_sqlite/sqlite/src/main.c700
-rw-r--r--ext/pdo_sqlite/sqlite/src/malloc.c239
-rw-r--r--ext/pdo_sqlite/sqlite/src/md5.c4
-rw-r--r--ext/pdo_sqlite/sqlite/src/mem1.c232
-rw-r--r--ext/pdo_sqlite/sqlite/src/mutex.c126
-rw-r--r--ext/pdo_sqlite/sqlite/src/mutex.h82
-rw-r--r--ext/pdo_sqlite/sqlite/src/mutex_unix.c298
-rw-r--r--ext/pdo_sqlite/sqlite/src/mutex_w32.c219
-rw-r--r--ext/pdo_sqlite/sqlite/src/opcodes.c280
-rw-r--r--ext/pdo_sqlite/sqlite/src/opcodes.h290
-rw-r--r--ext/pdo_sqlite/sqlite/src/os.c275
-rw-r--r--ext/pdo_sqlite/sqlite/src/os.h385
-rw-r--r--ext/pdo_sqlite/sqlite/src/os_common.h117
-rw-r--r--ext/pdo_sqlite/sqlite/src/os_unix.c2284
-rw-r--r--ext/pdo_sqlite/sqlite/src/os_win.c1425
-rw-r--r--ext/pdo_sqlite/sqlite/src/pager.c3572
-rw-r--r--ext/pdo_sqlite/sqlite/src/pager.h146
-rw-r--r--ext/pdo_sqlite/sqlite/src/parse.c3538
-rw-r--r--ext/pdo_sqlite/sqlite/src/parse.h179
-rw-r--r--ext/pdo_sqlite/sqlite/src/parse.y414
-rw-r--r--ext/pdo_sqlite/sqlite/src/pragma.c606
-rw-r--r--ext/pdo_sqlite/sqlite/src/prepare.c335
-rw-r--r--ext/pdo_sqlite/sqlite/src/printf.c303
-rw-r--r--ext/pdo_sqlite/sqlite/src/random.c79
-rw-r--r--ext/pdo_sqlite/sqlite/src/select.c1842
-rw-r--r--ext/pdo_sqlite/sqlite/src/shell.c556
-rw-r--r--ext/pdo_sqlite/sqlite/src/sqlite.h.in4644
-rw-r--r--ext/pdo_sqlite/sqlite/src/sqlite3ext.h80
-rw-r--r--ext/pdo_sqlite/sqlite/src/sqliteInt.h756
-rw-r--r--ext/pdo_sqlite/sqlite/src/sqliteLimit.h179
-rw-r--r--ext/pdo_sqlite/sqlite/src/table.c45
-rw-r--r--ext/pdo_sqlite/sqlite/src/tclsqlite.c670
-rw-r--r--ext/pdo_sqlite/sqlite/src/test1.c1831
-rw-r--r--ext/pdo_sqlite/sqlite/src/test2.c95
-rw-r--r--ext/pdo_sqlite/sqlite/src/test3.c275
-rw-r--r--ext/pdo_sqlite/sqlite/src/test4.c19
-rw-r--r--ext/pdo_sqlite/sqlite/src/test5.c15
-rw-r--r--ext/pdo_sqlite/sqlite/src/tokenize.c54
-rw-r--r--ext/pdo_sqlite/sqlite/src/trigger.c245
-rw-r--r--ext/pdo_sqlite/sqlite/src/update.c407
-rw-r--r--ext/pdo_sqlite/sqlite/src/utf.c327
-rw-r--r--ext/pdo_sqlite/sqlite/src/util.c1151
-rw-r--r--ext/pdo_sqlite/sqlite/src/vacuum.c140
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbe.c3925
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbe.h85
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbeInt.h77
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbeapi.c463
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbeaux.c1222
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbeblob.c337
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbefifo.c12
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbemem.c359
-rw-r--r--ext/pdo_sqlite/sqlite/src/vtab.c303
-rw-r--r--ext/pdo_sqlite/sqlite/src/where.c956
-rw-r--r--ext/pdo_sqlite/sqlite/tool/fragck.tcl149
-rw-r--r--ext/pdo_sqlite/sqlite/tool/lemon.c295
-rw-r--r--ext/pdo_sqlite/sqlite/tool/lempar.c147
-rw-r--r--ext/pdo_sqlite/sqlite/tool/mkkeywordhash.c120
-rw-r--r--ext/pdo_sqlite/sqlite/tool/mksqlite3c.tcl278
-rw-r--r--ext/pdo_sqlite/sqlite/tool/mksqlite3internalh.tcl145
-rw-r--r--ext/pdo_sqlite/sqlite/tool/omittest.tcl176
-rw-r--r--ext/pdo_sqlite/sqlite/tool/soak1.tcl103
-rw-r--r--ext/pdo_sqlite/sqlite/tool/spaceanal.tcl65
107 files changed, 38846 insertions, 24037 deletions
diff --git a/ext/pdo_sqlite/config.m4 b/ext/pdo_sqlite/config.m4
index 103a8cf34c..b14600d339 100644
--- a/ext/pdo_sqlite/config.m4
+++ b/ext/pdo_sqlite/config.m4
@@ -82,7 +82,10 @@ if test "$PHP_PDO_SQLITE" != "no"; then
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/vtab.c sqlite/src/loadext.c"
+ sqlite/src/alter.c sqlite/src/vdbefifo.c sqlite/src/vtab.c sqlite/src/loadext.c \
+ sqlite/src/btmutex.c sqlite/src/fault.c sqlite/src/journal.c \
+ sqlite/src/malloc.c sqlite/src/mem1.c sqlite/src/mutex.c sqlite/src/mutex_unix.c \
+ sqlite/src/mutex_w32.c sqlite/src/vdbeblob.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 f9d663f17f..5b27eb3b51 100644
--- a/ext/pdo_sqlite/config.w32
+++ b/ext/pdo_sqlite/config.w32
@@ -18,14 +18,15 @@ if (PHP_PDO_SQLITE != "no") {
FSO.CopyFile(configure_module_dirname + "\\sqlite\\src\\sqlite_config.w32.h",
configure_module_dirname + "\\sqlite\\src\\config.h");
-
+
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.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");
-
+ vdbeaux.c vdbe.c vdbemem.c vdbefifo.c where.c parse.c opcodes.c alter.c vtab.c loadext.c \
+ btmutex.c fault.c journal.c malloc.c mem1.c mutex.c mutex_unix.c mutex_w32.c vdbeblob.c", "pdo_sqlite");
+
ADD_EXTENSION_DEP('pdo_sqlite', 'pdo');
}
diff --git a/ext/pdo_sqlite/package.xml b/ext/pdo_sqlite/package.xml
index 2461d8d351..01cdb43ada 100755
--- a/ext/pdo_sqlite/package.xml
+++ b/ext/pdo_sqlite/package.xml
@@ -1,173 +1,187 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE package SYSTEM "../pear/package.dtd">
-<package version="1.0">
- <name>PDO_SQLITE</name>
- <summary>SQLite v3 Interface driver for PDO</summary>
- <maintainers>
- <maintainer>
- <user>wez</user>
- <name>Wez Furlong</name>
- <email>wez@php.net</email>
- <role>lead</role>
- </maintainer>
- </maintainers>
- <!-- configureoptions>
- <configureoption name="with-pdo-sqlite" prompt="Path to your sqlite3 install"/>
-</configureoptions -->
- <description>
- This extension provides an SQLite v3 driver for PDO.
- SQLite V3 is NOT compatible with the bundled SQLite 2 in PHP 5, but is a significant
- step forwards, featuring complete utf-8 support, native support for blobs,
- native support for prepared statements with bound parameters and improved
- concurrency.
- </description>
- <license>PHP</license>
- <release>
- <state>beta</state>
- <version>0.9</version>
- <date>2005-07-27</date>
-
- <notes>
- You need to install the PDO core module before you can make use of this one.
- This package includes a bundled SQLite 3 library.
-
- Windows binary: http://snaps.php.net/win32/PECL_5_0/php_pdo_sqlite.dll
-
- - Fixed PECL Bug #3452; problem when first row of a result set contains a NULL value.
- - Upgraded bundled sqlite to 3.1.3
- - setting PDO_ATTR_TIMEOUT controls the busy timeout
- - Fixed PECL Bug #3391; cannot bind NULL parameters
- - Fixed build problem when building the bundled sqlite library
- </notes>
-
- <filelist>
- <file role="src" name="config.m4"/>
- <file role="src" name="config.w32"/>
- <file role="src" name="pdo_sqlite.c"/>
- <file role="src" name="sqlite_driver.c"/>
- <file role="src" name="sqlite_statement.c"/>
- <file role="src" name="php_pdo_sqlite.h"/>
- <file role="src" name="php_pdo_sqlite_int.h"/>
-
- <file role="doc" name="CREDITS"/>
-
- <dir name="sqlite">
-<file role="src" name="aclocal.m4"/>
-<file role="src" name="config.guess"/>
-<file role="src" name="config.sub"/>
-<file role="src" name="configure"/>
-<file role="src" name="configure.ac"/>
-<file role="src" name="install-sh"/>
-<file role="src" name="ltmain.sh"/>
-<file role="src" name="main.mk"/>
-<file role="src" name="Makefile.in"/>
-<file role="src" name="Makefile.linux-gcc"/>
-<file role="src" name="mkdll.sh"/>
-<file role="src" name="mkopcodec.awk"/>
-<file role="src" name="mkopcodeh.awk"/>
-<file role="src" name="mkso.sh"/>
-<file role="src" name="publish.sh"/>
-<file role="src" name="README"/>
-<file role="src" name="spec.template"/>
-<file role="src" name="sqlite.1"/>
-<file role="src" name="sqlite3.def"/>
-<file role="src" name="sqlite3.pc.in"/>
-<file role="src" name="sqlite.pc.in"/>
-<file role="src" name="VERSION"/>
-<dir name="src">
-<file role="src" name="attach.c"/>
-<file role="src" name="alter.c"/>
-<file role="src" name="auth.c"/>
-<file role="src" name="btree.c"/>
-<file role="src" name="btree.h"/>
-<file role="src" name="build.c"/>
-<file role="src" name="callback.c"/>
-<file role="src" name="date.c"/>
-<file role="src" name="delete.c"/>
-<file role="src" name="expr.c"/>
-<file role="src" name="experimental.c"/>
-<file role="src" name="func.c"/>
-<file role="src" name="hash.c"/>
-<file role="src" name="hash.h"/>
-<file role="src" name="insert.c"/>
-<file role="src" name="legacy.c"/>
-<file role="src" name="main.c"/>
-<file role="src" name="md5.c"/>
-<file role="src" name="keywordhash.h"/>
-<file role="src" name="opcodes.c"/>
-<file role="src" name="opcodes.h"/>
-<file role="src" name="os_common.h"/>
-<file role="src" name="os.h"/>
-<file role="src" name="os_mac.c"/>
-<file role="src" name="os_mac.h"/>
-<file role="src" name="os_test.c"/>
-<file role="src" name="os_test.h"/>
-<file role="src" name="os_unix.c"/>
-<file role="src" name="os_unix.h"/>
-<file role="src" name="os_win.c"/>
-<file role="src" name="os_win.h"/>
-<file role="src" name="pager.c"/>
-<file role="src" name="pager.h"/>
-<file role="src" name="parse.y"/>
-<file role="src" name="parse.c"/>
-<file role="src" name="parse.h"/>
-<file role="src" name="pragma.c"/>
-<file role="src" name="prepare.c"/>
-<file role="src" name="printf.c"/>
-<file role="src" name="random.c"/>
-<file role="src" name="select.c"/>
-<file role="src" name="shell.c"/>
-<file role="src" name="sqlite.h.in"/>
-<file role="src" name="sqliteInt.h"/>
-<file role="src" name="table.c"/>
-<file role="src" name="tclsqlite.c"/>
-<file role="src" name="test1.c"/>
-<file role="src" name="test2.c"/>
-<file role="src" name="test3.c"/>
-<file role="src" name="test4.c"/>
-<file role="src" name="test5.c"/>
-<file role="src" name="tokenize.c"/>
-<file role="src" name="trigger.c"/>
-<file role="src" name="update.c"/>
-<file role="src" name="utf.c"/>
-<file role="src" name="util.c"/>
-<file role="src" name="vacuum.c"/>
-<file role="src" name="vdbeapi.c"/>
-<file role="src" name="vdbeaux.c"/>
-<file role="src" name="vdbe.c"/>
-<file role="src" name="vdbe.h"/>
-<file role="src" name="vdbeInt.h"/>
-<file role="src" name="vdbemem.c"/>
-<file role="src" name="where.c"/>
-<file role="src" name="sqlite3ext.h"/>
-</dir>
-
-<dir name="tool">
-<file role="src" name="diffdb.c"/>
-<file role="src" name="lemon.c"/>
-<file role="src" name="lempar.c"/>
-<file role="src" name="memleak2.awk"/>
-<file role="src" name="memleak3.tcl"/>
-<file role="src" name="memleak.awk"/>
-<file role="src" name="mkkeywordhash.c"/>
-<file role="src" name="mkopts.tcl"/>
-<file role="src" name="opcodeDoc.awk"/>
-<file role="src" name="report1.txt"/>
-<file role="src" name="showdb.c"/>
-<file role="src" name="showjournal.c"/>
-<file role="src" name="spaceanal.tcl"/>
-<file role="src" name="space_used.tcl"/>
-<file role="src" name="speedtest2.tcl"/>
-<file role="src" name="speedtest.tcl"/>
-</dir>
-
- </dir>
-
- </filelist>
- <deps>
- <dep type="php" rel="ge" version="5.0.3"/>
- <dep type="ext" rel="ge" name="pdo" version="0.9"/>
- </deps>
- </release>
-</package>
-<!-- vim: se ts=2 sw=2 et: -->
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE package SYSTEM "../pear/package.dtd">
+<package version="1.0">
+ <name>PDO_SQLITE</name>
+ <summary>SQLite v3 Interface driver for PDO</summary>
+ <maintainers>
+ <maintainer>
+ <user>wez</user>
+ <name>Wez Furlong</name>
+ <email>wez@php.net</email>
+ <role>lead</role>
+ </maintainer>
+ </maintainers>
+ <!-- configureoptions>
+ <configureoption name="with-pdo-sqlite" prompt="Path to your sqlite3 install"/>
+</configureoptions -->
+ <description>
+ This extension provides an SQLite v3 driver for PDO.
+ SQLite V3 is NOT compatible with the bundled SQLite 2 in PHP 5, but is a significant
+ step forwards, featuring complete utf-8 support, native support for blobs,
+ native support for prepared statements with bound parameters and improved
+ concurrency.
+ </description>
+ <license>PHP</license>
+ <release>
+ <state>beta</state>
+ <version>0.9</version>
+ <date>2005-07-27</date>
+
+ <notes>
+ You need to install the PDO core module before you can make use of this one.
+ This package includes a bundled SQLite 3 library.
+
+ Windows binary: http://snaps.php.net/win32/PECL_5_0/php_pdo_sqlite.dll
+
+ - Fixed PECL Bug #3452; problem when first row of a result set contains a NULL value.
+ - Upgraded bundled sqlite to 3.1.3
+ - setting PDO_ATTR_TIMEOUT controls the busy timeout
+ - Fixed PECL Bug #3391; cannot bind NULL parameters
+ - Fixed build problem when building the bundled sqlite library
+ </notes>
+
+ <filelist>
+ <file role="src" name="config.m4"/>
+ <file role="src" name="config.w32"/>
+ <file role="src" name="pdo_sqlite.c"/>
+ <file role="src" name="sqlite_driver.c"/>
+ <file role="src" name="sqlite_statement.c"/>
+ <file role="src" name="php_pdo_sqlite.h"/>
+ <file role="src" name="php_pdo_sqlite_int.h"/>
+
+ <file role="doc" name="CREDITS"/>
+
+ <dir name="sqlite">
+<file role="src" name="aclocal.m4"/>
+<file role="src" name="config.guess"/>
+<file role="src" name="config.sub"/>
+<file role="src" name="configure"/>
+<file role="src" name="configure.ac"/>
+<file role="src" name="install-sh"/>
+<file role="src" name="ltmain.sh"/>
+<file role="src" name="main.mk"/>
+<file role="src" name="Makefile.in"/>
+<file role="src" name="Makefile.linux-gcc"/>
+<file role="src" name="mkdll.sh"/>
+<file role="src" name="mkopcodec.awk"/>
+<file role="src" name="mkopcodeh.awk"/>
+<file role="src" name="mkso.sh"/>
+<file role="src" name="publish.sh"/>
+<file role="src" name="README"/>
+<file role="src" name="spec.template"/>
+<file role="src" name="sqlite.1"/>
+<file role="src" name="sqlite3.def"/>
+<file role="src" name="sqlite3.pc.in"/>
+<file role="src" name="sqlite.pc.in"/>
+<file role="src" name="VERSION"/>
+<dir name="src">
+<file role="src" name="attach.c"/>
+<file role="src" name="alter.c"/>
+<file role="src" name="auth.c"/>
+<file role="src" name="btree.c"/>
+<file role="src" name="btree.h"/>
+<file role="src" name="build.c"/>
+<file role="src" name="callback.c"/>
+<file role="src" name="date.c"/>
+<file role="src" name="delete.c"/>
+<file role="src" name="expr.c"/>
+<file role="src" name="experimental.c"/>
+<file role="src" name="func.c"/>
+<file role="src" name="hash.c"/>
+<file role="src" name="hash.h"/>
+<file role="src" name="insert.c"/>
+<file role="src" name="legacy.c"/>
+<file role="src" name="main.c"/>
+<file role="src" name="md5.c"/>
+<file role="src" name="keywordhash.h"/>
+<file role="src" name="opcodes.c"/>
+<file role="src" name="opcodes.h"/>
+<file role="src" name="os_common.h"/>
+<file role="src" name="os.h"/>
+<file role="src" name="os_mac.c"/>
+<file role="src" name="os_mac.h"/>
+<file role="src" name="os_test.c"/>
+<file role="src" name="os_test.h"/>
+<file role="src" name="os_unix.c"/>
+<file role="src" name="os_unix.h"/>
+<file role="src" name="os_win.c"/>
+<file role="src" name="os_win.h"/>
+<file role="src" name="pager.c"/>
+<file role="src" name="pager.h"/>
+<file role="src" name="parse.y"/>
+<file role="src" name="parse.c"/>
+<file role="src" name="parse.h"/>
+<file role="src" name="pragma.c"/>
+<file role="src" name="prepare.c"/>
+<file role="src" name="printf.c"/>
+<file role="src" name="random.c"/>
+<file role="src" name="select.c"/>
+<file role="src" name="shell.c"/>
+<file role="src" name="sqlite.h.in"/>
+<file role="src" name="sqliteInt.h"/>
+<file role="src" name="table.c"/>
+<file role="src" name="tclsqlite.c"/>
+<file role="src" name="test1.c"/>
+<file role="src" name="test2.c"/>
+<file role="src" name="test3.c"/>
+<file role="src" name="test4.c"/>
+<file role="src" name="test5.c"/>
+<file role="src" name="tokenize.c"/>
+<file role="src" name="trigger.c"/>
+<file role="src" name="update.c"/>
+<file role="src" name="utf.c"/>
+<file role="src" name="util.c"/>
+<file role="src" name="vacuum.c"/>
+<file role="src" name="vdbeapi.c"/>
+<file role="src" name="vdbeaux.c"/>
+<file role="src" name="vdbe.c"/>
+<file role="src" name="vdbe.h"/>
+<file role="src" name="vdbeInt.h"/>
+<file role="src" name="vdbemem.c"/>
+<file role="src" name="where.c"/>
+<file role="src" name="sqlite3ext.h"/>
+<file name="btmutex.c" role="src" />
+<file name="btreeInt.h" role="src" />
+<file name="experimental.c" role="src" />
+<file name="fault.c" role="src" />
+<file name="journal.c" role="src" />
+<file name="limits.h" role="src" />
+<file name="malloc.c" role="src" />
+<file name="mem1.c" role="src" />
+<file name="mutex.c" role="src" />
+<file name="mutex.h" role="src" />
+<file name="mutex_unix.c" role="src" />
+<file name="mutex_w32.c" role="src" />
+<file name="sqliteLimit.h" role="src" />
+<file name="vdbeblob.c" role="src" />
+</dir>
+
+<dir name="tool">
+<file role="src" name="diffdb.c"/>
+<file role="src" name="lemon.c"/>
+<file role="src" name="lempar.c"/>
+<file role="src" name="memleak2.awk"/>
+<file role="src" name="memleak3.tcl"/>
+<file role="src" name="memleak.awk"/>
+<file role="src" name="mkkeywordhash.c"/>
+<file role="src" name="mkopts.tcl"/>
+<file role="src" name="opcodeDoc.awk"/>
+<file role="src" name="report1.txt"/>
+<file role="src" name="showdb.c"/>
+<file role="src" name="showjournal.c"/>
+<file role="src" name="spaceanal.tcl"/>
+<file role="src" name="space_used.tcl"/>
+<file role="src" name="speedtest2.tcl"/>
+<file role="src" name="speedtest.tcl"/>
+</dir>
+
+ </dir>
+
+ </filelist>
+ <deps>
+ <dep type="php" rel="ge" version="5.0.3"/>
+ <dep type="ext" rel="ge" name="pdo" version="0.9"/>
+ </deps>
+ </release>
+</package>
+<!-- vim: se ts=2 sw=2 et: -->
diff --git a/ext/pdo_sqlite/sqlite/Makefile.in b/ext/pdo_sqlite/sqlite/Makefile.in
index 712823e5f6..6e01c4c269 100644
--- a/ext/pdo_sqlite/sqlite/Makefile.in
+++ b/ext/pdo_sqlite/sqlite/Makefile.in
@@ -26,7 +26,7 @@ BCC = @BUILD_CC@ @BUILD_CFLAGS@
# will run on the target platform. (BCC and TCC are usually the
# same unless your are cross-compiling.)
#
-TCC = @TARGET_CC@ @TARGET_CFLAGS@ -I. -I${TOP}/src
+TCC = @CC@ @CFLAGS@ -I. -I${TOP}/src
# Define -DNDEBUG to compile without debugging (i.e., for production usage)
# Omitting the define will cause extra debugging code to be inserted and
@@ -52,7 +52,7 @@ LIBREADLINE = @TARGET_READLINE_LIBS@
# Should the database engine be compiled threadsafe
#
-TCC += -DTHREADSAFE=@THREADSAFE@
+TCC += -DSQLITE_THREADSAFE=@SQLITE_THREADSAFE@
# The pthreads library if needed
#
@@ -63,7 +63,7 @@ LIBPTHREAD=@TARGET_THREAD_LIB@
TCC += -DSQLITE_THREAD_OVERRIDE_LOCK=@THREADSOVERRIDELOCKS@
# The fdatasync library
-TLIBS = @TARGET_LIBS@
+TLIBS = @LIBS@
# Flags controlling use of the in memory btree implementation
#
@@ -107,8 +107,8 @@ LIBTOOL = ./libtool
ALLOWRELEASE = @ALLOWRELEASE@
# libtool compile/link/install
-LTCOMPILE = $(LIBTOOL) --mode=compile $(TCC)
-LTLINK = $(LIBTOOL) --mode=link $(TCC)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(TCC)
+LTLINK = $(LIBTOOL) --mode=link $(TCC) @LDFLAGS@
LTINSTALL = $(LIBTOOL) --mode=install $(INSTALL)
# nawk compatible awk.
@@ -116,20 +116,21 @@ 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
+TCC += -DSQLITE_OMIT_LOAD_EXTENSION=1
# Object files for the SQLite library.
#
-LIBOBJ = alter.lo analyze.lo attach.lo auth.lo btree.lo build.lo \
+LIBOBJ = alter.lo analyze.lo attach.lo auth.lo btmutex.lo btree.lo build.lo \
callback.lo complete.lo date.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 \
+ delete.lo expr.lo fault.lo func.lo \
+ hash.lo journal.lo insert.lo loadext.lo \
+ main.lo malloc.lo mem1.lo mem2.lo mem3.lo mem4.lo mutex.lo \
+ mutex_os2.lo mutex_unix.lo mutex_w32.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 \
+ vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbefifo.lo vdbemem.lo \
where.lo utf.lo legacy.lo vtab.lo
# All of the source code files.
@@ -139,6 +140,7 @@ SRC = \
$(TOP)/src/analyze.c \
$(TOP)/src/attach.c \
$(TOP)/src/auth.c \
+ $(TOP)/src/btmutex.c \
$(TOP)/src/btree.c \
$(TOP)/src/btree.h \
$(TOP)/src/build.c \
@@ -147,13 +149,24 @@ SRC = \
$(TOP)/src/date.c \
$(TOP)/src/delete.c \
$(TOP)/src/expr.c \
+ $(TOP)/src/fault.c \
$(TOP)/src/func.c \
$(TOP)/src/hash.c \
$(TOP)/src/hash.h \
$(TOP)/src/insert.c \
+ $(TOP)/src/journal.c \
$(TOP)/src/legacy.c \
$(TOP)/src/loadext.c \
$(TOP)/src/main.c \
+ $(TOP)/src/malloc.c \
+ $(TOP)/src/mem1.c \
+ $(TOP)/src/mem2.c \
+ $(TOP)/src/mem3.c \
+ $(TOP)/src/mem4.c \
+ $(TOP)/src/mutex.c \
+ $(TOP)/src/mutex_os2.c \
+ $(TOP)/src/mutex_unix.c \
+ $(TOP)/src/mutex_w32.c \
$(TOP)/src/os.c \
$(TOP)/src/os_unix.c \
$(TOP)/src/os_win.c \
@@ -181,25 +194,46 @@ SRC = \
$(TOP)/src/vdbe.h \
$(TOP)/src/vdbeapi.c \
$(TOP)/src/vdbeaux.c \
+ $(TOP)/src/vdbeblob.c \
$(TOP)/src/vdbefifo.c \
$(TOP)/src/vdbemem.c \
$(TOP)/src/vdbeInt.h \
$(TOP)/src/vtab.c \
$(TOP)/src/where.c
+# Source code for extensions
+#
+SRC += \
+ $(TOP)/ext/fts1/fts1.c \
+ $(TOP)/ext/fts1/fts1.h \
+ $(TOP)/ext/fts1/fts1_hash.c \
+ $(TOP)/ext/fts1/fts1_hash.h \
+ $(TOP)/ext/fts1/fts1_porter.c \
+ $(TOP)/ext/fts1/fts1_tokenizer.h \
+ $(TOP)/ext/fts1/fts1_tokenizer1.c
+
+
# Source code to the test files.
#
TESTSRC = \
+ $(TOP)/src/attach.c \
$(TOP)/src/btree.c \
+ $(TOP)/src/build.c \
$(TOP)/src/date.c \
+ $(TOP)/src/expr.c \
$(TOP)/src/func.c \
+ $(TOP)/src/insert.c \
+ $(TOP)/src/malloc.c \
$(TOP)/src/os.c \
+ $(TOP)/src/os_os2.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/prepare.c \
$(TOP)/src/printf.c \
+ $(TOP)/src/random.c \
+ $(TOP)/src/select.c \
$(TOP)/src/test1.c \
$(TOP)/src/test2.c \
$(TOP)/src/test3.c \
@@ -208,22 +242,39 @@ TESTSRC = \
$(TOP)/src/test6.c \
$(TOP)/src/test7.c \
$(TOP)/src/test8.c \
+ $(TOP)/src/test9.c \
+ $(TOP)/src/test_autoext.c \
$(TOP)/src/test_async.c \
+ $(TOP)/src/test_btree.c \
+ $(TOP)/src/test_config.c \
+ $(TOP)/src/test_devsym.c \
+ $(TOP)/src/test_hexio.c \
+ $(TOP)/src/test_malloc.c \
$(TOP)/src/test_md5.c \
+ $(TOP)/src/test_onefile.c \
$(TOP)/src/test_schema.c \
$(TOP)/src/test_server.c \
$(TOP)/src/test_tclvar.c \
+ $(TOP)/src/test_thread.c \
+ $(TOP)/src/tokenize.c \
$(TOP)/src/utf.c \
$(TOP)/src/util.c \
$(TOP)/src/vdbe.c \
- $(TOP)/src/where.c
+ $(TOP)/src/vdbeapi.c \
+ $(TOP)/src/vdbeaux.c \
+ $(TOP)/src/vdbemem.c \
+ $(TOP)/src/where.c \
+ parse.c
# Header files used by all library source files.
#
HDR = \
sqlite3.h \
$(TOP)/src/btree.h \
+ $(TOP)/src/btreeInt.h \
$(TOP)/src/hash.h \
+ $(TOP)/src/sqliteLimit.h \
+ $(TOP)/src/mutex.h \
opcodes.h \
$(TOP)/src/os.h \
$(TOP)/src/os_common.h \
@@ -232,6 +283,13 @@ HDR = \
$(TOP)/src/vdbe.h \
parse.h
+# Header files used by extensions
+#
+HDR += \
+ $(TOP)/ext/fts1/fts1.h \
+ $(TOP)/ext/fts1/fts1_hash.h \
+ $(TOP)/ext/fts1/fts1_tokenizer.h
+
# Header files used by the VDBE submodule
#
VDBEHDR = \
@@ -280,12 +338,14 @@ target_source: $(SRC) parse.c opcodes.c keywordhash.h $(VDBEHDR)
cp $(SRC) $(VDBEHDR) tsrc
rm tsrc/sqlite.h.in tsrc/parse.y
cp parse.c opcodes.c keywordhash.h tsrc
- cp $(TOP)/sqlite3.def tsrc
+
+sqlite3.c: target_source $(TOP)/tool/mksqlite3c.tcl
+ tclsh $(TOP)/tool/mksqlite3c.tcl
# Rules to build the LEMON compiler generator
#
lemon$(BEXE): $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
- $(BCC) -o lemon $(TOP)/tool/lemon.c
+ $(BCC) -o lemon$(BEXE) $(TOP)/tool/lemon.c
cp $(TOP)/tool/lempar.c .
@@ -303,6 +363,9 @@ attach.lo: $(TOP)/src/attach.c $(HDR)
auth.lo: $(TOP)/src/auth.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/auth.c
+btmutex.lo: $(TOP)/src/btmutex.c $(HDR)
+ $(LTCOMPILE) -c $(TOP)/src/btmutex.c
+
btree.lo: $(TOP)/src/btree.c $(HDR) $(TOP)/src/pager.h
$(LTCOMPILE) -c $(TOP)/src/btree.c
@@ -324,6 +387,9 @@ delete.lo: $(TOP)/src/delete.c $(HDR)
expr.lo: $(TOP)/src/expr.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/expr.c
+fault.lo: $(TOP)/src/fault.c $(HDR)
+ $(LTCOMPILE) -c $(TOP)/src/fault.c
+
func.lo: $(TOP)/src/func.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/func.c
@@ -333,6 +399,9 @@ hash.lo: $(TOP)/src/hash.c $(HDR)
insert.lo: $(TOP)/src/insert.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/insert.c
+journal.lo: $(TOP)/src/journal.c $(HDR)
+ $(LTCOMPILE) -c $(TOP)/src/journal.c
+
legacy.lo: $(TOP)/src/legacy.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/legacy.c
@@ -342,6 +411,33 @@ loadext.lo: $(TOP)/src/loadext.c $(HDR)
main.lo: $(TOP)/src/main.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/main.c
+malloc.lo: $(TOP)/src/malloc.c $(HDR)
+ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/malloc.c
+
+mem1.lo: $(TOP)/src/mem1.c $(HDR)
+ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mem1.c
+
+mem2.lo: $(TOP)/src/mem2.c $(HDR)
+ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mem2.c
+
+mem3.lo: $(TOP)/src/mem3.c $(HDR)
+ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mem3.c
+
+mem4.lo: $(TOP)/src/mem4.c $(HDR)
+ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mem4.c
+
+mutex.lo: $(TOP)/src/mutex.c $(HDR)
+ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mutex.c
+
+mutex_os2.lo: $(TOP)/src/mutex_os2.c $(HDR)
+ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mutex_os2.c
+
+mutex_unix.lo: $(TOP)/src/mutex_unix.c $(HDR)
+ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mutex_unix.c
+
+mutex_w32.lo: $(TOP)/src/mutex_w32.c $(HDR)
+ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mutex_w32.c
+
pager.lo: $(TOP)/src/pager.c $(HDR) $(TOP)/src/pager.h
$(LTCOMPILE) -c $(TOP)/src/pager.c
@@ -373,9 +469,9 @@ parse.h: parse.c
parse.c: $(TOP)/src/parse.y lemon$(BEXE) $(TOP)/addopcodes.awk
cp $(TOP)/src/parse.y .
- ./lemon $(OPTS) parse.y
+ ./lemon$(BEXE) $(OPTS) parse.y
mv parse.h parse.h.temp
- awk -f $(TOP)/addopcodes.awk parse.h.temp >parse.h
+ $(NAWK) -f $(TOP)/addopcodes.awk parse.h.temp >parse.h
pragma.lo: $(TOP)/src/pragma.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/pragma.c
@@ -433,6 +529,9 @@ vdbeapi.lo: $(TOP)/src/vdbeapi.c $(VDBEHDR)
vdbeaux.lo: $(TOP)/src/vdbeaux.c $(VDBEHDR)
$(LTCOMPILE) -c $(TOP)/src/vdbeaux.c
+vdbeblob.lo: $(TOP)/src/vdbeblob.c $(VDBEHDR)
+ $(LTCOMPILE) -c $(TOP)/src/vdbeblob.c
+
vdbefifo.lo: $(TOP)/src/vdbefifo.c $(VDBEHDR)
$(LTCOMPILE) -c $(TOP)/src/vdbefifo.c
@@ -457,7 +556,8 @@ tclsqlite3: tclsqlite-shell.lo libsqlite3.la
testfixture$(TEXE): $(TOP)/src/tclsqlite.c libsqlite3.la $(TESTSRC)
$(LTLINK) -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 \
- $(TEMP_STORE) -o testfixture $(TESTSRC) $(TOP)/src/tclsqlite.c \
+ -DSQLITE_NO_SYNC=1 $(TEMP_STORE) \
+ -o testfixture $(TESTSRC) $(TOP)/src/tclsqlite.c \
libsqlite3.la $(LIBTCL)
@@ -480,172 +580,15 @@ sqlite3_analyzer$(TEXE): $(TOP)/src/tclsqlite.c libtclsqlite3.la \
-o sqlite3_analyzer$(EXE) $(TESTSRC) $(TOP)/src/tclsqlite.c \
libtclsqlite3.la $(LIBTCL)
-# Rules used to build documentation
-#
-arch.html: $(TOP)/www/arch.tcl
- tclsh $(TOP)/www/arch.tcl >arch.html
-
-arch2.gif: $(TOP)/www/arch2.gif
- cp $(TOP)/www/arch2.gif .
-
-autoinc.html: $(TOP)/www/autoinc.tcl
- tclsh $(TOP)/www/autoinc.tcl >autoinc.html
-
-c_interface.html: $(TOP)/www/c_interface.tcl
- tclsh $(TOP)/www/c_interface.tcl >c_interface.html
-
-capi3.html: $(TOP)/www/capi3.tcl
- tclsh $(TOP)/www/capi3.tcl >capi3.html
-capi3ref.html: $(TOP)/www/capi3ref.tcl
- tclsh $(TOP)/www/capi3ref.tcl >capi3ref.html
-
-changes.html: $(TOP)/www/changes.tcl
- tclsh $(TOP)/www/changes.tcl >changes.html
-
-compile.html: $(TOP)/www/compile.tcl
- tclsh $(TOP)/www/compile.tcl >compile.html
-
-copyright.html: $(TOP)/www/copyright.tcl
- tclsh $(TOP)/www/copyright.tcl >copyright.html
-
-copyright-release.html: $(TOP)/www/copyright-release.html
- cp $(TOP)/www/copyright-release.html .
-
-copyright-release.pdf: $(TOP)/www/copyright-release.pdf
- cp $(TOP)/www/copyright-release.pdf .
-
-common.tcl: $(TOP)/www/common.tcl
- cp $(TOP)/www/common.tcl .
-
-conflict.html: $(TOP)/www/conflict.tcl
- tclsh $(TOP)/www/conflict.tcl >conflict.html
-
-datatypes.html: $(TOP)/www/datatypes.tcl
- tclsh $(TOP)/www/datatypes.tcl >datatypes.html
-
-datatype3.html: $(TOP)/www/datatype3.tcl
- tclsh $(TOP)/www/datatype3.tcl >datatype3.html
-
-docs.html: $(TOP)/www/docs.tcl
- tclsh $(TOP)/www/docs.tcl >docs.html
-
-download.html: $(TOP)/www/download.tcl
- mkdir -p doc
- tclsh $(TOP)/www/download.tcl >download.html
-
-faq.html: $(TOP)/www/faq.tcl
- tclsh $(TOP)/www/faq.tcl >faq.html
-
-fileformat.html: $(TOP)/www/fileformat.tcl
- tclsh $(TOP)/www/fileformat.tcl >fileformat.html
-
-formatchng.html: $(TOP)/www/formatchng.tcl
- tclsh $(TOP)/www/formatchng.tcl >formatchng.html
-
-index.html: $(TOP)/www/index.tcl last_change
- tclsh $(TOP)/www/index.tcl >index.html
-
-lang.html: $(TOP)/www/lang.tcl
- tclsh $(TOP)/www/lang.tcl >lang.html
-
-pragma.html: $(TOP)/www/pragma.tcl
- tclsh $(TOP)/www/pragma.tcl >pragma.html
-
-lockingv3.html: $(TOP)/www/lockingv3.tcl
- tclsh $(TOP)/www/lockingv3.tcl >lockingv3.html
-
-oldnews.html: $(TOP)/www/oldnews.tcl
- tclsh $(TOP)/www/oldnews.tcl >oldnews.html
-
-omitted.html: $(TOP)/www/omitted.tcl
- tclsh $(TOP)/www/omitted.tcl >omitted.html
-
-opcode.html: $(TOP)/www/opcode.tcl $(TOP)/src/vdbe.c
- tclsh $(TOP)/www/opcode.tcl $(TOP)/src/vdbe.c >opcode.html
-
-mingw.html: $(TOP)/www/mingw.tcl
- tclsh $(TOP)/www/mingw.tcl >mingw.html
-
-nulls.html: $(TOP)/www/nulls.tcl
- tclsh $(TOP)/www/nulls.tcl >nulls.html
-
-quickstart.html: $(TOP)/www/quickstart.tcl
- tclsh $(TOP)/www/quickstart.tcl >quickstart.html
-
-speed.html: $(TOP)/www/speed.tcl
- tclsh $(TOP)/www/speed.tcl >speed.html
-
-sqlite.gif: $(TOP)/art/SQLite.gif
- cp $(TOP)/art/SQLite.gif sqlite.gif
-
-sqlite.html: $(TOP)/www/sqlite.tcl
- tclsh $(TOP)/www/sqlite.tcl >sqlite.html
-
-support.html: $(TOP)/www/support.tcl
- tclsh $(TOP)/www/support.tcl >support.html
-
-tclsqlite.html: $(TOP)/www/tclsqlite.tcl
- tclsh $(TOP)/www/tclsqlite.tcl >tclsqlite.html
-
-vdbe.html: $(TOP)/www/vdbe.tcl
- tclsh $(TOP)/www/vdbe.tcl >vdbe.html
-
-version3.html: $(TOP)/www/version3.tcl
- tclsh $(TOP)/www/version3.tcl >version3.html
-
-
-# Files to be published on the website.
-#
-DOC = \
- arch.html \
- arch2.gif \
- autoinc.html \
- c_interface.html \
- capi3.html \
- capi3ref.html \
- changes.html \
- compile.html \
- copyright.html \
- copyright-release.html \
- copyright-release.pdf \
- conflict.html \
- datatypes.html \
- datatype3.html \
- docs.html \
- download.html \
- faq.html \
- fileformat.html \
- formatchng.html \
- index.html \
- lang.html \
- lockingv3.html \
- mingw.html \
- nulls.html \
- oldnews.html \
- omitted.html \
- opcode.html \
- pragma.html \
- quickstart.html \
- speed.html \
- sqlite.gif \
- sqlite.html \
- support.html \
- tclsqlite.html \
- vdbe.html \
- version3.html
-
-doc: common.tcl $(DOC)
- mkdir -p doc
- mv $(DOC) doc
-
-install: sqlite3 libsqlite3.la sqlite3.h ${HAVE_TCL:1=tcl_install}
+install: sqlite3$(BEXE) libsqlite3.la sqlite3.h ${HAVE_TCL:1=tcl_install}
$(INSTALL) -d $(DESTDIR)$(libdir)
$(LTINSTALL) libsqlite3.la $(DESTDIR)$(libdir)
$(INSTALL) -d $(DESTDIR)$(exec_prefix)/bin
- $(LTINSTALL) sqlite3 $(DESTDIR)$(exec_prefix)/bin
+ $(LTINSTALL) sqlite3$(BEXE) $(DESTDIR)$(exec_prefix)/bin
$(INSTALL) -d $(DESTDIR)$(prefix)/include
$(INSTALL) -m 0644 sqlite3.h $(DESTDIR)$(prefix)/include
+ $(INSTALL) -m 0644 $(TOP)/src/sqlite3ext.h $(DESTDIR)$(prefix)/include
$(INSTALL) -d $(DESTDIR)$(libdir)/pkgconfig;
$(INSTALL) -m 0644 sqlite3.pc $(DESTDIR)$(libdir)/pkgconfig;
@@ -661,30 +604,26 @@ clean:
rm -f $(PUBLISH)
rm -f *.da *.bb *.bbg gmon.out
rm -f testfixture$(TEXE) test.db
- rm -rf doc
rm -f common.tcl
- rm -f sqlite3.dll sqlite3.lib
+ rm -f sqlite3.dll sqlite3.lib sqlite3.def
+
+distclean: clean
+ rm -f config.log config.status libtool Makefile config.h sqlite3.pc
#
-# Windows section; all this funky .dll stuff ;-)
+# Windows section
#
dll: sqlite3.dll
REAL_LIBOBJ = $(LIBOBJ:%.lo=.libs/%.o)
-sqlite3.dll: $(LIBOBJ) $(TOP)/sqlite3.def
- dllwrap --dllname sqlite3.dll --def $(TOP)/sqlite3.def $(REAL_LIBOBJ)
- strip sqlite3.dll
+$(REAL_LIBOBJ): $(LIBOBJ)
-#target for dll import libraries
-implib: sqlite3.lib
+sqlite3.def: $(REAL_LIBOBJ)
+ echo 'EXPORTS' >sqlite3.def
+ nm $(REAL_LIBOBJ) | grep ' T ' | grep ' _sqlite3_' \
+ | sed 's/^.* _//' >>sqlite3.def
-#make Borland C++ and/or Microsoft VC import library for the dll
-# ignore any errors (usually due to missing programs)
-sqlite3.lib: sqlite3.dll
- -impdef -a sqlite3.def sqlite3.dll
- -implib sqlite3.lib sqlite3.def
- -lib /machine:i386 /def:$(TOP)/sqlite3.def
-
-distclean: clean
- rm -f config.log config.status libtool Makefile config.h
+sqlite3.dll: $(REAL_LIBOBJ) sqlite3.def
+ $(TCC) -shared -o sqlite3.dll sqlite3.def \
+ -Wl,"--strip-all" $(REAL_LIBOBJ)
diff --git a/ext/pdo_sqlite/sqlite/Makefile.linux-gcc b/ext/pdo_sqlite/sqlite/Makefile.linux-gcc
index c865024b44..2bb618489a 100644
--- a/ext/pdo_sqlite/sqlite/Makefile.linux-gcc
+++ b/ext/pdo_sqlite/sqlite/Makefile.linux-gcc
@@ -104,6 +104,10 @@ LIBTCL = /home/drh/tcltk/8.4linux/libtcl8.4g.a -lm -ldl
#LIBTCL = /home/drh/tcltk/8.4win/libtcl84s.a -lmsvcrt
#LIBTCL = /home/drh/tcltk/8.3hpux/libtcl8.3.a -ldld -lm -lc
+#### Additional objects for SQLite library when TCL support is enabled.
+#TCLOBJ =
+TCLOBJ = tclsqlite.o
+
#### Compiler options needed for programs that use the readline() library.
#
READLINE_FLAGS =
@@ -114,12 +118,6 @@ READLINE_FLAGS =
LIBREADLINE =
#LIBREADLINE = -static -lreadline -ltermcap
-#### Should the database engine assume text is coded as UTF-8 or iso8859?
-#
-# ENCODING = UTF8
-ENCODING = ISO8859
-
-
#### Which "awk" program provides nawk compatibilty
#
# NAWK = nawk
diff --git a/ext/pdo_sqlite/sqlite/VERSION b/ext/pdo_sqlite/sqlite/VERSION
index 86fb650440..c49282585a 100644
--- a/ext/pdo_sqlite/sqlite/VERSION
+++ b/ext/pdo_sqlite/sqlite/VERSION
@@ -1 +1 @@
-3.3.7
+3.5.6
diff --git a/ext/pdo_sqlite/sqlite/aclocal.m4 b/ext/pdo_sqlite/sqlite/aclocal.m4
index b50b61e56a..27b6c66b39 100644
--- a/ext/pdo_sqlite/sqlite/aclocal.m4
+++ b/ext/pdo_sqlite/sqlite/aclocal.m4
@@ -1,7 +1,7 @@
-# generated automatically by aclocal 1.8.2 -*- Autoconf -*-
+# generated automatically by aclocal 1.10 -*- Autoconf -*-
-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
-# Free Software Foundation, Inc.
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -13,8 +13,7 @@
# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
-# serial 47 AC_PROG_LIBTOOL
-# Debian $Rev: 192 $
+# serial 48 AC_PROG_LIBTOOL
# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED)
@@ -124,7 +123,7 @@ esac
# Sed substitution that helps us do robust quoting. It backslashifies
# metacharacters that are still active within double-quoted strings.
-Xsed='sed -e s/^X//'
+Xsed='sed -e 1s/^X//'
[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g']
# Same as above, but do not quote variable references.
@@ -144,14 +143,14 @@ rm="rm -f"
default_ofile=libtool
can_build_shared=yes
-# All known linkers require a `.a' archive for static linking (except M$VC,
+# All known linkers require a `.a' archive for static linking (except MSVC,
# which needs '.lib').
libext=a
ltmain="$ac_aux_dir/ltmain.sh"
ofile="$default_ofile"
with_gnu_ld="$lt_cv_prog_gnu_ld"
-AC_CHECK_TOOL(AR, ar, AC_CHECK_TOOL(AR, emxomfar, false))
+AC_CHECK_TOOL(AR, ar, false)
AC_CHECK_TOOL(RANLIB, ranlib, :)
AC_CHECK_TOOL(STRIP, strip, :)
@@ -164,6 +163,7 @@ test -z "$AR_FLAGS" && AR_FLAGS=cru
test -z "$AS" && AS=as
test -z "$CC" && CC=cc
test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
test -z "$DLLTOOL" && DLLTOOL=dlltool
test -z "$LD" && LD=ld
test -z "$LN_S" && LN_S="ln -s"
@@ -183,15 +183,17 @@ old_postuninstall_cmds=
if test -n "$RANLIB"; then
case $host_os in
openbsd*)
- old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds"
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
;;
*)
- old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
;;
esac
old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
fi
+_LT_CC_BASENAME([$compiler])
+
# Only perform the check for file, if the check method requires it
case $deplibs_check_method in
file_magic*)
@@ -217,6 +219,14 @@ AC_ARG_WITH([pic],
[pic_mode=default])
test -z "$pic_mode" && pic_mode=default
+# Check if we have a version mismatch between libtool.m4 and ltmain.sh.
+#
+# Note: This should be in AC_LIBTOOL_SETUP, _after_ $ltmain have been defined.
+# We also should do it _before_ AC_LIBTOOL_LANG_C_CONFIG that actually
+# calls AC_LIBTOOL_CONFIG and creates libtool.
+#
+_LT_VERSION_CHECK
+
# Use C for the default configuration in the libtool script
tagname=
AC_LIBTOOL_LANG_C_CONFIG
@@ -224,6 +234,41 @@ _LT_AC_TAGCONFIG
])# AC_LIBTOOL_SETUP
+# _LT_VERSION_CHECK
+# -----------------
+AC_DEFUN([_LT_VERSION_CHECK],
+[AC_MSG_CHECKING([for correct ltmain.sh version])
+if test "x$ltmain" = "x" ; then
+ AC_MSG_RESULT(no)
+ AC_MSG_ERROR([
+
+*** @<:@Gentoo@:>@ sanity check failed! ***
+*** \$ltmain is not defined, please check the patch for consistency! ***
+])
+fi
+gentoo_lt_version="1.5.22"
+gentoo_ltmain_version=`sed -n '/^[[ ]]*VERSION=/{s/^[[ ]]*VERSION=//;p;q;}' "$ltmain"`
+if test "x$gentoo_lt_version" != "x$gentoo_ltmain_version" ; then
+ AC_MSG_RESULT(no)
+ AC_MSG_ERROR([
+
+*** @<:@Gentoo@:>@ sanity check failed! ***
+*** libtool.m4 and ltmain.sh have a version mismatch! ***
+*** (libtool.m4 = $gentoo_lt_version, ltmain.sh = $gentoo_ltmain_version) ***
+
+Please run:
+
+ libtoolize --copy --force
+
+if appropriate, please contact the maintainer of this
+package (or your distribution) for help.
+])
+else
+ AC_MSG_RESULT(yes)
+fi
+])# _LT_VERSION_CHECK
+
+
# _LT_AC_SYS_COMPILER
# -------------------
AC_DEFUN([_LT_AC_SYS_COMPILER],
@@ -232,11 +277,56 @@ AC_DEFUN([_LT_AC_SYS_COMPILER],
# If no C compiler was specified, use CC.
LTCC=${LTCC-"$CC"}
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
# Allow CC to be a program name with arguments.
compiler=$CC
])# _LT_AC_SYS_COMPILER
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+AC_DEFUN([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+ case $cc_temp in
+ compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+ distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+])
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+AC_DEFUN([_LT_COMPILER_BOILERPLATE],
+[ac_outfile=conftest.$ac_objext
+printf "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$rm conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+AC_DEFUN([_LT_LINKER_BOILERPLATE],
+[ac_outfile=conftest.$ac_objext
+printf "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$rm conftest*
+])# _LT_LINKER_BOILERPLATE
+
+
# _LT_AC_SYS_LIBPATH_AIX
# ----------------------
# Links a minimal program and checks the executable
@@ -309,15 +399,15 @@ fi
# The HP-UX ksh and POSIX shell print the target directory to stdout
# if CDPATH is set.
-if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
if test -z "$ECHO"; then
if test "X${echo_test_string+set}" != Xset; then
# find a string as large as possible, as long as the shell can cope with it
for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
# expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
- if (echo_test_string="`eval $cmd`") 2>/dev/null &&
- echo_test_string="`eval $cmd`" &&
+ if (echo_test_string=`eval $cmd`) 2>/dev/null &&
+ echo_test_string=`eval $cmd` &&
(test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
then
break
@@ -486,7 +576,7 @@ x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
# Find out which ABI we are using.
echo 'int i;' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
- case "`/usr/bin/file conftest.o`" in
+ case `/usr/bin/file conftest.o` in
*32-bit*)
case $host in
x86_64-*linux*)
@@ -537,6 +627,22 @@ x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
CFLAGS="$SAVE_CFLAGS"
fi
;;
+sparc*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*) LD="${LD-ld} -m elf64_sparc" ;;
+ *) LD="${LD-ld} -64" ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
[*-*-cygwin* | *-*-mingw* | *-*-pw32*)
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
@@ -568,7 +674,7 @@ AC_CACHE_CHECK([$1], [$2],
# with a dollar sign (not a hyphen), so the echo should work correctly.
# The option is referenced via a variable to avoid confusing sed.
lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
@@ -578,8 +684,10 @@ AC_CACHE_CHECK([$1], [$2],
echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
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
- if test ! -s conftest.err; then
+ # So say no if there are warnings other than the usual output.
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
$2=yes
fi
fi
@@ -605,11 +713,16 @@ AC_DEFUN([AC_LIBTOOL_LINKER_OPTION],
LDFLAGS="$LDFLAGS $3"
printf "$lt_simple_link_test_code" > conftest.$ac_ext
if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
- # The compiler can only warn and ignore the option if not recognized
+ # The linker can only warn and ignore the option if not recognized
# So say no if there are warnings
if test -s conftest.err; then
# Append any errors to the config.log.
cat conftest.err 1>&AS_MESSAGE_LOG_FD
+ $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
else
$2=yes
fi
@@ -633,7 +746,7 @@ AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN],
AC_MSG_CHECKING([the maximum length of command line arguments])
AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
i=0
- testring="ABCD"
+ teststring="ABCD"
case $build_os in
msdosdjgpp*)
@@ -668,20 +781,64 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
lt_cv_sys_max_cmd_len=8192;
;;
- *)
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
# If test is not a shell built-in, we'll probably end up computing a
# maximum length that is only half of the actual maximum length, but
# we can't tell.
- while (test "X"`$CONFIG_SHELL [$]0 --fallback-echo "X$testring" 2>/dev/null` \
- = "XX$testring") >/dev/null 2>&1 &&
- new_result=`expr "X$testring" : ".*" 2>&1` &&
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \
+ = "XX$teststring") >/dev/null 2>&1 &&
+ new_result=`expr "X$teststring" : ".*" 2>&1` &&
lt_cv_sys_max_cmd_len=$new_result &&
test $i != 17 # 1/2 MB should be enough
do
i=`expr $i + 1`
- testring=$testring$testring
+ teststring=$teststring$teststring
done
- testring=
+ teststring=
# Add a significant safety factor because C++ compilers can tack on massive
# amounts of additional arguments before passing them to the linker.
# It appears as though 1/2 is a usable value.
@@ -698,7 +855,7 @@ fi
# _LT_AC_CHECK_DLFCN
-# --------------------
+# ------------------
AC_DEFUN([_LT_AC_CHECK_DLFCN],
[AC_CHECK_HEADERS(dlfcn.h)dnl
])# _LT_AC_CHECK_DLFCN
@@ -706,7 +863,7 @@ AC_DEFUN([_LT_AC_CHECK_DLFCN],
# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
-# ------------------------------------------------------------------
+# ---------------------------------------------------------------------
AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF],
[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
if test "$cross_compiling" = yes; then :
@@ -772,17 +929,19 @@ int main ()
else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
/* dlclose (self); */
}
+ else
+ puts (dlerror ());
exit (status);
}]
EOF
if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
- (./conftest; exit; ) 2>/dev/null
+ (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
lt_status=$?
case x$lt_status in
x$lt_dlno_uscore) $1 ;;
x$lt_dlneed_uscore) $2 ;;
- x$lt_unknown|x*) $3 ;;
+ x$lt_dlunknown|x*) $3 ;;
esac
else :
# compilation failed
@@ -794,7 +953,7 @@ rm -fr conftest*
# AC_LIBTOOL_DLOPEN_SELF
-# -------------------
+# ----------------------
AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF],
[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
if test "x$enable_dlopen" != xyes; then
@@ -865,7 +1024,7 @@ else
test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
save_LDFLAGS="$LDFLAGS"
- eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
save_LIBS="$LIBS"
LIBS="$lt_cv_dlopen_libs $LIBS"
@@ -878,7 +1037,7 @@ else
])
if test "x$lt_cv_dlopen_self" = xyes; then
- LDFLAGS="$LDFLAGS $link_static_flag"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
lt_cv_dlopen_self_static, [dnl
_LT_AC_TRY_DLOPEN_SELF(
@@ -926,7 +1085,7 @@ AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
# Note that $ac_compile itself does not contain backslashes and begins
# with a dollar sign (not a hyphen), so the echo should work correctly.
lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
@@ -938,11 +1097,13 @@ AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
- if test ! -s out/conftest.err; then
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
fi
fi
- chmod u+w .
+ chmod u+w . 2>&AS_MESSAGE_LOG_FD
$rm conftest*
# SGI C++ compiler will create directory out/ii_files/ for
# template instantiation
@@ -1006,8 +1167,8 @@ AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH],
[AC_MSG_CHECKING([how to hardcode library paths into programs])
_LT_AC_TAGVAR(hardcode_action, $1)=
if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \
- test -n "$_LT_AC_TAGVAR(runpath_var $1)" || \
- test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)"="Xyes" ; then
+ test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \
+ test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
# We can hardcode non-existant directories.
if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no &&
@@ -1077,7 +1238,7 @@ AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER],
library_names_spec=
libname_spec='lib$name'
soname_spec=
-shrext=".so"
+shrext_cmds=".so"
postinstall_cmds=
postuninstall_cmds=
finish_cmds=
@@ -1174,7 +1335,7 @@ beos*)
shlibpath_var=LIBRARY_PATH
;;
-bsdi4*)
+bsdi[[45]]*)
version_type=linux
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
@@ -1190,7 +1351,7 @@ bsdi4*)
cygwin* | mingw* | pw32*)
version_type=windows
- shrext=".dll"
+ shrext_cmds=".dll"
need_version=no
need_lib_prefix=no
@@ -1202,7 +1363,8 @@ cygwin* | mingw* | pw32*)
dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
dldir=$destdir/`dirname \$dlpath`~
test -d \$dldir || mkdir -p \$dldir~
- $install_prog $dir/$dlname \$dldir/$dlname'
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname'
postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
dlpath=$dir/\$dldll~
$rm \$dlpath'
@@ -1232,11 +1394,35 @@ cygwin* | mingw* | pw32*)
;;
pw32*)
# pw32 DLLs use 'pw' prefix rather than 'lib'
- library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
;;
esac
;;
+ linux*)
+ if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ [01].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+ if test $supports_anon_versioning = yes; then
+ archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~
+cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+$echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ else
+ $archive_expsym_cmds="$archive_cmds"
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
*)
library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
;;
@@ -1255,7 +1441,7 @@ darwin* | rhapsody*)
soname_spec='${libname}${release}${major}$shared_ext'
shlibpath_overrides_runpath=yes
shlibpath_var=DYLD_LIBRARY_PATH
- shrext='$(test .$module = .yes && echo .so || echo .dylib)'
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
# Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
if test "$GCC" = yes; then
sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
@@ -1290,9 +1476,25 @@ kfreebsd*-gnu)
dynamic_linker='GNU ld.so'
;;
-freebsd*)
- objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
- version_type=freebsd-$objformat
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[[123]]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ # Handle Gentoo/FreeBSD as it was Linux
+ case $host_vendor in
+ gentoo)
+ version_type=linux ;;
+ *)
+ version_type=freebsd-$objformat ;;
+ esac
+
case $version_type in
freebsd-elf*)
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
@@ -1303,20 +1505,31 @@ freebsd*)
library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
need_version=yes
;;
+ linux)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ need_lib_prefix=no
+ need_version=no
+ ;;
esac
shlibpath_var=LD_LIBRARY_PATH
case $host_os in
freebsd2*)
shlibpath_overrides_runpath=yes
;;
- freebsd3.[01]* | freebsdelf3.[01]*)
+ freebsd3.[[01]]* | freebsdelf3.[[01]]*)
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
;;
- *) # from 3.2 on
+ freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
;;
+ freebsd*) # from 4.6 on
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
esac
;;
@@ -1336,9 +1549,9 @@ hpux9* | hpux10* | hpux11*)
version_type=sunos
need_lib_prefix=no
need_version=no
- case "$host_cpu" in
+ case $host_cpu in
ia64*)
- shrext='.so'
+ shrext_cmds='.so'
hardcode_into_libs=yes
dynamic_linker="$host_os dld.so"
shlibpath_var=LD_LIBRARY_PATH
@@ -1353,7 +1566,7 @@ hpux9* | hpux10* | hpux11*)
sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
hppa*64*)
- shrext='.sl'
+ shrext_cmds='.sl'
hardcode_into_libs=yes
dynamic_linker="$host_os dld.sl"
shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
@@ -1364,7 +1577,7 @@ hpux9* | hpux10* | hpux11*)
sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
*)
- shrext='.sl'
+ shrext_cmds='.sl'
dynamic_linker="$host_os dld.sl"
shlibpath_var=SHLIB_PATH
shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
@@ -1376,6 +1589,18 @@ hpux9* | hpux10* | hpux11*)
postinstall_cmds='chmod 555 $lib'
;;
+interix3*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
irix5* | irix6* | nonstopux*)
case $host_os in
nonstopux*) version_type=nonstopux ;;
@@ -1435,8 +1660,8 @@ linux*)
# Append ld.so.conf contents to the search path
if test -f /etc/ld.so.conf; then
- ld_extra=`$SED -e 's/[:,\t]/ /g;s/=[^=]*$//;s/=[^= ]* / /g' /etc/ld.so.conf`
- sys_lib_dlsearch_path_spec="/lib /usr/lib $ld_extra"
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
fi
# We used to test for /lib/ld.so.1 and disable shared libraries on
@@ -1497,8 +1722,13 @@ nto-qnx*)
openbsd*)
version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
need_lib_prefix=no
- need_version=yes
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
shlibpath_var=LD_LIBRARY_PATH
@@ -1518,7 +1748,7 @@ openbsd*)
os2*)
libname_spec='$name'
- shrext=".dll"
+ shrext_cmds=".dll"
need_lib_prefix=no
library_names_spec='$libname${shared_ext} $libname.a'
dynamic_linker='OS/2 ld.exe'
@@ -1536,13 +1766,6 @@ osf3* | osf4* | osf5*)
sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
;;
-sco3.2v5*)
- version_type=osf
- soname_spec='${libname}${release}${shared_ext}$major'
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
solaris*)
version_type=linux
need_lib_prefix=no
@@ -1568,7 +1791,7 @@ sunos4*)
need_version=yes
;;
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+sysv4 | sysv4.3*)
version_type=linux
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
@@ -1601,6 +1824,29 @@ sysv4*MP*)
fi
;;
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ shlibpath_overrides_runpath=no
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ shlibpath_overrides_runpath=yes
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
uts4*)
version_type=linux
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
@@ -1614,6 +1860,11 @@ uts4*)
esac
AC_MSG_RESULT([$dynamic_linker])
test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
])# AC_LIBTOOL_SYS_DYNAMIC_LINKER
@@ -1638,6 +1889,9 @@ if test -f "$ltmain" && test -n "$tagnames"; then
AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile'])
fi
fi
+ if test -z "$LTCFLAGS"; then
+ eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`"
+ fi
# Extract list of available tagged configurations in $ofile.
# Note that this assumes the entire list is on one line.
@@ -1664,7 +1918,9 @@ if test -f "$ltmain" && test -n "$tagnames"; then
case $tagname in
CXX)
- if test -n "$CXX" && test "X$CXX" != "Xno"; then
+ if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
AC_LIBTOOL_LANG_CXX_CONFIG
else
tagname=""
@@ -1726,7 +1982,7 @@ AC_DEFUN([AC_LIBTOOL_DLOPEN],
# AC_LIBTOOL_WIN32_DLL
# --------------------
-# declare package support for building win32 dll's
+# declare package support for building win32 DLLs
AC_DEFUN([AC_LIBTOOL_WIN32_DLL],
[AC_BEFORE([$0], [AC_LIBTOOL_SETUP])
])# AC_LIBTOOL_WIN32_DLL
@@ -1764,7 +2020,7 @@ AC_ARG_ENABLE([shared],
# AC_DISABLE_SHARED
# -----------------
-#- set the default shared flag to --disable-shared
+# set the default shared flag to --disable-shared
AC_DEFUN([AC_DISABLE_SHARED],
[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
AC_ENABLE_SHARED(no)
@@ -1900,7 +2156,7 @@ dnl not every word. This closes a longstanding sh security hole.
if test -n "$file_magic_test_file"; then
case $deplibs_check_method in
"file_magic "*)
- file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
$EGREP "$file_magic_regex" > /dev/null; then
@@ -2010,7 +2266,7 @@ AC_CACHE_VAL(lt_cv_path_LD,
if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
lt_cv_path_LD="$ac_dir/$ac_prog"
# Check to see if the program is GNU ld. I'd rather use --version,
- # but apparently some GNU ld's only accept -v.
+ # but apparently some variants of GNU ld only accept -v.
# Break only if it was the GNU/non-GNU ld that we prefer.
case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
*GNU* | *'with BFD'*)
@@ -2042,7 +2298,7 @@ AC_PROG_LD_GNU
AC_DEFUN([AC_PROG_LD_GNU],
[AC_REQUIRE([AC_PROG_EGREP])dnl
AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
-[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
case `$LD -v 2>&1 </dev/null` in
*GNU* | *'with BFD'*)
lt_cv_prog_gnu_ld=yes
@@ -2069,6 +2325,15 @@ case $reload_flag in
*) reload_flag=" $reload_flag" ;;
esac
reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
])# AC_PROG_LD_RELOAD_FLAG
@@ -2102,21 +2367,21 @@ beos*)
lt_cv_deplibs_check_method=pass_all
;;
-bsdi4*)
+bsdi[[45]]*)
lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
lt_cv_file_magic_cmd='/usr/bin/file -L'
lt_cv_file_magic_test_file=/shlib/libc.so
;;
cygwin*)
- # win32_libid is a shell function defined in ltmain.sh
+ # func_win32_libid is a shell function defined in ltmain.sh
lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
- lt_cv_file_magic_cmd='win32_libid'
+ lt_cv_file_magic_cmd='func_win32_libid'
;;
mingw* | pw32*)
# Base MSYS/MinGW do not provide the 'file' command needed by
- # win32_libid shell function, so use a weaker test based on 'objdump'.
+ # func_win32_libid shell function, so use a weaker test based on 'objdump'.
lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
lt_cv_file_magic_cmd='$OBJDUMP -f'
;;
@@ -2125,13 +2390,13 @@ darwin* | rhapsody*)
lt_cv_deplibs_check_method=pass_all
;;
-freebsd* | kfreebsd*-gnu)
+freebsd* | kfreebsd*-gnu | dragonfly*)
if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
case $host_cpu in
i*86 )
# Not sure whether the presence of OpenBSD here was a mistake.
# Let's accept both of them until this is cleared up.
- lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library'
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
lt_cv_file_magic_cmd=/usr/bin/file
lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
;;
@@ -2147,7 +2412,7 @@ gnu*)
hpux10.20* | hpux11*)
lt_cv_file_magic_cmd=/usr/bin/file
- case "$host_cpu" in
+ case $host_cpu in
ia64*)
lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
@@ -2163,6 +2428,11 @@ hpux10.20* | hpux11*)
esac
;;
+interix3*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+ ;;
+
irix5* | irix6* | nonstopux*)
case $LD in
*-32|*"-32 ") libmagic=32-bit;;
@@ -2178,7 +2448,7 @@ linux*)
lt_cv_deplibs_check_method=pass_all
;;
-netbsd* | knetbsd*-gnu)
+netbsd*)
if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
else
@@ -2197,12 +2467,10 @@ nto-qnx*)
;;
openbsd*)
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object'
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
else
- lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library'
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
fi
;;
@@ -2210,15 +2478,11 @@ osf3* | osf4* | osf5*)
lt_cv_deplibs_check_method=pass_all
;;
-sco3.2v5*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
solaris*)
lt_cv_deplibs_check_method=pass_all
;;
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+sysv4 | sysv4.3*)
case $host_vendor in
motorola)
lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
@@ -2239,10 +2503,13 @@ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
siemens)
lt_cv_deplibs_check_method=pass_all
;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
esac
;;
-sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7* | sysv4*uw2*)
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
lt_cv_deplibs_check_method=pass_all
;;
esac
@@ -2262,36 +2529,43 @@ AC_DEFUN([AC_PROG_NM],
# Let the user override the test.
lt_cv_path_NM="$NM"
else
- lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
- for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
- IFS="$lt_save_ifs"
- test -z "$ac_dir" && ac_dir=.
- tmp_nm="$ac_dir/${ac_tool_prefix}nm"
- if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
- # Check to see if the nm accepts a BSD-compat flag.
- # Adding the `sed 1q' prevents false positives on HP-UX, which says:
- # nm: unknown option "B" ignored
- # Tru64's nm complains that /dev/null is an invalid object file
- case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
- */dev/null* | *'Invalid file or object type'*)
- lt_cv_path_NM="$tmp_nm -B"
- break
- ;;
- *)
- case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
- */dev/null*)
- lt_cv_path_NM="$tmp_nm -p"
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
break
;;
*)
- lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
- continue # so that we can try to find one that supports BSD flags
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
;;
esac
- esac
- fi
+ fi
+ done
+ IFS="$lt_save_ifs"
done
- IFS="$lt_save_ifs"
test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
fi])
NM="$lt_cv_path_NM"
@@ -2323,13 +2597,13 @@ esac
# -----------------------------------
# sets LIBLTDL to the link flags for the libltdl convenience library and
# LTDLINCL to the include flags for the libltdl header and adds
-# --enable-ltdl-convenience to the configure arguments. Note that LIBLTDL
-# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If
-# DIRECTORY is not provided, it is assumed to be `libltdl'. LIBLTDL will
-# be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed with
-# '${top_srcdir}/' (note the single quotes!). If your package is not
-# flat and you're not using automake, define top_builddir and
-# top_srcdir appropriately in the Makefiles.
+# --enable-ltdl-convenience to the configure arguments. Note that
+# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided,
+# it is assumed to be `libltdl'. LIBLTDL will be prefixed with
+# '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/'
+# (note the single quotes!). If your package is not flat and you're not
+# using automake, define top_builddir and top_srcdir appropriately in
+# the Makefiles.
AC_DEFUN([AC_LIBLTDL_CONVENIENCE],
[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
case $enable_ltdl_convenience in
@@ -2348,13 +2622,13 @@ AC_DEFUN([AC_LIBLTDL_CONVENIENCE],
# -----------------------------------
# sets LIBLTDL to the link flags for the libltdl installable library and
# LTDLINCL to the include flags for the libltdl header and adds
-# --enable-ltdl-install to the configure arguments. Note that LIBLTDL
-# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If
-# DIRECTORY is not provided and an installed libltdl is not found, it is
-# assumed to be `libltdl'. LIBLTDL will be prefixed with '${top_builddir}/'
-# and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single
-# quotes!). If your package is not flat and you're not using automake,
-# define top_builddir and top_srcdir appropriately in the Makefiles.
+# --enable-ltdl-install to the configure arguments. Note that
+# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided,
+# and an installed libltdl is not found, it is assumed to be `libltdl'.
+# LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with
+# '${top_srcdir}/' (note the single quotes!). If your package is not
+# flat and you're not using automake, define top_builddir and top_srcdir
+# appropriately in the Makefiles.
# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
AC_DEFUN([AC_LIBLTDL_INSTALLABLE],
[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
@@ -2392,10 +2666,21 @@ AC_DEFUN([AC_LIBTOOL_CXX],
# ---------------
AC_DEFUN([_LT_AC_LANG_CXX],
[AC_REQUIRE([AC_PROG_CXX])
-AC_REQUIRE([AC_PROG_CXXCPP])
+AC_REQUIRE([_LT_AC_PROG_CXXCPP])
_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX])
])# _LT_AC_LANG_CXX
+# _LT_AC_PROG_CXXCPP
+# ------------------
+AC_DEFUN([_LT_AC_PROG_CXXCPP],
+[
+AC_REQUIRE([AC_PROG_CXX])
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
+ AC_PROG_CXXCPP
+fi
+])# _LT_AC_PROG_CXXCPP
# AC_LIBTOOL_F77
# --------------
@@ -2435,7 +2720,7 @@ _LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ])
# AC_LIBTOOL_RC
-# --------------
+# -------------
# enable support for Windows resource files
AC_DEFUN([AC_LIBTOOL_RC],
[AC_REQUIRE([LT_AC_PROG_RC])
@@ -2468,36 +2753,9 @@ lt_simple_link_test_code='int main(){return(0);}\n'
_LT_AC_SYS_COMPILER
-#
-# Check for any special shared library compilation flags.
-#
-_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)=
-if test "$GCC" = no; then
- case $host_os in
- sco3.2v5*)
- _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)='-belf'
- ;;
- esac
-fi
-if test -n "$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)"; then
- AC_MSG_WARN([`$CC' requires `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to build shared libraries])
- if echo "$old_CC $old_CFLAGS " | grep "[[ ]]$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)[[ ]]" >/dev/null; then :
- else
- AC_MSG_WARN([add `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to the CC or CFLAGS env variable and reconfigure])
- _LT_AC_TAGVAR(lt_cv_prog_cc_can_build_shared, $1)=no
- fi
-fi
-
-
-#
-# Check to make sure the static flag actually works.
-#
-AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $_LT_AC_TAGVAR(lt_prog_compiler_static, $1) works],
- _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1),
- $_LT_AC_TAGVAR(lt_prog_compiler_static, $1),
- [],
- [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=])
-
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
AC_LIBTOOL_PROG_COMPILER_PIC($1)
@@ -2507,9 +2765,9 @@ AC_LIBTOOL_PROG_LD_SHLIBS($1)
AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
AC_LIBTOOL_SYS_LIB_STRIP
-AC_LIBTOOL_DLOPEN_SELF($1)
+AC_LIBTOOL_DLOPEN_SELF
-# Report which librarie types wil actually be built
+# Report which library types will actually be built
AC_MSG_CHECKING([if libtool supports shared libraries])
AC_MSG_RESULT([$can_build_shared])
@@ -2518,7 +2776,7 @@ test "$can_build_shared" = "no" && enable_shared=no
# On AIX, shared libraries and static libraries use the same namespace, and
# are all built from PIC.
-case "$host_os" in
+case $host_os in
aix3*)
test "$enable_shared" = yes && enable_static=no
if test -n "$RANLIB"; then
@@ -2527,47 +2785,10 @@ aix3*)
fi
;;
-aix4*)
+aix4* | aix5*)
if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
test "$enable_shared" = yes && enable_static=no
fi
- ;;
- darwin* | rhapsody*)
- if test "$GCC" = yes; then
- _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
- case "$host_os" in
- rhapsody* | darwin1.[[012]])
- _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress'
- ;;
- *) # Darwin 1.3 on
- if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
- _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
- else
- case ${MACOSX_DEPLOYMENT_TARGET} in
- 10.[[012]])
- _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
- ;;
- 10.*)
- _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup'
- ;;
- esac
- fi
- ;;
- esac
- output_verbose_link_cmd='echo'
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring'
- _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
- # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
- _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- _LT_AC_TAGVAR(hardcode_direct, $1)=no
- _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
- _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
- _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience'
- _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
- else
- _LT_AC_TAGVAR(ld_shlibs, $1)=no
- fi
;;
esac
AC_MSG_RESULT([$enable_shared])
@@ -2593,7 +2814,7 @@ AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)])
AC_DEFUN([_LT_AC_LANG_CXX_CONFIG],
[AC_LANG_PUSH(C++)
AC_REQUIRE([AC_PROG_CXX])
-AC_REQUIRE([AC_PROG_CXXCPP])
+AC_REQUIRE([_LT_AC_PROG_CXXCPP])
_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_AC_TAGVAR(allow_undefined_flag, $1)=
@@ -2605,6 +2826,7 @@ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
_LT_AC_TAGVAR(hardcode_automatic, $1)=no
_LT_AC_TAGVAR(module_cmds, $1)=
_LT_AC_TAGVAR(module_expsym_cmds, $1)=
@@ -2622,7 +2844,7 @@ _LT_AC_TAGVAR(postdeps, $1)=
_LT_AC_TAGVAR(compiler_lib_search_path, $1)=
# Source file extension for C++ test sources.
-ac_ext=cc
+ac_ext=cpp
# Object file extension for compiled C++ test sources.
objext=o
@@ -2632,11 +2854,15 @@ _LT_AC_TAGVAR(objext, $1)=$objext
lt_simple_compile_test_code="int some_variable = 0;\n"
# Code to be used in simple link tests
-lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n'
+lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }\n'
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
_LT_AC_SYS_COMPILER
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
# Allow CC to be a program name with arguments.
lt_save_CC=$CC
lt_save_LD=$LD
@@ -2647,18 +2873,18 @@ lt_save_path_LD=$lt_cv_path_LD
if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
else
- unset lt_cv_prog_gnu_ld
+ $as_unset lt_cv_prog_gnu_ld
fi
if test -n "${lt_cv_path_LDCXX+set}"; then
lt_cv_path_LD=$lt_cv_path_LDCXX
else
- unset lt_cv_path_LD
+ $as_unset lt_cv_path_LD
fi
test -z "${LDCXX+set}" || LD=$LDCXX
CC=${CXX-"c++"}
compiler=$CC
_LT_AC_TAGVAR(compiler, $1)=$CC
-cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'`
+_LT_CC_BASENAME([$compiler])
# We don't want -fno-exception wen compiling C++ code, so set the
# no_builtin_flag separately
@@ -2747,6 +2973,7 @@ case $host_os in
;;
esac
done
+ ;;
esac
exp_sym_flag='-bexport'
@@ -2765,7 +2992,7 @@ case $host_os in
_LT_AC_TAGVAR(link_all_deplibs, $1)=yes
if test "$GXX" = yes; then
- case $host_os in aix4.[012]|aix4.[012].*)
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
# We only want to do this on AIX 4.2 and lower, the check
# below for broken collect2 doesn't work under 4.3+
collect2name=`${CC} -print-prog-name=collect2`
@@ -2784,8 +3011,12 @@ case $host_os in
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
fi
+ ;;
esac
shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
else
# not using gcc
if test "$host_cpu" = ia64; then
@@ -2812,12 +3043,12 @@ case $host_os in
_LT_AC_SYS_LIBPATH_AIX
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
- _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
else
if test "$host_cpu" = ia64; then
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
_LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
- _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
else
# Determine the default libpath from the value encoded in an empty executable.
_LT_AC_SYS_LIBPATH_AIX
@@ -2826,16 +3057,26 @@ case $host_os in
# -berok will link without error, but may produce a broken library.
_LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
- # -bexpall does not export symbols beginning with underscore (_)
- _LT_AC_TAGVAR(always_export_symbols, $1)=yes
# Exported symbols can be pulled into shared objects from archives
- _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' '
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
- # This is similar to how AIX traditionally builds it's shared libraries.
- _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ # This is similar to how AIX traditionally builds its shared libraries.
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
fi
fi
;;
+
+ beos*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
chorus*)
case $cc_basename in
*)
@@ -2854,7 +3095,7 @@ case $host_os in
_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
# If the export-symbols file already is a .def file (1st line
# is EXPORTS), use it as is; otherwise, prepend...
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
@@ -2863,70 +3104,81 @@ case $host_os in
echo EXPORTS > $output_objdir/$soname.def;
cat $export_symbols >> $output_objdir/$soname.def;
fi~
- $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
else
_LT_AC_TAGVAR(ld_shlibs, $1)=no
fi
;;
+ darwin* | rhapsody*)
+ case $host_os in
+ rhapsody* | darwin1.[[012]])
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[[012]])
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ ;;
+ 10.*)
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
- darwin* | rhapsody*)
- if test "$GXX" = yes; then
- _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
- case "$host_os" in
- rhapsody* | darwin1.[[012]])
- _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress'
- ;;
- *) # Darwin 1.3 on
- if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
- _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
+ if test "$GXX" = yes ; then
+ lt_int_apple_cc_single_mod=no
+ output_verbose_link_cmd='echo'
+ if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then
+ lt_int_apple_cc_single_mod=yes
+ fi
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
else
- case ${MACOSX_DEPLOYMENT_TARGET} in
- 10.[[012]])
- _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
- ;;
- 10.*)
- _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup'
- ;;
- esac
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ fi
+ _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ case $cc_basename in
+ xlc*)
+ output_verbose_link_cmd='echo'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+ _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ ;;
+ *)
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
fi
- ;;
- esac
- lt_int_apple_cc_single_mod=no
- output_verbose_link_cmd='echo'
- if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
- lt_int_apple_cc_single_mod=yes
- fi
- if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
- else
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
- fi
- _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
-
- # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
- if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
- _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- else
- _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- fi
- _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- _LT_AC_TAGVAR(hardcode_direct, $1)=no
- _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
- _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
- _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience'
- _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
- else
- _LT_AC_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
+ ;;
dgux*)
case $cc_basename in
- ec++)
+ ec++*)
# FIXME: insert proper C++ library support
_LT_AC_TAGVAR(ld_shlibs, $1)=no
;;
- ghcx)
+ ghcx*)
# Green Hills C++ Compiler
# FIXME: insert proper C++ library support
_LT_AC_TAGVAR(ld_shlibs, $1)=no
@@ -2937,14 +3189,14 @@ case $host_os in
;;
esac
;;
- freebsd[12]*)
+ freebsd[[12]]*)
# C++ shared libraries reported to be fairly broken before switch to ELF
_LT_AC_TAGVAR(ld_shlibs, $1)=no
;;
freebsd-elf*)
_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
;;
- freebsd* | kfreebsd*-gnu)
+ freebsd* | kfreebsd*-gnu | dragonfly*)
# FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
# conventions
_LT_AC_TAGVAR(ld_shlibs, $1)=yes
@@ -2961,11 +3213,11 @@ case $host_os in
# location of the library.
case $cc_basename in
- CC)
+ CC*)
# FIXME: insert proper C++ library support
_LT_AC_TAGVAR(ld_shlibs, $1)=no
;;
- aCC)
+ aCC*)
_LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
@@ -2975,7 +3227,7 @@ case $host_os in
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | egrep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
;;
*)
if test "$GXX" = yes; then
@@ -2989,34 +3241,23 @@ case $host_os in
;;
hpux10*|hpux11*)
if test $with_gnu_ld = no; then
- case "$host_cpu" in
- hppa*64*)
- _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
- _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
- ;;
- ia64*)
- _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
;;
*)
- _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
- _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
;;
esac
fi
- case "$host_cpu" in
- hppa*64*)
+ case $host_cpu in
+ hppa*64*|ia64*)
_LT_AC_TAGVAR(hardcode_direct, $1)=no
_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
- ia64*)
- _LT_AC_TAGVAR(hardcode_direct, $1)=no
- _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
- # but as the default
- # location of the library.
- ;;
*)
_LT_AC_TAGVAR(hardcode_direct, $1)=yes
_LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
@@ -3026,14 +3267,17 @@ case $host_os in
esac
case $cc_basename in
- CC)
+ CC*)
# FIXME: insert proper C++ library support
_LT_AC_TAGVAR(ld_shlibs, $1)=no
;;
- aCC)
- case "$host_cpu" in
- hppa*64*|ia64*)
- _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+ aCC*)
+ case $host_cpu in
+ hppa*64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
*)
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
@@ -3052,9 +3296,12 @@ case $host_os in
*)
if test "$GXX" = yes; then
if test $with_gnu_ld = no; then
- case "$host_cpu" in
- ia64*|hppa*64*)
- _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+ case $host_cpu in
+ hppa*64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
*)
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
@@ -3068,11 +3315,25 @@ case $host_os in
;;
esac
;;
+ interix3*)
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
irix5* | irix6*)
case $cc_basename in
- CC)
+ CC*)
# SGI C++
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
# Archives containing C++ object files must be created using
# "CC -ar", where "CC" is the IRIX C++ compiler. This is
@@ -3083,7 +3344,7 @@ case $host_os in
*)
if test "$GXX" = yes; then
if test "$with_gnu_ld" = no; then
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
else
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib'
fi
@@ -3096,7 +3357,7 @@ case $host_os in
;;
linux*)
case $cc_basename in
- KCC)
+ KCC*)
# Kuck and Associates, Inc. (KAI) C++ Compiler
# KCC will only create a shared library if the output file
@@ -3121,17 +3382,41 @@ case $host_os in
# "CC -Bstatic", where "CC" is the KAI C++ compiler.
_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
;;
- icpc)
+ icpc*)
# Intel C++
with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ tmp_idyn=
+ case $host_cpu in
+ ia64*) tmp_idyn=' -i_dynamic';;
+ esac
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
;;
- cxx)
+ pgCC*)
+ # Portland Group C++ compiler
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ ;;
+ cxx*)
# Compaq C++
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
@@ -3162,7 +3447,7 @@ case $host_os in
;;
mvs*)
case $cc_basename in
- cxx)
+ cxx*)
# FIXME: insert proper C++ library support
_LT_AC_TAGVAR(ld_shlibs, $1)=no
;;
@@ -3172,7 +3457,7 @@ case $host_os in
;;
esac
;;
- netbsd* | knetbsd*-gnu)
+ netbsd*)
if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
_LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
wlarc=
@@ -3183,9 +3468,25 @@ case $host_os in
# Workaround some broken pre-1.5 toolchains
output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
;;
+ openbsd2*)
+ # C++ shared libraries are fairly broken
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ openbsd*)
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ fi
+ output_verbose_link_cmd='echo'
+ ;;
osf3*)
case $cc_basename in
- KCC)
+ KCC*)
# Kuck and Associates, Inc. (KAI) C++ Compiler
# KCC will only create a shared library if the output file
@@ -3201,14 +3502,14 @@ case $host_os in
_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
;;
- RCC)
+ RCC*)
# Rational C++ 2.4.1
# FIXME: insert proper C++ library support
_LT_AC_TAGVAR(ld_shlibs, $1)=no
;;
- cxx)
+ cxx*)
_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
@@ -3226,7 +3527,7 @@ case $host_os in
*)
if test "$GXX" = yes && test "$with_gnu_ld" = no; then
_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
@@ -3245,7 +3546,7 @@ case $host_os in
;;
osf4* | osf5*)
case $cc_basename in
- KCC)
+ KCC*)
# Kuck and Associates, Inc. (KAI) C++ Compiler
# KCC will only create a shared library if the output file
@@ -3260,17 +3561,17 @@ case $host_os in
# the KAI C++ compiler.
_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs'
;;
- RCC)
+ RCC*)
# Rational C++ 2.4.1
# FIXME: insert proper C++ library support
_LT_AC_TAGVAR(ld_shlibs, $1)=no
;;
- cxx)
+ cxx*)
_LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
echo "-hidden">> $lib.exp~
- $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~
$rm $lib.exp'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
@@ -3289,7 +3590,7 @@ case $host_os in
*)
if test "$GXX" = yes && test "$with_gnu_ld" = no; then
_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
@@ -3310,27 +3611,14 @@ case $host_os in
# FIXME: insert proper C++ library support
_LT_AC_TAGVAR(ld_shlibs, $1)=no
;;
- sco*)
- _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
- case $cc_basename in
- CC)
- # FIXME: insert proper C++ library support
- _LT_AC_TAGVAR(ld_shlibs, $1)=no
- ;;
- *)
- # FIXME: insert proper C++ library support
- _LT_AC_TAGVAR(ld_shlibs, $1)=no
- ;;
- esac
- ;;
sunos4*)
case $cc_basename in
- CC)
+ CC*)
# Sun C++ 4.x
# FIXME: insert proper C++ library support
_LT_AC_TAGVAR(ld_shlibs, $1)=no
;;
- lcc)
+ lcc*)
# Lucid
# FIXME: insert proper C++ library support
_LT_AC_TAGVAR(ld_shlibs, $1)=no
@@ -3343,36 +3631,33 @@ case $host_os in
;;
solaris*)
case $cc_basename in
- CC)
+ CC*)
# Sun C++ 4.2, 5.x and Centerline C++
+ _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes
_LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
- $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
case $host_os in
- solaris2.[0-5] | solaris2.[0-5].*) ;;
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
*)
# The C++ compiler is used as linker so we must use $wl
# flag to pass the commands to the underlying system
- # linker.
+ # linker. We must also pass each convience library through
+ # to the system linker between allextract/defaultextract.
+ # The C++ compiler will combine linker options so we
+ # cannot just pass the convience library names through
+ # without $wl.
# Supported since Solaris 2.6 (maybe 2.5.1?)
- _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract'
;;
esac
_LT_AC_TAGVAR(link_all_deplibs, $1)=yes
- # Commands to make compiler produce verbose output that lists
- # what "hidden" libraries, object files and flags are used when
- # linking a shared library.
- #
- # There doesn't appear to be a way to prevent this compiler from
- # explicitly linking system object files so we need to strip them
- # from the output so that they don't get included in the library
- # dependencies.
- output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[[LR]]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ output_verbose_link_cmd='echo'
# Archives containing C++ object files must be created using
# "CC -xar", where "CC" is the Sun C++ compiler. This is
@@ -3380,7 +3665,7 @@ case $host_os in
# in the archive.
_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
;;
- gcx)
+ gcx*)
# Green Hills C++ Compiler
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
@@ -3418,12 +3703,63 @@ case $host_os in
;;
esac
;;
- sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*)
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ # So that behaviour is only enabled if SCOABSPATH is set to a
+ # non-empty value in the environment. Most likely only useful for
+ # creating official distributions of packages.
+ # This is a hack until libtool officially supports absolute path
+ # names for shared libraries.
+ _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
;;
tandem*)
case $cc_basename in
- NCC)
+ NCC*)
# NonStop-UX NCC 3.20
# FIXME: insert proper C++ library support
_LT_AC_TAGVAR(ld_shlibs, $1)=no
@@ -3456,8 +3792,6 @@ AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
AC_LIBTOOL_PROG_LD_SHLIBS($1)
AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
-AC_LIBTOOL_SYS_LIB_STRIP
-AC_LIBTOOL_DLOPEN_SELF($1)
AC_LIBTOOL_CONFIG($1)
@@ -3475,7 +3809,7 @@ lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
])# AC_LIBTOOL_LANG_CXX_CONFIG
# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME])
-# ------------------------
+# ------------------------------------
# Figure out "hidden" library dependencies from verbose
# compiler output when linking a shared library.
# Parse the compiler output and extract the necessary
@@ -3529,7 +3863,7 @@ if AC_TRY_EVAL(ac_compile); then
# The `*' in the case matches for architectures that use `case' in
# $output_verbose_cmd can trigger glob expansion during the loop
# eval without this substitution.
- output_verbose_link_cmd="`$echo \"X$output_verbose_link_cmd\" | $Xsed -e \"$no_glob_subst\"`"
+ output_verbose_link_cmd=`$echo "X$output_verbose_link_cmd" | $Xsed -e "$no_glob_subst"`
for p in `eval $output_verbose_link_cmd`; do
case $p in
@@ -3605,13 +3939,37 @@ fi
$rm -f confest.$objext
+# PORTME: override above test on systems where it is broken
+ifelse([$1],[CXX],
+[case $host_os in
+interix3*)
+ # Interix 3.5 installs completely hosed .la files for C++, so rather than
+ # hack all around it, let's just trust "g++" to DTRT.
+ _LT_AC_TAGVAR(predep_objects,$1)=
+ _LT_AC_TAGVAR(postdep_objects,$1)=
+ _LT_AC_TAGVAR(postdeps,$1)=
+ ;;
+
+solaris*)
+ case $cc_basename in
+ CC*)
+ # Adding this requires a known-good setup of shared libraries for
+ # Sun compiler versions before 5.6, else PIC objects from an old
+ # archive will be linked into the output, leading to subtle bugs.
+ _LT_AC_TAGVAR(postdeps,$1)='-lCstd -lCrun'
+ ;;
+ esac
+ ;;
+esac
+])
+
case " $_LT_AC_TAGVAR(postdeps, $1) " in
*" -lc "*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;;
esac
])# AC_LIBTOOL_POSTDEP_PREDEP
# AC_LIBTOOL_LANG_F77_CONFIG
-# ------------------------
+# --------------------------
# Ensure that the configuration vars for the C compiler are
# suitably defined. Those variables are subsequently used by
# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
@@ -3655,12 +4013,16 @@ lt_simple_link_test_code=" program t\n end\n"
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
_LT_AC_SYS_COMPILER
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
# Allow CC to be a program name with arguments.
lt_save_CC="$CC"
CC=${F77-"f77"}
compiler=$CC
_LT_AC_TAGVAR(compiler, $1)=$CC
-cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'`
+_LT_CC_BASENAME([$compiler])
AC_MSG_CHECKING([if libtool supports shared libraries])
AC_MSG_RESULT([$can_build_shared])
@@ -3670,7 +4032,7 @@ test "$can_build_shared" = "no" && enable_shared=no
# On AIX, shared libraries and static libraries use the same namespace, and
# are all built from PIC.
-case "$host_os" in
+case $host_os in
aix3*)
test "$enable_shared" = yes && enable_static=no
if test -n "$RANLIB"; then
@@ -3678,8 +4040,10 @@ aix3*)
postinstall_cmds='$RANLIB $lib'
fi
;;
-aix4*)
- test "$enable_shared" = yes && enable_static=no
+aix4* | aix5*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
;;
esac
AC_MSG_RESULT([$enable_shared])
@@ -3689,8 +4053,6 @@ AC_MSG_CHECKING([whether to build static libraries])
test "$enable_shared" = yes || enable_static=yes
AC_MSG_RESULT([$enable_static])
-test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
-
_LT_AC_TAGVAR(GCC, $1)="$G77"
_LT_AC_TAGVAR(LD, $1)="$LD"
@@ -3700,8 +4062,6 @@ AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
AC_LIBTOOL_PROG_LD_SHLIBS($1)
AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
-AC_LIBTOOL_SYS_LIB_STRIP
-
AC_LIBTOOL_CONFIG($1)
@@ -3730,20 +4090,27 @@ _LT_AC_TAGVAR(objext, $1)=$objext
lt_simple_compile_test_code="class foo {}\n"
# Code to be used in simple link tests
-lt_simple_link_test_code='public class conftest { public static void main(String[] argv) {}; }\n'
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }\n'
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
_LT_AC_SYS_COMPILER
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
# Allow CC to be a program name with arguments.
lt_save_CC="$CC"
CC=${GCJ-"gcj"}
compiler=$CC
_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
# GCJ did not exist at the time GCC didn't implicitly link libc in.
_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+
AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
AC_LIBTOOL_PROG_COMPILER_PIC($1)
AC_LIBTOOL_PROG_CC_C_O($1)
@@ -3751,8 +4118,6 @@ AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
AC_LIBTOOL_PROG_LD_SHLIBS($1)
AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
-AC_LIBTOOL_SYS_LIB_STRIP
-AC_LIBTOOL_DLOPEN_SELF($1)
AC_LIBTOOL_CONFIG($1)
@@ -3762,7 +4127,7 @@ CC="$lt_save_CC"
# AC_LIBTOOL_LANG_RC_CONFIG
-# --------------------------
+# -------------------------
# Ensure that the configuration vars for the Windows resource compiler are
# suitably defined. Those variables are subsequently used by
# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
@@ -3786,11 +4151,16 @@ lt_simple_link_test_code="$lt_simple_compile_test_code"
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
_LT_AC_SYS_COMPILER
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
# Allow CC to be a program name with arguments.
lt_save_CC="$CC"
CC=${RC-"windres"}
compiler=$CC
_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
AC_LIBTOOL_CONFIG($1)
@@ -3820,7 +4190,7 @@ if test -f "$ltmain"; then
# Now quote all the things that may contain metacharacters while being
# careful not to overquote the AC_SUBSTed values. We take copies of the
# variables and quote the copies for generation of the libtool script.
- for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \
SED SHELL STRIP \
libname_spec library_names_spec soname_spec extract_expsyms_cmds \
old_striplib striplib file_magic_cmd finish_cmds finish_eval \
@@ -3926,7 +4296,7 @@ ifelse([$1], [],
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
@@ -3937,11 +4307,11 @@ ifelse([$1], [],
SED=$lt_SED
# Sed that helps us avoid accidentally triggering echo(1) options like -n.
-Xsed="$SED -e s/^X//"
+Xsed="$SED -e 1s/^X//"
# The HP-UX ksh and POSIX shell print the target directory to stdout
# if CDPATH is set.
-if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
# The names of the tagged configurations supported by this script.
available_tags=
@@ -3972,6 +4342,12 @@ fast_install=$enable_fast_install
# The host system.
host_alias=$host_alias
host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
# An echo program that does not interpret backslashes.
echo=$lt_echo
@@ -3983,6 +4359,9 @@ AR_FLAGS=$lt_AR_FLAGS
# A C compiler.
LTCC=$lt_LTCC
+# LTCC compiler flags.
+LTCFLAGS=$lt_LTCFLAGS
+
# A language-specific compiler.
CC=$lt_[]_LT_AC_TAGVAR(compiler, $1)
@@ -4033,7 +4412,7 @@ objext="$ac_objext"
libext="$libext"
# Shared library suffix (normally ".so").
-shrext='$shrext'
+shrext_cmds='$shrext_cmds'
# Executable file suffix (normally "").
exeext="$exeext"
@@ -4048,7 +4427,7 @@ max_cmd_len=$lt_cv_sys_max_cmd_len
# Does compiler simultaneously support -c and -o options?
compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)
-# Must we lock files when doing compilation ?
+# Must we lock files when doing compilation?
need_locks=$lt_need_locks
# Do we need the lib prefix for modules?
@@ -4322,9 +4701,6 @@ symcode='[[BCDEGRST]]'
# Regexp to match symbols that can be accessed directly from C.
sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
-# Transform the above into a raw symbol and a C symbol.
-symxfrm='\1 \2\3 \3'
-
# Transform an extracted symbol line into a proper C declaration
lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'"
@@ -4346,15 +4722,31 @@ hpux*) # Its linker distinguishes data from code symbols
lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
;;
+linux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[[ABCDGIRSTW]]'
+ lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+ lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
+ fi
+ ;;
irix* | nonstopux*)
symcode='[[BCDEGRST]]'
;;
osf*)
symcode='[[BCDEGQRST]]'
;;
-solaris* | sysv5*)
+solaris*)
symcode='[[BDRT]]'
;;
+sco3.2v5*)
+ symcode='[[DT]]'
+ ;;
+sysv4.2uw2*)
+ symcode='[[DT]]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[[ABDT]]'
+ ;;
sysv4)
symcode='[[DFNSTU]]'
;;
@@ -4377,8 +4769,11 @@ esac
# Try without a prefix undercore, then with it.
for ac_symprfx in "" "_"; do
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
# Write the raw and C identifiers.
- lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'"
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
# Check to see that the pipe works correctly.
pipe_works=no
@@ -4534,6 +4929,10 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
# DJGPP does not support shared libraries at all
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
;;
+ interix3*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
sysv4*MP*)
if test -d /usr/nec; then
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
@@ -4542,7 +4941,7 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
hpux*)
# PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
# not for PA HP-UX.
- case "$host_cpu" in
+ case $host_cpu in
hppa*64*|ia64*)
;;
*)
@@ -4567,18 +4966,28 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
;;
chorus*)
case $cc_basename in
- cxch68)
+ cxch68*)
# Green Hills C++ Compiler
# _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
;;
esac
;;
+ darwin*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ case $cc_basename in
+ xlc*)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon'
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ ;;
+ esac
+ ;;
dgux*)
case $cc_basename in
- ec++)
+ ec++*)
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
;;
- ghcx)
+ ghcx*)
# Green Hills C++ Compiler
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
;;
@@ -4586,22 +4995,22 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
;;
esac
;;
- freebsd* | kfreebsd*-gnu)
+ freebsd* | kfreebsd*-gnu | dragonfly*)
# FreeBSD uses GNU C++
;;
hpux9* | hpux10* | hpux11*)
case $cc_basename in
- CC)
+ CC*)
_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
if test "$host_cpu" != ia64; then
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
fi
;;
- aCC)
+ aCC*)
_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
- case "$host_cpu" in
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ case $host_cpu in
hppa*64*|ia64*)
# +Z the default
;;
@@ -4614,9 +5023,13 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
;;
esac
;;
+ interix*)
+ # This is c89, which is MS Visual C++ (no shared libs)
+ # Anyone wants to do a port?
+ ;;
irix5* | irix6* | nonstopux*)
case $cc_basename in
- CC)
+ CC*)
_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
# CC pic flag -KPIC is the default.
@@ -4627,18 +5040,24 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
;;
linux*)
case $cc_basename in
- KCC)
+ KCC*)
# KAI C++ Compiler
_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
;;
- icpc)
+ icpc* | ecpc*)
# Intel C++
_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
;;
- cxx)
+ pgCC*)
+ # Portland Group C++ compiler.
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ cxx*)
# Compaq C++
# Make sure the PIC flag is empty. It appears that all Alpha
# Linux and Compaq Tru64 Unix objects are PIC.
@@ -4655,25 +5074,25 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
;;
mvs*)
case $cc_basename in
- cxx)
+ cxx*)
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
;;
*)
;;
esac
;;
- netbsd* | knetbsd*-gnu)
+ netbsd*)
;;
osf3* | osf4* | osf5*)
case $cc_basename in
- KCC)
+ KCC*)
_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
;;
- RCC)
+ RCC*)
# Rational C++ 2.4.1
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
;;
- cxx)
+ cxx*)
# Digital/Compaq C++
_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
# Make sure the PIC flag is empty. It appears that all Alpha
@@ -4687,24 +5106,15 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
;;
psos*)
;;
- sco*)
- case $cc_basename in
- CC)
- _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
- *)
- ;;
- esac
- ;;
solaris*)
case $cc_basename in
- CC)
+ CC*)
# Sun C++ 4.2, 5.x and Centerline C++
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
;;
- gcx)
+ gcx*)
# Green Hills C++ Compiler
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
;;
@@ -4714,12 +5124,12 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
;;
sunos4*)
case $cc_basename in
- CC)
+ CC*)
# Sun C++ 4.x
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
;;
- lcc)
+ lcc*)
# Lucid
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
;;
@@ -4729,7 +5139,7 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
;;
tandem*)
case $cc_basename in
- NCC)
+ NCC*)
# NonStop-UX NCC 3.20
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
;;
@@ -4737,7 +5147,14 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
;;
esac
;;
- unixware*)
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ case $cc_basename in
+ CC*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
;;
vxworks*)
;;
@@ -4784,6 +5201,11 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
;;
+ interix3*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
msdosdjgpp*)
# Just because we use GCC doesn't mean we suddenly get shared libraries
# on systems that don't support them.
@@ -4800,7 +5222,7 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
hpux*)
# PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
# not for PA HP-UX.
- case "$host_cpu" in
+ case $host_cpu in
hppa*64*|ia64*)
# +Z the default
;;
@@ -4826,6 +5248,16 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
fi
;;
+ darwin*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ case $cc_basename in
+ xlc*)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon'
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ ;;
+ esac
+ ;;
mingw* | pw32* | os2*)
# This hack is so that the source file can tell whether it is being
@@ -4837,7 +5269,7 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
# PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
# not for PA HP-UX.
- case "$host_cpu" in
+ case $host_cpu in
hppa*64*|ia64*)
# +Z the default
;;
@@ -4861,12 +5293,19 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
;;
linux*)
- case $CC in
+ case $cc_basename in
icc* | ecc*)
_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
;;
+ pgcc* | pgf77* | pgf90* | pgf95*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
ccc*)
_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
# All Alpha code is PIC.
@@ -4881,15 +5320,15 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
;;
- sco3.2v5*)
- _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kpic'
- _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-dn'
- ;;
-
solaris*)
- _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+ esac
;;
sunos4*)
@@ -4898,7 +5337,7 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
;;
- sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ sysv4 | sysv4.2uw2* | sysv4.3*)
_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
@@ -4911,6 +5350,17 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
fi
;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ unicos*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+
uts4*)
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
@@ -4938,7 +5388,7 @@ if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then
[_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
_LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
fi
-case "$host_os" in
+case $host_os in
# For platforms which do not support PIC, -DPIC is meaningless:
*djgpp*)
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
@@ -4947,6 +5397,16 @@ case "$host_os" in
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])"
;;
esac
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_AC_TAGVAR(lt_prog_compiler_static, $1)\"
+AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+ _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1),
+ $lt_tmp_static_flag,
+ [],
+ [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=])
])
@@ -4971,7 +5431,7 @@ ifelse([$1],[CXX],[
_LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
;;
cygwin* | mingw*)
- _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
;;
*)
_LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
@@ -5014,7 +5474,8 @@ ifelse([$1],[CXX],[
# rely on this symbol name, it's probably fine to never include it in
# preloaded symbol tables.
extract_expsyms_cmds=
-
+ # Just being paranoid about ensuring that cc_basename is set.
+ _LT_CC_BASENAME([$compiler])
case $host_os in
cygwin* | mingw* | pw32*)
# FIXME: the MSVC++ port hasn't been tested in a loooong time
@@ -5024,6 +5485,10 @@ ifelse([$1],[CXX],[
with_gnu_ld=no
fi
;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
openbsd*)
with_gnu_ld=no
;;
@@ -5034,6 +5499,27 @@ ifelse([$1],[CXX],[
# If archive_cmds runs LD, not CC, wlarc should be empty
wlarc='${wl}'
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
# See if GNU ld supports shared libraries.
case $host_os in
aix3* | aix4* | aix5*)
@@ -5084,10 +5570,10 @@ EOF
_LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
_LT_AC_TAGVAR(always_export_symbols, $1)=no
_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
- _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
# If the export-symbols file already is a .def file (1st line
# is EXPORTS), use it as is; otherwise, prepend...
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
@@ -5096,13 +5582,59 @@ EOF
echo EXPORTS > $output_objdir/$soname.def;
cat $export_symbols >> $output_objdir/$soname.def;
fi~
- $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
else
- ld_shlibs=no
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
fi
;;
- netbsd* | knetbsd*-gnu)
+ interix3*)
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ linux*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ tmp_addflag=
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ esac
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test $supports_anon_versioning = yes; then
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ $echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ netbsd*)
if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
_LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
wlarc=
@@ -5112,7 +5644,7 @@ EOF
fi
;;
- solaris* | sysv5*)
+ solaris*)
if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
_LT_AC_TAGVAR(ld_shlibs, $1)=no
cat <<EOF 1>&2
@@ -5133,6 +5665,33 @@ EOF
fi
;;
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib'
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
sunos4*)
_LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
wlarc=
@@ -5140,31 +5699,6 @@ EOF
_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
- linux*)
- if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_AC_TAGVAR(archive_cmds, $1)="$tmp_archive_cmds"
- supports_anon_versioning=no
- case `$LD -v 2>/dev/null` in
- *\ [01].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
- *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
- *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
- *\ 2.11.*) ;; # other 2.11 versions
- *) supports_anon_versioning=yes ;;
- esac
- if test $supports_anon_versioning = yes; then
- _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~
-cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-$echo "local: *; };" >> $output_objdir/$libname.ver~
- $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
- else
- _LT_AC_TAGVAR(archive_expsym_cmds, $1)="$tmp_archive_cmds"
- fi
- else
- _LT_AC_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
-
*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
@@ -5175,16 +5709,11 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
;;
esac
- if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = yes; then
- runpath_var=LD_RUN_PATH
- _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
- _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
- # ancient GNU ld didn't support --whole-archive et. al.
- if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
- _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
- else
- _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
- fi
+ if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then
+ runpath_var=
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
fi
else
# PORTME fill in a description of your system's linker (not GNU ld)
@@ -5196,7 +5725,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
# Note: this linker hardcodes the directories in LIBPATH if there
# are no directories specified by -L.
_LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
- if test "$GCC" = yes && test -z "$link_static_flag"; then
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
# Neither direct hardcoding nor static linking is supported with a
# broken collect2.
_LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
@@ -5230,6 +5759,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
break
fi
done
+ ;;
esac
exp_sym_flag='-bexport'
@@ -5248,7 +5778,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
_LT_AC_TAGVAR(link_all_deplibs, $1)=yes
if test "$GCC" = yes; then
- case $host_os in aix4.[012]|aix4.[012].*)
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
# We only want to do this on AIX 4.2 and lower, the check
# below for broken collect2 doesn't work under 4.3+
collect2name=`${CC} -print-prog-name=collect2`
@@ -5267,8 +5797,12 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
fi
+ ;;
esac
shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
else
# not using gcc
if test "$host_cpu" = ia64; then
@@ -5276,11 +5810,11 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
# chokes on -Wl,-G. The following line is correct:
shared_flag='-G'
else
- if test "$aix_use_runtimelinking" = yes; then
+ if test "$aix_use_runtimelinking" = yes; then
shared_flag='${wl}-G'
else
shared_flag='${wl}-bM:SRE'
- fi
+ fi
fi
fi
@@ -5294,12 +5828,12 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
# Determine the default libpath from the value encoded in an empty executable.
_LT_AC_SYS_LIBPATH_AIX
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
- _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
else
if test "$host_cpu" = ia64; then
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
_LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
- _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
else
# Determine the default libpath from the value encoded in an empty executable.
_LT_AC_SYS_LIBPATH_AIX
@@ -5308,13 +5842,11 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
# -berok will link without error, but may produce a broken library.
_LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
- # -bexpall does not export symbols beginning with underscore (_)
- _LT_AC_TAGVAR(always_export_symbols, $1)=yes
# Exported symbols can be pulled into shared objects from archives
- _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' '
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
- # This is similar to how AIX traditionally builds it's shared libraries.
- _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ # This is similar to how AIX traditionally builds its shared libraries.
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
fi
fi
;;
@@ -5327,7 +5859,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
_LT_AC_TAGVAR(ld_shlibs, $1)=no
;;
- bsdi4*)
+ bsdi[[45]]*)
_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
;;
@@ -5341,64 +5873,64 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
# Tell ltmain to make .lib files, not .a files.
libext=lib
# Tell ltmain to make .dll files, not .so files.
- shrext=".dll"
+ shrext_cmds=".dll"
# FIXME: Setting linknames here is a bad hack.
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
# The linker will automatically build a .lib file if we build a DLL.
_LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true'
# FIXME: Should let the user specify the lib program.
_LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs'
- fix_srcfile_path='`cygpath -w "$srcfile"`'
+ _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
;;
darwin* | rhapsody*)
- if test "$GXX" = yes ; then
- _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
- case "$host_os" in
- rhapsody* | darwin1.[[012]])
- _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress'
- ;;
- *) # Darwin 1.3 on
- if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
- _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
- else
- case ${MACOSX_DEPLOYMENT_TARGET} in
- 10.[[012]])
- _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress'
- ;;
- 10.*)
- _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup'
- ;;
- esac
- fi
- ;;
+ case $host_os in
+ rhapsody* | darwin1.[[012]])
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[[012]])
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ ;;
+ 10.*)
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
esac
- lt_int_apple_cc_single_mod=no
- output_verbose_link_cmd='echo'
- if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
- lt_int_apple_cc_single_mod=yes
- fi
- if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
- else
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
- fi
- _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
- # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
- if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
- _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- else
- _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- fi
- _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_AC_TAGVAR(hardcode_direct, $1)=no
_LT_AC_TAGVAR(hardcode_automatic, $1)=yes
_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
- _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience'
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
_LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+ if test "$GCC" = yes ; then
+ output_verbose_link_cmd='echo'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
else
- _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ case $cc_basename in
+ xlc*)
+ output_verbose_link_cmd='echo'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+ _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ ;;
+ *)
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
fi
;;
@@ -5432,7 +5964,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
;;
# FreeBSD 3 and greater uses gcc -shared to do shared libraries.
- freebsd* | kfreebsd*-gnu)
+ freebsd* | kfreebsd*-gnu | dragonfly*)
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
_LT_AC_TAGVAR(hardcode_direct, $1)=yes
@@ -5455,47 +5987,62 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
;;
- hpux10* | hpux11*)
+ hpux10*)
if test "$GCC" = yes -a "$with_gnu_ld" = no; then
- case "$host_cpu" in
- hppa*64*|ia64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
+ ia64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
*)
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
else
- case "$host_cpu" in
- hppa*64*|ia64*)
- _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+ case $host_cpu in
+ hppa*64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
;;
*)
- _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
fi
if test "$with_gnu_ld" = no; then
- case "$host_cpu" in
- hppa*64*)
- _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
- _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
- _LT_AC_TAGVAR(hardcode_direct, $1)=no
- _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
- ia64*)
- _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
_LT_AC_TAGVAR(hardcode_direct, $1)=no
_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
-
- # hardcode_minus_L: Not really in the search PATH,
- # but as the default location of the library.
- _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
;;
*)
- _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
- _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_AC_TAGVAR(hardcode_direct, $1)=yes
_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
@@ -5519,7 +6066,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
_LT_AC_TAGVAR(link_all_deplibs, $1)=yes
;;
- netbsd* | knetbsd*-gnu)
+ netbsd*)
if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
_LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
else
@@ -5543,6 +6090,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
else
@@ -5588,7 +6136,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
_LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
- $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
+ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp'
# Both c and cxx compiler support -rpath directly
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
@@ -5596,21 +6144,15 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
;;
- sco3.2v5*)
- _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
- runpath_var=LD_RUN_PATH
- hardcode_runpath_var=yes
- ;;
-
solaris*)
_LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
if test "$GCC" = yes; then
+ wlarc='${wl}'
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
$CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
else
+ wlarc=''
_LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
$LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
@@ -5619,8 +6161,18 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
case $host_os in
solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
- *) # Supported since Solaris 2.6 (maybe 2.5.1?)
- _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;;
+ *)
+ # The compiler driver will combine linker options so we
+ # cannot just pass the convience library names through
+ # without $wl, iff we do not link with $LD.
+ # Luckily, gcc supports the same syntax we need for Sun Studio.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ case $wlarc in
+ '')
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;;
+ *)
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;;
+ esac ;;
esac
_LT_AC_TAGVAR(link_all_deplibs, $1)=yes
;;
@@ -5677,36 +6229,45 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
fi
;;
- sysv4.2uw2*)
- _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
- _LT_AC_TAGVAR(hardcode_direct, $1)=yes
- _LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7*)
+ _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
- hardcode_runpath_var=yes
- runpath_var=LD_RUN_PATH
- ;;
+ runpath_var='LD_RUN_PATH'
- sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*)
- _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z ${wl}text'
if test "$GCC" = yes; then
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
else
- _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
fi
- runpath_var='LD_RUN_PATH'
- _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
- sysv5*)
- _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
- # $CC -shared without GNU ld will not create a library from C++
- # object files and a static libstdc++, better avoid it by now
- _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
- _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
- $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
- _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
;;
uts4*)
@@ -5724,11 +6285,6 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
- variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
-
#
# Do we need to explicitly link libc?
#
@@ -5756,6 +6312,7 @@ x|xyes)
libobjs=conftest.$ac_objext
deplibs=
wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
+ pic_flag=$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)
compiler_flags=-v
linker_flags=-v
verstring=
@@ -5881,7 +6438,7 @@ lt_ac_count=0
# Add /usr/xpg4/bin/sed as it is typically found on Solaris
# along with /bin/sed that truncates output.
for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
- test ! -f $lt_ac_sed && break
+ test ! -f $lt_ac_sed && continue
cat /dev/null > conftest.in
lt_ac_count=0
echo $ECHO_N "0123456789$ECHO_C" >conftest.in
@@ -5906,8 +6463,8 @@ for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
fi
done
done
-SED=$lt_cv_path_SED
])
+SED=$lt_cv_path_SED
AC_MSG_RESULT([$SED])
])
diff --git a/ext/pdo_sqlite/sqlite/addopcodes.awk b/ext/pdo_sqlite/sqlite/addopcodes.awk
new file mode 100644
index 0000000000..b806b1d96c
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/addopcodes.awk
@@ -0,0 +1,32 @@
+#!/usr/bin/awk
+#
+# This script appends additional token codes to the end of the
+# parse.h file that lemon generates. These extra token codes are
+# not used by the parser. But they are used by the tokenizer and/or
+# the code generator.
+#
+#
+BEGIN {
+ max = 0
+}
+/^#define TK_/ {
+ print $0
+ if( max<$3 ) max = $3
+}
+END {
+ printf "#define TK_%-29s %4d\n", "TO_TEXT", max+1
+ printf "#define TK_%-29s %4d\n", "TO_BLOB", max+2
+ printf "#define TK_%-29s %4d\n", "TO_NUMERIC", max+3
+ printf "#define TK_%-29s %4d\n", "TO_INT", max+4
+ printf "#define TK_%-29s %4d\n", "TO_REAL", max+5
+ printf "#define TK_%-29s %4d\n", "END_OF_FILE", max+6
+ printf "#define TK_%-29s %4d\n", "ILLEGAL", max+7
+ printf "#define TK_%-29s %4d\n", "SPACE", max+8
+ printf "#define TK_%-29s %4d\n", "UNCLOSED_STRING", max+9
+ printf "#define TK_%-29s %4d\n", "COMMENT", max+10
+ printf "#define TK_%-29s %4d\n", "FUNCTION", max+11
+ printf "#define TK_%-29s %4d\n", "COLUMN", max+12
+ printf "#define TK_%-29s %4d\n", "AGG_FUNCTION", max+13
+ printf "#define TK_%-29s %4d\n", "AGG_COLUMN", max+14
+ printf "#define TK_%-29s %4d\n", "CONST_FUNC", max+15
+}
diff --git a/ext/pdo_sqlite/sqlite/config.guess b/ext/pdo_sqlite/sqlite/config.guess
index e8c6fc0c33..6960a397af 100644
--- a/ext/pdo_sqlite/sqlite/config.guess
+++ b/ext/pdo_sqlite/sqlite/config.guess
@@ -1,9 +1,10 @@
#! /bin/sh
# Attempt to guess a canonical system name.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
+# Inc.
-timestamp='2004-01-05'
+timestamp='2007-01-15'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -17,13 +18,15 @@ timestamp='2004-01-05'
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
+
# Originally written by Per Bothner <per@bothner.com>.
# Please send patches to <config-patches@gnu.org>. Submit a context
# diff and a properly formatted ChangeLog entry.
@@ -53,7 +56,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
@@ -66,11 +69,11 @@ Try \`$me --help' for more information."
while test $# -gt 0 ; do
case $1 in
--time-stamp | --time* | -t )
- echo "$timestamp" ; exit 0 ;;
+ echo "$timestamp" ; exit ;;
--version | -v )
- echo "$version" ; exit 0 ;;
+ echo "$version" ; exit ;;
--help | --h* | -h )
- echo "$usage"; exit 0 ;;
+ echo "$usage"; exit ;;
-- ) # Stop option processing
shift; break ;;
- ) # Use stdin as input.
@@ -104,7 +107,7 @@ set_cc_for_build='
trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
: ${TMPDIR=/tmp} ;
- { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
{ test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
{ echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
@@ -123,7 +126,7 @@ case $CC_FOR_BUILD,$HOST_CC,$CC in
;;
,,*) CC_FOR_BUILD=$CC ;;
,*,*) CC_FOR_BUILD=$HOST_CC ;;
-esac ;'
+esac ; set_cc_for_build= ;'
# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
# (ghazi@noc.rutgers.edu 1994-08-24)
@@ -136,6 +139,23 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+if [ "${UNAME_SYSTEM}" = "Linux" ] ; then
+ eval $set_cc_for_build
+ cat << EOF > $dummy.c
+ #include <features.h>
+ #ifdef __UCLIBC__
+ # ifdef __UCLIBC_CONFIG_VERSION__
+ LIBC=uclibc __UCLIBC_CONFIG_VERSION__
+ # else
+ LIBC=uclibc
+ # endif
+ #else
+ LIBC=gnu
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep LIBC= | sed -e 's: ::g'`
+fi
+
# Note: order is significant - the case branches are not exclusive.
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
@@ -158,6 +178,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
arm*) machine=arm-unknown ;;
sh3el) machine=shl-unknown ;;
sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
*) machine=${UNAME_MACHINE_ARCH}-unknown ;;
esac
# The Operating System including object format, if it has switched
@@ -196,53 +217,32 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# contains redundant information, the shorter form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
echo "${machine}-${os}${release}"
- exit 0 ;;
- amiga:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- arc:OpenBSD:*:*)
- echo mipsel-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- hp300:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- mac68k:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- macppc:OpenBSD:*:*)
- echo powerpc-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- mvme68k:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- mvme88k:OpenBSD:*:*)
- echo m88k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- mvmeppc:OpenBSD:*:*)
- echo powerpc-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- pegasos:OpenBSD:*:*)
- echo powerpc-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- pmax:OpenBSD:*:*)
- echo mipsel-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- sgi:OpenBSD:*:*)
- echo mipseb-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- sun3:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- wgrisc:OpenBSD:*:*)
- echo mipsel-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
*:OpenBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
alpha:OSF1:*:*)
- if test $UNAME_RELEASE = "V4.0"; then
+ case $UNAME_RELEASE in
+ *4.0)
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
- fi
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
# According to Compaq, /usr/sbin/psrinfo has been available on
# OSF/1 and Tru64 systems produced since 1995. I hope that
# covers most systems running today. This code pipes the CPU
@@ -280,45 +280,49 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
"EV7.9 (21364A)")
UNAME_MACHINE="alphaev79" ;;
esac
+ # A Pn.n version is a patched version.
# A Vn.n version is a released version.
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
- echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- exit 0 ;;
- Alpha*:OpenVMS:*:*)
- echo alpha-hp-vms
- exit 0 ;;
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit ;;
Alpha\ *:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# Should we change UNAME_MACHINE based on the output of uname instead
# of the specific Alpha model?
echo alpha-pc-interix
- exit 0 ;;
+ exit ;;
21064:Windows_NT:50:3)
echo alpha-dec-winnt3.5
- exit 0 ;;
+ exit ;;
Amiga*:UNIX_System_V:4.0:*)
echo m68k-unknown-sysv4
- exit 0;;
+ exit ;;
*:[Aa]miga[Oo][Ss]:*:*)
echo ${UNAME_MACHINE}-unknown-amigaos
- exit 0 ;;
+ exit ;;
*:[Mm]orph[Oo][Ss]:*:*)
echo ${UNAME_MACHINE}-unknown-morphos
- exit 0 ;;
+ exit ;;
*:OS/390:*:*)
echo i370-ibm-openedition
- exit 0 ;;
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
*:OS400:*:*)
echo powerpc-ibm-os400
- exit 0 ;;
+ exit ;;
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
echo arm-acorn-riscix${UNAME_RELEASE}
- exit 0;;
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
echo hppa1.1-hitachi-hiuxmpp
- exit 0;;
+ exit ;;
Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
if test "`(/bin/universe) 2>/dev/null`" = att ; then
@@ -326,32 +330,32 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
else
echo pyramid-pyramid-bsd
fi
- exit 0 ;;
+ exit ;;
NILE*:*:*:dcosx)
echo pyramid-pyramid-svr4
- exit 0 ;;
+ exit ;;
DRS?6000:unix:4.0:6*)
echo sparc-icl-nx6
- exit 0 ;;
- DRS?6000:UNIX_SV:4.2*:7*)
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
case `/usr/bin/uname -p` in
- sparc) echo sparc-icl-nx7 && exit 0 ;;
+ sparc) echo sparc-icl-nx7; exit ;;
esac ;;
sun4H:SunOS:5.*:*)
echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
+ exit ;;
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
+ exit ;;
i86pc:SunOS:5.*:*)
echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
+ exit ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
# SunOS6. Hard to guess exactly what SunOS6 will be like, but
# it's likely to be more like Solaris than SunOS4.
echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
+ exit ;;
sun4*:SunOS:*:*)
case "`/usr/bin/arch -k`" in
Series*|S4*)
@@ -360,10 +364,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
esac
# Japanese Language versions have a version number like `4.1.3-JL'.
echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
- exit 0 ;;
+ exit ;;
sun3*:SunOS:*:*)
echo m68k-sun-sunos${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
sun*:*:4.2BSD:*)
UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
@@ -375,10 +379,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
echo sparc-sun-sunos${UNAME_RELEASE}
;;
esac
- exit 0 ;;
+ exit ;;
aushp:SunOS:*:*)
echo sparc-auspex-sunos${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
# The situation for MiNT is a little confusing. The machine name
# can be virtually everything (everything which is not
# "atarist" or "atariste" at least should have a processor
@@ -389,37 +393,40 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# be no problem.
atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
*falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
echo m68k-milan-mint${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
echo m68k-hades-mint${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
*:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
echo m68k-unknown-mint${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
powerpc:machten:*:*)
echo powerpc-apple-machten${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
RISC*:Mach:*:*)
echo mips-dec-mach_bsd4.3
- exit 0 ;;
+ exit ;;
RISC*:ULTRIX:*:*)
echo mips-dec-ultrix${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
VAX*:ULTRIX*:*:*)
echo vax-dec-ultrix${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
2020:CLIX:*:* | 2430:CLIX:*:*)
echo clipper-intergraph-clix${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
mips:*:*:UMIPS | mips:*:*:RISCos)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
@@ -443,32 +450,33 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
exit (-1);
}
EOF
- $CC_FOR_BUILD -o $dummy $dummy.c \
- && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
- && exit 0
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
echo mips-mips-riscos${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
Motorola:PowerMAX_OS:*:*)
echo powerpc-motorola-powermax
- exit 0 ;;
+ exit ;;
Motorola:*:4.3:PL8-*)
echo powerpc-harris-powermax
- exit 0 ;;
+ exit ;;
Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
echo powerpc-harris-powermax
- exit 0 ;;
+ exit ;;
Night_Hawk:Power_UNIX:*:*)
echo powerpc-harris-powerunix
- exit 0 ;;
+ exit ;;
m88k:CX/UX:7*:*)
echo m88k-harris-cxux7
- exit 0 ;;
+ exit ;;
m88k:*:4*:R4*)
echo m88k-motorola-sysv4
- exit 0 ;;
+ exit ;;
m88k:*:3*:R3*)
echo m88k-motorola-sysv3
- exit 0 ;;
+ exit ;;
AViiON:dgux:*:*)
# DG/UX returns AViiON for all architectures
UNAME_PROCESSOR=`/usr/bin/uname -p`
@@ -484,29 +492,29 @@ EOF
else
echo i586-dg-dgux${UNAME_RELEASE}
fi
- exit 0 ;;
+ exit ;;
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
echo m88k-dolphin-sysv3
- exit 0 ;;
+ exit ;;
M88*:*:R3*:*)
# Delta 88k system running SVR3
echo m88k-motorola-sysv3
- exit 0 ;;
+ exit ;;
XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
echo m88k-tektronix-sysv3
- exit 0 ;;
+ exit ;;
Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
echo m68k-tektronix-bsd
- exit 0 ;;
+ exit ;;
*:IRIX*:*:*)
echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
- exit 0 ;;
+ exit ;;
????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
- echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
- exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
i*86:AIX:*:*)
echo i386-ibm-aix
- exit 0 ;;
+ exit ;;
ia64:AIX:*:*)
if [ -x /usr/bin/oslevel ] ; then
IBM_REV=`/usr/bin/oslevel`
@@ -514,7 +522,7 @@ EOF
IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
fi
echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
- exit 0 ;;
+ exit ;;
*:AIX:2:3)
if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
eval $set_cc_for_build
@@ -529,14 +537,18 @@ EOF
exit(0);
}
EOF
- $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
- echo rs6000-ibm-aix3.2.5
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
echo rs6000-ibm-aix3.2.4
else
echo rs6000-ibm-aix3.2
fi
- exit 0 ;;
+ exit ;;
*:AIX:*:[45])
IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
@@ -550,28 +562,28 @@ EOF
IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
fi
echo ${IBM_ARCH}-ibm-aix${IBM_REV}
- exit 0 ;;
+ exit ;;
*:AIX:*:*)
echo rs6000-ibm-aix
- exit 0 ;;
+ exit ;;
ibmrt:4.4BSD:*|romp-ibm:BSD:*)
echo romp-ibm-bsd4.4
- exit 0 ;;
+ exit ;;
ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
- exit 0 ;; # report: romp-ibm BSD 4.3
+ exit ;; # report: romp-ibm BSD 4.3
*:BOSX:*:*)
echo rs6000-bull-bosx
- exit 0 ;;
+ exit ;;
DPX/2?00:B.O.S.:*:*)
echo m68k-bull-sysv3
- exit 0 ;;
+ exit ;;
9000/[34]??:4.3bsd:1.*:*)
echo m68k-hp-bsd
- exit 0 ;;
+ exit ;;
hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
echo m68k-hp-bsd4.4
- exit 0 ;;
+ exit ;;
9000/[34678]??:HP-UX:*:*)
HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
case "${UNAME_MACHINE}" in
@@ -633,9 +645,19 @@ EOF
esac
if [ ${HP_ARCH} = "hppa2.0w" ]
then
- # avoid double evaluation of $set_cc_for_build
- test -n "$CC_FOR_BUILD" || eval $set_cc_for_build
- if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep __LP64__ >/dev/null
then
HP_ARCH="hppa2.0w"
else
@@ -643,11 +665,11 @@ EOF
fi
fi
echo ${HP_ARCH}-hp-hpux${HPUX_REV}
- exit 0 ;;
+ exit ;;
ia64:HP-UX:*:*)
HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
echo ia64-hp-hpux${HPUX_REV}
- exit 0 ;;
+ exit ;;
3050*:HI-UX:*:*)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
@@ -675,163 +697,179 @@ EOF
exit (0);
}
EOF
- $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
echo unknown-hitachi-hiuxwe2
- exit 0 ;;
+ exit ;;
9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
echo hppa1.1-hp-bsd
- exit 0 ;;
+ exit ;;
9000/8??:4.3bsd:*:*)
echo hppa1.0-hp-bsd
- exit 0 ;;
+ exit ;;
*9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
echo hppa1.0-hp-mpeix
- exit 0 ;;
+ exit ;;
hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
echo hppa1.1-hp-osf
- exit 0 ;;
+ exit ;;
hp8??:OSF1:*:*)
echo hppa1.0-hp-osf
- exit 0 ;;
+ exit ;;
i*86:OSF1:*:*)
if [ -x /usr/sbin/sysversion ] ; then
echo ${UNAME_MACHINE}-unknown-osf1mk
else
echo ${UNAME_MACHINE}-unknown-osf1
fi
- exit 0 ;;
+ exit ;;
parisc*:Lites*:*:*)
echo hppa1.1-hp-lites
- exit 0 ;;
+ exit ;;
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
echo c1-convex-bsd
- exit 0 ;;
+ exit ;;
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
else echo c2-convex-bsd
fi
- exit 0 ;;
+ exit ;;
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
echo c34-convex-bsd
- exit 0 ;;
+ exit ;;
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
echo c38-convex-bsd
- exit 0 ;;
+ exit ;;
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
echo c4-convex-bsd
- exit 0 ;;
+ exit ;;
CRAY*Y-MP:*:*:*)
echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit 0 ;;
+ exit ;;
CRAY*[A-Z]90:*:*:*)
echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
-e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
-e 's/\.[^.]*$/.X/'
- exit 0 ;;
+ exit ;;
CRAY*TS:*:*:*)
echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit 0 ;;
+ exit ;;
CRAY*T3E:*:*:*)
echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit 0 ;;
+ exit ;;
CRAY*SV1:*:*:*)
echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit 0 ;;
+ exit ;;
*:UNICOS/mp:*:*)
- echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit 0 ;;
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit 0 ;;
+ exit ;;
5000:UNIX_System_V:4.*:*)
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit 0 ;;
+ exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
sparc*:BSD/OS:*:*)
echo sparc-unknown-bsdi${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
*:BSD/OS:*:*)
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
*:FreeBSD:*:*)
- # Determine whether the default compiler uses glibc.
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #include <features.h>
- #if __GLIBC__ >= 2
- LIBC=gnu
- #else
- LIBC=
- #endif
-EOF
- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
- # GNU/KFreeBSD systems have a "k" prefix to indicate we are using
- # FreeBSD's kernel, but not the complete OS.
- case ${LIBC} in gnu) kernel_only='k' ;; esac
- echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
- exit 0 ;;
+ case ${UNAME_MACHINE} in
+ pc98)
+ echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
- exit 0 ;;
- i*:MINGW*:*)
+ exit ;;
+ *:MINGW*:*)
echo ${UNAME_MACHINE}-pc-mingw32
- exit 0 ;;
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
i*:PW*:*)
echo ${UNAME_MACHINE}-pc-pw32
- exit 0 ;;
- x86:Interix*:[34]*)
- echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
- exit 0 ;;
+ exit ;;
+ x86:Interix*:[3456]*)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ EM64T:Interix*:[3456]* | authenticamd:Interix*:[3456]*)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
echo i${UNAME_MACHINE}-pc-mks
- exit 0 ;;
+ exit ;;
i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
# UNAME_MACHINE based on the output of uname instead of i386?
echo i586-pc-interix
- exit 0 ;;
+ exit ;;
i*:UWIN*:*)
echo ${UNAME_MACHINE}-pc-uwin
- exit 0 ;;
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
p*:CYGWIN*:*)
echo powerpcle-unknown-cygwin
- exit 0 ;;
+ exit ;;
prep*:SunOS:5.*:*)
echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
+ exit ;;
*:GNU:*:*)
# the GNU system
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
- exit 0 ;;
+ exit ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
- exit 0 ;;
+ exit ;;
i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix
- exit 0 ;;
+ exit ;;
arm*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit 0 ;;
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
cris:Linux:*:*)
- echo cris-axis-linux-gnu
- exit 0 ;;
+ echo cris-axis-linux-${LIBC}
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-${LIBC}
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-${LIBC}
+ exit ;;
ia64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit 0 ;;
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
m68*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit 0 ;;
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
mips:Linux:*:*)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
@@ -848,8 +886,12 @@ EOF
#endif
#endif
EOF
- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
- test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^CPU/{
+ s: ::g
+ p
+ }'`"
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
;;
mips64:Linux:*:*)
eval $set_cc_for_build
@@ -867,15 +909,22 @@ EOF
#endif
#endif
EOF
- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
- test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^CPU/{
+ s: ::g
+ p
+ }'`"
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-${LIBC}
+ exit ;;
ppc:Linux:*:*)
- echo powerpc-unknown-linux-gnu
- exit 0 ;;
+ echo powerpc-unknown-linux-${LIBC}
+ exit ;;
ppc64:Linux:*:*)
- echo powerpc64-unknown-linux-gnu
- exit 0 ;;
+ echo powerpc64-unknown-linux-${LIBC}
+ exit ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
EV5) UNAME_MACHINE=alphaev5 ;;
@@ -887,35 +936,41 @@ EOF
EV68*) UNAME_MACHINE=alphaev68 ;;
esac
objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
- if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
- echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
- exit 0 ;;
+ if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
- PA7*) echo hppa1.1-unknown-linux-gnu ;;
- PA8*) echo hppa2.0-unknown-linux-gnu ;;
- *) echo hppa-unknown-linux-gnu ;;
+ PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+ PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+ *) echo hppa-unknown-linux-${LIBC} ;;
esac
- exit 0 ;;
+ exit ;;
parisc64:Linux:*:* | hppa64:Linux:*:*)
- echo hppa64-unknown-linux-gnu
- exit 0 ;;
+ echo hppa64-unknown-linux-${LIBC}
+ exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux
- exit 0 ;;
+ exit ;;
sh64*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit 0 ;;
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
sh*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit 0 ;;
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
sparc:Linux:*:* | sparc64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit 0 ;;
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+ exit ;;
x86_64:Linux:*:*)
- echo x86_64-unknown-linux-gnu
- exit 0 ;;
+ echo x86_64-unknown-linux-${LIBC}
+ exit ;;
+ xtensa:Linux:*:*)
+ echo xtensa-unknown-linux-${LIBC}
+ exit ;;
i*86:Linux:*:*)
# The BFD linker knows what the default object file format is, so
# first see if it will tell us. cd to the root directory to prevent
@@ -929,20 +984,22 @@ EOF
p'`
case "$ld_supported_targets" in
elf32-i386)
- TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-${LIBC}"
;;
a.out-i386-linux)
- echo "${UNAME_MACHINE}-pc-linux-gnuaout"
- exit 0 ;;
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}aout"
+ exit ;;
coff-i386)
- echo "${UNAME_MACHINE}-pc-linux-gnucoff"
- exit 0 ;;
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}coff"
+ exit ;;
"")
# Either a pre-BFD a.out linker (linux-gnuoldld) or
# one that does not give us useful --help.
- echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
- exit 0 ;;
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}oldld"
+ exit ;;
esac
+ # This should get integrated into the C code below, but now we hack
+ if [ "$LIBC" != "gnu" ] ; then echo "$TENTATIVE" && exit 0 ; fi
# Determine whether the default compiler is a.out or elf
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
@@ -958,7 +1015,7 @@ EOF
LIBC=gnulibc1
# endif
#else
- #ifdef __INTEL_COMPILER
+ #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
LIBC=gnu
#else
LIBC=gnuaout
@@ -968,16 +1025,23 @@ EOF
LIBC=dietlibc
#endif
EOF
- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
- test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0
- test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^LIBC/{
+ s: ::g
+ p
+ }'`"
+ test x"${LIBC}" != x && {
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit
+ }
+ test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
;;
i*86:DYNIX/ptx:4*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
# earlier versions are messed up and put the nodename in both
# sysname and nodename.
echo i386-sequent-sysv4
- exit 0 ;;
+ exit ;;
i*86:UNIX_SV:4.2MP:2.*)
# Unixware is an offshoot of SVR4, but it has its own version
# number series starting with 2...
@@ -985,27 +1049,27 @@ EOF
# I just have to hope. -- rms.
# Use sysv4.2uw... so that sysv4* matches it.
echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
- exit 0 ;;
+ exit ;;
i*86:OS/2:*:*)
# If we were able to find `uname', then EMX Unix compatibility
# is probably installed.
echo ${UNAME_MACHINE}-pc-os2-emx
- exit 0 ;;
+ exit ;;
i*86:XTS-300:*:STOP)
echo ${UNAME_MACHINE}-unknown-stop
- exit 0 ;;
+ exit ;;
i*86:atheos:*:*)
echo ${UNAME_MACHINE}-unknown-atheos
- exit 0 ;;
- i*86:syllable:*:*)
+ exit ;;
+ i*86:syllable:*:*)
echo ${UNAME_MACHINE}-pc-syllable
- exit 0 ;;
+ exit ;;
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
echo i386-unknown-lynxos${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
i*86:*DOS:*:*)
echo ${UNAME_MACHINE}-pc-msdosdjgpp
- exit 0 ;;
+ exit ;;
i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
@@ -1013,15 +1077,16 @@ EOF
else
echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
fi
- exit 0 ;;
- i*86:*:5:[78]*)
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
case `/bin/uname -X | grep "^Machine"` in
*486*) UNAME_MACHINE=i486 ;;
*Pentium) UNAME_MACHINE=i586 ;;
*Pent*|*Celeron) UNAME_MACHINE=i686 ;;
esac
echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
- exit 0 ;;
+ exit ;;
i*86:*:3.2:*)
if test -f /usr/options/cb.name; then
UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
@@ -1039,73 +1104,73 @@ EOF
else
echo ${UNAME_MACHINE}-pc-sysv32
fi
- exit 0 ;;
+ exit ;;
pc:*:*:*)
# Left here for compatibility:
# uname -m prints for DJGPP always 'pc', but it prints nothing about
# the processor, so we play safe by assuming i386.
echo i386-pc-msdosdjgpp
- exit 0 ;;
+ exit ;;
Intel:Mach:3*:*)
echo i386-pc-mach3
- exit 0 ;;
+ exit ;;
paragon:*:*:*)
echo i860-intel-osf1
- exit 0 ;;
+ exit ;;
i860:*:4.*:*) # i860-SVR4
if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
else # Add other i860-SVR4 vendors below as they are discovered.
echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
fi
- exit 0 ;;
+ exit ;;
mini*:CTIX:SYS*5:*)
# "miniframe"
echo m68010-convergent-sysv
- exit 0 ;;
+ exit ;;
mc68k:UNIX:SYSTEM5:3.51m)
echo m68k-convergent-sysv
- exit 0 ;;
+ exit ;;
M680?0:D-NIX:5.3:*)
echo m68k-diab-dnix
- exit 0 ;;
- M68*:*:R3V[567]*:*)
- test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
- 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0)
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
OS_REL=''
test -r /etc/.relid \
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
- && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && echo i486-ncr-sysv4 && exit 0 ;;
+ && { echo i486-ncr-sysv4; exit; } ;;
m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
echo m68k-unknown-lynxos${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
mc68030:UNIX_System_V:4.*:*)
echo m68k-atari-sysv4
- exit 0 ;;
+ exit ;;
TSUNAMI:LynxOS:2.*:*)
echo sparc-unknown-lynxos${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
rs6000:LynxOS:2.*:*)
echo rs6000-unknown-lynxos${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
echo powerpc-unknown-lynxos${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
SM[BE]S:UNIX_SV:*:*)
echo mips-dde-sysv${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
RM*:ReliantUNIX-*:*:*)
echo mips-sni-sysv4
- exit 0 ;;
+ exit ;;
RM*:SINIX-*:*:*)
echo mips-sni-sysv4
- exit 0 ;;
+ exit ;;
*:SINIX-*:*:*)
if uname -p 2>/dev/null >/dev/null ; then
UNAME_MACHINE=`(uname -p) 2>/dev/null`
@@ -1113,68 +1178,81 @@ EOF
else
echo ns32k-sni-sysv
fi
- exit 0 ;;
+ exit ;;
PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
# says <Richard.M.Bartel@ccMail.Census.GOV>
echo i586-unisys-sysv4
- exit 0 ;;
+ exit ;;
*:UNIX_System_V:4*:FTX*)
# From Gerald Hewes <hewes@openmarket.com>.
# How about differentiating between stratus architectures? -djm
echo hppa1.1-stratus-sysv4
- exit 0 ;;
+ exit ;;
*:*:*:FTX*)
# From seanf@swdc.stratus.com.
echo i860-stratus-sysv4
- exit 0 ;;
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
*:VOS:*:*)
# From Paul.Green@stratus.com.
echo hppa1.1-stratus-vos
- exit 0 ;;
+ exit ;;
mc68*:A/UX:*:*)
echo m68k-apple-aux${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
news*:NEWS-OS:6*:*)
echo mips-sony-newsos6
- exit 0 ;;
+ exit ;;
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
if [ -d /usr/nec ]; then
echo mips-nec-sysv${UNAME_RELEASE}
else
echo mips-unknown-sysv${UNAME_RELEASE}
fi
- exit 0 ;;
+ exit ;;
BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
echo powerpc-be-beos
- exit 0 ;;
+ exit ;;
BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
echo powerpc-apple-beos
- exit 0 ;;
+ exit ;;
BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
echo i586-pc-beos
- exit 0 ;;
+ exit ;;
SX-4:SUPER-UX:*:*)
echo sx4-nec-superux${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
SX-5:SUPER-UX:*:*)
echo sx5-nec-superux${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
SX-6:SUPER-UX:*:*)
echo sx6-nec-superux${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
Power*:Rhapsody:*:*)
echo powerpc-apple-rhapsody${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
*:Rhapsody:*:*)
echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
*:Darwin:*:*)
- case `uname -p` in
- *86) UNAME_PROCESSOR=i686 ;;
- powerpc) UNAME_PROCESSOR=powerpc ;;
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ unknown) UNAME_PROCESSOR=powerpc ;;
esac
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
UNAME_PROCESSOR=`uname -p`
if test "$UNAME_PROCESSOR" = "x86"; then
@@ -1182,22 +1260,25 @@ EOF
UNAME_MACHINE=pc
fi
echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
*:QNX:*:4*)
echo i386-pc-qnx
- exit 0 ;;
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
NSR-?:NONSTOP_KERNEL:*:*)
echo nsr-tandem-nsk${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
*:NonStop-UX:*:*)
echo mips-compaq-nonstopux
- exit 0 ;;
+ exit ;;
BS2000:POSIX*:*:*)
echo bs2000-siemens-sysv
- exit 0 ;;
+ exit ;;
DS/*:UNIX_System_V:*:*)
echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
*:Plan9:*:*)
# "uname -m" is not consistent, so use $cputype instead. 386
# is converted to i386 for consistency with other x86
@@ -1208,31 +1289,47 @@ EOF
UNAME_MACHINE="$cputype"
fi
echo ${UNAME_MACHINE}-unknown-plan9
- exit 0 ;;
+ exit ;;
*:TOPS-10:*:*)
echo pdp10-unknown-tops10
- exit 0 ;;
+ exit ;;
*:TENEX:*:*)
echo pdp10-unknown-tenex
- exit 0 ;;
+ exit ;;
KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
echo pdp10-dec-tops20
- exit 0 ;;
+ exit ;;
XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
echo pdp10-xkl-tops20
- exit 0 ;;
+ exit ;;
*:TOPS-20:*:*)
echo pdp10-unknown-tops20
- exit 0 ;;
+ exit ;;
*:ITS:*:*)
echo pdp10-unknown-its
- exit 0 ;;
+ exit ;;
SEI:*:*:SEIUX)
echo mips-sei-seiux${UNAME_RELEASE}
- exit 0 ;;
- *:DRAGONFLY:*:*)
- echo ${UNAME_MACHINE}-unknown-dragonfly${UNAME_RELEASE}
- exit 0 ;;
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
esac
#echo '(No uname command or uname output not recognized.)' 1>&2
@@ -1264,7 +1361,7 @@ main ()
#endif
#if defined (__arm) && defined (__acorn) && defined (__unix)
- printf ("arm-acorn-riscix"); exit (0);
+ printf ("arm-acorn-riscix\n"); exit (0);
#endif
#if defined (hp300) && !defined (hpux)
@@ -1353,11 +1450,12 @@ main ()
}
EOF
-$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
# Apollos put the system type in the environment.
-test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
# Convex versions that predate uname can use getsysinfo(1)
@@ -1366,22 +1464,22 @@ then
case `getsysinfo -f cpu_type` in
c1*)
echo c1-convex-bsd
- exit 0 ;;
+ exit ;;
c2*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
else echo c2-convex-bsd
fi
- exit 0 ;;
+ exit ;;
c34*)
echo c34-convex-bsd
- exit 0 ;;
+ exit ;;
c38*)
echo c38-convex-bsd
- exit 0 ;;
+ exit ;;
c4*)
echo c4-convex-bsd
- exit 0 ;;
+ exit ;;
esac
fi
@@ -1392,7 +1490,9 @@ This script, last modified $timestamp, has failed to recognize
the operating system you are using. It is advised that you
download the most up to date version of the config scripts from
- ftp://ftp.gnu.org/pub/gnu/config/
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+and
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
If the version you run ($0) is already up to date, please
send the following data and any information you think might be
diff --git a/ext/pdo_sqlite/sqlite/config.sub b/ext/pdo_sqlite/sqlite/config.sub
index 463186dbfd..2a4932e7f5 100644
--- a/ext/pdo_sqlite/sqlite/config.sub
+++ b/ext/pdo_sqlite/sqlite/config.sub
@@ -1,9 +1,10 @@
#! /bin/sh
# Configuration validation subroutine script.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
+# Inc.
-timestamp='2004-01-05'
+timestamp='2007-01-18'
# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
@@ -21,14 +22,15 @@ timestamp='2004-01-05'
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
+
# Please send patches to <config-patches@gnu.org>. Submit a context
# diff and a properly formatted ChangeLog entry.
#
@@ -70,7 +72,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
@@ -83,11 +85,11 @@ Try \`$me --help' for more information."
while test $# -gt 0 ; do
case $1 in
--time-stamp | --time* | -t )
- echo "$timestamp" ; exit 0 ;;
+ echo "$timestamp" ; exit ;;
--version | -v )
- echo "$version" ; exit 0 ;;
+ echo "$version" ; exit ;;
--help | --h* | -h )
- echo "$usage"; exit 0 ;;
+ echo "$usage"; exit ;;
-- ) # Stop option processing
shift; break ;;
- ) # Use stdin as input.
@@ -99,7 +101,7 @@ while test $# -gt 0 ; do
*local*)
# First pass through any local machine types.
echo $1
- exit 0;;
+ exit ;;
* )
break ;;
@@ -118,8 +120,9 @@ esac
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
- nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \
- kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
@@ -145,7 +148,7 @@ case $os in
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
- -apple | -axis)
+ -apple | -axis | -knuth | -cray)
os=
basic_machine=$1
;;
@@ -170,6 +173,10 @@ case $os in
-hiux*)
os=-hiuxwe2
;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
-sco5)
os=-sco3.2v5
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
@@ -186,6 +193,10 @@ case $os in
# Don't forget version if it is 3.2v4 or newer.
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
-sco*)
os=-sco3.2v2
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
@@ -230,14 +241,16 @@ case $basic_machine in
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
| am33_2.0 \
- | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+ | bfin \
| c4x | clipper \
- | d10v | d30v | dlx | dsp16xx \
- | fr30 | frv \
+ | d10v | d30v | dlx | dsp16xx | dvp \
+ | fido | fr30 | frv \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| i370 | i860 | i960 | ia64 \
| ip2k | iq2000 \
- | m32r | m68000 | m68k | m88k | mcore \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | mcore | mep \
| mips | mipsbe | mipseb | mipsel | mipsle \
| mips16 \
| mips64 | mips64el \
@@ -246,6 +259,7 @@ case $basic_machine in
| mips64vr4100 | mips64vr4100el \
| mips64vr4300 | mips64vr4300el \
| mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
| mipsisa32 | mipsisa32el \
| mipsisa32r2 | mipsisa32r2el \
| mipsisa64 | mipsisa64el \
@@ -254,20 +268,24 @@ case $basic_machine in
| mipsisa64sr71k | mipsisa64sr71kel \
| mipstx39 | mipstx39el \
| mn10200 | mn10300 \
+ | mt \
| msp430 \
+ | nios | nios2 \
| ns16k | ns32k \
- | openrisc | or32 \
+ | or32 \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
| pyramid \
- | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]a*eb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
- | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
- | strongarm \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu | strongarm \
| tahoe | thumb | tic4x | tic80 | tron \
| v850 | v850e \
| we32k \
- | x86 | xscale | xstormy16 | xtensa \
+ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
| z8k)
basic_machine=$basic_machine-unknown
;;
@@ -278,6 +296,9 @@ case $basic_machine in
;;
m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
# We use `pc' rather than `unknown'
# because (1) that's what they normally are, and
@@ -297,20 +318,20 @@ case $basic_machine in
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
- | avr-* \
- | bs2000-* \
+ | avr-* | avr32-* \
+ | bfin-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
- | clipper-* | cydra-* \
+ | clipper-* | craynv-* | cydra-* \
| d10v-* | d30v-* | dlx-* \
| elxsi-* \
- | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| i*86-* | i860-* | i960-* | ia64-* \
| ip2k-* | iq2000-* \
- | m32r-* \
+ | m32c-* | m32r-* | m32rle-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
- | m88110-* | m88k-* | mcore-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* \
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
| mips16-* \
| mips64-* | mips64el-* \
@@ -319,6 +340,7 @@ case $basic_machine in
| mips64vr4100-* | mips64vr4100el-* \
| mips64vr4300-* | mips64vr4300el-* \
| mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
| mipsisa32-* | mipsisa32el-* \
| mipsisa32r2-* | mipsisa32r2el-* \
| mipsisa64-* | mipsisa64el-* \
@@ -326,24 +348,28 @@ case $basic_machine in
| mipsisa64sb1-* | mipsisa64sb1el-* \
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
| mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
| msp430-* \
- | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
+ | nios-* | nios2-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
| pyramid-* \
| romp-* | rs6000-* \
- | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]a*eb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
- | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
- | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
| tahoe-* | thumb-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tron-* \
| v850-* | v850e-* | vax-* \
| we32k-* \
- | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
- | xtensa-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa-* \
| ymp-* \
| z8k-*)
;;
@@ -363,6 +389,9 @@ case $basic_machine in
basic_machine=a29k-amd
os=-udi
;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
adobe68k)
basic_machine=m68010-adobe
os=-scout
@@ -442,12 +471,27 @@ case $basic_machine in
basic_machine=j90-cray
os=-unicos
;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16c)
+ basic_machine=cr16c-unknown
+ os=-elf
+ ;;
crds | unos)
basic_machine=m68k-crds
;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
cris | cris-* | etrax*)
basic_machine=cris-axis
;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
da30 | da30-*)
basic_machine=m68k-da30
;;
@@ -470,6 +514,10 @@ case $basic_machine in
basic_machine=m88k-motorola
os=-sysv3
;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
dpx20 | dpx20-*)
basic_machine=rs6000-bull
os=-bosx
@@ -642,16 +690,30 @@ case $basic_machine in
basic_machine=m68k-atari
os=-mint
;;
+ mipsEE* | ee | ps2)
+ basic_machine=mips64r5900el-scei
+ case $os in
+ -linux*)
+ ;;
+ *)
+ os=-elf
+ ;;
+ esac
+ ;;
+ iop)
+ basic_machine=mipsel-scei
+ os=-irx
+ ;;
+ dvp)
+ basic_machine=dvp-scei
+ os=-elf
+ ;;
mips3*-*)
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
;;
mips3*)
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
;;
- mmix*)
- basic_machine=mmix-knuth
- os=-mmixware
- ;;
monitor)
basic_machine=m68k-rom68k
os=-coff
@@ -664,6 +726,9 @@ case $basic_machine in
basic_machine=i386-pc
os=-msdos
;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
mvs)
basic_machine=i370-ibm
os=-mvs
@@ -732,10 +797,6 @@ case $basic_machine in
np1)
basic_machine=np1-gould
;;
- nv1)
- basic_machine=nv1-cray
- os=-unicosmp
- ;;
nsr-tandem)
basic_machine=nsr-tandem
;;
@@ -743,9 +804,8 @@ case $basic_machine in
basic_machine=hppa1.1-oki
os=-proelf
;;
- or32 | or32-*)
+ openrisc | openrisc-*)
basic_machine=or32-unknown
- os=-coff
;;
os400)
basic_machine=powerpc-ibm
@@ -776,6 +836,12 @@ case $basic_machine in
pc532 | pc532-*)
basic_machine=ns32k-pc532
;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
pentium | p5 | k5 | k6 | nexgen | viac3)
basic_machine=i586-pc
;;
@@ -832,6 +898,10 @@ case $basic_machine in
basic_machine=i586-unknown
os=-pw32
;;
+ rdos)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
rom68k)
basic_machine=m68k-rom68k
os=-coff
@@ -858,6 +928,10 @@ case $basic_machine in
sb1el)
basic_machine=mipsisa64sb1el-unknown
;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
sei)
basic_machine=mips-sei
os=-seiux
@@ -869,6 +943,9 @@ case $basic_machine in
basic_machine=sh-hitachi
os=-hms
;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
sh64)
basic_machine=sh64-unknown
;;
@@ -1018,6 +1095,10 @@ case $basic_machine in
basic_machine=hppa1.1-winbond
os=-proelf
;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
xps | xps100)
basic_machine=xps100-honeywell
;;
@@ -1048,6 +1129,9 @@ case $basic_machine in
romp)
basic_machine=romp-ibm
;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
rs6000)
basic_machine=rs6000-ibm
;;
@@ -1064,13 +1148,10 @@ case $basic_machine in
we32k)
basic_machine=we32k-att
;;
- sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
+ sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
basic_machine=sh-unknown
;;
- sh64)
- basic_machine=sh64-unknown
- ;;
- sparc | sparcv9 | sparcv9b)
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
basic_machine=sparc-sun
;;
cydra)
@@ -1143,19 +1224,23 @@ case $os in
| -aos* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
- | -hiux* | -386bsd* | -knetbsd* | -netbsd* | -openbsd* | -kfreebsd* | -freebsd* | -riscix* \
- | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
- | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
- | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly*)
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -irx*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
@@ -1173,7 +1258,7 @@ case $os in
os=`echo $os | sed -e 's|nto|nto-qnx|'`
;;
-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
- | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
| -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
;;
-mac*)
@@ -1282,6 +1367,9 @@ case $os in
-kaos*)
os=-kaos
;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
-none)
;;
*)
@@ -1304,6 +1392,12 @@ else
# system, and we'll never get to this point.
case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
*-acorn)
os=-riscix1.2
;;
@@ -1313,9 +1407,9 @@ case $basic_machine in
arm*-semi)
os=-aout
;;
- c4x-* | tic4x-*)
- os=-coff
- ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
# This must come before the *-dec entry.
pdp10-*)
os=-tops20
@@ -1341,6 +1435,9 @@ case $basic_machine in
m68*-cisco)
os=-aout
;;
+ mep-*)
+ os=-elf
+ ;;
mips*-cisco)
os=-elf
;;
@@ -1359,9 +1456,15 @@ case $basic_machine in
*-be)
os=-beos
;;
+ *-haiku)
+ os=-haiku
+ ;;
*-ibm)
os=-aix
;;
+ *-knuth)
+ os=-mmixware
+ ;;
*-wec)
os=-proelf
;;
@@ -1527,7 +1630,7 @@ case $basic_machine in
esac
echo $basic_machine$os
-exit 0
+exit
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
diff --git a/ext/pdo_sqlite/sqlite/configure b/ext/pdo_sqlite/sqlite/configure
index 666f18668e..7696e6c18a 100755
--- a/ext/pdo_sqlite/sqlite/configure
+++ b/ext/pdo_sqlite/sqlite/configure
@@ -278,15 +278,15 @@ fi
# The HP-UX ksh and POSIX shell print the target directory to stdout
# if CDPATH is set.
-if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
if test -z "$ECHO"; then
if test "X${echo_test_string+set}" != Xset; then
# find a string as large as possible, as long as the shell can cope with it
for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do
# expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
- if (echo_test_string="`eval $cmd`") 2>/dev/null &&
- echo_test_string="`eval $cmd`" &&
+ if (echo_test_string=`eval $cmd`) 2>/dev/null &&
+ echo_test_string=`eval $cmd` &&
(test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
then
break
@@ -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 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_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 SQLITE_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 LIBOBJS LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@@ -1034,6 +1034,7 @@ Optional Features:
--enable-tempstore Use an in-ram database for temporary tables
(never,no,yes,always)
--disable-tcl do not build TCL extension
+ --disable-readline disable readline support [default=detect]
--enable-debug enable debugging & verbose explain
Optional Packages:
@@ -1047,6 +1048,8 @@ Optional Packages:
--with-hints=FILE Read configuration options from FILE
--with-tcl=DIR directory containing tcl configuration
(tclConfig.sh)
+ --with-readline-lib specify readline library
+ --with-readline-inc specify readline include paths
Some influential environment variables:
CC C compiler command
@@ -2613,7 +2616,7 @@ lt_ac_count=0
# Add /usr/xpg4/bin/sed as it is typically found on Solaris
# along with /bin/sed that truncates output.
for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
- test ! -f $lt_ac_sed && break
+ test ! -f $lt_ac_sed && continue
cat /dev/null > conftest.in
lt_ac_count=0
echo $ECHO_N "0123456789$ECHO_C" >conftest.in
@@ -2638,10 +2641,10 @@ for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
fi
done
done
-SED=$lt_cv_path_SED
fi
+SED=$lt_cv_path_SED
echo "$as_me:$LINENO: result: $SED" >&5
echo "${ECHO_T}$SED" >&6
@@ -2718,7 +2721,7 @@ else
if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
lt_cv_path_LD="$ac_dir/$ac_prog"
# Check to see if the program is GNU ld. I'd rather use --version,
- # but apparently some GNU ld's only accept -v.
+ # but apparently some variants of GNU ld only accept -v.
# Break only if it was the GNU/non-GNU ld that we prefer.
case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
*GNU* | *'with BFD'*)
@@ -2752,7 +2755,7 @@ echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6
if test "${lt_cv_prog_gnu_ld+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
- # I'd rather use --version here, but apparently some GNU ld's only accept -v.
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
case `$LD -v 2>&1 </dev/null` in
*GNU* | *'with BFD'*)
lt_cv_prog_gnu_ld=yes
@@ -2782,6 +2785,15 @@ case $reload_flag in
*) reload_flag=" $reload_flag" ;;
esac
reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5
echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6
@@ -2792,36 +2804,43 @@ else
# Let the user override the test.
lt_cv_path_NM="$NM"
else
- lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
- for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
- IFS="$lt_save_ifs"
- test -z "$ac_dir" && ac_dir=.
- tmp_nm="$ac_dir/${ac_tool_prefix}nm"
- if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
- # Check to see if the nm accepts a BSD-compat flag.
- # Adding the `sed 1q' prevents false positives on HP-UX, which says:
- # nm: unknown option "B" ignored
- # Tru64's nm complains that /dev/null is an invalid object file
- case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
- */dev/null* | *'Invalid file or object type'*)
- lt_cv_path_NM="$tmp_nm -B"
- break
- ;;
- *)
- case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
- */dev/null*)
- lt_cv_path_NM="$tmp_nm -p"
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
break
;;
*)
- lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
- continue # so that we can try to find one that supports BSD flags
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
;;
esac
- esac
- fi
+ fi
+ done
+ IFS="$lt_save_ifs"
done
- IFS="$lt_save_ifs"
test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
fi
fi
@@ -2868,21 +2887,21 @@ beos*)
lt_cv_deplibs_check_method=pass_all
;;
-bsdi4*)
+bsdi[45]*)
lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
lt_cv_file_magic_cmd='/usr/bin/file -L'
lt_cv_file_magic_test_file=/shlib/libc.so
;;
cygwin*)
- # win32_libid is a shell function defined in ltmain.sh
+ # func_win32_libid is a shell function defined in ltmain.sh
lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
- lt_cv_file_magic_cmd='win32_libid'
+ lt_cv_file_magic_cmd='func_win32_libid'
;;
mingw* | pw32*)
# Base MSYS/MinGW do not provide the 'file' command needed by
- # win32_libid shell function, so use a weaker test based on 'objdump'.
+ # func_win32_libid shell function, so use a weaker test based on 'objdump'.
lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
lt_cv_file_magic_cmd='$OBJDUMP -f'
;;
@@ -2891,13 +2910,13 @@ darwin* | rhapsody*)
lt_cv_deplibs_check_method=pass_all
;;
-freebsd* | kfreebsd*-gnu)
+freebsd* | kfreebsd*-gnu | dragonfly*)
if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
case $host_cpu in
i*86 )
# Not sure whether the presence of OpenBSD here was a mistake.
# Let's accept both of them until this is cleared up.
- lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library'
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
lt_cv_file_magic_cmd=/usr/bin/file
lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
;;
@@ -2913,7 +2932,7 @@ gnu*)
hpux10.20* | hpux11*)
lt_cv_file_magic_cmd=/usr/bin/file
- case "$host_cpu" in
+ case $host_cpu in
ia64*)
lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
@@ -2929,6 +2948,11 @@ hpux10.20* | hpux11*)
esac
;;
+interix3*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+ ;;
+
irix5* | irix6* | nonstopux*)
case $LD in
*-32|*"-32 ") libmagic=32-bit;;
@@ -2944,7 +2968,7 @@ linux*)
lt_cv_deplibs_check_method=pass_all
;;
-netbsd* | knetbsd*-gnu)
+netbsd*)
if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
else
@@ -2963,12 +2987,10 @@ nto-qnx*)
;;
openbsd*)
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object'
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
else
- lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library'
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
fi
;;
@@ -2976,15 +2998,11 @@ osf3* | osf4* | osf5*)
lt_cv_deplibs_check_method=pass_all
;;
-sco3.2v5*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
solaris*)
lt_cv_deplibs_check_method=pass_all
;;
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+sysv4 | sysv4.3*)
case $host_vendor in
motorola)
lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
@@ -3005,10 +3023,13 @@ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
siemens)
lt_cv_deplibs_check_method=pass_all
;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
esac
;;
-sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7* | sysv4*uw2*)
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
lt_cv_deplibs_check_method=pass_all
;;
esac
@@ -3026,6 +3047,9 @@ test -z "$deplibs_check_method" && deplibs_check_method=unknown
# If no C compiler was specified, use CC.
LTCC=${LTCC-"$CC"}
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
# Allow CC to be a program name with arguments.
compiler=$CC
@@ -3061,7 +3085,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 3064 "configure"' > conftest.$ac_ext
+ echo '#line 3088 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -3104,7 +3128,7 @@ x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; then
- case "`/usr/bin/file conftest.o`" in
+ case `/usr/bin/file conftest.o` in
*32-bit*)
case $host in
x86_64-*linux*)
@@ -3217,6 +3241,26 @@ echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6
CFLAGS="$SAVE_CFLAGS"
fi
;;
+sparc*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*) LD="${LD-ld} -m elf64_sparc" ;;
+ *) LD="${LD-ld} -64" ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
esac
@@ -4201,7 +4245,12 @@ ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-ac_ext=cc
+
+
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
+ ac_ext=cc
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
@@ -4431,6 +4480,8 @@ ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+fi
+
ac_ext=f
ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5'
@@ -4524,7 +4575,7 @@ fi
# Provide some information about the compiler.
-echo "$as_me:4527:" \
+echo "$as_me:4578:" \
"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
@@ -4679,7 +4730,7 @@ if test "${lt_cv_sys_max_cmd_len+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
i=0
- testring="ABCD"
+ teststring="ABCD"
case $build_os in
msdosdjgpp*)
@@ -4714,20 +4765,64 @@ else
lt_cv_sys_max_cmd_len=8192;
;;
- *)
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
# If test is not a shell built-in, we'll probably end up computing a
# maximum length that is only half of the actual maximum length, but
# we can't tell.
- while (test "X"`$CONFIG_SHELL $0 --fallback-echo "X$testring" 2>/dev/null` \
- = "XX$testring") >/dev/null 2>&1 &&
- new_result=`expr "X$testring" : ".*" 2>&1` &&
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ while (test "X"`$SHELL $0 --fallback-echo "X$teststring" 2>/dev/null` \
+ = "XX$teststring") >/dev/null 2>&1 &&
+ new_result=`expr "X$teststring" : ".*" 2>&1` &&
lt_cv_sys_max_cmd_len=$new_result &&
test $i != 17 # 1/2 MB should be enough
do
i=`expr $i + 1`
- testring=$testring$testring
+ teststring=$teststring$teststring
done
- testring=
+ teststring=
# Add a significant safety factor because C++ compilers can tack on massive
# amounts of additional arguments before passing them to the linker.
# It appears as though 1/2 is a usable value.
@@ -4764,9 +4859,6 @@ symcode='[BCDEGRST]'
# Regexp to match symbols that can be accessed directly from C.
sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
-# Transform the above into a raw symbol and a C symbol.
-symxfrm='\1 \2\3 \3'
-
# Transform an extracted symbol line into a proper C declaration
lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'"
@@ -4788,15 +4880,31 @@ hpux*) # Its linker distinguishes data from code symbols
lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
;;
+linux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[ABCDGIRSTW]'
+ lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+ lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
+ fi
+ ;;
irix* | nonstopux*)
symcode='[BCDEGRST]'
;;
osf*)
symcode='[BCDEGQRST]'
;;
-solaris* | sysv5*)
+solaris*)
symcode='[BDRT]'
;;
+sco3.2v5*)
+ symcode='[DT]'
+ ;;
+sysv4.2uw2*)
+ symcode='[DT]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[ABDT]'
+ ;;
sysv4)
symcode='[DFNSTU]'
;;
@@ -4819,8 +4927,11 @@ esac
# Try without a prefix undercore, then with it.
for ac_symprfx in "" "_"; do
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
# Write the raw and C identifiers.
- lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'"
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
# Check to see that the pipe works correctly.
pipe_works=no
@@ -4982,7 +5093,7 @@ esac
# Sed substitution that helps us do robust quoting. It backslashifies
# metacharacters that are still active within double-quoted strings.
-Xsed='sed -e s/^X//'
+Xsed='sed -e 1s/^X//'
sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'
# Same as above, but do not quote variable references.
@@ -5002,7 +5113,7 @@ rm="rm -f"
default_ofile=libtool
can_build_shared=yes
-# All known linkers require a `.a' archive for static linking (except M$VC,
+# All known linkers require a `.a' archive for static linking (except MSVC,
# which needs '.lib').
libext=a
ltmain="$ac_aux_dir/ltmain.sh"
@@ -5259,6 +5370,7 @@ test -z "$AR_FLAGS" && AR_FLAGS=cru
test -z "$AS" && AS=as
test -z "$CC" && CC=cc
test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
test -z "$DLLTOOL" && DLLTOOL=dlltool
test -z "$LD" && LD=ld
test -z "$LN_S" && LN_S="ln -s"
@@ -5278,15 +5390,26 @@ old_postuninstall_cmds=
if test -n "$RANLIB"; then
case $host_os in
openbsd*)
- old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds"
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
;;
*)
- old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
;;
esac
old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
fi
+for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+
+
# Only perform the check for file, if the check method requires it
case $deplibs_check_method in
file_magic*)
@@ -5312,7 +5435,7 @@ else
if test -n "$file_magic_test_file"; then
case $deplibs_check_method in
"file_magic "*)
- file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
$EGREP "$file_magic_regex" > /dev/null; then
@@ -5374,7 +5497,7 @@ else
if test -n "$file_magic_test_file"; then
case $deplibs_check_method in
"file_magic "*)
- file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
$EGREP "$file_magic_regex" > /dev/null; then
@@ -5442,6 +5565,67 @@ else
fi;
test -z "$pic_mode" && pic_mode=default
+# Check if we have a version mismatch between libtool.m4 and ltmain.sh.
+#
+# Note: This should be in AC_LIBTOOL_SETUP, _after_ $ltmain have been defined.
+# We also should do it _before_ AC_LIBTOOL_LANG_C_CONFIG that actually
+# calls AC_LIBTOOL_CONFIG and creates libtool.
+#
+echo "$as_me:$LINENO: checking for correct ltmain.sh version" >&5
+echo $ECHO_N "checking for correct ltmain.sh version... $ECHO_C" >&6
+if test "x$ltmain" = "x" ; then
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ { { echo "$as_me:$LINENO: error:
+
+*** [Gentoo] sanity check failed! ***
+*** \$ltmain is not defined, please check the patch for consistency! ***
+" >&5
+echo "$as_me: error:
+
+*** [Gentoo] sanity check failed! ***
+*** \$ltmain is not defined, please check the patch for consistency! ***
+" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+gentoo_lt_version="1.5.22"
+gentoo_ltmain_version=`sed -n '/^[ ]*VERSION=/{s/^[ ]*VERSION=//;p;q;}' "$ltmain"`
+if test "x$gentoo_lt_version" != "x$gentoo_ltmain_version" ; then
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ { { echo "$as_me:$LINENO: error:
+
+*** [Gentoo] sanity check failed! ***
+*** libtool.m4 and ltmain.sh have a version mismatch! ***
+*** (libtool.m4 = $gentoo_lt_version, ltmain.sh = $gentoo_ltmain_version) ***
+
+Please run:
+
+ libtoolize --copy --force
+
+if appropriate, please contact the maintainer of this
+package (or your distribution) for help.
+" >&5
+echo "$as_me: error:
+
+*** [Gentoo] sanity check failed! ***
+*** libtool.m4 and ltmain.sh have a version mismatch! ***
+*** (libtool.m4 = $gentoo_lt_version, ltmain.sh = $gentoo_ltmain_version) ***
+
+Please run:
+
+ libtoolize --copy --force
+
+if appropriate, please contact the maintainer of this
+package (or your distribution) for help.
+" >&2;}
+ { (exit 1); exit 1; }; }
+else
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+fi
+
+
# Use C for the default configuration in the libtool script
tagname=
lt_save_CC="$CC"
@@ -5469,68 +5653,25 @@ lt_simple_link_test_code='int main(){return(0);}\n'
# If no C compiler was specified, use CC.
LTCC=${LTCC-"$CC"}
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
# Allow CC to be a program name with arguments.
compiler=$CC
-#
-# Check for any special shared library compilation flags.
-#
-lt_prog_cc_shlib=
-if test "$GCC" = no; then
- case $host_os in
- sco3.2v5*)
- lt_prog_cc_shlib='-belf'
- ;;
- esac
-fi
-if test -n "$lt_prog_cc_shlib"; then
- { echo "$as_me:$LINENO: WARNING: \`$CC' requires \`$lt_prog_cc_shlib' to build shared libraries" >&5
-echo "$as_me: WARNING: \`$CC' requires \`$lt_prog_cc_shlib' to build shared libraries" >&2;}
- if echo "$old_CC $old_CFLAGS " | grep "[ ]$lt_prog_cc_shlib[ ]" >/dev/null; then :
- else
- { echo "$as_me:$LINENO: WARNING: add \`$lt_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&5
-echo "$as_me: WARNING: add \`$lt_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&2;}
- lt_cv_prog_cc_can_build_shared=no
- fi
-fi
-
-
-#
-# Check to make sure the static flag actually works.
-#
-echo "$as_me:$LINENO: checking if $compiler static flag $lt_prog_compiler_static works" >&5
-echo $ECHO_N "checking if $compiler static flag $lt_prog_compiler_static works... $ECHO_C" >&6
-if test "${lt_prog_compiler_static_works+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- lt_prog_compiler_static_works=no
- save_LDFLAGS="$LDFLAGS"
- LDFLAGS="$LDFLAGS $lt_prog_compiler_static"
- printf "$lt_simple_link_test_code" > conftest.$ac_ext
- if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s conftest.err; then
- # Append any errors to the config.log.
- cat conftest.err 1>&5
- else
- lt_prog_compiler_static_works=yes
- fi
- fi
- $rm conftest*
- LDFLAGS="$save_LDFLAGS"
-
-fi
-echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works" >&5
-echo "${ECHO_T}$lt_prog_compiler_static_works" >&6
-
-if test x"$lt_prog_compiler_static_works" = xyes; then
- :
-else
- lt_prog_compiler_static=
-fi
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+printf "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$rm conftest*
+ac_outfile=conftest.$ac_objext
+printf "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$rm conftest*
@@ -5555,18 +5696,20 @@ else
# with a dollar sign (not a hyphen), so the echo should work correctly.
# The option is referenced via a variable to avoid confusing sed.
lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:5561: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:5702: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:5565: \$? = $ac_status" >&5
+ echo "$as_me:5706: \$? = $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
- if test ! -s conftest.err; then
+ # So say no if there are warnings other than the usual output.
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
lt_cv_prog_compiler_rtti_exceptions=yes
fi
fi
@@ -5627,6 +5770,11 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
lt_prog_compiler_pic='-fno-common'
;;
+ interix3*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
msdosdjgpp*)
# Just because we use GCC doesn't mean we suddenly get shared libraries
# on systems that don't support them.
@@ -5643,7 +5791,7 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
hpux*)
# PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
# not for PA HP-UX.
- case "$host_cpu" in
+ case $host_cpu in
hppa*64*|ia64*)
# +Z the default
;;
@@ -5669,6 +5817,16 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
fi
;;
+ darwin*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ case $cc_basename in
+ xlc*)
+ lt_prog_compiler_pic='-qnocommon'
+ lt_prog_compiler_wl='-Wl,'
+ ;;
+ esac
+ ;;
mingw* | pw32* | os2*)
# This hack is so that the source file can tell whether it is being
@@ -5680,7 +5838,7 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
lt_prog_compiler_wl='-Wl,'
# PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
# not for PA HP-UX.
- case "$host_cpu" in
+ case $host_cpu in
hppa*64*|ia64*)
# +Z the default
;;
@@ -5704,12 +5862,19 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
;;
linux*)
- case $CC in
+ case $cc_basename in
icc* | ecc*)
lt_prog_compiler_wl='-Wl,'
lt_prog_compiler_pic='-KPIC'
lt_prog_compiler_static='-static'
;;
+ pgcc* | pgf77* | pgf90* | pgf95*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
ccc*)
lt_prog_compiler_wl='-Wl,'
# All Alpha code is PIC.
@@ -5724,15 +5889,15 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
lt_prog_compiler_static='-non_shared'
;;
- sco3.2v5*)
- lt_prog_compiler_pic='-Kpic'
- lt_prog_compiler_static='-dn'
- ;;
-
solaris*)
- lt_prog_compiler_wl='-Wl,'
lt_prog_compiler_pic='-KPIC'
lt_prog_compiler_static='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95*)
+ lt_prog_compiler_wl='-Qoption ld ';;
+ *)
+ lt_prog_compiler_wl='-Wl,';;
+ esac
;;
sunos4*)
@@ -5741,7 +5906,7 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
lt_prog_compiler_static='-Bstatic'
;;
- sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ sysv4 | sysv4.2uw2* | sysv4.3*)
lt_prog_compiler_wl='-Wl,'
lt_prog_compiler_pic='-KPIC'
lt_prog_compiler_static='-Bstatic'
@@ -5754,6 +5919,17 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
fi
;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ unicos*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_can_build_shared=no
+ ;;
+
uts4*)
lt_prog_compiler_pic='-pic'
lt_prog_compiler_static='-Bstatic'
@@ -5788,18 +5964,20 @@ else
# with a dollar sign (not a hyphen), so the echo should work correctly.
# The option is referenced via a variable to avoid confusing sed.
lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:5794: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:5970: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:5798: \$? = $ac_status" >&5
+ echo "$as_me:5974: \$? = $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
- if test ! -s conftest.err; then
+ # So say no if there are warnings other than the usual output.
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
lt_prog_compiler_pic_works=yes
fi
fi
@@ -5820,7 +5998,7 @@ else
fi
fi
-case "$host_os" in
+case $host_os in
# For platforms which do not support PIC, -DPIC is meaningless:
*djgpp*)
lt_prog_compiler_pic=
@@ -5830,6 +6008,48 @@ case "$host_os" in
;;
esac
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6
+if test "${lt_prog_compiler_static_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_static_works=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ printf "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_prog_compiler_static_works=yes
+ fi
+ else
+ lt_prog_compiler_static_works=yes
+ fi
+ fi
+ $rm conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works" >&5
+echo "${ECHO_T}$lt_prog_compiler_static_works" >&6
+
+if test x"$lt_prog_compiler_static_works" = xyes; then
+ :
+else
+ lt_prog_compiler_static=
+fi
+
+
echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
if test "${lt_cv_prog_compiler_c_o+set}" = set; then
@@ -5848,23 +6068,25 @@ else
# Note that $ac_compile itself does not contain backslashes and begins
# with a dollar sign (not a hyphen), so the echo should work correctly.
lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:5854: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:6074: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:5858: \$? = $ac_status" >&5
+ echo "$as_me:6078: \$? = $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
# So say no if there are warnings
- if test ! -s out/conftest.err; then
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
lt_cv_prog_compiler_c_o=yes
fi
fi
- chmod u+w .
+ chmod u+w . 2>&5
$rm conftest*
# SGI C++ compiler will create directory out/ii_files/ for
# template instantiation
@@ -5940,6 +6162,16 @@ echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared librar
# rely on this symbol name, it's probably fine to never include it in
# preloaded symbol tables.
extract_expsyms_cmds=
+ # Just being paranoid about ensuring that cc_basename is set.
+ for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
case $host_os in
cygwin* | mingw* | pw32*)
@@ -5950,6 +6182,10 @@ echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared librar
with_gnu_ld=no
fi
;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
openbsd*)
with_gnu_ld=no
;;
@@ -5960,6 +6196,27 @@ echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared librar
# If archive_cmds runs LD, not CC, wlarc should be empty
wlarc='${wl}'
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
# See if GNU ld supports shared libraries.
case $host_os in
aix3* | aix4* | aix5*)
@@ -6010,10 +6267,10 @@ EOF
allow_undefined_flag=unsupported
always_export_symbols=no
enable_shared_with_static_runtimes=yes
- export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
# If the export-symbols file already is a .def file (1st line
# is EXPORTS), use it as is; otherwise, prepend...
archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
@@ -6022,13 +6279,59 @@ EOF
echo EXPORTS > $output_objdir/$soname.def;
cat $export_symbols >> $output_objdir/$soname.def;
fi~
- $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ interix3*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ linux*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ tmp_addflag=
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ esac
+ archive_cmds='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test $supports_anon_versioning = yes; then
+ archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ $echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
else
ld_shlibs=no
fi
;;
- netbsd* | knetbsd*-gnu)
+ netbsd*)
if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
wlarc=
@@ -6038,7 +6341,7 @@ EOF
fi
;;
- solaris* | sysv5*)
+ solaris*)
if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
ld_shlibs=no
cat <<EOF 1>&2
@@ -6059,6 +6362,33 @@ EOF
fi
;;
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+
sunos4*)
archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
wlarc=
@@ -6066,31 +6396,6 @@ EOF
hardcode_shlibpath_var=no
;;
- linux*)
- if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_cmds="$tmp_archive_cmds"
- supports_anon_versioning=no
- case `$LD -v 2>/dev/null` in
- *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
- *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
- *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
- *\ 2.11.*) ;; # other 2.11 versions
- *) supports_anon_versioning=yes ;;
- esac
- if test $supports_anon_versioning = yes; then
- archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~
-cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-$echo "local: *; };" >> $output_objdir/$libname.ver~
- $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
- else
- archive_expsym_cmds="$tmp_archive_cmds"
- fi
- else
- ld_shlibs=no
- fi
- ;;
-
*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
@@ -6101,16 +6406,11 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
;;
esac
- if test "$ld_shlibs" = yes; then
- runpath_var=LD_RUN_PATH
- hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
- export_dynamic_flag_spec='${wl}--export-dynamic'
- # ancient GNU ld didn't support --whole-archive et. al.
- if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
- whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
- else
- whole_archive_flag_spec=
- fi
+ if test "$ld_shlibs" = no; then
+ runpath_var=
+ hardcode_libdir_flag_spec=
+ export_dynamic_flag_spec=
+ whole_archive_flag_spec=
fi
else
# PORTME fill in a description of your system's linker (not GNU ld)
@@ -6122,7 +6422,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
# Note: this linker hardcodes the directories in LIBPATH if there
# are no directories specified by -L.
hardcode_minus_L=yes
- if test "$GCC" = yes && test -z "$link_static_flag"; then
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
# Neither direct hardcoding nor static linking is supported with a
# broken collect2.
hardcode_direct=unsupported
@@ -6156,6 +6456,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
break
fi
done
+ ;;
esac
exp_sym_flag='-bexport'
@@ -6174,7 +6475,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
link_all_deplibs=yes
if test "$GCC" = yes; then
- case $host_os in aix4.012|aix4.012.*)
+ case $host_os in aix4.[012]|aix4.[012].*)
# We only want to do this on AIX 4.2 and lower, the check
# below for broken collect2 doesn't work under 4.3+
collect2name=`${CC} -print-prog-name=collect2`
@@ -6193,8 +6494,12 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
hardcode_libdir_flag_spec='-L$libdir'
hardcode_libdir_separator=
fi
+ ;;
esac
shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
else
# not using gcc
if test "$host_cpu" = ia64; then
@@ -6202,11 +6507,11 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
# chokes on -Wl,-G. The following line is correct:
shared_flag='-G'
else
- if test "$aix_use_runtimelinking" = yes; then
+ if test "$aix_use_runtimelinking" = yes; then
shared_flag='${wl}-G'
else
shared_flag='${wl}-bM:SRE'
- fi
+ fi
fi
fi
@@ -6271,12 +6576,12 @@ rm -f conftest.err conftest.$ac_objext \
if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
- archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
else
if test "$host_cpu" = ia64; then
hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
allow_undefined_flag="-z nodefs"
- archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
else
# Determine the default libpath from the value encoded in an empty executable.
cat >conftest.$ac_ext <<_ACEOF
@@ -6336,13 +6641,11 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
# -berok will link without error, but may produce a broken library.
no_undefined_flag=' ${wl}-bernotok'
allow_undefined_flag=' ${wl}-berok'
- # -bexpall does not export symbols beginning with underscore (_)
- always_export_symbols=yes
# Exported symbols can be pulled into shared objects from archives
- whole_archive_flag_spec=' '
+ whole_archive_flag_spec='$convenience'
archive_cmds_need_lc=yes
- # This is similar to how AIX traditionally builds it's shared libraries.
- archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
fi
fi
;;
@@ -6355,7 +6658,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
ld_shlibs=no
;;
- bsdi4*)
+ bsdi[45]*)
export_dynamic_flag_spec=-rdynamic
;;
@@ -6369,7 +6672,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
# Tell ltmain to make .lib files, not .a files.
libext=lib
# Tell ltmain to make .dll files, not .so files.
- shrext=".dll"
+ shrext_cmds=".dll"
# FIXME: Setting linknames here is a bad hack.
archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
# The linker will automatically build a .lib file if we build a DLL.
@@ -6381,52 +6684,52 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
;;
darwin* | rhapsody*)
- if test "$GXX" = yes ; then
- archive_cmds_need_lc=no
- case "$host_os" in
- rhapsody* | darwin1.[012])
- allow_undefined_flag='-undefined suppress'
- ;;
- *) # Darwin 1.3 on
- if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
- allow_undefined_flag='-flat_namespace -undefined suppress'
- else
- case ${MACOSX_DEPLOYMENT_TARGET} in
- 10.[012])
- allow_undefined_flag='-flat_namespace -undefined suppress'
- ;;
- 10.*)
- allow_undefined_flag='-undefined dynamic_lookup'
- ;;
- esac
- fi
- ;;
+ case $host_os in
+ rhapsody* | darwin1.[012])
+ allow_undefined_flag='${wl}-undefined ${wl}suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[012])
+ allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ ;;
+ 10.*)
+ allow_undefined_flag='${wl}-undefined ${wl}dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
esac
- lt_int_apple_cc_single_mod=no
- output_verbose_link_cmd='echo'
- if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
- lt_int_apple_cc_single_mod=yes
- fi
- if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
- archive_cmds='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
- else
- archive_cmds='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
- fi
- module_cmds='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
- # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
- if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
- archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- else
- archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- fi
- module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ archive_cmds_need_lc=no
hardcode_direct=no
hardcode_automatic=yes
hardcode_shlibpath_var=unsupported
- whole_archive_flag_spec='-all_load $convenience'
+ whole_archive_flag_spec=''
link_all_deplibs=yes
+ if test "$GCC" = yes ; then
+ output_verbose_link_cmd='echo'
+ archive_cmds='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
else
- ld_shlibs=no
+ case $cc_basename in
+ xlc*)
+ output_verbose_link_cmd='echo'
+ archive_cmds='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+ module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ ;;
+ *)
+ ld_shlibs=no
+ ;;
+ esac
fi
;;
@@ -6460,7 +6763,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
;;
# FreeBSD 3 and greater uses gcc -shared to do shared libraries.
- freebsd* | kfreebsd*-gnu)
+ freebsd* | kfreebsd*-gnu | dragonfly*)
archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
@@ -6483,47 +6786,62 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
export_dynamic_flag_spec='${wl}-E'
;;
- hpux10* | hpux11*)
+ hpux10*)
if test "$GCC" = yes -a "$with_gnu_ld" = no; then
- case "$host_cpu" in
- hppa*64*|ia64*)
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+
+ hardcode_direct=yes
+ export_dynamic_flag_spec='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
+ ia64*)
+ archive_cmds='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
*)
archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
else
- case "$host_cpu" in
- hppa*64*|ia64*)
- archive_cmds='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
;;
*)
- archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
fi
if test "$with_gnu_ld" = no; then
- case "$host_cpu" in
- hppa*64*)
- hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
hardcode_libdir_flag_spec_ld='+b $libdir'
- hardcode_libdir_separator=:
- hardcode_direct=no
- hardcode_shlibpath_var=no
- ;;
- ia64*)
- hardcode_libdir_flag_spec='-L$libdir'
hardcode_direct=no
hardcode_shlibpath_var=no
-
- # hardcode_minus_L: Not really in the search PATH,
- # but as the default location of the library.
- hardcode_minus_L=yes
;;
*)
- hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
- hardcode_libdir_separator=:
hardcode_direct=yes
export_dynamic_flag_spec='${wl}-E'
@@ -6547,7 +6865,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
link_all_deplibs=yes
;;
- netbsd* | knetbsd*-gnu)
+ netbsd*)
if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
else
@@ -6571,6 +6889,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
hardcode_shlibpath_var=no
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
export_dynamic_flag_spec='${wl}-E'
else
@@ -6616,7 +6935,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
allow_undefined_flag=' -expect_unresolved \*'
archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
- $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
+ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp'
# Both c and cxx compiler support -rpath directly
hardcode_libdir_flag_spec='-rpath $libdir'
@@ -6624,21 +6943,15 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
hardcode_libdir_separator=:
;;
- sco3.2v5*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_shlibpath_var=no
- export_dynamic_flag_spec='${wl}-Bexport'
- runpath_var=LD_RUN_PATH
- hardcode_runpath_var=yes
- ;;
-
solaris*)
no_undefined_flag=' -z text'
if test "$GCC" = yes; then
+ wlarc='${wl}'
archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
$CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
else
+ wlarc=''
archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
$LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
@@ -6647,8 +6960,18 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
hardcode_shlibpath_var=no
case $host_os in
solaris2.[0-5] | solaris2.[0-5].*) ;;
- *) # Supported since Solaris 2.6 (maybe 2.5.1?)
- whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;;
+ *)
+ # The compiler driver will combine linker options so we
+ # cannot just pass the convience library names through
+ # without $wl, iff we do not link with $LD.
+ # Luckily, gcc supports the same syntax we need for Sun Studio.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ case $wlarc in
+ '')
+ whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;;
+ *)
+ whole_archive_flag_spec='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;;
+ esac ;;
esac
link_all_deplibs=yes
;;
@@ -6705,36 +7028,45 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
fi
;;
- sysv4.2uw2*)
- archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes
- hardcode_minus_L=no
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*)
+ no_undefined_flag='${wl}-z,text'
+ archive_cmds_need_lc=no
hardcode_shlibpath_var=no
- hardcode_runpath_var=yes
- runpath_var=LD_RUN_PATH
- ;;
+ runpath_var='LD_RUN_PATH'
- sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*)
- no_undefined_flag='${wl}-z ${wl}text'
if test "$GCC" = yes; then
- archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
else
- archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
fi
- runpath_var='LD_RUN_PATH'
- hardcode_shlibpath_var=no
;;
- sysv5*)
- no_undefined_flag=' -z text'
- # $CC -shared without GNU ld will not create a library from C++
- # object files and a static libstdc++, better avoid it by now
- archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
- archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
- $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
- hardcode_libdir_flag_spec=
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag='${wl}-z,text'
+ allow_undefined_flag='${wl}-z,nodefs'
+ archive_cmds_need_lc=no
hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ export_dynamic_flag_spec='${wl}-Bexport'
runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
;;
uts4*)
@@ -6753,11 +7085,6 @@ echo "$as_me:$LINENO: result: $ld_shlibs" >&5
echo "${ECHO_T}$ld_shlibs" >&6
test "$ld_shlibs" = no && can_build_shared=no
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
- variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
-
#
# Do we need to explicitly link libc?
#
@@ -6790,6 +7117,7 @@ echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&
libobjs=conftest.$ac_objext
deplibs=
wl=$lt_prog_compiler_wl
+ pic_flag=$lt_prog_compiler_pic
compiler_flags=-v
linker_flags=-v
verstring=
@@ -6825,7 +7153,7 @@ echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
library_names_spec=
libname_spec='lib$name'
soname_spec=
-shrext=".so"
+shrext_cmds=".so"
postinstall_cmds=
postuninstall_cmds=
finish_cmds=
@@ -6922,7 +7250,7 @@ beos*)
shlibpath_var=LIBRARY_PATH
;;
-bsdi4*)
+bsdi[45]*)
version_type=linux
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
@@ -6938,7 +7266,7 @@ bsdi4*)
cygwin* | mingw* | pw32*)
version_type=windows
- shrext=".dll"
+ shrext_cmds=".dll"
need_version=no
need_lib_prefix=no
@@ -6950,7 +7278,8 @@ cygwin* | mingw* | pw32*)
dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
dldir=$destdir/`dirname \$dlpath`~
test -d \$dldir || mkdir -p \$dldir~
- $install_prog $dir/$dlname \$dldir/$dlname'
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname'
postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
dlpath=$dir/\$dldll~
$rm \$dlpath'
@@ -6980,11 +7309,35 @@ cygwin* | mingw* | pw32*)
;;
pw32*)
# pw32 DLLs use 'pw' prefix rather than 'lib'
- library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
;;
esac
;;
+ linux*)
+ if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+ if test $supports_anon_versioning = yes; then
+ archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~
+cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+$echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ else
+ $archive_expsym_cmds="$archive_cmds"
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
*)
library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
;;
@@ -7003,7 +7356,7 @@ darwin* | rhapsody*)
soname_spec='${libname}${release}${major}$shared_ext'
shlibpath_overrides_runpath=yes
shlibpath_var=DYLD_LIBRARY_PATH
- shrext='$(test .$module = .yes && echo .so || echo .dylib)'
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
# Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
if test "$GCC" = yes; then
sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
@@ -7038,9 +7391,25 @@ kfreebsd*-gnu)
dynamic_linker='GNU ld.so'
;;
-freebsd*)
- objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
- version_type=freebsd-$objformat
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[123]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ # Handle Gentoo/FreeBSD as it was Linux
+ case $host_vendor in
+ gentoo)
+ version_type=linux ;;
+ *)
+ version_type=freebsd-$objformat ;;
+ esac
+
case $version_type in
freebsd-elf*)
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
@@ -7051,20 +7420,31 @@ freebsd*)
library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
need_version=yes
;;
+ linux)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ need_lib_prefix=no
+ need_version=no
+ ;;
esac
shlibpath_var=LD_LIBRARY_PATH
case $host_os in
freebsd2*)
shlibpath_overrides_runpath=yes
;;
- freebsd3.01* | freebsdelf3.01*)
+ freebsd3.[01]* | freebsdelf3.[01]*)
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
;;
- *) # from 3.2 on
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
;;
+ freebsd*) # from 4.6 on
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
esac
;;
@@ -7084,9 +7464,9 @@ hpux9* | hpux10* | hpux11*)
version_type=sunos
need_lib_prefix=no
need_version=no
- case "$host_cpu" in
+ case $host_cpu in
ia64*)
- shrext='.so'
+ shrext_cmds='.so'
hardcode_into_libs=yes
dynamic_linker="$host_os dld.so"
shlibpath_var=LD_LIBRARY_PATH
@@ -7101,7 +7481,7 @@ hpux9* | hpux10* | hpux11*)
sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
hppa*64*)
- shrext='.sl'
+ shrext_cmds='.sl'
hardcode_into_libs=yes
dynamic_linker="$host_os dld.sl"
shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
@@ -7112,7 +7492,7 @@ hpux9* | hpux10* | hpux11*)
sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
*)
- shrext='.sl'
+ shrext_cmds='.sl'
dynamic_linker="$host_os dld.sl"
shlibpath_var=SHLIB_PATH
shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
@@ -7124,6 +7504,18 @@ hpux9* | hpux10* | hpux11*)
postinstall_cmds='chmod 555 $lib'
;;
+interix3*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
irix5* | irix6* | nonstopux*)
case $host_os in
nonstopux*) version_type=nonstopux ;;
@@ -7183,8 +7575,8 @@ linux*)
# Append ld.so.conf contents to the search path
if test -f /etc/ld.so.conf; then
- ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf`
- sys_lib_dlsearch_path_spec="/lib /usr/lib $ld_extra"
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
fi
# We used to test for /lib/ld.so.1 and disable shared libraries on
@@ -7245,8 +7637,13 @@ nto-qnx*)
openbsd*)
version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
need_lib_prefix=no
- need_version=yes
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
shlibpath_var=LD_LIBRARY_PATH
@@ -7266,7 +7663,7 @@ openbsd*)
os2*)
libname_spec='$name'
- shrext=".dll"
+ shrext_cmds=".dll"
need_lib_prefix=no
library_names_spec='$libname${shared_ext} $libname.a'
dynamic_linker='OS/2 ld.exe'
@@ -7284,13 +7681,6 @@ osf3* | osf4* | osf5*)
sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
;;
-sco3.2v5*)
- version_type=osf
- soname_spec='${libname}${release}${shared_ext}$major'
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
solaris*)
version_type=linux
need_lib_prefix=no
@@ -7316,7 +7706,7 @@ sunos4*)
need_version=yes
;;
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+sysv4 | sysv4.3*)
version_type=linux
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
@@ -7349,6 +7739,29 @@ sysv4*MP*)
fi
;;
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ shlibpath_overrides_runpath=no
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ shlibpath_overrides_runpath=yes
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
uts4*)
version_type=linux
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
@@ -7364,12 +7777,17 @@ echo "$as_me:$LINENO: result: $dynamic_linker" >&5
echo "${ECHO_T}$dynamic_linker" >&6
test "$dynamic_linker" = no && can_build_shared=no
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
hardcode_action=
if test -n "$hardcode_libdir_flag_spec" || \
- test -n "$runpath_var " || \
- test "X$hardcode_automatic"="Xyes" ; then
+ test -n "$runpath_var" || \
+ test "X$hardcode_automatic" = "Xyes" ; then
# We can hardcode non-existant directories.
if test "$hardcode_direct" != no &&
@@ -8019,7 +8437,7 @@ fi
test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
save_LDFLAGS="$LDFLAGS"
- eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
save_LIBS="$LIBS"
LIBS="$lt_cv_dlopen_libs $LIBS"
@@ -8035,7 +8453,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 8038 "configure"
+#line 8456 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -8092,6 +8510,8 @@ int main ()
else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
/* dlclose (self); */
}
+ else
+ puts (dlerror ());
exit (status);
}
@@ -8101,12 +8521,12 @@ EOF
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
- (./conftest; exit; ) 2>/dev/null
+ (./conftest; exit; ) >&5 2>/dev/null
lt_status=$?
case x$lt_status in
x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
- x$lt_unknown|x*) lt_cv_dlopen_self=no ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
esac
else :
# compilation failed
@@ -8121,7 +8541,7 @@ echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
echo "${ECHO_T}$lt_cv_dlopen_self" >&6
if test "x$lt_cv_dlopen_self" = xyes; then
- LDFLAGS="$LDFLAGS $link_static_flag"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6
if test "${lt_cv_dlopen_self_static+set}" = set; then
@@ -8133,7 +8553,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 8136 "configure"
+#line 8556 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -8190,6 +8610,8 @@ int main ()
else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
/* dlclose (self); */
}
+ else
+ puts (dlerror ());
exit (status);
}
@@ -8199,12 +8621,12 @@ EOF
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
- (./conftest; exit; ) 2>/dev/null
+ (./conftest; exit; ) >&5 2>/dev/null
lt_status=$?
case x$lt_status in
x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
- x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
esac
else :
# compilation failed
@@ -8237,7 +8659,7 @@ echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6
fi
-# Report which librarie types wil actually be built
+# Report which library types will actually be built
echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5
echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6
echo "$as_me:$LINENO: result: $can_build_shared" >&5
@@ -8249,7 +8671,7 @@ test "$can_build_shared" = "no" && enable_shared=no
# On AIX, shared libraries and static libraries use the same namespace, and
# are all built from PIC.
-case "$host_os" in
+case $host_os in
aix3*)
test "$enable_shared" = yes && enable_static=no
if test -n "$RANLIB"; then
@@ -8258,47 +8680,10 @@ aix3*)
fi
;;
-aix4*)
+aix4* | aix5*)
if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
test "$enable_shared" = yes && enable_static=no
fi
- ;;
- darwin* | rhapsody*)
- if test "$GCC" = yes; then
- archive_cmds_need_lc=no
- case "$host_os" in
- rhapsody* | darwin1.[012])
- allow_undefined_flag='-undefined suppress'
- ;;
- *) # Darwin 1.3 on
- if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
- allow_undefined_flag='-flat_namespace -undefined suppress'
- else
- case ${MACOSX_DEPLOYMENT_TARGET} in
- 10.[012])
- allow_undefined_flag='-flat_namespace -undefined suppress'
- ;;
- 10.*)
- allow_undefined_flag='-undefined dynamic_lookup'
- ;;
- esac
- fi
- ;;
- esac
- output_verbose_link_cmd='echo'
- archive_cmds='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring'
- module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
- # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
- archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- hardcode_direct=no
- hardcode_automatic=yes
- hardcode_shlibpath_var=unsupported
- whole_archive_flag_spec='-all_load $convenience'
- link_all_deplibs=yes
- else
- ld_shlibs=no
- fi
;;
esac
echo "$as_me:$LINENO: result: $enable_shared" >&5
@@ -8324,7 +8709,7 @@ if test -f "$ltmain"; then
# Now quote all the things that may contain metacharacters while being
# careful not to overquote the AC_SUBSTed values. We take copies of the
# variables and quote the copies for generation of the libtool script.
- for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \
SED SHELL STRIP \
libname_spec library_names_spec soname_spec extract_expsyms_cmds \
old_striplib striplib file_magic_cmd finish_cmds finish_eval \
@@ -8428,7 +8813,7 @@ echo "$as_me: creating $ofile" >&6;}
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
@@ -8439,11 +8824,11 @@ echo "$as_me: creating $ofile" >&6;}
SED=$lt_SED
# Sed that helps us avoid accidentally triggering echo(1) options like -n.
-Xsed="$SED -e s/^X//"
+Xsed="$SED -e 1s/^X//"
# The HP-UX ksh and POSIX shell print the target directory to stdout
# if CDPATH is set.
-if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
# The names of the tagged configurations supported by this script.
available_tags=
@@ -8473,6 +8858,12 @@ fast_install=$enable_fast_install
# The host system.
host_alias=$host_alias
host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
# An echo program that does not interpret backslashes.
echo=$lt_echo
@@ -8484,6 +8875,9 @@ AR_FLAGS=$lt_AR_FLAGS
# A C compiler.
LTCC=$lt_LTCC
+# LTCC compiler flags.
+LTCFLAGS=$lt_LTCFLAGS
+
# A language-specific compiler.
CC=$lt_compiler
@@ -8534,7 +8928,7 @@ objext="$ac_objext"
libext="$libext"
# Shared library suffix (normally ".so").
-shrext='$shrext'
+shrext_cmds='$shrext_cmds'
# Executable file suffix (normally "").
exeext="$exeext"
@@ -8549,7 +8943,7 @@ max_cmd_len=$lt_cv_sys_max_cmd_len
# Does compiler simultaneously support -c and -o options?
compiler_c_o=$lt_lt_cv_prog_compiler_c_o
-# Must we lock files when doing compilation ?
+# Must we lock files when doing compilation?
need_locks=$lt_need_locks
# Do we need the lib prefix for modules?
@@ -8814,6 +9208,9 @@ echo "$as_me: WARNING: output file \`$ofile' does not look like a libtool script
echo "$as_me: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&2;}
fi
fi
+ if test -z "$LTCFLAGS"; then
+ eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`"
+ fi
# Extract list of available tagged configurations in $ofile.
# Note that this assumes the entire list is on one line.
@@ -8844,7 +9241,9 @@ echo "$as_me: error: tag name \"$tagname\" already exists" >&2;}
case $tagname in
CXX)
- if test -n "$CXX" && test "X$CXX" != "Xno"; then
+ if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
ac_ext=cc
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -8864,6 +9263,7 @@ hardcode_libdir_flag_spec_CXX=
hardcode_libdir_flag_spec_ld_CXX=
hardcode_libdir_separator_CXX=
hardcode_minus_L_CXX=no
+hardcode_shlibpath_var_CXX=unsupported
hardcode_automatic_CXX=no
module_cmds_CXX=
module_expsym_cmds_CXX=
@@ -8881,7 +9281,7 @@ postdeps_CXX=
compiler_lib_search_path_CXX=
# Source file extension for C++ test sources.
-ac_ext=cc
+ac_ext=cpp
# Object file extension for compiled C++ test sources.
objext=o
@@ -8891,17 +9291,34 @@ objext_CXX=$objext
lt_simple_compile_test_code="int some_variable = 0;\n"
# Code to be used in simple link tests
-lt_simple_link_test_code='int main(int, char *) { return(0); }\n'
+lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n'
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
# If no C compiler was specified, use CC.
LTCC=${LTCC-"$CC"}
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
# Allow CC to be a program name with arguments.
compiler=$CC
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+printf "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$rm conftest*
+
+ac_outfile=conftest.$ac_objext
+printf "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$rm conftest*
+
+
# Allow CC to be a program name with arguments.
lt_save_CC=$CC
lt_save_LD=$LD
@@ -8912,18 +9329,27 @@ lt_save_path_LD=$lt_cv_path_LD
if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
else
- unset lt_cv_prog_gnu_ld
+ $as_unset lt_cv_prog_gnu_ld
fi
if test -n "${lt_cv_path_LDCXX+set}"; then
lt_cv_path_LD=$lt_cv_path_LDCXX
else
- unset lt_cv_path_LD
+ $as_unset lt_cv_path_LD
fi
test -z "${LDCXX+set}" || LD=$LDCXX
CC=${CXX-"c++"}
compiler=$CC
compiler_CXX=$CC
-cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'`
+for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+
# We don't want -fno-exception wen compiling C++ code, so set the
# no_builtin_flag separately
@@ -8994,7 +9420,7 @@ else
if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
lt_cv_path_LD="$ac_dir/$ac_prog"
# Check to see if the program is GNU ld. I'd rather use --version,
- # but apparently some GNU ld's only accept -v.
+ # but apparently some variants of GNU ld only accept -v.
# Break only if it was the GNU/non-GNU ld that we prefer.
case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
*GNU* | *'with BFD'*)
@@ -9028,7 +9454,7 @@ echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6
if test "${lt_cv_prog_gnu_ld+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
- # I'd rather use --version here, but apparently some GNU ld's only accept -v.
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
case `$LD -v 2>&1 </dev/null` in
*GNU* | *'with BFD'*)
lt_cv_prog_gnu_ld=yes
@@ -9119,6 +9545,7 @@ case $host_os in
;;
esac
done
+ ;;
esac
exp_sym_flag='-bexport'
@@ -9137,7 +9564,7 @@ case $host_os in
link_all_deplibs_CXX=yes
if test "$GXX" = yes; then
- case $host_os in aix4.012|aix4.012.*)
+ case $host_os in aix4.[012]|aix4.[012].*)
# We only want to do this on AIX 4.2 and lower, the check
# below for broken collect2 doesn't work under 4.3+
collect2name=`${CC} -print-prog-name=collect2`
@@ -9156,8 +9583,12 @@ case $host_os in
hardcode_libdir_flag_spec_CXX='-L$libdir'
hardcode_libdir_separator_CXX=
fi
+ ;;
esac
shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
else
# not using gcc
if test "$host_cpu" = ia64; then
@@ -9235,12 +9666,12 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
- archive_expsym_cmds_CXX="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ archive_expsym_cmds_CXX="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
else
if test "$host_cpu" = ia64; then
hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib'
allow_undefined_flag_CXX="-z nodefs"
- archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
else
# Determine the default libpath from the value encoded in an empty executable.
cat >conftest.$ac_ext <<_ACEOF
@@ -9300,16 +9731,26 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
# -berok will link without error, but may produce a broken library.
no_undefined_flag_CXX=' ${wl}-bernotok'
allow_undefined_flag_CXX=' ${wl}-berok'
- # -bexpall does not export symbols beginning with underscore (_)
- always_export_symbols_CXX=yes
# Exported symbols can be pulled into shared objects from archives
- whole_archive_flag_spec_CXX=' '
+ whole_archive_flag_spec_CXX='$convenience'
archive_cmds_need_lc_CXX=yes
- # This is similar to how AIX traditionally builds it's shared libraries.
- archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
fi
fi
;;
+
+ beos*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag_CXX=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs_CXX=no
+ fi
+ ;;
+
chorus*)
case $cc_basename in
*)
@@ -9328,7 +9769,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
enable_shared_with_static_runtimes_CXX=yes
if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
- archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
# If the export-symbols file already is a .def file (1st line
# is EXPORTS), use it as is; otherwise, prepend...
archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
@@ -9337,70 +9778,81 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
echo EXPORTS > $output_objdir/$soname.def;
cat $export_symbols >> $output_objdir/$soname.def;
fi~
- $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
else
ld_shlibs_CXX=no
fi
;;
+ darwin* | rhapsody*)
+ case $host_os in
+ rhapsody* | darwin1.[012])
+ allow_undefined_flag_CXX='${wl}-undefined ${wl}suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ allow_undefined_flag_CXX='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[012])
+ allow_undefined_flag_CXX='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ ;;
+ 10.*)
+ allow_undefined_flag_CXX='${wl}-undefined ${wl}dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ archive_cmds_need_lc_CXX=no
+ hardcode_direct_CXX=no
+ hardcode_automatic_CXX=yes
+ hardcode_shlibpath_var_CXX=unsupported
+ whole_archive_flag_spec_CXX=''
+ link_all_deplibs_CXX=yes
- darwin* | rhapsody*)
- if test "$GXX" = yes; then
- archive_cmds_need_lc_CXX=no
- case "$host_os" in
- rhapsody* | darwin1.[012])
- allow_undefined_flag_CXX='-undefined suppress'
- ;;
- *) # Darwin 1.3 on
- if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
- allow_undefined_flag_CXX='-flat_namespace -undefined suppress'
+ if test "$GXX" = yes ; then
+ lt_int_apple_cc_single_mod=no
+ output_verbose_link_cmd='echo'
+ if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then
+ lt_int_apple_cc_single_mod=yes
+ fi
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ archive_cmds_CXX='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
else
- case ${MACOSX_DEPLOYMENT_TARGET} in
- 10.[012])
- allow_undefined_flag_CXX='-flat_namespace -undefined suppress'
- ;;
- 10.*)
- allow_undefined_flag_CXX='-undefined dynamic_lookup'
- ;;
- esac
+ archive_cmds_CXX='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ fi
+ module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ case $cc_basename in
+ xlc*)
+ output_verbose_link_cmd='echo'
+ archive_cmds_CXX='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+ module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ ;;
+ *)
+ ld_shlibs_CXX=no
+ ;;
+ esac
fi
- ;;
- esac
- lt_int_apple_cc_single_mod=no
- output_verbose_link_cmd='echo'
- if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
- lt_int_apple_cc_single_mod=yes
- fi
- if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
- archive_cmds_CXX='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
- else
- archive_cmds_CXX='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
- fi
- module_cmds_CXX='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
-
- # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
- if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
- archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- else
- archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- fi
- module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- hardcode_direct_CXX=no
- hardcode_automatic_CXX=yes
- hardcode_shlibpath_var_CXX=unsupported
- whole_archive_flag_spec_CXX='-all_load $convenience'
- link_all_deplibs_CXX=yes
- else
- ld_shlibs_CXX=no
- fi
- ;;
+ ;;
dgux*)
case $cc_basename in
- ec++)
+ ec++*)
# FIXME: insert proper C++ library support
ld_shlibs_CXX=no
;;
- ghcx)
+ ghcx*)
# Green Hills C++ Compiler
# FIXME: insert proper C++ library support
ld_shlibs_CXX=no
@@ -9411,14 +9863,14 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
;;
esac
;;
- freebsd12*)
+ freebsd[12]*)
# C++ shared libraries reported to be fairly broken before switch to ELF
ld_shlibs_CXX=no
;;
freebsd-elf*)
archive_cmds_need_lc_CXX=no
;;
- freebsd* | kfreebsd*-gnu)
+ freebsd* | kfreebsd*-gnu | dragonfly*)
# FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
# conventions
ld_shlibs_CXX=yes
@@ -9435,11 +9887,11 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
# location of the library.
case $cc_basename in
- CC)
+ CC*)
# FIXME: insert proper C++ library support
ld_shlibs_CXX=no
;;
- aCC)
+ aCC*)
archive_cmds_CXX='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
@@ -9449,7 +9901,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | egrep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[-]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
;;
*)
if test "$GXX" = yes; then
@@ -9463,33 +9915,22 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
;;
hpux10*|hpux11*)
if test $with_gnu_ld = no; then
- case "$host_cpu" in
- hppa*64*)
- hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
hardcode_libdir_flag_spec_ld_CXX='+b $libdir'
- hardcode_libdir_separator_CXX=:
- ;;
- ia64*)
- hardcode_libdir_flag_spec_CXX='-L$libdir'
;;
*)
- hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
- hardcode_libdir_separator_CXX=:
export_dynamic_flag_spec_CXX='${wl}-E'
;;
esac
fi
- case "$host_cpu" in
- hppa*64*)
- hardcode_direct_CXX=no
- hardcode_shlibpath_var_CXX=no
- ;;
- ia64*)
+ case $host_cpu in
+ hppa*64*|ia64*)
hardcode_direct_CXX=no
hardcode_shlibpath_var_CXX=no
- hardcode_minus_L_CXX=yes # Not in the search PATH,
- # but as the default
- # location of the library.
;;
*)
hardcode_direct_CXX=yes
@@ -9500,14 +9941,17 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
esac
case $cc_basename in
- CC)
+ CC*)
# FIXME: insert proper C++ library support
ld_shlibs_CXX=no
;;
- aCC)
- case "$host_cpu" in
- hppa*64*|ia64*)
- archive_cmds_CXX='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+ aCC*)
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
*)
archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
@@ -9526,9 +9970,12 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
*)
if test "$GXX" = yes; then
if test $with_gnu_ld = no; then
- case "$host_cpu" in
- ia64*|hppa*64*)
- archive_cmds_CXX='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs'
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
*)
archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
@@ -9542,11 +9989,25 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
;;
esac
;;
+ interix3*)
+ hardcode_direct_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
irix5* | irix6*)
case $cc_basename in
- CC)
+ CC*)
# SGI C++
- archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
# Archives containing C++ object files must be created using
# "CC -ar", where "CC" is the IRIX C++ compiler. This is
@@ -9557,7 +10018,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
*)
if test "$GXX" = yes; then
if test "$with_gnu_ld" = no; then
- archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
else
archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib'
fi
@@ -9570,7 +10031,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
;;
linux*)
case $cc_basename in
- KCC)
+ KCC*)
# Kuck and Associates, Inc. (KAI) C++ Compiler
# KCC will only create a shared library if the output file
@@ -9595,17 +10056,41 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
# "CC -Bstatic", where "CC" is the KAI C++ compiler.
old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs'
;;
- icpc)
+ icpc*)
# Intel C++
with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ tmp_idyn=
+ case $host_cpu in
+ ia64*) tmp_idyn=' -i_dynamic';;
+ esac
+ archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
archive_cmds_need_lc_CXX=no
- archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
;;
- cxx)
+ pgCC*)
+ # Portland Group C++ compiler
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+ whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ ;;
+ cxx*)
# Compaq C++
archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
@@ -9636,7 +10121,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
;;
mvs*)
case $cc_basename in
- cxx)
+ cxx*)
# FIXME: insert proper C++ library support
ld_shlibs_CXX=no
;;
@@ -9646,7 +10131,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
;;
esac
;;
- netbsd* | knetbsd*-gnu)
+ netbsd*)
if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
wlarc=
@@ -9657,9 +10142,25 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
# Workaround some broken pre-1.5 toolchains
output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
;;
+ openbsd2*)
+ # C++ shared libraries are fairly broken
+ ld_shlibs_CXX=no
+ ;;
+ openbsd*)
+ hardcode_direct_CXX=yes
+ hardcode_shlibpath_var_CXX=no
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ fi
+ output_verbose_link_cmd='echo'
+ ;;
osf3*)
case $cc_basename in
- KCC)
+ KCC*)
# Kuck and Associates, Inc. (KAI) C++ Compiler
# KCC will only create a shared library if the output file
@@ -9675,14 +10176,14 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs'
;;
- RCC)
+ RCC*)
# Rational C++ 2.4.1
# FIXME: insert proper C++ library support
ld_shlibs_CXX=no
;;
- cxx)
+ cxx*)
allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
- archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator_CXX=:
@@ -9700,7 +10201,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
*)
if test "$GXX" = yes && test "$with_gnu_ld" = no; then
allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
- archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator_CXX=:
@@ -9719,7 +10220,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
;;
osf4* | osf5*)
case $cc_basename in
- KCC)
+ KCC*)
# Kuck and Associates, Inc. (KAI) C++ Compiler
# KCC will only create a shared library if the output file
@@ -9734,17 +10235,17 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
# the KAI C++ compiler.
old_archive_cmds_CXX='$CC -o $oldlib $oldobjs'
;;
- RCC)
+ RCC*)
# Rational C++ 2.4.1
# FIXME: insert proper C++ library support
ld_shlibs_CXX=no
;;
- cxx)
+ cxx*)
allow_undefined_flag_CXX=' -expect_unresolved \*'
- archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
echo "-hidden">> $lib.exp~
- $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~
$rm $lib.exp'
hardcode_libdir_flag_spec_CXX='-rpath $libdir'
@@ -9763,7 +10264,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
*)
if test "$GXX" = yes && test "$with_gnu_ld" = no; then
allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
- archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator_CXX=:
@@ -9784,27 +10285,14 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
# FIXME: insert proper C++ library support
ld_shlibs_CXX=no
;;
- sco*)
- archive_cmds_need_lc_CXX=no
- case $cc_basename in
- CC)
- # FIXME: insert proper C++ library support
- ld_shlibs_CXX=no
- ;;
- *)
- # FIXME: insert proper C++ library support
- ld_shlibs_CXX=no
- ;;
- esac
- ;;
sunos4*)
case $cc_basename in
- CC)
+ CC*)
# Sun C++ 4.x
# FIXME: insert proper C++ library support
ld_shlibs_CXX=no
;;
- lcc)
+ lcc*)
# Lucid
# FIXME: insert proper C++ library support
ld_shlibs_CXX=no
@@ -9817,36 +10305,33 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
;;
solaris*)
case $cc_basename in
- CC)
+ CC*)
# Sun C++ 4.2, 5.x and Centerline C++
+ archive_cmds_need_lc_CXX=yes
no_undefined_flag_CXX=' -zdefs'
- archive_cmds_CXX='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
- $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
hardcode_libdir_flag_spec_CXX='-R$libdir'
hardcode_shlibpath_var_CXX=no
case $host_os in
- solaris2.0-5 | solaris2.0-5.*) ;;
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
*)
# The C++ compiler is used as linker so we must use $wl
# flag to pass the commands to the underlying system
- # linker.
+ # linker. We must also pass each convience library through
+ # to the system linker between allextract/defaultextract.
+ # The C++ compiler will combine linker options so we
+ # cannot just pass the convience library names through
+ # without $wl.
# Supported since Solaris 2.6 (maybe 2.5.1?)
- whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract'
;;
esac
link_all_deplibs_CXX=yes
- # Commands to make compiler produce verbose output that lists
- # what "hidden" libraries, object files and flags are used when
- # linking a shared library.
- #
- # There doesn't appear to be a way to prevent this compiler from
- # explicitly linking system object files so we need to strip them
- # from the output so that they don't get included in the library
- # dependencies.
- output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[LR]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ output_verbose_link_cmd='echo'
# Archives containing C++ object files must be created using
# "CC -xar", where "CC" is the Sun C++ compiler. This is
@@ -9854,7 +10339,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
# in the archive.
old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
;;
- gcx)
+ gcx*)
# Green Hills C++ Compiler
archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
@@ -9892,12 +10377,63 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
;;
esac
;;
- sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*)
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag_CXX='${wl}-z,text'
+ archive_cmds_need_lc_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ # So that behaviour is only enabled if SCOABSPATH is set to a
+ # non-empty value in the environment. Most likely only useful for
+ # creating official distributions of packages.
+ # This is a hack until libtool officially supports absolute path
+ # names for shared libraries.
+ no_undefined_flag_CXX='${wl}-z,text'
+ allow_undefined_flag_CXX='${wl}-z,nodefs'
archive_cmds_need_lc_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ hardcode_libdir_flag_spec_CXX='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+ hardcode_libdir_separator_CXX=':'
+ link_all_deplibs_CXX=yes
+ export_dynamic_flag_spec_CXX='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ archive_cmds_CXX='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
;;
tandem*)
case $cc_basename in
- NCC)
+ NCC*)
# NonStop-UX NCC 3.20
# FIXME: insert proper C++ library support
ld_shlibs_CXX=no
@@ -9950,7 +10486,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
# The `*' in the case matches for architectures that use `case' in
# $output_verbose_cmd can trigger glob expansion during the loop
# eval without this substitution.
- output_verbose_link_cmd="`$echo \"X$output_verbose_link_cmd\" | $Xsed -e \"$no_glob_subst\"`"
+ output_verbose_link_cmd=`$echo "X$output_verbose_link_cmd" | $Xsed -e "$no_glob_subst"`
for p in `eval $output_verbose_link_cmd`; do
case $p in
@@ -10026,6 +10562,29 @@ fi
$rm -f confest.$objext
+# PORTME: override above test on systems where it is broken
+case $host_os in
+interix3*)
+ # Interix 3.5 installs completely hosed .la files for C++, so rather than
+ # hack all around it, let's just trust "g++" to DTRT.
+ predep_objects_CXX=
+ postdep_objects_CXX=
+ postdeps_CXX=
+ ;;
+
+solaris*)
+ case $cc_basename in
+ CC*)
+ # Adding this requires a known-good setup of shared libraries for
+ # Sun compiler versions before 5.6, else PIC objects from an old
+ # archive will be linked into the output, leading to subtle bugs.
+ postdeps_CXX='-lCstd -lCrun'
+ ;;
+ esac
+ ;;
+esac
+
+
case " $postdeps_CXX " in
*" -lc "*) archive_cmds_need_lc_CXX=no ;;
esac
@@ -10073,6 +10632,10 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
# DJGPP does not support shared libraries at all
lt_prog_compiler_pic_CXX=
;;
+ interix3*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
sysv4*MP*)
if test -d /usr/nec; then
lt_prog_compiler_pic_CXX=-Kconform_pic
@@ -10081,7 +10644,7 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
hpux*)
# PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
# not for PA HP-UX.
- case "$host_cpu" in
+ case $host_cpu in
hppa*64*|ia64*)
;;
*)
@@ -10106,18 +10669,28 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
;;
chorus*)
case $cc_basename in
- cxch68)
+ cxch68*)
# Green Hills C++ Compiler
# _LT_AC_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
;;
esac
;;
+ darwin*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ case $cc_basename in
+ xlc*)
+ lt_prog_compiler_pic_CXX='-qnocommon'
+ lt_prog_compiler_wl_CXX='-Wl,'
+ ;;
+ esac
+ ;;
dgux*)
case $cc_basename in
- ec++)
+ ec++*)
lt_prog_compiler_pic_CXX='-KPIC'
;;
- ghcx)
+ ghcx*)
# Green Hills C++ Compiler
lt_prog_compiler_pic_CXX='-pic'
;;
@@ -10125,22 +10698,22 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
;;
esac
;;
- freebsd* | kfreebsd*-gnu)
+ freebsd* | kfreebsd*-gnu | dragonfly*)
# FreeBSD uses GNU C++
;;
hpux9* | hpux10* | hpux11*)
case $cc_basename in
- CC)
+ CC*)
lt_prog_compiler_wl_CXX='-Wl,'
- lt_prog_compiler_static_CXX="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
+ lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
if test "$host_cpu" != ia64; then
lt_prog_compiler_pic_CXX='+Z'
fi
;;
- aCC)
+ aCC*)
lt_prog_compiler_wl_CXX='-Wl,'
- lt_prog_compiler_static_CXX="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive"
- case "$host_cpu" in
+ lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
+ case $host_cpu in
hppa*64*|ia64*)
# +Z the default
;;
@@ -10153,9 +10726,13 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
;;
esac
;;
+ interix*)
+ # This is c89, which is MS Visual C++ (no shared libs)
+ # Anyone wants to do a port?
+ ;;
irix5* | irix6* | nonstopux*)
case $cc_basename in
- CC)
+ CC*)
lt_prog_compiler_wl_CXX='-Wl,'
lt_prog_compiler_static_CXX='-non_shared'
# CC pic flag -KPIC is the default.
@@ -10166,18 +10743,24 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
;;
linux*)
case $cc_basename in
- KCC)
+ KCC*)
# KAI C++ Compiler
lt_prog_compiler_wl_CXX='--backend -Wl,'
lt_prog_compiler_pic_CXX='-fPIC'
;;
- icpc)
+ icpc* | ecpc*)
# Intel C++
lt_prog_compiler_wl_CXX='-Wl,'
lt_prog_compiler_pic_CXX='-KPIC'
lt_prog_compiler_static_CXX='-static'
;;
- cxx)
+ pgCC*)
+ # Portland Group C++ compiler.
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-fpic'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ ;;
+ cxx*)
# Compaq C++
# Make sure the PIC flag is empty. It appears that all Alpha
# Linux and Compaq Tru64 Unix objects are PIC.
@@ -10194,25 +10777,25 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
;;
mvs*)
case $cc_basename in
- cxx)
+ cxx*)
lt_prog_compiler_pic_CXX='-W c,exportall'
;;
*)
;;
esac
;;
- netbsd* | knetbsd*-gnu)
+ netbsd*)
;;
osf3* | osf4* | osf5*)
case $cc_basename in
- KCC)
+ KCC*)
lt_prog_compiler_wl_CXX='--backend -Wl,'
;;
- RCC)
+ RCC*)
# Rational C++ 2.4.1
lt_prog_compiler_pic_CXX='-pic'
;;
- cxx)
+ cxx*)
# Digital/Compaq C++
lt_prog_compiler_wl_CXX='-Wl,'
# Make sure the PIC flag is empty. It appears that all Alpha
@@ -10226,24 +10809,15 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
;;
psos*)
;;
- sco*)
- case $cc_basename in
- CC)
- lt_prog_compiler_pic_CXX='-fPIC'
- ;;
- *)
- ;;
- esac
- ;;
solaris*)
case $cc_basename in
- CC)
+ CC*)
# Sun C++ 4.2, 5.x and Centerline C++
lt_prog_compiler_pic_CXX='-KPIC'
lt_prog_compiler_static_CXX='-Bstatic'
lt_prog_compiler_wl_CXX='-Qoption ld '
;;
- gcx)
+ gcx*)
# Green Hills C++ Compiler
lt_prog_compiler_pic_CXX='-PIC'
;;
@@ -10253,12 +10827,12 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
;;
sunos4*)
case $cc_basename in
- CC)
+ CC*)
# Sun C++ 4.x
lt_prog_compiler_pic_CXX='-pic'
lt_prog_compiler_static_CXX='-Bstatic'
;;
- lcc)
+ lcc*)
# Lucid
lt_prog_compiler_pic_CXX='-pic'
;;
@@ -10268,7 +10842,7 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
;;
tandem*)
case $cc_basename in
- NCC)
+ NCC*)
# NonStop-UX NCC 3.20
lt_prog_compiler_pic_CXX='-KPIC'
;;
@@ -10276,7 +10850,14 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
;;
esac
;;
- unixware*)
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ case $cc_basename in
+ CC*)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ ;;
+ esac
;;
vxworks*)
;;
@@ -10309,18 +10890,20 @@ else
# with a dollar sign (not a hyphen), so the echo should work correctly.
# The option is referenced via a variable to avoid confusing sed.
lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:10315: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:10896: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:10319: \$? = $ac_status" >&5
+ echo "$as_me:10900: \$? = $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
- if test ! -s conftest.err; then
+ # So say no if there are warnings other than the usual output.
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
lt_prog_compiler_pic_works_CXX=yes
fi
fi
@@ -10341,7 +10924,7 @@ else
fi
fi
-case "$host_os" in
+case $host_os in
# For platforms which do not support PIC, -DPIC is meaningless:
*djgpp*)
lt_prog_compiler_pic_CXX=
@@ -10351,6 +10934,48 @@ case "$host_os" in
;;
esac
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\"
+echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6
+if test "${lt_prog_compiler_static_works_CXX+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_static_works_CXX=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ printf "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_prog_compiler_static_works_CXX=yes
+ fi
+ else
+ lt_prog_compiler_static_works_CXX=yes
+ fi
+ fi
+ $rm conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_CXX" >&5
+echo "${ECHO_T}$lt_prog_compiler_static_works_CXX" >&6
+
+if test x"$lt_prog_compiler_static_works_CXX" = xyes; then
+ :
+else
+ lt_prog_compiler_static_CXX=
+fi
+
+
echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then
@@ -10369,23 +10994,25 @@ else
# Note that $ac_compile itself does not contain backslashes and begins
# with a dollar sign (not a hyphen), so the echo should work correctly.
lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:10375: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:11000: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:10379: \$? = $ac_status" >&5
+ echo "$as_me:11004: \$? = $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
# So say no if there are warnings
- if test ! -s out/conftest.err; then
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
lt_cv_prog_compiler_c_o_CXX=yes
fi
fi
- chmod u+w .
+ chmod u+w . 2>&5
$rm conftest*
# SGI C++ compiler will create directory out/ii_files/ for
# template instantiation
@@ -10440,7 +11067,7 @@ echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared librar
export_symbols_cmds_CXX="$ltdll_cmds"
;;
cygwin* | mingw*)
- export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
+ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([^ ]*\) [^ ]*/\1 DATA/;/^I /d;/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
;;
*)
export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
@@ -10451,11 +11078,6 @@ echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5
echo "${ECHO_T}$ld_shlibs_CXX" >&6
test "$ld_shlibs_CXX" = no && can_build_shared=no
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
- variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
-
#
# Do we need to explicitly link libc?
#
@@ -10488,6 +11110,7 @@ echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&
libobjs=conftest.$ac_objext
deplibs=
wl=$lt_prog_compiler_wl_CXX
+ pic_flag=$lt_prog_compiler_pic_CXX
compiler_flags=-v
linker_flags=-v
verstring=
@@ -10523,7 +11146,7 @@ echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
library_names_spec=
libname_spec='lib$name'
soname_spec=
-shrext=".so"
+shrext_cmds=".so"
postinstall_cmds=
postuninstall_cmds=
finish_cmds=
@@ -10620,7 +11243,7 @@ beos*)
shlibpath_var=LIBRARY_PATH
;;
-bsdi4*)
+bsdi[45]*)
version_type=linux
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
@@ -10636,7 +11259,7 @@ bsdi4*)
cygwin* | mingw* | pw32*)
version_type=windows
- shrext=".dll"
+ shrext_cmds=".dll"
need_version=no
need_lib_prefix=no
@@ -10648,7 +11271,8 @@ cygwin* | mingw* | pw32*)
dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
dldir=$destdir/`dirname \$dlpath`~
test -d \$dldir || mkdir -p \$dldir~
- $install_prog $dir/$dlname \$dldir/$dlname'
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname'
postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
dlpath=$dir/\$dldll~
$rm \$dlpath'
@@ -10678,11 +11302,35 @@ cygwin* | mingw* | pw32*)
;;
pw32*)
# pw32 DLLs use 'pw' prefix rather than 'lib'
- library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
;;
esac
;;
+ linux*)
+ if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+ if test $supports_anon_versioning = yes; then
+ archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~
+cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+$echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ else
+ $archive_expsym_cmds="$archive_cmds"
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
*)
library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
;;
@@ -10701,7 +11349,7 @@ darwin* | rhapsody*)
soname_spec='${libname}${release}${major}$shared_ext'
shlibpath_overrides_runpath=yes
shlibpath_var=DYLD_LIBRARY_PATH
- shrext='$(test .$module = .yes && echo .so || echo .dylib)'
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
# Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
if test "$GCC" = yes; then
sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
@@ -10736,9 +11384,25 @@ kfreebsd*-gnu)
dynamic_linker='GNU ld.so'
;;
-freebsd*)
- objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
- version_type=freebsd-$objformat
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[123]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ # Handle Gentoo/FreeBSD as it was Linux
+ case $host_vendor in
+ gentoo)
+ version_type=linux ;;
+ *)
+ version_type=freebsd-$objformat ;;
+ esac
+
case $version_type in
freebsd-elf*)
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
@@ -10749,20 +11413,31 @@ freebsd*)
library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
need_version=yes
;;
+ linux)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ need_lib_prefix=no
+ need_version=no
+ ;;
esac
shlibpath_var=LD_LIBRARY_PATH
case $host_os in
freebsd2*)
shlibpath_overrides_runpath=yes
;;
- freebsd3.01* | freebsdelf3.01*)
+ freebsd3.[01]* | freebsdelf3.[01]*)
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
;;
- *) # from 3.2 on
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
;;
+ freebsd*) # from 4.6 on
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
esac
;;
@@ -10782,9 +11457,9 @@ hpux9* | hpux10* | hpux11*)
version_type=sunos
need_lib_prefix=no
need_version=no
- case "$host_cpu" in
+ case $host_cpu in
ia64*)
- shrext='.so'
+ shrext_cmds='.so'
hardcode_into_libs=yes
dynamic_linker="$host_os dld.so"
shlibpath_var=LD_LIBRARY_PATH
@@ -10799,7 +11474,7 @@ hpux9* | hpux10* | hpux11*)
sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
hppa*64*)
- shrext='.sl'
+ shrext_cmds='.sl'
hardcode_into_libs=yes
dynamic_linker="$host_os dld.sl"
shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
@@ -10810,7 +11485,7 @@ hpux9* | hpux10* | hpux11*)
sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
*)
- shrext='.sl'
+ shrext_cmds='.sl'
dynamic_linker="$host_os dld.sl"
shlibpath_var=SHLIB_PATH
shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
@@ -10822,6 +11497,18 @@ hpux9* | hpux10* | hpux11*)
postinstall_cmds='chmod 555 $lib'
;;
+interix3*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
irix5* | irix6* | nonstopux*)
case $host_os in
nonstopux*) version_type=nonstopux ;;
@@ -10881,8 +11568,8 @@ linux*)
# Append ld.so.conf contents to the search path
if test -f /etc/ld.so.conf; then
- ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf`
- sys_lib_dlsearch_path_spec="/lib /usr/lib $ld_extra"
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
fi
# We used to test for /lib/ld.so.1 and disable shared libraries on
@@ -10943,8 +11630,13 @@ nto-qnx*)
openbsd*)
version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
need_lib_prefix=no
- need_version=yes
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
shlibpath_var=LD_LIBRARY_PATH
@@ -10964,7 +11656,7 @@ openbsd*)
os2*)
libname_spec='$name'
- shrext=".dll"
+ shrext_cmds=".dll"
need_lib_prefix=no
library_names_spec='$libname${shared_ext} $libname.a'
dynamic_linker='OS/2 ld.exe'
@@ -10982,13 +11674,6 @@ osf3* | osf4* | osf5*)
sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
;;
-sco3.2v5*)
- version_type=osf
- soname_spec='${libname}${release}${shared_ext}$major'
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
solaris*)
version_type=linux
need_lib_prefix=no
@@ -11014,7 +11699,7 @@ sunos4*)
need_version=yes
;;
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+sysv4 | sysv4.3*)
version_type=linux
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
@@ -11047,6 +11732,29 @@ sysv4*MP*)
fi
;;
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ shlibpath_overrides_runpath=no
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ shlibpath_overrides_runpath=yes
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
uts4*)
version_type=linux
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
@@ -11062,12 +11770,17 @@ echo "$as_me:$LINENO: result: $dynamic_linker" >&5
echo "${ECHO_T}$dynamic_linker" >&6
test "$dynamic_linker" = no && can_build_shared=no
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
hardcode_action_CXX=
if test -n "$hardcode_libdir_flag_spec_CXX" || \
- test -n "$runpath_var CXX" || \
- test "X$hardcode_automatic_CXX"="Xyes" ; then
+ test -n "$runpath_var_CXX" || \
+ test "X$hardcode_automatic_CXX" = "Xyes" ; then
# We can hardcode non-existant directories.
if test "$hardcode_direct_CXX" != no &&
@@ -11099,841 +11812,6 @@ elif test "$shlibpath_overrides_runpath" = yes ||
enable_fast_install=needless
fi
-striplib=
-old_striplib=
-echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
-echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
-if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
- test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
- test -z "$striplib" && striplib="$STRIP --strip-unneeded"
- echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6
-else
-# FIXME - insert some real tests, host_os isn't really good enough
- case $host_os in
- darwin*)
- if test -n "$STRIP" ; then
- striplib="$STRIP -x"
- echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6
- else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
- ;;
- *)
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
- ;;
- esac
-fi
-
-if test "x$enable_dlopen" != xyes; then
- enable_dlopen=unknown
- enable_dlopen_self=unknown
- enable_dlopen_self_static=unknown
-else
- lt_cv_dlopen=no
- lt_cv_dlopen_libs=
-
- case $host_os in
- beos*)
- lt_cv_dlopen="load_add_on"
- lt_cv_dlopen_libs=
- lt_cv_dlopen_self=yes
- ;;
-
- mingw* | pw32*)
- lt_cv_dlopen="LoadLibrary"
- lt_cv_dlopen_libs=
- ;;
-
- cygwin*)
- lt_cv_dlopen="dlopen"
- lt_cv_dlopen_libs=
- ;;
-
- darwin*)
- # if libdl is installed we need to link against it
- echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
-echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
-if test "${ac_cv_lib_dl_dlopen+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-
-/* Override any gcc2 internal prototype to avoid an error. */
-#ifdef __cplusplus
-extern "C"
-#endif
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dlopen ();
-int
-main ()
-{
-dlopen ();
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_cxx_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_lib_dl_dlopen=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_lib_dl_dlopen=no
-fi
-rm -f conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
-echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
-if test $ac_cv_lib_dl_dlopen = yes; then
- lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
-else
-
- lt_cv_dlopen="dyld"
- lt_cv_dlopen_libs=
- lt_cv_dlopen_self=yes
-
-fi
-
- ;;
-
- *)
- echo "$as_me:$LINENO: checking for shl_load" >&5
-echo $ECHO_N "checking for shl_load... $ECHO_C" >&6
-if test "${ac_cv_func_shl_load+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 shl_load to an innocuous variant, in case <limits.h> declares shl_load.
- For example, HP-UX 11i <limits.h> declares gettimeofday. */
-#define shl_load innocuous_shl_load
-
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char shl_load (); 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 shl_load
-
-/* 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 shl_load ();
-/* 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_shl_load) || defined (__stub___shl_load)
-choke me
-#else
-char (*f) () = shl_load;
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-int
-main ()
-{
-return f != shl_load;
- ;
- 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_cxx_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_shl_load=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_func_shl_load=no
-fi
-rm -f conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-fi
-echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5
-echo "${ECHO_T}$ac_cv_func_shl_load" >&6
-if test $ac_cv_func_shl_load = yes; then
- lt_cv_dlopen="shl_load"
-else
- echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
-echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6
-if test "${ac_cv_lib_dld_shl_load+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldld $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 shl_load ();
-int
-main ()
-{
-shl_load ();
- ;
- 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_cxx_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_lib_dld_shl_load=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_lib_dld_shl_load=no
-fi
-rm -f conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
-echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6
-if test $ac_cv_lib_dld_shl_load = yes; then
- lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"
-else
- echo "$as_me:$LINENO: checking for dlopen" >&5
-echo $ECHO_N "checking for dlopen... $ECHO_C" >&6
-if test "${ac_cv_func_dlopen+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 dlopen to an innocuous variant, in case <limits.h> declares dlopen.
- For example, HP-UX 11i <limits.h> declares gettimeofday. */
-#define dlopen innocuous_dlopen
-
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char dlopen (); 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 dlopen
-
-/* Override any gcc2 internal prototype to avoid an error. */
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dlopen ();
-/* 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_dlopen) || defined (__stub___dlopen)
-choke me
-#else
-char (*f) () = dlopen;
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-int
-main ()
-{
-return f != dlopen;
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_cxx_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_dlopen=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_func_dlopen=no
-fi
-rm -f conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-fi
-echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
-echo "${ECHO_T}$ac_cv_func_dlopen" >&6
-if test $ac_cv_func_dlopen = yes; then
- lt_cv_dlopen="dlopen"
-else
- echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
-echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
-if test "${ac_cv_lib_dl_dlopen+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-
-/* Override any gcc2 internal prototype to avoid an error. */
-#ifdef __cplusplus
-extern "C"
-#endif
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dlopen ();
-int
-main ()
-{
-dlopen ();
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_cxx_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_lib_dl_dlopen=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_lib_dl_dlopen=no
-fi
-rm -f conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
-echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
-if test $ac_cv_lib_dl_dlopen = yes; then
- lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
-else
- echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5
-echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6
-if test "${ac_cv_lib_svld_dlopen+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsvld $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-
-/* Override any gcc2 internal prototype to avoid an error. */
-#ifdef __cplusplus
-extern "C"
-#endif
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dlopen ();
-int
-main ()
-{
-dlopen ();
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_cxx_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_lib_svld_dlopen=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_lib_svld_dlopen=no
-fi
-rm -f conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5
-echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6
-if test $ac_cv_lib_svld_dlopen = yes; then
- lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
-else
- echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5
-echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6
-if test "${ac_cv_lib_dld_dld_link+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldld $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 dld_link ();
-int
-main ()
-{
-dld_link ();
- ;
- 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_cxx_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_lib_dld_dld_link=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_lib_dld_dld_link=no
-fi
-rm -f conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5
-echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6
-if test $ac_cv_lib_dld_dld_link = yes; then
- lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
- ;;
- esac
-
- if test "x$lt_cv_dlopen" != xno; then
- enable_dlopen=yes
- else
- enable_dlopen=no
- fi
-
- case $lt_cv_dlopen in
- dlopen)
- save_CPPFLAGS="$CPPFLAGS"
- test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
-
- save_LDFLAGS="$LDFLAGS"
- eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
-
- save_LIBS="$LIBS"
- LIBS="$lt_cv_dlopen_libs $LIBS"
-
- echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5
-echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6
-if test "${lt_cv_dlopen_self+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test "$cross_compiling" = yes; then :
- lt_cv_dlopen_self=cross
-else
- lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
- lt_status=$lt_dlunknown
- cat > conftest.$ac_ext <<EOF
-#line 11736 "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-# define LT_DLGLOBAL RTLD_GLOBAL
-#else
-# ifdef DL_GLOBAL
-# define LT_DLGLOBAL DL_GLOBAL
-# else
-# define LT_DLGLOBAL 0
-# endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-# ifdef RTLD_LAZY
-# define LT_DLLAZY_OR_NOW RTLD_LAZY
-# else
-# ifdef DL_LAZY
-# define LT_DLLAZY_OR_NOW DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define LT_DLLAZY_OR_NOW RTLD_NOW
-# else
-# ifdef DL_NOW
-# define LT_DLLAZY_OR_NOW DL_NOW
-# else
-# define LT_DLLAZY_OR_NOW 0
-# endif
-# endif
-# endif
-# endif
-#endif
-
-#ifdef __cplusplus
-extern "C" void exit (int);
-#endif
-
-void fnord() { int i=42;}
-int main ()
-{
- void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
- int status = $lt_dlunknown;
-
- if (self)
- {
- if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
- else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
- /* dlclose (self); */
- }
-
- exit (status);
-}
-EOF
- if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
- (./conftest; exit; ) 2>/dev/null
- lt_status=$?
- case x$lt_status in
- x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
- x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
- x$lt_unknown|x*) lt_cv_dlopen_self=no ;;
- esac
- else :
- # compilation failed
- lt_cv_dlopen_self=no
- fi
-fi
-rm -fr conftest*
-
-
-fi
-echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
-echo "${ECHO_T}$lt_cv_dlopen_self" >&6
-
- if test "x$lt_cv_dlopen_self" = xyes; then
- LDFLAGS="$LDFLAGS $link_static_flag"
- echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
-echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6
-if test "${lt_cv_dlopen_self_static+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test "$cross_compiling" = yes; then :
- lt_cv_dlopen_self_static=cross
-else
- lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
- lt_status=$lt_dlunknown
- cat > conftest.$ac_ext <<EOF
-#line 11834 "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-# define LT_DLGLOBAL RTLD_GLOBAL
-#else
-# ifdef DL_GLOBAL
-# define LT_DLGLOBAL DL_GLOBAL
-# else
-# define LT_DLGLOBAL 0
-# endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-# ifdef RTLD_LAZY
-# define LT_DLLAZY_OR_NOW RTLD_LAZY
-# else
-# ifdef DL_LAZY
-# define LT_DLLAZY_OR_NOW DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define LT_DLLAZY_OR_NOW RTLD_NOW
-# else
-# ifdef DL_NOW
-# define LT_DLLAZY_OR_NOW DL_NOW
-# else
-# define LT_DLLAZY_OR_NOW 0
-# endif
-# endif
-# endif
-# endif
-#endif
-
-#ifdef __cplusplus
-extern "C" void exit (int);
-#endif
-
-void fnord() { int i=42;}
-int main ()
-{
- void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
- int status = $lt_dlunknown;
-
- if (self)
- {
- if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
- else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
- /* dlclose (self); */
- }
-
- exit (status);
-}
-EOF
- if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
- (./conftest; exit; ) 2>/dev/null
- lt_status=$?
- case x$lt_status in
- x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
- x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
- x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;;
- esac
- else :
- # compilation failed
- lt_cv_dlopen_self_static=no
- fi
-fi
-rm -fr conftest*
-
-
-fi
-echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5
-echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6
- fi
-
- CPPFLAGS="$save_CPPFLAGS"
- LDFLAGS="$save_LDFLAGS"
- LIBS="$save_LIBS"
- ;;
- esac
-
- case $lt_cv_dlopen_self in
- yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
- *) enable_dlopen_self=unknown ;;
- esac
-
- case $lt_cv_dlopen_self_static in
- yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
- *) enable_dlopen_self_static=unknown ;;
- esac
-fi
-
# The else clause should only fire when bootstrapping the
# libtool distribution, otherwise you forgot to ship ltmain.sh
@@ -11948,7 +11826,7 @@ if test -f "$ltmain"; then
# Now quote all the things that may contain metacharacters while being
# careful not to overquote the AC_SUBSTed values. We take copies of the
# variables and quote the copies for generation of the libtool script.
- for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \
SED SHELL STRIP \
libname_spec library_names_spec soname_spec extract_expsyms_cmds \
old_striplib striplib file_magic_cmd finish_cmds finish_eval \
@@ -12049,6 +11927,12 @@ fast_install=$enable_fast_install
# The host system.
host_alias=$host_alias
host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
# An echo program that does not interpret backslashes.
echo=$lt_echo
@@ -12060,6 +11944,9 @@ AR_FLAGS=$lt_AR_FLAGS
# A C compiler.
LTCC=$lt_LTCC
+# LTCC compiler flags.
+LTCFLAGS=$lt_LTCFLAGS
+
# A language-specific compiler.
CC=$lt_compiler_CXX
@@ -12110,7 +11997,7 @@ objext="$ac_objext"
libext="$libext"
# Shared library suffix (normally ".so").
-shrext='$shrext'
+shrext_cmds='$shrext_cmds'
# Executable file suffix (normally "").
exeext="$exeext"
@@ -12125,7 +12012,7 @@ max_cmd_len=$lt_cv_sys_max_cmd_len
# Does compiler simultaneously support -c and -o options?
compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX
-# Must we lock files when doing compilation ?
+# Must we lock files when doing compilation?
need_locks=$lt_need_locks
# Do we need the lib prefix for modules?
@@ -12402,16 +12289,42 @@ lt_simple_link_test_code=" program t\n end\n"
# If no C compiler was specified, use CC.
LTCC=${LTCC-"$CC"}
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
# Allow CC to be a program name with arguments.
compiler=$CC
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+printf "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$rm conftest*
+
+ac_outfile=conftest.$ac_objext
+printf "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$rm conftest*
+
+
# Allow CC to be a program name with arguments.
lt_save_CC="$CC"
CC=${F77-"f77"}
compiler=$CC
compiler_F77=$CC
-cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'`
+for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+
echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5
echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6
@@ -12424,7 +12337,7 @@ test "$can_build_shared" = "no" && enable_shared=no
# On AIX, shared libraries and static libraries use the same namespace, and
# are all built from PIC.
-case "$host_os" in
+case $host_os in
aix3*)
test "$enable_shared" = yes && enable_static=no
if test -n "$RANLIB"; then
@@ -12432,8 +12345,10 @@ aix3*)
postinstall_cmds='$RANLIB $lib'
fi
;;
-aix4*)
- test "$enable_shared" = yes && enable_static=no
+aix4* | aix5*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
;;
esac
echo "$as_me:$LINENO: result: $enable_shared" >&5
@@ -12446,8 +12361,6 @@ test "$enable_shared" = yes || enable_static=yes
echo "$as_me:$LINENO: result: $enable_static" >&5
echo "${ECHO_T}$enable_static" >&6
-test "$ld_shlibs_F77" = no && can_build_shared=no
-
GCC_F77="$G77"
LD_F77="$LD"
@@ -12494,6 +12407,11 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
lt_prog_compiler_pic_F77='-fno-common'
;;
+ interix3*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
msdosdjgpp*)
# Just because we use GCC doesn't mean we suddenly get shared libraries
# on systems that don't support them.
@@ -12510,7 +12428,7 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
hpux*)
# PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
# not for PA HP-UX.
- case "$host_cpu" in
+ case $host_cpu in
hppa*64*|ia64*)
# +Z the default
;;
@@ -12536,6 +12454,16 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
lt_prog_compiler_static_F77='-bnso -bI:/lib/syscalls.exp'
fi
;;
+ darwin*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ case $cc_basename in
+ xlc*)
+ lt_prog_compiler_pic_F77='-qnocommon'
+ lt_prog_compiler_wl_F77='-Wl,'
+ ;;
+ esac
+ ;;
mingw* | pw32* | os2*)
# This hack is so that the source file can tell whether it is being
@@ -12547,7 +12475,7 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
lt_prog_compiler_wl_F77='-Wl,'
# PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
# not for PA HP-UX.
- case "$host_cpu" in
+ case $host_cpu in
hppa*64*|ia64*)
# +Z the default
;;
@@ -12571,12 +12499,19 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
;;
linux*)
- case $CC in
+ case $cc_basename in
icc* | ecc*)
lt_prog_compiler_wl_F77='-Wl,'
lt_prog_compiler_pic_F77='-KPIC'
lt_prog_compiler_static_F77='-static'
;;
+ pgcc* | pgf77* | pgf90* | pgf95*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ lt_prog_compiler_wl_F77='-Wl,'
+ lt_prog_compiler_pic_F77='-fpic'
+ lt_prog_compiler_static_F77='-Bstatic'
+ ;;
ccc*)
lt_prog_compiler_wl_F77='-Wl,'
# All Alpha code is PIC.
@@ -12591,15 +12526,15 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
lt_prog_compiler_static_F77='-non_shared'
;;
- sco3.2v5*)
- lt_prog_compiler_pic_F77='-Kpic'
- lt_prog_compiler_static_F77='-dn'
- ;;
-
solaris*)
- lt_prog_compiler_wl_F77='-Wl,'
lt_prog_compiler_pic_F77='-KPIC'
lt_prog_compiler_static_F77='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95*)
+ lt_prog_compiler_wl_F77='-Qoption ld ';;
+ *)
+ lt_prog_compiler_wl_F77='-Wl,';;
+ esac
;;
sunos4*)
@@ -12608,7 +12543,7 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
lt_prog_compiler_static_F77='-Bstatic'
;;
- sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ sysv4 | sysv4.2uw2* | sysv4.3*)
lt_prog_compiler_wl_F77='-Wl,'
lt_prog_compiler_pic_F77='-KPIC'
lt_prog_compiler_static_F77='-Bstatic'
@@ -12621,6 +12556,17 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
fi
;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ lt_prog_compiler_pic_F77='-KPIC'
+ lt_prog_compiler_static_F77='-Bstatic'
+ ;;
+
+ unicos*)
+ lt_prog_compiler_wl_F77='-Wl,'
+ lt_prog_compiler_can_build_shared_F77=no
+ ;;
+
uts4*)
lt_prog_compiler_pic_F77='-pic'
lt_prog_compiler_static_F77='-Bstatic'
@@ -12655,18 +12601,20 @@ else
# with a dollar sign (not a hyphen), so the echo should work correctly.
# The option is referenced via a variable to avoid confusing sed.
lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:12661: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:12607: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:12665: \$? = $ac_status" >&5
+ echo "$as_me:12611: \$? = $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
- if test ! -s conftest.err; then
+ # So say no if there are warnings other than the usual output.
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
lt_prog_compiler_pic_works_F77=yes
fi
fi
@@ -12687,7 +12635,7 @@ else
fi
fi
-case "$host_os" in
+case $host_os in
# For platforms which do not support PIC, -DPIC is meaningless:
*djgpp*)
lt_prog_compiler_pic_F77=
@@ -12697,6 +12645,48 @@ case "$host_os" in
;;
esac
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl_F77 eval lt_tmp_static_flag=\"$lt_prog_compiler_static_F77\"
+echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6
+if test "${lt_prog_compiler_static_works_F77+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_static_works_F77=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ printf "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_prog_compiler_static_works_F77=yes
+ fi
+ else
+ lt_prog_compiler_static_works_F77=yes
+ fi
+ fi
+ $rm conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_F77" >&5
+echo "${ECHO_T}$lt_prog_compiler_static_works_F77" >&6
+
+if test x"$lt_prog_compiler_static_works_F77" = xyes; then
+ :
+else
+ lt_prog_compiler_static_F77=
+fi
+
+
echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
if test "${lt_cv_prog_compiler_c_o_F77+set}" = set; then
@@ -12715,23 +12705,25 @@ else
# Note that $ac_compile itself does not contain backslashes and begins
# with a dollar sign (not a hyphen), so the echo should work correctly.
lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:12721: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:12711: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:12725: \$? = $ac_status" >&5
+ echo "$as_me:12715: \$? = $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
# So say no if there are warnings
- if test ! -s out/conftest.err; then
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
lt_cv_prog_compiler_c_o_F77=yes
fi
fi
- chmod u+w .
+ chmod u+w . 2>&5
$rm conftest*
# SGI C++ compiler will create directory out/ii_files/ for
# template instantiation
@@ -12807,6 +12799,16 @@ echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared librar
# rely on this symbol name, it's probably fine to never include it in
# preloaded symbol tables.
extract_expsyms_cmds=
+ # Just being paranoid about ensuring that cc_basename is set.
+ for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
case $host_os in
cygwin* | mingw* | pw32*)
@@ -12817,6 +12819,10 @@ echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared librar
with_gnu_ld=no
fi
;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
openbsd*)
with_gnu_ld=no
;;
@@ -12827,6 +12833,27 @@ echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared librar
# If archive_cmds runs LD, not CC, wlarc should be empty
wlarc='${wl}'
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec_F77='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec_F77='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec_F77="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec_F77=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
# See if GNU ld supports shared libraries.
case $host_os in
aix3* | aix4* | aix5*)
@@ -12877,10 +12904,10 @@ EOF
allow_undefined_flag_F77=unsupported
always_export_symbols_F77=no
enable_shared_with_static_runtimes_F77=yes
- export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
+ export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
- archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
# If the export-symbols file already is a .def file (1st line
# is EXPORTS), use it as is; otherwise, prepend...
archive_expsym_cmds_F77='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
@@ -12889,13 +12916,59 @@ EOF
echo EXPORTS > $output_objdir/$soname.def;
cat $export_symbols >> $output_objdir/$soname.def;
fi~
- $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
else
- ld_shlibs=no
+ ld_shlibs_F77=no
+ fi
+ ;;
+
+ interix3*)
+ hardcode_direct_F77=no
+ hardcode_shlibpath_var_F77=no
+ hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_F77='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds_F77='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds_F77='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ linux*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ tmp_addflag=
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers
+ whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ esac
+ archive_cmds_F77='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test $supports_anon_versioning = yes; then
+ archive_expsym_cmds_F77='$echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ $echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ else
+ ld_shlibs_F77=no
fi
;;
- netbsd* | knetbsd*-gnu)
+ netbsd*)
if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
archive_cmds_F77='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
wlarc=
@@ -12905,7 +12978,7 @@ EOF
fi
;;
- solaris* | sysv5*)
+ solaris*)
if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
ld_shlibs_F77=no
cat <<EOF 1>&2
@@ -12926,6 +12999,33 @@ EOF
fi
;;
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs_F77=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec_F77='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
+ archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib'
+ archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib'
+ else
+ ld_shlibs_F77=no
+ fi
+ ;;
+ esac
+ ;;
+
sunos4*)
archive_cmds_F77='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
wlarc=
@@ -12933,31 +13033,6 @@ EOF
hardcode_shlibpath_var_F77=no
;;
- linux*)
- if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_cmds_F77="$tmp_archive_cmds"
- supports_anon_versioning=no
- case `$LD -v 2>/dev/null` in
- *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
- *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
- *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
- *\ 2.11.*) ;; # other 2.11 versions
- *) supports_anon_versioning=yes ;;
- esac
- if test $supports_anon_versioning = yes; then
- archive_expsym_cmds_F77='$echo "{ global:" > $output_objdir/$libname.ver~
-cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-$echo "local: *; };" >> $output_objdir/$libname.ver~
- $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
- else
- archive_expsym_cmds_F77="$tmp_archive_cmds"
- fi
- else
- ld_shlibs_F77=no
- fi
- ;;
-
*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
@@ -12968,16 +13043,11 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
;;
esac
- if test "$ld_shlibs_F77" = yes; then
- runpath_var=LD_RUN_PATH
- hardcode_libdir_flag_spec_F77='${wl}--rpath ${wl}$libdir'
- export_dynamic_flag_spec_F77='${wl}--export-dynamic'
- # ancient GNU ld didn't support --whole-archive et. al.
- if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
- whole_archive_flag_spec_F77="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
- else
- whole_archive_flag_spec_F77=
- fi
+ if test "$ld_shlibs_F77" = no; then
+ runpath_var=
+ hardcode_libdir_flag_spec_F77=
+ export_dynamic_flag_spec_F77=
+ whole_archive_flag_spec_F77=
fi
else
# PORTME fill in a description of your system's linker (not GNU ld)
@@ -12989,7 +13059,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
# Note: this linker hardcodes the directories in LIBPATH if there
# are no directories specified by -L.
hardcode_minus_L_F77=yes
- if test "$GCC" = yes && test -z "$link_static_flag"; then
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
# Neither direct hardcoding nor static linking is supported with a
# broken collect2.
hardcode_direct_F77=unsupported
@@ -13023,6 +13093,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
break
fi
done
+ ;;
esac
exp_sym_flag='-bexport'
@@ -13041,7 +13112,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
link_all_deplibs_F77=yes
if test "$GCC" = yes; then
- case $host_os in aix4.012|aix4.012.*)
+ case $host_os in aix4.[012]|aix4.[012].*)
# We only want to do this on AIX 4.2 and lower, the check
# below for broken collect2 doesn't work under 4.3+
collect2name=`${CC} -print-prog-name=collect2`
@@ -13060,8 +13131,12 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
hardcode_libdir_flag_spec_F77='-L$libdir'
hardcode_libdir_separator_F77=
fi
+ ;;
esac
shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
else
# not using gcc
if test "$host_cpu" = ia64; then
@@ -13069,11 +13144,11 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
# chokes on -Wl,-G. The following line is correct:
shared_flag='-G'
else
- if test "$aix_use_runtimelinking" = yes; then
+ if test "$aix_use_runtimelinking" = yes; then
shared_flag='${wl}-G'
else
shared_flag='${wl}-bM:SRE'
- fi
+ fi
fi
fi
@@ -13128,12 +13203,12 @@ rm -f conftest.err conftest.$ac_objext \
if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath"
- archive_expsym_cmds_F77="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ archive_expsym_cmds_F77="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
else
if test "$host_cpu" = ia64; then
hardcode_libdir_flag_spec_F77='${wl}-R $libdir:/usr/lib:/lib'
allow_undefined_flag_F77="-z nodefs"
- archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
else
# Determine the default libpath from the value encoded in an empty executable.
cat >conftest.$ac_ext <<_ACEOF
@@ -13183,13 +13258,11 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
# -berok will link without error, but may produce a broken library.
no_undefined_flag_F77=' ${wl}-bernotok'
allow_undefined_flag_F77=' ${wl}-berok'
- # -bexpall does not export symbols beginning with underscore (_)
- always_export_symbols_F77=yes
# Exported symbols can be pulled into shared objects from archives
- whole_archive_flag_spec_F77=' '
+ whole_archive_flag_spec_F77='$convenience'
archive_cmds_need_lc_F77=yes
- # This is similar to how AIX traditionally builds it's shared libraries.
- archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
fi
fi
;;
@@ -13202,7 +13275,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
ld_shlibs_F77=no
;;
- bsdi4*)
+ bsdi[45]*)
export_dynamic_flag_spec_F77=-rdynamic
;;
@@ -13216,64 +13289,64 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
# Tell ltmain to make .lib files, not .a files.
libext=lib
# Tell ltmain to make .dll files, not .so files.
- shrext=".dll"
+ shrext_cmds=".dll"
# FIXME: Setting linknames here is a bad hack.
archive_cmds_F77='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
# The linker will automatically build a .lib file if we build a DLL.
old_archive_From_new_cmds_F77='true'
# FIXME: Should let the user specify the lib program.
old_archive_cmds_F77='lib /OUT:$oldlib$oldobjs$old_deplibs'
- fix_srcfile_path='`cygpath -w "$srcfile"`'
+ fix_srcfile_path_F77='`cygpath -w "$srcfile"`'
enable_shared_with_static_runtimes_F77=yes
;;
darwin* | rhapsody*)
- if test "$GXX" = yes ; then
- archive_cmds_need_lc_F77=no
- case "$host_os" in
- rhapsody* | darwin1.[012])
- allow_undefined_flag_F77='-undefined suppress'
- ;;
- *) # Darwin 1.3 on
- if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
- allow_undefined_flag_F77='-flat_namespace -undefined suppress'
- else
- case ${MACOSX_DEPLOYMENT_TARGET} in
- 10.[012])
- allow_undefined_flag_F77='-flat_namespace -undefined suppress'
- ;;
- 10.*)
- allow_undefined_flag_F77='-undefined dynamic_lookup'
- ;;
- esac
- fi
- ;;
+ case $host_os in
+ rhapsody* | darwin1.[012])
+ allow_undefined_flag_F77='${wl}-undefined ${wl}suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[012])
+ allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ ;;
+ 10.*)
+ allow_undefined_flag_F77='${wl}-undefined ${wl}dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
esac
- lt_int_apple_cc_single_mod=no
- output_verbose_link_cmd='echo'
- if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
- lt_int_apple_cc_single_mod=yes
- fi
- if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
- archive_cmds_F77='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
- else
- archive_cmds_F77='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
- fi
- module_cmds_F77='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
- # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
- if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
- archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- else
- archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- fi
- module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ archive_cmds_need_lc_F77=no
hardcode_direct_F77=no
hardcode_automatic_F77=yes
hardcode_shlibpath_var_F77=unsupported
- whole_archive_flag_spec_F77='-all_load $convenience'
+ whole_archive_flag_spec_F77=''
link_all_deplibs_F77=yes
+ if test "$GCC" = yes ; then
+ output_verbose_link_cmd='echo'
+ archive_cmds_F77='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
else
- ld_shlibs_F77=no
+ case $cc_basename in
+ xlc*)
+ output_verbose_link_cmd='echo'
+ archive_cmds_F77='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+ module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ ;;
+ *)
+ ld_shlibs_F77=no
+ ;;
+ esac
fi
;;
@@ -13307,7 +13380,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
;;
# FreeBSD 3 and greater uses gcc -shared to do shared libraries.
- freebsd* | kfreebsd*-gnu)
+ freebsd* | kfreebsd*-gnu | dragonfly*)
archive_cmds_F77='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
hardcode_libdir_flag_spec_F77='-R$libdir'
hardcode_direct_F77=yes
@@ -13330,47 +13403,62 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
export_dynamic_flag_spec_F77='${wl}-E'
;;
- hpux10* | hpux11*)
+ hpux10*)
if test "$GCC" = yes -a "$with_gnu_ld" = no; then
- case "$host_cpu" in
- hppa*64*|ia64*)
+ archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_F77='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_F77=:
+
+ hardcode_direct_F77=yes
+ export_dynamic_flag_spec_F77='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_F77=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
+ ia64*)
+ archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
*)
archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
else
- case "$host_cpu" in
- hppa*64*|ia64*)
- archive_cmds_F77='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
;;
*)
- archive_cmds_F77='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
fi
if test "$with_gnu_ld" = no; then
- case "$host_cpu" in
- hppa*64*)
- hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_F77=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
hardcode_libdir_flag_spec_ld_F77='+b $libdir'
- hardcode_libdir_separator_F77=:
- hardcode_direct_F77=no
- hardcode_shlibpath_var_F77=no
- ;;
- ia64*)
- hardcode_libdir_flag_spec_F77='-L$libdir'
hardcode_direct_F77=no
hardcode_shlibpath_var_F77=no
-
- # hardcode_minus_L: Not really in the search PATH,
- # but as the default location of the library.
- hardcode_minus_L_F77=yes
;;
*)
- hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir'
- hardcode_libdir_separator_F77=:
hardcode_direct_F77=yes
export_dynamic_flag_spec_F77='${wl}-E'
@@ -13394,7 +13482,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
link_all_deplibs_F77=yes
;;
- netbsd* | knetbsd*-gnu)
+ netbsd*)
if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
else
@@ -13418,6 +13506,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
hardcode_shlibpath_var_F77=no
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir'
export_dynamic_flag_spec_F77='${wl}-E'
else
@@ -13463,7 +13552,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
allow_undefined_flag_F77=' -expect_unresolved \*'
archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
archive_expsym_cmds_F77='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
- $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
+ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp'
# Both c and cxx compiler support -rpath directly
hardcode_libdir_flag_spec_F77='-rpath $libdir'
@@ -13471,21 +13560,15 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
hardcode_libdir_separator_F77=:
;;
- sco3.2v5*)
- archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_shlibpath_var_F77=no
- export_dynamic_flag_spec_F77='${wl}-Bexport'
- runpath_var=LD_RUN_PATH
- hardcode_runpath_var=yes
- ;;
-
solaris*)
no_undefined_flag_F77=' -z text'
if test "$GCC" = yes; then
+ wlarc='${wl}'
archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
$CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
else
+ wlarc=''
archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
$LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
@@ -13494,8 +13577,18 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
hardcode_shlibpath_var_F77=no
case $host_os in
solaris2.[0-5] | solaris2.[0-5].*) ;;
- *) # Supported since Solaris 2.6 (maybe 2.5.1?)
- whole_archive_flag_spec_F77='-z allextract$convenience -z defaultextract' ;;
+ *)
+ # The compiler driver will combine linker options so we
+ # cannot just pass the convience library names through
+ # without $wl, iff we do not link with $LD.
+ # Luckily, gcc supports the same syntax we need for Sun Studio.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ case $wlarc in
+ '')
+ whole_archive_flag_spec_F77='-z allextract$convenience -z defaultextract' ;;
+ *)
+ whole_archive_flag_spec_F77='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;;
+ esac ;;
esac
link_all_deplibs_F77=yes
;;
@@ -13552,36 +13645,45 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
fi
;;
- sysv4.2uw2*)
- archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct_F77=yes
- hardcode_minus_L_F77=no
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*)
+ no_undefined_flag_F77='${wl}-z,text'
+ archive_cmds_need_lc_F77=no
hardcode_shlibpath_var_F77=no
- hardcode_runpath_var=yes
- runpath_var=LD_RUN_PATH
- ;;
+ runpath_var='LD_RUN_PATH'
- sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*)
- no_undefined_flag_F77='${wl}-z ${wl}text'
if test "$GCC" = yes; then
- archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds_F77='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_F77='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
else
- archive_cmds_F77='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds_F77='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_F77='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
fi
- runpath_var='LD_RUN_PATH'
- hardcode_shlibpath_var_F77=no
;;
- sysv5*)
- no_undefined_flag_F77=' -z text'
- # $CC -shared without GNU ld will not create a library from C++
- # object files and a static libstdc++, better avoid it by now
- archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
- archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
- $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
- hardcode_libdir_flag_spec_F77=
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag_F77='${wl}-z,text'
+ allow_undefined_flag_F77='${wl}-z,nodefs'
+ archive_cmds_need_lc_F77=no
hardcode_shlibpath_var_F77=no
+ hardcode_libdir_flag_spec_F77='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+ hardcode_libdir_separator_F77=':'
+ link_all_deplibs_F77=yes
+ export_dynamic_flag_spec_F77='${wl}-Bexport'
runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds_F77='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_F77='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_F77='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_F77='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
;;
uts4*)
@@ -13600,11 +13702,6 @@ echo "$as_me:$LINENO: result: $ld_shlibs_F77" >&5
echo "${ECHO_T}$ld_shlibs_F77" >&6
test "$ld_shlibs_F77" = no && can_build_shared=no
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
- variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
-
#
# Do we need to explicitly link libc?
#
@@ -13637,6 +13734,7 @@ echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&
libobjs=conftest.$ac_objext
deplibs=
wl=$lt_prog_compiler_wl_F77
+ pic_flag=$lt_prog_compiler_pic_F77
compiler_flags=-v
linker_flags=-v
verstring=
@@ -13672,7 +13770,7 @@ echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
library_names_spec=
libname_spec='lib$name'
soname_spec=
-shrext=".so"
+shrext_cmds=".so"
postinstall_cmds=
postuninstall_cmds=
finish_cmds=
@@ -13769,7 +13867,7 @@ beos*)
shlibpath_var=LIBRARY_PATH
;;
-bsdi4*)
+bsdi[45]*)
version_type=linux
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
@@ -13785,7 +13883,7 @@ bsdi4*)
cygwin* | mingw* | pw32*)
version_type=windows
- shrext=".dll"
+ shrext_cmds=".dll"
need_version=no
need_lib_prefix=no
@@ -13797,7 +13895,8 @@ cygwin* | mingw* | pw32*)
dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
dldir=$destdir/`dirname \$dlpath`~
test -d \$dldir || mkdir -p \$dldir~
- $install_prog $dir/$dlname \$dldir/$dlname'
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname'
postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
dlpath=$dir/\$dldll~
$rm \$dlpath'
@@ -13827,11 +13926,35 @@ cygwin* | mingw* | pw32*)
;;
pw32*)
# pw32 DLLs use 'pw' prefix rather than 'lib'
- library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
;;
esac
;;
+ linux*)
+ if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+ if test $supports_anon_versioning = yes; then
+ archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~
+cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+$echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ else
+ $archive_expsym_cmds="$archive_cmds"
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
*)
library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
;;
@@ -13850,7 +13973,7 @@ darwin* | rhapsody*)
soname_spec='${libname}${release}${major}$shared_ext'
shlibpath_overrides_runpath=yes
shlibpath_var=DYLD_LIBRARY_PATH
- shrext='$(test .$module = .yes && echo .so || echo .dylib)'
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
# Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
if test "$GCC" = yes; then
sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
@@ -13885,9 +14008,25 @@ kfreebsd*-gnu)
dynamic_linker='GNU ld.so'
;;
-freebsd*)
- objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
- version_type=freebsd-$objformat
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[123]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ # Handle Gentoo/FreeBSD as it was Linux
+ case $host_vendor in
+ gentoo)
+ version_type=linux ;;
+ *)
+ version_type=freebsd-$objformat ;;
+ esac
+
case $version_type in
freebsd-elf*)
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
@@ -13898,20 +14037,31 @@ freebsd*)
library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
need_version=yes
;;
+ linux)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ need_lib_prefix=no
+ need_version=no
+ ;;
esac
shlibpath_var=LD_LIBRARY_PATH
case $host_os in
freebsd2*)
shlibpath_overrides_runpath=yes
;;
- freebsd3.01* | freebsdelf3.01*)
+ freebsd3.[01]* | freebsdelf3.[01]*)
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
;;
- *) # from 3.2 on
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
;;
+ freebsd*) # from 4.6 on
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
esac
;;
@@ -13931,9 +14081,9 @@ hpux9* | hpux10* | hpux11*)
version_type=sunos
need_lib_prefix=no
need_version=no
- case "$host_cpu" in
+ case $host_cpu in
ia64*)
- shrext='.so'
+ shrext_cmds='.so'
hardcode_into_libs=yes
dynamic_linker="$host_os dld.so"
shlibpath_var=LD_LIBRARY_PATH
@@ -13948,7 +14098,7 @@ hpux9* | hpux10* | hpux11*)
sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
hppa*64*)
- shrext='.sl'
+ shrext_cmds='.sl'
hardcode_into_libs=yes
dynamic_linker="$host_os dld.sl"
shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
@@ -13959,7 +14109,7 @@ hpux9* | hpux10* | hpux11*)
sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
*)
- shrext='.sl'
+ shrext_cmds='.sl'
dynamic_linker="$host_os dld.sl"
shlibpath_var=SHLIB_PATH
shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
@@ -13971,6 +14121,18 @@ hpux9* | hpux10* | hpux11*)
postinstall_cmds='chmod 555 $lib'
;;
+interix3*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
irix5* | irix6* | nonstopux*)
case $host_os in
nonstopux*) version_type=nonstopux ;;
@@ -14030,8 +14192,8 @@ linux*)
# Append ld.so.conf contents to the search path
if test -f /etc/ld.so.conf; then
- ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf`
- sys_lib_dlsearch_path_spec="/lib /usr/lib $ld_extra"
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
fi
# We used to test for /lib/ld.so.1 and disable shared libraries on
@@ -14092,8 +14254,13 @@ nto-qnx*)
openbsd*)
version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
need_lib_prefix=no
- need_version=yes
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
shlibpath_var=LD_LIBRARY_PATH
@@ -14113,7 +14280,7 @@ openbsd*)
os2*)
libname_spec='$name'
- shrext=".dll"
+ shrext_cmds=".dll"
need_lib_prefix=no
library_names_spec='$libname${shared_ext} $libname.a'
dynamic_linker='OS/2 ld.exe'
@@ -14131,13 +14298,6 @@ osf3* | osf4* | osf5*)
sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
;;
-sco3.2v5*)
- version_type=osf
- soname_spec='${libname}${release}${shared_ext}$major'
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
solaris*)
version_type=linux
need_lib_prefix=no
@@ -14163,7 +14323,7 @@ sunos4*)
need_version=yes
;;
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+sysv4 | sysv4.3*)
version_type=linux
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
@@ -14196,6 +14356,29 @@ sysv4*MP*)
fi
;;
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ shlibpath_overrides_runpath=no
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ shlibpath_overrides_runpath=yes
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
uts4*)
version_type=linux
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
@@ -14211,12 +14394,17 @@ echo "$as_me:$LINENO: result: $dynamic_linker" >&5
echo "${ECHO_T}$dynamic_linker" >&6
test "$dynamic_linker" = no && can_build_shared=no
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
hardcode_action_F77=
if test -n "$hardcode_libdir_flag_spec_F77" || \
- test -n "$runpath_var F77" || \
- test "X$hardcode_automatic_F77"="Xyes" ; then
+ test -n "$runpath_var_F77" || \
+ test "X$hardcode_automatic_F77" = "Xyes" ; then
# We can hardcode non-existant directories.
if test "$hardcode_direct_F77" != no &&
@@ -14248,36 +14436,6 @@ elif test "$shlibpath_overrides_runpath" = yes ||
enable_fast_install=needless
fi
-striplib=
-old_striplib=
-echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
-echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
-if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
- test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
- test -z "$striplib" && striplib="$STRIP --strip-unneeded"
- echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6
-else
-# FIXME - insert some real tests, host_os isn't really good enough
- case $host_os in
- darwin*)
- if test -n "$STRIP" ; then
- striplib="$STRIP -x"
- echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6
- else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
- ;;
- *)
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
- ;;
- esac
-fi
-
-
# The else clause should only fire when bootstrapping the
# libtool distribution, otherwise you forgot to ship ltmain.sh
@@ -14292,7 +14450,7 @@ if test -f "$ltmain"; then
# Now quote all the things that may contain metacharacters while being
# careful not to overquote the AC_SUBSTed values. We take copies of the
# variables and quote the copies for generation of the libtool script.
- for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \
SED SHELL STRIP \
libname_spec library_names_spec soname_spec extract_expsyms_cmds \
old_striplib striplib file_magic_cmd finish_cmds finish_eval \
@@ -14393,6 +14551,12 @@ fast_install=$enable_fast_install
# The host system.
host_alias=$host_alias
host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
# An echo program that does not interpret backslashes.
echo=$lt_echo
@@ -14404,6 +14568,9 @@ AR_FLAGS=$lt_AR_FLAGS
# A C compiler.
LTCC=$lt_LTCC
+# LTCC compiler flags.
+LTCFLAGS=$lt_LTCFLAGS
+
# A language-specific compiler.
CC=$lt_compiler_F77
@@ -14454,7 +14621,7 @@ objext="$ac_objext"
libext="$libext"
# Shared library suffix (normally ".so").
-shrext='$shrext'
+shrext_cmds='$shrext_cmds'
# Executable file suffix (normally "").
exeext="$exeext"
@@ -14469,7 +14636,7 @@ max_cmd_len=$lt_cv_sys_max_cmd_len
# Does compiler simultaneously support -c and -o options?
compiler_c_o=$lt_lt_cv_prog_compiler_c_o_F77
-# Must we lock files when doing compilation ?
+# Must we lock files when doing compilation?
need_locks=$lt_need_locks
# Do we need the lib prefix for modules?
@@ -14707,26 +14874,55 @@ objext_GCJ=$objext
lt_simple_compile_test_code="class foo {}\n"
# Code to be used in simple link tests
-lt_simple_link_test_code='public class conftest { public static void main(String argv) {}; }\n'
+lt_simple_link_test_code='public class conftest { public static void main(String[] argv) {}; }\n'
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
# If no C compiler was specified, use CC.
LTCC=${LTCC-"$CC"}
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
# Allow CC to be a program name with arguments.
compiler=$CC
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+printf "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$rm conftest*
+
+ac_outfile=conftest.$ac_objext
+printf "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$rm conftest*
+
+
# Allow CC to be a program name with arguments.
lt_save_CC="$CC"
CC=${GCJ-"gcj"}
compiler=$CC
compiler_GCJ=$CC
+for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+
# GCJ did not exist at the time GCC didn't implicitly link libc in.
archive_cmds_need_lc_GCJ=no
+old_archive_cmds_GCJ=$old_archive_cmds
+
lt_prog_compiler_no_builtin_flag_GCJ=
@@ -14749,18 +14945,20 @@ else
# with a dollar sign (not a hyphen), so the echo should work correctly.
# The option is referenced via a variable to avoid confusing sed.
lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:14755: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:14951: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:14759: \$? = $ac_status" >&5
+ echo "$as_me:14955: \$? = $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
- if test ! -s conftest.err; then
+ # So say no if there are warnings other than the usual output.
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
lt_cv_prog_compiler_rtti_exceptions=yes
fi
fi
@@ -14821,6 +15019,11 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
lt_prog_compiler_pic_GCJ='-fno-common'
;;
+ interix3*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
msdosdjgpp*)
# Just because we use GCC doesn't mean we suddenly get shared libraries
# on systems that don't support them.
@@ -14837,7 +15040,7 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
hpux*)
# PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
# not for PA HP-UX.
- case "$host_cpu" in
+ case $host_cpu in
hppa*64*|ia64*)
# +Z the default
;;
@@ -14863,6 +15066,16 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
lt_prog_compiler_static_GCJ='-bnso -bI:/lib/syscalls.exp'
fi
;;
+ darwin*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ case $cc_basename in
+ xlc*)
+ lt_prog_compiler_pic_GCJ='-qnocommon'
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ ;;
+ esac
+ ;;
mingw* | pw32* | os2*)
# This hack is so that the source file can tell whether it is being
@@ -14874,7 +15087,7 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
lt_prog_compiler_wl_GCJ='-Wl,'
# PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
# not for PA HP-UX.
- case "$host_cpu" in
+ case $host_cpu in
hppa*64*|ia64*)
# +Z the default
;;
@@ -14898,12 +15111,19 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
;;
linux*)
- case $CC in
+ case $cc_basename in
icc* | ecc*)
lt_prog_compiler_wl_GCJ='-Wl,'
lt_prog_compiler_pic_GCJ='-KPIC'
lt_prog_compiler_static_GCJ='-static'
;;
+ pgcc* | pgf77* | pgf90* | pgf95*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ lt_prog_compiler_pic_GCJ='-fpic'
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ ;;
ccc*)
lt_prog_compiler_wl_GCJ='-Wl,'
# All Alpha code is PIC.
@@ -14918,15 +15138,15 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
lt_prog_compiler_static_GCJ='-non_shared'
;;
- sco3.2v5*)
- lt_prog_compiler_pic_GCJ='-Kpic'
- lt_prog_compiler_static_GCJ='-dn'
- ;;
-
solaris*)
- lt_prog_compiler_wl_GCJ='-Wl,'
lt_prog_compiler_pic_GCJ='-KPIC'
lt_prog_compiler_static_GCJ='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95*)
+ lt_prog_compiler_wl_GCJ='-Qoption ld ';;
+ *)
+ lt_prog_compiler_wl_GCJ='-Wl,';;
+ esac
;;
sunos4*)
@@ -14935,7 +15155,7 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
lt_prog_compiler_static_GCJ='-Bstatic'
;;
- sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ sysv4 | sysv4.2uw2* | sysv4.3*)
lt_prog_compiler_wl_GCJ='-Wl,'
lt_prog_compiler_pic_GCJ='-KPIC'
lt_prog_compiler_static_GCJ='-Bstatic'
@@ -14948,6 +15168,17 @@ echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
fi
;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ lt_prog_compiler_pic_GCJ='-KPIC'
+ lt_prog_compiler_static_GCJ='-Bstatic'
+ ;;
+
+ unicos*)
+ lt_prog_compiler_wl_GCJ='-Wl,'
+ lt_prog_compiler_can_build_shared_GCJ=no
+ ;;
+
uts4*)
lt_prog_compiler_pic_GCJ='-pic'
lt_prog_compiler_static_GCJ='-Bstatic'
@@ -14982,18 +15213,20 @@ else
# with a dollar sign (not a hyphen), so the echo should work correctly.
# The option is referenced via a variable to avoid confusing sed.
lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:14988: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:15219: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:14992: \$? = $ac_status" >&5
+ echo "$as_me:15223: \$? = $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
- if test ! -s conftest.err; then
+ # So say no if there are warnings other than the usual output.
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
lt_prog_compiler_pic_works_GCJ=yes
fi
fi
@@ -15014,7 +15247,7 @@ else
fi
fi
-case "$host_os" in
+case $host_os in
# For platforms which do not support PIC, -DPIC is meaningless:
*djgpp*)
lt_prog_compiler_pic_GCJ=
@@ -15024,6 +15257,48 @@ case "$host_os" in
;;
esac
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl_GCJ eval lt_tmp_static_flag=\"$lt_prog_compiler_static_GCJ\"
+echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6
+if test "${lt_prog_compiler_static_works_GCJ+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_static_works_GCJ=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ printf "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_prog_compiler_static_works_GCJ=yes
+ fi
+ else
+ lt_prog_compiler_static_works_GCJ=yes
+ fi
+ fi
+ $rm conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_GCJ" >&5
+echo "${ECHO_T}$lt_prog_compiler_static_works_GCJ" >&6
+
+if test x"$lt_prog_compiler_static_works_GCJ" = xyes; then
+ :
+else
+ lt_prog_compiler_static_GCJ=
+fi
+
+
echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
if test "${lt_cv_prog_compiler_c_o_GCJ+set}" = set; then
@@ -15042,23 +15317,25 @@ else
# Note that $ac_compile itself does not contain backslashes and begins
# with a dollar sign (not a hyphen), so the echo should work correctly.
lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:15048: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:15323: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:15052: \$? = $ac_status" >&5
+ echo "$as_me:15327: \$? = $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
# So say no if there are warnings
- if test ! -s out/conftest.err; then
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
lt_cv_prog_compiler_c_o_GCJ=yes
fi
fi
- chmod u+w .
+ chmod u+w . 2>&5
$rm conftest*
# SGI C++ compiler will create directory out/ii_files/ for
# template instantiation
@@ -15134,6 +15411,16 @@ echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared librar
# rely on this symbol name, it's probably fine to never include it in
# preloaded symbol tables.
extract_expsyms_cmds=
+ # Just being paranoid about ensuring that cc_basename is set.
+ for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
case $host_os in
cygwin* | mingw* | pw32*)
@@ -15144,6 +15431,10 @@ echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared librar
with_gnu_ld=no
fi
;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
openbsd*)
with_gnu_ld=no
;;
@@ -15154,6 +15445,27 @@ echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared librar
# If archive_cmds runs LD, not CC, wlarc should be empty
wlarc='${wl}'
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec_GCJ='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec_GCJ='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec_GCJ="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec_GCJ=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
# See if GNU ld supports shared libraries.
case $host_os in
aix3* | aix4* | aix5*)
@@ -15204,10 +15516,10 @@ EOF
allow_undefined_flag_GCJ=unsupported
always_export_symbols_GCJ=no
enable_shared_with_static_runtimes_GCJ=yes
- export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
+ export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols'
if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
- archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
# If the export-symbols file already is a .def file (1st line
# is EXPORTS), use it as is; otherwise, prepend...
archive_expsym_cmds_GCJ='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
@@ -15216,13 +15528,59 @@ EOF
echo EXPORTS > $output_objdir/$soname.def;
cat $export_symbols >> $output_objdir/$soname.def;
fi~
- $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib'
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
else
- ld_shlibs=no
+ ld_shlibs_GCJ=no
fi
;;
- netbsd* | knetbsd*-gnu)
+ interix3*)
+ hardcode_direct_GCJ=no
+ hardcode_shlibpath_var_GCJ=no
+ hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_GCJ='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds_GCJ='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds_GCJ='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ linux*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ tmp_addflag=
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ whole_archive_flag_spec_GCJ='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers
+ whole_archive_flag_spec_GCJ='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ esac
+ archive_cmds_GCJ='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test $supports_anon_versioning = yes; then
+ archive_expsym_cmds_GCJ='$echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ $echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ else
+ ld_shlibs_GCJ=no
+ fi
+ ;;
+
+ netbsd*)
if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
archive_cmds_GCJ='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
wlarc=
@@ -15232,7 +15590,7 @@ EOF
fi
;;
- solaris* | sysv5*)
+ solaris*)
if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
ld_shlibs_GCJ=no
cat <<EOF 1>&2
@@ -15253,6 +15611,33 @@ EOF
fi
;;
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs_GCJ=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec_GCJ='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
+ archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib'
+ archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib'
+ else
+ ld_shlibs_GCJ=no
+ fi
+ ;;
+ esac
+ ;;
+
sunos4*)
archive_cmds_GCJ='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
wlarc=
@@ -15260,31 +15645,6 @@ EOF
hardcode_shlibpath_var_GCJ=no
;;
- linux*)
- if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_cmds_GCJ="$tmp_archive_cmds"
- supports_anon_versioning=no
- case `$LD -v 2>/dev/null` in
- *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
- *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
- *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
- *\ 2.11.*) ;; # other 2.11 versions
- *) supports_anon_versioning=yes ;;
- esac
- if test $supports_anon_versioning = yes; then
- archive_expsym_cmds_GCJ='$echo "{ global:" > $output_objdir/$libname.ver~
-cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-$echo "local: *; };" >> $output_objdir/$libname.ver~
- $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
- else
- archive_expsym_cmds_GCJ="$tmp_archive_cmds"
- fi
- else
- ld_shlibs_GCJ=no
- fi
- ;;
-
*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
@@ -15295,16 +15655,11 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
;;
esac
- if test "$ld_shlibs_GCJ" = yes; then
- runpath_var=LD_RUN_PATH
- hardcode_libdir_flag_spec_GCJ='${wl}--rpath ${wl}$libdir'
- export_dynamic_flag_spec_GCJ='${wl}--export-dynamic'
- # ancient GNU ld didn't support --whole-archive et. al.
- if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
- whole_archive_flag_spec_GCJ="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
- else
- whole_archive_flag_spec_GCJ=
- fi
+ if test "$ld_shlibs_GCJ" = no; then
+ runpath_var=
+ hardcode_libdir_flag_spec_GCJ=
+ export_dynamic_flag_spec_GCJ=
+ whole_archive_flag_spec_GCJ=
fi
else
# PORTME fill in a description of your system's linker (not GNU ld)
@@ -15316,7 +15671,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
# Note: this linker hardcodes the directories in LIBPATH if there
# are no directories specified by -L.
hardcode_minus_L_GCJ=yes
- if test "$GCC" = yes && test -z "$link_static_flag"; then
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
# Neither direct hardcoding nor static linking is supported with a
# broken collect2.
hardcode_direct_GCJ=unsupported
@@ -15350,6 +15705,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
break
fi
done
+ ;;
esac
exp_sym_flag='-bexport'
@@ -15368,7 +15724,7 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
link_all_deplibs_GCJ=yes
if test "$GCC" = yes; then
- case $host_os in aix4.012|aix4.012.*)
+ case $host_os in aix4.[012]|aix4.[012].*)
# We only want to do this on AIX 4.2 and lower, the check
# below for broken collect2 doesn't work under 4.3+
collect2name=`${CC} -print-prog-name=collect2`
@@ -15387,8 +15743,12 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
hardcode_libdir_flag_spec_GCJ='-L$libdir'
hardcode_libdir_separator_GCJ=
fi
+ ;;
esac
shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
else
# not using gcc
if test "$host_cpu" = ia64; then
@@ -15396,11 +15756,11 @@ $echo "local: *; };" >> $output_objdir/$libname.ver~
# chokes on -Wl,-G. The following line is correct:
shared_flag='-G'
else
- if test "$aix_use_runtimelinking" = yes; then
+ if test "$aix_use_runtimelinking" = yes; then
shared_flag='${wl}-G'
else
shared_flag='${wl}-bM:SRE'
- fi
+ fi
fi
fi
@@ -15465,12 +15825,12 @@ rm -f conftest.err conftest.$ac_objext \
if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath"
- archive_expsym_cmds_GCJ="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ archive_expsym_cmds_GCJ="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
else
if test "$host_cpu" = ia64; then
hardcode_libdir_flag_spec_GCJ='${wl}-R $libdir:/usr/lib:/lib'
allow_undefined_flag_GCJ="-z nodefs"
- archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+ archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
else
# Determine the default libpath from the value encoded in an empty executable.
cat >conftest.$ac_ext <<_ACEOF
@@ -15530,13 +15890,11 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
# -berok will link without error, but may produce a broken library.
no_undefined_flag_GCJ=' ${wl}-bernotok'
allow_undefined_flag_GCJ=' ${wl}-berok'
- # -bexpall does not export symbols beginning with underscore (_)
- always_export_symbols_GCJ=yes
# Exported symbols can be pulled into shared objects from archives
- whole_archive_flag_spec_GCJ=' '
+ whole_archive_flag_spec_GCJ='$convenience'
archive_cmds_need_lc_GCJ=yes
- # This is similar to how AIX traditionally builds it's shared libraries.
- archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
fi
fi
;;
@@ -15549,7 +15907,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
ld_shlibs_GCJ=no
;;
- bsdi4*)
+ bsdi[45]*)
export_dynamic_flag_spec_GCJ=-rdynamic
;;
@@ -15563,64 +15921,64 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
# Tell ltmain to make .lib files, not .a files.
libext=lib
# Tell ltmain to make .dll files, not .so files.
- shrext=".dll"
+ shrext_cmds=".dll"
# FIXME: Setting linknames here is a bad hack.
archive_cmds_GCJ='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
# The linker will automatically build a .lib file if we build a DLL.
old_archive_From_new_cmds_GCJ='true'
# FIXME: Should let the user specify the lib program.
old_archive_cmds_GCJ='lib /OUT:$oldlib$oldobjs$old_deplibs'
- fix_srcfile_path='`cygpath -w "$srcfile"`'
+ fix_srcfile_path_GCJ='`cygpath -w "$srcfile"`'
enable_shared_with_static_runtimes_GCJ=yes
;;
darwin* | rhapsody*)
- if test "$GXX" = yes ; then
- archive_cmds_need_lc_GCJ=no
- case "$host_os" in
- rhapsody* | darwin1.[012])
- allow_undefined_flag_GCJ='-undefined suppress'
- ;;
- *) # Darwin 1.3 on
- if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
- allow_undefined_flag_GCJ='-flat_namespace -undefined suppress'
- else
- case ${MACOSX_DEPLOYMENT_TARGET} in
- 10.[012])
- allow_undefined_flag_GCJ='-flat_namespace -undefined suppress'
- ;;
- 10.*)
- allow_undefined_flag_GCJ='-undefined dynamic_lookup'
- ;;
- esac
- fi
- ;;
+ case $host_os in
+ rhapsody* | darwin1.[012])
+ allow_undefined_flag_GCJ='${wl}-undefined ${wl}suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[012])
+ allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ ;;
+ 10.*)
+ allow_undefined_flag_GCJ='${wl}-undefined ${wl}dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
esac
- lt_int_apple_cc_single_mod=no
- output_verbose_link_cmd='echo'
- if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then
- lt_int_apple_cc_single_mod=yes
- fi
- if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
- archive_cmds_GCJ='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
- else
- archive_cmds_GCJ='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
- fi
- module_cmds_GCJ='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
- # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's
- if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
- archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- else
- archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
- fi
- module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ archive_cmds_need_lc_GCJ=no
hardcode_direct_GCJ=no
hardcode_automatic_GCJ=yes
hardcode_shlibpath_var_GCJ=unsupported
- whole_archive_flag_spec_GCJ='-all_load $convenience'
+ whole_archive_flag_spec_GCJ=''
link_all_deplibs_GCJ=yes
+ if test "$GCC" = yes ; then
+ output_verbose_link_cmd='echo'
+ archive_cmds_GCJ='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
else
- ld_shlibs_GCJ=no
+ case $cc_basename in
+ xlc*)
+ output_verbose_link_cmd='echo'
+ archive_cmds_GCJ='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+ module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ ;;
+ *)
+ ld_shlibs_GCJ=no
+ ;;
+ esac
fi
;;
@@ -15654,7 +16012,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
;;
# FreeBSD 3 and greater uses gcc -shared to do shared libraries.
- freebsd* | kfreebsd*-gnu)
+ freebsd* | kfreebsd*-gnu | dragonfly*)
archive_cmds_GCJ='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
hardcode_libdir_flag_spec_GCJ='-R$libdir'
hardcode_direct_GCJ=yes
@@ -15677,47 +16035,62 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
export_dynamic_flag_spec_GCJ='${wl}-E'
;;
- hpux10* | hpux11*)
+ hpux10*)
if test "$GCC" = yes -a "$with_gnu_ld" = no; then
- case "$host_cpu" in
- hppa*64*|ia64*)
+ archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_GCJ='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_GCJ=:
+
+ hardcode_direct_GCJ=yes
+ export_dynamic_flag_spec_GCJ='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_GCJ=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
+ ia64*)
+ archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
*)
archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
else
- case "$host_cpu" in
- hppa*64*|ia64*)
- archive_cmds_GCJ='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags'
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
;;
*)
- archive_cmds_GCJ='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
fi
if test "$with_gnu_ld" = no; then
- case "$host_cpu" in
- hppa*64*)
- hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_GCJ=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
hardcode_libdir_flag_spec_ld_GCJ='+b $libdir'
- hardcode_libdir_separator_GCJ=:
- hardcode_direct_GCJ=no
- hardcode_shlibpath_var_GCJ=no
- ;;
- ia64*)
- hardcode_libdir_flag_spec_GCJ='-L$libdir'
hardcode_direct_GCJ=no
hardcode_shlibpath_var_GCJ=no
-
- # hardcode_minus_L: Not really in the search PATH,
- # but as the default location of the library.
- hardcode_minus_L_GCJ=yes
;;
*)
- hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir'
- hardcode_libdir_separator_GCJ=:
hardcode_direct_GCJ=yes
export_dynamic_flag_spec_GCJ='${wl}-E'
@@ -15741,7 +16114,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
link_all_deplibs_GCJ=yes
;;
- netbsd* | knetbsd*-gnu)
+ netbsd*)
if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
else
@@ -15765,6 +16138,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
hardcode_shlibpath_var_GCJ=no
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir'
export_dynamic_flag_spec_GCJ='${wl}-E'
else
@@ -15810,7 +16184,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
allow_undefined_flag_GCJ=' -expect_unresolved \*'
archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
archive_expsym_cmds_GCJ='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
- $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
+ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp'
# Both c and cxx compiler support -rpath directly
hardcode_libdir_flag_spec_GCJ='-rpath $libdir'
@@ -15818,21 +16192,15 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
hardcode_libdir_separator_GCJ=:
;;
- sco3.2v5*)
- archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_shlibpath_var_GCJ=no
- export_dynamic_flag_spec_GCJ='${wl}-Bexport'
- runpath_var=LD_RUN_PATH
- hardcode_runpath_var=yes
- ;;
-
solaris*)
no_undefined_flag_GCJ=' -z text'
if test "$GCC" = yes; then
+ wlarc='${wl}'
archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
$CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
else
+ wlarc=''
archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
$LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
@@ -15841,8 +16209,18 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
hardcode_shlibpath_var_GCJ=no
case $host_os in
solaris2.[0-5] | solaris2.[0-5].*) ;;
- *) # Supported since Solaris 2.6 (maybe 2.5.1?)
- whole_archive_flag_spec_GCJ='-z allextract$convenience -z defaultextract' ;;
+ *)
+ # The compiler driver will combine linker options so we
+ # cannot just pass the convience library names through
+ # without $wl, iff we do not link with $LD.
+ # Luckily, gcc supports the same syntax we need for Sun Studio.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ case $wlarc in
+ '')
+ whole_archive_flag_spec_GCJ='-z allextract$convenience -z defaultextract' ;;
+ *)
+ whole_archive_flag_spec_GCJ='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;;
+ esac ;;
esac
link_all_deplibs_GCJ=yes
;;
@@ -15899,36 +16277,45 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
fi
;;
- sysv4.2uw2*)
- archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct_GCJ=yes
- hardcode_minus_L_GCJ=no
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*)
+ no_undefined_flag_GCJ='${wl}-z,text'
+ archive_cmds_need_lc_GCJ=no
hardcode_shlibpath_var_GCJ=no
- hardcode_runpath_var=yes
- runpath_var=LD_RUN_PATH
- ;;
+ runpath_var='LD_RUN_PATH'
- sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*)
- no_undefined_flag_GCJ='${wl}-z ${wl}text'
if test "$GCC" = yes; then
- archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds_GCJ='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_GCJ='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
else
- archive_cmds_GCJ='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds_GCJ='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_GCJ='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
fi
- runpath_var='LD_RUN_PATH'
- hardcode_shlibpath_var_GCJ=no
;;
- sysv5*)
- no_undefined_flag_GCJ=' -z text'
- # $CC -shared without GNU ld will not create a library from C++
- # object files and a static libstdc++, better avoid it by now
- archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
- archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
- $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
- hardcode_libdir_flag_spec_GCJ=
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag_GCJ='${wl}-z,text'
+ allow_undefined_flag_GCJ='${wl}-z,nodefs'
+ archive_cmds_need_lc_GCJ=no
hardcode_shlibpath_var_GCJ=no
+ hardcode_libdir_flag_spec_GCJ='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+ hardcode_libdir_separator_GCJ=':'
+ link_all_deplibs_GCJ=yes
+ export_dynamic_flag_spec_GCJ='${wl}-Bexport'
runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds_GCJ='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_GCJ='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_GCJ='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_GCJ='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
;;
uts4*)
@@ -15947,11 +16334,6 @@ echo "$as_me:$LINENO: result: $ld_shlibs_GCJ" >&5
echo "${ECHO_T}$ld_shlibs_GCJ" >&6
test "$ld_shlibs_GCJ" = no && can_build_shared=no
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
- variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
-
#
# Do we need to explicitly link libc?
#
@@ -15984,6 +16366,7 @@ echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&
libobjs=conftest.$ac_objext
deplibs=
wl=$lt_prog_compiler_wl_GCJ
+ pic_flag=$lt_prog_compiler_pic_GCJ
compiler_flags=-v
linker_flags=-v
verstring=
@@ -16019,7 +16402,7 @@ echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
library_names_spec=
libname_spec='lib$name'
soname_spec=
-shrext=".so"
+shrext_cmds=".so"
postinstall_cmds=
postuninstall_cmds=
finish_cmds=
@@ -16116,7 +16499,7 @@ beos*)
shlibpath_var=LIBRARY_PATH
;;
-bsdi4*)
+bsdi[45]*)
version_type=linux
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
@@ -16132,7 +16515,7 @@ bsdi4*)
cygwin* | mingw* | pw32*)
version_type=windows
- shrext=".dll"
+ shrext_cmds=".dll"
need_version=no
need_lib_prefix=no
@@ -16144,7 +16527,8 @@ cygwin* | mingw* | pw32*)
dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
dldir=$destdir/`dirname \$dlpath`~
test -d \$dldir || mkdir -p \$dldir~
- $install_prog $dir/$dlname \$dldir/$dlname'
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname'
postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
dlpath=$dir/\$dldll~
$rm \$dlpath'
@@ -16174,11 +16558,35 @@ cygwin* | mingw* | pw32*)
;;
pw32*)
# pw32 DLLs use 'pw' prefix rather than 'lib'
- library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
;;
esac
;;
+ linux*)
+ if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+ if test $supports_anon_versioning = yes; then
+ archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~
+cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+$echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ else
+ $archive_expsym_cmds="$archive_cmds"
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
*)
library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
;;
@@ -16197,7 +16605,7 @@ darwin* | rhapsody*)
soname_spec='${libname}${release}${major}$shared_ext'
shlibpath_overrides_runpath=yes
shlibpath_var=DYLD_LIBRARY_PATH
- shrext='$(test .$module = .yes && echo .so || echo .dylib)'
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
# Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
if test "$GCC" = yes; then
sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
@@ -16232,9 +16640,25 @@ kfreebsd*-gnu)
dynamic_linker='GNU ld.so'
;;
-freebsd*)
- objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
- version_type=freebsd-$objformat
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[123]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ # Handle Gentoo/FreeBSD as it was Linux
+ case $host_vendor in
+ gentoo)
+ version_type=linux ;;
+ *)
+ version_type=freebsd-$objformat ;;
+ esac
+
case $version_type in
freebsd-elf*)
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
@@ -16245,20 +16669,31 @@ freebsd*)
library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
need_version=yes
;;
+ linux)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ need_lib_prefix=no
+ need_version=no
+ ;;
esac
shlibpath_var=LD_LIBRARY_PATH
case $host_os in
freebsd2*)
shlibpath_overrides_runpath=yes
;;
- freebsd3.01* | freebsdelf3.01*)
+ freebsd3.[01]* | freebsdelf3.[01]*)
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
;;
- *) # from 3.2 on
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
;;
+ freebsd*) # from 4.6 on
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
esac
;;
@@ -16278,9 +16713,9 @@ hpux9* | hpux10* | hpux11*)
version_type=sunos
need_lib_prefix=no
need_version=no
- case "$host_cpu" in
+ case $host_cpu in
ia64*)
- shrext='.so'
+ shrext_cmds='.so'
hardcode_into_libs=yes
dynamic_linker="$host_os dld.so"
shlibpath_var=LD_LIBRARY_PATH
@@ -16295,7 +16730,7 @@ hpux9* | hpux10* | hpux11*)
sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
hppa*64*)
- shrext='.sl'
+ shrext_cmds='.sl'
hardcode_into_libs=yes
dynamic_linker="$host_os dld.sl"
shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
@@ -16306,7 +16741,7 @@ hpux9* | hpux10* | hpux11*)
sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
*)
- shrext='.sl'
+ shrext_cmds='.sl'
dynamic_linker="$host_os dld.sl"
shlibpath_var=SHLIB_PATH
shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
@@ -16318,6 +16753,18 @@ hpux9* | hpux10* | hpux11*)
postinstall_cmds='chmod 555 $lib'
;;
+interix3*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
irix5* | irix6* | nonstopux*)
case $host_os in
nonstopux*) version_type=nonstopux ;;
@@ -16377,8 +16824,8 @@ linux*)
# Append ld.so.conf contents to the search path
if test -f /etc/ld.so.conf; then
- ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf`
- sys_lib_dlsearch_path_spec="/lib /usr/lib $ld_extra"
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
fi
# We used to test for /lib/ld.so.1 and disable shared libraries on
@@ -16439,8 +16886,13 @@ nto-qnx*)
openbsd*)
version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
need_lib_prefix=no
- need_version=yes
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
shlibpath_var=LD_LIBRARY_PATH
@@ -16460,7 +16912,7 @@ openbsd*)
os2*)
libname_spec='$name'
- shrext=".dll"
+ shrext_cmds=".dll"
need_lib_prefix=no
library_names_spec='$libname${shared_ext} $libname.a'
dynamic_linker='OS/2 ld.exe'
@@ -16478,13 +16930,6 @@ osf3* | osf4* | osf5*)
sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
;;
-sco3.2v5*)
- version_type=osf
- soname_spec='${libname}${release}${shared_ext}$major'
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
solaris*)
version_type=linux
need_lib_prefix=no
@@ -16510,7 +16955,7 @@ sunos4*)
need_version=yes
;;
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+sysv4 | sysv4.3*)
version_type=linux
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
@@ -16543,6 +16988,29 @@ sysv4*MP*)
fi
;;
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ shlibpath_overrides_runpath=no
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ shlibpath_overrides_runpath=yes
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
uts4*)
version_type=linux
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
@@ -16558,12 +17026,17 @@ echo "$as_me:$LINENO: result: $dynamic_linker" >&5
echo "${ECHO_T}$dynamic_linker" >&6
test "$dynamic_linker" = no && can_build_shared=no
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
hardcode_action_GCJ=
if test -n "$hardcode_libdir_flag_spec_GCJ" || \
- test -n "$runpath_var GCJ" || \
- test "X$hardcode_automatic_GCJ"="Xyes" ; then
+ test -n "$runpath_var_GCJ" || \
+ test "X$hardcode_automatic_GCJ" = "Xyes" ; then
# We can hardcode non-existant directories.
if test "$hardcode_direct_GCJ" != no &&
@@ -16595,841 +17068,6 @@ elif test "$shlibpath_overrides_runpath" = yes ||
enable_fast_install=needless
fi
-striplib=
-old_striplib=
-echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
-echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
-if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
- test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
- test -z "$striplib" && striplib="$STRIP --strip-unneeded"
- echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6
-else
-# FIXME - insert some real tests, host_os isn't really good enough
- case $host_os in
- darwin*)
- if test -n "$STRIP" ; then
- striplib="$STRIP -x"
- echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6
- else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
- ;;
- *)
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
- ;;
- esac
-fi
-
-if test "x$enable_dlopen" != xyes; then
- enable_dlopen=unknown
- enable_dlopen_self=unknown
- enable_dlopen_self_static=unknown
-else
- lt_cv_dlopen=no
- lt_cv_dlopen_libs=
-
- case $host_os in
- beos*)
- lt_cv_dlopen="load_add_on"
- lt_cv_dlopen_libs=
- lt_cv_dlopen_self=yes
- ;;
-
- mingw* | pw32*)
- lt_cv_dlopen="LoadLibrary"
- lt_cv_dlopen_libs=
- ;;
-
- cygwin*)
- lt_cv_dlopen="dlopen"
- lt_cv_dlopen_libs=
- ;;
-
- darwin*)
- # if libdl is installed we need to link against it
- echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
-echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
-if test "${ac_cv_lib_dl_dlopen+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-
-/* Override any gcc2 internal prototype to avoid an error. */
-#ifdef __cplusplus
-extern "C"
-#endif
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dlopen ();
-int
-main ()
-{
-dlopen ();
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_c_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_lib_dl_dlopen=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_lib_dl_dlopen=no
-fi
-rm -f conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
-echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
-if test $ac_cv_lib_dl_dlopen = yes; then
- lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
-else
-
- lt_cv_dlopen="dyld"
- lt_cv_dlopen_libs=
- lt_cv_dlopen_self=yes
-
-fi
-
- ;;
-
- *)
- echo "$as_me:$LINENO: checking for shl_load" >&5
-echo $ECHO_N "checking for shl_load... $ECHO_C" >&6
-if test "${ac_cv_func_shl_load+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 shl_load to an innocuous variant, in case <limits.h> declares shl_load.
- For example, HP-UX 11i <limits.h> declares gettimeofday. */
-#define shl_load innocuous_shl_load
-
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char shl_load (); 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 shl_load
-
-/* 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 shl_load ();
-/* 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_shl_load) || defined (__stub___shl_load)
-choke me
-#else
-char (*f) () = shl_load;
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-int
-main ()
-{
-return f != shl_load;
- ;
- 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_shl_load=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_func_shl_load=no
-fi
-rm -f conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-fi
-echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5
-echo "${ECHO_T}$ac_cv_func_shl_load" >&6
-if test $ac_cv_func_shl_load = yes; then
- lt_cv_dlopen="shl_load"
-else
- echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
-echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6
-if test "${ac_cv_lib_dld_shl_load+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldld $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 shl_load ();
-int
-main ()
-{
-shl_load ();
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_c_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_lib_dld_shl_load=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_lib_dld_shl_load=no
-fi
-rm -f conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
-echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6
-if test $ac_cv_lib_dld_shl_load = yes; then
- lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"
-else
- echo "$as_me:$LINENO: checking for dlopen" >&5
-echo $ECHO_N "checking for dlopen... $ECHO_C" >&6
-if test "${ac_cv_func_dlopen+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 dlopen to an innocuous variant, in case <limits.h> declares dlopen.
- For example, HP-UX 11i <limits.h> declares gettimeofday. */
-#define dlopen innocuous_dlopen
-
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char dlopen (); 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 dlopen
-
-/* Override any gcc2 internal prototype to avoid an error. */
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dlopen ();
-/* 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_dlopen) || defined (__stub___dlopen)
-choke me
-#else
-char (*f) () = dlopen;
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-int
-main ()
-{
-return f != dlopen;
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_c_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_func_dlopen=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_func_dlopen=no
-fi
-rm -f conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-fi
-echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
-echo "${ECHO_T}$ac_cv_func_dlopen" >&6
-if test $ac_cv_func_dlopen = yes; then
- lt_cv_dlopen="dlopen"
-else
- echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
-echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
-if test "${ac_cv_lib_dl_dlopen+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-
-/* Override any gcc2 internal prototype to avoid an error. */
-#ifdef __cplusplus
-extern "C"
-#endif
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dlopen ();
-int
-main ()
-{
-dlopen ();
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_c_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_lib_dl_dlopen=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_lib_dl_dlopen=no
-fi
-rm -f conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
-echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
-if test $ac_cv_lib_dl_dlopen = yes; then
- lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
-else
- echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5
-echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6
-if test "${ac_cv_lib_svld_dlopen+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsvld $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-
-/* Override any gcc2 internal prototype to avoid an error. */
-#ifdef __cplusplus
-extern "C"
-#endif
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dlopen ();
-int
-main ()
-{
-dlopen ();
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_c_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_lib_svld_dlopen=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_lib_svld_dlopen=no
-fi
-rm -f conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5
-echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6
-if test $ac_cv_lib_svld_dlopen = yes; then
- lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
-else
- echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5
-echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6
-if test "${ac_cv_lib_dld_dld_link+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldld $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 dld_link ();
-int
-main ()
-{
-dld_link ();
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_c_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_lib_dld_dld_link=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_lib_dld_dld_link=no
-fi
-rm -f conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5
-echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6
-if test $ac_cv_lib_dld_dld_link = yes; then
- lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
- ;;
- esac
-
- if test "x$lt_cv_dlopen" != xno; then
- enable_dlopen=yes
- else
- enable_dlopen=no
- fi
-
- case $lt_cv_dlopen in
- dlopen)
- save_CPPFLAGS="$CPPFLAGS"
- test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
-
- save_LDFLAGS="$LDFLAGS"
- eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
-
- save_LIBS="$LIBS"
- LIBS="$lt_cv_dlopen_libs $LIBS"
-
- echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5
-echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6
-if test "${lt_cv_dlopen_self+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test "$cross_compiling" = yes; then :
- lt_cv_dlopen_self=cross
-else
- lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
- lt_status=$lt_dlunknown
- cat > conftest.$ac_ext <<EOF
-#line 17232 "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-# define LT_DLGLOBAL RTLD_GLOBAL
-#else
-# ifdef DL_GLOBAL
-# define LT_DLGLOBAL DL_GLOBAL
-# else
-# define LT_DLGLOBAL 0
-# endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-# ifdef RTLD_LAZY
-# define LT_DLLAZY_OR_NOW RTLD_LAZY
-# else
-# ifdef DL_LAZY
-# define LT_DLLAZY_OR_NOW DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define LT_DLLAZY_OR_NOW RTLD_NOW
-# else
-# ifdef DL_NOW
-# define LT_DLLAZY_OR_NOW DL_NOW
-# else
-# define LT_DLLAZY_OR_NOW 0
-# endif
-# endif
-# endif
-# endif
-#endif
-
-#ifdef __cplusplus
-extern "C" void exit (int);
-#endif
-
-void fnord() { int i=42;}
-int main ()
-{
- void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
- int status = $lt_dlunknown;
-
- if (self)
- {
- if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
- else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
- /* dlclose (self); */
- }
-
- exit (status);
-}
-EOF
- if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
- (./conftest; exit; ) 2>/dev/null
- lt_status=$?
- case x$lt_status in
- x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
- x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
- x$lt_unknown|x*) lt_cv_dlopen_self=no ;;
- esac
- else :
- # compilation failed
- lt_cv_dlopen_self=no
- fi
-fi
-rm -fr conftest*
-
-
-fi
-echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
-echo "${ECHO_T}$lt_cv_dlopen_self" >&6
-
- if test "x$lt_cv_dlopen_self" = xyes; then
- LDFLAGS="$LDFLAGS $link_static_flag"
- echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
-echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6
-if test "${lt_cv_dlopen_self_static+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test "$cross_compiling" = yes; then :
- lt_cv_dlopen_self_static=cross
-else
- lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
- lt_status=$lt_dlunknown
- cat > conftest.$ac_ext <<EOF
-#line 17330 "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-# define LT_DLGLOBAL RTLD_GLOBAL
-#else
-# ifdef DL_GLOBAL
-# define LT_DLGLOBAL DL_GLOBAL
-# else
-# define LT_DLGLOBAL 0
-# endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-# ifdef RTLD_LAZY
-# define LT_DLLAZY_OR_NOW RTLD_LAZY
-# else
-# ifdef DL_LAZY
-# define LT_DLLAZY_OR_NOW DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define LT_DLLAZY_OR_NOW RTLD_NOW
-# else
-# ifdef DL_NOW
-# define LT_DLLAZY_OR_NOW DL_NOW
-# else
-# define LT_DLLAZY_OR_NOW 0
-# endif
-# endif
-# endif
-# endif
-#endif
-
-#ifdef __cplusplus
-extern "C" void exit (int);
-#endif
-
-void fnord() { int i=42;}
-int main ()
-{
- void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
- int status = $lt_dlunknown;
-
- if (self)
- {
- if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
- else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
- /* dlclose (self); */
- }
-
- exit (status);
-}
-EOF
- if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
- (./conftest; exit; ) 2>/dev/null
- lt_status=$?
- case x$lt_status in
- x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
- x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
- x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;;
- esac
- else :
- # compilation failed
- lt_cv_dlopen_self_static=no
- fi
-fi
-rm -fr conftest*
-
-
-fi
-echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5
-echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6
- fi
-
- CPPFLAGS="$save_CPPFLAGS"
- LDFLAGS="$save_LDFLAGS"
- LIBS="$save_LIBS"
- ;;
- esac
-
- case $lt_cv_dlopen_self in
- yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
- *) enable_dlopen_self=unknown ;;
- esac
-
- case $lt_cv_dlopen_self_static in
- yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
- *) enable_dlopen_self_static=unknown ;;
- esac
-fi
-
# The else clause should only fire when bootstrapping the
# libtool distribution, otherwise you forgot to ship ltmain.sh
@@ -17444,7 +17082,7 @@ if test -f "$ltmain"; then
# Now quote all the things that may contain metacharacters while being
# careful not to overquote the AC_SUBSTed values. We take copies of the
# variables and quote the copies for generation of the libtool script.
- for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \
SED SHELL STRIP \
libname_spec library_names_spec soname_spec extract_expsyms_cmds \
old_striplib striplib file_magic_cmd finish_cmds finish_eval \
@@ -17545,6 +17183,12 @@ fast_install=$enable_fast_install
# The host system.
host_alias=$host_alias
host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
# An echo program that does not interpret backslashes.
echo=$lt_echo
@@ -17556,6 +17200,9 @@ AR_FLAGS=$lt_AR_FLAGS
# A C compiler.
LTCC=$lt_LTCC
+# LTCC compiler flags.
+LTCFLAGS=$lt_LTCFLAGS
+
# A language-specific compiler.
CC=$lt_compiler_GCJ
@@ -17606,7 +17253,7 @@ objext="$ac_objext"
libext="$libext"
# Shared library suffix (normally ".so").
-shrext='$shrext'
+shrext_cmds='$shrext_cmds'
# Executable file suffix (normally "").
exeext="$exeext"
@@ -17621,7 +17268,7 @@ max_cmd_len=$lt_cv_sys_max_cmd_len
# Does compiler simultaneously support -c and -o options?
compiler_c_o=$lt_lt_cv_prog_compiler_c_o_GCJ
-# Must we lock files when doing compilation ?
+# Must we lock files when doing compilation?
need_locks=$lt_need_locks
# Do we need the lib prefix for modules?
@@ -17865,15 +17512,42 @@ lt_simple_link_test_code="$lt_simple_compile_test_code"
# If no C compiler was specified, use CC.
LTCC=${LTCC-"$CC"}
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
# Allow CC to be a program name with arguments.
compiler=$CC
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+printf "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$rm conftest*
+
+ac_outfile=conftest.$ac_objext
+printf "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$rm conftest*
+
+
# Allow CC to be a program name with arguments.
lt_save_CC="$CC"
CC=${RC-"windres"}
compiler=$CC
compiler_RC=$CC
+for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+
lt_cv_prog_compiler_c_o_RC=yes
# The else clause should only fire when bootstrapping the
@@ -17889,7 +17563,7 @@ if test -f "$ltmain"; then
# Now quote all the things that may contain metacharacters while being
# careful not to overquote the AC_SUBSTed values. We take copies of the
# variables and quote the copies for generation of the libtool script.
- for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \
SED SHELL STRIP \
libname_spec library_names_spec soname_spec extract_expsyms_cmds \
old_striplib striplib file_magic_cmd finish_cmds finish_eval \
@@ -17990,6 +17664,12 @@ fast_install=$enable_fast_install
# The host system.
host_alias=$host_alias
host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
# An echo program that does not interpret backslashes.
echo=$lt_echo
@@ -18001,6 +17681,9 @@ AR_FLAGS=$lt_AR_FLAGS
# A C compiler.
LTCC=$lt_LTCC
+# LTCC compiler flags.
+LTCFLAGS=$lt_LTCFLAGS
+
# A language-specific compiler.
CC=$lt_compiler_RC
@@ -18051,7 +17734,7 @@ objext="$ac_objext"
libext="$libext"
# Shared library suffix (normally ".so").
-shrext='$shrext'
+shrext_cmds='$shrext_cmds'
# Executable file suffix (normally "").
exeext="$exeext"
@@ -18066,7 +17749,7 @@ max_cmd_len=$lt_cv_sys_max_cmd_len
# Does compiler simultaneously support -c and -o options?
compiler_c_o=$lt_lt_cv_prog_compiler_c_o_RC
-# Must we lock files when doing compilation ?
+# Must we lock files when doing compilation?
need_locks=$lt_need_locks
# Do we need the lib prefix for modules?
@@ -18524,282 +18207,22 @@ fi
# Locate a compiler for the build machine. This compiler should
# generate command-line programs that run on the build machine.
#
-default_build_cflags="-g"
-if test "$config_BUILD_CC" = ""; then
- ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}gcc; 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_CC+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
+if test x"$cross_compiling" = xno; then
+ BUILD_CC=$CC
+ BUILD_CFLAGS=$CFLAGS
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_CC="${ac_tool_prefix}gcc"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- echo "$as_me:$LINENO: result: $CC" >&5
-echo "${ECHO_T}$CC" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
-fi
-if test -z "$ac_cv_prog_CC"; then
- ac_ct_CC=$CC
- # Extract the first word of "gcc", so it can be a program name with args.
-set dummy gcc; 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_ac_ct_CC+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # 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_ac_ct_CC="gcc"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
- echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
-echo "${ECHO_T}$ac_ct_CC" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- CC=$ac_ct_CC
-else
- CC="$ac_cv_prog_CC"
-fi
-
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}cc; 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_CC+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # 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_CC="${ac_tool_prefix}cc"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- echo "$as_me:$LINENO: result: $CC" >&5
-echo "${ECHO_T}$CC" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
-fi
-if test -z "$ac_cv_prog_CC"; then
- ac_ct_CC=$CC
- # Extract the first word of "cc", so it can be a program name with args.
-set dummy cc; 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_ac_ct_CC+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # 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_ac_ct_CC="cc"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
- echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
-echo "${ECHO_T}$ac_ct_CC" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- CC=$ac_ct_CC
-else
- CC="$ac_cv_prog_CC"
-fi
-
-fi
-if test -z "$CC"; then
- # Extract the first word of "cc", so it can be a program name with args.
-set dummy cc; 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_CC+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
- ac_prog_rejected=no
-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
- if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
- ac_prog_rejected=yes
- continue
- fi
- ac_cv_prog_CC="cc"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-if test $ac_prog_rejected = yes; then
- # We found a bogon in the path, so make sure we never use it.
- set dummy $ac_cv_prog_CC
- shift
- if test $# != 0; then
- # We chose a different compiler from the bogus one.
- # However, it has the same basename, so the bogon will be chosen
- # first if we set CC to just the basename; use the full file name.
- shift
- ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
- fi
-fi
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- echo "$as_me:$LINENO: result: $CC" >&5
-echo "${ECHO_T}$CC" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
-fi
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- for ac_prog in cl
- do
- # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
-set dummy $ac_tool_prefix$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_CC+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # 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_CC="$ac_tool_prefix$ac_prog"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- echo "$as_me:$LINENO: result: $CC" >&5
-echo "${ECHO_T}$CC" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- test -n "$CC" && break
- done
-fi
-if test -z "$CC"; then
- ac_ct_CC=$CC
- for ac_prog in cl
+ if test "${BUILD_CC+set}" != set; then
+ for ac_prog in gcc cc cl
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_ac_ct_CC+set}" = set; then
+if test "${ac_cv_prog_BUILD_CC+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+ if test -n "$BUILD_CC"; then
+ ac_cv_prog_BUILD_CC="$BUILD_CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
@@ -18808,7 +18231,7 @@ do
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_ac_ct_CC="$ac_prog"
+ ac_cv_prog_BUILD_CC="$ac_prog"
echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
@@ -18817,628 +18240,26 @@ done
fi
fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
- echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
-echo "${ECHO_T}$ac_ct_CC" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- test -n "$ac_ct_CC" && break
-done
-
- CC=$ac_ct_CC
-fi
-
-fi
-
-
-test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
-See \`config.log' for more details." >&5
-echo "$as_me: error: no acceptable C compiler found in \$PATH
-See \`config.log' for more details." >&2;}
- { (exit 1); exit 1; }; }
-
-# Provide some information about the compiler.
-echo "$as_me:$LINENO:" \
- "checking for C compiler version" >&5
-ac_compiler=`set X $ac_compile; echo $2`
-{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
- (eval $ac_compiler --version </dev/null >&5) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }
-{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
- (eval $ac_compiler -v </dev/null >&5) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }
-{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
- (eval $ac_compiler -V </dev/null >&5) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }
-
-echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
-echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
-if test "${ac_cv_c_compiler_gnu+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. */
-
-int
-main ()
-{
-#ifndef __GNUC__
- choke me
-#endif
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_c_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_compiler_gnu=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_compiler_gnu=no
-fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
-ac_cv_c_compiler_gnu=$ac_compiler_gnu
-
-fi
-echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
-echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
-GCC=`test $ac_compiler_gnu = yes && echo yes`
-ac_test_CFLAGS=${CFLAGS+set}
-ac_save_CFLAGS=$CFLAGS
-CFLAGS="-g"
-echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
-echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
-if test "${ac_cv_prog_cc_g+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. */
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_c_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_prog_cc_g=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_prog_cc_g=no
-fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
-echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
-if test "$ac_test_CFLAGS" = set; then
- CFLAGS=$ac_save_CFLAGS
-elif test $ac_cv_prog_cc_g = yes; then
- if test "$GCC" = yes; then
- CFLAGS="-g -O2"
- else
- CFLAGS="-g"
- fi
-else
- if test "$GCC" = yes; then
- CFLAGS="-O2"
- else
- CFLAGS=
- fi
-fi
-echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
-echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
-if test "${ac_cv_prog_cc_stdc+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_cv_prog_cc_stdc=no
-ac_save_CC=$CC
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-#include <stdarg.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
-struct buf { int x; };
-FILE * (*rcsopen) (struct buf *, struct stat *, int);
-static char *e (p, i)
- char **p;
- int i;
-{
- return p[i];
-}
-static char *f (char * (*g) (char **, int), char **p, ...)
-{
- char *s;
- va_list v;
- va_start (v,p);
- s = g (p, va_arg (v,int));
- va_end (v);
- return s;
-}
-
-/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
- function prototypes and stuff, but not '\xHH' hex character constants.
- These don't provoke an error unfortunately, instead are silently treated
- as 'x'. The following induces an error, until -std1 is added to get
- proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
- array size at least. It's necessary to write '\x00'==0 to get something
- that's true only with -std1. */
-int osf4_cc_array ['\x00' == 0 ? 1 : -1];
-
-int test (int i, double x);
-struct s1 {int (*f) (int a);};
-struct s2 {int (*f) (double a);};
-int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
-int argc;
-char **argv;
-int
-main ()
-{
-return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
- ;
- return 0;
-}
-_ACEOF
-# Don't try gcc -ansi; that turns off useful extensions and
-# breaks some systems' header files.
-# AIX -qlanglvl=ansi
-# Ultrix and OSF/1 -std1
-# HP-UX 10.20 and later -Ae
-# HP-UX older versions -Aa -D_HPUX_SOURCE
-# SVR4 -Xc -D__EXTENSIONS__
-for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
-do
- CC="$ac_save_CC $ac_arg"
- rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_c_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_prog_cc_stdc=$ac_arg
-break
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-fi
-rm -f conftest.err conftest.$ac_objext
-done
-rm -f conftest.$ac_ext conftest.$ac_objext
-CC=$ac_save_CC
-
-fi
-
-case "x$ac_cv_prog_cc_stdc" in
- x|xno)
- echo "$as_me:$LINENO: result: none needed" >&5
-echo "${ECHO_T}none needed" >&6 ;;
- *)
- echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
-echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
- CC="$CC $ac_cv_prog_cc_stdc" ;;
-esac
-
-# Some people use a C++ compiler to compile C. Since we use `exit',
-# in C++ we need to declare it. In case someone uses the same compiler
-# for both compiling C and C++ we need to have the C++ compiler decide
-# the declaration of exit, since it's the most demanding environment.
-cat >conftest.$ac_ext <<_ACEOF
-#ifndef __cplusplus
- choke me
-#endif
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_c_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- for ac_declaration in \
- '' \
- 'extern "C" void std::exit (int) throw (); using std::exit;' \
- 'extern "C" void std::exit (int); using std::exit;' \
- 'extern "C" void exit (int) throw ();' \
- 'extern "C" void exit (int);' \
- 'void exit (int);'
-do
- cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-$ac_declaration
-#include <stdlib.h>
-int
-main ()
-{
-exit (42);
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_c_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- :
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-continue
-fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
- cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-$ac_declaration
-int
-main ()
-{
-exit (42);
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_c_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- 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_ext
-done
-rm -f conftest*
-if test -n "$ac_declaration"; then
- echo '#ifdef __cplusplus' >>confdefs.h
- echo $ac_declaration >>confdefs.h
- echo '#endif' >>confdefs.h
-fi
-
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
- if test "$cross_compiling" = "yes"; then
- { { echo "$as_me:$LINENO: error: unable to find a compiler for building build tools" >&5
-echo "$as_me: error: unable to find a compiler for building build tools" >&2;}
- { (exit 1); exit 1; }; }
- fi
- BUILD_CC=$CC
- default_build_cflags=$CFLAGS
-else
- BUILD_CC=$config_BUILD_CC
- echo "$as_me:$LINENO: checking host compiler" >&5
-echo $ECHO_N "checking host compiler... $ECHO_C" >&6
- CC=$BUILD_CC
+BUILD_CC=$ac_cv_prog_BUILD_CC
+if test -n "$BUILD_CC"; then
echo "$as_me:$LINENO: result: $BUILD_CC" >&5
echo "${ECHO_T}$BUILD_CC" >&6
-fi
-echo "$as_me:$LINENO: checking switches for the host compiler" >&5
-echo $ECHO_N "checking switches for the host compiler... $ECHO_C" >&6
-if test "$config_BUILD_CFLAGS" != ""; then
- CFLAGS=$config_BUILD_CFLAGS
- BUILD_CFLAGS=$config_BUILD_CFLAGS
-else
- BUILD_CFLAGS=$default_build_cflags
-fi
-echo "$as_me:$LINENO: result: $BUILD_CFLAGS" >&5
-echo "${ECHO_T}$BUILD_CFLAGS" >&6
-if test "$config_BUILD_LIBS" != ""; then
- BUILD_LIBS=$config_BUILD_LIBS
-fi
-
-
-
-
-##########
-# Locate a compiler that converts C code into *.o files that run on
-# the target machine.
-#
-echo "$as_me:$LINENO: checking target compiler" >&5
-echo $ECHO_N "checking target compiler... $ECHO_C" >&6
-if test "$config_TARGET_CC" != ""; then
- TARGET_CC=$config_TARGET_CC
-else
- TARGET_CC=$BUILD_CC
-fi
-echo "$as_me:$LINENO: result: $TARGET_CC" >&5
-echo "${ECHO_T}$TARGET_CC" >&6
-echo "$as_me:$LINENO: checking switches on the target compiler" >&5
-echo $ECHO_N "checking switches on the target compiler... $ECHO_C" >&6
-if test "$config_TARGET_CFLAGS" != ""; then
- TARGET_CFLAGS=$config_TARGET_CFLAGS
-else
- TARGET_CFLAGS=$BUILD_CFLAGS
-fi
-echo "$as_me:$LINENO: result: $TARGET_CFLAGS" >&5
-echo "${ECHO_T}$TARGET_CFLAGS" >&6
-echo "$as_me:$LINENO: checking target linker" >&5
-echo $ECHO_N "checking target linker... $ECHO_C" >&6
-if test "$config_TARGET_LINK" = ""; then
- TARGET_LINK=$TARGET_CC
-else
- TARGET_LINK=$config_TARGET_LINK
-fi
-echo "$as_me:$LINENO: result: $TARGET_LINK" >&5
-echo "${ECHO_T}$TARGET_LINK" >&6
-echo "$as_me:$LINENO: checking switches on the target compiler" >&5
-echo $ECHO_N "checking switches on the target compiler... $ECHO_C" >&6
-if test "$config_TARGET_TFLAGS" != ""; then
- TARGET_TFLAGS=$config_TARGET_TFLAGS
-else
- TARGET_TFLAGS=$BUILD_CFLAGS
-fi
-if test "$config_TARGET_RANLIB" != ""; then
- TARGET_RANLIB=$config_TARGET_RANLIB
-else
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
-set dummy ${ac_tool_prefix}ranlib; 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_RANLIB+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$RANLIB"; then
- ac_cv_prog_RANLIB="$RANLIB" # 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_RANLIB="${ac_tool_prefix}ranlib"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-RANLIB=$ac_cv_prog_RANLIB
-if test -n "$RANLIB"; then
- echo "$as_me:$LINENO: result: $RANLIB" >&5
-echo "${ECHO_T}$RANLIB" >&6
else
echo "$as_me:$LINENO: result: no" >&5
echo "${ECHO_T}no" >&6
fi
-fi
-if test -z "$ac_cv_prog_RANLIB"; then
- ac_ct_RANLIB=$RANLIB
- # Extract the first word of "ranlib", so it can be a program name with args.
-set dummy ranlib; 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_ac_ct_RANLIB+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$ac_ct_RANLIB"; then
- ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # 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_ac_ct_RANLIB="ranlib"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
+ test -n "$BUILD_CC" && break
done
- test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
-fi
-fi
-ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
-if test -n "$ac_ct_RANLIB"; then
- echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
-echo "${ECHO_T}$ac_ct_RANLIB" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- RANLIB=$ac_ct_RANLIB
-else
- RANLIB="$ac_cv_prog_RANLIB"
-fi
-
- TARGET_RANLIB=$RANLIB
-fi
-if test "$config_TARGET_AR" != ""; then
- TARGET_AR=$config_TARGET_AR
-else
- TARGET_AR='ar cr'
+ fi
+ if test "${BUILD_CFLAGS+set}" != set; then
+ BUILD_CFLAGS="-g"
+ fi
fi
-echo "$as_me:$LINENO: result: $TARGET_TFLAGS" >&5
-echo "${ECHO_T}$TARGET_TFLAGS" >&6
-
-
-
-
-# Set the $cross variable if we are cross-compiling. Make
-# it 0 if we are not.
-#
-echo "$as_me:$LINENO: checking if host and target compilers are the same" >&5
-echo $ECHO_N "checking if host and target compilers are the same... $ECHO_C" >&6
-if test "$BUILD_CC" = "$TARGET_CC"; then
- cross=0
- echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6
-else
- cross=1
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
##########
# Do we want to support multithreaded use of sqlite
#
@@ -19447,22 +18268,22 @@ if test "${enable_threadsafe+set}" = set; then
enableval="$enable_threadsafe"
else
- enable_threadsafe=no
+ enable_threadsafe=yes
fi;
echo "$as_me:$LINENO: checking whether to support threadsafe operation" >&5
echo $ECHO_N "checking whether to support threadsafe operation... $ECHO_C" >&6
if test "$enable_threadsafe" = "no"; then
- THREADSAFE=0
+ SQLITE_THREADSAFE=0
echo "$as_me:$LINENO: result: no" >&5
echo "${ECHO_T}no" >&6
else
- THREADSAFE=1
+ SQLITE_THREADSAFE=1
echo "$as_me:$LINENO: result: yes" >&5
echo "${ECHO_T}yes" >&6
fi
-if test "$THREADSAFE" = "1"; then
+if test "$SQLITE_THREADSAFE" = "1"; then
LIBS=""
echo "$as_me:$LINENO: checking for pthread_create in -lpthread" >&5
@@ -19613,7 +18434,7 @@ if test "$enable_releasemode" = "no"; then
echo "$as_me:$LINENO: result: no" >&5
echo "${ECHO_T}no" >&6
else
- ALLOWRELEASE="-release `cat VERSION`"
+ ALLOWRELEASE="-release `cat $srcdir/VERSION`"
echo "$as_me:$LINENO: result: yes" >&5
echo "${ECHO_T}yes" >&6
fi
@@ -19689,7 +18510,7 @@ if test "$CYGWIN" = "yes"; then
else
BUILD_EXEEXT=$EXEEXT
fi
-if test "$cross" = "0"; then
+if test x"$cross_compiling" = xno; then
TARGET_EXEEXT=$BUILD_EXEEXT
else
TARGET_EXEEXT=$config_TARGET_EXEEXT
@@ -19724,14 +18545,6 @@ fi
-##########
-# Extract generic linker options from the environment.
-#
-if test "$config_TARGET_LIBS" != ""; then
- TARGET_LIBS=$config_TARGET_LIBS
-else
- TARGET_LIBS=""
-fi
##########
# Figure out all the parameters needed to compile against Tcl.
@@ -19904,12 +18717,32 @@ fi
# Figure out what C libraries are required to compile programs
# that use "readline()" library.
#
-if test "$config_TARGET_READLINE_LIBS" != ""; then
- TARGET_READLINE_LIBS="$config_TARGET_READLINE_LIBS"
+TARGET_READLINE_LIBS=""
+TARGET_READLINE_INC=""
+TARGET_HAVE_READLINE=0
+# Check whether --enable-readline or --disable-readline was given.
+if test "${enable_readline+set}" = set; then
+ enableval="$enable_readline"
+ with_readline=$enableval
+else
+ with_readline=auto
+fi;
+
+if test x"$with_readline" != xno; then
+ found="yes"
+
+
+# Check whether --with-readline-lib or --without-readline-lib was given.
+if test "${with_readline_lib+set}" = set; then
+ withval="$with_readline_lib"
+ with_readline_lib=$withval
else
- CC=$TARGET_CC
- LIBS=""
- echo "$as_me:$LINENO: checking for library containing tgetent" >&5
+ with_readline_lib="auto"
+fi;
+ if test "x$with_readline_lib" = xauto; then
+ save_LIBS="$LIBS"
+ LIBS=""
+ echo "$as_me:$LINENO: checking for library containing tgetent" >&5
echo $ECHO_N "checking for library containing tgetent... $ECHO_C" >&6
if test "${ac_cv_search_tgetent+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
@@ -20032,11 +18865,12 @@ echo "$as_me:$LINENO: result: $ac_cv_search_tgetent" >&5
echo "${ECHO_T}$ac_cv_search_tgetent" >&6
if test "$ac_cv_search_tgetent" != no; then
test "$ac_cv_search_tgetent" = "none required" || LIBS="$ac_cv_search_tgetent $LIBS"
-
+ term_LIBS="$LIBS"
+else
+ term_LIBS=""
fi
-
-echo "$as_me:$LINENO: checking for readline in -lreadline" >&5
+ echo "$as_me:$LINENO: checking for readline in -lreadline" >&5
echo $ECHO_N "checking for readline in -lreadline... $ECHO_C" >&6
if test "${ac_cv_lib_readline_readline+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
@@ -20101,169 +18935,27 @@ fi
echo "$as_me:$LINENO: result: $ac_cv_lib_readline_readline" >&5
echo "${ECHO_T}$ac_cv_lib_readline_readline" >&6
if test $ac_cv_lib_readline_readline = yes; then
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBREADLINE 1
-_ACEOF
-
- LIBS="-lreadline $LIBS"
-
-fi
-
- TARGET_READLINE_LIBS="$LIBS"
-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"
+ TARGET_READLINE_LIBS="-lreadline"
else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
+ found="no"
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_READLINE_LIBS="$TARGET_READLINE_LIBS $term_LIBS"
+ LIBS="$save_LIBS"
+ else
+ TARGET_READLINE_LIBS="$with_readline_lib"
+ fi
-TARGET_LIBS="$LIBS"
-##########
-# Figure out where to get the READLINE header files.
-#
-echo "$as_me:$LINENO: checking readline header files" >&5
-echo $ECHO_N "checking readline header files... $ECHO_C" >&6
-found=no
-if test "$config_TARGET_READLINE_INC" != ""; then
- TARGET_READLINE_INC=$config_TARGET_READLINE_INC
- found=yes
-fi
-if test "$found" = "yes"; then
- echo "$as_me:$LINENO: result: $TARGET_READLINE_INC" >&5
-echo "${ECHO_T}$TARGET_READLINE_INC" >&6
+# Check whether --with-readline-inc or --without-readline-inc was given.
+if test "${with_readline_inc+set}" = set; then
+ withval="$with_readline_inc"
+ with_readline_inc=$withval
else
- echo "$as_me:$LINENO: result: not specified: still searching..." >&5
-echo "${ECHO_T}not specified: still searching..." >&6
- if test "${ac_cv_header_readline_h+set}" = set; then
+ with_readline_inc="auto"
+fi;
+ if test "x$with_readline_inc" = xauto; then
+ if test "${ac_cv_header_readline_h+set}" = set; then
echo "$as_me:$LINENO: checking for readline.h" >&5
echo $ECHO_N "checking for readline.h... $ECHO_C" >&6
if test "${ac_cv_header_readline_h+set}" = set; then
@@ -20401,16 +19093,16 @@ echo "${ECHO_T}$ac_cv_header_readline_h" >&6
fi
if test $ac_cv_header_readline_h = yes; then
- found=yes
-fi
-
+ found="yes"
+else
-fi
-if test "$found" = "no"; then
- for dir in /usr /usr/local /usr/local/readline /usr/contrib /mingw; do
- as_ac_File=`echo "ac_cv_file_$dir/include/readline.h" | $as_tr_sh`
-echo "$as_me:$LINENO: checking for $dir/include/readline.h" >&5
-echo $ECHO_N "checking for $dir/include/readline.h... $ECHO_C" >&6
+ found="no"
+ if test "$cross_compiling" != yes; then
+ for dir in /usr /usr/local /usr/local/readline /usr/contrib /mingw; do
+ for subdir in include include/readline; do
+ as_ac_File=`echo "ac_cv_file_$dir/$subdir/readline.h" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $dir/$subdir/readline.h" >&5
+echo $ECHO_N "checking for $dir/$subdir/readline.h... $ECHO_C" >&6
if eval "test \"\${$as_ac_File+set}\" = set"; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
@@ -20418,7 +19110,7 @@ else
{ { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
{ (exit 1); exit 1; }; }
-if test -r "$dir/include/readline.h"; then
+if test -r "$dir/$subdir/readline.h"; then
eval "$as_ac_File=yes"
else
eval "$as_ac_File=no"
@@ -20430,48 +19122,164 @@ if test `eval echo '${'$as_ac_File'}'` = yes; then
found=yes
fi
- if test "$found" = "yes"; then
- TARGET_READLINE_INC="-I$dir/include"
- break
- fi
- as_ac_File=`echo "ac_cv_file_$dir/include/readline/readline.h" | $as_tr_sh`
-echo "$as_me:$LINENO: checking for $dir/include/readline/readline.h" >&5
-echo $ECHO_N "checking for $dir/include/readline/readline.h... $ECHO_C" >&6
-if eval "test \"\${$as_ac_File+set}\" = set"; then
+ if test "$found" = "yes"; then
+ TARGET_READLINE_INC="-I$dir/$subdir"
+ break
+ fi
+ done
+ test "$found" = "yes" && break
+ done
+ fi
+
+fi
+
+
+ else
+ TARGET_READLINE_INC="$with_readline_inc"
+ fi
+
+ if test x"$found" = xno; then
+ TARGET_READLINE_LIBS=""
+ TARGET_READLINE_INC=""
+ TARGET_HAVE_READLINE=0
+ else
+ TARGET_HAVE_READLINE=1
+ fi
+fi
+
+
+
+
+
+##########
+# Figure out what C libraries are required to compile programs
+# that use "fdatasync()" function.
+#
+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
- test "$cross_compiling" = yes &&
- { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
-echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
- { (exit 1); exit 1; }; }
-if test -r "$dir/include/readline/readline.h"; then
- eval "$as_ac_File=yes"
+ 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
- eval "$as_ac_File=no"
-fi
-fi
-echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_File'}'`" >&5
-echo "${ECHO_T}`eval echo '${'$as_ac_File'}'`" >&6
-if test `eval echo '${'$as_ac_File'}'` = yes; then
- found=yes
+ 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. */
- if test "$found" = "yes"; then
- TARGET_READLINE_INC="-I$dir/include/readline"
- break
- fi
+/* 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
-if test "$found" = "yes"; then
- if test "$TARGET_READLINE_LIBS" = ""; then
- TARGET_HAVE_READLINE=0
- else
- TARGET_HAVE_READLINE=1
- fi
-else
- TARGET_HAVE_READLINE=0
+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
#########
@@ -20688,11 +19496,6 @@ fi
#########
-# Put out accumulated miscellaneous LIBRARIES
-#
-
-
-#########
# Generate the output files.
#
ac_config_files="$ac_config_files Makefile sqlite3.pc"
@@ -21375,14 +20178,7 @@ s,@RELEASE@,$RELEASE,;t t
s,@VERSION_NUMBER@,$VERSION_NUMBER,;t t
s,@BUILD_CC@,$BUILD_CC,;t t
s,@BUILD_CFLAGS@,$BUILD_CFLAGS,;t t
-s,@BUILD_LIBS@,$BUILD_LIBS,;t t
-s,@TARGET_CC@,$TARGET_CC,;t t
-s,@TARGET_CFLAGS@,$TARGET_CFLAGS,;t t
-s,@TARGET_LINK@,$TARGET_LINK,;t t
-s,@TARGET_LFLAGS@,$TARGET_LFLAGS,;t t
-s,@TARGET_RANLIB@,$TARGET_RANLIB,;t t
-s,@TARGET_AR@,$TARGET_AR,;t t
-s,@THREADSAFE@,$THREADSAFE,;t t
+s,@SQLITE_THREADSAFE@,$SQLITE_THREADSAFE,;t t
s,@TARGET_THREAD_LIB@,$TARGET_THREAD_LIB,;t t
s,@XTHREADCONNECT@,$XTHREADCONNECT,;t t
s,@THREADSOVERRIDELOCKS@,$THREADSOVERRIDELOCKS,;t t
@@ -21409,7 +20205,6 @@ 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 cfec34ab36..e9cec2fa60 100644
--- a/ext/pdo_sqlite/sqlite/configure.ac
+++ b/ext/pdo_sqlite/sqlite/configure.ac
@@ -45,18 +45,6 @@
# The filename extension for executables on the build
# platform. "" for Unix and ".exe" for Windows.
#
-# TARGET_CC
-#
-# The name of a command that runs on the build platform
-# and converts C source files into *.o files for the
-# target platform. In other words, the cross-compiler.
-#
-# TARGET_CFLAGS
-#
-# Switches that the target compiler needs to turn C source files
-# into *.o files. Do not include TARGET_TCL_INC in this list.
-# Makefiles might add additional switches such as "-I.".
-#
# TCL_*
#
# Lots of values are read in from the tclConfig.sh script,
@@ -76,18 +64,6 @@
# files for the readline library. If the compiler is able
# to find <readline.h> on its own, then this can be blank.
#
-# TARGET_LINK
-#
-# The name of the linker that combines *.o files generated
-# by TARGET_CC into executables for the target platform.
-#
-# TARGET_LIBS
-#
-# Additional libraries or other switch that the target linker needs
-# to build an executable on the target. Do not include
-# on this list any libraries in TARGET_TCL_LIBS and
-# TARGET_READLINE_LIBS, etc.
-#
# TARGET_EXEEXT
#
# The filename extension for executables on the
@@ -184,113 +160,36 @@ fi
# Locate a compiler for the build machine. This compiler should
# generate command-line programs that run on the build machine.
#
-default_build_cflags="-g"
-if test "$config_BUILD_CC" = ""; then
- AC_PROG_CC
- if test "$cross_compiling" = "yes"; then
- AC_MSG_ERROR([unable to find a compiler for building build tools])
- fi
- BUILD_CC=$CC
- default_build_cflags=$CFLAGS
-else
- BUILD_CC=$config_BUILD_CC
- AC_MSG_CHECKING([host compiler])
- CC=$BUILD_CC
- AC_MSG_RESULT($BUILD_CC)
-fi
-AC_MSG_CHECKING([switches for the host compiler])
-if test "$config_BUILD_CFLAGS" != ""; then
- CFLAGS=$config_BUILD_CFLAGS
- BUILD_CFLAGS=$config_BUILD_CFLAGS
+if test x"$cross_compiling" = xno; then
+ BUILD_CC=$CC
+ BUILD_CFLAGS=$CFLAGS
else
- BUILD_CFLAGS=$default_build_cflags
-fi
-AC_MSG_RESULT($BUILD_CFLAGS)
-if test "$config_BUILD_LIBS" != ""; then
- BUILD_LIBS=$config_BUILD_LIBS
+ if test "${BUILD_CC+set}" != set; then
+ AC_CHECK_PROGS(BUILD_CC, gcc cc cl)
+ fi
+ if test "${BUILD_CFLAGS+set}" != set; then
+ BUILD_CFLAGS="-g"
+ fi
fi
AC_SUBST(BUILD_CC)
AC_SUBST(BUILD_CFLAGS)
-AC_SUBST(BUILD_LIBS)
-
-##########
-# Locate a compiler that converts C code into *.o files that run on
-# the target machine.
-#
-AC_MSG_CHECKING([target compiler])
-if test "$config_TARGET_CC" != ""; then
- TARGET_CC=$config_TARGET_CC
-else
- TARGET_CC=$BUILD_CC
-fi
-AC_MSG_RESULT($TARGET_CC)
-AC_MSG_CHECKING([switches on the target compiler])
-if test "$config_TARGET_CFLAGS" != ""; then
- TARGET_CFLAGS=$config_TARGET_CFLAGS
-else
- TARGET_CFLAGS=$BUILD_CFLAGS
-fi
-AC_MSG_RESULT($TARGET_CFLAGS)
-AC_MSG_CHECKING([target linker])
-if test "$config_TARGET_LINK" = ""; then
- TARGET_LINK=$TARGET_CC
-else
- TARGET_LINK=$config_TARGET_LINK
-fi
-AC_MSG_RESULT($TARGET_LINK)
-AC_MSG_CHECKING([switches on the target compiler])
-if test "$config_TARGET_TFLAGS" != ""; then
- TARGET_TFLAGS=$config_TARGET_TFLAGS
-else
- TARGET_TFLAGS=$BUILD_CFLAGS
-fi
-if test "$config_TARGET_RANLIB" != ""; then
- TARGET_RANLIB=$config_TARGET_RANLIB
-else
- AC_PROG_RANLIB
- TARGET_RANLIB=$RANLIB
-fi
-if test "$config_TARGET_AR" != ""; then
- TARGET_AR=$config_TARGET_AR
-else
- TARGET_AR='ar cr'
-fi
-AC_MSG_RESULT($TARGET_TFLAGS)
-AC_SUBST(TARGET_CC)
-AC_SUBST(TARGET_CFLAGS)
-AC_SUBST(TARGET_LINK)
-AC_SUBST(TARGET_LFLAGS)
-AC_SUBST(TARGET_RANLIB)
-AC_SUBST(TARGET_AR)
-
-# Set the $cross variable if we are cross-compiling. Make
-# it 0 if we are not.
-#
-AC_MSG_CHECKING([if host and target compilers are the same])
-if test "$BUILD_CC" = "$TARGET_CC"; then
- cross=0
- AC_MSG_RESULT(yes)
-else
- cross=1
- AC_MSG_RESULT(no)
-fi
##########
# Do we want to support multithreaded use of sqlite
#
AC_ARG_ENABLE(threadsafe,
-AC_HELP_STRING([--enable-threadsafe],[Support threadsafe operation]),,enable_threadsafe=no)
+AC_HELP_STRING([--enable-threadsafe],[Support threadsafe operation]),,enable_threadsafe=yes)
AC_MSG_CHECKING([whether to support threadsafe operation])
if test "$enable_threadsafe" = "no"; then
- THREADSAFE=0
+ SQLITE_THREADSAFE=0
AC_MSG_RESULT([no])
else
- THREADSAFE=1
+ SQLITE_THREADSAFE=1
AC_MSG_RESULT([yes])
fi
-AC_SUBST(THREADSAFE)
+AC_SUBST(SQLITE_THREADSAFE)
-if test "$THREADSAFE" = "1"; then
+if test "$SQLITE_THREADSAFE" = "1"; then
LIBS=""
AC_CHECK_LIB(pthread, pthread_create)
TARGET_THREAD_LIB="$LIBS"
@@ -345,7 +244,7 @@ if test "$enable_releasemode" = "no"; then
ALLOWRELEASE=""
AC_MSG_RESULT([no])
else
- ALLOWRELEASE="-release `cat VERSION`"
+ ALLOWRELEASE="-release `cat $srcdir/VERSION`"
AC_MSG_RESULT([yes])
fi
AC_SUBST(ALLOWRELEASE)
@@ -401,7 +300,7 @@ if test "$CYGWIN" = "yes"; then
else
BUILD_EXEEXT=$EXEEXT
fi
-if test "$cross" = "0"; then
+if test x"$cross_compiling" = xno; then
TARGET_EXEEXT=$BUILD_EXEEXT
else
TARGET_EXEEXT=$config_TARGET_EXEEXT
@@ -438,15 +337,6 @@ AC_SUBST(OS_OS2)
AC_SUBST(TARGET_EXEEXT)
##########
-# Extract generic linker options from the environment.
-#
-if test "$config_TARGET_LIBS" != ""; then
- TARGET_LIBS=$config_TARGET_LIBS
-else
- TARGET_LIBS=""
-fi
-
-##########
# Figure out all the parameters needed to compile against Tcl.
#
# This code is derived from the SC_PATH_TCLCONFIG and SC_LOAD_TCLCONFIG
@@ -592,66 +482,74 @@ AC_SUBST(HAVE_TCL)
# Figure out what C libraries are required to compile programs
# that use "readline()" library.
#
-if test "$config_TARGET_READLINE_LIBS" != ""; then
- TARGET_READLINE_LIBS="$config_TARGET_READLINE_LIBS"
-else
- CC=$TARGET_CC
- LIBS=""
- AC_SEARCH_LIBS(tgetent, [readline ncurses curses termcap])
- AC_CHECK_LIB([readline], [readline])
- TARGET_READLINE_LIBS="$LIBS"
+TARGET_READLINE_LIBS=""
+TARGET_READLINE_INC=""
+TARGET_HAVE_READLINE=0
+AC_ARG_ENABLE([readline],
+ [AC_HELP_STRING([--disable-readline],[disable readline support [default=detect]])],
+ [with_readline=$enableval],
+ [with_readline=auto])
+
+if test x"$with_readline" != xno; then
+ found="yes"
+
+ AC_ARG_WITH([readline-lib],
+ [AC_HELP_STRING([--with-readline-lib],[specify readline library])],
+ [with_readline_lib=$withval],
+ [with_readline_lib="auto"])
+ if test "x$with_readline_lib" = xauto; then
+ save_LIBS="$LIBS"
+ LIBS=""
+ AC_SEARCH_LIBS(tgetent, [readline ncurses curses termcap], [term_LIBS="$LIBS"], [term_LIBS=""])
+ AC_CHECK_LIB([readline], [readline], [TARGET_READLINE_LIBS="-lreadline"], [found="no"])
+ TARGET_READLINE_LIBS="$TARGET_READLINE_LIBS $term_LIBS"
+ LIBS="$save_LIBS"
+ else
+ TARGET_READLINE_LIBS="$with_readline_lib"
+ fi
+
+ AC_ARG_WITH([readline-inc],
+ [AC_HELP_STRING([--with-readline-inc],[specify readline include paths])],
+ [with_readline_inc=$withval],
+ [with_readline_inc="auto"])
+ if test "x$with_readline_inc" = xauto; then
+ AC_CHECK_HEADER(readline.h, [found="yes"], [
+ found="no"
+ if test "$cross_compiling" != yes; then
+ for dir in /usr /usr/local /usr/local/readline /usr/contrib /mingw; do
+ for subdir in include include/readline; do
+ AC_CHECK_FILE($dir/$subdir/readline.h, found=yes)
+ if test "$found" = "yes"; then
+ TARGET_READLINE_INC="-I$dir/$subdir"
+ break
+ fi
+ done
+ test "$found" = "yes" && break
+ done
+ fi
+ ])
+ else
+ TARGET_READLINE_INC="$with_readline_inc"
+ fi
+
+ if test x"$found" = xno; then
+ TARGET_READLINE_LIBS=""
+ TARGET_READLINE_INC=""
+ TARGET_HAVE_READLINE=0
+ else
+ TARGET_HAVE_READLINE=1
+ fi
fi
+
AC_SUBST(TARGET_READLINE_LIBS)
+AC_SUBST(TARGET_READLINE_INC)
+AC_SUBST(TARGET_HAVE_READLINE)
##########
# 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])
-found=no
-if test "$config_TARGET_READLINE_INC" != ""; then
- TARGET_READLINE_INC=$config_TARGET_READLINE_INC
- found=yes
-fi
-if test "$found" = "yes"; then
- AC_MSG_RESULT($TARGET_READLINE_INC)
-else
- AC_MSG_RESULT(not specified: still searching...)
- AC_CHECK_HEADER(readline.h, [found=yes])
-fi
-if test "$found" = "no"; then
- for dir in /usr /usr/local /usr/local/readline /usr/contrib /mingw; do
- AC_CHECK_FILE($dir/include/readline.h, found=yes)
- if test "$found" = "yes"; then
- TARGET_READLINE_INC="-I$dir/include"
- break
- fi
- AC_CHECK_FILE($dir/include/readline/readline.h, found=yes)
- if test "$found" = "yes"; then
- TARGET_READLINE_INC="-I$dir/include/readline"
- break
- fi
- done
-fi
-if test "$found" = "yes"; then
- if test "$TARGET_READLINE_LIBS" = ""; then
- TARGET_HAVE_READLINE=0
- else
- TARGET_HAVE_READLINE=1
- fi
-else
- TARGET_HAVE_READLINE=0
-fi
-AC_SUBST(TARGET_READLINE_INC)
-AC_SUBST(TARGET_HAVE_READLINE)
#########
# check for debug enabled
@@ -676,11 +574,6 @@ AC_CHECK_FUNC(usleep, [TARGET_CFLAGS="$TARGET_CFLAGS -DHAVE_USLEEP=1"])
AC_CHECK_FUNC(fdatasync, [TARGET_CFLAGS="$TARGET_CFLAGS -DHAVE_FDATASYNC=1"])
#########
-# Put out accumulated miscellaneous LIBRARIES
-#
-AC_SUBST(TARGET_LIBS)
-
-#########
# Generate the output files.
#
AC_OUTPUT([
diff --git a/ext/pdo_sqlite/sqlite/ltmain.sh b/ext/pdo_sqlite/sqlite/ltmain.sh
index 4b9f940539..8f7a6ac10d 100644
--- a/ext/pdo_sqlite/sqlite/ltmain.sh
+++ b/ext/pdo_sqlite/sqlite/ltmain.sh
@@ -1,7 +1,7 @@
# ltmain.sh - Provide generalized library-building support services.
# NOTE: Changing this file will not affect anything until you rerun configure.
#
-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005
# Free Software Foundation, Inc.
# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
#
@@ -17,13 +17,51 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
+basename="s,^.*/,,g"
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+# define SED for historic ltconfig's generated by Libtool 1.3
+test -z "$SED" && SED=sed
+
+# The name of this program:
+progname=`echo "$progpath" | $SED $basename`
+modename="$progname"
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+
+PROGRAM=ltmain.sh
+PACKAGE=libtool
+VERSION=1.5.22
+TIMESTAMP=" (1.1220.2.365 2005/12/18 22:14:06)"
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes.
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+# Same for EGREP, and just to be sure, do LTCC as well
+if test "X$EGREP" = X ; then
+ EGREP=egrep
+fi
+if test "X$LTCC" = X ; then
+ LTCC=${CC-gcc}
+fi
+
# Check that we have a working $echo.
if test "X$1" = X--no-reexec; then
# Discard the --no-reexec flag, and continue.
@@ -36,7 +74,7 @@ elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
:
else
# Restart under the correct shell, and then maybe $echo will work.
- exec $SHELL "$0" --no-reexec ${1+"$@"}
+ exec $SHELL "$progpath" --no-reexec ${1+"$@"}
fi
if test "X$1" = X--fallback-echo; then
@@ -45,19 +83,9 @@ if test "X$1" = X--fallback-echo; then
cat <<EOF
$*
EOF
- exit 0
+ exit $EXIT_SUCCESS
fi
-# The name of this program.
-progname=`$echo "$0" | ${SED} 's%^.*/%%'`
-modename="$progname"
-
-# Constants.
-PROGRAM=ltmain.sh
-PACKAGE=libtool
-VERSION=1.5.2
-TIMESTAMP=" (1.1220.2.60 2004/01/25 12:25:08) Debian$Rev: 192 $"
-
default_mode=
help="Try \`$progname --help' for more information."
magic="%%%MAGIC variable%%%"
@@ -70,14 +98,15 @@ rm="rm -f"
Xsed="${SED}"' -e 1s/^X//'
sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
# test EBCDIC or ASCII
-case `echo A|tr A '\301'` in
- A) # EBCDIC based system
- SP2NL="tr '\100' '\n'"
- NL2SP="tr '\r\n' '\100\100'"
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ SP2NL='tr \040 \012'
+ NL2SP='tr \015\012 \040\040'
;;
- *) # Assume ASCII based system
- SP2NL="tr '\040' '\012'"
- NL2SP="tr '\015\012' '\040\040'"
+ *) # EBCDIC based system
+ SP2NL='tr \100 \n'
+ NL2SP='tr \r\n \100\100'
;;
esac
@@ -94,13 +123,14 @@ if test "${LANG+set}" = set; then
fi
# Make sure IFS has a sensible default
-: ${IFS="
-"}
+lt_nl='
+'
+IFS=" $lt_nl"
if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
$echo "$modename: not configured to build any kind of library" 1>&2
$echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
# Global variables.
@@ -112,17 +142,84 @@ run=
show="$echo"
show_help=
execute_dlfiles=
+duplicate_deps=no
+preserve_args=
lo2o="s/\\.lo\$/.${objext}/"
o2lo="s/\\.${objext}\$/.lo/"
+if test -z "$max_cmd_len"; then
+ i=0
+ testring="ABCD"
+ new_result=
+
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while (test "X"`$SHELL $0 --fallback-echo "X$testring" 2>/dev/null` \
+ = "XX$testring") >/dev/null 2>&1 &&
+ new_result=`expr "X$testring" : ".*" 2>&1` &&
+ max_cmd_len="$new_result" &&
+ test "$i" != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ testring="$testring$testring"
+ done
+ testring=
+ # Add a significant safety factor because C++ compilers can tack on massive
+ # amounts of additional arguments before passing them to the linker.
+ # It appears as though 1/2 is a usable value.
+ max_cmd_len=`expr $max_cmd_len \/ 2`
+fi
+
#####################################
# Shell function definitions:
# This seems to be the best place for them
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible. If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+ my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+ if test "$run" = ":"; then
+ # Return a directory name, but don't create it in dry-run mode
+ my_tmpdir="${my_template}-$$"
+ else
+
+ # If mktemp works, use that first and foremost
+ my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+ if test ! -d "$my_tmpdir"; then
+ # Failing that, at least try and use $RANDOM to avoid a race
+ my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+ save_mktempdir_umask=`umask`
+ umask 0077
+ $mkdir "$my_tmpdir"
+ umask $save_mktempdir_umask
+ fi
+
+ # If we're not in dry-run mode, bomb out on failure
+ test -d "$my_tmpdir" || {
+ $echo "cannot create temporary directory \`$my_tmpdir'" 1>&2
+ exit $EXIT_FAILURE
+ }
+ fi
+
+ $echo "X$my_tmpdir" | $Xsed
+}
+
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
# Need a lot of goo to handle *both* DLLs and import libs
# Has to be a shell function in order to 'eat' the argument
# that is supplied when $file_magic_command is called.
-win32_libid () {
+func_win32_libid ()
+{
win32_libid_type="unknown"
win32_fileres=`file -L $1 2>/dev/null`
case $win32_fileres in
@@ -131,17 +228,16 @@ win32_libid () {
;;
*ar\ archive*) # could be an import, or static
if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \
- grep -E 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then
+ $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then
win32_nmres=`eval $NM -f posix -A $1 | \
- sed -n -e '1,100{/ I /{x;/import/!{s/^/import/;h;p;};x;};}'`
- if test "X$win32_nmres" = "Ximport" ; then
- win32_libid_type="x86 archive import"
- else
- win32_libid_type="x86 archive static"
- fi
+ $SED -n -e '1,100{/ I /{s,.*,import,;p;q;};}'`
+ case $win32_nmres in
+ import*) win32_libid_type="x86 archive import";;
+ *) win32_libid_type="x86 archive static";;
+ esac
fi
;;
- *DLL*)
+ *DLL*)
win32_libid_type="x86 DLL"
;;
*executable*) # but shell scripts are "executable" too...
@@ -155,9 +251,195 @@ win32_libid () {
$echo $win32_libid_type
}
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+ if test -n "$available_tags" && test -z "$tagname"; then
+ CC_quoted=
+ for arg in $CC; do
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ CC_quoted="$CC_quoted $arg"
+ done
+ case $@ in
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when configure was run.
+ " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;;
+ # Blanks at the start of $base_compile will cause this to fail
+ # if we don't check for them as well.
+ *)
+ for z in $available_tags; do
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+ CC_quoted=
+ for arg in $CC; do
+ # Double-quote args containing other shell metacharacters.
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ CC_quoted="$CC_quoted $arg"
+ done
+ # user sometimes does CC=<HOST>-gcc so we need to match that to 'gcc'
+ trimedcc=`echo ${CC} | $SED -e "s/${host}-//g"`
+ # and sometimes libtool has CC=<HOST>-gcc but user does CC=gcc
+ extendcc=${host}-${CC}
+ # and sometimes libtool has CC=<OLDHOST>-gcc but user has CC=<NEWHOST>-gcc
+ # (Gentoo-specific hack because we always export $CHOST)
+ mungedcc=${CHOST-${host}}-${trimedcc}
+ case "$@ " in
+ "cc "* | " cc "* | "${host}-cc "* | " ${host}-cc "*|\
+ "gcc "* | " gcc "* | "${host}-gcc "* | " ${host}-gcc "*)
+ tagname=CC
+ break ;;
+ "$trimedcc "* | " $trimedcc "* | "`$echo $trimedcc` "* | " `$echo $trimedcc` "*|\
+ "$extendcc "* | " $extendcc "* | "`$echo $extendcc` "* | " `$echo $extendcc` "*|\
+ "$mungedcc "* | " $mungedcc "* | "`$echo $mungedcc` "* | " `$echo $mungedcc` "*|\
+ " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*)
+ # The compiler in the base compile command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ $echo "$modename: unable to infer tagged configuration"
+ $echo "$modename: specify a tag with \`--tag'" 1>&2
+ exit $EXIT_FAILURE
+# else
+# $echo "$modename: using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+ f_ex_an_ar_dir="$1"; shift
+ f_ex_an_ar_oldlib="$1"
+
+ $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)"
+ $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $?
+ if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "$modename: ERROR: object name conflicts: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" 1>&2
+ exit $EXIT_FAILURE
+ fi
+}
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+ my_gentop="$1"; shift
+ my_oldlibs=${1+"$@"}
+ my_oldobjs=""
+ my_xlib=""
+ my_xabs=""
+ my_xdir=""
+ my_status=""
+
+ $show "${rm}r $my_gentop"
+ $run ${rm}r "$my_gentop"
+ $show "$mkdir $my_gentop"
+ $run $mkdir "$my_gentop"
+ my_status=$?
+ if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then
+ exit $my_status
+ fi
+
+ for my_xlib in $my_oldlibs; do
+ # Extract the objects.
+ case $my_xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+ *) my_xabs=`pwd`"/$my_xlib" ;;
+ esac
+ my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'`
+ my_xdir="$my_gentop/$my_xlib"
+
+ $show "${rm}r $my_xdir"
+ $run ${rm}r "$my_xdir"
+ $show "$mkdir $my_xdir"
+ $run $mkdir "$my_xdir"
+ exit_status=$?
+ if test "$exit_status" -ne 0 && test ! -d "$my_xdir"; then
+ exit $exit_status
+ fi
+ case $host in
+ *-darwin*)
+ $show "Extracting $my_xabs"
+ # Do not bother doing anything if just a dry run
+ if test -z "$run"; then
+ darwin_orig_dir=`pwd`
+ cd $my_xdir || exit $?
+ darwin_archive=$my_xabs
+ darwin_curdir=`pwd`
+ darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'`
+ darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null`
+ if test -n "$darwin_arches"; then
+ darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'`
+ darwin_arch=
+ $show "$darwin_base_archive has multiple architectures $darwin_arches"
+ for darwin_arch in $darwin_arches ; do
+ mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+ lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+ cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+ func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+ cd "$darwin_curdir"
+ $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+ done # $darwin_arches
+ ## Okay now we have a bunch of thin objects, gotta fatten them up :)
+ darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP`
+ darwin_file=
+ darwin_files=
+ for darwin_file in $darwin_filelist; do
+ darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP`
+ lipo -create -output "$darwin_file" $darwin_files
+ done # $darwin_filelist
+ ${rm}r unfat-$$
+ cd "$darwin_orig_dir"
+ else
+ cd "$darwin_orig_dir"
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ fi # $darwin_arches
+ fi # $run
+ ;;
+ *)
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ ;;
+ esac
+ my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+ done
+ func_extract_archives_result="$my_oldobjs"
+}
# End of Shell function definitions
#####################################
+# Darwin sucks
+eval std_shrext=\"$shrext_cmds\"
+
+disable_libs=no
+
# Parse our command line options once, thoroughly.
while test "$#" -gt 0
do
@@ -183,7 +465,7 @@ do
case $tagname in
*[!-_A-Za-z0-9,/]*)
$echo "$progname: invalid tag name: $tagname" 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
esac
@@ -193,10 +475,10 @@ do
# not specially marked.
;;
*)
- if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$0" > /dev/null; then
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then
taglist="$taglist $tagname"
# Evaluate the configuration.
- eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $0`"
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`"
else
$echo "$progname: ignoring unknown tag $tagname" 1>&2
fi
@@ -222,19 +504,19 @@ do
--version)
$echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"
$echo
- $echo "Copyright (C) 2003 Free Software Foundation, Inc."
+ $echo "Copyright (C) 2005 Free Software Foundation, Inc."
$echo "This is free software; see the source for copying conditions. There is NO"
$echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
- exit 0
+ exit $?
;;
--config)
- ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $0
+ ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath
# Now print the configurations for the tags.
for tagname in $taglist; do
- ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$0"
+ ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath"
done
- exit 0
+ exit $?
;;
--debug)
@@ -259,7 +541,7 @@ do
else
$echo "disable static libraries"
fi
- exit 0
+ exit $?
;;
--finish) mode="finish" ;;
@@ -274,7 +556,11 @@ do
preserve_args="$preserve_args $arg"
;;
- --tag) prevopt="--tag" prev=tag ;;
+ --tag)
+ prevopt="--tag"
+ prev=tag
+ preserve_args="$preserve_args --tag"
+ ;;
--tag=*)
set tag "$optarg" ${1+"$@"}
shift
@@ -290,7 +576,7 @@ do
-*)
$echo "$modename: unrecognized option \`$arg'" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
*)
@@ -303,9 +589,21 @@ done
if test -n "$prevopt"; then
$echo "$modename: option \`$prevopt' requires an argument" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
+case $disable_libs in
+no)
+ ;;
+shared)
+ build_libtool_libs=no
+ build_old_libs=yes
+ ;;
+static)
+ build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+ ;;
+esac
+
# If this variable is set in any of the actions, the command in it
# will be execed at the end. This prevents here-documents from being
# left over by shells.
@@ -316,7 +614,7 @@ if test -z "$show_help"; then
# Infer the operation mode.
if test -z "$mode"; then
$echo "*** Warning: inferring the mode of operation is deprecated." 1>&2
- $echo "*** Future versions of Libtool will require -mode=MODE be specified." 1>&2
+ $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2
case $nonopt in
*cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*)
mode=link
@@ -359,7 +657,7 @@ if test -z "$show_help"; then
if test -n "$execute_dlfiles" && test "$mode" != execute; then
$echo "$modename: unrecognized option \`-dlopen'" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
# Change the help message to a mode-specific one.
@@ -382,7 +680,7 @@ if test -z "$show_help"; then
for arg
do
- case "$arg_mode" in
+ case $arg_mode in
arg )
# do not "continue". Instead, add this to base_compile
lastarg="$arg"
@@ -401,7 +699,7 @@ if test -z "$show_help"; then
-o)
if test -n "$libobj" ; then
$echo "$modename: you cannot specify \`-o' more than once" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
arg_mode=target
continue
@@ -426,7 +724,7 @@ if test -z "$show_help"; then
args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"`
lastarg=
save_ifs="$IFS"; IFS=','
- for arg in $args; do
+ for arg in $args; do
IFS="$save_ifs"
# Double-quote args containing other shell metacharacters.
@@ -464,7 +762,10 @@ if test -z "$show_help"; then
case $lastarg in
# Double-quote args containing other shell metacharacters.
# Many Bourne shells cannot handle close brackets correctly
- # in scan sets, so we specify it separately.
+ # in scan sets, and some SunOS ksh mistreat backslash-escaping
+ # in scan sets (worked around with variable expansion),
+ # and furthermore cannot handle '|' '&' '(' ')' in scan sets
+ # at all, so we specify them separately.
*[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
lastarg="\"$lastarg\""
;;
@@ -476,11 +777,11 @@ if test -z "$show_help"; then
case $arg_mode in
arg)
$echo "$modename: you must specify an argument for -Xcompile"
- exit 1
+ exit $EXIT_FAILURE
;;
target)
$echo "$modename: you must specify a target with \`-o'" 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
*)
# Get the name of the library object.
@@ -513,50 +814,11 @@ if test -z "$show_help"; then
*.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;;
*)
$echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
esac
- # Infer tagged configuration to use if any are available and
- # if one wasn't chosen via the "--tag" command line option.
- # Only attempt this if the compiler in the base compile
- # command doesn't match the default compiler.
- if test -n "$available_tags" && test -z "$tagname"; then
- case $base_compile in
- # Blanks in the command may have been stripped by the calling shell,
- # but not from the CC environment variable when configure was run.
- " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "*) ;;
- # Blanks at the start of $base_compile will cause this to fail
- # if we don't check for them as well.
- *)
- for z in $available_tags; do
- if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$0" > /dev/null; then
- # Evaluate the configuration.
- eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $0`"
- case "$base_compile " in
- "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*)
- # The compiler in the base compile command matches
- # the one in the tagged configuration.
- # Assume this is the tagged configuration we want.
- tagname=$z
- break
- ;;
- esac
- fi
- done
- # If $tagname still isn't set, then no tagged configuration
- # was found and let the user know that the "--tag" command
- # line option must be used.
- if test -z "$tagname"; then
- $echo "$modename: unable to infer tagged configuration"
- $echo "$modename: specify a tag with \`--tag'" 1>&2
- exit 1
-# else
-# $echo "$modename: using $tagname tagged configuration"
- fi
- ;;
- esac
- fi
+ func_infer_tag $base_compile
for arg in $later; do
case $arg in
@@ -577,6 +839,14 @@ if test -z "$show_help"; then
esac
done
+ qlibobj=`$echo "X$libobj" | $Xsed -e "$sed_quote_subst"`
+ case $qlibobj in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ qlibobj="\"$qlibobj\"" ;;
+ esac
+ test "X$libobj" != "X$qlibobj" \
+ && $echo "X$libobj" | grep '[]~#^*{};<>?"'"'"' &()|`$[]' \
+ && $echo "$modename: libobj name \`$libobj' may not contain shell special characters."
objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
if test "X$xdir" = "X$obj"; then
@@ -589,7 +859,7 @@ if test -z "$show_help"; then
if test -z "$base_compile"; then
$echo "$modename: you must specify a compilation command" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
# Delete any leftover library objects.
@@ -600,7 +870,7 @@ if test -z "$show_help"; then
fi
$run $rm $removelist
- trap "$run $rm $removelist; exit 1" 1 2 15
+ trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15
# On Cygwin there's no "real" PIC flag so we must build both object types
case $host_os in
@@ -619,7 +889,7 @@ if test -z "$show_help"; then
output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
lockfile="$output_obj.lock"
removelist="$removelist $output_obj $lockfile"
- trap "$run $rm $removelist; exit 1" 1 2 15
+ trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15
else
output_obj=
need_locks=no
@@ -629,7 +899,7 @@ if test -z "$show_help"; then
# Lock this critical section if it is needed
# We use this script file to make the link, it avoids creating a new file
if test "$need_locks" = yes; then
- until $run ln "$0" "$lockfile" 2>/dev/null; do
+ until $run ln "$srcfile" "$lockfile" 2>/dev/null; do
$show "Waiting for $lockfile to be removed"
sleep 2
done
@@ -647,14 +917,19 @@ avoid parallel builds (make -j) in this platform, or get a better
compiler."
$run $rm $removelist
- exit 1
+ exit $EXIT_FAILURE
fi
- $echo $srcfile > "$lockfile"
+ $echo "$srcfile" > "$lockfile"
fi
if test -n "$fix_srcfile_path"; then
eval srcfile=\"$fix_srcfile_path\"
fi
+ qsrcfile=`$echo "X$srcfile" | $Xsed -e "$sed_quote_subst"`
+ case $qsrcfile in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ qsrcfile="\"$qsrcfile\"" ;;
+ esac
$run $rm "$libobj" "${libobj}T"
@@ -676,18 +951,18 @@ EOF
fbsd_hideous_sh_bug=$base_compile
if test "$pic_mode" != no; then
- command="$base_compile $srcfile $pic_flag"
+ command="$base_compile $qsrcfile $pic_flag"
else
# Don't build PIC code
- command="$base_compile $srcfile"
+ command="$base_compile $qsrcfile"
fi
if test ! -d "${xdir}$objdir"; then
$show "$mkdir ${xdir}$objdir"
$run $mkdir ${xdir}$objdir
- status=$?
- if test "$status" -ne 0 && test ! -d "${xdir}$objdir"; then
- exit $status
+ exit_status=$?
+ if test "$exit_status" -ne 0 && test ! -d "${xdir}$objdir"; then
+ exit $exit_status
fi
fi
@@ -702,7 +977,7 @@ EOF
if $run eval "$command"; then :
else
test -n "$output_obj" && $run $rm $removelist
- exit 1
+ exit $EXIT_FAILURE
fi
if test "$need_locks" = warn &&
@@ -722,7 +997,7 @@ avoid parallel builds (make -j) in this platform, or get a better
compiler."
$run $rm $removelist
- exit 1
+ exit $EXIT_FAILURE
fi
# Just move the object if needed, then go on to compile the next one
@@ -759,9 +1034,9 @@ EOF
if test "$build_old_libs" = yes; then
if test "$pic_mode" != yes; then
# Don't build PIC code
- command="$base_compile $srcfile"
+ command="$base_compile $qsrcfile"
else
- command="$base_compile $srcfile $pic_flag"
+ command="$base_compile $qsrcfile $pic_flag"
fi
if test "$compiler_c_o" = yes; then
command="$command -o $obj"
@@ -774,7 +1049,7 @@ EOF
if $run eval "$command"; then :
else
$run $rm $removelist
- exit 1
+ exit $EXIT_FAILURE
fi
if test "$need_locks" = warn &&
@@ -794,7 +1069,7 @@ avoid parallel builds (make -j) in this platform, or get a better
compiler."
$run $rm $removelist
- exit 1
+ exit $EXIT_FAILURE
fi
# Just move the object if needed
@@ -832,7 +1107,7 @@ EOF
$run $rm "$lockfile"
fi
- exit 0
+ exit $EXIT_SUCCESS
;;
# libtool link mode
@@ -890,6 +1165,7 @@ EOF
no_install=no
objs=
non_pic_objects=
+ notinst_path= # paths that contain not-installed libtool libraries
precious_files_regex=
prefer_static_libs=no
preload=no
@@ -904,46 +1180,7 @@ EOF
vinfo=
vinfo_number=no
- # Infer tagged configuration to use if any are available and
- # if one wasn't chosen via the "--tag" command line option.
- # Only attempt this if the compiler in the base link
- # command doesn't match the default compiler.
- if test -n "$available_tags" && test -z "$tagname"; then
- case $base_compile in
- # Blanks in the command may have been stripped by the calling shell,
- # but not from the CC environment variable when configure was run.
- "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*) ;;
- # Blanks at the start of $base_compile will cause this to fail
- # if we don't check for them as well.
- *)
- for z in $available_tags; do
- if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$0" > /dev/null; then
- # Evaluate the configuration.
- eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $0`"
- case $base_compile in
- "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*)
- # The compiler in $compile_command matches
- # the one in the tagged configuration.
- # Assume this is the tagged configuration we want.
- tagname=$z
- break
- ;;
- esac
- fi
- done
- # If $tagname still isn't set, then no tagged configuration
- # was found and let the user know that the "--tag" command
- # line option must be used.
- if test -z "$tagname"; then
- $echo "$modename: unable to infer tagged configuration"
- $echo "$modename: specify a tag with \`--tag'" 1>&2
- exit 1
-# else
-# $echo "$modename: using $tagname tagged configuration"
- fi
- ;;
- esac
- fi
+ func_infer_tag $base_compile
# We need to know -static, to get the right output filenames.
for arg
@@ -957,14 +1194,15 @@ EOF
if test -n "$link_static_flag"; then
dlopen_self=$dlopen_self_static
fi
+ prefer_static_libs=yes
else
if test -z "$pic_flag" && test -n "$link_static_flag"; then
dlopen_self=$dlopen_self_static
fi
+ prefer_static_libs=built
fi
build_libtool_libs=no
build_old_libs=yes
- prefer_static_libs=yes
break
;;
esac
@@ -1039,7 +1277,7 @@ EOF
export_symbols="$arg"
if test ! -f "$arg"; then
$echo "$modename: symbol file \`$arg' does not exist"
- exit 1
+ exit $EXIT_FAILURE
fi
prev=
continue
@@ -1091,7 +1329,7 @@ EOF
test "$pic_object" = none && \
test "$non_pic_object" = none; then
$echo "$modename: cannot find name of object for \`$arg'" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
# Extract subdirectory from the argument.
@@ -1139,12 +1377,17 @@ EOF
if test -z "$pic_object" || test "$pic_object" = none ; then
arg="$non_pic_object"
fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object="$pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
fi
else
# Only an error if not doing a dry-run.
if test -z "$run"; then
$echo "$modename: \`$arg' is not a valid libtool object" 1>&2
- exit 1
+ exit $EXIT_FAILURE
else
# Dry-run case.
@@ -1165,7 +1408,7 @@ EOF
done
else
$echo "$modename: link input file \`$save_arg' does not exist"
- exit 1
+ exit $EXIT_FAILURE
fi
arg=$save_arg
prev=
@@ -1177,7 +1420,7 @@ EOF
[\\/]* | [A-Za-z]:[\\/]*) ;;
*)
$echo "$modename: only absolute run-paths are allowed" 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
esac
if test "$prev" = rpath; then
@@ -1217,6 +1460,18 @@ EOF
finalize_command="$finalize_command $qarg"
continue
;;
+ shrext)
+ shrext_cmds="$arg"
+ prev=
+ continue
+ ;;
+ darwin_framework|darwin_framework_skip)
+ test "$prev" = "darwin_framework" && compiler_flags="$compiler_flags $arg"
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ prev=
+ continue
+ ;;
*)
eval "$prev=\"\$arg\""
prev=
@@ -1265,7 +1520,7 @@ EOF
-export-symbols | -export-symbols-regex)
if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
$echo "$modename: more than one -exported-symbols argument is not allowed"
- exit 1
+ exit $EXIT_FAILURE
fi
if test "X$arg" = "X-export-symbols"; then
prev=expsyms
@@ -1275,6 +1530,18 @@ EOF
continue
;;
+ -framework|-arch|-isysroot)
+ case " $CC " in
+ *" ${arg} ${1} "* | *" ${arg} ${1} "*)
+ prev=darwin_framework_skip ;;
+ *) compiler_flags="$compiler_flags $arg"
+ prev=darwin_framework ;;
+ esac
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ continue
+ ;;
+
-inst-prefix-dir)
prev=inst_prefix
continue
@@ -1301,7 +1568,8 @@ EOF
absdir=`cd "$dir" && pwd`
if test -z "$absdir"; then
$echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2
- exit 1
+ absdir="$dir"
+ notinst_path="$notinst_path $dir"
fi
dir="$absdir"
;;
@@ -1315,10 +1583,15 @@ EOF
esac
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ testbindir=`$echo "X$dir" | $Xsed -e 's*/lib$*/bin*'`
case :$dllsearchpath: in
*":$dir:"*) ;;
*) dllsearchpath="$dllsearchpath:$dir";;
esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$testbindir";;
+ esac
;;
esac
continue
@@ -1327,15 +1600,15 @@ EOF
-l*)
if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
case $host in
- *-*-cygwin* | *-*-pw32* | *-*-beos*)
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos*)
# These systems don't actually have a C or math library (as such)
continue
;;
- *-*-mingw* | *-*-os2*)
+ *-*-os2*)
# These systems don't actually have a C library (as such)
test "X$arg" = "X-lc" && continue
;;
- *-*-openbsd* | *-*-freebsd*)
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
# Do not include libc due to us having libc/libc_r.
test "X$arg" = "X-lc" && continue
;;
@@ -1343,10 +1616,19 @@ EOF
# Rhapsody C and math libraries are in the System framework
deplibs="$deplibs -framework System"
continue
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ test "X$arg" = "X-lc" && continue
+ ;;
esac
elif test "X$arg" = "X-lc_r"; then
case $host in
- *-*-openbsd* | *-*-freebsd*)
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
# Do not include libc_r directly, use -pthread flag.
continue
;;
@@ -1356,8 +1638,20 @@ EOF
continue
;;
+ # Tru64 UNIX uses -model [arg] to determine the layout of C++
+ # classes, name mangling, and exception handling.
+ -model)
+ compile_command="$compile_command $arg"
+ compiler_flags="$compiler_flags $arg"
+ finalize_command="$finalize_command $arg"
+ prev=xcompiler
+ continue
+ ;;
+
-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe)
- deplibs="$deplibs $arg"
+ compiler_flags="$compiler_flags $arg"
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
continue
;;
@@ -1366,13 +1660,19 @@ EOF
continue
;;
- # gcc -m* arguments should be passed to the linker via $compiler_flags
- # in order to pass architecture information to the linker
- # (e.g. 32 vs 64-bit). This may also be accomplished via -Wl,-mfoo
- # but this is not reliable with gcc because gcc may use -mfoo to
- # select a different linker, different libraries, etc, while
- # -Wl,-mfoo simply passes -mfoo to the linker.
- -m*)
+ # -64, -mips[0-9] enable 64-bit mode on the SGI compiler
+ # -r[0-9][0-9]* specifies the processor on the SGI compiler
+ # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler
+ # +DA*, +DD* enable 64-bit mode on the HP compiler
+ # -q* pass through compiler args for the IBM compiler
+ # -m* pass through architecture-specific compiler args for GCC
+ # -m*, -t[45]*, -txscale* pass through architecture-specific
+ # compiler args for GCC
+ # -pg pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \
+ -t[45]*|-txscale*|@*)
+
# Unknown arguments in both finalize_command and compile_command need
# to be aesthetically quoted because they are evaled later.
arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
@@ -1383,9 +1683,7 @@ EOF
esac
compile_command="$compile_command $arg"
finalize_command="$finalize_command $arg"
- if test "$with_gcc" = "yes" ; then
- compiler_flags="$compiler_flags $arg"
- fi
+ compiler_flags="$compiler_flags $arg"
continue
;;
@@ -1452,7 +1750,7 @@ EOF
[\\/]* | [A-Za-z]:[\\/]*) ;;
*)
$echo "$modename: only absolute run-paths are allowed" 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
esac
case "$xrpath " in
@@ -1575,7 +1873,7 @@ EOF
test "$pic_object" = none && \
test "$non_pic_object" = none; then
$echo "$modename: cannot find name of object for \`$arg'" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
# Extract subdirectory from the argument.
@@ -1623,12 +1921,17 @@ EOF
if test -z "$pic_object" || test "$pic_object" = none ; then
arg="$non_pic_object"
fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object="$pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
fi
else
# Only an error if not doing a dry-run.
if test -z "$run"; then
$echo "$modename: \`$arg' is not a valid libtool object" 1>&2
- exit 1
+ exit $EXIT_FAILURE
else
# Dry-run case.
@@ -1695,7 +1998,7 @@ EOF
if test -n "$prev"; then
$echo "$modename: the \`$prevarg' option requires an argument" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
@@ -1728,9 +2031,9 @@ EOF
if test ! -d "$output_objdir"; then
$show "$mkdir $output_objdir"
$run $mkdir $output_objdir
- status=$?
- if test "$status" -ne 0 && test ! -d "$output_objdir"; then
- exit $status
+ exit_status=$?
+ if test "$exit_status" -ne 0 && test ! -d "$output_objdir"; then
+ exit $exit_status
fi
fi
@@ -1739,7 +2042,7 @@ EOF
"")
$echo "$modename: you must specify an output file" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
*.$libext) linkmode=oldlib ;;
*.lo | *.$objext) linkmode=obj ;;
@@ -1749,7 +2052,7 @@ EOF
case $host in
*cygwin* | *mingw* | *pw32*)
- # don't eliminate duplcations in $postdeps and $predeps
+ # don't eliminate duplications in $postdeps and $predeps
duplicate_compiler_generated_deps=yes
;;
*)
@@ -1793,7 +2096,6 @@ EOF
newlib_search_path=
need_relink=no # whether we're linking any uninstalled libtool libraries
notinst_deplibs= # not-installed libtool libraries
- notinst_path= # paths that contain not-installed libtool libraries
case $linkmode in
lib)
passes="conv link"
@@ -1802,7 +2104,7 @@ EOF
*.la) ;;
*)
$echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
esac
done
@@ -1845,7 +2147,7 @@ EOF
compile_deplibs="$deplib $compile_deplibs"
finalize_deplibs="$deplib $finalize_deplibs"
else
- deplibs="$deplib $deplibs"
+ compiler_flags="$compiler_flags $deplib"
fi
continue
;;
@@ -1854,13 +2156,9 @@ EOF
$echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2
continue
fi
- if test "$pass" = conv; then
- deplibs="$deplib $deplibs"
- continue
- fi
name=`$echo "X$deplib" | $Xsed -e 's/^-l//'`
for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do
- for search_ext in .la $shrext .so .a; do
+ for search_ext in .la $std_shrext .so .a; do
# Search the libtool library
lib="$searchdir/lib${name}${search_ext}"
if test -f "$lib"; then
@@ -1936,11 +2234,11 @@ EOF
fi
if test "$pass" = scan; then
deplibs="$deplib $deplibs"
- newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
else
compile_deplibs="$deplib $compile_deplibs"
finalize_deplibs="$deplib $finalize_deplibs"
fi
+ newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
;;
*)
$echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2
@@ -1968,7 +2266,22 @@ EOF
fi
case $linkmode in
lib)
- if test "$deplibs_check_method" != pass_all; then
+ valid_a_lib=no
+ case $deplibs_check_method in
+ match_pattern*)
+ set dummy $deplibs_check_method
+ match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+ if eval $echo \"$deplib\" 2>/dev/null \
+ | $SED 10q \
+ | $EGREP "$match_pattern_regex" > /dev/null; then
+ valid_a_lib=yes
+ fi
+ ;;
+ pass_all)
+ valid_a_lib=yes
+ ;;
+ esac
+ if test "$valid_a_lib" != yes; then
$echo
$echo "*** Warning: Trying to link with static lib archive $deplib."
$echo "*** I have the capability to make that library automatically link in when"
@@ -2018,15 +2331,15 @@ EOF
esac # case $deplib
if test "$found" = yes || test -f "$lib"; then :
else
- $echo "$modename: cannot find the library \`$lib'" 1>&2
- exit 1
+ $echo "$modename: cannot find the library \`$lib' or unhandled argument \`$deplib'" 1>&2
+ exit $EXIT_FAILURE
fi
# Check to see that this really is a libtool archive.
if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
else
$echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
@@ -2042,6 +2355,8 @@ EOF
# it will not redefine variables installed, or shouldnotlink
installed=yes
shouldnotlink=no
+ avoidtemprpath=
+
# Read the .la file
case $lib in
@@ -2062,7 +2377,7 @@ EOF
if test -z "$libdir"; then
if test -z "$old_library"; then
$echo "$modename: cannot find name of link library for \`$lib'" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
# It is a libtool convenience library, so add in its objects.
convenience="$convenience $ladir/$objdir/$old_library"
@@ -2079,12 +2394,12 @@ EOF
done
elif test "$linkmode" != prog && test "$linkmode" != lib; then
$echo "$modename: \`$lib' is not a convenience library" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
continue
fi # $pass = conv
-
+
# Get the name of the library we link against.
linklib=
for l in $old_library $library_names; do
@@ -2092,16 +2407,18 @@ EOF
done
if test -z "$linklib"; then
$echo "$modename: cannot find name of link library for \`$lib'" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
# This library was specified with -dlopen.
if test "$pass" = dlopen; then
if test -z "$libdir"; then
$echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
- if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+ if test -z "$dlname" ||
+ test "$dlopen_support" != yes ||
+ test "$build_libtool_libs" = no; then
# If there is no dlname, no dlopen support or we're linking
# statically, we need to preload. We also need to preload any
# dependent libraries so libltdl's deplib preloader doesn't
@@ -2138,11 +2455,19 @@ EOF
dir="$libdir"
absdir="$libdir"
fi
+ test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
else
- dir="$ladir/$objdir"
- absdir="$abs_ladir/$objdir"
- # Remove this search path later
- notinst_path="$notinst_path $abs_ladir"
+ if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ dir="$ladir"
+ absdir="$abs_ladir"
+ # Remove this search path later
+ notinst_path="$notinst_path $abs_ladir"
+ else
+ dir="$ladir/$objdir"
+ absdir="$abs_ladir/$objdir"
+ # Remove this search path later
+ notinst_path="$notinst_path $abs_ladir"
+ fi
fi # $installed = yes
name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
@@ -2150,7 +2475,7 @@ EOF
if test "$pass" = dlpreopen; then
if test -z "$libdir"; then
$echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
# Prefer using a static library (so that no silly _DYNAMIC symbols
# are required to link).
@@ -2177,7 +2502,7 @@ EOF
continue
fi
-
+
if test "$linkmode" = prog && test "$pass" != link; then
newlib_search_path="$newlib_search_path $ladir"
deplibs="$lib $deplibs"
@@ -2215,12 +2540,12 @@ EOF
if test -n "$library_names" &&
{ test "$prefer_static_libs" = no || test -z "$old_library"; }; then
# We need to hardcode the library path
- if test -n "$shlibpath_var"; then
+ if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
# Make sure the rpath contains only unique directories.
case "$temp_rpath " in
*" $dir "*) ;;
*" $absdir "*) ;;
- *) temp_rpath="$temp_rpath $dir" ;;
+ *) temp_rpath="$temp_rpath $absdir" ;;
esac
fi
@@ -2257,24 +2582,29 @@ EOF
fi
link_static=no # Whether the deplib will be linked statically
+ use_static_libs=$prefer_static_libs
+ if test "$use_static_libs" = built && test "$installed" = yes ; then
+ use_static_libs=no
+ fi
if test -n "$library_names" &&
- { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
+ { test "$use_static_libs" = no || test -z "$old_library"; }; then
if test "$installed" = no; then
notinst_deplibs="$notinst_deplibs $lib"
need_relink=yes
fi
# This is a shared library
-
- # Warn about portability, can't link against -module's on some systems (darwin)
- if test "$shouldnotlink" = yes && test "$pass" = link ; then
+
+ # Warn about portability, can't link against -module's on
+ # some systems (darwin)
+ if test "$shouldnotlink" = yes && test "$pass" = link ; then
$echo
if test "$linkmode" = prog; then
$echo "*** Warning: Linking the executable $output against the loadable module"
else
$echo "*** Warning: Linking the shared library $output against the loadable module"
fi
- $echo "*** $linklib is not portable!"
- fi
+ $echo "*** $linklib is not portable!"
+ fi
if test "$linkmode" = lib &&
test "$hardcode_into_libs" = yes; then
# Hardcode the library path.
@@ -2370,11 +2700,15 @@ EOF
if test "$hardcode_direct" = no; then
add="$dir/$linklib"
case $host in
- *-*-sco3.2v5* ) add_dir="-L$dir" ;;
+ *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+ *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+ *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+ *-*-unixware7*) add_dir="-L$dir" ;;
*-*-darwin* )
- # if the lib is a module then we can not link against it, someone
- # is ignoring the new warnings I added
- if /usr/bin/file -L $add 2> /dev/null | grep "bundle" >/dev/null ; then
+ # if the lib is a module then we can not link against
+ # it, someone is ignoring the new warnings I added
+ if /usr/bin/file -L $add 2> /dev/null |
+ $EGREP ": [^:]* bundle" >/dev/null ; then
$echo "** Warning, lib $linklib is a module, not a shared library"
if test -z "$old_library" ; then
$echo
@@ -2382,7 +2716,7 @@ EOF
$echo "** The link will probably fail, sorry"
else
add="$dir/$old_library"
- fi
+ fi
fi
esac
elif test "$hardcode_minus_L" = no; then
@@ -2405,7 +2739,7 @@ EOF
add_dir="-L$dir"
# Try looking first in the location we're being installed to.
if test -n "$inst_prefix_dir"; then
- case "$libdir" in
+ case $libdir in
[\\/]*)
add_dir="$add_dir -L$inst_prefix_dir$libdir"
;;
@@ -2424,7 +2758,7 @@ EOF
if test "$lib_linked" != yes; then
$echo "$modename: configuration error: unsupported hardcode properties"
- exit 1
+ exit $EXIT_FAILURE
fi
if test -n "$add_shlibpath"; then
@@ -2467,7 +2801,8 @@ EOF
esac
add="-l$name"
elif test "$hardcode_automatic" = yes; then
- if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then
+ if test -n "$inst_prefix_dir" &&
+ test -f "$inst_prefix_dir$libdir/$linklib" ; then
add="$inst_prefix_dir$libdir/$linklib"
else
add="$libdir/$linklib"
@@ -2477,7 +2812,7 @@ EOF
add_dir="-L$libdir"
# Try looking first in the location we're being installed to.
if test -n "$inst_prefix_dir"; then
- case "$libdir" in
+ case $libdir in
[\\/]*)
add_dir="$add_dir -L$inst_prefix_dir$libdir"
;;
@@ -2538,8 +2873,6 @@ EOF
fi
fi
else
- convenience="$convenience $dir/$old_library"
- old_convenience="$old_convenience $dir/$old_library"
deplibs="$dir/$old_library $deplibs"
link_static=yes
fi
@@ -2547,7 +2880,8 @@ EOF
if test "$linkmode" = lib; then
if test -n "$dependency_libs" &&
- { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes ||
+ { test "$hardcode_into_libs" != yes ||
+ test "$build_old_libs" = yes ||
test "$link_static" = yes; }; then
# Extract -R from dependency_libs
temp_deplibs=
@@ -2604,7 +2938,7 @@ EOF
eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
if test -z "$libdir"; then
$echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
if test "$absdir" != "$libdir"; then
$echo "$modename: warning: \`$deplib' seems to be moved" 1>&2
@@ -2614,7 +2948,8 @@ EOF
depdepl=
case $host in
*-*-darwin*)
- # we do not want to link against static libs, but need to link against shared
+ # we do not want to link against static libs,
+ # but need to link against shared
eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
if test -n "$deplibrary_names" ; then
for tmp in $deplibrary_names ; do
@@ -2622,7 +2957,7 @@ EOF
done
if test -f "$path/$depdepl" ; then
depdepl="$path/$depdepl"
- fi
+ fi
# do not add paths which are already there
case " $newlib_search_path " in
*" $path "*) ;;
@@ -2632,36 +2967,35 @@ EOF
path=""
;;
*)
- path="-L$path"
- ;;
- esac
-
+ path="-L$path"
+ ;;
+ esac
;;
- -l*)
+ -l*)
case $host in
*-*-darwin*)
- # Again, we only want to link against shared libraries
- eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"`
- for tmp in $newlib_search_path ; do
- if test -f "$tmp/lib$tmp_libs.dylib" ; then
- eval depdepl="$tmp/lib$tmp_libs.dylib"
- break
- fi
- done
- path=""
+ # Again, we only want to link against shared libraries
+ eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"`
+ for tmp in $newlib_search_path ; do
+ if test -f "$tmp/lib$tmp_libs.dylib" ; then
+ eval depdepl="$tmp/lib$tmp_libs.dylib"
+ break
+ fi
+ done
+ path=""
;;
*) continue ;;
- esac
+ esac
;;
*) continue ;;
esac
case " $deplibs " in
- *" $depdepl "*) ;;
- *) deplibs="$deplibs $depdepl" ;;
- esac
- case " $deplibs " in
*" $path "*) ;;
- *) deplibs="$deplibs $path" ;;
+ *) deplibs="$path $deplibs" ;;
+ esac
+ case " $deplibs " in
+ *" $depdepl "*) ;;
+ *) deplibs="$depdepl $deplibs" ;;
esac
done
fi # link_all_deplibs != no
@@ -2748,7 +3082,8 @@ EOF
eval $var=\"$tmp_libs\"
done # for var
fi
- # Last step: remove runtime libs from dependency_libs (they stay in deplibs)
+ # Last step: remove runtime libs from dependency_libs
+ # (they stay in deplibs)
tmp_libs=
for i in $dependency_libs ; do
case " $predeps $postdeps $compiler_lib_search_path " in
@@ -2808,19 +3143,19 @@ EOF
case $outputname in
lib*)
name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
- eval shared_ext=\"$shrext\"
+ eval shared_ext=\"$shrext_cmds\"
eval libname=\"$libname_spec\"
;;
*)
if test "$module" = no; then
$echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
if test "$need_lib_prefix" != no; then
# Add the "lib" prefix for modules if required
name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
- eval shared_ext=\"$shrext\"
+ eval shared_ext=\"$shrext_cmds\"
eval libname=\"$libname_spec\"
else
libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
@@ -2831,7 +3166,7 @@ EOF
if test -n "$objs"; then
if test "$deplibs_check_method" != pass_all; then
$echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1
- exit 1
+ exit $EXIT_FAILURE
else
$echo
$echo "*** Warning: Linking the shared library $output against the non-libtool"
@@ -2879,13 +3214,13 @@ EOF
if test -n "$8"; then
$echo "$modename: too many parameters to \`-version-info'" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
# convert absolute version numbers to libtool ages
# this retains compatibility with .la files and attempts
# to make the code below a bit more comprehensible
-
+
case $vinfo_number in
yes)
number_major="$2"
@@ -2925,36 +3260,36 @@ EOF
# Check that each of the things are valid numbers.
case $current in
- 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;;
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
*)
- $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2
+ $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2
$echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
esac
case $revision in
- 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;;
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
*)
- $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2
+ $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2
$echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
esac
case $age in
- 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;;
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
*)
- $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2
+ $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2
$echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
esac
if test "$age" -gt "$current"; then
$echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
$echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
# Calculate the version variables.
@@ -2971,7 +3306,7 @@ EOF
versuffix="$major.$age.$revision"
# Darwin ld doesn't like 0 for these options...
minor_current=`expr $current + 1`
- verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ verstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
;;
freebsd-aout)
@@ -3043,7 +3378,7 @@ EOF
*)
$echo "$modename: unknown library version type \`$version_type'" 1>&2
$echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
esac
@@ -3097,9 +3432,11 @@ EOF
*.$objext)
;;
$output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
- if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
- then
- continue
+ if test "X$precious_files_regex" != "X"; then
+ if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+ then
+ continue
+ fi
fi
removelist="$removelist $p"
;;
@@ -3122,9 +3459,9 @@ EOF
# Eliminate all temporary directories.
for path in $notinst_path; do
- lib_search_path=`$echo "$lib_search_path " | ${SED} -e 's% $path % %g'`
- deplibs=`$echo "$deplibs " | ${SED} -e 's% -L$path % %g'`
- dependency_libs=`$echo "$dependency_libs " | ${SED} -e 's% -L$path % %g'`
+ lib_search_path=`$echo "$lib_search_path " | ${SED} -e "s% $path % %g"`
+ deplibs=`$echo "$deplibs " | ${SED} -e "s% -L$path % %g"`
+ dependency_libs=`$echo "$dependency_libs " | ${SED} -e "s% -L$path % %g"`
done
if test -n "$xrpath"; then
@@ -3175,9 +3512,14 @@ EOF
*-*-netbsd*)
# Don't link with libc until the a.out ld.so is fixed.
;;
- *-*-openbsd* | *-*-freebsd*)
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
# Do not include libc due to us having libc/libc_r.
- test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
;;
*)
# Add libc to deplibs on all other systems if necessary.
@@ -3221,11 +3563,11 @@ EOF
int main() { return 0; }
EOF
$rm conftest
- $LTCC -o conftest conftest.c $deplibs
+ $LTCC $LTCFLAGS -o conftest conftest.c $deplibs
if test "$?" -eq 0 ; then
ldd_output=`ldd conftest`
for i in $deplibs; do
- name="`expr $i : '-l\(.*\)'`"
+ name=`expr $i : '-l\(.*\)'`
# If $name is empty we are operating on a -L argument.
if test "$name" != "" && test "$name" -ne "0"; then
if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
@@ -3262,11 +3604,11 @@ EOF
# Error occurred in the first compile. Let's try to salvage
# the situation: Compile a separate program for each library.
for i in $deplibs; do
- name="`expr $i : '-l\(.*\)'`"
+ name=`expr $i : '-l\(.*\)'`
# If $name is empty we are operating on a -L argument.
if test "$name" != "" && test "$name" != "0"; then
$rm conftest
- $LTCC -o conftest conftest.c $i
+ $LTCC $LTCFLAGS -o conftest conftest.c $i
# Did it work?
if test "$?" -eq 0 ; then
ldd_output=`ldd conftest`
@@ -3314,7 +3656,7 @@ EOF
set dummy $deplibs_check_method
file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
for a_deplib in $deplibs; do
- name="`expr $a_deplib : '-l\(.*\)'`"
+ name=`expr $a_deplib : '-l\(.*\)'`
# If $name is empty we are operating on a -L argument.
if test "$name" != "" && test "$name" != "0"; then
if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
@@ -3348,6 +3690,13 @@ EOF
*) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
esac
done
+ # It is ok to link against an archive when
+ # building a shared library.
+ if $AR -t $potlib > /dev/null 2>&1; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \
| ${SED} 10q \
| $EGREP "$file_magic_regex" > /dev/null; then
@@ -3383,7 +3732,7 @@ EOF
set dummy $deplibs_check_method
match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
for a_deplib in $deplibs; do
- name="`expr $a_deplib : '-l\(.*\)'`"
+ name=`expr $a_deplib : '-l\(.*\)'`
# If $name is empty we are operating on a -L argument.
if test -n "$name" && test "$name" != "0"; then
if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
@@ -3513,6 +3862,35 @@ EOF
deplibs=$newdeplibs
fi
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $deplibs " in
+ *" -L$path/$objdir "*)
+ new_libs="$new_libs -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ done
+ deplibs="$new_libs"
+
+
# All the library-specific variables (install_libdir is set above).
library_names=
old_library=
@@ -3580,7 +3958,7 @@ EOF
fi
# Get the real and link names of the library.
- eval shared_ext=\"$shrext\"
+ eval shared_ext=\"$shrext_cmds\"
eval library_names=\"$library_names_spec\"
set dummy $library_names
realname="$2"
@@ -3596,6 +3974,7 @@ EOF
fi
lib="$output_objdir/$realname"
+ linknames=
for link
do
linknames="$linknames $link"
@@ -3624,6 +4003,9 @@ EOF
# The command line is too long to execute in one step.
$show "using reloadable object file for export list..."
skipped_export=:
+ # Break out early, otherwise skipped_export may be
+ # set to false by a later but shorter cmd.
+ break
fi
done
IFS="$save_ifs"
@@ -3644,12 +4026,12 @@ EOF
for test_deplib in $deplibs; do
case " $convenience " in
*" $test_deplib "*) ;;
- *)
+ *)
tmp_deplibs="$tmp_deplibs $test_deplib"
;;
esac
done
- deplibs="$tmp_deplibs"
+ deplibs="$tmp_deplibs"
if test -n "$convenience"; then
if test -n "$whole_archive_flag_spec"; then
@@ -3657,67 +4039,13 @@ EOF
eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
else
gentop="$output_objdir/${outputname}x"
- $show "${rm}r $gentop"
- $run ${rm}r "$gentop"
- $show "$mkdir $gentop"
- $run $mkdir "$gentop"
- status=$?
- if test "$status" -ne 0 && test ! -d "$gentop"; then
- exit $status
- fi
generated="$generated $gentop"
- for xlib in $convenience; do
- # Extract the objects.
- case $xlib in
- [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
- *) xabs=`pwd`"/$xlib" ;;
- esac
- xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
- xdir="$gentop/$xlib"
-
- $show "${rm}r $xdir"
- $run ${rm}r "$xdir"
- $show "$mkdir $xdir"
- $run $mkdir "$xdir"
- status=$?
- if test "$status" -ne 0 && test ! -d "$xdir"; then
- exit $status
- fi
- # We will extract separately just the conflicting names and we will no
- # longer touch any unique names. It is faster to leave these extract
- # automatically by $AR in one run.
- $show "(cd $xdir && $AR x $xabs)"
- $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
- if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then
- :
- else
- $echo "$modename: warning: object name conflicts; renaming object files" 1>&2
- $echo "$modename: warning: to ensure that they will not overwrite" 1>&2
- $AR t "$xabs" | sort | uniq -cd | while read -r count name
- do
- i=1
- while test "$i" -le "$count"
- do
- # Put our $i before any first dot (extension)
- # Never overwrite any file
- name_to="$name"
- while test "X$name_to" = "X$name" || test -f "$xdir/$name_to"
- do
- name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"`
- done
- $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')"
- $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $?
- i=`expr $i + 1`
- done
- done
- fi
-
- libobjs="$libobjs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
- done
+ func_extract_archives $gentop $convenience
+ libobjs="$libobjs $func_extract_archives_result"
fi
fi
-
+
if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
eval flag=\"$thread_safe_flag_spec\"
linker_flags="$linker_flags $flag"
@@ -3747,7 +4075,8 @@ EOF
fi
fi
- if test "X$skipped_export" != "X:" && len=`expr "X$test_cmds" : ".*"` &&
+ if test "X$skipped_export" != "X:" &&
+ len=`expr "X$test_cmds" : ".*" 2>/dev/null` &&
test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
:
else
@@ -3766,6 +4095,7 @@ EOF
save_libobjs=$libobjs
fi
save_output=$output
+ output_la=`$echo "X$output" | $Xsed -e "$basename"`
# Clear the reloadable object creation command queue and
# initialize k to one.
@@ -3775,13 +4105,13 @@ EOF
delfiles=
last_robj=
k=1
- output=$output_objdir/$save_output-${k}.$objext
+ output=$output_objdir/$output_la-${k}.$objext
# Loop over the list of objects to be linked.
for obj in $save_libobjs
do
eval test_cmds=\"$reload_cmds $objlist $last_robj\"
if test "X$objlist" = X ||
- { len=`expr "X$test_cmds" : ".*"` &&
+ { len=`expr "X$test_cmds" : ".*" 2>/dev/null` &&
test "$len" -le "$max_cmd_len"; }; then
objlist="$objlist $obj"
else
@@ -3795,9 +4125,9 @@ EOF
# the last one created.
eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\"
fi
- last_robj=$output_objdir/$save_output-${k}.$objext
+ last_robj=$output_objdir/$output_la-${k}.$objext
k=`expr $k + 1`
- output=$output_objdir/$save_output-${k}.$objext
+ output=$output_objdir/$output_la-${k}.$objext
objlist=$obj
len=1
fi
@@ -3817,13 +4147,13 @@ EOF
eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\"
fi
- # Set up a command to remove the reloadale object files
+ # Set up a command to remove the reloadable object files
# after they are used.
i=0
while test "$i" -lt "$k"
do
i=`expr $i + 1`
- delfiles="$delfiles $output_objdir/$save_output-${i}.$objext"
+ delfiles="$delfiles $output_objdir/$output_la-${i}.$objext"
done
$echo "creating a temporary reloadable object file: $output"
@@ -3832,7 +4162,6 @@ EOF
save_ifs="$IFS"; IFS='~'
for cmd in $concat_cmds; do
IFS="$save_ifs"
- eval cmd=\"$cmd\"
$show "$cmd"
$run eval "$cmd" || exit $?
done
@@ -3872,14 +4201,31 @@ EOF
IFS="$save_ifs"
eval cmd=\"$cmd\"
$show "$cmd"
- $run eval "$cmd" || exit $?
+ $run eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)'
+ fi
+
+ exit $lt_exit
+ }
done
IFS="$save_ifs"
# Restore the uninstalled library and exit
if test "$mode" = relink; then
$run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $?
- exit 0
+
+ if test -n "$convenience"; then
+ if test -z "$whole_archive_flag_spec"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ fi
+ fi
+
+ exit $EXIT_SUCCESS
fi
# Create links to the real library.
@@ -3927,7 +4273,7 @@ EOF
*.lo)
if test -n "$objs$old_deplibs"; then
$echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
libobj="$output"
obj=`$echo "X$output" | $Xsed -e "$lo2o"`
@@ -3956,64 +4302,10 @@ EOF
eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\"
else
gentop="$output_objdir/${obj}x"
- $show "${rm}r $gentop"
- $run ${rm}r "$gentop"
- $show "$mkdir $gentop"
- $run $mkdir "$gentop"
- status=$?
- if test "$status" -ne 0 && test ! -d "$gentop"; then
- exit $status
- fi
generated="$generated $gentop"
- for xlib in $convenience; do
- # Extract the objects.
- case $xlib in
- [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
- *) xabs=`pwd`"/$xlib" ;;
- esac
- xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
- xdir="$gentop/$xlib"
-
- $show "${rm}r $xdir"
- $run ${rm}r "$xdir"
- $show "$mkdir $xdir"
- $run $mkdir "$xdir"
- status=$?
- if test "$status" -ne 0 && test ! -d "$xdir"; then
- exit $status
- fi
- # We will extract separately just the conflicting names and we will no
- # longer touch any unique names. It is faster to leave these extract
- # automatically by $AR in one run.
- $show "(cd $xdir && $AR x $xabs)"
- $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
- if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then
- :
- else
- $echo "$modename: warning: object name conflicts; renaming object files" 1>&2
- $echo "$modename: warning: to ensure that they will not overwrite" 1>&2
- $AR t "$xabs" | sort | uniq -cd | while read -r count name
- do
- i=1
- while test "$i" -le "$count"
- do
- # Put our $i before any first dot (extension)
- # Never overwrite any file
- name_to="$name"
- while test "X$name_to" = "X$name" || test -f "$xdir/$name_to"
- do
- name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"`
- done
- $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')"
- $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $?
- i=`expr $i + 1`
- done
- done
- fi
-
- reload_conv_objs="$reload_objs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
- done
+ func_extract_archives $gentop $convenience
+ reload_conv_objs="$reload_objs $func_extract_archives_result"
fi
fi
@@ -4038,7 +4330,7 @@ EOF
$run ${rm}r $gentop
fi
- exit 0
+ exit $EXIT_SUCCESS
fi
if test "$build_libtool_libs" != yes; then
@@ -4051,7 +4343,7 @@ EOF
# accidentally link it into a program.
# $show "echo timestamp > $libobj"
# $run eval "echo timestamp > $libobj" || exit $?
- exit 0
+ exit $EXIT_SUCCESS
fi
if test -n "$pic_flag" || test "$pic_mode" != default; then
@@ -4074,7 +4366,7 @@ EOF
$run ${rm}r $gentop
fi
- exit 0
+ exit $EXIT_SUCCESS
;;
prog)
@@ -4114,6 +4406,35 @@ EOF
;;
esac
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $compile_deplibs " in
+ *" -L$path/$objdir "*)
+ new_libs="$new_libs -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $compile_deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ done
+ compile_deplibs="$new_libs"
+
+
compile_command="$compile_command $compile_deplibs"
finalize_command="$finalize_command $finalize_deplibs"
@@ -4158,10 +4479,15 @@ EOF
fi
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ testbindir=`$echo "X$libdir" | $Xsed -e 's*/lib$*/bin*'`
case :$dllsearchpath: in
*":$libdir:"*) ;;
*) dllsearchpath="$dllsearchpath:$libdir";;
esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$testbindir";;
+ esac
;;
esac
done
@@ -4275,13 +4601,25 @@ extern \"C\" {
# Prepare the list of exported symbols
if test -z "$export_symbols"; then
- export_symbols="$output_objdir/$output.exp"
+ export_symbols="$output_objdir/$outputname.exp"
$run $rm $export_symbols
- $run eval "${SED} -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ $run eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ case $host in
+ *cygwin* | *mingw* )
+ $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ $run eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
else
- $run eval "${SED} -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"'
- $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T'
+ $run eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+ $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
$run eval 'mv "$nlist"T "$nlist"'
+ case $host in
+ *cygwin* | *mingw* )
+ $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ $run eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
fi
fi
@@ -4332,7 +4670,26 @@ extern \"C\" {
#endif
/* The mapping between symbol names and symbols. */
+"
+
+ case $host in
+ *cygwin* | *mingw* )
+ $echo >> "$output_objdir/$dlsyms" "\
+/* DATA imports from DLLs on WIN32 can't be const, because
+ runtime relocations are performed -- see ld's documentation
+ on pseudo-relocs */
+struct {
+"
+ ;;
+ * )
+ $echo >> "$output_objdir/$dlsyms" "\
const struct {
+"
+ ;;
+ esac
+
+
+ $echo >> "$output_objdir/$dlsyms" "\
const char *name;
lt_ptr address;
}
@@ -4379,20 +4736,33 @@ static const void *lt_preloaded_setup() {
esac
# Now compile the dynamic symbol file.
- $show "(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
- $run eval '(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
+ $show "(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
+ $run eval '(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
# Clean up the generated files.
$show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T"
$run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T"
# Transform the symbol file into the correct name.
- compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
- finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ case $host in
+ *cygwin* | *mingw* )
+ if test -f "$output_objdir/${outputname}.def" ; then
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%"`
+ else
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ fi
+ ;;
+ * )
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ ;;
+ esac
;;
*)
$echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
esac
else
@@ -4413,7 +4783,7 @@ static const void *lt_preloaded_setup() {
# We have no uninstalled library dependencies, so finalize right now.
$show "$link_command"
$run eval "$link_command"
- status=$?
+ exit_status=$?
# Delete the generated files.
if test -n "$dlsyms"; then
@@ -4421,7 +4791,7 @@ static const void *lt_preloaded_setup() {
$run $rm "$output_objdir/${outputname}S.${objext}"
fi
- exit $status
+ exit $exit_status
fi
if test -n "$shlibpath_var"; then
@@ -4480,7 +4850,7 @@ static const void *lt_preloaded_setup() {
# Link the executable and exit
$show "$link_command"
$run eval "$link_command" || exit $?
- exit 0
+ exit $EXIT_SUCCESS
fi
if test "$hardcode_action" = relink; then
@@ -4535,10 +4905,10 @@ static const void *lt_preloaded_setup() {
fi
# Quote $echo for shipping.
- if test "X$echo" = "X$SHELL $0 --fallback-echo"; then
- case $0 in
- [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";;
- *) qecho="$SHELL `pwd`/$0 --fallback-echo";;
+ if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then
+ case $progpath in
+ [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";;
+ *) qecho="$SHELL `pwd`/$progpath --fallback-echo";;
esac
qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"`
else
@@ -4561,10 +4931,12 @@ static const void *lt_preloaded_setup() {
esac
case $host in
*cygwin* | *mingw* )
- cwrappersource=`$echo ${objdir}/lt-${output}.c`
- cwrapper=`$echo ${output}.exe`
- $rm $cwrappersource $cwrapper
- trap "$rm $cwrappersource $cwrapper; exit 1" 1 2 15
+ output_name=`basename $output`
+ output_path=`dirname $output`
+ cwrappersource="$output_path/$objdir/lt-$output_name.c"
+ cwrapper="$output_path/$output_name.exe"
+ $rm $cwrappersource $cwrapper
+ trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
cat > $cwrappersource <<EOF
@@ -4573,7 +4945,7 @@ static const void *lt_preloaded_setup() {
The $output program cannot be directly executed until all the libtool
libraries that it depends on are installed.
-
+
This wrapper executable should never be moved out of the build directory.
If it is, it will not operate correctly.
@@ -4589,6 +4961,9 @@ EOF
#include <malloc.h>
#include <stdarg.h>
#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/stat.h>
#if defined(PATH_MAX)
# define LT_PATHMAX PATH_MAX
@@ -4599,15 +4974,19 @@ EOF
#endif
#ifndef DIR_SEPARATOR
-#define DIR_SEPARATOR '/'
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
#endif
#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
defined (__OS2__)
-#define HAVE_DOS_BASED_FILE_SYSTEM
-#ifndef DIR_SEPARATOR_2
-#define DIR_SEPARATOR_2 '\\'
-#endif
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# ifndef DIR_SEPARATOR_2
+# define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+# define PATH_SEPARATOR_2 ';'
+# endif
#endif
#ifndef DIR_SEPARATOR_2
@@ -4617,17 +4996,32 @@ EOF
(((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
#endif /* DIR_SEPARATOR_2 */
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
#define XFREE(stale) do { \
if (stale) { free ((void *) stale); stale = 0; } \
} while (0)
+/* -DDEBUG is fairly common in CFLAGS. */
+#undef DEBUG
+#if defined DEBUGWRAPPER
+# define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__)
+#else
+# define DEBUG(format, ...)
+#endif
+
const char *program_name = NULL;
void * xmalloc (size_t num);
char * xstrdup (const char *string);
-char * basename (const char *name);
-char * fnqualify(const char *path);
+const char * base_name (const char *name);
+char * find_executable(const char *wrapper);
+int check_executable(const char *path);
char * strendzap(char *str, const char *pat);
void lt_fatal (const char *message, ...);
@@ -4636,30 +5030,52 @@ main (int argc, char *argv[])
{
char **newargz;
int i;
-
- program_name = (char *) xstrdup ((char *) basename (argv[0]));
+
+ program_name = (char *) xstrdup (base_name (argv[0]));
+ DEBUG("(main) argv[0] : %s\n",argv[0]);
+ DEBUG("(main) program_name : %s\n",program_name);
newargz = XMALLOC(char *, argc+2);
EOF
- cat >> $cwrappersource <<EOF
- newargz[0] = "$SHELL";
+ cat >> $cwrappersource <<EOF
+ newargz[0] = (char *) xstrdup("$SHELL");
EOF
- cat >> $cwrappersource <<"EOF"
- newargz[1] = fnqualify(argv[0]);
+ cat >> $cwrappersource <<"EOF"
+ newargz[1] = find_executable(argv[0]);
+ if (newargz[1] == NULL)
+ lt_fatal("Couldn't find %s", argv[0]);
+ DEBUG("(main) found exe at : %s\n",newargz[1]);
/* we know the script has the same name, without the .exe */
/* so make sure newargz[1] doesn't end in .exe */
- strendzap(newargz[1],".exe");
+ strendzap(newargz[1],".exe");
for (i = 1; i < argc; i++)
newargz[i+1] = xstrdup(argv[i]);
newargz[argc+1] = NULL;
+
+ for (i=0; i<argc+1; i++)
+ {
+ DEBUG("(main) newargz[%d] : %s\n",i,newargz[i]);
+ ;
+ }
+
EOF
- cat >> $cwrappersource <<EOF
+ case $host_os in
+ mingw*)
+ cat >> $cwrappersource <<EOF
+ execv("$SHELL",(char const **)newargz);
+EOF
+ ;;
+ *)
+ cat >> $cwrappersource <<EOF
execv("$SHELL",newargz);
EOF
+ ;;
+ esac
- cat >> $cwrappersource <<"EOF"
+ cat >> $cwrappersource <<"EOF"
+ return 127;
}
void *
@@ -4672,59 +5088,159 @@ xmalloc (size_t num)
return p;
}
-char *
+char *
xstrdup (const char *string)
{
return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL
;
}
-char *
-basename (const char *name)
+const char *
+base_name (const char *name)
{
const char *base;
#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
/* Skip over the disk name in MSDOS pathnames. */
- if (isalpha (name[0]) && name[1] == ':')
+ if (isalpha ((unsigned char)name[0]) && name[1] == ':')
name += 2;
#endif
for (base = name; *name; name++)
if (IS_DIR_SEPARATOR (*name))
base = name + 1;
- return (char *) base;
+ return base;
}
-char *
-fnqualify(const char *path)
+int
+check_executable(const char * path)
{
- size_t size;
- char *p;
+ struct stat st;
+
+ DEBUG("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!");
+ if ((!path) || (!*path))
+ return 0;
+
+ if ((stat (path, &st) >= 0) &&
+ (
+ /* MinGW & native WIN32 do not support S_IXOTH or S_IXGRP */
+#if defined (S_IXOTH)
+ ((st.st_mode & S_IXOTH) == S_IXOTH) ||
+#endif
+#if defined (S_IXGRP)
+ ((st.st_mode & S_IXGRP) == S_IXGRP) ||
+#endif
+ ((st.st_mode & S_IXUSR) == S_IXUSR))
+ )
+ return 1;
+ else
+ return 0;
+}
+
+/* Searches for the full path of the wrapper. Returns
+ newly allocated full path name if found, NULL otherwise */
+char *
+find_executable (const char* wrapper)
+{
+ int has_slash = 0;
+ const char* p;
+ const char* p_next;
+ /* static buffer for getcwd */
char tmp[LT_PATHMAX + 1];
+ int tmp_len;
+ char* concat_name;
- assert(path != NULL);
+ DEBUG("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!");
- /* Is it qualified already? */
+ if ((wrapper == NULL) || (*wrapper == '\0'))
+ return NULL;
+
+ /* Absolute path? */
#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
- if (isalpha (path[0]) && path[1] == ':')
- return xstrdup (path);
+ if (isalpha ((unsigned char)wrapper[0]) && wrapper[1] == ':')
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable(concat_name))
+ return concat_name;
+ XFREE(concat_name);
+ }
+ else
+ {
+#endif
+ if (IS_DIR_SEPARATOR (wrapper[0]))
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable(concat_name))
+ return concat_name;
+ XFREE(concat_name);
+ }
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ }
#endif
- if (IS_DIR_SEPARATOR (path[0]))
- return xstrdup (path);
- /* prepend the current directory */
- /* doesn't handle '~' */
+ for (p = wrapper; *p; p++)
+ if (*p == '/')
+ {
+ has_slash = 1;
+ break;
+ }
+ if (!has_slash)
+ {
+ /* no slashes; search PATH */
+ const char* path = getenv ("PATH");
+ if (path != NULL)
+ {
+ for (p = path; *p; p = p_next)
+ {
+ const char* q;
+ size_t p_len;
+ for (q = p; *q; q++)
+ if (IS_PATH_SEPARATOR(*q))
+ break;
+ p_len = q - p;
+ p_next = (*q == '\0' ? q : q + 1);
+ if (p_len == 0)
+ {
+ /* empty path: current directory */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal ("getcwd failed");
+ tmp_len = strlen(tmp);
+ concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+ }
+ else
+ {
+ concat_name = XMALLOC(char, p_len + 1 + strlen(wrapper) + 1);
+ memcpy (concat_name, p, p_len);
+ concat_name[p_len] = '/';
+ strcpy (concat_name + p_len + 1, wrapper);
+ }
+ if (check_executable(concat_name))
+ return concat_name;
+ XFREE(concat_name);
+ }
+ }
+ /* not found in PATH; assume curdir */
+ }
+ /* Relative path | not found in path: prepend cwd */
if (getcwd (tmp, LT_PATHMAX) == NULL)
lt_fatal ("getcwd failed");
- size = strlen(tmp) + 1 + strlen(path) + 1; /* +2 for '/' and '\0' */
- p = XMALLOC(char, size);
- sprintf(p, "%s%c%s", tmp, DIR_SEPARATOR, path);
- return p;
+ tmp_len = strlen(tmp);
+ concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+
+ if (check_executable(concat_name))
+ return concat_name;
+ XFREE(concat_name);
+ return NULL;
}
char *
-strendzap(char *str, const char *pat)
+strendzap(char *str, const char *pat)
{
size_t len, patlen;
@@ -4744,7 +5260,7 @@ strendzap(char *str, const char *pat)
}
static void
-lt_error_core (int exit_status, const char * mode,
+lt_error_core (int exit_status, const char * mode,
const char * message, va_list ap)
{
fprintf (stderr, "%s: %s: ", program_name, mode);
@@ -4764,16 +5280,16 @@ lt_fatal (const char *message, ...)
va_end (ap);
}
EOF
- # we should really use a build-platform specific compiler
- # here, but OTOH, the wrappers (shell script and this C one)
- # are only useful if you want to execute the "real" binary.
- # Since the "real" binary is built for $host, then this
- # wrapper might as well be built for $host, too.
- $run $LTCC -s -o $cwrapper $cwrappersource
- ;;
- esac
- $rm $output
- trap "$rm $output; exit 1" 1 2 15
+ # we should really use a build-platform specific compiler
+ # here, but OTOH, the wrappers (shell script and this C one)
+ # are only useful if you want to execute the "real" binary.
+ # Since the "real" binary is built for $host, then this
+ # wrapper might as well be built for $host, too.
+ $run $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource
+ ;;
+ esac
+ $rm $output
+ trap "$rm $output; exit $EXIT_FAILURE" 1 2 15
$echo > $output "\
#! $SHELL
@@ -4794,7 +5310,7 @@ sed_quote_subst='$sed_quote_subst'
# The HP-UX ksh and POSIX shell print the target directory to stdout
# if CDPATH is set.
-if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
relink_command=\"$relink_command\"
@@ -4873,7 +5389,7 @@ else
else
$echo \"\$relink_command_output\" >&2
$rm \"\$progdir/\$file\"
- exit 1
+ exit $EXIT_FAILURE
fi
fi
@@ -4918,37 +5434,42 @@ else
$echo >> $output "\
if test \"\$libtool_execute_magic\" != \"$magic\"; then
# Run the actual program with our arguments.
+
+ # Make sure env LD_LIBRARY_PATH does not mess us up
+ if test -n \"\${LD_LIBRARY_PATH+set}\"; then
+ export LD_LIBRARY_PATH=\$progdir:\$LD_LIBRARY_PATH
+ fi
"
case $host in
# Backslashes separate directories on plain windows
*-*-mingw | *-*-os2*)
$echo >> $output "\
- exec \$progdir\\\\\$program \${1+\"\$@\"}
+ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
"
;;
*)
$echo >> $output "\
- exec \$progdir/\$program \${1+\"\$@\"}
+ exec \"\$progdir/\$program\" \${1+\"\$@\"}
"
;;
esac
$echo >> $output "\
\$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\"
- exit 1
+ exit $EXIT_FAILURE
fi
else
# The program doesn't exist.
- \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2
+ \$echo \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
\$echo \"This script is just a wrapper for \$program.\" 1>&2
$echo \"See the $PACKAGE documentation for more information.\" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
fi\
"
chmod +x $output
fi
- exit 0
+ exit $EXIT_SUCCESS
;;
esac
@@ -4971,71 +5492,73 @@ fi\
if test -n "$addlibs"; then
gentop="$output_objdir/${outputname}x"
- $show "${rm}r $gentop"
- $run ${rm}r "$gentop"
- $show "$mkdir $gentop"
- $run $mkdir "$gentop"
- status=$?
- if test "$status" -ne 0 && test ! -d "$gentop"; then
- exit $status
- fi
generated="$generated $gentop"
- # Add in members from convenience archives.
- for xlib in $addlibs; do
- # Extract the objects.
- case $xlib in
- [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
- *) xabs=`pwd`"/$xlib" ;;
- esac
- xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
- xdir="$gentop/$xlib"
-
- $show "${rm}r $xdir"
- $run ${rm}r "$xdir"
- $show "$mkdir $xdir"
- $run $mkdir "$xdir"
- status=$?
- if test "$status" -ne 0 && test ! -d "$xdir"; then
- exit $status
- fi
- # We will extract separately just the conflicting names and we will no
- # longer touch any unique names. It is faster to leave these extract
- # automatically by $AR in one run.
- $show "(cd $xdir && $AR x $xabs)"
- $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
- if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then
- :
- else
- $echo "$modename: warning: object name conflicts; renaming object files" 1>&2
- $echo "$modename: warning: to ensure that they will not overwrite" 1>&2
- $AR t "$xabs" | sort | uniq -cd | while read -r count name
- do
- i=1
- while test "$i" -le "$count"
- do
- # Put our $i before any first dot (extension)
- # Never overwrite any file
- name_to="$name"
- while test "X$name_to" = "X$name" || test -f "$xdir/$name_to"
- do
- name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"`
- done
- $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')"
- $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $?
- i=`expr $i + 1`
- done
- done
- fi
-
- oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP`
- done
+ func_extract_archives $gentop $addlibs
+ oldobjs="$oldobjs $func_extract_archives_result"
fi
# Do each command in the archive commands.
if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
cmds=$old_archive_from_new_cmds
else
+ # POSIX demands no paths to be encoded in archives. We have
+ # to avoid creating archives with duplicate basenames if we
+ # might have to extract them afterwards, e.g., when creating a
+ # static archive out of a convenience library, or when linking
+ # the entirety of a libtool archive into another (currently
+ # not supported by libtool).
+ if (for obj in $oldobjs
+ do
+ $echo "X$obj" | $Xsed -e 's%^.*/%%'
+ done | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "copying selected object files to avoid basename conflicts..."
+
+ if test -z "$gentop"; then
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "$mkdir $gentop"
+ $run $mkdir "$gentop"
+ exit_status=$?
+ if test "$exit_status" -ne 0 && test ! -d "$gentop"; then
+ exit $exit_status
+ fi
+ fi
+
+ save_oldobjs=$oldobjs
+ oldobjs=
+ counter=1
+ for obj in $save_oldobjs
+ do
+ objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
+ case " $oldobjs " in
+ " ") oldobjs=$obj ;;
+ *[\ /]"$objbase "*)
+ while :; do
+ # Make sure we don't pick an alternate name that also
+ # overlaps.
+ newobj=lt$counter-$objbase
+ counter=`expr $counter + 1`
+ case " $oldobjs " in
+ *[\ /]"$newobj "*) ;;
+ *) if test ! -f "$gentop/$newobj"; then break; fi ;;
+ esac
+ done
+ $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+ $run ln "$obj" "$gentop/$newobj" ||
+ $run cp "$obj" "$gentop/$newobj"
+ oldobjs="$oldobjs $gentop/$newobj"
+ ;;
+ *) oldobjs="$oldobjs $obj" ;;
+ esac
+ done
+ fi
+
eval cmds=\"$old_archive_cmds\"
if len=`expr "X$cmds" : ".*"` &&
@@ -5049,31 +5572,18 @@ fi\
objlist=
concat_cmds=
save_oldobjs=$oldobjs
- # GNU ar 2.10+ was changed to match POSIX; thus no paths are
- # encoded into archives. This makes 'ar r' malfunction in
- # this piecewise linking case whenever conflicting object
- # names appear in distinct ar calls; check, warn and compensate.
- if (for obj in $save_oldobjs
- do
- $echo "X$obj" | $Xsed -e 's%^.*/%%'
- done | sort | sort -uc >/dev/null 2>&1); then
- :
- else
- $echo "$modename: warning: object name conflicts; overriding AR_FLAGS to 'cq'" 1>&2
- $echo "$modename: warning: to ensure that POSIX-compatible ar will work" 1>&2
- AR_FLAGS=cq
- fi
+
# Is there a better way of finding the last object in the list?
for obj in $save_oldobjs
do
last_oldobj=$obj
- done
+ done
for obj in $save_oldobjs
do
oldobjs="$objlist $obj"
objlist="$objlist $obj"
eval test_cmds=\"$old_archive_cmds\"
- if len=`expr "X$test_cmds" : ".*"` &&
+ if len=`expr "X$test_cmds" : ".*" 2>/dev/null` &&
test "$len" -le "$max_cmd_len"; then
:
else
@@ -5081,7 +5591,7 @@ fi\
oldobjs=$objlist
if test "$obj" = "$last_oldobj" ; then
RANLIB=$save_RANLIB
- fi
+ fi
test -z "$concat_cmds" || concat_cmds=$concat_cmds~
eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
objlist=
@@ -5130,11 +5640,13 @@ fi\
fi
done
# Quote the link command for shipping.
- relink_command="(cd `pwd`; $SHELL $0 $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+ relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
if test "$hardcode_automatic" = yes ; then
- relink_command=
- fi
+ relink_command=
+ fi
+
+
# Only create the output if not a dry run.
if test -z "$run"; then
for installed in no yes; do
@@ -5152,11 +5664,55 @@ fi\
eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
if test -z "$libdir"; then
$echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
- exit 1
+ exit $EXIT_FAILURE
+ fi
+ if test "X$EGREP" = X ; then
+ EGREP=egrep
+ fi
+ # We do not want portage's install root ($D) present. Check only for
+ # this if the .la is being installed.
+ if test "$installed" = yes && test "$D"; then
+ eval mynewdependency_lib=`echo "$libdir/$name" |sed -e "s:$D:/:g" -e 's:/\+:/:g'`
+ else
+ mynewdependency_lib="$libdir/$name"
+ fi
+ # Do not add duplicates
+ if test "$mynewdependency_lib"; then
+ my_little_ninja_foo_1=`echo $newdependency_libs |$EGREP -e "$mynewdependency_lib"`
+ if test -z "$my_little_ninja_foo_1"; then
+ newdependency_libs="$newdependency_libs $mynewdependency_lib"
+ fi
+ fi
+ ;;
+ *)
+ if test "$installed" = yes; then
+ # Rather use S=WORKDIR if our version of portage supports it.
+ # This is because some ebuild (gcc) do not use $S as buildroot.
+ if test "$PWORKDIR"; then
+ S="$PWORKDIR"
+ fi
+ # We do not want portage's build root ($S) present.
+ my_little_ninja_foo_2=`echo $deplib |$EGREP -e "$S"`
+ # We do not want portage's install root ($D) present.
+ my_little_ninja_foo_3=`echo $deplib |$EGREP -e "$D"`
+ if test -n "$my_little_ninja_foo_2" && test "$S"; then
+ mynewdependency_lib=""
+ elif test -n "$my_little_ninja_foo_3" && test "$D"; then
+ eval mynewdependency_lib=`echo "$deplib" |sed -e "s:$D:/:g" -e 's:/\+:/:g'`
+ else
+ mynewdependency_lib="$deplib"
+ fi
+ else
+ mynewdependency_lib="$deplib"
+ fi
+ # Do not add duplicates
+ if test "$mynewdependency_lib"; then
+ my_little_ninja_foo_4=`echo $newdependency_libs |$EGREP -e "$mynewdependency_lib"`
+ if test -z "$my_little_ninja_foo_4"; then
+ newdependency_libs="$newdependency_libs $mynewdependency_lib"
+ fi
fi
- newdependency_libs="$newdependency_libs $libdir/$name"
;;
- *) newdependency_libs="$newdependency_libs $deplib" ;;
esac
done
dependency_libs="$newdependency_libs"
@@ -5166,7 +5722,7 @@ fi\
eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
if test -z "$libdir"; then
$echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
newdlfiles="$newdlfiles $libdir/$name"
done
@@ -5177,7 +5733,7 @@ fi\
eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
if test -z "$libdir"; then
$echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
newdlprefiles="$newdlprefiles $libdir/$name"
done
@@ -5185,7 +5741,7 @@ fi\
else
newdlfiles=
for lib in $dlfiles; do
- case $lib in
+ case $lib in
[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
*) abs=`pwd`"/$lib" ;;
esac
@@ -5194,7 +5750,7 @@ fi\
dlfiles="$newdlfiles"
newdlprefiles=
for lib in $dlprefiles; do
- case $lib in
+ case $lib in
[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
*) abs=`pwd`"/$lib" ;;
esac
@@ -5208,6 +5764,10 @@ fi\
case $host,$output,$installed,$module,$dlname in
*cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
esac
+ # Do not add duplicates
+ if test "$installed" = yes && test "$D"; then
+ install_libdir=`echo "$install_libdir" |sed -e "s:$D:/:g" -e 's:/\+:/:g'`
+ fi
$echo > $output "\
# $outputname - a libtool library file
# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
@@ -5257,7 +5817,7 @@ relink_command=\"$relink_command\""
$run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $?
;;
esac
- exit 0
+ exit $EXIT_SUCCESS
;;
# libtool install mode
@@ -5268,11 +5828,11 @@ relink_command=\"$relink_command\""
# install_prog (especially on Windows NT).
if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
# Allow the use of GNU shtool's install command.
- $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then
+ $echo "X$nonopt" | grep shtool > /dev/null; then
# Aesthetically quote it.
arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
arg="\"$arg\""
;;
esac
@@ -5281,14 +5841,14 @@ relink_command=\"$relink_command\""
shift
else
install_prog=
- arg="$nonopt"
+ arg=$nonopt
fi
# The real first argument should be the name of the installation program.
# Aesthetically quote it.
arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
arg="\"$arg\""
;;
esac
@@ -5306,28 +5866,31 @@ relink_command=\"$relink_command\""
do
if test -n "$dest"; then
files="$files $dest"
- dest="$arg"
+ dest=$arg
continue
fi
case $arg in
-d) isdir=yes ;;
- -f) prev="-f" ;;
- -g) prev="-g" ;;
- -m) prev="-m" ;;
- -o) prev="-o" ;;
+ -f)
+ case " $install_prog " in
+ *[\\\ /]cp\ *) ;;
+ *) prev=$arg ;;
+ esac
+ ;;
+ -g | -m | -o) prev=$arg ;;
-s)
stripme=" -s"
continue
;;
- -*) ;;
-
+ -*)
+ ;;
*)
# If the previous option needed an argument, then skip it.
if test -n "$prev"; then
prev=
else
- dest="$arg"
+ dest=$arg
continue
fi
;;
@@ -5336,7 +5899,7 @@ relink_command=\"$relink_command\""
# Aesthetically quote the argument.
arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
arg="\"$arg\""
;;
esac
@@ -5346,13 +5909,13 @@ relink_command=\"$relink_command\""
if test -z "$install_prog"; then
$echo "$modename: you must specify an install program" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
if test -n "$prev"; then
$echo "$modename: the \`$prev' option requires an argument" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
if test -z "$files"; then
@@ -5362,7 +5925,7 @@ relink_command=\"$relink_command\""
$echo "$modename: you must specify a destination" 1>&2
fi
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
# Strip any trailing slash from the destination.
@@ -5383,7 +5946,7 @@ relink_command=\"$relink_command\""
if test "$#" -gt 2; then
$echo "$modename: \`$dest' is not a directory" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
fi
case $destdir in
@@ -5395,7 +5958,7 @@ relink_command=\"$relink_command\""
*)
$echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
esac
done
@@ -5424,7 +5987,7 @@ relink_command=\"$relink_command\""
else
$echo "$modename: \`$file' is not a valid libtool archive" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
library_names=
@@ -5466,7 +6029,7 @@ relink_command=\"$relink_command\""
# but it's something to keep an eye on.
if test "$inst_prefix_dir" = "$destdir"; then
$echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
if test -n "$inst_prefix_dir"; then
@@ -5481,7 +6044,7 @@ relink_command=\"$relink_command\""
if $run eval "$relink_command"; then :
else
$echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
fi
@@ -5505,11 +6068,14 @@ relink_command=\"$relink_command\""
if test "$#" -gt 0; then
# Delete the old symlinks, and create new ones.
+ # Try `ln -sf' first, because the `ln' binary might depend on
+ # the symlink we replace! Solaris /bin/ln does not understand -f,
+ # so we also need to try rm && ln -s.
for linkname
do
if test "$linkname" != "$realname"; then
- $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
- $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+ $show "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })"
+ $run eval "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })"
fi
done
fi
@@ -5522,7 +6088,16 @@ relink_command=\"$relink_command\""
IFS="$save_ifs"
eval cmd=\"$cmd\"
$show "$cmd"
- $run eval "$cmd" || exit $?
+ $run eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)'
+ fi
+
+ exit $lt_exit
+ }
done
IFS="$save_ifs"
fi
@@ -5560,7 +6135,7 @@ relink_command=\"$relink_command\""
*)
$echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
esac
@@ -5578,7 +6153,7 @@ relink_command=\"$relink_command\""
$show "$install_prog $staticobj $staticdest"
$run eval "$install_prog \$staticobj \$staticdest" || exit $?
fi
- exit 0
+ exit $EXIT_SUCCESS
;;
*)
@@ -5616,23 +6191,21 @@ relink_command=\"$relink_command\""
notinst_deplibs=
relink_command=
- # To insure that "foo" is sourced, and not "foo.exe",
- # finese the cygwin/MSYS system by explicitly sourcing "foo."
- # which disallows the automatic-append-.exe behavior.
- case $build in
- *cygwin* | *mingw*) wrapperdot=${wrapper}. ;;
- *) wrapperdot=${wrapper} ;;
- esac
+ # Note that it is not necessary on cygwin/mingw to append a dot to
+ # foo even if both foo and FILE.exe exist: automatic-append-.exe
+ # behavior happens only for exec(3), not for open(2)! Also, sourcing
+ # `FILE.' does not work on cygwin managed mounts.
+ #
# If there is no directory component, then add one.
- case $file in
- */* | *\\*) . ${wrapperdot} ;;
- *) . ./${wrapperdot} ;;
+ case $wrapper in
+ */* | *\\*) . ${wrapper} ;;
+ *) . ./${wrapper} ;;
esac
# Check the variables that should have been set.
if test -z "$notinst_deplibs"; then
$echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
finalize=yes
@@ -5654,30 +6227,21 @@ relink_command=\"$relink_command\""
done
relink_command=
- # To insure that "foo" is sourced, and not "foo.exe",
- # finese the cygwin/MSYS system by explicitly sourcing "foo."
- # which disallows the automatic-append-.exe behavior.
- case $build in
- *cygwin* | *mingw*) wrapperdot=${wrapper}. ;;
- *) wrapperdot=${wrapper} ;;
- esac
+ # Note that it is not necessary on cygwin/mingw to append a dot to
+ # foo even if both foo and FILE.exe exist: automatic-append-.exe
+ # behavior happens only for exec(3), not for open(2)! Also, sourcing
+ # `FILE.' does not work on cygwin managed mounts.
+ #
# If there is no directory component, then add one.
- case $file in
- */* | *\\*) . ${wrapperdot} ;;
- *) . ./${wrapperdot} ;;
+ case $wrapper in
+ */* | *\\*) . ${wrapper} ;;
+ *) . ./${wrapper} ;;
esac
outputname=
if test "$fast_install" = no && test -n "$relink_command"; then
if test "$finalize" = yes && test -z "$run"; then
- tmpdir="/tmp"
- test -n "$TMPDIR" && tmpdir="$TMPDIR"
- tmpdir="$tmpdir/libtool-$$"
- if $mkdir "$tmpdir" && chmod 700 "$tmpdir"; then :
- else
- $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2
- continue
- fi
+ tmpdir=`func_mktempdir`
file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'`
outputname="$tmpdir/$file"
# Replace the output file specification.
@@ -5701,7 +6265,7 @@ relink_command=\"$relink_command\""
fi
# remove .exe since cygwin /usr/bin/install will append another
- # one anyways
+ # one anyway
case $install_prog,$host in
*/usr/bin/install*,*cygwin*)
case $file:$destfile in
@@ -5757,9 +6321,9 @@ relink_command=\"$relink_command\""
if test -n "$current_libdirs"; then
# Maybe just do a dry run.
test -n "$run" && current_libdirs=" -n$current_libdirs"
- exec_cmd='$SHELL $0 $preserve_args --finish$current_libdirs'
+ exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
else
- exit 0
+ exit $EXIT_SUCCESS
fi
;;
@@ -5799,9 +6363,9 @@ relink_command=\"$relink_command\""
fi
# Exit here if they wanted silent mode.
- test "$show" = : && exit 0
+ test "$show" = : && exit $EXIT_SUCCESS
- $echo "----------------------------------------------------------------------"
+ $echo "X----------------------------------------------------------------------" | $Xsed
$echo "Libraries have been installed in:"
for libdir in $libdirs; do
$echo " $libdir"
@@ -5834,8 +6398,8 @@ relink_command=\"$relink_command\""
$echo
$echo "See any operating system documentation about shared libraries for"
$echo "more information, such as the ld(1) and ld.so(8) manual pages."
- $echo "----------------------------------------------------------------------"
- exit 0
+ $echo "X----------------------------------------------------------------------" | $Xsed
+ exit $EXIT_SUCCESS
;;
# libtool execute mode
@@ -5847,7 +6411,7 @@ relink_command=\"$relink_command\""
if test -z "$cmd"; then
$echo "$modename: you must specify a COMMAND" 1>&2
$echo "$help"
- exit 1
+ exit $EXIT_FAILURE
fi
# Handle -dlopen flags immediately.
@@ -5855,7 +6419,7 @@ relink_command=\"$relink_command\""
if test ! -f "$file"; then
$echo "$modename: \`$file' is not a file" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
dir=
@@ -5866,7 +6430,7 @@ relink_command=\"$relink_command\""
else
$echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
# Read the libtool library.
@@ -5893,7 +6457,7 @@ relink_command=\"$relink_command\""
dir="$dir/$objdir"
else
$echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
;;
@@ -5973,7 +6537,7 @@ relink_command=\"$relink_command\""
$echo "export $shlibpath_var"
fi
$echo "$cmd$args"
- exit 0
+ exit $EXIT_SUCCESS
fi
;;
@@ -6001,7 +6565,7 @@ relink_command=\"$relink_command\""
if test -z "$rm"; then
$echo "$modename: you must specify an RM program" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
rmdirs=
@@ -6051,9 +6615,17 @@ relink_command=\"$relink_command\""
rmfiles="$rmfiles $objdir/$n"
done
test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
- test "$mode" = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
- if test "$mode" = uninstall; then
+ case "$mode" in
+ clean)
+ case " $library_names " in
+ # " " in the beginning catches empty $dlname
+ *" $dlname "*) ;;
+ *) rmfiles="$rmfiles $objdir/$dlname" ;;
+ esac
+ test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
+ ;;
+ uninstall)
if test -n "$library_names"; then
# Do each command in the postuninstall commands.
cmds=$postuninstall_cmds
@@ -6086,7 +6658,8 @@ relink_command=\"$relink_command\""
IFS="$save_ifs"
fi
# FIXME: should reinstall the best remaining shared library.
- fi
+ ;;
+ esac
fi
;;
@@ -6115,7 +6688,7 @@ relink_command=\"$relink_command\""
if test "$mode" = clean ; then
noexename=$name
case $file in
- *.exe)
+ *.exe)
file=`$echo $file|${SED} 's,.exe$,,'`
noexename=`$echo $name|${SED} 's,.exe$,,'`
# $file with .exe has already been added to rmfiles,
@@ -6160,20 +6733,20 @@ relink_command=\"$relink_command\""
"")
$echo "$modename: you must specify a MODE" 1>&2
$echo "$generic_help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
esac
if test -z "$exec_cmd"; then
$echo "$modename: invalid operation mode \`$mode'" 1>&2
$echo "$generic_help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
fi
fi # test -z "$show_help"
if test -n "$exec_cmd"; then
eval exec $exec_cmd
- exit 1
+ exit $EXIT_FAILURE
fi
# We need to display help for each of the modes.
@@ -6209,7 +6782,7 @@ MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for
a more detailed description of MODE.
Report bugs to <bug-libtool@gnu.org>."
- exit 0
+ exit $EXIT_SUCCESS
;;
clean)
@@ -6364,14 +6937,14 @@ Otherwise, only FILE itself is deleted using RM."
*)
$echo "$modename: invalid operation mode \`$mode'" 1>&2
$echo "$help" 1>&2
- exit 1
+ exit $EXIT_FAILURE
;;
esac
$echo
$echo "Try \`$modename --help' for more information about other modes."
-exit 0
+exit $?
# The TAGs below are defined such that we never get into a situation
# in which we disable both kinds of libraries. Given conflicting
@@ -6385,12 +6958,11 @@ exit 0
# configuration. But we'll never go from static-only to shared-only.
# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
-build_libtool_libs=no
-build_old_libs=yes
+disable_libs=shared
# ### END LIBTOOL TAG CONFIG: disable-shared
# ### BEGIN LIBTOOL TAG CONFIG: disable-static
-build_old_libs=`case $build_libtool_libs in yes) $echo no;; *) $echo yes;; esac`
+disable_libs=static
# ### END LIBTOOL TAG CONFIG: disable-static
# Local Variables:
diff --git a/ext/pdo_sqlite/sqlite/main.mk b/ext/pdo_sqlite/sqlite/main.mk
index 2653815457..5b1fe53728 100644
--- a/ext/pdo_sqlite/sqlite/main.mk
+++ b/ext/pdo_sqlite/sqlite/main.mk
@@ -9,13 +9,6 @@
# BCC C Compiler and options for use in building executables that
# will run on the platform that is doing the build.
#
-# USLEEP If the target operating system supports the "usleep()" system
-# call, then define the HAVE_USLEEP macro for all C modules.
-#
-# THREADSAFE If you want the SQLite library to be safe for use within a
-# multi-threaded program, then define the following macro
-# appropriately:
-#
# THREADLIB Specify any extra linker options needed to make the library
# thread safe
#
@@ -51,20 +44,40 @@
# This is how we compile
#
-TCCX = $(TCC) $(OPTS) $(THREADSAFE) $(USLEEP) -I. -I$(TOP)/src
+TCCX = $(TCC) $(OPTS) -I. -I$(TOP)/src
# Object files for the SQLite library.
#
-LIBOBJ+= alter.o analyze.o attach.o auth.o btree.o build.o \
+LIBOBJ+= alter.o analyze.o attach.o auth.o btmutex.o btree.o build.o \
callback.o complete.o date.o delete.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 \
+ expr.o fault.o func.o hash.o insert.o journal.o loadext.o \
+ main.o malloc.o mem1.o mem2.o mem3.o mem4.o mutex.o mutex_os2.o \
+ mutex_unix.o mutex_w32.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 \
+ select.o table.o $(TCLOBJ) tokenize.o trigger.o \
update.o util.o vacuum.o \
- vdbe.o vdbeapi.o vdbeaux.o vdbefifo.o vdbemem.o \
+ vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbefifo.o vdbemem.o \
where.o utf.o legacy.o vtab.o
+EXTOBJ = icu.o
+EXTOBJ += fts1.o \
+ fts1_hash.o \
+ fts1_tokenizer1.o \
+ fts1_porter.o
+EXTOBJ += fts2.o \
+ fts2_hash.o \
+ fts2_icu.o \
+ fts2_porter.o \
+ fts2_tokenizer.o \
+ fts2_tokenizer1.o
+EXTOBJ += fts3.o \
+ fts3_hash.o \
+ fts3_icu.o \
+ fts3_porter.o \
+ fts3_tokenizer.o \
+ fts3_tokenizer1.o
+
# All of the source code files.
#
SRC = \
@@ -72,22 +85,38 @@ SRC = \
$(TOP)/src/analyze.c \
$(TOP)/src/attach.c \
$(TOP)/src/auth.c \
+ $(TOP)/src/btmutex.c \
$(TOP)/src/btree.c \
$(TOP)/src/btree.h \
+ $(TOP)/src/btreeInt.h \
$(TOP)/src/build.c \
$(TOP)/src/callback.c \
$(TOP)/src/complete.c \
$(TOP)/src/date.c \
$(TOP)/src/delete.c \
$(TOP)/src/expr.c \
+ $(TOP)/src/fault.c \
$(TOP)/src/func.c \
$(TOP)/src/hash.c \
$(TOP)/src/hash.h \
$(TOP)/src/insert.c \
+ $(TOP)/src/journal.c \
$(TOP)/src/legacy.c \
$(TOP)/src/loadext.c \
$(TOP)/src/main.c \
+ $(TOP)/src/malloc.c \
+ $(TOP)/src/mem1.c \
+ $(TOP)/src/mem2.c \
+ $(TOP)/src/mem3.c \
+ $(TOP)/src/mem4.c \
+ $(TOP)/src/mutex.c \
+ $(TOP)/src/mutex.h \
+ $(TOP)/src/mutex_os2.c \
+ $(TOP)/src/mutex_unix.c \
+ $(TOP)/src/mutex_w32.c \
$(TOP)/src/os.c \
+ $(TOP)/src/os.h \
+ $(TOP)/src/os_common.h \
$(TOP)/src/os_os2.c \
$(TOP)/src/os_unix.c \
$(TOP)/src/os_win.c \
@@ -101,7 +130,9 @@ SRC = \
$(TOP)/src/select.c \
$(TOP)/src/shell.c \
$(TOP)/src/sqlite.h.in \
+ $(TOP)/src/sqlite3ext.h \
$(TOP)/src/sqliteInt.h \
+ $(TOP)/src/sqliteLimit.h \
$(TOP)/src/table.c \
$(TOP)/src/tclsqlite.c \
$(TOP)/src/tokenize.c \
@@ -114,25 +145,61 @@ SRC = \
$(TOP)/src/vdbe.h \
$(TOP)/src/vdbeapi.c \
$(TOP)/src/vdbeaux.c \
+ $(TOP)/src/vdbeblob.c \
$(TOP)/src/vdbefifo.c \
$(TOP)/src/vdbemem.c \
$(TOP)/src/vdbeInt.h \
$(TOP)/src/vtab.c \
$(TOP)/src/where.c
+# Source code for extensions
+#
+SRC += \
+ $(TOP)/ext/fts1/fts1.c \
+ $(TOP)/ext/fts1/fts1.h \
+ $(TOP)/ext/fts1/fts1_hash.c \
+ $(TOP)/ext/fts1/fts1_hash.h \
+ $(TOP)/ext/fts1/fts1_porter.c \
+ $(TOP)/ext/fts1/fts1_tokenizer.h \
+ $(TOP)/ext/fts1/fts1_tokenizer1.c
+SRC += \
+ $(TOP)/ext/fts2/fts2.c \
+ $(TOP)/ext/fts2/fts2.h \
+ $(TOP)/ext/fts2/fts2_hash.c \
+ $(TOP)/ext/fts2/fts2_hash.h \
+ $(TOP)/ext/fts2/fts2_icu.c \
+ $(TOP)/ext/fts2/fts2_porter.c \
+ $(TOP)/ext/fts2/fts2_tokenizer.h \
+ $(TOP)/ext/fts2/fts2_tokenizer.c \
+ $(TOP)/ext/fts2/fts2_tokenizer1.c
+SRC += \
+ $(TOP)/ext/fts3/fts3.c \
+ $(TOP)/ext/fts3/fts3.h \
+ $(TOP)/ext/fts3/fts3_hash.c \
+ $(TOP)/ext/fts3/fts3_hash.h \
+ $(TOP)/ext/fts3/fts3_icu.c \
+ $(TOP)/ext/fts3/fts3_porter.c \
+ $(TOP)/ext/fts3/fts3_tokenizer.h \
+ $(TOP)/ext/fts3/fts3_tokenizer.c \
+ $(TOP)/ext/fts3/fts3_tokenizer1.c
+SRC += \
+ $(TOP)/ext/icu/icu.c
+
+
+# Generated source code files
+#
+SRC += \
+ keywordhash.h \
+ opcodes.c \
+ opcodes.h \
+ parse.c \
+ parse.h \
+ sqlite3.h
+
+
# Source code to the test files.
#
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 \
- $(TOP)/src/pragma.c \
- $(TOP)/src/printf.c \
$(TOP)/src/test1.c \
$(TOP)/src/test2.c \
$(TOP)/src/test3.c \
@@ -141,54 +208,81 @@ TESTSRC = \
$(TOP)/src/test6.c \
$(TOP)/src/test7.c \
$(TOP)/src/test8.c \
+ $(TOP)/src/test9.c \
+ $(TOP)/src/test_autoext.c \
$(TOP)/src/test_async.c \
+ $(TOP)/src/test_btree.c \
+ $(TOP)/src/test_config.c \
+ $(TOP)/src/test_devsym.c \
+ $(TOP)/src/test_hexio.c \
+ $(TOP)/src/test_malloc.c \
$(TOP)/src/test_md5.c \
+ $(TOP)/src/test_onefile.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/where.c
+ $(TOP)/src/test_thread.c \
+
+#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
+#TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c
+
+TESTSRC2 = \
+ $(TOP)/src/attach.c $(TOP)/src/btree.c $(TOP)/src/build.c $(TOP)/src/date.c \
+ $(TOP)/src/expr.c $(TOP)/src/func.c $(TOP)/src/insert.c $(TOP)/src/os.c \
+ $(TOP)/src/os_os2.c $(TOP)/src/os_unix.c $(TOP)/src/os_win.c \
+ $(TOP)/src/pager.c $(TOP)/src/pragma.c $(TOP)/src/prepare.c \
+ $(TOP)/src/printf.c $(TOP)/src/random.c \
+ $(TOP)/src/select.c $(TOP)/src/tokenize.c \
+ $(TOP)/src/utf.c $(TOP)/src/util.c $(TOP)/src/vdbeapi.c $(TOP)/src/vdbeaux.c \
+ $(TOP)/src/vdbe.c $(TOP)/src/vdbemem.c $(TOP)/src/where.c parse.c
# Header files used by all library source files.
#
HDR = \
- sqlite3.h \
$(TOP)/src/btree.h \
+ $(TOP)/src/btreeInt.h \
$(TOP)/src/hash.h \
+ keywordhash.h \
+ $(TOP)/src/mutex.h \
opcodes.h \
$(TOP)/src/os.h \
$(TOP)/src/os_common.h \
+ $(TOP)/src/pager.h \
+ parse.h \
+ sqlite3.h \
$(TOP)/src/sqlite3ext.h \
$(TOP)/src/sqliteInt.h \
+ $(TOP)/src/sqliteLimit.h \
$(TOP)/src/vdbe.h \
- parse.h
+ $(TOP)/src/vdbeInt.h
-# Header files used by the VDBE submodule
+# Header files used by extensions
#
-VDBEHDR = \
- $(HDR) \
- $(TOP)/src/vdbeInt.h
+EXTHDR += \
+ $(TOP)/ext/fts1/fts1.h \
+ $(TOP)/ext/fts1/fts1_hash.h \
+ $(TOP)/ext/fts1/fts1_tokenizer.h
+EXTHDR += \
+ $(TOP)/ext/fts2/fts2.h \
+ $(TOP)/ext/fts2/fts2_hash.h \
+ $(TOP)/ext/fts2/fts2_tokenizer.h
+EXTHDR += \
+ $(TOP)/ext/fts3/fts3.h \
+ $(TOP)/ext/fts3/fts3_hash.h \
+ $(TOP)/ext/fts3/fts3_tokenizer.h
# This is the default Makefile target. The objects listed here
# are what get build when you type just "make" with no arguments.
#
all: sqlite3.h libsqlite3.a sqlite3$(EXE)
-# Generate the file "last_change" which contains the date of change
-# of the most recently modified source code file
-#
-last_change: $(SRC)
- cat $(SRC) | grep '$$Id: ' | sort -k 5 | tail -1 \
- | $(NAWK) '{print $$5,$$6}' >last_change
-
libsqlite3.a: $(LIBOBJ)
$(AR) libsqlite3.a $(LIBOBJ)
$(RANLIB) libsqlite3.a
sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h
- $(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) $(TOP)/src/shell.c \
+ $(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) \
+ $(TOP)/src/shell.c \
libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
objects: $(LIBOBJ_ORIG)
@@ -199,13 +293,23 @@ objects: $(LIBOBJ_ORIG)
# files are automatically generated. This target takes care of
# all that automatic generation.
#
-target_source: $(SRC) $(VDBEHDR) opcodes.c keywordhash.h
+target_source: $(SRC)
rm -rf tsrc
mkdir tsrc
- cp $(SRC) $(VDBEHDR) tsrc
+ cp -f $(SRC) tsrc
rm tsrc/sqlite.h.in tsrc/parse.y
- cp parse.c opcodes.c keywordhash.h tsrc
- cp $(TOP)/sqlite3.def tsrc
+ touch target_source
+
+sqlite3.c: target_source $(TOP)/tool/mksqlite3c.tcl
+ tclsh $(TOP)/tool/mksqlite3c.tcl
+ cp sqlite3.c tclsqlite3.c
+ cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c
+
+fts2amal.c: target_source $(TOP)/ext/fts2/mkfts2amal.tcl
+ tclsh $(TOP)/ext/fts2/mkfts2amal.tcl
+
+fts3amal.c: target_source $(TOP)/ext/fts3/mkfts3amal.tcl
+ tclsh $(TOP)/ext/fts3/mkfts3amal.tcl
# Rules to build the LEMON compiler generator
#
@@ -213,162 +317,97 @@ lemon: $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
$(BCC) -o lemon $(TOP)/tool/lemon.c
cp $(TOP)/tool/lempar.c .
-# Rules to build individual files
+# Rules to build individual *.o files from files in the src directory.
#
-alter.o: $(TOP)/src/alter.c $(HDR)
- $(TCCX) -c $(TOP)/src/alter.c
+%.o: %.c $(HDR)
+ $(TCCX) -c $<
-analyze.o: $(TOP)/src/analyze.c $(HDR)
- $(TCCX) -c $(TOP)/src/analyze.c
-
-attach.o: $(TOP)/src/attach.c $(HDR)
- $(TCCX) -c $(TOP)/src/attach.c
-
-auth.o: $(TOP)/src/auth.c $(HDR)
- $(TCCX) -c $(TOP)/src/auth.c
-
-btree.o: $(TOP)/src/btree.c $(HDR) $(TOP)/src/pager.h
- $(TCCX) -c $(TOP)/src/btree.c
-
-build.o: $(TOP)/src/build.c $(HDR)
- $(TCCX) -c $(TOP)/src/build.c
-
-callback.o: $(TOP)/src/callback.c $(HDR)
- $(TCCX) -c $(TOP)/src/callback.c
-
-complete.o: $(TOP)/src/complete.c $(HDR)
- $(TCCX) -c $(TOP)/src/complete.c
-
-date.o: $(TOP)/src/date.c $(HDR)
- $(TCCX) -c $(TOP)/src/date.c
-
-delete.o: $(TOP)/src/delete.c $(HDR)
- $(TCCX) -c $(TOP)/src/delete.c
-
-expr.o: $(TOP)/src/expr.c $(HDR)
- $(TCCX) -c $(TOP)/src/expr.c
-
-func.o: $(TOP)/src/func.c $(HDR)
- $(TCCX) -c $(TOP)/src/func.c
-
-hash.o: $(TOP)/src/hash.c $(HDR)
- $(TCCX) -c $(TOP)/src/hash.c
-
-insert.o: $(TOP)/src/insert.c $(HDR)
- $(TCCX) -c $(TOP)/src/insert.c
-
-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
+# Rules to build individual *.o files from generated *.c files. This
+# applies to:
+#
+# parse.o
+# opcodes.o
+#
+%.o: $(TOP)/src/%.c $(HDR)
+ $(TCCX) -c $<
-main.o: $(TOP)/src/main.c $(HDR)
- $(TCCX) -c $(TOP)/src/main.c
+tclsqlite.o: $(TOP)/src/tclsqlite.c $(HDR)
+ $(TCCX) $(TCL_FLAGS) -c $(TOP)/src/tclsqlite.c
-pager.o: $(TOP)/src/pager.c $(HDR) $(TOP)/src/pager.h
- $(TCCX) -c $(TOP)/src/pager.c
-opcodes.o: opcodes.c
- $(TCCX) -c opcodes.c
+# Rules to build opcodes.c and opcodes.h
+#
opcodes.c: opcodes.h $(TOP)/mkopcodec.awk
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 | $(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
-
-os_win.o: $(TOP)/src/os_win.c $(HDR)
- $(TCCX) -c $(TOP)/src/os_win.c
+ cat parse.h $(TOP)/src/vdbe.c |$(NAWK) -f $(TOP)/mkopcodeh.awk >opcodes.h
-parse.o: parse.c $(HDR)
- $(TCCX) -c parse.c
+# Rules to build parse.c and parse.h - the outputs of lemon.
+#
parse.h: parse.c
parse.c: $(TOP)/src/parse.y lemon $(TOP)/addopcodes.awk
cp $(TOP)/src/parse.y .
+ rm -f parse.h
./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
-
-prepare.o: $(TOP)/src/prepare.c $(HDR)
- $(TCCX) $(TCL_FLAGS) -c $(TOP)/src/prepare.c
-
-printf.o: $(TOP)/src/printf.c $(HDR)
- $(TCCX) $(TCL_FLAGS) -c $(TOP)/src/printf.c
-
-random.o: $(TOP)/src/random.c $(HDR)
- $(TCCX) -c $(TOP)/src/random.c
-
-select.o: $(TOP)/src/select.c $(HDR)
- $(TCCX) -c $(TOP)/src/select.c
-
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' | $(NAWK) '{printf "%d%03d%03d",$$1,$$2,$$3}'`/ \
$(TOP)/src/sqlite.h.in >sqlite3.h
-table.o: $(TOP)/src/table.c $(HDR)
- $(TCCX) -c $(TOP)/src/table.c
-
-tclsqlite.o: $(TOP)/src/tclsqlite.c $(HDR)
- $(TCCX) $(TCL_FLAGS) -c $(TOP)/src/tclsqlite.c
-
-tokenize.o: $(TOP)/src/tokenize.c keywordhash.h $(HDR)
- $(TCCX) -c $(TOP)/src/tokenize.c
-
keywordhash.h: $(TOP)/tool/mkkeywordhash.c
$(BCC) -o mkkeywordhash $(OPTS) $(TOP)/tool/mkkeywordhash.c
./mkkeywordhash >keywordhash.h
-trigger.o: $(TOP)/src/trigger.c $(HDR)
- $(TCCX) -c $(TOP)/src/trigger.c
-update.o: $(TOP)/src/update.c $(HDR)
- $(TCCX) -c $(TOP)/src/update.c
-utf.o: $(TOP)/src/utf.c $(HDR)
- $(TCCX) -c $(TOP)/src/utf.c
+# Rules to build the extension objects.
+#
+icu.o: $(TOP)/ext/icu/icu.c $(HDR) $(EXTHDR)
+ $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/icu/icu.c
+
+fts2.o: $(TOP)/ext/fts2/fts2.c $(HDR) $(EXTHDR)
+ $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2.c
+
+fts2_hash.o: $(TOP)/ext/fts2/fts2_hash.c $(HDR) $(EXTHDR)
+ $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_hash.c
+
+fts2_icu.o: $(TOP)/ext/fts2/fts2_icu.c $(HDR) $(EXTHDR)
+ $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_icu.c
-util.o: $(TOP)/src/util.c $(HDR)
- $(TCCX) -c $(TOP)/src/util.c
+fts2_porter.o: $(TOP)/ext/fts2/fts2_porter.c $(HDR) $(EXTHDR)
+ $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_porter.c
-vacuum.o: $(TOP)/src/vacuum.c $(HDR)
- $(TCCX) -c $(TOP)/src/vacuum.c
+fts2_tokenizer.o: $(TOP)/ext/fts2/fts2_tokenizer.c $(HDR) $(EXTHDR)
+ $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_tokenizer.c
-vdbe.o: $(TOP)/src/vdbe.c $(VDBEHDR)
- $(TCCX) -c $(TOP)/src/vdbe.c
+fts2_tokenizer1.o: $(TOP)/ext/fts2/fts2_tokenizer1.c $(HDR) $(EXTHDR)
+ $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_tokenizer1.c
-vdbeapi.o: $(TOP)/src/vdbeapi.c $(VDBEHDR)
- $(TCCX) -c $(TOP)/src/vdbeapi.c
+fts3.o: $(TOP)/ext/fts3/fts3.c $(HDR) $(EXTHDR)
+ $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3.c
-vdbeaux.o: $(TOP)/src/vdbeaux.c $(VDBEHDR)
- $(TCCX) -c $(TOP)/src/vdbeaux.c
+fts3_hash.o: $(TOP)/ext/fts3/fts3_hash.c $(HDR) $(EXTHDR)
+ $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_hash.c
-vdbefifo.o: $(TOP)/src/vdbefifo.c $(VDBEHDR)
- $(TCCX) -c $(TOP)/src/vdbefifo.c
+fts3_icu.o: $(TOP)/ext/fts3/fts3_icu.c $(HDR) $(EXTHDR)
+ $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_icu.c
-vdbemem.o: $(TOP)/src/vdbemem.c $(VDBEHDR)
- $(TCCX) -c $(TOP)/src/vdbemem.c
+fts3_porter.o: $(TOP)/ext/fts3/fts3_porter.c $(HDR) $(EXTHDR)
+ $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_porter.c
-vtab.o: $(TOP)/src/vtab.c $(VDBEHDR)
- $(TCCX) -c $(TOP)/src/vtab.c
+fts3_tokenizer.o: $(TOP)/ext/fts3/fts3_tokenizer.c $(HDR) $(EXTHDR)
+ $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer.c
+
+fts3_tokenizer1.o: $(TOP)/ext/fts3/fts3_tokenizer1.c $(HDR) $(EXTHDR)
+ $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer1.c
-where.o: $(TOP)/src/where.c $(HDR)
- $(TCCX) -c $(TOP)/src/where.c
# Rules for building test programs and for running tests
#
@@ -376,19 +415,38 @@ tclsqlite3: $(TOP)/src/tclsqlite.c libsqlite3.a
$(TCCX) $(TCL_FLAGS) -DTCLSH=1 -o tclsqlite3 \
$(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 -DSQLITE_CRASH_TEST=1 \
- -DSQLITE_SERVER=1 -o testfixture$(EXE) \
- $(TESTSRC) $(TOP)/src/tclsqlite.c \
- libsqlite3.a $(LIBTCL) $(THREADLIB)
+
+# Rules to build the 'testfixture' application.
+#
+TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
+TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
+
+testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c
+ $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
+ $(TESTSRC) $(TESTSRC2) $(TOP)/src/tclsqlite.c \
+ -o testfixture$(EXE) $(LIBTCL) $(THREADLIB) libsqlite3.a
+
+amalgamation-testfixture$(EXE): sqlite3.c $(TESTSRC) $(TOP)/src/tclsqlite.c
+ $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
+ $(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c \
+ -o testfixture$(EXE) $(LIBTCL) $(THREADLIB)
+
+fts3-testfixture$(EXE): sqlite3.c fts3amal.c $(TESTSRC) $(TOP)/src/tclsqlite.c
+ $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
+ -DSQLITE_ENABLE_FTS3=1 \
+ $(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c fts3amal.c \
+ -o testfixture$(EXE) $(LIBTCL) $(THREADLIB)
fulltest: testfixture$(EXE) sqlite3$(EXE)
./testfixture$(EXE) $(TOP)/test/all.test
+soaktest: testfixture$(EXE) sqlite3$(EXE)
+ ./testfixture$(EXE) $(TOP)/test/all.test -soak 1
+
test: testfixture$(EXE) sqlite3$(EXE)
./testfixture$(EXE) $(TOP)/test/quick.test
-sqlite3_analyzer$(EXE): $(TOP)/src/tclsqlite.c libsqlite3.a $(TESTSRC) \
+sqlite3_analyzer$(EXE): $(TOP)/src/tclsqlite.c sqlite3.c $(TESTSRC) \
$(TOP)/tool/spaceanal.tcl
sed \
-e '/^#/d' \
@@ -397,9 +455,11 @@ 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 -DSQLITE_DEBUG=1 -o \
- sqlite3_analyzer$(EXE) $(TESTSRC) $(TOP)/src/tclsqlite.c \
- libsqlite3.a $(LIBTCL) $(THREADLIB)
+ $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
+ -DTCLSH=2 -DSQLITE_TEST=1 -DSQLITE_DEBUG=1 -DSQLITE_PRIVATE="" \
+ $(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c \
+ -o sqlite3_analyzer$(EXE) \
+ $(LIBTCL) $(THREADLIB)
TEST_EXTENSION = $(SHPREFIX)testloadext.$(SO)
$(TEST_EXTENSION): $(TOP)/src/test_loadext.c
@@ -408,180 +468,6 @@ $(TEST_EXTENSION): $(TOP)/src/test_loadext.c
extensiontest: testfixture$(EXE) $(TEST_EXTENSION)
./testfixture$(EXE) $(TOP)/test/loadext.test
-# Rules used to build documentation
-#
-arch.html: $(TOP)/www/arch.tcl
- tclsh $(TOP)/www/arch.tcl >arch.html
-
-arch.png: $(TOP)/www/arch.png
- cp $(TOP)/www/arch.png .
-
-arch2.gif: $(TOP)/www/arch2.gif
- cp $(TOP)/www/arch2.gif .
-
-autoinc.html: $(TOP)/www/autoinc.tcl
- tclsh $(TOP)/www/autoinc.tcl >autoinc.html
-
-c_interface.html: $(TOP)/www/c_interface.tcl
- tclsh $(TOP)/www/c_interface.tcl >c_interface.html
-
-capi3.html: $(TOP)/www/capi3.tcl
- tclsh $(TOP)/www/capi3.tcl >capi3.html
-
-capi3ref.html: $(TOP)/www/capi3ref.tcl
- tclsh $(TOP)/www/capi3ref.tcl >capi3ref.html
-
-changes.html: $(TOP)/www/changes.tcl
- tclsh $(TOP)/www/changes.tcl >changes.html
-
-compile.html: $(TOP)/www/compile.tcl
- tclsh $(TOP)/www/compile.tcl >compile.html
-
-copyright.html: $(TOP)/www/copyright.tcl
- tclsh $(TOP)/www/copyright.tcl >copyright.html
-
-copyright-release.html: $(TOP)/www/copyright-release.html
- cp $(TOP)/www/copyright-release.html .
-
-copyright-release.pdf: $(TOP)/www/copyright-release.pdf
- cp $(TOP)/www/copyright-release.pdf .
-
-common.tcl: $(TOP)/www/common.tcl
- cp $(TOP)/www/common.tcl .
-
-conflict.html: $(TOP)/www/conflict.tcl
- tclsh $(TOP)/www/conflict.tcl >conflict.html
-
-datatypes.html: $(TOP)/www/datatypes.tcl
- tclsh $(TOP)/www/datatypes.tcl >datatypes.html
-
-datatype3.html: $(TOP)/www/datatype3.tcl
- tclsh $(TOP)/www/datatype3.tcl >datatype3.html
-
-different.html: $(TOP)/www/different.tcl
- tclsh $(TOP)/www/different.tcl >different.html
-
-docs.html: $(TOP)/www/docs.tcl
- tclsh $(TOP)/www/docs.tcl >docs.html
-
-download.html: $(TOP)/www/download.tcl
- mkdir -p doc
- tclsh $(TOP)/www/download.tcl >download.html
-
-faq.html: $(TOP)/www/faq.tcl
- tclsh $(TOP)/www/faq.tcl >faq.html
-
-fileformat.html: $(TOP)/www/fileformat.tcl
- tclsh $(TOP)/www/fileformat.tcl >fileformat.html
-
-formatchng.html: $(TOP)/www/formatchng.tcl
- tclsh $(TOP)/www/formatchng.tcl >formatchng.html
-
-index.html: $(TOP)/www/index.tcl last_change
- tclsh $(TOP)/www/index.tcl >index.html
-
-lang.html: $(TOP)/www/lang.tcl
- tclsh $(TOP)/www/lang.tcl doc >lang.html
-
-pragma.html: $(TOP)/www/pragma.tcl
- tclsh $(TOP)/www/pragma.tcl >pragma.html
-
-lockingv3.html: $(TOP)/www/lockingv3.tcl
- tclsh $(TOP)/www/lockingv3.tcl >lockingv3.html
-
-oldnews.html: $(TOP)/www/oldnews.tcl
- tclsh $(TOP)/www/oldnews.tcl >oldnews.html
-
-omitted.html: $(TOP)/www/omitted.tcl
- tclsh $(TOP)/www/omitted.tcl >omitted.html
-
-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
-
-nulls.html: $(TOP)/www/nulls.tcl
- tclsh $(TOP)/www/nulls.tcl >nulls.html
-
-quickstart.html: $(TOP)/www/quickstart.tcl
- tclsh $(TOP)/www/quickstart.tcl >quickstart.html
-
-speed.html: $(TOP)/www/speed.tcl
- tclsh $(TOP)/www/speed.tcl >speed.html
-
-sqlite.gif: $(TOP)/art/SQLite.gif
- cp $(TOP)/art/SQLite.gif sqlite.gif
-
-sqlite.html: $(TOP)/www/sqlite.tcl
- tclsh $(TOP)/www/sqlite.tcl >sqlite.html
-
-support.html: $(TOP)/www/support.tcl
- tclsh $(TOP)/www/support.tcl >support.html
-
-tclsqlite.html: $(TOP)/www/tclsqlite.tcl
- tclsh $(TOP)/www/tclsqlite.tcl >tclsqlite.html
-
-vdbe.html: $(TOP)/www/vdbe.tcl
- tclsh $(TOP)/www/vdbe.tcl >vdbe.html
-
-version3.html: $(TOP)/www/version3.tcl
- tclsh $(TOP)/www/version3.tcl >version3.html
-
-whentouse.html: $(TOP)/www/whentouse.tcl
- tclsh $(TOP)/www/whentouse.tcl >whentouse.html
-
-
-# Files to be published on the website.
-#
-DOC = \
- arch.html \
- arch.png \
- arch2.gif \
- autoinc.html \
- c_interface.html \
- capi3.html \
- capi3ref.html \
- changes.html \
- compile.html \
- copyright.html \
- copyright-release.html \
- copyright-release.pdf \
- conflict.html \
- datatypes.html \
- datatype3.html \
- different.html \
- docs.html \
- download.html \
- faq.html \
- fileformat.html \
- formatchng.html \
- index.html \
- lang.html \
- lockingv3.html \
- mingw.html \
- nulls.html \
- oldnews.html \
- omitted.html \
- opcode.html \
- pragma.html \
- quickstart.html \
- sharedcache.html \
- speed.html \
- sqlite.gif \
- sqlite.html \
- support.html \
- tclsqlite.html \
- vdbe.html \
- version3.html \
- whentouse.html
-
-doc: common.tcl $(DOC)
- mkdir -p doc
- mv $(DOC) doc
# Standard install and cleanup targets
#
@@ -595,4 +481,6 @@ clean:
rm -f lemon lempar.c parse.* sqlite*.tar.gz mkkeywordhash keywordhash.h
rm -f $(PUBLISH)
rm -f *.da *.bb *.bbg gmon.out
- rm -rf tsrc
+ rm -rf tsrc target_source
+ rm -f testloadext.dll libtestloadext.so
+ rm -f sqlite3.c fts?amal.c
diff --git a/ext/pdo_sqlite/sqlite/mkdll.sh b/ext/pdo_sqlite/sqlite/mkdll.sh
index 50dd60b711..ed1e741ca6 100644
--- a/ext/pdo_sqlite/sqlite/mkdll.sh
+++ b/ext/pdo_sqlite/sqlite/mkdll.sh
@@ -6,39 +6,41 @@
# library. "tclsqlite3.dll" contains the TCL bindings and is the
# library that is loaded into TCL in order to run SQLite.
#
-make target_source
-cd tsrc
+make sqlite3.c
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 -DBUILD_sqlite=1'
-CC="i386-mingw32msvc-gcc -O2 $OPTS -I. -I$TCLDIR"
-rm shell.c
-for i in *.c; do
- CMD="$CC -c $i"
- echo $CMD
- $CMD
-done
+OPTS='-DUSE_TCL_STUBS=1 -DSQLITE_THREADSAFE=1 -DBUILD_sqlite=1 -DOS_WIN=1'
+OPTS="$OPTS -DSQLITE_ENABLE_FTS3=1"
+CC="i386-mingw32msvc-gcc -Os $OPTS -Itsrc -I$TCLDIR"
+NM="i386-mingw32msvc-nm"
+CMD="$CC -c sqlite3.c"
+echo $CMD
+$CMD
+CMD="$CC -c tclsqlite3.c"
+echo $CMD
+$CMD
echo 'EXPORTS' >tclsqlite3.def
-echo 'Tclsqlite3_Init' >>tclsqlite3.def
-echo 'Tclsqlite_Init' >>tclsqlite3.def
-echo 'Sqlite3_Init' >>tclsqlite3.def
-echo 'Sqlite_Init' >>tclsqlite3.def
+$NM tclsqlite3.o | grep ' T ' >temp1
+grep '_Init$' temp1 >temp2
+grep '_SafeInit$' temp1 >>temp2
+grep ' T _sqlite3_' temp1 >>temp2
+echo 'EXPORTS' >tclsqlite3.def
+sed 's/^.* T _//' temp2 | sort | uniq >>tclsqlite3.def
i386-mingw32msvc-dllwrap \
--def tclsqlite3.def -v --export-all \
--driver-name i386-mingw32msvc-gcc \
--dlltool-name i386-mingw32msvc-dlltool \
--as i386-mingw32msvc-as \
--target i386-mingw32 \
- -dllname tclsqlite3.dll -lmsvcrt *.o $TCLSTUBLIB
-#i386-mingw32msvc-strip tclsqlite3.dll
-rm tclsqlite.o
+ -dllname tclsqlite3.dll -lmsvcrt tclsqlite3.o $TCLSTUBLIB
+$NM sqlite3.o | grep ' T ' >temp1
+echo 'EXPORTS' >sqlite3.def
+grep ' _sqlite3_' temp1 | sed 's/^.* _//' >>sqlite3.def
i386-mingw32msvc-dllwrap \
--def sqlite3.def -v --export-all \
--driver-name i386-mingw32msvc-gcc \
--dlltool-name i386-mingw32msvc-dlltool \
--as i386-mingw32msvc-as \
--target i386-mingw32 \
- -dllname sqlite3.dll -lmsvcrt *.o
-#i386-mingw32msvc-strip sqlite3.dll
-cd ..
+ -dllname sqlite3.dll -lmsvcrt sqlite3.o
diff --git a/ext/pdo_sqlite/sqlite/mkopcodec.awk b/ext/pdo_sqlite/sqlite/mkopcodec.awk
index bf6bfbeb37..ec80953009 100644
--- a/ext/pdo_sqlite/sqlite/mkopcodec.awk
+++ b/ext/pdo_sqlite/sqlite/mkopcodec.awk
@@ -15,14 +15,17 @@ BEGIN {
printf " || !defined(NDEBUG)"
printf " || defined(VDBE_PROFILE)"
print " || defined(SQLITE_DEBUG)"
- print "const char *const sqlite3OpcodeNames[] = { \"?\","
+ print "const char *sqlite3OpcodeName(int i){"
+ print " static const char *const azName[] = { \"?\","
}
/define OP_/ {
sub("OP_","",$2)
i++
- printf " /* %3d */ \"%s\",\n", $3, $2
+ printf " /* %3d */ \"%s\",\n", $3, $2
}
END {
- print "};"
+ print " };"
+ print " return azName[i];"
+ print "}"
print "#endif"
}
diff --git a/ext/pdo_sqlite/sqlite/mkopcodeh.awk b/ext/pdo_sqlite/sqlite/mkopcodeh.awk
index 0fa50ead09..796a7afe7a 100644
--- a/ext/pdo_sqlite/sqlite/mkopcodeh.awk
+++ b/ext/pdo_sqlite/sqlite/mkopcodeh.awk
@@ -41,15 +41,21 @@
# Remember the TK_ values from the parse.h file
/^#define TK_/ {
- tk[$2] = $3
+ tk[$2] = 0+$3
}
# Scan for "case OP_aaaa:" lines in the vdbe.c file
/^case OP_/ {
name = $2
- gsub(/:/,"",name)
- gsub("\r","",name)
+ sub(/:/,"",name)
+ sub("\r","",name)
op[name] = -1
+ jump[name] = 0
+ out2_prerelease[name] = 0
+ in1[name] = 0
+ in2[name] = 0
+ in3[name] = 0
+ out3[name] = 0
for(i=3; i<NF; i++){
if($i=="same" && $(i+1)=="as"){
sym = $(i+2)
@@ -58,8 +64,20 @@
used[op[name]] = 1
sameas[op[name]] = sym
}
- if($i=="no-push"){
- nopush[name] = 1
+ x = $i
+ sub(",","",x)
+ if(x=="jump"){
+ jump[name] = 1
+ }else if(x=="out2-prerelease"){
+ out2_prerelease[name] = 1
+ }else if(x=="in1"){
+ in1[name] = 1
+ }else if(x=="in2"){
+ in2[name] = 1
+ }else if(x=="in3"){
+ in3[name] = 1
+ }else if(x=="out3"){
+ out3[name] = 1
}
}
}
@@ -70,6 +88,8 @@ END {
max = 0
print "/* Automatically generated. Do not edit */"
print "/* See the mkopcodeh.awk script for details */"
+ op["OP_Noop"] = -1;
+ op["OP_Explain"] = -1;
for(name in op){
if( op[name]<0 ){
cnt++
@@ -96,32 +116,42 @@ END {
}
}
- # Generate the 10 16-bit bitmasks used by function opcodeUsesStack()
- # in vdbeaux.c. See comments in that function for details.
- #
- nopush[0] = 0 # 0..15
- nopush[1] = 0 # 16..31
- nopush[2] = 0 # 32..47
- nopush[3] = 0 # 48..63
- nopush[4] = 0 # 64..79
- nopush[5] = 0 # 80..95
- nopush[6] = 0 # 96..111
- nopush[7] = 0 # 112..127
- nopush[8] = 0 # 128..143
- nopush[9] = 0 # 144..159
+ # Generate the bitvectors:
+ #
+ # bit 0: jump
+ # bit 1: pushes a result onto stack
+ # bit 2: output to p1. release p1 before opcode runs
+ #
+ for(i=0; i<=max; i++) bv[i] = 0;
for(name in op){
- if( nopush[name] ){
- n = op[name]
- j = n%16
- i = ((n - j)/16)
- nopush[i] = nopush[i] + (2^j)
- }
+ x = op[name]
+ a0 = a1 = a2 = a3 = a4 = a5 = a6 = a7 = 0
+ # a8 = a9 = a10 = a11 = a12 = a13 = a14 = a15 = 0
+ if( jump[name] ) a0 = 1;
+ if( out2_prerelease[name] ) a1 = 2;
+ if( in1[name] ) a2 = 4;
+ if( in2[name] ) a3 = 8;
+ if( in3[name] ) a4 = 16;
+ if( out3[name] ) a5 = 32;
+ # bv[x] = a0+a1+a2+a3+a4+a5+a6+a7+a8+a9+a10+a11+a12+a13+a14+a15;
+ bv[x] = a0+a1+a2+a3+a4+a5+a6+a7;
}
- 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 0x%04x\n", i, nopush[i]
+ print "\n"
+ print "/* Properties such as \"out2\" or \"jump\" that are specified in"
+ print "** comments following the \"case\" for each opcode in the vdbe.c"
+ print "** are encoded into bitvectors as follows:"
+ print "*/"
+ print "#define OPFLG_JUMP 0x0001 /* jump: P2 holds jmp target */"
+ print "#define OPFLG_OUT2_PRERELEASE 0x0002 /* out2-prerelease: */"
+ print "#define OPFLG_IN1 0x0004 /* in1: P1 is an input */"
+ print "#define OPFLG_IN2 0x0008 /* in2: P2 is an input */"
+ print "#define OPFLG_IN3 0x0010 /* in3: P3 is an input */"
+ print "#define OPFLG_OUT3 0x0020 /* out3: P3 is an output */"
+ print "#define OPFLG_INITIALIZER {\\"
+ for(i=0; i<=max; i++){
+ if( i%8==0 ) printf("/* %3d */",i)
+ printf " 0x%02x,", bv[i]
+ if( i%8==7 ) printf("\\\n");
}
+ print "}"
}
diff --git a/ext/pdo_sqlite/sqlite/mkso.sh b/ext/pdo_sqlite/sqlite/mkso.sh
index b26382c99a..9050d74255 100644
--- a/ext/pdo_sqlite/sqlite/mkso.sh
+++ b/ext/pdo_sqlite/sqlite/mkso.sh
@@ -11,7 +11,7 @@ cd tsrc
rm shell.c
TCLDIR=/home/drh/tcltk/846/linux/846linux
TCLSTUBLIB=$TCLDIR/libtclstub8.4g.a
-OPTS='-DUSE_TCL_STUBS=1 -DNDEBUG=1'
+OPTS='-DUSE_TCL_STUBS=1 -DNDEBUG=1 -DHAVE_DLOPEN=1'
for i in *.c; do
if test $i != 'keywordhash.c'; then
CMD="cc -fPIC $OPTS -O2 -I. -I$TCLDIR -c $i"
diff --git a/ext/pdo_sqlite/sqlite/publish.sh b/ext/pdo_sqlite/sqlite/publish.sh
index 043c89a039..138f3d901a 100644
--- a/ext/pdo_sqlite/sqlite/publish.sh
+++ b/ext/pdo_sqlite/sqlite/publish.sh
@@ -1,9 +1,7 @@
#!/bin/sh
#
-# This script is used to compile SQLite and all its documentation and
-# ship everything up to the SQLite website. This script will only work
-# on the system "zadok" at the Hwaci offices. But others might find
-# the script useful as an example.
+# This script is used to compile SQLite and package everything up
+# so that it is ready to move to the SQLite website.
#
# Set srcdir to the name of the directory that contains the publish.sh
@@ -20,63 +18,80 @@ chmod +x $srcdir/install-sh
#
VERS=`cat $srcdir/VERSION`
VERSW=`sed 's/\./_/g' $srcdir/VERSION`
+echo "VERSIONS: $VERS $VERSW"
# Start by building an sqlite shell for linux.
#
make clean
-make sqlite3
+make sqlite3.c
+CFLAGS="-Os -DSQLITE_ENABLE_FTS3=1 -DSQLITE_THREADSAFE=0"
+echo '***** '"COMPILING sqlite3-$VERS.bin..."
+gcc $CFLAGS -Itsrc sqlite3.c tsrc/shell.c -o sqlite3 -ldl
strip sqlite3
mv sqlite3 sqlite3-$VERS.bin
gzip sqlite3-$VERS.bin
+chmod 644 sqlite3-$VERS.bin.gz
mv sqlite3-$VERS.bin.gz doc
# Build a source archive useful for windows.
#
make target_source
cd tsrc
+echo '***** BUILDING preprocessed source archives'
+rm fts[12]* icu*
+rm -f ../doc/sqlite-source-$VERSW.zip
zip ../doc/sqlite-source-$VERSW.zip *
cd ..
+cp tsrc/sqlite3.h tsrc/sqlite3ext.h .
+pwd
+zip doc/sqlite-amalgamation-$VERSW.zip sqlite3.c sqlite3.h sqlite3ext.h
# Build the sqlite.so and tclsqlite.so shared libraries
# under Linux
#
-. $srcdir/mkso.sh
-cd tsrc
+TCLDIR=/home/drh/tcltk/846/linux/846linux
+TCLSTUBLIB=$TCLDIR/libtclstub8.4g.a
+CFLAGS="-Os -DSQLITE_ENABLE_FTS3=1 -DHAVE_LOCALTIME_R=1 -DHAVE_GMTIME_R=1"
+echo '***** BUILDING shared libraries for linux'
+gcc $CFLAGS -shared tclsqlite3.c $TCLSTUBLIB -o tclsqlite3.so -lpthread
+strip tclsqlite3.so
+chmod 644 tclsqlite3.so
mv tclsqlite3.so tclsqlite-$VERS.so
gzip tclsqlite-$VERS.so
-mv tclsqlite-$VERS.so.gz ../doc
+mv tclsqlite-$VERS.so.gz doc
+gcc $CFLAGS -shared sqlite3.c -o sqlite3.so -lpthread
+strip sqlite3.so
+chmod 644 sqlite3.so
mv sqlite3.so sqlite-$VERS.so
gzip sqlite-$VERS.so
-mv sqlite-$VERS.so.gz ../doc
-cd ..
+mv sqlite-$VERS.so.gz doc
+
# Build the tclsqlite3.dll and sqlite3.dll shared libraries.
#
. $srcdir/mkdll.sh
-cd tsrc
-echo zip ../doc/tclsqlite-$VERSW.zip tclsqlite3.dll
-zip ../doc/tclsqlite-$VERSW.zip tclsqlite3.dll
-echo zip ../doc/sqlitedll-$VERSW.zip sqlite3.dll sqlite3.def
-zip ../doc/sqlitedll-$VERSW.zip sqlite3.dll sqlite3.def
-cd ..
+echo '***** PACKAGING shared libraries for windows'
+echo zip doc/tclsqlite-$VERSW.zip tclsqlite3.dll
+zip doc/tclsqlite-$VERSW.zip tclsqlite3.dll
+echo zip doc/sqlitedll-$VERSW.zip sqlite3.dll sqlite3.def
+zip doc/sqlitedll-$VERSW.zip sqlite3.dll sqlite3.def
# Build the sqlite.exe executable for windows.
#
-make target_source
-cd tsrc
-rm tclsqlite.c
-OPTS='-DSTATIC_BUILD=1 -DNDEBUG=1'
-i386-mingw32msvc-gcc -O2 $OPTS -I. -I$TCLDIR *.c -o sqlite3.exe
-zip ../doc/sqlite-$VERSW.zip sqlite3.exe
-cd ..
+OPTS='-DSTATIC_BUILD=1 -DNDEBUG=1 -DSQLITE_THREADSAFE=0'
+OPTS="$OPTS -DSQLITE_ENABLE_FTS3=1"
+i386-mingw32msvc-gcc -Os $OPTS -Itsrc -I$TCLDIR sqlite3.c tsrc/shell.c \
+ -o sqlite3.exe
+zip doc/sqlite-$VERSW.zip sqlite3.exe
# Construct a tarball of the source tree
#
+echo '***** BUILDING source archive'
ORIGIN=`pwd`
cd $srcdir
cd ..
mv sqlite sqlite-$VERS
-EXCLUDE=`find sqlite-$VERS -print | grep CVS | sed 's,^, --exclude ,'`
+EXCLUDE=`find sqlite-$VERS -print | egrep (CVS|www/|art/|doc/|contrib/) | sed 's,^, --exclude ,'`
tar czf $ORIGIN/doc/sqlite-$VERS.tar.gz $EXCLUDE sqlite-$VERS
mv sqlite-$VERS sqlite
cd $ORIGIN
@@ -112,6 +127,6 @@ mv $HOME/rpm/SRPMS/sqlite-$vers*.rpm doc
# Build the website
#
#cp $srcdir/../historical/* doc
-make doc
-cd doc
-chmod 644 *.gz
+#make doc
+#cd doc
+#chmod 644 *.gz
diff --git a/ext/pdo_sqlite/sqlite/sqlite3.def b/ext/pdo_sqlite/sqlite/sqlite3.def
index e42a0cd3d6..4947925e47 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_load_extension
sqlite3_enable_shared_cache
sqlite3_errcode
sqlite3_errmsg
@@ -57,12 +58,15 @@ sqlite3_interrupt
sqlite3_last_insert_rowid
sqlite3_libversion
sqlite3_libversion_number
+sqlite3_load_extension
+sqlite3_malloc
sqlite3_mprintf
sqlite3_open
sqlite3_open16
sqlite3_prepare
sqlite3_prepare16
sqlite3_progress_handler
+sqlite3_realloc
sqlite3_reset
sqlite3_result_blob
sqlite3_result_double
diff --git a/ext/pdo_sqlite/sqlite/sqlite3.pc.in b/ext/pdo_sqlite/sqlite/sqlite3.pc.in
index 13d80a0b20..2de6effc31 100644
--- a/ext/pdo_sqlite/sqlite/sqlite3.pc.in
+++ b/ext/pdo_sqlite/sqlite/sqlite3.pc.in
@@ -9,4 +9,5 @@ Name: SQLite
Description: SQL database engine
Version: @VERSION@
Libs: -L${libdir} -lsqlite3
+Libs.private: -lpthread
Cflags: -I${includedir}
diff --git a/ext/pdo_sqlite/sqlite/src/alter.c b/ext/pdo_sqlite/sqlite/src/alter.c
index 0d6bfbf9dc..fa32de1674 100644
--- a/ext/pdo_sqlite/sqlite/src/alter.c
+++ b/ext/pdo_sqlite/sqlite/src/alter.c
@@ -28,7 +28,7 @@
** This function is used by SQL generated to implement the
** ALTER TABLE command. The first argument is the text of a CREATE TABLE or
** CREATE INDEX command. The second is a table name. The table name in
-** the CREATE TABLE or CREATE INDEX statement is replaced with the second
+** the CREATE TABLE or CREATE INDEX statement is replaced with the third
** argument and the result returned. Examples:
**
** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def')
@@ -51,37 +51,44 @@ static void renameTableFunc(
int len = 0;
char *zRet;
+ sqlite3 *db = sqlite3_user_data(context);
+
/* The principle used to locate the table name in the CREATE TABLE
** statement is that the table name is the first token that is immediatedly
- ** followed by a left parenthesis - TK_LP.
+ ** followed by a left parenthesis - TK_LP - or "USING" TK_USING.
*/
if( zSql ){
do {
+ if( !*zCsr ){
+ /* Ran out of input before finding an opening bracket. Return NULL. */
+ return;
+ }
+
/* Store the token that zCsr points to in tname. */
tname.z = zCsr;
tname.n = len;
/* Advance zCsr to the next token. Store that token type in 'token',
- ** and it's length in 'len' (to be used next iteration of this loop).
+ ** and its length in 'len' (to be used next iteration of this loop).
*/
do {
zCsr += len;
len = sqlite3GetToken(zCsr, &token);
} while( token==TK_SPACE );
assert( len>0 );
- } while( token!=TK_LP );
+ } while( token!=TK_LP && token!=TK_USING );
- zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql,
+ zRet = sqlite3MPrintf(db, "%.*s%Q%s", tname.z - zSql, zSql,
zTableName, tname.z+tname.n);
- sqlite3_result_text(context, zRet, -1, sqlite3FreeX);
+ sqlite3_result_text(context, zRet, -1, sqlite3_free);
}
}
#ifndef SQLITE_OMIT_TRIGGER
-/* This function is used by SQL generated to implement the ALTER TABLE
+/* This function is used by SQL generated to implement the
** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER
** statement. The second is a table name. The table name in the CREATE
-** TRIGGER statement is replaced with the second argument and the result
+** TRIGGER statement is replaced with the third argument and the result
** returned. This is analagous to renameTableFunc() above, except for CREATE
** TRIGGER, not CREATE INDEX and CREATE TABLE.
*/
@@ -100,6 +107,8 @@ static void renameTriggerFunc(
int len = 0;
char *zRet;
+ sqlite3 *db = sqlite3_user_data(context);
+
/* The principle used to locate the table name in the CREATE TRIGGER
** statement is that the table name is the first token that is immediatedly
** preceded by either TK_ON or TK_DOT and immediatedly followed by one
@@ -107,12 +116,18 @@ static void renameTriggerFunc(
*/
if( zSql ){
do {
+
+ if( !*zCsr ){
+ /* Ran out of input before finding the table name. Return NULL. */
+ return;
+ }
+
/* Store the token that zCsr points to in tname. */
tname.z = zCsr;
tname.n = len;
/* Advance zCsr to the next token. Store that token type in 'token',
- ** and it's length in 'len' (to be used next iteration of this loop).
+ ** and its length in 'len' (to be used next iteration of this loop).
*/
do {
zCsr += len;
@@ -138,9 +153,9 @@ static void renameTriggerFunc(
/* Variable tname now contains the token that is the old table-name
** in the CREATE TRIGGER statement.
*/
- zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql,
+ zRet = sqlite3MPrintf(db, "%.*s%Q%s", tname.z - zSql, zSql,
zTableName, tname.z+tname.n);
- sqlite3_result_text(context, zRet, -1, sqlite3FreeX);
+ sqlite3_result_text(context, zRet, -1, sqlite3_free);
}
}
#endif /* !SQLITE_OMIT_TRIGGER */
@@ -163,7 +178,7 @@ void sqlite3AlterFunctions(sqlite3 *db){
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
- SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
+ SQLITE_UTF8, (void *)db, aFuncs[i].xFunc, 0, 0);
}
}
@@ -185,14 +200,15 @@ static char *whereTempTriggers(Parse *pParse, Table *pTab){
** expression being built up in zWhere.
*/
if( pTab->pSchema!=pTempSchema ){
+ sqlite3 *db = pParse->db;
for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
if( pTrig->pSchema==pTempSchema ){
if( !zWhere ){
- zWhere = sqlite3MPrintf("name=%Q", pTrig->name);
+ zWhere = sqlite3MPrintf(db, "name=%Q", pTrig->name);
}else{
tmp = zWhere;
- zWhere = sqlite3MPrintf("%s OR name=%Q", zWhere, pTrig->name);
- sqliteFree(tmp);
+ zWhere = sqlite3MPrintf(db, "%s OR name=%Q", zWhere, pTrig->name);
+ sqlite3_free(tmp);
}
}
}
@@ -218,6 +234,7 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
v = sqlite3GetVdbe(pParse);
if( !v ) return;
+ assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
assert( iDb>=0 );
@@ -226,24 +243,24 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
for(pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext){
int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
assert( iTrigDb==iDb || iTrigDb==1 );
- sqlite3VdbeOp3(v, OP_DropTrigger, iTrigDb, 0, pTrig->name, 0);
+ sqlite3VdbeAddOp4(v, OP_DropTrigger, iTrigDb, 0, 0, pTrig->name, 0);
}
#endif
/* Drop the table and index from the internal schema */
- sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0);
+ sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0);
/* Reload the table, index and permanent trigger schemas. */
- zWhere = sqlite3MPrintf("tbl_name=%Q", zName);
+ zWhere = sqlite3MPrintf(pParse->db, "tbl_name=%Q", zName);
if( !zWhere ) return;
- sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC);
+ sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
#ifndef SQLITE_OMIT_TRIGGER
/* 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))!=0 ){
- sqlite3VdbeOp3(v, OP_ParseSchema, 1, 0, zWhere, P3_DYNAMIC);
+ sqlite3VdbeAddOp4(v, OP_ParseSchema, 1, 0, 0, zWhere, P4_DYNAMIC);
}
#endif
}
@@ -262,27 +279,25 @@ void sqlite3AlterRenameTable(
Table *pTab; /* Table being renamed */
char *zName = 0; /* NULL-terminated version of pName */
sqlite3 *db = pParse->db; /* Database connection */
+ int nTabName; /* Number of UTF-8 characters in zTabName */
+ const char *zTabName; /* Original name of the table */
Vdbe *v;
#ifndef SQLITE_OMIT_TRIGGER
char *zWhere = 0; /* Where clause to locate temp triggers */
#endif
+ int isVirtualRename = 0; /* True if this is a v-table with an xRename() */
- if( sqlite3MallocFailed() ) goto exit_rename_table;
+ if( db->mallocFailed ) goto exit_rename_table;
assert( pSrc->nSrc==1 );
+ assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
- pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
+ pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase);
if( !pTab ) goto exit_rename_table;
-#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. */
- zName = sqlite3NameFromToken(pName);
+ zName = sqlite3NameFromToken(db, pName);
if( !zName ) goto exit_rename_table;
/* Check that a table or index named 'zName' does not already exist
@@ -305,6 +320,13 @@ void sqlite3AlterRenameTable(
goto exit_rename_table;
}
+#ifndef SQLITE_OMIT_VIEW
+ if( pTab->pSelect ){
+ sqlite3ErrorMsg(pParse, "view %s may not be altered", pTab->zName);
+ goto exit_rename_table;
+ }
+#endif
+
#ifndef SQLITE_OMIT_AUTHORIZATION
/* Invoke the authorization callback. */
if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){
@@ -312,16 +334,43 @@ void sqlite3AlterRenameTable(
}
#endif
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( sqlite3ViewGetColumnNames(pParse, pTab) ){
+ goto exit_rename_table;
+ }
+ if( IsVirtual(pTab) && pTab->pMod->pModule->xRename ){
+ isVirtualRename = 1;
+ }
+#endif
+
/* Begin a transaction and code the VerifyCookie for database iDb.
** Then modify the schema cookie (since the ALTER TABLE modifies the
- ** schema).
+ ** schema). Open a statement transaction if the table is a virtual
+ ** table.
*/
v = sqlite3GetVdbe(pParse);
if( v==0 ){
goto exit_rename_table;
}
- sqlite3BeginWriteOperation(pParse, 0, iDb);
- sqlite3ChangeCookie(db, v, iDb);
+ sqlite3BeginWriteOperation(pParse, isVirtualRename, iDb);
+ sqlite3ChangeCookie(pParse, iDb);
+
+ /* If this is a virtual table, invoke the xRename() function if
+ ** one is defined. The xRename() callback will modify the names
+ ** of any resources used by the v-table implementation (including other
+ ** SQLite tables) that are identified by the name of the virtual table.
+ */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( isVirtualRename ){
+ int i = ++pParse->nMem;
+ sqlite3VdbeAddOp4(v, OP_String8, 0, i, 0, zName, 0);
+ sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pTab->pVtab, P4_VTAB);
+ }
+#endif
+
+ /* figure out how many UTF-8 characters are in zName */
+ zTabName = pTab->zName;
+ nTabName = sqlite3Utf8CharLen(zTabName, -1);
/* Modify the sqlite_master table to use the new table name. */
sqlite3NestedParse(pParse,
@@ -337,7 +386,7 @@ void sqlite3AlterRenameTable(
"name = CASE "
"WHEN type='table' THEN %Q "
"WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN "
- "'sqlite_autoindex_' || %Q || substr(name, %d+18,10) "
+ "'sqlite_autoindex_' || %Q || substr(name,%d+18) "
"ELSE name END "
"WHERE tbl_name=%Q AND "
"(type='table' OR type='index' OR type='trigger');",
@@ -345,7 +394,7 @@ void sqlite3AlterRenameTable(
#ifndef SQLITE_OMIT_TRIGGER
zName,
#endif
- zName, strlen(pTab->zName), pTab->zName
+ zName, nTabName, zTabName
);
#ifndef SQLITE_OMIT_AUTOINCREMENT
@@ -370,7 +419,7 @@ void sqlite3AlterRenameTable(
"sql = sqlite_rename_trigger(sql, %Q), "
"tbl_name = %Q "
"WHERE %s;", zName, zName, zWhere);
- sqliteFree(zWhere);
+ sqlite3_free(zWhere);
}
#endif
@@ -379,7 +428,7 @@ void sqlite3AlterRenameTable(
exit_rename_table:
sqlite3SrcListDelete(pSrc);
- sqliteFree(zName);
+ sqlite3_free(zName);
}
@@ -400,17 +449,20 @@ 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 */
+ sqlite3 *db; /* The database connection; */
if( pParse->nErr ) return;
pNew = pParse->pNewTable;
assert( pNew );
- iDb = sqlite3SchemaToIndex(pParse->db, pNew->pSchema);
- zDb = pParse->db->aDb[iDb].zName;
+ db = pParse->db;
+ assert( sqlite3BtreeHoldsAllMutexes(db) );
+ iDb = sqlite3SchemaToIndex(db, pNew->pSchema);
+ zDb = db->aDb[iDb].zName;
zTab = pNew->zName;
pCol = &pNew->aCol[pNew->nCol-1];
pDflt = pCol->pDflt;
- pTab = sqlite3FindTable(pParse->db, zTab, zDb);
+ pTab = sqlite3FindTable(db, zTab, zDb);
assert( pTab );
#ifndef SQLITE_OMIT_AUTHORIZATION
@@ -451,8 +503,8 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
*/
if( pDflt ){
sqlite3_value *pVal;
- if( sqlite3ValueFromExpr(pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){
- /* malloc() has failed */
+ if( sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){
+ db->mallocFailed = 1;
return;
}
if( !pVal ){
@@ -463,7 +515,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
}
/* Modify the CREATE TABLE statement. */
- zCol = sqliteStrNDup((char*)pColDef->z, pColDef->n);
+ zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
if( zCol ){
char *zEnd = &zCol[pColDef->n-1];
while( (zEnd>zCol && *zEnd==';') || isspace(*(unsigned char *)zEnd) ){
@@ -471,12 +523,12 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
}
sqlite3NestedParse(pParse,
"UPDATE %Q.%s SET "
- "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d,length(sql)) "
+ "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
"WHERE type = 'table' AND name = %Q",
zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1,
zTab
);
- sqliteFree(zCol);
+ sqlite3_free(zCol);
}
/* If the default value of the new column is NULL, then set the file
@@ -511,11 +563,13 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
int iDb;
int i;
int nAlloc;
+ sqlite3 *db = pParse->db;
/* Look up the table being altered. */
assert( pParse->pNewTable==0 );
- if( sqlite3MallocFailed() ) goto exit_begin_add_column;
- pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
+ assert( sqlite3BtreeHoldsAllMutexes(db) );
+ if( db->mallocFailed ) goto exit_begin_add_column;
+ pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase);
if( !pTab ) goto exit_begin_add_column;
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -532,12 +586,12 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
}
assert( pTab->addColOffset>0 );
- iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
/* Put a copy of the Table struct in Parse.pNewTable for the
** sqlite3AddColumn() function and friends to modify.
*/
- pNew = (Table *)sqliteMalloc(sizeof(Table));
+ pNew = (Table*)sqlite3DbMallocZero(db, sizeof(Table));
if( !pNew ) goto exit_begin_add_column;
pParse->pNewTable = pNew;
pNew->nRef = 1;
@@ -545,20 +599,21 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
assert( pNew->nCol>0 );
nAlloc = (((pNew->nCol-1)/8)*8)+8;
assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 );
- pNew->aCol = (Column *)sqliteMalloc(sizeof(Column)*nAlloc);
- pNew->zName = sqliteStrDup(pTab->zName);
+ pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc);
+ pNew->zName = sqlite3DbStrDup(db, pTab->zName);
if( !pNew->aCol || !pNew->zName ){
+ db->mallocFailed = 1;
goto exit_begin_add_column;
}
memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol);
for(i=0; i<pNew->nCol; i++){
Column *pCol = &pNew->aCol[i];
- pCol->zName = sqliteStrDup(pCol->zName);
+ pCol->zName = sqlite3DbStrDup(db, pCol->zName);
pCol->zColl = 0;
pCol->zType = 0;
pCol->pDflt = 0;
}
- pNew->pSchema = pParse->db->aDb[iDb].pSchema;
+ pNew->pSchema = db->aDb[iDb].pSchema;
pNew->addColOffset = pTab->addColOffset;
pNew->nRef = 1;
@@ -566,7 +621,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
sqlite3BeginWriteOperation(pParse, 0, iDb);
v = sqlite3GetVdbe(pParse);
if( !v ) goto exit_begin_add_column;
- sqlite3ChangeCookie(pParse->db, v, iDb);
+ sqlite3ChangeCookie(pParse, iDb);
exit_begin_add_column:
sqlite3SrcListDelete(pSrc);
diff --git a/ext/pdo_sqlite/sqlite/src/analyze.c b/ext/pdo_sqlite/sqlite/src/analyze.c
index dc1f33286d..1d441019c3 100644
--- a/ext/pdo_sqlite/sqlite/src/analyze.c
+++ b/ext/pdo_sqlite/sqlite/src/analyze.c
@@ -33,20 +33,25 @@ static void openStatTable(
sqlite3 *db = pParse->db;
Db *pDb;
int iRootPage;
+ int createStat1 = 0;
Table *pStat;
Vdbe *v = sqlite3GetVdbe(pParse);
+ if( v==0 ) return;
+ assert( sqlite3BtreeHoldsAllMutexes(db) );
+ assert( sqlite3VdbeDb(v)==db );
pDb = &db->aDb[iDb];
if( (pStat = sqlite3FindTable(db, "sqlite_stat1", pDb->zName))==0 ){
/* The sqlite_stat1 tables does not exist. Create it.
** Note that a side-effect of the CREATE TABLE statement is to leave
- ** the rootpage of the new table on the top of the stack. This is
+ ** the rootpage of the new table in register pParse->regRoot. This is
** important because the OpenWrite opcode below will be needing it. */
sqlite3NestedParse(pParse,
"CREATE TABLE %Q.sqlite_stat1(tbl,idx,stat)",
pDb->zName
);
- iRootPage = 0; /* Cause rootpage to be taken from top of stack */
+ iRootPage = pParse->regRoot;
+ createStat1 = 1; /* Cause rootpage to be taken from top of stack */
}else if( zWhere ){
/* The sqlite_stat1 table exists. Delete all entries associated with
** the table zWhere. */
@@ -58,7 +63,7 @@ static void openStatTable(
}else{
/* The sqlite_stat1 table already exists. Delete all rows. */
iRootPage = pStat->tnum;
- sqlite3VdbeAddOp(v, OP_Clear, pStat->tnum, iDb);
+ sqlite3VdbeAddOp2(v, OP_Clear, pStat->tnum, iDb);
}
/* Open the sqlite_stat1 table for writing. Unless it was created
@@ -66,12 +71,12 @@ static void openStatTable(
** 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 ){
+ if( !createStat1 ){
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);
+ sqlite3VdbeAddOp3(v, OP_OpenWrite, iStatCur, iRootPage, iDb);
+ sqlite3VdbeChangeP5(v, createStat1);
+ sqlite3VdbeAddOp2(v, OP_SetNumColumns, iStatCur, 3);
}
/*
@@ -95,11 +100,11 @@ static void analyzeOneTable(
int iDb; /* Index of database containing pTab */
v = sqlite3GetVdbe(pParse);
- if( pTab==0 || pTab->pIndex==0 ){
+ if( v==0 || pTab==0 || pTab->pIndex==0 ){
/* Do no analysis for tables that have no indices */
return;
}
-
+ assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
assert( iDb>=0 );
#ifndef SQLITE_OMIT_AUTHORIZATION
@@ -115,19 +120,27 @@ static void analyzeOneTable(
iIdxCur = pParse->nTab;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
+ int regFields; /* Register block for building records */
+ int regRec; /* Register holding completed record */
+ int regTemp; /* Temporary use register */
+ int regCol; /* Content of a column from the table being analyzed */
+ int regRowid; /* Rowid for the inserted record */
+ int regF2;
/* Open a cursor to the index to be analyzed
*/
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 *)pKey, P3_KEYINFO_HANDOFF);
+ sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb,
+ (char *)pKey, P4_KEYINFO_HANDOFF);
+ VdbeComment((v, "%s", pIdx->zName));
nCol = pIdx->nColumn;
- if( iMem+nCol*2>=pParse->nMem ){
- pParse->nMem = iMem+nCol*2+1;
+ regFields = iMem+nCol*2;
+ regTemp = regRowid = regCol = regFields+3;
+ regRec = regCol+1;
+ if( regRec>pParse->nMem ){
+ pParse->nMem = regRec;
}
- sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, nCol+1);
+ sqlite3VdbeAddOp2(v, OP_SetNumColumns, iIdxCur, nCol+1);
/* Memory cells are used as follows:
**
@@ -143,37 +156,37 @@ static void analyzeOneTable(
** are initialized to NULL.
*/
for(i=0; i<=nCol; i++){
- sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem+i);
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, iMem+i);
}
for(i=0; i<nCol; i++){
- sqlite3VdbeAddOp(v, OP_MemNull, iMem+nCol+i+1, 0);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, iMem+nCol+i+1);
}
/* Do the analysis.
*/
endOfLoop = sqlite3VdbeMakeLabel(v);
- sqlite3VdbeAddOp(v, OP_Rewind, iIdxCur, endOfLoop);
+ sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur, endOfLoop);
topOfLoop = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeAddOp(v, OP_MemIncr, 1, iMem);
+ sqlite3VdbeAddOp2(v, OP_AddImm, iMem, 1);
for(i=0; i<nCol; i++){
- sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i);
- sqlite3VdbeAddOp(v, OP_MemLoad, iMem+nCol+i+1, 0);
- sqlite3VdbeAddOp(v, OP_Ne, 0x100, 0);
+ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regCol);
+ sqlite3VdbeAddOp3(v, OP_Ne, regCol, 0, iMem+nCol+i+1);
+ /**** TODO: add collating sequence *****/
+ sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
}
- sqlite3VdbeAddOp(v, OP_Goto, 0, endOfLoop);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, endOfLoop);
for(i=0; i<nCol; i++){
- 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);
+ sqlite3VdbeJumpHere(v, topOfLoop + 2*(i + 1));
+ sqlite3VdbeAddOp2(v, OP_AddImm, iMem+i+1, 1);
+ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, iMem+nCol+i+1);
}
sqlite3VdbeResolveLabel(v, endOfLoop);
- sqlite3VdbeAddOp(v, OP_Next, iIdxCur, topOfLoop);
- sqlite3VdbeAddOp(v, OP_Close, iIdxCur, 0);
+ sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, topOfLoop);
+ sqlite3VdbeAddOp1(v, OP_Close, iIdxCur);
/* Store the results.
**
- ** The result is a single row of the sqlite_stmt1 table. The first
+ ** The result is a single row of the sqlite_stat1 table. The first
** two columns are the names of the table and index. The third column
** is a string composed of a list of integer statistics about the
** index. The first integer in the list is the total number of entires
@@ -189,29 +202,24 @@ static void analyzeOneTable(
** If K>0 then it is always the case the D>0 so division by zero
** is never possible.
*/
- sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0);
- addr = sqlite3VdbeAddOp(v, OP_IfNot, 0, 0);
- sqlite3VdbeAddOp(v, OP_NewRowid, iStatCur, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0);
- sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, " ", 0);
+ addr = sqlite3VdbeAddOp1(v, OP_IfNot, iMem);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, regFields, 0, pTab->zName, 0);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, regFields+1, 0, pIdx->zName, 0);
+ regF2 = regFields+2;
+ sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regF2);
for(i=0; i<nCol; i++){
- sqlite3VdbeAddOp(v, OP_MemLoad, iMem, 0);
- sqlite3VdbeAddOp(v, OP_MemLoad, iMem+i+1, 0);
- sqlite3VdbeAddOp(v, OP_Add, 0, 0);
- 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);
- }
+ sqlite3VdbeAddOp4(v, OP_String8, 0, regTemp, 0, " ", 0);
+ sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regF2, regF2);
+ sqlite3VdbeAddOp3(v, OP_Add, iMem, iMem+i+1, regTemp);
+ sqlite3VdbeAddOp2(v, OP_AddImm, regTemp, -1);
+ sqlite3VdbeAddOp3(v, OP_Divide, iMem+i+1, regTemp, regTemp);
+ sqlite3VdbeAddOp1(v, OP_ToInt, regTemp);
+ sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regF2, regF2);
}
- sqlite3VdbeOp3(v, OP_MakeRecord, 3, 0, "aaa", 0);
- sqlite3VdbeAddOp(v, OP_Insert, iStatCur, 0);
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, regFields, 3, regRec, "aaa", 0);
+ sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid);
+ sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid);
+ sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
sqlite3VdbeJumpHere(v, addr);
}
}
@@ -222,7 +230,9 @@ static void analyzeOneTable(
*/
static void loadAnalysis(Parse *pParse, int iDb){
Vdbe *v = sqlite3GetVdbe(pParse);
- sqlite3VdbeAddOp(v, OP_LoadAnalysis, iDb, 0);
+ if( v ){
+ sqlite3VdbeAddOp1(v, OP_LoadAnalysis, iDb);
+ }
}
/*
@@ -238,7 +248,7 @@ static void analyzeDatabase(Parse *pParse, int iDb){
sqlite3BeginWriteOperation(pParse, 0, iDb);
iStatCur = pParse->nTab++;
openStatTable(pParse, iDb, iStatCur, 0);
- iMem = pParse->nMem;
+ iMem = pParse->nMem+1;
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
Table *pTab = (Table*)sqliteHashData(k);
analyzeOneTable(pParse, pTab, iStatCur, iMem);
@@ -255,11 +265,12 @@ static void analyzeTable(Parse *pParse, Table *pTab){
int iStatCur;
assert( pTab!=0 );
+ assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
sqlite3BeginWriteOperation(pParse, 0, iDb);
iStatCur = pParse->nTab++;
openStatTable(pParse, iDb, iStatCur, pTab->zName);
- analyzeOneTable(pParse, pTab, iStatCur, pParse->nMem);
+ analyzeOneTable(pParse, pTab, iStatCur, pParse->nMem+1);
loadAnalysis(pParse, iDb);
}
@@ -285,6 +296,7 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
/* Read the database schema. If an error occurs, leave an error message
** and code in pParse and return NULL. */
+ assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
return;
}
@@ -301,11 +313,13 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
if( iDb>=0 ){
analyzeDatabase(pParse, iDb);
}else{
- z = sqlite3NameFromToken(pName1);
- pTab = sqlite3LocateTable(pParse, z, 0);
- sqliteFree(z);
- if( pTab ){
- analyzeTable(pParse, pTab);
+ z = sqlite3NameFromToken(db, pName1);
+ if( z ){
+ pTab = sqlite3LocateTable(pParse, 0, z, 0);
+ sqlite3_free(z);
+ if( pTab ){
+ analyzeTable(pParse, pTab);
+ }
}
}
}else{
@@ -313,11 +327,13 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName);
if( iDb>=0 ){
zDb = db->aDb[iDb].zName;
- z = sqlite3NameFromToken(pTableName);
- pTab = sqlite3LocateTable(pParse, z, zDb);
- sqliteFree(z);
- if( pTab ){
- analyzeTable(pParse, pTab);
+ z = sqlite3NameFromToken(db, pTableName);
+ if( z ){
+ pTab = sqlite3LocateTable(pParse, 0, z, zDb);
+ sqlite3_free(z);
+ if( pTab ){
+ analyzeTable(pParse, pTab);
+ }
}
}
}
@@ -371,10 +387,15 @@ static int analysisLoader(void *pData, int argc, char **argv, char **azNotUsed){
/*
** Load the content of the sqlite_stat1 table into the index hash tables.
*/
-void sqlite3AnalysisLoad(sqlite3 *db, int iDb){
+int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
analysisInfo sInfo;
HashElem *i;
char *zSql;
+ int rc;
+
+ assert( iDb>=0 && iDb<db->nDb );
+ assert( db->aDb[iDb].pBt!=0 );
+ assert( sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
/* Clear any prior statistics */
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
@@ -386,17 +407,18 @@ void sqlite3AnalysisLoad(sqlite3 *db, int iDb){
sInfo.db = db;
sInfo.zDatabase = db->aDb[iDb].zName;
if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){
- return;
+ return SQLITE_ERROR;
}
/* Load new statistics out of the sqlite_stat1 table */
- zSql = sqlite3MPrintf("SELECT idx, stat FROM %Q.sqlite_stat1",
+ zSql = sqlite3MPrintf(db, "SELECT idx, stat FROM %Q.sqlite_stat1",
sInfo.zDatabase);
- sqlite3SafetyOff(db);
- sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
- sqlite3SafetyOn(db);
- sqliteFree(zSql);
+ (void)sqlite3SafetyOff(db);
+ rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
+ (void)sqlite3SafetyOn(db);
+ sqlite3_free(zSql);
+ return rc;
}
diff --git a/ext/pdo_sqlite/sqlite/src/attach.c b/ext/pdo_sqlite/sqlite/src/attach.c
index 10abc49014..473a6c5992 100644
--- a/ext/pdo_sqlite/sqlite/src/attach.c
+++ b/ext/pdo_sqlite/sqlite/src/attach.c
@@ -15,6 +15,7 @@
*/
#include "sqliteInt.h"
+#ifndef SQLITE_OMIT_ATTACH
/*
** Resolve an expression that was part of an ATTACH or DETACH statement. This
** is slightly different from resolving a normal SQL expression, because simple
@@ -39,6 +40,10 @@ static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
if( pExpr ){
if( pExpr->op!=TK_ID ){
rc = sqlite3ExprResolveNames(pName, pExpr);
+ if( rc==SQLITE_OK && !sqlite3ExprIsConstant(pExpr) ){
+ sqlite3ErrorMsg(pName->pParse, "invalid name: \"%T\"", &pExpr->span);
+ return SQLITE_ERROR;
+ }
}else{
pExpr->op = TK_STRING;
}
@@ -68,8 +73,8 @@ static void attachFunc(
const char *zName;
const char *zFile;
Db *aNew;
- char zErr[128];
char *zErrDyn = 0;
+ char zErr[128];
zFile = (const char *)sqlite3_value_text(argv[0]);
zName = (const char *)sqlite3_value_text(argv[1]);
@@ -82,20 +87,23 @@ static void attachFunc(
** * Transaction currently open
** * Specified database name already being used.
*/
- if( db->nDb>=MAX_ATTACHED+2 ){
+ if( db->nDb>=SQLITE_MAX_ATTACHED+2 ){
sqlite3_snprintf(
- sizeof(zErr), zErr, "too many attached databases - max %d", MAX_ATTACHED
+ sizeof(zErr), zErr, "too many attached databases - max %d",
+ SQLITE_MAX_ATTACHED
);
goto attach_error;
}
if( !db->autoCommit ){
- strcpy(zErr, "cannot ATTACH database within transaction");
+ sqlite3_snprintf(sizeof(zErr), zErr,
+ "cannot ATTACH database within transaction");
goto attach_error;
}
for(i=0; i<db->nDb; i++){
char *z = db->aDb[i].zName;
if( z && zName && sqlite3StrICmp(z, zName)==0 ){
- sqlite3_snprintf(sizeof(zErr), zErr, "database %s is already in use", zName);
+ sqlite3_snprintf(sizeof(zErr), zErr,
+ "database %s is already in use", zName);
goto attach_error;
}
}
@@ -104,14 +112,16 @@ static void attachFunc(
** hash tables.
*/
if( db->aDb==db->aDbStatic ){
- aNew = sqliteMalloc( sizeof(db->aDb[0])*3 );
+ aNew = sqlite3_malloc( sizeof(db->aDb[0])*3 );
if( aNew==0 ){
+ db->mallocFailed = 1;
return;
}
memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
}else{
- aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
+ aNew = sqlite3_realloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
if( aNew==0 ){
+ db->mallocFailed = 1;
return;
}
}
@@ -123,23 +133,26 @@ static void attachFunc(
** 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);
+ rc = sqlite3BtreeFactory(db, zFile, 0, SQLITE_DEFAULT_CACHE_SIZE,
+ db->openFlags | SQLITE_OPEN_MAIN_DB,
+ &aNew->pBt);
if( rc==SQLITE_OK ){
- aNew->pSchema = sqlite3SchemaGet(aNew->pBt);
+ aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt);
if( !aNew->pSchema ){
rc = SQLITE_NOMEM;
}else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
- strcpy(zErr,
+ sqlite3_snprintf(sizeof(zErr), zErr,
"attached databases must use the same text encoding as main database");
goto attach_error;
}
+ sqlite3PagerLockingMode(sqlite3BtreePager(aNew->pBt), db->dfltLockMode);
}
- aNew->zName = sqliteStrDup(zName);
+ aNew->zName = sqlite3DbStrDup(db, zName);
aNew->safety_level = 3;
#if SQLITE_HAS_CODEC
{
- extern int sqlite3CodecAttach(sqlite3*, int, void*, int);
+ extern int sqlite3CodecAttach(sqlite3*, int, const void*, int);
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
int nKey;
char *zKey;
@@ -147,7 +160,7 @@ static void attachFunc(
switch( t ){
case SQLITE_INTEGER:
case SQLITE_FLOAT:
- zErrDyn = sqliteStrDup("Invalid key value");
+ zErrDyn = sqlite3DbStrDup(db, "Invalid key value");
rc = SQLITE_ERROR;
break;
@@ -173,9 +186,11 @@ static void attachFunc(
** we found it.
*/
if( rc==SQLITE_OK ){
- sqlite3SafetyOn(db);
+ (void)sqlite3SafetyOn(db);
+ sqlite3BtreeEnterAll(db);
rc = sqlite3Init(db, &zErrDyn);
- sqlite3SafetyOff(db);
+ sqlite3BtreeLeaveAll(db);
+ (void)sqlite3SafetyOff(db);
}
if( rc ){
int iDb = db->nDb - 1;
@@ -187,8 +202,8 @@ static void attachFunc(
}
sqlite3ResetInternalSchema(db, 0);
db->nDb = iDb;
- if( rc==SQLITE_NOMEM ){
- if( !sqlite3MallocFailed() ) sqlite3FailedMalloc();
+ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
+ db->mallocFailed = 1;
sqlite3_snprintf(sizeof(zErr),zErr, "out of memory");
}else{
sqlite3_snprintf(sizeof(zErr),zErr, "unable to open database: %s", zFile);
@@ -202,11 +217,12 @@ attach_error:
/* Return an error if we get here */
if( zErrDyn ){
sqlite3_result_error(context, zErrDyn, -1);
- sqliteFree(zErrDyn);
+ sqlite3_free(zErrDyn);
}else{
zErr[sizeof(zErr)-1] = 0;
sqlite3_result_error(context, zErr, -1);
}
+ if( rc ) sqlite3_result_error_code(context, rc);
}
/*
@@ -244,7 +260,8 @@ static void detachFunc(
goto detach_error;
}
if( !db->autoCommit ){
- strcpy(zErr, "cannot DETACH database within transaction");
+ sqlite3_snprintf(sizeof(zErr), zErr,
+ "cannot DETACH database within transaction");
goto detach_error;
}
if( sqlite3BtreeIsInReadTrans(pDb->pBt) ){
@@ -281,16 +298,17 @@ static void codeAttach(
Vdbe *v;
FuncDef *pFunc;
sqlite3* db = pParse->db;
+ int regArgs;
#ifndef SQLITE_OMIT_AUTHORIZATION
- assert( sqlite3MallocFailed() || pAuthArg );
+ assert( db->mallocFailed || pAuthArg );
if( pAuthArg ){
- char *zAuthArg = sqlite3NameFromToken(&pAuthArg->span);
+ char *zAuthArg = sqlite3NameFromToken(db, &pAuthArg->span);
if( !zAuthArg ){
goto attach_end;
}
rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0);
- sqliteFree(zAuthArg);
+ sqlite3_free(zAuthArg);
if(rc!=SQLITE_OK ){
goto attach_end;
}
@@ -310,21 +328,23 @@ static void codeAttach(
}
v = sqlite3GetVdbe(pParse);
- sqlite3ExprCode(pParse, pFilename);
- sqlite3ExprCode(pParse, pDbname);
- sqlite3ExprCode(pParse, pKey);
+ regArgs = sqlite3GetTempRange(pParse, 3);
+ sqlite3ExprCode(pParse, pFilename, regArgs);
+ sqlite3ExprCode(pParse, pDbname, regArgs+1);
+ sqlite3ExprCode(pParse, pKey, regArgs+2);
- assert( v || sqlite3MallocFailed() );
+ assert( v || db->mallocFailed );
if( v ){
- sqlite3VdbeAddOp(v, OP_Function, 0, nFunc);
+ sqlite3VdbeAddOp3(v, OP_Function, 0, regArgs+3-nFunc, regArgs);
+ sqlite3VdbeChangeP5(v, nFunc);
pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0);
- sqlite3VdbeChangeP3(v, -1, (char *)pFunc, P3_FUNCDEF);
+ sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_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);
+ sqlite3VdbeAddOp1(v, OP_Expire, (type==SQLITE_ATTACH));
}
attach_end:
@@ -350,14 +370,17 @@ void sqlite3Detach(Parse *pParse, Expr *pDbname){
void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
codeAttach(pParse, SQLITE_ATTACH, "sqlite_attach", 3, p, p, pDbname, pKey);
}
+#endif /* SQLITE_OMIT_ATTACH */
/*
** Register the functions sqlite_attach and sqlite_detach.
*/
void sqlite3AttachFunctions(sqlite3 *db){
+#ifndef SQLITE_OMIT_ATTACH
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);
+#endif
}
/*
@@ -412,7 +435,7 @@ int sqlite3FixSrcList(
zDb = pFix->zDb;
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
if( pItem->zDatabase==0 ){
- pItem->zDatabase = sqliteStrDup(zDb);
+ pItem->zDatabase = sqlite3DbStrDup(pFix->pParse->db, zDb);
}else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){
sqlite3ErrorMsg(pFix->pParse,
"%s %T cannot reference objects in database %s",
diff --git a/ext/pdo_sqlite/sqlite/src/auth.c b/ext/pdo_sqlite/sqlite/src/auth.c
index 3983c1bc69..dd83eda0aa 100644
--- a/ext/pdo_sqlite/sqlite/src/auth.c
+++ b/ext/pdo_sqlite/sqlite/src/auth.c
@@ -74,9 +74,11 @@ int sqlite3_set_authorizer(
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
void *pArg
){
+ sqlite3_mutex_enter(db->mutex);
db->xAuth = xAuth;
db->pAuthArg = pArg;
sqlite3ExpirePreparedStatements(db);
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
@@ -103,11 +105,12 @@ static void sqliteAuthBadReturnCode(Parse *pParse, int rc){
void sqlite3AuthRead(
Parse *pParse, /* The parser context */
Expr *pExpr, /* The expression to check authorization on */
+ Schema *pSchema, /* The schema of the expression */
SrcList *pTabList /* All table that pExpr might refer to */
){
sqlite3 *db = pParse->db;
int rc;
- Table *pTab; /* The table being read */
+ Table *pTab = 0; /* The table being read */
const char *zCol; /* Name of the column of the table */
int iSrc; /* Index in pTabList->a[] of table being read */
const char *zDBase; /* Name of database being accessed */
@@ -115,9 +118,8 @@ void sqlite3AuthRead(
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( pExpr->op!=TK_COLUMN ) return;
+ iDb = sqlite3SchemaToIndex(pParse->db, pSchema);
if( iDb<0 ){
/* An attempt to read a column out of a subquery or other
** temporary table. */
@@ -134,8 +136,6 @@ void sqlite3AuthRead(
*/
assert( pExpr->iTable==pStack->newIdx || pExpr->iTable==pStack->oldIdx );
pTab = pStack->pTab;
- }else{
- return;
}
if( pTab==0 ) return;
if( pExpr->iColumn>=0 ){
diff --git a/ext/pdo_sqlite/sqlite/src/btmutex.c b/ext/pdo_sqlite/sqlite/src/btmutex.c
new file mode 100644
index 0000000000..986368eaee
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/btmutex.c
@@ -0,0 +1,317 @@
+/*
+** 2007 August 27
+**
+** 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.
+**
+*************************************************************************
+**
+** $Id$
+**
+** This file contains code used to implement mutexes on Btree objects.
+** This code really belongs in btree.c. But btree.c is getting too
+** big and we want to break it down some. This packaged seemed like
+** a good breakout.
+*/
+#include "btreeInt.h"
+#if SQLITE_THREADSAFE && !defined(SQLITE_OMIT_SHARED_CACHE)
+
+
+/*
+** Enter a mutex on the given BTree object.
+**
+** If the object is not sharable, then no mutex is ever required
+** and this routine is a no-op. The underlying mutex is non-recursive.
+** But we keep a reference count in Btree.wantToLock so the behavior
+** of this interface is recursive.
+**
+** To avoid deadlocks, multiple Btrees are locked in the same order
+** by all database connections. The p->pNext is a list of other
+** Btrees belonging to the same database connection as the p Btree
+** which need to be locked after p. If we cannot get a lock on
+** p, then first unlock all of the others on p->pNext, then wait
+** for the lock to become available on p, then relock all of the
+** subsequent Btrees that desire a lock.
+*/
+void sqlite3BtreeEnter(Btree *p){
+ Btree *pLater;
+
+ /* Some basic sanity checking on the Btree. The list of Btrees
+ ** connected by pNext and pPrev should be in sorted order by
+ ** Btree.pBt value. All elements of the list should belong to
+ ** the same connection. Only shared Btrees are on the list. */
+ assert( p->pNext==0 || p->pNext->pBt>p->pBt );
+ assert( p->pPrev==0 || p->pPrev->pBt<p->pBt );
+ assert( p->pNext==0 || p->pNext->db==p->db );
+ assert( p->pPrev==0 || p->pPrev->db==p->db );
+ assert( p->sharable || (p->pNext==0 && p->pPrev==0) );
+
+ /* Check for locking consistency */
+ assert( !p->locked || p->wantToLock>0 );
+ assert( p->sharable || p->wantToLock==0 );
+
+ /* We should already hold a lock on the database connection */
+ assert( sqlite3_mutex_held(p->db->mutex) );
+
+ if( !p->sharable ) return;
+ p->wantToLock++;
+ if( p->locked ) return;
+
+#ifndef SQLITE_MUTEX_NOOP
+ /* In most cases, we should be able to acquire the lock we
+ ** want without having to go throught the ascending lock
+ ** procedure that follows. Just be sure not to block.
+ */
+ if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
+ p->locked = 1;
+ return;
+ }
+
+ /* To avoid deadlock, first release all locks with a larger
+ ** BtShared address. Then acquire our lock. Then reacquire
+ ** the other BtShared locks that we used to hold in ascending
+ ** order.
+ */
+ for(pLater=p->pNext; pLater; pLater=pLater->pNext){
+ assert( pLater->sharable );
+ assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt );
+ assert( !pLater->locked || pLater->wantToLock>0 );
+ if( pLater->locked ){
+ sqlite3_mutex_leave(pLater->pBt->mutex);
+ pLater->locked = 0;
+ }
+ }
+ sqlite3_mutex_enter(p->pBt->mutex);
+ p->locked = 1;
+ for(pLater=p->pNext; pLater; pLater=pLater->pNext){
+ if( pLater->wantToLock ){
+ sqlite3_mutex_enter(pLater->pBt->mutex);
+ pLater->locked = 1;
+ }
+ }
+#endif /* SQLITE_MUTEX_NOOP */
+}
+
+/*
+** Exit the recursive mutex on a Btree.
+*/
+void sqlite3BtreeLeave(Btree *p){
+ if( p->sharable ){
+ assert( p->wantToLock>0 );
+ p->wantToLock--;
+ if( p->wantToLock==0 ){
+ assert( p->locked );
+ sqlite3_mutex_leave(p->pBt->mutex);
+ p->locked = 0;
+ }
+ }
+}
+
+#ifndef NDEBUG
+/*
+** Return true if the BtShared mutex is held on the btree.
+**
+** This routine makes no determination one why or another if the
+** database connection mutex is held.
+**
+** This routine is used only from within assert() statements.
+*/
+int sqlite3BtreeHoldsMutex(Btree *p){
+ return (p->sharable==0 ||
+ (p->locked && p->wantToLock && sqlite3_mutex_held(p->pBt->mutex)));
+}
+#endif
+
+
+#ifndef SQLITE_OMIT_INCRBLOB
+/*
+** Enter and leave a mutex on a Btree given a cursor owned by that
+** Btree. These entry points are used by incremental I/O and can be
+** omitted if that module is not used.
+*/
+void sqlite3BtreeEnterCursor(BtCursor *pCur){
+ sqlite3BtreeEnter(pCur->pBtree);
+}
+void sqlite3BtreeLeaveCursor(BtCursor *pCur){
+ sqlite3BtreeLeave(pCur->pBtree);
+}
+#endif /* SQLITE_OMIT_INCRBLOB */
+
+
+/*
+** Enter the mutex on every Btree associated with a database
+** connection. This is needed (for example) prior to parsing
+** a statement since we will be comparing table and column names
+** against all schemas and we do not want those schemas being
+** reset out from under us.
+**
+** There is a corresponding leave-all procedures.
+**
+** Enter the mutexes in accending order by BtShared pointer address
+** to avoid the possibility of deadlock when two threads with
+** two or more btrees in common both try to lock all their btrees
+** at the same instant.
+*/
+void sqlite3BtreeEnterAll(sqlite3 *db){
+ int i;
+ Btree *p, *pLater;
+ assert( sqlite3_mutex_held(db->mutex) );
+ for(i=0; i<db->nDb; i++){
+ p = db->aDb[i].pBt;
+ if( p && p->sharable ){
+ p->wantToLock++;
+ if( !p->locked ){
+ assert( p->wantToLock==1 );
+ while( p->pPrev ) p = p->pPrev;
+ while( p->locked && p->pNext ) p = p->pNext;
+ for(pLater = p->pNext; pLater; pLater=pLater->pNext){
+ if( pLater->locked ){
+ sqlite3_mutex_leave(pLater->pBt->mutex);
+ pLater->locked = 0;
+ }
+ }
+ while( p ){
+ sqlite3_mutex_enter(p->pBt->mutex);
+ p->locked++;
+ p = p->pNext;
+ }
+ }
+ }
+ }
+}
+void sqlite3BtreeLeaveAll(sqlite3 *db){
+ int i;
+ Btree *p;
+ assert( sqlite3_mutex_held(db->mutex) );
+ for(i=0; i<db->nDb; i++){
+ p = db->aDb[i].pBt;
+ if( p && p->sharable ){
+ assert( p->wantToLock>0 );
+ p->wantToLock--;
+ if( p->wantToLock==0 ){
+ assert( p->locked );
+ sqlite3_mutex_leave(p->pBt->mutex);
+ p->locked = 0;
+ }
+ }
+ }
+}
+
+#ifndef NDEBUG
+/*
+** Return true if the current thread holds the database connection
+** mutex and all required BtShared mutexes.
+**
+** This routine is used inside assert() statements only.
+*/
+int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){
+ int i;
+ if( !sqlite3_mutex_held(db->mutex) ){
+ return 0;
+ }
+ for(i=0; i<db->nDb; i++){
+ Btree *p;
+ p = db->aDb[i].pBt;
+ if( p && p->sharable &&
+ (p->wantToLock==0 || !sqlite3_mutex_held(p->pBt->mutex)) ){
+ return 0;
+ }
+ }
+ return 1;
+}
+#endif /* NDEBUG */
+
+/*
+** Potentially dd a new Btree pointer to a BtreeMutexArray.
+** Really only add the Btree if it can possibly be shared with
+** another database connection.
+**
+** The Btrees are kept in sorted order by pBtree->pBt. That
+** way when we go to enter all the mutexes, we can enter them
+** in order without every having to backup and retry and without
+** worrying about deadlock.
+**
+** The number of shared btrees will always be small (usually 0 or 1)
+** so an insertion sort is an adequate algorithm here.
+*/
+void sqlite3BtreeMutexArrayInsert(BtreeMutexArray *pArray, Btree *pBtree){
+ int i, j;
+ BtShared *pBt;
+ if( pBtree==0 || pBtree->sharable==0 ) return;
+#ifndef NDEBUG
+ {
+ for(i=0; i<pArray->nMutex; i++){
+ assert( pArray->aBtree[i]!=pBtree );
+ }
+ }
+#endif
+ assert( pArray->nMutex>=0 );
+ assert( pArray->nMutex<sizeof(pArray->aBtree)/sizeof(pArray->aBtree[0])-1 );
+ pBt = pBtree->pBt;
+ for(i=0; i<pArray->nMutex; i++){
+ assert( pArray->aBtree[i]!=pBtree );
+ if( pArray->aBtree[i]->pBt>pBt ){
+ for(j=pArray->nMutex; j>i; j--){
+ pArray->aBtree[j] = pArray->aBtree[j-1];
+ }
+ pArray->aBtree[i] = pBtree;
+ pArray->nMutex++;
+ return;
+ }
+ }
+ pArray->aBtree[pArray->nMutex++] = pBtree;
+}
+
+/*
+** Enter the mutex of every btree in the array. This routine is
+** called at the beginning of sqlite3VdbeExec(). The mutexes are
+** exited at the end of the same function.
+*/
+void sqlite3BtreeMutexArrayEnter(BtreeMutexArray *pArray){
+ int i;
+ for(i=0; i<pArray->nMutex; i++){
+ Btree *p = pArray->aBtree[i];
+ /* Some basic sanity checking */
+ assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt );
+ assert( !p->locked || p->wantToLock>0 );
+
+ /* We should already hold a lock on the database connection */
+ assert( sqlite3_mutex_held(p->db->mutex) );
+
+ p->wantToLock++;
+ if( !p->locked && p->sharable ){
+ sqlite3_mutex_enter(p->pBt->mutex);
+ p->locked = 1;
+ }
+ }
+}
+
+/*
+** Leave the mutex of every btree in the group.
+*/
+void sqlite3BtreeMutexArrayLeave(BtreeMutexArray *pArray){
+ int i;
+ for(i=0; i<pArray->nMutex; i++){
+ Btree *p = pArray->aBtree[i];
+ /* Some basic sanity checking */
+ assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt );
+ assert( p->locked || !p->sharable );
+ assert( p->wantToLock>0 );
+
+ /* We should already hold a lock on the database connection */
+ assert( sqlite3_mutex_held(p->db->mutex) );
+
+ p->wantToLock--;
+ if( p->wantToLock==0 && p->locked ){
+ sqlite3_mutex_leave(p->pBt->mutex);
+ p->locked = 0;
+ }
+ }
+}
+
+
+#endif /* SQLITE_THREADSAFE && !SQLITE_OMIT_SHARED_CACHE */
diff --git a/ext/pdo_sqlite/sqlite/src/btree.c b/ext/pdo_sqlite/sqlite/src/btree.c
index 52bc749a32..c83b3ec8d8 100644
--- a/ext/pdo_sqlite/sqlite/src/btree.c
+++ b/ext/pdo_sqlite/sqlite/src/btree.c
@@ -12,490 +12,64 @@
** $Id$
**
** This file implements a external (disk-based) database using BTrees.
-** For a detailed discussion of BTrees, refer to
-**
-** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
-** "Sorting And Searching", pages 473-480. Addison-Wesley
-** Publishing Company, Reading, Massachusetts.
-**
-** The basic idea is that each page of the file contains N database
-** entries and N+1 pointers to subpages.
-**
-** ----------------------------------------------------------------
-** | Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N) | Ptr(N+1) |
-** ----------------------------------------------------------------
-**
-** All of the keys on the page that Ptr(0) points to have values less
-** than Key(0). All of the keys on page Ptr(1) and its subpages have
-** values greater than Key(0) and less than Key(1). All of the keys
-** on Ptr(N+1) and its subpages have values greater than Key(N). And
-** so forth.
-**
-** Finding a particular key requires reading O(log(M)) pages from the
-** disk where M is the number of entries in the tree.
-**
-** In this implementation, a single file can hold one or more separate
-** BTrees. Each BTree is identified by the index of its root page. The
-** key and data for any entry are combined to form the "payload". A
-** fixed amount of payload can be carried directly on the database
-** page. If the payload is larger than the preset amount then surplus
-** bytes are stored on overflow pages. The payload for an entry
-** and the preceding pointer are combined to form a "Cell". Each
-** page has a small header which contains the Ptr(N+1) pointer and other
-** information such as the size of key and data.
-**
-** FORMAT DETAILS
-**
-** The file is divided into pages. The first page is called page 1,
-** the second is page 2, and so forth. A page number of zero indicates
-** "no such page". The page size can be anything between 512 and 65536.
-** Each page can be either a btree page, a freelist page or an overflow
-** page.
-**
-** The first page is always a btree page. The first 100 bytes of the first
-** page contain a special header (the "file header") that describes the file.
-** The format of the file header is as follows:
-**
-** OFFSET SIZE DESCRIPTION
-** 0 16 Header string: "SQLite format 3\000"
-** 16 2 Page size in bytes.
-** 18 1 File format write version
-** 19 1 File format read version
-** 20 1 Bytes of unused space at the end of each page
-** 21 1 Max embedded payload fraction
-** 22 1 Min embedded payload fraction
-** 23 1 Min leaf payload fraction
-** 24 4 File change counter
-** 28 4 Reserved for future use
-** 32 4 First freelist page
-** 36 4 Number of freelist pages in the file
-** 40 60 15 4-byte meta values passed to higher layers
-**
-** All of the integer values are big-endian (most significant byte first).
-**
-** The file change counter is incremented when the database is changed more
-** than once within the same second. This counter, together with the
-** modification time of the file, allows other processes to know
-** when the file has changed and thus when they need to flush their
-** cache.
-**
-** The max embedded payload fraction is the amount of the total usable
-** space in a page that can be consumed by a single cell for standard
-** B-tree (non-LEAFDATA) tables. A value of 255 means 100%. The default
-** is to limit the maximum cell size so that at least 4 cells will fit
-** on one page. Thus the default max embedded payload fraction is 64.
-**
-** If the payload for a cell is larger than the max payload, then extra
-** payload is spilled to overflow pages. Once an overflow page is allocated,
-** as many bytes as possible are moved into the overflow pages without letting
-** the cell size drop below the min embedded payload fraction.
-**
-** The min leaf payload fraction is like the min embedded payload fraction
-** except that it applies to leaf nodes in a LEAFDATA tree. The maximum
-** payload fraction for a LEAFDATA tree is always 100% (or 255) and it
-** not specified in the header.
-**
-** Each btree pages is divided into three sections: The header, the
-** cell pointer array, and the cell area area. Page 1 also has a 100-byte
-** file header that occurs before the page header.
-**
-** |----------------|
-** | file header | 100 bytes. Page 1 only.
-** |----------------|
-** | page header | 8 bytes for leaves. 12 bytes for interior nodes
-** |----------------|
-** | cell pointer | | 2 bytes per cell. Sorted order.
-** | array | | Grows downward
-** | | v
-** |----------------|
-** | unallocated |
-** | space |
-** |----------------| ^ Grows upwards
-** | cell content | | Arbitrary order interspersed with freeblocks.
-** | area | | and free space fragments.
-** |----------------|
-**
-** The page headers looks like this:
-**
-** OFFSET SIZE DESCRIPTION
-** 0 1 Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf
-** 1 2 byte offset to the first freeblock
-** 3 2 number of cells on this page
-** 5 2 first byte of the cell content area
-** 7 1 number of fragmented free bytes
-** 8 4 Right child (the Ptr(N+1) value). Omitted on leaves.
-**
-** The flags define the format of this btree page. The leaf flag means that
-** this page has no children. The zerodata flag means that this page carries
-** only keys and no data. The intkey flag means that the key is a integer
-** which is stored in the key size entry of the cell header rather than in
-** the payload area.
-**
-** The cell pointer array begins on the first byte after the page header.
-** The cell pointer array contains zero or more 2-byte numbers which are
-** offsets from the beginning of the page to the cell content in the cell
-** content area. The cell pointers occur in sorted order. The system strives
-** to keep free space after the last cell pointer so that new cells can
-** be easily added without having to defragment the page.
-**
-** Cell content is stored at the very end of the page and grows toward the
-** beginning of the page.
-**
-** Unused space within the cell content area is collected into a linked list of
-** freeblocks. Each freeblock is at least 4 bytes in size. The byte offset
-** to the first freeblock is given in the header. Freeblocks occur in
-** increasing order. Because a freeblock must be at least 4 bytes in size,
-** any group of 3 or fewer unused bytes in the cell content area cannot
-** exist on the freeblock chain. A group of 3 or fewer free bytes is called
-** a fragment. The total number of bytes in all fragments is recorded.
-** in the page header at offset 7.
-**
-** SIZE DESCRIPTION
-** 2 Byte offset of the next freeblock
-** 2 Bytes in this freeblock
-**
-** Cells are of variable length. Cells are stored in the cell content area at
-** the end of the page. Pointers to the cells are in the cell pointer array
-** that immediately follows the page header. Cells is not necessarily
-** contiguous or in order, but cell pointers are contiguous and in order.
-**
-** Cell content makes use of variable length integers. A variable
-** length integer is 1 to 9 bytes where the lower 7 bits of each
-** byte are used. The integer consists of all bytes that have bit 8 set and
-** the first byte with bit 8 clear. The most significant byte of the integer
-** appears first. A variable-length integer may not be more than 9 bytes long.
-** As a special case, all 8 bytes of the 9th byte are used as data. This
-** allows a 64-bit integer to be encoded in 9 bytes.
-**
-** 0x00 becomes 0x00000000
-** 0x7f becomes 0x0000007f
-** 0x81 0x00 becomes 0x00000080
-** 0x82 0x00 becomes 0x00000100
-** 0x80 0x7f becomes 0x0000007f
-** 0x8a 0x91 0xd1 0xac 0x78 becomes 0x12345678
-** 0x81 0x81 0x81 0x81 0x01 becomes 0x10204081
-**
-** Variable length integers are used for rowids and to hold the number of
-** bytes of key and data in a btree cell.
-**
-** The content of a cell looks like this:
-**
-** SIZE DESCRIPTION
-** 4 Page number of the left child. Omitted if leaf flag is set.
-** var Number of bytes of data. Omitted if the zerodata flag is set.
-** var Number of bytes of key. Or the key itself if intkey flag is set.
-** * Payload
-** 4 First page of the overflow chain. Omitted if no overflow
-**
-** Overflow pages form a linked list. Each page except the last is completely
-** filled with data (pagesize - 4 bytes). The last page can have as little
-** as 1 byte of data.
-**
-** SIZE DESCRIPTION
-** 4 Page number of next overflow page
-** * Data
-**
-** Freelist pages come in two subtypes: trunk pages and leaf pages. The
-** file header points to first in a linked list of trunk page. Each trunk
-** page points to multiple leaf pages. The content of a leaf page is
-** unspecified. A trunk page looks like this:
-**
-** SIZE DESCRIPTION
-** 4 Page number of next trunk page
-** 4 Number of leaf pointers on this page
-** * zero or more pages numbers of leaves
-*/
-#include "sqliteInt.h"
-#include "pager.h"
-#include "btree.h"
-#include "os.h"
-#include <assert.h>
-
-/* Round up a number to the next larger multiple of 8. This is used
-** to force 8-byte alignment on 64-bit architectures.
+** See the header comment on "btreeInt.h" for additional information.
+** Including a description of file format and an overview of operation.
*/
-#define ROUND8(x) ((x+7)&~7)
-
-
-/* The following value is the maximum cell size assuming a maximum page
-** size give above.
-*/
-#define MX_CELL_SIZE(pBt) (pBt->pageSize-8)
-
-/* The maximum number of cells on a single page of the database. This
-** assumes a minimum cell size of 3 bytes. Such small cells will be
-** exceedingly rare, but they are possible.
-*/
-#define MX_CELL(pBt) ((pBt->pageSize-8)/3)
-
-/* Forward declarations */
-typedef struct MemPage MemPage;
-typedef struct BtLock BtLock;
-
-/*
-** This is a magic string that appears at the beginning of every
-** SQLite database in order to identify the file as a real database.
-**
-** You can change this value at compile-time by specifying a
-** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The
-** header must be exactly 16 bytes including the zero-terminator so
-** the string itself should be 15 characters long. If you change
-** the header, then your custom library will not be able to read
-** databases generated by the standard tools and the standard tools
-** will not be able to read databases created by your custom library.
-*/
-#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
-# define SQLITE_FILE_HEADER "SQLite format 3"
-#endif
-static const char zMagicHeader[] = SQLITE_FILE_HEADER;
-
-/*
-** Page type flags. An ORed combination of these flags appear as the
-** first byte of every BTree page.
-*/
-#define PTF_INTKEY 0x01
-#define PTF_ZERODATA 0x02
-#define PTF_LEAFDATA 0x04
-#define PTF_LEAF 0x08
-
-/*
-** As each page of the file is loaded into memory, an instance of the following
-** structure is appended and initialized to zero. This structure stores
-** information about the page that is decoded from the raw file page.
-**
-** The pParent field points back to the parent page. This allows us to
-** walk up the BTree from any leaf to the root. Care must be taken to
-** unref() the parent page pointer when this page is no longer referenced.
-** The pageDestructor() routine handles that chore.
-*/
-struct MemPage {
- u8 isInit; /* True if previously initialized. MUST BE FIRST! */
- u8 idxShift; /* True if Cell indices have changed */
- u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
- u8 intKey; /* True if intkey flag is set */
- u8 leaf; /* True if leaf flag is set */
- u8 zeroData; /* True if table stores keys only */
- u8 leafData; /* True if tables stores data on leaves only */
- u8 hasData; /* True if this page stores data */
- u8 hdrOffset; /* 100 for page 1. 0 otherwise */
- u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
- u16 maxLocal; /* Copy of Btree.maxLocal or Btree.maxLeaf */
- u16 minLocal; /* Copy of Btree.minLocal or Btree.minLeaf */
- u16 cellOffset; /* Index in aData of first cell pointer */
- u16 idxParent; /* Index in parent of this node */
- 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 */
- } aOvfl[5];
- 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 */
-};
-
-/*
-** The in-memory image of a disk page has the auxiliary information appended
-** to the end. EXTRA_SIZE is the number of bytes of space needed to hold
-** that extra information.
-*/
-#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 BtShared {
- Pager *pPager; /* The page cache */
- BtCursor *pCursor; /* A list of all open cursors */
- MemPage *pPage1; /* First page of the database */
- 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 */
- u8 minEmbedFrac; /* Minimum payload as % of total page size */
- u8 minLeafFrac; /* Minimum leaf payload as % of total page size */
- u8 pageSizeFixed; /* True if the page size can no longer be changed */
-#ifndef SQLITE_OMIT_AUTOVACUUM
- u8 autoVacuum; /* True if database supports auto-vacuum */
-#endif
- u16 pageSize; /* Total number of bytes on a page */
- u16 usableSize; /* Number of usable bytes on each page */
- int maxLocal; /* Maximum local payload in non-LEAFDATA tables */
- int minLocal; /* Minimum local payload in non-LEAFDATA tables */
- 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
-};
-
-/*
-** An instance of the following structure is used to hold information
-** about a cell. The parseCellPtr() function fills in this structure
-** based on information extract from the raw disk page.
-*/
-typedef struct CellInfo CellInfo;
-struct CellInfo {
- u8 *pCell; /* Pointer to the start of cell content */
- i64 nKey; /* The key for INTKEY tables, or number of bytes in key */
- u32 nData; /* Number of bytes of data */
- u16 nHeader; /* Size of the cell content header in bytes */
- u16 nLocal; /* Amount of payload held locally */
- u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */
- u16 nSize; /* Size of the cell content on the main b-tree page */
-};
-
-/*
-** A cursor is a pointer to a particular entry in the BTree.
-** The entry is identified by its MemPage and the index in
-** MemPage.aCell[] of the entry.
-*/
-struct BtCursor {
- 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() */
- Pgno pgnoRoot; /* The root page of this tree */
- MemPage *pPage; /* Page that contains the entry */
- 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 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
-};
+#include "btreeInt.h"
/*
-** 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.
+** The header string that appears at the beginning of every
+** SQLite database.
*/
-#define CURSOR_INVALID 0
-#define CURSOR_VALID 1
-#define CURSOR_REQUIRESEEK 2
+static const char zMagicHeader[] = SQLITE_FILE_HEADER;
/*
-** The TRACE macro will print high-level status information about the
-** btree operation when the global variable sqlite3_btree_trace is
-** enabled.
+** Set this global variable to 1 to enable tracing using the TRACE
+** macro.
*/
#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
-/*
-** Forward declaration
-*/
-static int checkReadLocks(BtShared*,Pgno,BtCursor*);
-/*
-** Read or write a two- and four-byte big-endian integer values.
-*/
-static u32 get2byte(unsigned char *p){
- return (p[0]<<8) | p[1];
-}
-static u32 get4byte(unsigned char *p){
- return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
-}
-static void put2byte(unsigned char *p, u32 v){
- p[0] = v>>8;
- p[1] = v;
-}
-static void put4byte(unsigned char *p, u32 v){
- p[0] = v>>24;
- p[1] = v>>16;
- p[2] = v>>8;
- p[3] = v;
-}
+#ifndef SQLITE_OMIT_SHARED_CACHE
/*
-** Routines to read and write variable-length integers. These used to
-** be defined locally, but now we use the varint routines in the util.c
-** file.
+** A flag to indicate whether or not shared cache is enabled. Also,
+** a list of BtShared objects that are eligible for participation
+** in shared cache. The variables have file scope during normal builds,
+** but the test harness needs to access these variables so we make them
+** global for test builds.
*/
-#define getVarint sqlite3GetVarint
-/* #define getVarint32 sqlite3GetVarint32 */
-#define getVarint32(A,B) ((*B=*(A))<=0x7f?1:sqlite3GetVarint32(A,B))
-#define putVarint sqlite3PutVarint
+#ifdef SQLITE_TEST
+BtShared *sqlite3SharedCacheList = 0;
+int sqlite3SharedCacheEnabled = 0;
+#else
+static BtShared *sqlite3SharedCacheList = 0;
+static int sqlite3SharedCacheEnabled = 0;
+#endif
+#endif /* SQLITE_OMIT_SHARED_CACHE */
-/* 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).
+#ifndef SQLITE_OMIT_SHARED_CACHE
+/*
+** Enable or disable the shared pager and schema features.
**
-** If disk I/O is omitted (meaning that the database is stored purely
-** in memory) then there is no pending byte.
+** This routine has no effect on existing database connections.
+** The shared cache setting effects only future calls to
+** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2().
*/
-#ifdef SQLITE_OMIT_DISKIO
-# define PENDING_BYTE_PAGE(pBt) 0x7fffffff
-#else
-# define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1)
+int sqlite3_enable_shared_cache(int enable){
+ sqlite3SharedCacheEnabled = enable;
+ return SQLITE_OK;
+}
#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.
+** Forward declaration
*/
-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 */
-};
+static int checkReadLocks(Btree*,Pgno,BtCursor*);
-/* Candidate values for BtLock.eLock */
-#define READ_LOCK 1
-#define WRITE_LOCK 2
#ifdef SQLITE_OMIT_SHARED_CACHE
/*
@@ -509,106 +83,9 @@ struct BtLock {
#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)
+#endif
+#ifndef SQLITE_OMIT_SHARED_CACHE
/*
** 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
@@ -619,11 +96,20 @@ static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){
BtShared *pBt = p->pBt;
BtLock *pIter;
+ assert( sqlite3BtreeHoldsMutex(p) );
+
/* This is a no-op if the shared-cache is not enabled */
- if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){
+ if( !p->sharable ){
return SQLITE_OK;
}
+ /* If some other connection is holding an exclusive lock, the
+ ** requested lock may not be obtained.
+ */
+ if( pBt->pExclusive && pBt->pExclusive!=p ){
+ return SQLITE_LOCKED;
+ }
+
/* 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
@@ -639,8 +125,8 @@ static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){
** write-cursor does not change.
*/
if(
- !p->pSqlite ||
- 0==(p->pSqlite->flags&SQLITE_ReadUncommitted) ||
+ !p->db ||
+ 0==(p->db->flags&SQLITE_ReadUncommitted) ||
eLock==WRITE_LOCK ||
iTab==MASTER_ROOT
){
@@ -653,7 +139,9 @@ static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){
}
return SQLITE_OK;
}
+#endif /* !SQLITE_OMIT_SHARED_CACHE */
+#ifndef SQLITE_OMIT_SHARED_CACHE
/*
** 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
@@ -667,8 +155,10 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){
BtLock *pLock = 0;
BtLock *pIter;
+ assert( sqlite3BtreeHoldsMutex(p) );
+
/* This is a no-op if the shared-cache is not enabled */
- if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){
+ if( !p->sharable ){
return SQLITE_OK;
}
@@ -680,8 +170,8 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){
** the ReadUncommitted flag.
*/
if(
- (p->pSqlite) &&
- (p->pSqlite->flags&SQLITE_ReadUncommitted) &&
+ (p->db) &&
+ (p->db->flags&SQLITE_ReadUncommitted) &&
(eLock==READ_LOCK) &&
iTable!=MASTER_ROOT
){
@@ -700,7 +190,7 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){
** with table iTable, allocate one and link it into the list.
*/
if( !pLock ){
- pLock = (BtLock *)sqliteMalloc(sizeof(BtLock));
+ pLock = (BtLock *)sqlite3MallocZero(sizeof(BtLock));
if( !pLock ){
return SQLITE_NOMEM;
}
@@ -721,56 +211,200 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){
return SQLITE_OK;
}
+#endif /* !SQLITE_OMIT_SHARED_CACHE */
+#ifndef SQLITE_OMIT_SHARED_CACHE
/*
** 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;
+ BtShared *pBt = p->pBt;
+ BtLock **ppIter = &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 );
+ assert( sqlite3BtreeHoldsMutex(p) );
+ assert( p->sharable || 0==*ppIter );
while( *ppIter ){
BtLock *pLock = *ppIter;
+ assert( pBt->pExclusive==0 || pBt->pExclusive==pLock->pBtree );
if( pLock->pBtree==p ){
*ppIter = pLock->pNext;
- sqliteFree(pLock);
+ sqlite3_free(pLock);
}else{
ppIter = &pLock->pNext;
}
}
+
+ if( pBt->pExclusive==p ){
+ pBt->pExclusive = 0;
+ }
}
#endif /* SQLITE_OMIT_SHARED_CACHE */
-#ifndef SQLITE_OMIT_AUTOVACUUM
+static void releasePage(MemPage *pPage); /* Forward reference */
+
/*
-** These macros define the location of the pointer-map entry for a
-** database page. The first argument to each is the number of usable
-** bytes on each page of the database (often 1024). The second is the
-** page number to look up in the pointer map.
-**
-** PTRMAP_PAGENO returns the database page number of the pointer-map
-** page that stores the required pointer. PTRMAP_PTROFFSET returns
-** the offset of the requested map entry.
+** Verify that the cursor holds a mutex on the BtShared
+*/
+#ifndef NDEBUG
+static int cursorHoldsMutex(BtCursor *p){
+ return sqlite3_mutex_held(p->pBt->mutex);
+}
+#endif
+
+
+#ifndef SQLITE_OMIT_INCRBLOB
+/*
+** Invalidate the overflow page-list cache for cursor pCur, if any.
+*/
+static void invalidateOverflowCache(BtCursor *pCur){
+ assert( cursorHoldsMutex(pCur) );
+ sqlite3_free(pCur->aOverflow);
+ pCur->aOverflow = 0;
+}
+
+/*
+** Invalidate the overflow page-list cache for all cursors opened
+** on the shared btree structure pBt.
+*/
+static void invalidateAllOverflowCache(BtShared *pBt){
+ BtCursor *p;
+ assert( sqlite3_mutex_held(pBt->mutex) );
+ for(p=pBt->pCursor; p; p=p->pNext){
+ invalidateOverflowCache(p);
+ }
+}
+#else
+ #define invalidateOverflowCache(x)
+ #define invalidateAllOverflowCache(x)
+#endif
+
+/*
+** 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 );
+ assert( cursorHoldsMutex(pCur) );
+
+ 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 = sqlite3_malloc(pCur->nKey);
+ if( pKey ){
+ rc = sqlite3BtreeKey(pCur, 0, pCur->nKey, pKey);
+ if( rc==SQLITE_OK ){
+ pCur->pKey = pKey;
+ }else{
+ sqlite3_free(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;
+ }
+
+ invalidateOverflowCache(pCur);
+ 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;
+ assert( sqlite3_mutex_held(pBt->mutex) );
+ assert( pExcept==0 || pExcept->pBt==pBt );
+ 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;
+}
+
+/*
+** Clear the current cursor position.
+*/
+static void clearCursorPosition(BtCursor *pCur){
+ assert( cursorHoldsMutex(pCur) );
+ sqlite3_free(pCur->pKey);
+ pCur->pKey = 0;
+ pCur->eState = CURSOR_INVALID;
+}
+
+/*
+** 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 pgno argument passed to PTRMAP_PAGENO is a pointer-map page,
-** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
-** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
-** this test.
+** If the second argument argument - doSeek - is false, then instead of
+** returning the cursor to its saved position, any saved position is deleted
+** and the cursor state set to CURSOR_INVALID.
*/
-#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))
+int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){
+ int rc;
+ assert( cursorHoldsMutex(pCur) );
+ assert( pCur->eState>=CURSOR_REQUIRESEEK );
+ if( pCur->eState==CURSOR_FAULT ){
+ return pCur->skip;
+ }
+#ifndef SQLITE_OMIT_INCRBLOB
+ if( pCur->isIncrblobHandle ){
+ return SQLITE_ABORT;
+ }
+#endif
+ pCur->eState = CURSOR_INVALID;
+ rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &pCur->skip);
+ if( rc==SQLITE_OK ){
+ sqlite3_free(pCur->pKey);
+ pCur->pKey = 0;
+ assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID );
+ }
+ return rc;
+}
+#define restoreOrClearCursorPosition(p) \
+ (p->eState>=CURSOR_REQUIRESEEK ? \
+ sqlite3BtreeRestoreOrClearCursorPosition(p) : \
+ SQLITE_OK)
+
+#ifndef SQLITE_OMIT_AUTOVACUUM
+/*
+** Given a page number of a regular database page, return the page
+** number for the pointer-map page that contains the entry for the
+** input page number.
+*/
static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){
- int nPagesPerMapPage = (pBt->usableSize/5)+1;
- int iPtrMap = (pgno-2)/nPagesPerMapPage;
- int ret = (iPtrMap*nPagesPerMapPage) + 2;
+ int nPagesPerMapPage, iPtrMap, ret;
+ assert( sqlite3_mutex_held(pBt->mutex) );
+ nPagesPerMapPage = (pBt->usableSize/5)+1;
+ iPtrMap = (pgno-2)/nPagesPerMapPage;
+ ret = (iPtrMap*nPagesPerMapPage) + 2;
if( ret==PENDING_BYTE_PAGE(pBt) ){
ret++;
}
@@ -778,43 +412,6 @@ static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){
}
/*
-** The pointer map is a lookup table that identifies the parent page for
-** each child page in the database file. The parent page is the page that
-** contains a pointer to the child. Every page in the database contains
-** 0 or 1 parent pages. (In this context 'database page' refers
-** to any page that is not part of the pointer map itself.) Each pointer map
-** entry consists of a single byte 'type' and a 4 byte parent page number.
-** The PTRMAP_XXX identifiers below are the valid types.
-**
-** The purpose of the pointer map is to facility moving pages from one
-** position in the file to another as part of autovacuum. When a page
-** is moved, the pointer in its parent must be updated to point to the
-** new location. The pointer map is used to locate the parent page quickly.
-**
-** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not
-** used in this case.
-**
-** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number
-** is not used in this case.
-**
-** PTRMAP_OVERFLOW1: The database page is the first page in a list of
-** overflow pages. The page number identifies the page that
-** contains the cell with a pointer to this overflow page.
-**
-** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of
-** overflow pages. The page-number identifies the previous
-** page in the overflow page list.
-**
-** PTRMAP_BTREE: The database page is a non-root btree page. The page number
-** identifies the parent page in the btree.
-*/
-#define PTRMAP_ROOTPAGE 1
-#define PTRMAP_FREEPAGE 2
-#define PTRMAP_OVERFLOW1 3
-#define PTRMAP_OVERFLOW2 4
-#define PTRMAP_BTREE 5
-
-/*
** Write an entry into the pointer map.
**
** This routine updates the pointer map entry for page number 'key'
@@ -822,11 +419,13 @@ static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){
** An error code is returned if something goes wrong, otherwise SQLITE_OK.
*/
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 */
+ DbPage *pDbPage; /* The pointer map page */
+ u8 *pPtrmap; /* The pointer map data */
+ Pgno iPtrmap; /* The pointer map page number */
+ int offset; /* Offset in pointer map page */
int rc;
+ assert( sqlite3_mutex_held(pBt->mutex) );
/* The master-journal page number must never be used as a pointer map page */
assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) );
@@ -835,22 +434,23 @@ static int ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent){
return SQLITE_CORRUPT_BKPT;
}
iPtrmap = PTRMAP_PAGENO(pBt, key);
- rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
+ rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage);
if( rc!=SQLITE_OK ){
return rc;
}
offset = PTRMAP_PTROFFSET(pBt, key);
+ pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));
- rc = sqlite3pager_write(pPtrmap);
+ rc = sqlite3PagerWrite(pDbPage);
if( rc==SQLITE_OK ){
pPtrmap[offset] = eType;
put4byte(&pPtrmap[offset+1], parent);
}
}
- sqlite3pager_unref(pPtrmap);
+ sqlite3PagerUnref(pDbPage);
return rc;
}
@@ -862,23 +462,27 @@ static int ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent){
** An error code is returned if something goes wrong, otherwise SQLITE_OK.
*/
static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
+ DbPage *pDbPage; /* The pointer map page */
int iPtrmap; /* Pointer map page index */
u8 *pPtrmap; /* Pointer map page data */
int offset; /* Offset of entry in pointer map */
int rc;
+ assert( sqlite3_mutex_held(pBt->mutex) );
+
iPtrmap = PTRMAP_PAGENO(pBt, key);
- rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
+ rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage);
if( rc!=0 ){
return rc;
}
+ pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
offset = PTRMAP_PTROFFSET(pBt, key);
assert( pEType!=0 );
*pEType = pPtrmap[offset];
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
- sqlite3pager_unref(pPtrmap);
+ sqlite3PagerUnref(pDbPage);
if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT;
return SQLITE_OK;
}
@@ -892,19 +496,23 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
**
** This routine works only for pages that do not contain overflow cells.
*/
-static u8 *findCell(MemPage *pPage, int iCell){
- u8 *data = pPage->aData;
+#define findCell(pPage, iCell) \
+ ((pPage)->aData + get2byte(&(pPage)->aData[(pPage)->cellOffset+2*(iCell)]))
+#ifdef SQLITE_TEST
+u8 *sqlite3BtreeFindCell(MemPage *pPage, int iCell){
assert( iCell>=0 );
- assert( iCell<get2byte(&data[pPage->hdrOffset+3]) );
- return data + get2byte(&data[pPage->cellOffset+2*iCell]);
+ assert( iCell<get2byte(&pPage->aData[pPage->hdrOffset+3]) );
+ return findCell(pPage, iCell);
}
+#endif
/*
-** This a more complex version of findCell() that works for
+** This a more complex version of sqlite3BtreeFindCell() that works for
** pages that do contain overflow cells. See insert
*/
static u8 *findOverflowCell(MemPage *pPage, int iCell){
int i;
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
for(i=pPage->nOverflow-1; i>=0; i--){
int k;
struct _OvflCell *pOvfl;
@@ -922,11 +530,14 @@ static u8 *findOverflowCell(MemPage *pPage, int iCell){
/*
** Parse a cell content block and fill in the CellInfo structure. There
-** are two versions of this function. parseCell() takes a cell index
-** as the second argument and parseCellPtr() takes a pointer to the
-** body of the cell as its second argument.
+** are two versions of this function. sqlite3BtreeParseCell() takes a
+** cell index as the second argument and sqlite3BtreeParseCellPtr()
+** takes a pointer to the body of the cell as its second argument.
+**
+** Within this file, the parseCell() macro can be called instead of
+** sqlite3BtreeParseCellPtr(). Using some compilers, this will be faster.
*/
-static void parseCellPtr(
+void sqlite3BtreeParseCellPtr(
MemPage *pPage, /* Page containing the cell */
u8 *pCell, /* Pointer to the cell text. */
CellInfo *pInfo /* Fill in this structure */
@@ -934,6 +545,8 @@ static void parseCellPtr(
int n; /* Number bytes in cell content header */
u32 nPayload; /* Number of bytes of cell payload */
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+
pInfo->pCell = pCell;
assert( pPage->leaf==0 || pPage->leaf==1 );
n = pPage->childPtrSize;
@@ -952,6 +565,7 @@ static void parseCellPtr(
pInfo->nKey = x;
nPayload += x;
}
+ pInfo->nPayload = nPayload;
pInfo->nHeader = n;
if( nPayload<=pPage->maxLocal ){
/* This is the (easy) common case where the entire payload fits
@@ -991,12 +605,14 @@ static void parseCellPtr(
pInfo->nSize = pInfo->iOverflow + 4;
}
}
-static void parseCell(
+#define parseCell(pPage, iCell, pInfo) \
+ sqlite3BtreeParseCellPtr((pPage), findCell((pPage), (iCell)), (pInfo))
+void sqlite3BtreeParseCell(
MemPage *pPage, /* Page containing the cell */
int iCell, /* The cell index. First cell is 0 */
CellInfo *pInfo /* Fill in this structure */
){
- parseCellPtr(pPage, findCell(pPage, iCell), pInfo);
+ parseCell(pPage, iCell, pInfo);
}
/*
@@ -1008,13 +624,13 @@ static void parseCell(
#ifndef NDEBUG
static int cellSize(MemPage *pPage, int iCell){
CellInfo info;
- parseCell(pPage, iCell, &info);
+ sqlite3BtreeParseCell(pPage, iCell, &info);
return info.nSize;
}
#endif
static int cellSizePtr(MemPage *pPage, u8 *pCell){
CellInfo info;
- parseCellPtr(pPage, pCell, &info);
+ sqlite3BtreeParseCellPtr(pPage, pCell, &info);
return info.nSize;
}
@@ -1027,7 +643,8 @@ static int cellSizePtr(MemPage *pPage, u8 *pCell){
static int ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell){
if( pCell ){
CellInfo info;
- parseCellPtr(pPage, pCell, &info);
+ sqlite3BtreeParseCellPtr(pPage, pCell, &info);
+ assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload );
if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){
Pgno ovfl = get4byte(&pCell[info.iOverflow]);
return ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno);
@@ -1042,6 +659,7 @@ static int ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell){
*/
static int ptrmapPutOvfl(MemPage *pPage, int iCell){
u8 *pCell;
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
pCell = findOverflowCell(pPage, iCell);
return ptrmapPutOvflPtr(pPage, pCell);
}
@@ -1049,100 +667,6 @@ static int ptrmapPutOvfl(MemPage *pPage, int iCell){
/*
-** Do sanity checking on a page. Throw an exception if anything is
-** not right.
-**
-** This routine is used for internal error checking only. It is omitted
-** from most builds.
-*/
-#if defined(BTREE_DEBUG) && !defined(NDEBUG) && 0
-static void _pageIntegrity(MemPage *pPage){
- int usableSize;
- u8 *data;
- int i, j, idx, c, pc, hdr, nFree;
- int cellOffset;
- int nCell, cellLimit;
- u8 *used;
-
- used = sqliteMallocRaw( pPage->pBt->pageSize );
- if( used==0 ) return;
- usableSize = pPage->pBt->usableSize;
- assert( pPage->aData==&((unsigned char*)pPage)[-pPage->pBt->pageSize] );
- hdr = pPage->hdrOffset;
- assert( hdr==(pPage->pgno==1 ? 100 : 0) );
- assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
- c = pPage->aData[hdr];
- if( pPage->isInit ){
- assert( pPage->leaf == ((c & PTF_LEAF)!=0) );
- assert( pPage->zeroData == ((c & PTF_ZERODATA)!=0) );
- assert( pPage->leafData == ((c & PTF_LEAFDATA)!=0) );
- assert( pPage->intKey == ((c & (PTF_INTKEY|PTF_LEAFDATA))!=0) );
- assert( pPage->hasData ==
- !(pPage->zeroData || (!pPage->leaf && pPage->leafData)) );
- assert( pPage->cellOffset==pPage->hdrOffset+12-4*pPage->leaf );
- assert( pPage->nCell = get2byte(&pPage->aData[hdr+3]) );
- }
- data = pPage->aData;
- memset(used, 0, usableSize);
- for(i=0; i<hdr+10-pPage->leaf*4; i++) used[i] = 1;
- nFree = 0;
- pc = get2byte(&data[hdr+1]);
- while( pc ){
- int size;
- assert( pc>0 && pc<usableSize-4 );
- size = get2byte(&data[pc+2]);
- assert( pc+size<=usableSize );
- nFree += size;
- for(i=pc; i<pc+size; i++){
- assert( used[i]==0 );
- used[i] = 1;
- }
- pc = get2byte(&data[pc]);
- }
- idx = 0;
- nCell = get2byte(&data[hdr+3]);
- cellLimit = get2byte(&data[hdr+5]);
- assert( pPage->isInit==0
- || pPage->nFree==nFree+data[hdr+7]+cellLimit-(cellOffset+2*nCell) );
- cellOffset = pPage->cellOffset;
- for(i=0; i<nCell; i++){
- int size;
- pc = get2byte(&data[cellOffset+2*i]);
- assert( pc>0 && pc<usableSize-4 );
- size = cellSize(pPage, &data[pc]);
- assert( pc+size<=usableSize );
- for(j=pc; j<pc+size; j++){
- assert( used[j]==0 );
- used[j] = 1;
- }
- }
- for(i=cellOffset+2*nCell; i<cellimit; i++){
- assert( used[i]==0 );
- used[i] = 1;
- }
- nFree = 0;
- for(i=0; i<usableSize; i++){
- assert( used[i]<=1 );
- if( used[i]==0 ) nFree++;
- }
- assert( nFree==data[hdr+7] );
- sqliteFree(used);
-}
-#define pageIntegrity(X) _pageIntegrity(X)
-#else
-# 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
** end of the page and all free space is collected into one
** big FreeBlk that occurs in between the header and cell
@@ -1161,12 +685,12 @@ static int defragmentPage(MemPage *pPage){
unsigned char *data; /* The page data */
unsigned char *temp; /* Temp area for cell content */
- assert( sqlite3pager_iswriteable(pPage->aData) );
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( pPage->pBt!=0 );
assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE );
assert( pPage->nOverflow==0 );
- temp = sqliteMalloc( pPage->pBt->pageSize );
- if( temp==0 ) return SQLITE_NOMEM;
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+ temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
data = pPage->aData;
hdr = pPage->hdrOffset;
cellOffset = pPage->cellOffset;
@@ -1193,7 +717,6 @@ static int defragmentPage(MemPage *pPage){
data[hdr+7] = 0;
addr = cellOffset+2*nCell;
memset(&data[addr], 0, brk-addr);
- sqliteFree(temp);
return SQLITE_OK;
}
@@ -1219,8 +742,9 @@ static int allocateSpace(MemPage *pPage, int nByte){
unsigned char *data;
data = pPage->aData;
- assert( sqlite3pager_iswriteable(data) );
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( pPage->pBt );
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
if( nByte<4 ) nByte = 4;
if( pPage->nFree<nByte || pPage->nOverflow>0 ) return 0;
pPage->nFree -= nByte;
@@ -1276,9 +800,10 @@ static void freeSpace(MemPage *pPage, int start, int size){
unsigned char *data = pPage->aData;
assert( pPage->pBt!=0 );
- assert( sqlite3pager_iswriteable(data) );
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( start>=pPage->hdrOffset+6+(pPage->leaf?0:4) );
assert( (start + size)<=pPage->pBt->usableSize );
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
if( size<4 ) size = 4;
#ifdef SQLITE_SECURE_DELETE
@@ -1339,6 +864,7 @@ static void decodeFlags(MemPage *pPage, int flagByte){
BtShared *pBt; /* A copy of pPage->pBt */
assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) );
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
pPage->intKey = (flagByte & (PTF_INTKEY|PTF_LEAFDATA))!=0;
pPage->zeroData = (flagByte & PTF_ZERODATA)!=0;
pPage->leaf = (flagByte & PTF_LEAF)!=0;
@@ -1369,7 +895,7 @@ static void decodeFlags(MemPage *pPage, int flagByte){
** guarantee that the page is well-formed. It only shows that
** we failed to detect any corruption.
*/
-static int initPage(
+int sqlite3BtreeInitPage(
MemPage *pPage, /* The page to be initialized */
MemPage *pParent /* The parent. Might be NULL */
){
@@ -1385,8 +911,10 @@ static int initPage(
pBt = pPage->pBt;
assert( pBt!=0 );
assert( pParent==0 || pParent->pBt==pBt );
- assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
- assert( pPage->aData == &((unsigned char*)pPage)[-pBt->pageSize] );
+ assert( sqlite3_mutex_held(pBt->mutex) );
+ assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) );
+ assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) );
+ assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) );
if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){
/* The parent page should never change unless the file is corrupt */
return SQLITE_CORRUPT_BKPT;
@@ -1394,7 +922,7 @@ static int initPage(
if( pPage->isInit ) return SQLITE_OK;
if( pPage->pParent==0 && pParent!=0 ){
pPage->pParent = pParent;
- sqlite3pager_ref(pParent->aData);
+ sqlite3PagerRef(pParent->pDbPage);
}
hdr = pPage->hdrOffset;
data = pPage->aData;
@@ -1439,7 +967,6 @@ static int initPage(
}
pPage->isInit = 1;
- pageIntegrity(pPage);
return SQLITE_OK;
}
@@ -1453,9 +980,11 @@ static void zeroPage(MemPage *pPage, int flags){
int hdr = pPage->hdrOffset;
int first;
- assert( sqlite3pager_pagenumber(data)==pPage->pgno );
- assert( &data[pBt->pageSize] == (unsigned char*)pPage );
- assert( sqlite3pager_iswriteable(data) );
+ assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno );
+ assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );
+ assert( sqlite3PagerGetData(pPage->pDbPage) == data );
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) );
+ assert( sqlite3_mutex_held(pBt->mutex) );
memset(&data[hdr], 0, pBt->usableSize - hdr);
data[hdr] = flags;
first = hdr + 8 + 4*((flags&PTF_LEAF)==0);
@@ -1470,21 +999,35 @@ static void zeroPage(MemPage *pPage, int flags){
pPage->idxShift = 0;
pPage->nCell = 0;
pPage->isInit = 1;
- pageIntegrity(pPage);
}
/*
** Get a page from the pager. Initialize the MemPage.pBt and
** MemPage.aData elements if needed.
-*/
-static int getPage(BtShared *pBt, Pgno pgno, MemPage **ppPage){
+**
+** If the noContent flag is set, it means that we do not care about
+** the content of the page at this time. So do not go to the disk
+** to fetch the content. Just fill in the content with zeros for now.
+** If in the future we call sqlite3PagerWrite() on this page, that
+** means we have started to be concerned about content and the disk
+** read should occur at that point.
+*/
+int sqlite3BtreeGetPage(
+ BtShared *pBt, /* The btree */
+ Pgno pgno, /* Number of the page to fetch */
+ MemPage **ppPage, /* Return the page in this parameter */
+ int noContent /* Do not load page content if true */
+){
int rc;
- unsigned char *aData;
MemPage *pPage;
- rc = sqlite3pager_get(pBt->pPager, pgno, (void**)&aData);
+ DbPage *pDbPage;
+
+ assert( sqlite3_mutex_held(pBt->mutex) );
+ rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, noContent);
if( rc ) return rc;
- pPage = (MemPage*)&aData[pBt->pageSize];
- pPage->aData = aData;
+ pPage = (MemPage *)sqlite3PagerGetExtra(pDbPage);
+ pPage->aData = sqlite3PagerGetData(pDbPage);
+ pPage->pDbPage = pDbPage;
pPage->pBt = pBt;
pPage->pgno = pgno;
pPage->hdrOffset = pPage->pgno==1 ? 100 : 0;
@@ -1495,7 +1038,7 @@ static int getPage(BtShared *pBt, Pgno pgno, MemPage **ppPage){
/*
** Get a page from the pager and initialize it. This routine
** is just a convenience wrapper around separate calls to
-** getPage() and initPage().
+** sqlite3BtreeGetPage() and sqlite3BtreeInitPage().
*/
static int getAndInitPage(
BtShared *pBt, /* The database file */
@@ -1504,26 +1047,29 @@ static int getAndInitPage(
MemPage *pParent /* Parent of the page */
){
int rc;
+ assert( sqlite3_mutex_held(pBt->mutex) );
if( pgno==0 ){
return SQLITE_CORRUPT_BKPT;
}
- rc = getPage(pBt, pgno, ppPage);
+ rc = sqlite3BtreeGetPage(pBt, pgno, ppPage, 0);
if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){
- rc = initPage(*ppPage, pParent);
+ rc = sqlite3BtreeInitPage(*ppPage, pParent);
}
return rc;
}
/*
** Release a MemPage. This should be called once for each prior
-** call to getPage.
+** call to sqlite3BtreeGetPage.
*/
static void releasePage(MemPage *pPage){
if( pPage ){
assert( pPage->aData );
assert( pPage->pBt );
- assert( &pPage->aData[pPage->pBt->pageSize]==(unsigned char*)pPage );
- sqlite3pager_unref(pPage->aData);
+ assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );
+ assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData );
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+ sqlite3PagerUnref(pPage->pDbPage);
}
}
@@ -1532,12 +1078,14 @@ static void releasePage(MemPage *pPage){
** reaches zero. We need to unref the pParent pointer when that
** happens.
*/
-static void pageDestructor(void *pData, int pageSize){
+static void pageDestructor(DbPage *pData, int pageSize){
MemPage *pPage;
assert( (pageSize & 7)==0 );
- pPage = (MemPage*)&((char*)pData)[pageSize];
+ pPage = (MemPage *)sqlite3PagerGetExtra(pData);
+ assert( pPage->isInit==0 || sqlite3_mutex_held(pPage->pBt->mutex) );
if( pPage->pParent ){
MemPage *pParent = pPage->pParent;
+ assert( pParent->pBt==pPage->pBt );
pPage->pParent = 0;
releasePage(pParent);
}
@@ -1552,37 +1100,49 @@ static void pageDestructor(void *pData, int pageSize){
** This routine needs to reset the extra data section at the end of the
** page to agree with the restored data.
*/
-static void pageReinit(void *pData, int pageSize){
+static void pageReinit(DbPage *pData, int pageSize){
MemPage *pPage;
assert( (pageSize & 7)==0 );
- pPage = (MemPage*)&((char*)pData)[pageSize];
+ pPage = (MemPage *)sqlite3PagerGetExtra(pData);
if( pPage->isInit ){
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
pPage->isInit = 0;
- initPage(pPage, pPage->pParent);
+ sqlite3BtreeInitPage(pPage, pPage->pParent);
}
}
/*
+** Invoke the busy handler for a btree.
+*/
+static int sqlite3BtreeInvokeBusyHandler(void *pArg, int n){
+ BtShared *pBt = (BtShared*)pArg;
+ assert( pBt->db );
+ assert( sqlite3_mutex_held(pBt->db->mutex) );
+ return sqlite3InvokeBusyHandler(&pBt->db->busyHandler);
+}
+
+/*
** Open a database file.
**
** zFilename is the name of the database file. If zFilename is NULL
** a new database with a random name is created. This randomly named
** database file will be deleted when sqlite3BtreeClose() is called.
+** If zFilename is ":memory:" then an in-memory database is created
+** that is automatically destroyed when it is closed.
*/
int sqlite3BtreeOpen(
const char *zFilename, /* Name of the file containing the BTree database */
- sqlite3 *pSqlite, /* Associated database handle */
+ sqlite3 *db, /* Associated database handle */
Btree **ppBtree, /* Pointer to new Btree object written here */
- int flags /* Options */
+ int flags, /* Options */
+ int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */
){
- BtShared *pBt; /* Shared part of btree structure */
+ sqlite3_vfs *pVfs; /* The VFS to use for this btree */
+ BtShared *pBt = 0; /* Shared part of btree structure */
Btree *p; /* Handle to return */
- int rc;
+ int rc = SQLITE_OK;
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
@@ -1591,122 +1151,249 @@ int sqlite3BtreeOpen(
*/
#if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM)
#ifdef SQLITE_OMIT_MEMORYDB
- const int isMemdb = !zFilename;
+ const int isMemdb = 0;
#else
- const int isMemdb = !zFilename || (strcmp(zFilename, ":memory:")?0:1);
+ const int isMemdb = zFilename && !strcmp(zFilename, ":memory:");
#endif
#endif
- p = sqliteMalloc(sizeof(Btree));
+ assert( db!=0 );
+ assert( sqlite3_mutex_held(db->mutex) );
+
+ pVfs = db->pVfs;
+ p = sqlite3MallocZero(sizeof(Btree));
if( !p ){
return SQLITE_NOMEM;
}
p->inTrans = TRANS_NONE;
- p->pSqlite = pSqlite;
+ p->db = db;
- /* 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;
+ /*
+ ** If this Btree is a candidate for shared cache, try to find an
+ ** existing BtShared object that we can share with
+ */
+ if( (flags & BTREE_PRIVATE)==0
+ && isMemdb==0
+ && (db->flags & SQLITE_Vtab)==0
+ && zFilename && zFilename[0]
+ ){
+ if( sqlite3SharedCacheEnabled ){
+ int nFullPathname = pVfs->mxPathname+1;
+ char *zFullPathname = (char *)sqlite3_malloc(nFullPathname);
+ sqlite3_mutex *mutexShared;
+ p->sharable = 1;
+ if( db ){
+ db->flags |= SQLITE_SharedCache;
+ }
+ if( !zFullPathname ){
+ sqlite3_free(p);
+ return SQLITE_NOMEM;
}
+ sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname);
+ mutexShared = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex_enter(mutexShared);
+ for(pBt=sqlite3SharedCacheList; pBt; pBt=pBt->pNext){
+ assert( pBt->nRef>0 );
+ if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager))
+ && sqlite3PagerVfs(pBt->pPager)==pVfs ){
+ p->pBt = pBt;
+ pBt->nRef++;
+ break;
+ }
+ }
+ sqlite3_mutex_leave(mutexShared);
+ sqlite3_free(zFullPathname);
+ }
+#ifdef SQLITE_DEBUG
+ else{
+ /* In debug mode, we mark all persistent databases as sharable
+ ** even when they are not. This exercises the locking code and
+ ** gives more opportunity for asserts(sqlite3_mutex_held())
+ ** statements to find locking problems.
+ */
+ p->sharable = 1;
}
- sqliteFree(zFullPathname);
+#endif
}
#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 || sizeof(i64)==4 );
- assert( sizeof(u64)==8 || sizeof(u64)==4 );
- assert( sizeof(u32)==4 );
- assert( sizeof(u16)==2 );
- assert( sizeof(Pgno)==4 );
-
- 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;
- pBt->pPage1 = 0;
- pBt->readOnly = sqlite3pager_isreadonly(pBt->pPager);
- sqlite3pager_read_fileheader(pBt->pPager, sizeof(zDbHeader), zDbHeader);
- pBt->pageSize = get2byte(&zDbHeader[16]);
- if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
- || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
- pBt->pageSize = SQLITE_DEFAULT_PAGE_SIZE;
- pBt->maxEmbedFrac = 64; /* 25% */
- pBt->minEmbedFrac = 32; /* 12.5% */
- pBt->minLeafFrac = 32; /* 12.5% */
-#ifndef SQLITE_OMIT_AUTOVACUUM
- /* If the magic name ":memory:" will create an in-memory database, then
- ** do not set the auto-vacuum flag, even if SQLITE_DEFAULT_AUTOVACUUM
- ** is true. On the other hand, if SQLITE_OMIT_MEMORYDB has been defined,
- ** then ":memory:" is just a regular file-name. Respect the auto-vacuum
- ** default in this case.
+ /*
+ ** 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.
*/
- if( zFilename && !isMemdb ){
- pBt->autoVacuum = SQLITE_DEFAULT_AUTOVACUUM;
+ 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 );
+
+ pBt = sqlite3MallocZero( sizeof(*pBt) );
+ if( pBt==0 ){
+ rc = SQLITE_NOMEM;
+ goto btree_open_out;
}
+ pBt->busyHdr.xFunc = sqlite3BtreeInvokeBusyHandler;
+ pBt->busyHdr.pArg = pBt;
+ rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename,
+ EXTRA_SIZE, flags, vfsFlags);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
+ }
+ if( rc!=SQLITE_OK ){
+ goto btree_open_out;
+ }
+ sqlite3PagerSetBusyhandler(pBt->pPager, &pBt->busyHdr);
+ p->pBt = pBt;
+
+ sqlite3PagerSetDestructor(pBt->pPager, pageDestructor);
+ sqlite3PagerSetReiniter(pBt->pPager, pageReinit);
+ pBt->pCursor = 0;
+ pBt->pPage1 = 0;
+ pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager);
+ pBt->pageSize = get2byte(&zDbHeader[16]);
+ if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
+ || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
+ pBt->pageSize = 0;
+ sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize);
+ pBt->maxEmbedFrac = 64; /* 25% */
+ pBt->minEmbedFrac = 32; /* 12.5% */
+ pBt->minLeafFrac = 32; /* 12.5% */
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ /* If the magic name ":memory:" will create an in-memory database, then
+ ** leave the autoVacuum mode at 0 (do not auto-vacuum), even if
+ ** SQLITE_DEFAULT_AUTOVACUUM is true. On the other hand, if
+ ** SQLITE_OMIT_MEMORYDB has been defined, then ":memory:" is just a
+ ** regular file-name. In this case the auto-vacuum applies as per normal.
+ */
+ if( zFilename && !isMemdb ){
+ pBt->autoVacuum = (SQLITE_DEFAULT_AUTOVACUUM ? 1 : 0);
+ pBt->incrVacuum = (SQLITE_DEFAULT_AUTOVACUUM==2 ? 1 : 0);
+ }
#endif
- nReserve = 0;
- }else{
- nReserve = zDbHeader[20];
- pBt->maxEmbedFrac = zDbHeader[21];
- pBt->minEmbedFrac = zDbHeader[22];
- pBt->minLeafFrac = zDbHeader[23];
- pBt->pageSizeFixed = 1;
+ nReserve = 0;
+ }else{
+ nReserve = zDbHeader[20];
+ pBt->maxEmbedFrac = zDbHeader[21];
+ pBt->minEmbedFrac = zDbHeader[22];
+ pBt->minLeafFrac = zDbHeader[23];
+ pBt->pageSizeFixed = 1;
#ifndef SQLITE_OMIT_AUTOVACUUM
- pBt->autoVacuum = (get4byte(&zDbHeader[36 + 4*4])?1:0);
+ pBt->autoVacuum = (get4byte(&zDbHeader[36 + 4*4])?1:0);
+ pBt->incrVacuum = (get4byte(&zDbHeader[36 + 7*4])?1:0);
+#endif
+ }
+ pBt->usableSize = pBt->pageSize - nReserve;
+ assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */
+ sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize);
+
+#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
+ /* Add the new BtShared object to the linked list sharable BtShareds.
+ */
+ if( p->sharable ){
+ sqlite3_mutex *mutexShared;
+ pBt->nRef = 1;
+ mutexShared = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
+ if( SQLITE_THREADSAFE ){
+ pBt->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( pBt->mutex==0 ){
+ rc = SQLITE_NOMEM;
+ db->mallocFailed = 0;
+ goto btree_open_out;
+ }
+ }
+ sqlite3_mutex_enter(mutexShared);
+ pBt->pNext = sqlite3SharedCacheList;
+ sqlite3SharedCacheList = pBt;
+ sqlite3_mutex_leave(mutexShared);
+ }
#endif
}
- pBt->usableSize = pBt->pageSize - nReserve;
- assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */
- sqlite3pager_set_pagesize(pBt->pPager, pBt->pageSize);
#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 the new Btree uses a sharable pBtShared, then link the new
+ ** Btree into the list of all sharable Btrees for the same connection.
+ ** The list is kept in ascending order by pBt address.
*/
- if( pTsdro->useSharedData && zFilename && !isMemdb ){
- pBt->pNext = pTsdro->pBtree;
- sqlite3ThreadData()->pBtree = pBt;
+ if( p->sharable ){
+ int i;
+ Btree *pSib;
+ for(i=0; i<db->nDb; i++){
+ if( (pSib = db->aDb[i].pBt)!=0 && pSib->sharable ){
+ while( pSib->pPrev ){ pSib = pSib->pPrev; }
+ if( p->pBt<pSib->pBt ){
+ p->pNext = pSib;
+ p->pPrev = 0;
+ pSib->pPrev = p;
+ }else{
+ while( pSib->pNext && pSib->pNext->pBt<p->pBt ){
+ pSib = pSib->pNext;
+ }
+ p->pNext = pSib->pNext;
+ p->pPrev = pSib;
+ if( p->pNext ){
+ p->pNext->pPrev = p;
+ }
+ pSib->pNext = p;
+ }
+ break;
+ }
+ }
}
#endif
- pBt->nRef = 1;
*ppBtree = p;
- return SQLITE_OK;
+
+btree_open_out:
+ if( rc!=SQLITE_OK ){
+ if( pBt && pBt->pPager ){
+ sqlite3PagerClose(pBt->pPager);
+ }
+ sqlite3_free(pBt);
+ sqlite3_free(p);
+ *ppBtree = 0;
+ }
+ return rc;
+}
+
+/*
+** Decrement the BtShared.nRef counter. When it reaches zero,
+** remove the BtShared structure from the sharing list. Return
+** true if the BtShared.nRef counter reaches zero and return
+** false if it is still positive.
+*/
+static int removeFromSharingList(BtShared *pBt){
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ sqlite3_mutex *pMaster;
+ BtShared *pList;
+ int removed = 0;
+
+ assert( sqlite3_mutex_notheld(pBt->mutex) );
+ pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex_enter(pMaster);
+ pBt->nRef--;
+ if( pBt->nRef<=0 ){
+ if( sqlite3SharedCacheList==pBt ){
+ sqlite3SharedCacheList = pBt->pNext;
+ }else{
+ pList = sqlite3SharedCacheList;
+ while( pList && pList->pNext!=pBt ){
+ pList=pList->pNext;
+ }
+ if( pList ){
+ pList->pNext = pBt->pNext;
+ }
+ }
+ if( SQLITE_THREADSAFE ){
+ sqlite3_mutex_free(pBt->mutex);
+ }
+ removed = 1;
+ }
+ sqlite3_mutex_leave(pMaster);
+ return removed;
+#else
+ return 1;
+#endif
}
/*
@@ -1716,11 +1403,10 @@ 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. */
+ assert( sqlite3_mutex_held(p->db->mutex) );
+ sqlite3BtreeEnter(p);
+ pBt->db = p->db;
pCur = pBt->pCursor;
while( pCur ){
BtCursor *pTmp = pCur;
@@ -1735,55 +1421,36 @@ int sqlite3BtreeClose(Btree *p){
** this handle.
*/
sqlite3BtreeRollback(p);
- sqliteFree(p);
+ sqlite3BtreeLeave(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;
+ assert( p->wantToLock==0 && p->locked==0 );
+ if( !p->sharable || removeFromSharingList(pBt) ){
+ /* The pBt is no longer on the sharing list, so we can access
+ ** it without having to hold the mutex.
+ **
+ ** Clean out and delete the BtShared object.
+ */
+ assert( !pBt->pCursor );
+ sqlite3PagerClose(pBt->pPager);
+ if( pBt->xFreeSchema && pBt->pSchema ){
+ pBt->xFreeSchema(pBt->pSchema);
}
+ sqlite3_free(pBt->pSchema);
+ sqlite3_free(pBt);
}
-#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;
-}
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ assert( p->wantToLock==0 );
+ assert( p->locked==0 );
+ if( p->pPrev ) p->pPrev->pNext = p->pNext;
+ if( p->pNext ) p->pNext->pPrev = p->pPrev;
+#endif
-/*
-** Change the busy handler callback function.
-*/
-int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){
- BtShared *pBt = p->pBt;
- pBt->pBusyHandler = pHandler;
- sqlite3pager_set_busyhandler(pBt->pPager, pHandler);
+ sqlite3_free(p);
return SQLITE_OK;
}
@@ -1804,7 +1471,10 @@ int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){
*/
int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
BtShared *pBt = p->pBt;
- sqlite3pager_set_cachesize(pBt->pPager, mxPage);
+ assert( sqlite3_mutex_held(p->db->mutex) );
+ sqlite3BtreeEnter(p);
+ sqlite3PagerSetCachesize(pBt->pPager, mxPage);
+ sqlite3BtreeLeave(p);
return SQLITE_OK;
}
@@ -1819,7 +1489,10 @@ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){
BtShared *pBt = p->pBt;
- sqlite3pager_set_safety_level(pBt->pPager, level, fullSync);
+ assert( sqlite3_mutex_held(p->db->mutex) );
+ sqlite3BtreeEnter(p);
+ sqlite3PagerSetSafetyLevel(pBt->pPager, level, fullSync);
+ sqlite3BtreeLeave(p);
return SQLITE_OK;
}
#endif
@@ -1830,8 +1503,13 @@ int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){
*/
int sqlite3BtreeSyncDisabled(Btree *p){
BtShared *pBt = p->pBt;
+ int rc;
+ assert( sqlite3_mutex_held(p->db->mutex) );
+ sqlite3BtreeEnter(p);
assert( pBt && pBt->pPager );
- return sqlite3pager_nosync(pBt->pPager);
+ rc = sqlite3PagerNosync(pBt->pPager);
+ sqlite3BtreeLeave(p);
+ return rc;
}
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM)
@@ -1851,8 +1529,11 @@ int sqlite3BtreeSyncDisabled(Btree *p){
** bytes per page is left unchanged.
*/
int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve){
+ int rc = SQLITE_OK;
BtShared *pBt = p->pBt;
+ sqlite3BtreeEnter(p);
if( pBt->pageSizeFixed ){
+ sqlite3BtreeLeave(p);
return SQLITE_READONLY;
}
if( nReserve<0 ){
@@ -1862,10 +1543,12 @@ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve){
((pageSize-1)&pageSize)==0 ){
assert( (pageSize & 7)==0 );
assert( !pBt->pPage1 && !pBt->pCursor );
- pBt->pageSize = sqlite3pager_set_pagesize(pBt->pPager, pageSize);
+ pBt->pageSize = pageSize;
+ rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize);
}
pBt->usableSize = pBt->pageSize - nReserve;
- return SQLITE_OK;
+ sqlite3BtreeLeave(p);
+ return rc;
}
/*
@@ -1875,7 +1558,24 @@ int sqlite3BtreeGetPageSize(Btree *p){
return p->pBt->pageSize;
}
int sqlite3BtreeGetReserve(Btree *p){
- return p->pBt->pageSize - p->pBt->usableSize;
+ int n;
+ sqlite3BtreeEnter(p);
+ n = p->pBt->pageSize - p->pBt->usableSize;
+ sqlite3BtreeLeave(p);
+ return n;
+}
+
+/*
+** Set the maximum page count for a database if mxPage is positive.
+** No changes are made if mxPage is 0 or negative.
+** Regardless of the value of mxPage, return the maximum page count.
+*/
+int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){
+ int n;
+ sqlite3BtreeEnter(p);
+ n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage);
+ sqlite3BtreeLeave(p);
+ return n;
}
#endif /* !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) */
@@ -1886,15 +1586,21 @@ int sqlite3BtreeGetReserve(Btree *p){
** determined by the SQLITE_DEFAULT_AUTOVACUUM macro.
*/
int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){
- BtShared *pBt = p->pBt;;
#ifdef SQLITE_OMIT_AUTOVACUUM
return SQLITE_READONLY;
#else
- if( pBt->pageSizeFixed ){
- return SQLITE_READONLY;
+ BtShared *pBt = p->pBt;
+ int rc = SQLITE_OK;
+ int av = (autoVacuum?1:0);
+
+ sqlite3BtreeEnter(p);
+ if( pBt->pageSizeFixed && av!=pBt->autoVacuum ){
+ rc = SQLITE_READONLY;
+ }else{
+ pBt->autoVacuum = av;
}
- pBt->autoVacuum = (autoVacuum?1:0);
- return SQLITE_OK;
+ sqlite3BtreeLeave(p);
+ return rc;
#endif
}
@@ -1904,9 +1610,17 @@ int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){
*/
int sqlite3BtreeGetAutoVacuum(Btree *p){
#ifdef SQLITE_OMIT_AUTOVACUUM
- return 0;
+ return BTREE_AUTOVACUUM_NONE;
#else
- return p->pBt->autoVacuum;
+ int rc;
+ sqlite3BtreeEnter(p);
+ rc = (
+ (!p->pBt->autoVacuum)?BTREE_AUTOVACUUM_NONE:
+ (!p->pBt->incrVacuum)?BTREE_AUTOVACUUM_FULL:
+ BTREE_AUTOVACUUM_INCR
+ );
+ sqlite3BtreeLeave(p);
+ return rc;
#endif
}
@@ -1918,14 +1632,15 @@ int sqlite3BtreeGetAutoVacuum(Btree *p){
** SQLITE_OK is returned on success. If the file is not a
** well-formed database file, then SQLITE_CORRUPT is returned.
** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM
-** is returned if we run out of memory. SQLITE_PROTOCOL is returned
-** if there is a locking protocol violation.
+** is returned if we run out of memory.
*/
static int lockBtree(BtShared *pBt){
int rc, pageSize;
MemPage *pPage1;
+
+ assert( sqlite3_mutex_held(pBt->mutex) );
if( pBt->pPage1 ) return SQLITE_OK;
- rc = getPage(pBt, 1, &pPage1);
+ rc = sqlite3BtreeGetPage(pBt, 1, &pPage1, 0);
if( rc!=SQLITE_OK ) return rc;
@@ -1933,16 +1648,21 @@ static int lockBtree(BtShared *pBt){
** a valid database file.
*/
rc = SQLITE_NOTADB;
- if( sqlite3pager_pagecount(pBt->pPager)>0 ){
+ if( sqlite3PagerPagecount(pBt->pPager)>0 ){
u8 *page1 = pPage1->aData;
if( memcmp(page1, zMagicHeader, 16)!=0 ){
goto page1_init_failed;
}
- if( page1[18]>1 || page1[19]>1 ){
+ if( page1[18]>1 ){
+ pBt->readOnly = 1;
+ }
+ if( page1[19]>1 ){
goto page1_init_failed;
}
pageSize = get2byte(&page1[16]);
- if( ((pageSize-1)&pageSize)!=0 ){
+ if( ((pageSize-1)&pageSize)!=0 || pageSize<512 ||
+ (SQLITE_MAX_PAGE_SIZE<32768 && pageSize>SQLITE_MAX_PAGE_SIZE)
+ ){
goto page1_init_failed;
}
assert( (pageSize & 7)==0 );
@@ -1956,6 +1676,7 @@ static int lockBtree(BtShared *pBt){
pBt->minLeafFrac = page1[23];
#ifndef SQLITE_OMIT_AUTOVACUUM
pBt->autoVacuum = (get4byte(&page1[36 + 4*4])?1:0);
+ pBt->incrVacuum = (get4byte(&page1[36 + 7*4])?1:0);
#endif
}
@@ -1995,6 +1716,8 @@ page1_init_failed:
*/
static int lockBtreeWithRetry(Btree *pRef){
int rc = SQLITE_OK;
+
+ assert( sqlite3BtreeHoldsMutex(pRef) );
if( pRef->inTrans==TRANS_NONE ){
u8 inTransaction = pRef->pBt->inTransaction;
btreeIntegrity(pRef);
@@ -2021,14 +1744,20 @@ static int lockBtreeWithRetry(Btree *pRef){
** If there is a transaction in progress, this routine is a no-op.
*/
static void unlockBtreeIfUnused(BtShared *pBt){
+ assert( sqlite3_mutex_held(pBt->mutex) );
if( pBt->inTransaction==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){
- if( pBt->pPage1->aData==0 ){
- MemPage *pPage = pBt->pPage1;
- pPage->aData = &((u8*)pPage)[-pBt->pageSize];
- pPage->pBt = pBt;
- pPage->pgno = 1;
+ if( sqlite3PagerRefcount(pBt->pPager)>=1 ){
+ assert( pBt->pPage1->aData );
+#if 0
+ if( pBt->pPage1->aData==0 ){
+ MemPage *pPage = pBt->pPage1;
+ pPage->aData = sqlite3PagerGetData(pPage->pDbPage);
+ pPage->pBt = pBt;
+ pPage->pgno = 1;
+ }
+#endif
+ releasePage(pBt->pPage1);
}
- releasePage(pBt->pPage1);
pBt->pPage1 = 0;
pBt->inStmt = 0;
}
@@ -2042,11 +1771,13 @@ static int newDatabase(BtShared *pBt){
MemPage *pP1;
unsigned char *data;
int rc;
- if( sqlite3pager_pagecount(pBt->pPager)>0 ) return SQLITE_OK;
+
+ assert( sqlite3_mutex_held(pBt->mutex) );
+ if( sqlite3PagerPagecount(pBt->pPager)>0 ) return SQLITE_OK;
pP1 = pBt->pPage1;
assert( pP1!=0 );
data = pP1->aData;
- rc = sqlite3pager_write(data);
+ rc = sqlite3PagerWrite(pP1->pDbPage);
if( rc ) return rc;
memcpy(data, zMagicHeader, sizeof(zMagicHeader));
assert( sizeof(zMagicHeader)==16 );
@@ -2061,9 +1792,10 @@ static int newDatabase(BtShared *pBt){
zeroPage(pP1, PTF_INTKEY|PTF_LEAF|PTF_LEAFDATA );
pBt->pageSizeFixed = 1;
#ifndef SQLITE_OMIT_AUTOVACUUM
- if( pBt->autoVacuum ){
- put4byte(&data[36 + 4*4], 1);
- }
+ assert( pBt->autoVacuum==1 || pBt->autoVacuum==0 );
+ assert( pBt->incrVacuum==1 || pBt->incrVacuum==0 );
+ put4byte(&data[36 + 4*4], pBt->autoVacuum);
+ put4byte(&data[36 + 7*4], pBt->incrVacuum);
#endif
return SQLITE_OK;
}
@@ -2107,6 +1839,8 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
BtShared *pBt = p->pBt;
int rc = SQLITE_OK;
+ sqlite3BtreeEnter(p);
+ pBt->db = p->db;
btreeIntegrity(p);
/* If the btree is already in a write-transaction, or it
@@ -2114,12 +1848,13 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
** is requested, this is a no-op.
*/
if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
- return SQLITE_OK;
+ goto trans_begun;
}
/* Write transactions are not possible on a read-only database */
if( pBt->readOnly && wrflag ){
- return SQLITE_READONLY;
+ rc = SQLITE_READONLY;
+ goto trans_begun;
}
/* If another database handle has already opened a write transaction
@@ -2127,18 +1862,35 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
** requested, return SQLITE_BUSY.
*/
if( pBt->inTransaction==TRANS_WRITE && wrflag ){
- return SQLITE_BUSY;
+ rc = SQLITE_BUSY;
+ goto trans_begun;
+ }
+
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ if( wrflag>1 ){
+ BtLock *pIter;
+ for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
+ if( pIter->pBtree!=p ){
+ rc = SQLITE_BUSY;
+ goto trans_begun;
+ }
+ }
}
+#endif
do {
if( pBt->pPage1==0 ){
rc = lockBtree(pBt);
}
-
+
if( rc==SQLITE_OK && wrflag ){
- rc = sqlite3pager_begin(pBt->pPage1->aData, wrflag>1);
- if( rc==SQLITE_OK ){
- rc = newDatabase(pBt);
+ if( pBt->readOnly ){
+ rc = SQLITE_READONLY;
+ }else{
+ rc = sqlite3PagerBegin(pBt->pPage1->pDbPage, wrflag>1);
+ if( rc==SQLITE_OK ){
+ rc = newDatabase(pBt);
+ }
}
}
@@ -2148,7 +1900,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
unlockBtreeIfUnused(pBt);
}
}while( rc==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
- sqlite3InvokeBusyHandler(pBt->pBusyHandler) );
+ sqlite3BtreeInvokeBusyHandler(pBt, 0) );
if( rc==SQLITE_OK ){
if( p->inTrans==TRANS_NONE ){
@@ -2158,9 +1910,18 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
if( p->inTrans>pBt->inTransaction ){
pBt->inTransaction = p->inTrans;
}
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ if( wrflag>1 ){
+ assert( !pBt->pExclusive );
+ pBt->pExclusive = p;
+ }
+#endif
}
+
+trans_begun:
btreeIntegrity(p);
+ sqlite3BtreeLeave(p);
return rc;
}
@@ -2174,12 +1935,16 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
static int setChildPtrmaps(MemPage *pPage){
int i; /* Counter variable */
int nCell; /* Number of cells in page pPage */
- int rc = SQLITE_OK; /* Return code */
+ int rc; /* Return code */
BtShared *pBt = pPage->pBt;
int isInitOrig = pPage->isInit;
Pgno pgno = pPage->pgno;
- initPage(pPage, 0);
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+ rc = sqlite3BtreeInitPage(pPage, pPage->pParent);
+ if( rc!=SQLITE_OK ){
+ goto set_child_ptrmaps_out;
+ }
nCell = pPage->nCell;
for(i=0; i<nCell; i++){
@@ -2223,6 +1988,7 @@ set_child_ptrmaps_out:
** overflow page in the list.
*/
static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
if( eType==PTRMAP_OVERFLOW2 ){
/* The pointer is always the first 4 bytes of the page in this case. */
if( get4byte(pPage->aData)!=iFrom ){
@@ -2234,14 +2000,14 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
int i;
int nCell;
- initPage(pPage, 0);
+ sqlite3BtreeInitPage(pPage, 0);
nCell = pPage->nCell;
for(i=0; i<nCell; i++){
u8 *pCell = findCell(pPage, i);
if( eType==PTRMAP_OVERFLOW1 ){
CellInfo info;
- parseCellPtr(pPage, pCell, &info);
+ sqlite3BtreeParseCellPtr(pPage, pCell, &info);
if( info.iOverflow ){
if( iFrom==get4byte(&pCell[info.iOverflow]) ){
put4byte(&pCell[info.iOverflow], iTo);
@@ -2288,11 +2054,13 @@ static int relocatePage(
assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 ||
eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE );
+ assert( sqlite3_mutex_held(pBt->mutex) );
+ assert( pDbPage->pBt==pBt );
- /* Move page iDbPage from it's current location to page number iFreePage */
+ /* Move page iDbPage from its current location to page number iFreePage */
TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n",
iDbPage, iFreePage, iPtrPage, eType));
- rc = sqlite3pager_movepage(pPager, pDbPage->aData, iFreePage);
+ rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -2326,11 +2094,11 @@ static int relocatePage(
** iPtrPage.
*/
if( eType!=PTRMAP_ROOTPAGE ){
- rc = getPage(pBt, iPtrPage, &pPtrPage);
+ rc = sqlite3BtreeGetPage(pBt, iPtrPage, &pPtrPage, 0);
if( rc!=SQLITE_OK ){
return rc;
}
- rc = sqlite3pager_write(pPtrPage->aData);
+ rc = sqlite3PagerWrite(pPtrPage->pDbPage);
if( rc!=SQLITE_OK ){
releasePage(pPtrPage);
return rc;
@@ -2344,154 +2112,278 @@ static int relocatePage(
return rc;
}
-/* Forward declaration required by autoVacuumCommit(). */
-static int allocatePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
+/* Forward declaration required by incrVacuumStep(). */
+static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
/*
-** This routine is called prior to sqlite3pager_commit when a transaction
-** is commited for an auto-vacuum database.
+** Perform a single step of an incremental-vacuum. If successful,
+** return SQLITE_OK. If there is no work to do (and therefore no
+** point in calling this function again), return SQLITE_DONE.
+**
+** More specificly, this function attempts to re-organize the
+** database so that the last page of the file currently in use
+** is no longer in use.
+**
+** If the nFin parameter is non-zero, the implementation assumes
+** that the caller will keep calling incrVacuumStep() until
+** it returns SQLITE_DONE or an error, and that nFin is the
+** number of pages the database file will contain after this
+** process is complete.
*/
-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 */
- u8 eType;
- int pgsz = pBt->pageSize; /* Page size for this database */
- Pgno iDbPage; /* The database page to move */
- MemPage *pDbMemPage = 0; /* "" */
- Pgno iPtrPage; /* The page that contains a pointer to iDbPage */
- Pgno iFreePage; /* The free-list page to move iDbPage to */
- MemPage *pFreeMemPage = 0; /* "" */
-
-#ifndef NDEBUG
- int nRef = sqlite3pager_refcount(pPager);
-#endif
+static int incrVacuumStep(BtShared *pBt, Pgno nFin){
+ Pgno iLastPg; /* Last page in the database */
+ Pgno nFreeList; /* Number of pages still on the free-list */
- assert( pBt->autoVacuum );
- if( PTRMAP_ISPAGE(pBt, sqlite3pager_pagecount(pPager)) ){
- return SQLITE_CORRUPT_BKPT;
+ assert( sqlite3_mutex_held(pBt->mutex) );
+ iLastPg = pBt->nTrunc;
+ if( iLastPg==0 ){
+ iLastPg = sqlite3PagerPagecount(pBt->pPager);
}
- /* Figure out how many free-pages are in the database. If there are no
- ** free pages, then auto-vacuum is a no-op.
- */
- nFreeList = get4byte(&pBt->pPage1->aData[36]);
- if( nFreeList==0 ){
- *nTrunc = 0;
- return SQLITE_OK;
- }
+ if( !PTRMAP_ISPAGE(pBt, iLastPg) && iLastPg!=PENDING_BYTE_PAGE(pBt) ){
+ int rc;
+ u8 eType;
+ Pgno iPtrPage;
- /* 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);
- 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) ){
- finSize--;
- }
- while( PTRMAP_ISPAGE(pBt, finSize) || finSize==PENDING_BYTE_PAGE(pBt) ){
- finSize--;
- }
- TRACE(("AUTOVACUUM: Begin (db size %d->%d)\n", origSize, finSize));
-
- /* Variable 'finSize' will be the size of the file in pages after
- ** the auto-vacuum has completed (the current file size minus the number
- ** of pages on the free list). Loop through the pages that lie beyond
- ** this mark, and if they are not already on the free list, move them
- ** to a free page earlier in the file (somewhere before finSize).
- */
- for( iDbPage=finSize+1; iDbPage<=origSize; iDbPage++ ){
- /* If iDbPage is a pointer map page, or the pending-byte page, skip it. */
- if( PTRMAP_ISPAGE(pBt, iDbPage) || iDbPage==PENDING_BYTE_PAGE(pBt) ){
- continue;
+ nFreeList = get4byte(&pBt->pPage1->aData[36]);
+ if( nFreeList==0 || nFin==iLastPg ){
+ return SQLITE_DONE;
}
- rc = ptrmapGet(pBt, iDbPage, &eType, &iPtrPage);
- if( rc!=SQLITE_OK ) goto autovacuum_out;
+ rc = ptrmapGet(pBt, iLastPg, &eType, &iPtrPage);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
if( eType==PTRMAP_ROOTPAGE ){
- rc = SQLITE_CORRUPT_BKPT;
- goto autovacuum_out;
+ return SQLITE_CORRUPT_BKPT;
}
- /* If iDbPage is free, do not swap it. */
if( eType==PTRMAP_FREEPAGE ){
- continue;
- }
- rc = getPage(pBt, iDbPage, &pDbMemPage);
- if( rc!=SQLITE_OK ) goto autovacuum_out;
+ if( nFin==0 ){
+ /* Remove the page from the files free-list. This is not required
+ ** if nFin is non-zero. In that case, the free-list will be
+ ** truncated to zero after this function returns, so it doesn't
+ ** matter if it still contains some garbage entries.
+ */
+ Pgno iFreePg;
+ MemPage *pFreePg;
+ rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, 1);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ assert( iFreePg==iLastPg );
+ releasePage(pFreePg);
+ }
+ } else {
+ Pgno iFreePg; /* Index of free page to move pLastPg to */
+ MemPage *pLastPg;
- /* Find the next page in the free-list that is not already at the end
- ** of the file. A page can be pulled off the free list using the
- ** allocatePage() routine.
- */
- do{
- if( pFreeMemPage ){
- releasePage(pFreeMemPage);
- pFreeMemPage = 0;
+ rc = sqlite3BtreeGetPage(pBt, iLastPg, &pLastPg, 0);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+
+ /* If nFin is zero, this loop runs exactly once and page pLastPg
+ ** is swapped with the first free page pulled off the free list.
+ **
+ ** On the other hand, if nFin is greater than zero, then keep
+ ** looping until a free-page located within the first nFin pages
+ ** of the file is found.
+ */
+ do {
+ MemPage *pFreePg;
+ rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, 0, 0);
+ if( rc!=SQLITE_OK ){
+ releasePage(pLastPg);
+ return rc;
+ }
+ releasePage(pFreePg);
+ }while( nFin!=0 && iFreePg>nFin );
+ assert( iFreePg<iLastPg );
+
+ rc = sqlite3PagerWrite(pLastPg->pDbPage);
+ if( rc==SQLITE_OK ){
+ rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg);
}
- rc = allocatePage(pBt, &pFreeMemPage, &iFreePage, 0, 0);
+ releasePage(pLastPg);
if( rc!=SQLITE_OK ){
- releasePage(pDbMemPage);
- goto autovacuum_out;
+ return rc;
}
- assert( iFreePage<=origSize );
- }while( iFreePage>finSize );
- 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;
+ }
}
- /* The entire free-list has been swapped to the end of the file. So
- ** truncate the database file to finSize pages and consider the
- ** free-list empty.
- */
- rc = sqlite3pager_write(pBt->pPage1->aData);
- if( rc!=SQLITE_OK ) goto autovacuum_out;
- put4byte(&pBt->pPage1->aData[32], 0);
- put4byte(&pBt->pPage1->aData[36], 0);
- *nTrunc = finSize;
- assert( finSize!=PENDING_BYTE_PAGE(pBt) );
-
-autovacuum_out:
- assert( nRef==sqlite3pager_refcount(pPager) );
- if( rc!=SQLITE_OK ){
- sqlite3pager_rollback(pPager);
+ pBt->nTrunc = iLastPg - 1;
+ while( pBt->nTrunc==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, pBt->nTrunc) ){
+ pBt->nTrunc--;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** A write-transaction must be opened before calling this function.
+** It performs a single unit of work towards an incremental vacuum.
+**
+** If the incremental vacuum is finished after this function has run,
+** SQLITE_DONE is returned. If it is not finished, but no error occured,
+** SQLITE_OK is returned. Otherwise an SQLite error code.
+*/
+int sqlite3BtreeIncrVacuum(Btree *p){
+ int rc;
+ BtShared *pBt = p->pBt;
+
+ sqlite3BtreeEnter(p);
+ pBt->db = p->db;
+ assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE );
+ if( !pBt->autoVacuum ){
+ rc = SQLITE_DONE;
+ }else{
+ invalidateAllOverflowCache(pBt);
+ rc = incrVacuumStep(pBt, 0);
+ }
+ sqlite3BtreeLeave(p);
+ return rc;
+}
+
+/*
+** This routine is called prior to sqlite3PagerCommit when a transaction
+** is commited for an auto-vacuum database.
+**
+** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages
+** the database file should be truncated to during the commit process.
+** i.e. the database has been reorganized so that only the first *pnTrunc
+** pages are in use.
+*/
+static int autoVacuumCommit(BtShared *pBt, Pgno *pnTrunc){
+ int rc = SQLITE_OK;
+ Pager *pPager = pBt->pPager;
+#ifndef NDEBUG
+ int nRef = sqlite3PagerRefcount(pPager);
+#endif
+
+ assert( sqlite3_mutex_held(pBt->mutex) );
+ invalidateAllOverflowCache(pBt);
+ assert(pBt->autoVacuum);
+ if( !pBt->incrVacuum ){
+ Pgno nFin = 0;
+
+ if( pBt->nTrunc==0 ){
+ Pgno nFree;
+ Pgno nPtrmap;
+ const int pgsz = pBt->pageSize;
+ Pgno nOrig = sqlite3PagerPagecount(pBt->pPager);
+
+ if( PTRMAP_ISPAGE(pBt, nOrig) ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ if( nOrig==PENDING_BYTE_PAGE(pBt) ){
+ nOrig--;
+ }
+ nFree = get4byte(&pBt->pPage1->aData[36]);
+ nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+pgsz/5)/(pgsz/5);
+ nFin = nOrig - nFree - nPtrmap;
+ if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<=PENDING_BYTE_PAGE(pBt) ){
+ nFin--;
+ }
+ while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){
+ nFin--;
+ }
+ }
+
+ while( rc==SQLITE_OK ){
+ rc = incrVacuumStep(pBt, nFin);
+ }
+ if( rc==SQLITE_DONE ){
+ assert(nFin==0 || pBt->nTrunc==0 || nFin<=pBt->nTrunc);
+ rc = SQLITE_OK;
+ if( pBt->nTrunc ){
+ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
+ put4byte(&pBt->pPage1->aData[32], 0);
+ put4byte(&pBt->pPage1->aData[36], 0);
+ pBt->nTrunc = nFin;
+ }
+ }
+ if( rc!=SQLITE_OK ){
+ sqlite3PagerRollback(pPager);
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ *pnTrunc = pBt->nTrunc;
+ pBt->nTrunc = 0;
}
+ assert( nRef==sqlite3PagerRefcount(pPager) );
return rc;
}
+
#endif
/*
+** This routine does the first phase of a two-phase commit. This routine
+** causes a rollback journal to be created (if it does not already exist)
+** and populated with enough information so that if a power loss occurs
+** the database can be restored to its original state by playing back
+** the journal. Then the contents of the journal are flushed out to
+** the disk. After the journal is safely on oxide, the changes to the
+** database are written into the database file and flushed to oxide.
+** At the end of this call, the rollback journal still exists on the
+** disk and we are still holding all locks, so the transaction has not
+** committed. See sqlite3BtreeCommit() for the second phase of the
+** commit process.
+**
+** This call is a no-op if no write-transaction is currently active on pBt.
+**
+** Otherwise, sync the database file for the btree pBt. zMaster points to
+** the name of a master journal file that should be written into the
+** individual journal file, or is NULL, indicating no master journal file
+** (single database transaction).
+**
+** When this is called, the master journal should already have been
+** created, populated with this journal pointer and synced to disk.
+**
+** 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 sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
+ int rc = SQLITE_OK;
+ if( p->inTrans==TRANS_WRITE ){
+ BtShared *pBt = p->pBt;
+ Pgno nTrunc = 0;
+ sqlite3BtreeEnter(p);
+ pBt->db = p->db;
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( pBt->autoVacuum ){
+ rc = autoVacuumCommit(pBt, &nTrunc);
+ if( rc!=SQLITE_OK ){
+ sqlite3BtreeLeave(p);
+ return rc;
+ }
+ }
+#endif
+ rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, nTrunc);
+ sqlite3BtreeLeave(p);
+ }
+ return rc;
+}
+
+/*
** Commit the transaction currently in progress.
**
+** This routine implements the second phase of a 2-phase commit. The
+** sqlite3BtreeSync() routine does the first phase and should be invoked
+** prior to calling this routine. The sqlite3BtreeSync() routine did
+** all the work of writing information out to disk and flushing the
+** contents so that they are written onto the disk platter. All this
+** routine has to do is delete or truncate the rollback journal
+** (which causes the transaction to commit) and drop locks.
+**
** 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 *p){
+int sqlite3BtreeCommitPhaseTwo(Btree *p){
BtShared *pBt = p->pBt;
+ sqlite3BtreeEnter(p);
+ pBt->db = p->db;
btreeIntegrity(p);
/* If the handle has a write-transaction open, commit the shared-btrees
@@ -2501,8 +2393,9 @@ int sqlite3BtreeCommit(Btree *p){
int rc;
assert( pBt->inTransaction==TRANS_WRITE );
assert( pBt->nTransaction>0 );
- rc = sqlite3pager_commit(pBt->pPager);
+ rc = sqlite3PagerCommitPhaseTwo(pBt->pPager);
if( rc!=SQLITE_OK ){
+ sqlite3BtreeLeave(p);
return rc;
}
pBt->inTransaction = TRANS_READ;
@@ -2529,43 +2422,72 @@ int sqlite3BtreeCommit(Btree *p){
unlockBtreeIfUnused(pBt);
btreeIntegrity(p);
+ sqlite3BtreeLeave(p);
return SQLITE_OK;
}
+/*
+** Do both phases of a commit.
+*/
+int sqlite3BtreeCommit(Btree *p){
+ int rc;
+ sqlite3BtreeEnter(p);
+ rc = sqlite3BtreeCommitPhaseOne(p, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3BtreeCommitPhaseTwo(p);
+ }
+ sqlite3BtreeLeave(p);
+ return rc;
+}
+
#ifndef NDEBUG
/*
** Return the number of write-cursors open on this handle. This is for use
** in assert() expressions, so it is only compiled if NDEBUG is not
** defined.
+**
+** For the purposes of this routine, a write-cursor is any cursor that
+** is capable of writing to the databse. That means the cursor was
+** originally opened for writing and the cursor has not be disabled
+** by having its state changed to CURSOR_FAULT.
*/
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 && pCur->eState!=CURSOR_FAULT ) r++;
}
return r;
}
#endif
-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
/*
-** Print debugging information about all cursors to standard output.
+** This routine sets the state to CURSOR_FAULT and the error
+** code to errCode for every cursor on BtShared that pBtree
+** references.
+**
+** Every cursor is tripped, including cursors that belong
+** to other database connections that happen to be sharing
+** the cache with pBtree.
+**
+** This routine gets called when a rollback occurs.
+** All cursors using the same cache must be tripped
+** to prevent them from trying to use the btree after
+** the rollback. The rollback may have deleted tables
+** or moved root pages, so it is not sufficient to
+** save the state of the cursor. The cursor must be
+** invalidated.
*/
-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->eState==CURSOR_VALID) ? "" : " eof"
- );
+void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){
+ BtCursor *p;
+ sqlite3BtreeEnter(pBtree);
+ for(p=pBtree->pBt->pCursor; p; p=p->pNext){
+ clearCursorPosition(p);
+ p->eState = CURSOR_FAULT;
+ p->skip = errCode;
}
+ sqlite3BtreeLeave(pBtree);
}
-#endif
/*
** Rollback the transaction in progress. All cursors will be
@@ -2581,6 +2503,8 @@ int sqlite3BtreeRollback(Btree *p){
BtShared *pBt = p->pBt;
MemPage *pPage1;
+ sqlite3BtreeEnter(p);
+ pBt->db = p->db;
rc = saveAllCursors(pBt, 0, 0);
#ifndef SQLITE_OMIT_SHARED_CACHE
if( rc!=SQLITE_OK ){
@@ -2591,12 +2515,7 @@ int sqlite3BtreeRollback(Btree *p){
** 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);
- }
- }
+ sqlite3BtreeTripAllCursors(p, rc);
}
#endif
btreeIntegrity(p);
@@ -2605,16 +2524,20 @@ int sqlite3BtreeRollback(Btree *p){
if( p->inTrans==TRANS_WRITE ){
int rc2;
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ pBt->nTrunc = 0;
+#endif
+
assert( TRANS_WRITE==pBt->inTransaction );
- rc2 = sqlite3pager_rollback(pBt->pPager);
+ rc2 = sqlite3PagerRollback(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. */
- if( getPage(pBt, 1, &pPage1)==SQLITE_OK ){
+ ** call sqlite3BtreeGetPage() on page 1 again to make
+ ** sure pPage1->aData is set correctly. */
+ if( sqlite3BtreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){
releasePage(pPage1);
}
assert( countWriteCursors(pBt)==0 );
@@ -2634,6 +2557,7 @@ int sqlite3BtreeRollback(Btree *p){
unlockBtreeIfUnused(pBt);
btreeIntegrity(p);
+ sqlite3BtreeLeave(p);
return rc;
}
@@ -2655,12 +2579,16 @@ int sqlite3BtreeRollback(Btree *p){
int sqlite3BtreeBeginStmt(Btree *p){
int rc;
BtShared *pBt = p->pBt;
+ sqlite3BtreeEnter(p);
+ pBt->db = p->db;
if( (p->inTrans!=TRANS_WRITE) || pBt->inStmt ){
- return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+ rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+ }else{
+ assert( pBt->inTransaction==TRANS_WRITE );
+ rc = pBt->readOnly ? SQLITE_OK : sqlite3PagerStmtBegin(pBt->pPager);
+ pBt->inStmt = 1;
}
- assert( pBt->inTransaction==TRANS_WRITE );
- rc = pBt->readOnly ? SQLITE_OK : sqlite3pager_stmt_begin(pBt->pPager);
- pBt->inStmt = 1;
+ sqlite3BtreeLeave(p);
return rc;
}
@@ -2672,12 +2600,15 @@ int sqlite3BtreeBeginStmt(Btree *p){
int sqlite3BtreeCommitStmt(Btree *p){
int rc;
BtShared *pBt = p->pBt;
+ sqlite3BtreeEnter(p);
+ pBt->db = p->db;
if( pBt->inStmt && !pBt->readOnly ){
- rc = sqlite3pager_stmt_commit(pBt->pPager);
+ rc = sqlite3PagerStmtCommit(pBt->pPager);
}else{
rc = SQLITE_OK;
}
pBt->inStmt = 0;
+ sqlite3BtreeLeave(p);
return rc;
}
@@ -2692,13 +2623,14 @@ int sqlite3BtreeCommitStmt(Btree *p){
int sqlite3BtreeRollbackStmt(Btree *p){
int rc = SQLITE_OK;
BtShared *pBt = p->pBt;
- sqlite3MallocDisallow();
+ sqlite3BtreeEnter(p);
+ pBt->db = p->db;
if( pBt->inStmt && !pBt->readOnly ){
- rc = sqlite3pager_stmt_rollback(pBt->pPager);
+ rc = sqlite3PagerStmtRollback(pBt->pPager);
assert( countWriteCursors(pBt)==0 );
pBt->inStmt = 0;
}
- sqlite3MallocAllow();
+ sqlite3BtreeLeave(p);
return rc;
}
@@ -2732,25 +2664,16 @@ static int dfltCompare(
**
** 1: The cursor must have been opened with wrFlag==1
**
-** 2: No other cursors may be open with wrFlag==0 on the same table
+** 2: Other database connections that share the same pager cache
+** but which are not in the READ_UNCOMMITTED state may not have
+** cursors open with wrFlag==0 on the same table. Otherwise
+** the changes made by this write cursor would be visible to
+** the read cursors in the other database connection.
**
** 3: The database must be writable (not on read-only media)
**
** 4: There must be an active transaction.
**
-** Condition 2 warrants further discussion. If any cursor is opened
-** on a table with wrFlag==0, that prevents all other cursors from
-** writing to that table. This is a kind of "read-lock". When a cursor
-** is opened with wrFlag==0 it is guaranteed that the table will not
-** change as long as the cursor is open. This allows the cursor to
-** do a sequential scan of the table without having to worry about
-** entries being inserted or deleted during the scan. Cursors should
-** be opened with wrFlag==0 only if this read-lock property is needed.
-** That is to say, cursors should be opened with wrFlag==0 only if they
-** intend to use the sqlite3BtreeNext() system call. All other cursors
-** should be opened with wrFlag==1 even if they never really intend
-** to write.
-**
** No checking is done to make sure that page iTable really is the
** root page of a b-tree. If it is not, then the cursor acquired
** will not work correctly.
@@ -2761,7 +2684,7 @@ static int dfltCompare(
** default comparison function is used. The comparison function is
** always ignored for INTKEY tables.
*/
-int sqlite3BtreeCursor(
+static int btreeCursor(
Btree *p, /* The btree */
int iTable, /* Root page of table to open */
int wrFlag, /* 1 to write. 0 read-only */
@@ -2773,12 +2696,13 @@ int sqlite3BtreeCursor(
BtCursor *pCur;
BtShared *pBt = p->pBt;
+ assert( sqlite3BtreeHoldsMutex(p) );
*ppCur = 0;
if( wrFlag ){
if( pBt->readOnly ){
return SQLITE_READONLY;
}
- if( checkReadLocks(pBt, iTable, 0) ){
+ if( checkReadLocks(p, iTable, 0) ){
return SQLITE_LOCKED;
}
}
@@ -2788,14 +2712,17 @@ int sqlite3BtreeCursor(
if( rc!=SQLITE_OK ){
return rc;
}
+ if( pBt->readOnly && wrFlag ){
+ return SQLITE_READONLY;
+ }
}
- pCur = sqliteMalloc( sizeof(*pCur) );
+ pCur = sqlite3MallocZero( sizeof(*pCur) );
if( pCur==0 ){
rc = SQLITE_NOMEM;
goto create_cursor_exception;
}
pCur->pgnoRoot = (Pgno)iTable;
- if( iTable==1 && sqlite3pager_pagecount(pBt->pPager)==0 ){
+ if( iTable==1 && sqlite3PagerPagecount(pBt->pPager)==0 ){
rc = SQLITE_EMPTY;
goto create_cursor_exception;
}
@@ -2811,6 +2738,7 @@ int sqlite3BtreeCursor(
pCur->xCompare = xCmp ? xCmp : dfltCompare;
pCur->pArg = pArg;
pCur->pBtree = p;
+ pCur->pBt = pBt;
pCur->wrFlag = wrFlag;
pCur->pNext = pBt->pCursor;
if( pCur->pNext ){
@@ -2821,36 +2749,43 @@ int sqlite3BtreeCursor(
*ppCur = pCur;
return SQLITE_OK;
+
create_cursor_exception:
if( pCur ){
releasePage(pCur->pPage);
- sqliteFree(pCur);
+ sqlite3_free(pCur);
}
unlockBtreeIfUnused(pBt);
return rc;
}
-
-#if 0 /* Not Used */
-/*
-** Change the value of the comparison function used by a cursor.
-*/
-void sqlite3BtreeSetCompare(
- BtCursor *pCur, /* The cursor to whose comparison function is changed */
- int(*xCmp)(void*,int,const void*,int,const void*), /* New comparison func */
- void *pArg /* First argument to xCmp() */
+int sqlite3BtreeCursor(
+ 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 */
+ void *pArg, /* First arg to xCompare() */
+ BtCursor **ppCur /* Write new cursor here */
){
- pCur->xCompare = xCmp ? xCmp : dfltCompare;
- pCur->pArg = pArg;
+ int rc;
+ sqlite3BtreeEnter(p);
+ p->pBt->db = p->db;
+ rc = btreeCursor(p, iTable, wrFlag, xCmp, pArg, ppCur);
+ sqlite3BtreeLeave(p);
+ return rc;
}
-#endif
+
/*
** Close a cursor. The read lock on the database file is released
** when the last cursor is closed.
*/
int sqlite3BtreeCloseCursor(BtCursor *pCur){
- BtShared *pBt = pCur->pBtree->pBt;
- restoreOrClearCursorPosition(pCur, 0);
+ BtShared *pBt = pCur->pBt;
+ Btree *pBtree = pCur->pBtree;
+
+ sqlite3BtreeEnter(pBtree);
+ pBt->db = pBtree->db;
+ clearCursorPosition(pCur);
if( pCur->pPrev ){
pCur->pPrev->pNext = pCur->pNext;
}else{
@@ -2861,7 +2796,9 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
}
releasePage(pCur->pPage);
unlockBtreeIfUnused(pBt);
- sqliteFree(pCur);
+ invalidateOverflowCache(pCur);
+ sqlite3_free(pCur);
+ sqlite3BtreeLeave(pBtree);
return SQLITE_OK;
}
@@ -2869,12 +2806,13 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
** Make a temporary cursor by filling in the fields of pTempCur.
** The temporary cursor is not on the cursor list for the Btree.
*/
-static void getTempCursor(BtCursor *pCur, BtCursor *pTempCur){
+void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur){
+ assert( cursorHoldsMutex(pCur) );
memcpy(pTempCur, pCur, sizeof(*pCur));
pTempCur->pNext = 0;
pTempCur->pPrev = 0;
if( pTempCur->pPage ){
- sqlite3pager_ref(pTempCur->pPage->aData);
+ sqlite3PagerRef(pTempCur->pPage->pDbPage);
}
}
@@ -2882,31 +2820,56 @@ static void getTempCursor(BtCursor *pCur, BtCursor *pTempCur){
** Delete a temporary cursor such as was made by the CreateTemporaryCursor()
** function above.
*/
-static void releaseTempCursor(BtCursor *pCur){
+void sqlite3BtreeReleaseTempCursor(BtCursor *pCur){
+ assert( cursorHoldsMutex(pCur) );
if( pCur->pPage ){
- sqlite3pager_unref(pCur->pPage->aData);
+ sqlite3PagerUnref(pCur->pPage->pDbPage);
}
}
/*
-** Make sure the BtCursor.info field of the given cursor is valid.
-** If it is not already valid, call parseCell() to fill it in.
+** Make sure the BtCursor* given in the argument has a valid
+** BtCursor.info structure. If it is not already valid, call
+** sqlite3BtreeParseCell() to fill it in.
**
** BtCursor.info is a cache of the information in the current cell.
-** Using this cache reduces the number of calls to parseCell().
+** Using this cache reduces the number of calls to sqlite3BtreeParseCell().
+**
+** 2007-06-25: There is a bug in some versions of MSVC that cause the
+** compiler to crash when getCellInfo() is implemented as a macro.
+** But there is a measureable speed advantage to using the macro on gcc
+** (when less compiler optimizations like -Os or -O0 are used and the
+** compiler is not doing agressive inlining.) So we use a real function
+** for MSVC and a macro for everything else. Ticket #2457.
*/
-static void getCellInfo(BtCursor *pCur){
- if( pCur->info.nSize==0 ){
- parseCell(pCur->pPage, pCur->idx, &pCur->info);
- }else{
#ifndef NDEBUG
+ static void assertCellInfo(BtCursor *pCur){
CellInfo info;
memset(&info, 0, sizeof(info));
- parseCell(pCur->pPage, pCur->idx, &info);
+ sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &info);
assert( memcmp(&info, &pCur->info, sizeof(info))==0 );
+ }
+#else
+ #define assertCellInfo(x)
#endif
+#ifdef _MSC_VER
+ /* Use a real function in MSVC to work around bugs in that compiler. */
+ static void getCellInfo(BtCursor *pCur){
+ if( pCur->info.nSize==0 ){
+ sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &pCur->info);
+ }else{
+ assertCellInfo(pCur);
+ }
}
-}
+#else /* if not _MSC_VER */
+ /* Use a macro in all other compilers so that the function is inlined */
+#define getCellInfo(pCur) \
+ if( pCur->info.nSize==0 ){ \
+ sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &pCur->info); \
+ }else{ \
+ assertCellInfo(pCur); \
+ }
+#endif /* _MSC_VER */
/*
** Set *pSize to the size of the buffer needed to hold the value of
@@ -2917,7 +2880,10 @@ static void getCellInfo(BtCursor *pCur){
** itself, not the number of bytes in the key.
*/
int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
- int rc = restoreOrClearCursorPosition(pCur, 1);
+ int rc;
+
+ assert( cursorHoldsMutex(pCur) );
+ rc = restoreOrClearCursorPosition(pCur);
if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID );
if( pCur->eState==CURSOR_INVALID ){
@@ -2938,7 +2904,10 @@ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
** the database is empty) then *pSize is set to 0.
*/
int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
- int rc = restoreOrClearCursorPosition(pCur, 1);
+ int rc;
+
+ assert( cursorHoldsMutex(pCur) );
+ rc = restoreOrClearCursorPosition(pCur);
if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID );
if( pCur->eState==CURSOR_INVALID ){
@@ -2953,93 +2922,284 @@ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
}
/*
-** Read payload information from the entry that the pCur cursor is
-** pointing to. Begin reading the payload at "offset" and read
-** a total of "amt" bytes. Put the result in zBuf.
+** Given the page number of an overflow page in the database (parameter
+** ovfl), this function finds the page number of the next page in the
+** linked list of overflow pages. If possible, it uses the auto-vacuum
+** pointer-map data instead of reading the content of page ovfl to do so.
**
-** This routine does not make a distinction between key and data.
-** It just reads bytes from the payload area. Data might appear
-** on the main page or be scattered out on multiple overflow pages.
+** If an error occurs an SQLite error code is returned. Otherwise:
+**
+** Unless pPgnoNext is NULL, the page number of the next overflow
+** page in the linked list is written to *pPgnoNext. If page ovfl
+** is the last page in its linked list, *pPgnoNext is set to zero.
+**
+** If ppPage is not NULL, *ppPage is set to the MemPage* handle
+** for page ovfl. The underlying pager page may have been requested
+** with the noContent flag set, so the page data accessable via
+** this handle may not be trusted.
*/
-static int getPayload(
+static int getOverflowPage(
+ BtShared *pBt,
+ Pgno ovfl, /* Overflow page */
+ MemPage **ppPage, /* OUT: MemPage handle */
+ Pgno *pPgnoNext /* OUT: Next overflow page number */
+){
+ Pgno next = 0;
+ int rc;
+
+ assert( sqlite3_mutex_held(pBt->mutex) );
+ /* One of these must not be NULL. Otherwise, why call this function? */
+ assert(ppPage || pPgnoNext);
+
+ /* If pPgnoNext is NULL, then this function is being called to obtain
+ ** a MemPage* reference only. No page-data is required in this case.
+ */
+ if( !pPgnoNext ){
+ return sqlite3BtreeGetPage(pBt, ovfl, ppPage, 1);
+ }
+
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ /* Try to find the next page in the overflow list using the
+ ** autovacuum pointer-map pages. Guess that the next page in
+ ** the overflow list is page number (ovfl+1). If that guess turns
+ ** out to be wrong, fall back to loading the data of page
+ ** number ovfl to determine the next page number.
+ */
+ if( pBt->autoVacuum ){
+ Pgno pgno;
+ Pgno iGuess = ovfl+1;
+ u8 eType;
+
+ while( PTRMAP_ISPAGE(pBt, iGuess) || iGuess==PENDING_BYTE_PAGE(pBt) ){
+ iGuess++;
+ }
+
+ if( iGuess<=sqlite3PagerPagecount(pBt->pPager) ){
+ rc = ptrmapGet(pBt, iGuess, &eType, &pgno);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ if( eType==PTRMAP_OVERFLOW2 && pgno==ovfl ){
+ next = iGuess;
+ }
+ }
+ }
+#endif
+
+ if( next==0 || ppPage ){
+ MemPage *pPage = 0;
+
+ rc = sqlite3BtreeGetPage(pBt, ovfl, &pPage, next!=0);
+ assert(rc==SQLITE_OK || pPage==0);
+ if( next==0 && rc==SQLITE_OK ){
+ next = get4byte(pPage->aData);
+ }
+
+ if( ppPage ){
+ *ppPage = pPage;
+ }else{
+ releasePage(pPage);
+ }
+ }
+ *pPgnoNext = next;
+
+ return rc;
+}
+
+/*
+** Copy data from a buffer to a page, or from a page to a buffer.
+**
+** pPayload is a pointer to data stored on database page pDbPage.
+** If argument eOp is false, then nByte bytes of data are copied
+** from pPayload to the buffer pointed at by pBuf. If eOp is true,
+** then sqlite3PagerWrite() is called on pDbPage and nByte bytes
+** of data are copied from the buffer pBuf to pPayload.
+**
+** SQLITE_OK is returned on success, otherwise an error code.
+*/
+static int copyPayload(
+ void *pPayload, /* Pointer to page data */
+ void *pBuf, /* Pointer to buffer */
+ int nByte, /* Number of bytes to copy */
+ int eOp, /* 0 -> copy from page, 1 -> copy to page */
+ DbPage *pDbPage /* Page containing pPayload */
+){
+ if( eOp ){
+ /* Copy data from buffer to page (a write operation) */
+ int rc = sqlite3PagerWrite(pDbPage);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ memcpy(pPayload, pBuf, nByte);
+ }else{
+ /* Copy data from page to buffer (a read operation) */
+ memcpy(pBuf, pPayload, nByte);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** This function is used to read or overwrite payload information
+** for the entry that the pCur cursor is pointing to. If the eOp
+** parameter is 0, this is a read operation (data copied into
+** buffer pBuf). If it is non-zero, a write (data copied from
+** buffer pBuf).
+**
+** A total of "amt" bytes are read or written beginning at "offset".
+** Data is read to or from the buffer pBuf.
+**
+** This routine does not make a distinction between key and data.
+** It just reads or writes bytes from the payload area. Data might
+** appear on the main page or be scattered out on multiple overflow
+** pages.
+**
+** If the BtCursor.isIncrblobHandle flag is set, and the current
+** cursor entry uses one or more overflow pages, this function
+** allocates space for and lazily popluates the overflow page-list
+** cache array (BtCursor.aOverflow). Subsequent calls use this
+** cache to make seeking to the supplied offset more efficient.
+**
+** Once an overflow page-list cache has been allocated, it may be
+** invalidated if some other cursor writes to the same table, or if
+** the cursor is moved to a different row. Additionally, in auto-vacuum
+** mode, the following events may invalidate an overflow page-list cache.
+**
+** * An incremental vacuum,
+** * A commit in auto_vacuum="full" mode,
+** * Creating a table (may require moving an overflow page).
+*/
+static int accessPayload(
BtCursor *pCur, /* Cursor pointing to entry to read from */
int offset, /* Begin reading this far into payload */
int amt, /* Read this many bytes */
unsigned char *pBuf, /* Write the bytes into this buffer */
- int skipKey /* offset begins at data if this is true */
+ int skipKey, /* offset begins at data if this is true */
+ int eOp /* zero to read. non-zero to write. */
){
unsigned char *aPayload;
- Pgno nextPage;
- int rc;
- MemPage *pPage;
- BtShared *pBt;
- int ovflSize;
+ int rc = SQLITE_OK;
u32 nKey;
+ int iIdx = 0;
+ MemPage *pPage = pCur->pPage; /* Btree page of current cursor entry */
+ BtShared *pBt; /* Btree this cursor belongs to */
- assert( pCur!=0 && pCur->pPage!=0 );
+ assert( pPage );
assert( pCur->eState==CURSOR_VALID );
- pBt = pCur->pBtree->pBt;
- pPage = pCur->pPage;
- pageIntegrity(pPage);
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
+ assert( offset>=0 );
+ assert( cursorHoldsMutex(pCur) );
+
getCellInfo(pCur);
aPayload = pCur->info.pCell + pCur->info.nHeader;
- if( pPage->intKey ){
- nKey = 0;
- }else{
- nKey = pCur->info.nKey;
- }
- assert( offset>=0 );
+ nKey = (pPage->intKey ? 0 : pCur->info.nKey);
+
if( skipKey ){
offset += nKey;
}
if( offset+amt > nKey+pCur->info.nData ){
+ /* Trying to read or write past the end of the data is an error */
return SQLITE_ERROR;
}
+
+ /* Check if data must be read/written to/from the btree page itself. */
if( offset<pCur->info.nLocal ){
int a = amt;
if( a+offset>pCur->info.nLocal ){
a = pCur->info.nLocal - offset;
}
- memcpy(pBuf, &aPayload[offset], a);
- if( a==amt ){
- return SQLITE_OK;
- }
+ rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage);
offset = 0;
pBuf += a;
amt -= a;
}else{
offset -= pCur->info.nLocal;
}
- ovflSize = pBt->usableSize - 4;
- if( amt>0 ){
+
+ pBt = pCur->pBt;
+ if( rc==SQLITE_OK && amt>0 ){
+ const int ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */
+ Pgno nextPage;
+
nextPage = get4byte(&aPayload[pCur->info.nLocal]);
- while( amt>0 && nextPage ){
- rc = sqlite3pager_get(pBt->pPager, nextPage, (void**)&aPayload);
- if( rc!=0 ){
- return rc;
+
+#ifndef SQLITE_OMIT_INCRBLOB
+ /* If the isIncrblobHandle flag is set and the BtCursor.aOverflow[]
+ ** has not been allocated, allocate it now. The array is sized at
+ ** one entry for each overflow page in the overflow chain. The
+ ** page number of the first overflow page is stored in aOverflow[0],
+ ** etc. A value of 0 in the aOverflow[] array means "not yet known"
+ ** (the cache is lazily populated).
+ */
+ if( pCur->isIncrblobHandle && !pCur->aOverflow ){
+ int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
+ pCur->aOverflow = (Pgno *)sqlite3MallocZero(sizeof(Pgno)*nOvfl);
+ if( nOvfl && !pCur->aOverflow ){
+ rc = SQLITE_NOMEM;
+ }
+ }
+
+ /* If the overflow page-list cache has been allocated and the
+ ** entry for the first required overflow page is valid, skip
+ ** directly to it.
+ */
+ if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){
+ iIdx = (offset/ovflSize);
+ nextPage = pCur->aOverflow[iIdx];
+ offset = (offset%ovflSize);
+ }
+#endif
+
+ for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){
+
+#ifndef SQLITE_OMIT_INCRBLOB
+ /* If required, populate the overflow page-list cache. */
+ if( pCur->aOverflow ){
+ assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage);
+ pCur->aOverflow[iIdx] = nextPage;
}
- nextPage = get4byte(aPayload);
- if( offset<ovflSize ){
+#endif
+
+ if( offset>=ovflSize ){
+ /* The only reason to read this page is to obtain the page
+ ** number for the next page in the overflow chain. The page
+ ** data is not required. So first try to lookup the overflow
+ ** page-list cache, if any, then fall back to the getOverflowPage()
+ ** function.
+ */
+#ifndef SQLITE_OMIT_INCRBLOB
+ if( pCur->aOverflow && pCur->aOverflow[iIdx+1] ){
+ nextPage = pCur->aOverflow[iIdx+1];
+ } else
+#endif
+ rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
+ offset -= ovflSize;
+ }else{
+ /* Need to read this page properly. It contains some of the
+ ** range of data that is being read (eOp==0) or written (eOp!=0).
+ */
+ DbPage *pDbPage;
int a = amt;
- if( a + offset > ovflSize ){
- a = ovflSize - offset;
+ rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage);
+ if( rc==SQLITE_OK ){
+ aPayload = sqlite3PagerGetData(pDbPage);
+ nextPage = get4byte(aPayload);
+ if( a + offset > ovflSize ){
+ a = ovflSize - offset;
+ }
+ rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage);
+ sqlite3PagerUnref(pDbPage);
+ offset = 0;
+ amt -= a;
+ pBuf += a;
}
- memcpy(pBuf, &aPayload[offset+4], a);
- offset = 0;
- amt -= a;
- pBuf += a;
- }else{
- offset -= ovflSize;
}
- sqlite3pager_unref(aPayload);
}
}
- if( amt>0 ){
+ if( rc==SQLITE_OK && amt>0 ){
return SQLITE_CORRUPT_BKPT;
}
- return SQLITE_OK;
+ return rc;
}
/*
@@ -3052,7 +3212,10 @@ static int getPayload(
** the available payload.
*/
int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
- int rc = restoreOrClearCursorPosition(pCur, 1);
+ int rc;
+
+ assert( cursorHoldsMutex(pCur) );
+ rc = restoreOrClearCursorPosition(pCur);
if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_VALID );
assert( pCur->pPage!=0 );
@@ -3061,7 +3224,7 @@ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
}
assert( pCur->pPage->intKey==0 );
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
- rc = getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
+ rc = accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0, 0);
}
return rc;
}
@@ -3076,12 +3239,15 @@ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
** the available payload.
*/
int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
- int rc = restoreOrClearCursorPosition(pCur, 1);
+ int rc;
+
+ assert( cursorHoldsMutex(pCur) );
+ rc = restoreOrClearCursorPosition(pCur);
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);
+ rc = accessPayload(pCur, offset, amt, pBuf, 1, 0);
}
return rc;
}
@@ -3098,7 +3264,7 @@ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
** and data to fit on the local page and for there to be no overflow
** pages. When that is so, this routine can be used to access the
** key and data without making a copy. If the key and/or data spills
-** onto overflow pages, then getPayload() must be used to reassembly
+** onto overflow pages, then accessPayload() must be used to reassembly
** the key/data and copy it into a preallocated buffer.
**
** The pointer returned by this routine looks directly into the cached
@@ -3117,8 +3283,8 @@ static const unsigned char *fetchPayload(
assert( pCur!=0 && pCur->pPage!=0 );
assert( pCur->eState==CURSOR_VALID );
+ assert( cursorHoldsMutex(pCur) );
pPage = pCur->pPage;
- pageIntegrity(pPage);
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
getCellInfo(pCur);
aPayload = pCur->info.pCell;
@@ -3148,18 +3314,23 @@ static const unsigned char *fetchPayload(
** b-tree page. Write the number of available bytes into *pAmt.
**
** The pointer returned is ephemeral. The key/data may move
-** or be destroyed on the next call to any Btree routine.
+** or be destroyed on the next call to any Btree routine,
+** including calls from other threads against the same cache.
+** Hence, a mutex on the BtShared should be held prior to calling
+** this routine.
**
** These routines is used to get quick access to key and data
** in the common case where no overflow pages are used.
*/
const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){
+ assert( cursorHoldsMutex(pCur) );
if( pCur->eState==CURSOR_VALID ){
return (const void*)fetchPayload(pCur, pAmt, 0);
}
return 0;
}
const void *sqlite3BtreeDataFetch(BtCursor *pCur, int *pAmt){
+ assert( cursorHoldsMutex(pCur) );
if( pCur->eState==CURSOR_VALID ){
return (const void*)fetchPayload(pCur, pAmt, 1);
}
@@ -3175,12 +3346,12 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
int rc;
MemPage *pNewPage;
MemPage *pOldPage;
- BtShared *pBt = pCur->pBtree->pBt;
+ BtShared *pBt = pCur->pBt;
+ assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage);
if( rc ) return rc;
- pageIntegrity(pNewPage);
pNewPage->idxParent = pCur->idx;
pOldPage = pCur->pPage;
pOldPage->idxShift = 0;
@@ -3203,8 +3374,11 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
** virtual root page is the page that the right-pointer of page
** 1 is pointing to.
*/
-static int isRootPage(MemPage *pPage){
- MemPage *pParent = pPage->pParent;
+int sqlite3BtreeIsRootPage(MemPage *pPage){
+ MemPage *pParent;
+
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+ pParent = pPage->pParent;
if( pParent==0 ) return 1;
if( pParent->pgno>1 ) return 0;
if( get2byte(&pParent->aData[pParent->hdrOffset+3])==0 ) return 1;
@@ -3219,21 +3393,20 @@ static int isRootPage(MemPage *pPage){
** right-most child page then pCur->idx is set to one more than
** the largest cell index.
*/
-static void moveToParent(BtCursor *pCur){
+void sqlite3BtreeMoveToParent(BtCursor *pCur){
MemPage *pParent;
MemPage *pPage;
int idxParent;
+ assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
pPage = pCur->pPage;
assert( pPage!=0 );
- assert( !isRootPage(pPage) );
- pageIntegrity(pPage);
+ assert( !sqlite3BtreeIsRootPage(pPage) );
pParent = pPage->pParent;
assert( pParent!=0 );
- pageIntegrity(pParent);
idxParent = pPage->idxParent;
- sqlite3pager_ref(pParent->aData);
+ sqlite3PagerRef(pParent->pDbPage);
releasePage(pPage);
pCur->pPage = pParent;
pCur->info.nSize = 0;
@@ -3247,9 +3420,19 @@ static void moveToParent(BtCursor *pCur){
static int moveToRoot(BtCursor *pCur){
MemPage *pRoot;
int rc = SQLITE_OK;
- BtShared *pBt = pCur->pBtree->pBt;
+ Btree *p = pCur->pBtree;
+ BtShared *pBt = p->pBt;
- restoreOrClearCursorPosition(pCur, 0);
+ assert( cursorHoldsMutex(pCur) );
+ assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
+ assert( CURSOR_VALID < CURSOR_REQUIRESEEK );
+ assert( CURSOR_FAULT > CURSOR_REQUIRESEEK );
+ if( pCur->eState>=CURSOR_REQUIRESEEK ){
+ if( pCur->eState==CURSOR_FAULT ){
+ return pCur->skip;
+ }
+ clearCursorPosition(pCur);
+ }
pRoot = pCur->pPage;
if( pRoot && pRoot->pgno==pCur->pgnoRoot ){
assert( pRoot->isInit );
@@ -3261,7 +3444,6 @@ static int moveToRoot(BtCursor *pCur){
return rc;
}
releasePage(pCur->pPage);
- pageIntegrity(pRoot);
pCur->pPage = pRoot;
}
pCur->idx = 0;
@@ -3287,17 +3469,17 @@ static int moveToRoot(BtCursor *pCur){
*/
static int moveToLeftmost(BtCursor *pCur){
Pgno pgno;
- int rc;
+ int rc = SQLITE_OK;
MemPage *pPage;
+ assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
- while( !(pPage = pCur->pPage)->leaf ){
+ while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
pgno = get4byte(findCell(pPage, pCur->idx));
rc = moveToChild(pCur, pgno);
- if( rc ) return rc;
}
- return SQLITE_OK;
+ return rc;
}
/*
@@ -3312,18 +3494,20 @@ static int moveToLeftmost(BtCursor *pCur){
*/
static int moveToRightmost(BtCursor *pCur){
Pgno pgno;
- int rc;
+ int rc = SQLITE_OK;
MemPage *pPage;
+ assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
- while( !(pPage = pCur->pPage)->leaf ){
+ while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
pCur->idx = pPage->nCell;
rc = moveToChild(pCur, pgno);
- if( rc ) return rc;
}
- pCur->idx = pPage->nCell - 1;
- pCur->info.nSize = 0;
+ if( rc==SQLITE_OK ){
+ pCur->idx = pPage->nCell - 1;
+ pCur->info.nSize = 0;
+ }
return SQLITE_OK;
}
@@ -3333,16 +3517,21 @@ static int moveToRightmost(BtCursor *pCur){
*/
int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
int rc;
+
+ assert( cursorHoldsMutex(pCur) );
+ assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
rc = moveToRoot(pCur);
- if( rc ) return rc;
- if( pCur->eState==CURSOR_INVALID ){
- assert( pCur->pPage->nCell==0 );
- *pRes = 1;
- return SQLITE_OK;
+ if( rc==SQLITE_OK ){
+ if( pCur->eState==CURSOR_INVALID ){
+ assert( pCur->pPage->nCell==0 );
+ *pRes = 1;
+ rc = SQLITE_OK;
+ }else{
+ assert( pCur->pPage->nCell>0 );
+ *pRes = 0;
+ rc = moveToLeftmost(pCur);
+ }
}
- assert( pCur->pPage->nCell>0 );
- *pRes = 0;
- rc = moveToLeftmost(pCur);
return rc;
}
@@ -3352,16 +3541,20 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
*/
int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
int rc;
+
+ assert( cursorHoldsMutex(pCur) );
+ assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
rc = moveToRoot(pCur);
- if( rc ) return rc;
- if( CURSOR_INVALID==pCur->eState ){
- assert( pCur->pPage->nCell==0 );
- *pRes = 1;
- return SQLITE_OK;
+ if( rc==SQLITE_OK ){
+ if( CURSOR_INVALID==pCur->eState ){
+ assert( pCur->pPage->nCell==0 );
+ *pRes = 1;
+ }else{
+ assert( pCur->eState==CURSOR_VALID );
+ *pRes = 0;
+ rc = moveToRightmost(pCur);
+ }
}
- assert( pCur->eState==CURSOR_VALID );
- *pRes = 0;
- rc = moveToRightmost(pCur);
return rc;
}
@@ -3391,21 +3584,31 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
**
** *pRes>0 The cursor is left pointing at an entry that
** is larger than pKey.
+**
*/
-int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
+int sqlite3BtreeMoveto(
+ BtCursor *pCur, /* The cursor to be moved */
+ const void *pKey, /* The key content for indices. Not used by tables */
+ i64 nKey, /* Size of pKey. Or the key for tables */
+ int biasRight, /* If true, bias the search to the high end */
+ int *pRes /* Search result flag */
+){
int rc;
- int tryRightmost;
+
+ assert( cursorHoldsMutex(pCur) );
+ assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
rc = moveToRoot(pCur);
- if( rc ) return rc;
+ if( rc ){
+ return rc;
+ }
assert( pCur->pPage );
assert( pCur->pPage->isInit );
- tryRightmost = pCur->pPage->intKey;
if( pCur->eState==CURSOR_INVALID ){
*pRes = -1;
assert( pCur->pPage->nCell==0 );
return SQLITE_OK;
}
- for(;;){
+ for(;;){
int lwr, upr;
Pgno chldPg;
MemPage *pPage = pCur->pPage;
@@ -3415,17 +3618,17 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
if( !pPage->intKey && pKey==0 ){
return SQLITE_CORRUPT_BKPT;
}
- pageIntegrity(pPage);
- while( lwr<=upr ){
+ if( biasRight ){
+ pCur->idx = upr;
+ }else{
+ pCur->idx = (upr+lwr)/2;
+ }
+ if( lwr<=upr ) for(;;){
void *pCellKey;
i64 nCellKey;
- pCur->idx = (lwr+upr)/2;
pCur->info.nSize = 0;
if( pPage->intKey ){
u8 *pCell;
- if( tryRightmost ){
- pCur->idx = upr;
- }
pCell = findCell(pPage, pCur->idx) + pPage->childPtrSize;
if( pPage->hasData ){
u32 dummy;
@@ -3436,7 +3639,6 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
c = -1;
}else if( nCellKey>nKey ){
c = +1;
- tryRightmost = 0;
}else{
c = 0;
}
@@ -3447,12 +3649,14 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
if( available>=nCellKey ){
c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey);
}else{
- pCellKey = sqliteMallocRaw( nCellKey );
+ pCellKey = sqlite3_malloc( nCellKey );
if( pCellKey==0 ) return SQLITE_NOMEM;
rc = sqlite3BtreeKey(pCur, 0, nCellKey, (void *)pCellKey);
c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey);
- sqliteFree(pCellKey);
- if( rc ) return rc;
+ sqlite3_free(pCellKey);
+ if( rc ){
+ return rc;
+ }
}
}
if( c==0 ){
@@ -3470,6 +3674,10 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
}else{
upr = pCur->idx-1;
}
+ if( lwr>upr ){
+ break;
+ }
+ pCur->idx = (lwr+upr)/2;
}
assert( lwr==upr+1 );
assert( pPage->isInit );
@@ -3495,6 +3703,7 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
/* NOT REACHED */
}
+
/*
** Return TRUE if the cursor is not pointing at an entry of the table.
**
@@ -3511,34 +3720,41 @@ int sqlite3BtreeEof(BtCursor *pCur){
}
/*
+** Return the database connection handle for a cursor.
+*/
+sqlite3 *sqlite3BtreeCursorDb(const BtCursor *pCur){
+ assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
+ return pCur->pBtree->db;
+}
+
+/*
** Advance the cursor to the next entry in the database. If
** successful then set *pRes=0. If the cursor
** was already pointing to the last entry in the database before
** this routine was called, then set *pRes=1.
*/
-int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
+static int btreeNext(BtCursor *pCur, int *pRes){
int rc;
MemPage *pPage;
-#ifndef SQLITE_OMIT_SHARED_CACHE
- rc = restoreOrClearCursorPosition(pCur, 1);
+ assert( cursorHoldsMutex(pCur) );
+ rc = restoreOrClearCursorPosition(pCur);
if( rc!=SQLITE_OK ){
return rc;
}
+ assert( pRes!=0 );
+ pPage = pCur->pPage;
+ if( CURSOR_INVALID==pCur->eState ){
+ *pRes = 1;
+ return SQLITE_OK;
+ }
if( pCur->skip>0 ){
pCur->skip = 0;
*pRes = 0;
return SQLITE_OK;
}
pCur->skip = 0;
-#endif
- assert( pRes!=0 );
- pPage = pCur->pPage;
- if( CURSOR_INVALID==pCur->eState ){
- *pRes = 1;
- return SQLITE_OK;
- }
assert( pPage->isInit );
assert( pCur->idx<pPage->nCell );
@@ -3553,12 +3769,12 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
return rc;
}
do{
- if( isRootPage(pPage) ){
+ if( sqlite3BtreeIsRootPage(pPage) ){
*pRes = 1;
pCur->eState = CURSOR_INVALID;
return SQLITE_OK;
}
- moveToParent(pCur);
+ sqlite3BtreeMoveToParent(pCur);
pPage = pCur->pPage;
}while( pCur->idx>=pPage->nCell );
*pRes = 0;
@@ -3576,6 +3792,13 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
rc = moveToLeftmost(pCur);
return rc;
}
+int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
+ int rc;
+ assert( cursorHoldsMutex(pCur) );
+ rc = btreeNext(pCur, pRes);
+ return rc;
+}
+
/*
** Step the cursor to the back to the previous entry in the database. If
@@ -3583,28 +3806,26 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
** was already pointing to the first entry in the database before
** this routine was called, then set *pRes=1.
*/
-int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
+static int btreePrevious(BtCursor *pCur, int *pRes){
int rc;
Pgno pgno;
MemPage *pPage;
-#ifndef SQLITE_OMIT_SHARED_CACHE
- rc = restoreOrClearCursorPosition(pCur, 1);
+ assert( cursorHoldsMutex(pCur) );
+ rc = restoreOrClearCursorPosition(pCur);
if( rc!=SQLITE_OK ){
return rc;
}
+ if( CURSOR_INVALID==pCur->eState ){
+ *pRes = 1;
+ return SQLITE_OK;
+ }
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;
- }
pPage = pCur->pPage;
assert( pPage->isInit );
@@ -3612,16 +3833,18 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
if( !pPage->leaf ){
pgno = get4byte( findCell(pPage, pCur->idx) );
rc = moveToChild(pCur, pgno);
- if( rc ) return rc;
+ if( rc ){
+ return rc;
+ }
rc = moveToRightmost(pCur);
}else{
while( pCur->idx==0 ){
- if( isRootPage(pPage) ){
+ if( sqlite3BtreeIsRootPage(pPage) ){
pCur->eState = CURSOR_INVALID;
*pRes = 1;
return SQLITE_OK;
}
- moveToParent(pCur);
+ sqlite3BtreeMoveToParent(pCur);
pPage = pCur->pPage;
}
pCur->idx--;
@@ -3635,18 +3858,24 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
*pRes = 0;
return rc;
}
+int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
+ int rc;
+ assert( cursorHoldsMutex(pCur) );
+ rc = btreePrevious(pCur, pRes);
+ return rc;
+}
/*
** Allocate a new page from the database file.
**
-** The new page is marked as dirty. (In other words, sqlite3pager_write()
+** The new page is marked as dirty. (In other words, sqlite3PagerWrite()
** has already been called on the new page.) The new page has also
** been referenced and the calling routine is responsible for calling
-** sqlite3pager_unref() on the new page when it is done.
+** sqlite3PagerUnref() on the new page when it is done.
**
** SQLITE_OK is returned on success. Any other return value indicates
** an error. *ppPage and *pPgno are undefined in the event of an error.
-** Do not invoke sqlite3pager_unref() on *ppPage if an error is returned.
+** Do not invoke sqlite3PagerUnref() on *ppPage if an error is returned.
**
** If the "nearby" parameter is not 0, then a (feeble) effort is made to
** locate a page close to the page number "nearby". This can be used in an
@@ -3657,7 +3886,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
** anywhere on the free-list, then it is guarenteed to be returned. This
** is only used by auto-vacuum databases when allocating a new table.
*/
-static int allocatePage(
+static int allocateBtreePage(
BtShared *pBt,
MemPage **ppPage,
Pgno *pPgno,
@@ -3668,14 +3897,15 @@ static int allocatePage(
int rc;
int n; /* Number of pages on the freelist */
int k; /* Number of leaves on the trunk of the freelist */
+ MemPage *pTrunk = 0;
+ MemPage *pPrevTrunk = 0;
+ assert( sqlite3_mutex_held(pBt->mutex) );
pPage1 = pBt->pPage1;
n = get4byte(&pPage1->aData[36]);
if( n>0 ){
/* There are pages on the freelist. Reuse one of those pages. */
- MemPage *pTrunk = 0;
Pgno iTrunk;
- MemPage *pPrevTrunk = 0;
u8 searchList = 0; /* If the free-list must be searched for 'nearby' */
/* If the 'exact' parameter was true and a query of the pointer-map
@@ -3683,7 +3913,7 @@ static int allocatePage(
** the entire-list will be searched for that page.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
- if( exact ){
+ if( exact && nearby<=sqlite3PagerPagecount(pBt->pPager) ){
u8 eType;
assert( nearby>0 );
assert( pBt->autoVacuum );
@@ -3699,7 +3929,7 @@ static int allocatePage(
/* Decrement the free-list count by 1. Set iTrunk to the index of the
** first free-list trunk page. iPrevTrunk is initially 1.
*/
- rc = sqlite3pager_write(pPage1->aData);
+ rc = sqlite3PagerWrite(pPage1->pDbPage);
if( rc ) return rc;
put4byte(&pPage1->aData[36], n-1);
@@ -3714,18 +3944,10 @@ static int allocatePage(
}else{
iTrunk = get4byte(&pPage1->aData[32]);
}
- rc = getPage(pBt, iTrunk, &pTrunk);
+ rc = sqlite3BtreeGetPage(pBt, iTrunk, &pTrunk, 0);
if( rc ){
- releasePage(pPrevTrunk);
- return rc;
- }
-
- /* TODO: This should move to after the loop? */
- rc = sqlite3pager_write(pTrunk->aData);
- if( rc ){
- releasePage(pTrunk);
- releasePage(pPrevTrunk);
- return rc;
+ pTrunk = 0;
+ goto end_allocate_page;
}
k = get4byte(&pTrunk->aData[4]);
@@ -3734,6 +3956,10 @@ static int allocatePage(
** So extract the trunk page itself and use it as the newly
** allocated page */
assert( pPrevTrunk==0 );
+ rc = sqlite3PagerWrite(pTrunk->pDbPage);
+ if( rc ){
+ goto end_allocate_page;
+ }
*pPgno = iTrunk;
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
*ppPage = pTrunk;
@@ -3741,7 +3967,8 @@ static int allocatePage(
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
}else if( k>pBt->usableSize/4 - 8 ){
/* Value of k is out of range. Database corruption */
- return SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_BKPT;
+ goto end_allocate_page;
#ifndef SQLITE_OMIT_AUTOVACUUM
}else if( searchList && nearby==iTrunk ){
/* The list is being searched and this trunk page is the page
@@ -3750,6 +3977,10 @@ static int allocatePage(
assert( *pPgno==iTrunk );
*ppPage = pTrunk;
searchList = 0;
+ rc = sqlite3PagerWrite(pTrunk->pDbPage);
+ if( rc ){
+ goto end_allocate_page;
+ }
if( k==0 ){
if( !pPrevTrunk ){
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
@@ -3763,28 +3994,28 @@ static int allocatePage(
*/
MemPage *pNewTrunk;
Pgno iNewTrunk = get4byte(&pTrunk->aData[8]);
- rc = getPage(pBt, iNewTrunk, &pNewTrunk);
+ rc = sqlite3BtreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0);
if( rc!=SQLITE_OK ){
- releasePage(pTrunk);
- releasePage(pPrevTrunk);
- return rc;
+ goto end_allocate_page;
}
- rc = sqlite3pager_write(pNewTrunk->aData);
+ rc = sqlite3PagerWrite(pNewTrunk->pDbPage);
if( rc!=SQLITE_OK ){
releasePage(pNewTrunk);
- releasePage(pTrunk);
- releasePage(pPrevTrunk);
- return rc;
+ goto end_allocate_page;
}
memcpy(&pNewTrunk->aData[0], &pTrunk->aData[0], 4);
put4byte(&pNewTrunk->aData[4], k-1);
memcpy(&pNewTrunk->aData[8], &pTrunk->aData[12], (k-1)*4);
+ releasePage(pNewTrunk);
if( !pPrevTrunk ){
put4byte(&pPage1->aData[32], iNewTrunk);
}else{
+ rc = sqlite3PagerWrite(pPrevTrunk->pDbPage);
+ if( rc ){
+ goto end_allocate_page;
+ }
put4byte(&pPrevTrunk->aData[0], iNewTrunk);
}
- releasePage(pNewTrunk);
}
pTrunk = 0;
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
@@ -3794,6 +4025,10 @@ static int allocatePage(
int closest;
Pgno iPage;
unsigned char *aData = pTrunk->aData;
+ rc = sqlite3PagerWrite(pTrunk->pDbPage);
+ if( rc ){
+ goto end_allocate_page;
+ }
if( nearby>0 ){
int i, dist;
closest = 0;
@@ -3814,7 +4049,7 @@ static int allocatePage(
iPage = get4byte(&aData[8+closest*4]);
if( !searchList || iPage==nearby ){
*pPgno = iPage;
- if( *pPgno>sqlite3pager_pagecount(pBt->pPager) ){
+ if( *pPgno>sqlite3PagerPagecount(pBt->pPager) ){
/* Free page off the end of the file */
return SQLITE_CORRUPT_BKPT;
}
@@ -3825,10 +4060,10 @@ static int allocatePage(
memcpy(&aData[8+closest*4], &aData[4+k*4], 4);
}
put4byte(&aData[4], k-1);
- rc = getPage(pBt, *pPgno, ppPage);
+ rc = sqlite3BtreeGetPage(pBt, *pPgno, ppPage, 1);
if( rc==SQLITE_OK ){
- sqlite3pager_dont_rollback((*ppPage)->aData);
- rc = sqlite3pager_write((*ppPage)->aData);
+ sqlite3PagerDontRollback((*ppPage)->pDbPage);
+ rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){
releasePage(*ppPage);
}
@@ -3837,14 +4072,24 @@ static int allocatePage(
}
}
releasePage(pPrevTrunk);
+ pPrevTrunk = 0;
}while( searchList );
- releasePage(pTrunk);
}else{
/* There are no pages on the freelist, so create a new page at the
** end of the file */
- *pPgno = sqlite3pager_pagecount(pBt->pPager) + 1;
+ *pPgno = sqlite3PagerPagecount(pBt->pPager) + 1;
#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( pBt->nTrunc ){
+ /* An incr-vacuum has already run within this transaction. So the
+ ** page to allocate is not from the physical end of the file, but
+ ** at pBt->nTrunc.
+ */
+ *pPgno = pBt->nTrunc+1;
+ if( *pPgno==PENDING_BYTE_PAGE(pBt) ){
+ (*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
@@ -3853,13 +4098,17 @@ static int allocatePage(
TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", *pPgno));
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
(*pPgno)++;
+ if( *pPgno==PENDING_BYTE_PAGE(pBt) ){ (*pPgno)++; }
+ }
+ if( pBt->nTrunc ){
+ pBt->nTrunc = *pPgno;
}
#endif
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
- rc = getPage(pBt, *pPgno, ppPage);
+ rc = sqlite3BtreeGetPage(pBt, *pPgno, ppPage, 0);
if( rc ) return rc;
- rc = sqlite3pager_write((*ppPage)->aData);
+ rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){
releasePage(*ppPage);
}
@@ -3867,13 +4116,17 @@ static int allocatePage(
}
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
+
+end_allocate_page:
+ releasePage(pTrunk);
+ releasePage(pPrevTrunk);
return rc;
}
/*
** Add a page of the database file to the freelist.
**
-** sqlite3pager_unref() is NOT called for pPage.
+** sqlite3PagerUnref() is NOT called for pPage.
*/
static int freePage(MemPage *pPage){
BtShared *pBt = pPage->pBt;
@@ -3881,13 +4134,14 @@ static int freePage(MemPage *pPage){
int rc, n, k;
/* Prepare the page for freeing */
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( pPage->pgno>1 );
pPage->isInit = 0;
releasePage(pPage->pParent);
pPage->pParent = 0;
/* Increment the free page count on pPage1 */
- rc = sqlite3pager_write(pPage1->aData);
+ rc = sqlite3PagerWrite(pPage1->pDbPage);
if( rc ) return rc;
n = get4byte(&pPage1->aData[36]);
put4byte(&pPage1->aData[36], n+1);
@@ -3896,7 +4150,7 @@ static int freePage(MemPage *pPage){
/* If the SQLITE_SECURE_DELETE compile-time option is enabled, then
** always fully overwrite deleted information with zeros.
*/
- rc = sqlite3pager_write(pPage->aData);
+ rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc ) return rc;
memset(pPage->aData, 0, pPage->pBt->pageSize);
#endif
@@ -3913,7 +4167,7 @@ static int freePage(MemPage *pPage){
if( n==0 ){
/* This is the first free page */
- rc = sqlite3pager_write(pPage->aData);
+ rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc ) return rc;
memset(pPage->aData, 0, 8);
put4byte(&pPage1->aData[32], pPage->pgno);
@@ -3922,28 +4176,32 @@ static int freePage(MemPage *pPage){
/* Other free pages already exist. Retrive the first trunk page
** of the freelist and find out how many leaves it has. */
MemPage *pTrunk;
- rc = getPage(pBt, get4byte(&pPage1->aData[32]), &pTrunk);
+ rc = sqlite3BtreeGetPage(pBt, get4byte(&pPage1->aData[32]), &pTrunk, 0);
if( rc ) return rc;
k = get4byte(&pTrunk->aData[4]);
if( k>=pBt->usableSize/4 - 8 ){
/* The trunk is full. Turn the page being freed into a new
** trunk page with no leaves. */
- rc = sqlite3pager_write(pPage->aData);
- if( rc ) return rc;
- put4byte(pPage->aData, pTrunk->pgno);
- put4byte(&pPage->aData[4], 0);
- put4byte(&pPage1->aData[32], pPage->pgno);
- TRACE(("FREE-PAGE: %d new trunk page replacing %d\n",
- pPage->pgno, pTrunk->pgno));
+ rc = sqlite3PagerWrite(pPage->pDbPage);
+ if( rc==SQLITE_OK ){
+ put4byte(pPage->aData, pTrunk->pgno);
+ put4byte(&pPage->aData[4], 0);
+ put4byte(&pPage1->aData[32], pPage->pgno);
+ TRACE(("FREE-PAGE: %d new trunk page replacing %d\n",
+ pPage->pgno, pTrunk->pgno));
+ }
+ }else if( k<0 ){
+ rc = SQLITE_CORRUPT;
}else{
/* Add the newly freed page as a leaf on the current trunk */
- rc = sqlite3pager_write(pTrunk->aData);
- if( rc ) return rc;
- put4byte(&pTrunk->aData[4], k+1);
- put4byte(&pTrunk->aData[8+k*4], pPage->pgno);
+ rc = sqlite3PagerWrite(pTrunk->pDbPage);
+ if( rc==SQLITE_OK ){
+ 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);
+ sqlite3PagerDontWrite(pPage->pDbPage);
#endif
+ }
TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno));
}
releasePage(pTrunk);
@@ -3959,22 +4217,28 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
CellInfo info;
Pgno ovflPgno;
int rc;
+ int nOvfl;
+ int ovflPageSize;
- parseCellPtr(pPage, pCell, &info);
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+ sqlite3BtreeParseCellPtr(pPage, pCell, &info);
if( info.iOverflow==0 ){
return SQLITE_OK; /* No overflow pages. Return without doing anything */
}
ovflPgno = get4byte(&pCell[info.iOverflow]);
- while( ovflPgno!=0 ){
+ ovflPageSize = pBt->usableSize - 4;
+ nOvfl = (info.nPayload - info.nLocal + ovflPageSize - 1)/ovflPageSize;
+ assert( ovflPgno==0 || nOvfl>0 );
+ while( nOvfl-- ){
MemPage *pOvfl;
- if( ovflPgno>sqlite3pager_pagecount(pBt->pPager) ){
+ if( ovflPgno==0 || ovflPgno>sqlite3PagerPagecount(pBt->pPager) ){
return SQLITE_CORRUPT_BKPT;
}
- rc = getPage(pBt, ovflPgno, &pOvfl);
+
+ rc = getOverflowPage(pBt, ovflPgno, &pOvfl, (nOvfl==0)?0:&ovflPgno);
if( rc ) return rc;
- ovflPgno = get4byte(pOvfl->aData);
rc = freePage(pOvfl);
- sqlite3pager_unref(pOvfl->aData);
+ sqlite3PagerUnref(pOvfl->pDbPage);
if( rc ) return rc;
}
return SQLITE_OK;
@@ -3997,6 +4261,7 @@ static int fillInCell(
unsigned char *pCell, /* Complete text of the cell */
const void *pKey, i64 nKey, /* The key */
const void *pData,int nData, /* The data */
+ int nZero, /* Extra zero bytes to append to pData */
int *pnSize /* Write cell size here */
){
int nPayload;
@@ -4012,24 +4277,26 @@ static int fillInCell(
int nHeader;
CellInfo info;
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+
/* Fill in the header. */
nHeader = 0;
if( !pPage->leaf ){
nHeader += 4;
}
if( pPage->hasData ){
- nHeader += putVarint(&pCell[nHeader], nData);
+ nHeader += putVarint(&pCell[nHeader], nData+nZero);
}else{
- nData = 0;
+ nData = nZero = 0;
}
nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey);
- parseCellPtr(pPage, pCell, &info);
+ sqlite3BtreeParseCellPtr(pPage, pCell, &info);
assert( info.nHeader==nHeader );
assert( info.nKey==nKey );
- assert( info.nData==nData );
+ assert( info.nData==nData+nZero );
/* Fill in the payload */
- nPayload = nData;
+ nPayload = nData + nZero;
if( pPage->intKey ){
pSrc = pData;
nSrc = nData;
@@ -4046,23 +4313,42 @@ static int fillInCell(
while( nPayload>0 ){
if( spaceLeft==0 ){
+ int isExact = 0;
#ifndef SQLITE_OMIT_AUTOVACUUM
Pgno pgnoPtrmap = pgnoOvfl; /* Overflow page pointer-map entry page */
+ if( pBt->autoVacuum ){
+ do{
+ pgnoOvfl++;
+ } while(
+ PTRMAP_ISPAGE(pBt, pgnoOvfl) || pgnoOvfl==PENDING_BYTE_PAGE(pBt)
+ );
+ if( pgnoOvfl>1 ){
+ /* isExact = 1; */
+ }
+ }
#endif
- rc = allocatePage(pBt, &pOvfl, &pgnoOvfl, pgnoOvfl, 0);
+ rc = allocateBtreePage(pBt, &pOvfl, &pgnoOvfl, pgnoOvfl, isExact);
#ifndef SQLITE_OMIT_AUTOVACUUM
/* If the database supports auto-vacuum, and the second or subsequent
** overflow page is being allocated, add an entry to the pointer-map
- ** for that page now. The entry for the first overflow page will be
- ** added later, by the insertCell() routine.
+ ** for that page now.
+ **
+ ** If this is the first overflow page, then write a partial entry
+ ** to the pointer-map. If we write nothing to this pointer-map slot,
+ ** then the optimistic overflow chain processing in clearCell()
+ ** may misinterpret the uninitialised values and delete the
+ ** wrong pages from the database.
*/
- if( pBt->autoVacuum && pgnoPtrmap!=0 && rc==SQLITE_OK ){
- rc = ptrmapPut(pBt, pgnoOvfl, PTRMAP_OVERFLOW2, pgnoPtrmap);
+ if( pBt->autoVacuum && rc==SQLITE_OK ){
+ u8 eType = (pgnoPtrmap?PTRMAP_OVERFLOW2:PTRMAP_OVERFLOW1);
+ rc = ptrmapPut(pBt, pgnoOvfl, eType, pgnoPtrmap);
+ if( rc ){
+ releasePage(pOvfl);
+ }
}
#endif
if( rc ){
releasePage(pToRelease);
- /* clearCell(pPage, pCell); */
return rc;
}
put4byte(pPrior, pgnoOvfl);
@@ -4075,9 +4361,13 @@ static int fillInCell(
}
n = nPayload;
if( n>spaceLeft ) n = spaceLeft;
- if( n>nSrc ) n = nSrc;
- assert( pSrc );
- memcpy(pPayload, pSrc, n);
+ if( nSrc>0 ){
+ if( n>nSrc ) n = nSrc;
+ assert( pSrc );
+ memcpy(pPayload, pSrc, n);
+ }else{
+ memset(pPayload, 0, n);
+ }
nPayload -= n;
pPayload += n;
pSrc += n;
@@ -4099,24 +4389,25 @@ static int fillInCell(
*/
static int reparentPage(BtShared *pBt, Pgno pgno, MemPage *pNewParent, int idx){
MemPage *pThis;
- unsigned char *aData;
+ DbPage *pDbPage;
+ assert( sqlite3_mutex_held(pBt->mutex) );
assert( pNewParent!=0 );
if( pgno==0 ) return SQLITE_OK;
assert( pBt->pPager!=0 );
- aData = sqlite3pager_lookup(pBt->pPager, pgno);
- if( aData ){
- pThis = (MemPage*)&aData[pBt->pageSize];
- assert( pThis->aData==aData );
+ pDbPage = sqlite3PagerLookup(pBt->pPager, pgno);
+ if( pDbPage ){
+ pThis = (MemPage *)sqlite3PagerGetExtra(pDbPage);
if( pThis->isInit ){
+ assert( pThis->aData==sqlite3PagerGetData(pDbPage) );
if( pThis->pParent!=pNewParent ){
- if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData);
+ if( pThis->pParent ) sqlite3PagerUnref(pThis->pParent->pDbPage);
pThis->pParent = pNewParent;
- sqlite3pager_ref(pNewParent->aData);
+ sqlite3PagerRef(pNewParent->pDbPage);
}
pThis->idxParent = idx;
}
- sqlite3pager_unref(aData);
+ sqlite3PagerUnref(pDbPage);
}
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -4144,6 +4435,7 @@ static int reparentChildPages(MemPage *pPage){
BtShared *pBt = pPage->pBt;
int rc = SQLITE_OK;
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
if( pPage->leaf ) return SQLITE_OK;
for(i=0; i<pPage->nCell; i++){
@@ -4177,7 +4469,8 @@ static void dropCell(MemPage *pPage, int idx, int sz){
assert( idx>=0 && idx<pPage->nCell );
assert( sz==cellSize(pPage, idx) );
- assert( sqlite3pager_iswriteable(pPage->aData) );
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) );
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
data = pPage->aData;
ptr = &data[pPage->cellOffset + 2*idx];
pc = get2byte(ptr);
@@ -4230,7 +4523,7 @@ static int insertCell(
assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
assert( sz==cellSizePtr(pPage, pCell) );
- assert( sqlite3pager_iswriteable(pPage->aData) );
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
if( pPage->nOverflow || sz+2>pPage->nFree ){
if( pTemp ){
memcpy(pTemp+nSkip, pCell+nSkip, sz-nSkip);
@@ -4242,6 +4535,11 @@ static int insertCell(
pPage->aOvfl[j].idx = i;
pPage->nFree = 0;
}else{
+ int rc = sqlite3PagerWrite(pPage->pDbPage);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) );
data = pPage->aData;
hdr = pPage->hdrOffset;
top = get2byte(&data[hdr+5]);
@@ -4249,7 +4547,7 @@ static int insertCell(
end = cellOffset + 2*pPage->nCell + 2;
ins = cellOffset + 2*i;
if( end > top - sz ){
- int rc = defragmentPage(pPage);
+ rc = defragmentPage(pPage);
if( rc!=SQLITE_OK ) return rc;
top = get2byte(&data[hdr+5]);
assert( end + sz <= top );
@@ -4267,17 +4565,17 @@ static int insertCell(
put2byte(&data[ins], idx);
put2byte(&data[hdr+3], pPage->nCell);
pPage->idxShift = 1;
- pageIntegrity(pPage);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pPage->pBt->autoVacuum ){
/* The cell may contain a pointer to an overflow page. If so, write
** the entry for the overflow page into the pointer map.
*/
CellInfo info;
- parseCellPtr(pPage, pCell, &info);
+ sqlite3BtreeParseCellPtr(pPage, pCell, &info);
+ assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload );
if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){
Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]);
- int rc = ptrmapPut(pPage->pBt, pgnoOvfl, PTRMAP_OVERFLOW1, pPage->pgno);
+ rc = ptrmapPut(pPage->pBt, pgnoOvfl, PTRMAP_OVERFLOW1, pPage->pgno);
if( rc!=SQLITE_OK ) return rc;
}
}
@@ -4305,6 +4603,7 @@ static void assemblePage(
u8 *data; /* Data for the page */
assert( pPage->nOverflow==0 );
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
totalSize = 0;
for(i=0; i<nCell; i++){
totalSize += aSize[i];
@@ -4379,10 +4678,12 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){
int parentSize; /* Size of new divider cell */
u8 parentCell[64]; /* Space for the new divider cell */
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+
/* Allocate a new page. Insert the overflow cell from pPage
** into it. Then remove the overflow cell from pPage.
*/
- rc = allocatePage(pBt, &pNew, &pgnoNew, 0, 0);
+ rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -4394,15 +4695,16 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){
/* Set the parent of the newly allocated page to pParent. */
pNew->pParent = pParent;
- sqlite3pager_ref(pParent->aData);
+ sqlite3PagerRef(pParent->pDbPage);
/* pPage is currently the right-child of pParent. Change this
** so that the right-child is the new page allocated above and
** pPage is the next-to-right child.
*/
assert( pPage->nCell>0 );
- parseCellPtr(pPage, findCell(pPage, pPage->nCell-1), &info);
- rc = fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, &parentSize);
+ pCell = findCell(pPage, pPage->nCell-1);
+ sqlite3BtreeParseCellPtr(pPage, pCell, &info);
+ rc = fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, 0, &parentSize);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -4421,11 +4723,11 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){
*/
if( pBt->autoVacuum ){
rc = ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno);
- if( rc!=SQLITE_OK ){
- return rc;
+ if( rc==SQLITE_OK ){
+ rc = ptrmapPutOvfl(pNew, 0);
}
- rc = ptrmapPutOvfl(pNew, 0);
if( rc!=SQLITE_OK ){
+ releasePage(pNew);
return rc;
}
}
@@ -4440,19 +4742,6 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){
#endif /* SQLITE_OMIT_QUICKBALANCE */
/*
-** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
-** if the database supports auto-vacuum or not. Because it is used
-** within an expression that is an argument to another macro
-** (sqliteMallocRaw), it is not possible to use conditional compilation.
-** So, this macro is defined instead.
-*/
-#ifndef SQLITE_OMIT_AUTOVACUUM
-#define ISAUTOVACUUM (pBt->autoVacuum)
-#else
-#define ISAUTOVACUUM 0
-#endif
-
-/*
** This routine redistributes Cells on pPage and up to NN*2 siblings
** of pPage so that all pages have about the same amount of free space.
** Usually NN siblings on either side of pPage is used in the balancing,
@@ -4483,7 +4772,7 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){
*/
static int balance_nonroot(MemPage *pPage){
MemPage *pParent; /* The parent of pPage */
- BtShared *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[] */
@@ -4515,15 +4804,17 @@ static int balance_nonroot(MemPage *pPage){
u8 *aFrom = 0;
#endif
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+
/*
** Find the parent page.
*/
assert( pPage->isInit );
- assert( sqlite3pager_iswriteable(pPage->aData) );
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) || pPage->nOverflow==1 );
pBt = pPage->pBt;
pParent = pPage->pParent;
assert( pParent );
- if( SQLITE_OK!=(rc = sqlite3pager_write(pParent->aData)) ){
+ if( SQLITE_OK!=(rc = sqlite3PagerWrite(pParent->pDbPage)) ){
return rc;
}
TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno));
@@ -4553,6 +4844,10 @@ static int balance_nonroot(MemPage *pPage){
}
#endif
+ if( SQLITE_OK!=(rc = sqlite3PagerWrite(pPage->pDbPage)) ){
+ return rc;
+ }
+
/*
** Find the cell in the parent page whose left child points back
** to pPage. The "idx" variable is the index of that cell. If pPage
@@ -4561,7 +4856,7 @@ static int balance_nonroot(MemPage *pPage){
if( pParent->idxShift ){
Pgno pgno;
pgno = pPage->pgno;
- assert( pgno==sqlite3pager_pagenumber(pPage->aData) );
+ assert( pgno==sqlite3PagerPagenumber(pPage->pDbPage) );
for(idx=0; idx<pParent->nCell; idx++){
if( get4byte(findCell(pParent, idx))==pgno ){
break;
@@ -4578,7 +4873,7 @@ static int balance_nonroot(MemPage *pPage){
** directly to balance_cleanup at any moment.
*/
nOld = nNew = 0;
- sqlite3pager_ref(pParent->aData);
+ sqlite3PagerRef(pParent->pDbPage);
/*
** Find sibling pages to pPage and the cells in pParent that divide
@@ -4622,7 +4917,7 @@ static int balance_nonroot(MemPage *pPage){
/*
** Allocate space for memory structures
*/
- apCell = sqliteMallocRaw(
+ apCell = sqlite3_malloc(
nMaxCells*sizeof(u8*) /* apCell */
+ nMaxCells*sizeof(int) /* szCell */
+ ROUND8(sizeof(MemPage))*NB /* aCopy */
@@ -4655,12 +4950,10 @@ static int balance_nonroot(MemPage *pPage){
** process of being overwritten.
*/
for(i=0; i<nOld; i++){
- MemPage *p = apCopy[i] = (MemPage*)&aCopy[i][pBt->pageSize];
- p->aData = &((u8*)p)[-pBt->pageSize];
- memcpy(p->aData, apOld[i]->aData, pBt->pageSize + sizeof(MemPage));
- /* The memcpy() above changes the value of p->aData so we have to
- ** set it again. */
- p->aData = &((u8*)p)[-pBt->pageSize];
+ MemPage *p = apCopy[i] = (MemPage*)aCopy[i];
+ memcpy(p, apOld[i], sizeof(MemPage));
+ p->aData = (void*)&p[1];
+ memcpy(p->aData, apOld[i]->aData, pBt->pageSize);
}
/*
@@ -4736,6 +5029,10 @@ static int balance_nonroot(MemPage *pPage){
memcpy(apCell[nCell], &pOld->aData[pOld->hdrOffset+8], 4);
}else{
assert( leafCorrection==4 );
+ if( szCell[nCell]<4 ){
+ /* Do not allow any cells smaller than 4 bytes. */
+ szCell[nCell] = 4;
+ }
}
nCell++;
}
@@ -4822,15 +5119,16 @@ static int balance_nonroot(MemPage *pPage){
pNew = apNew[i] = apOld[i];
pgnoNew[i] = pgnoOld[i];
apOld[i] = 0;
- rc = sqlite3pager_write(pNew->aData);
+ rc = sqlite3PagerWrite(pNew->pDbPage);
+ nNew++;
if( rc ) goto balance_cleanup;
}else{
assert( i>0 );
- rc = allocatePage(pBt, &pNew, &pgnoNew[i], pgnoNew[i-1], 0);
+ rc = allocateBtreePage(pBt, &pNew, &pgnoNew[i], pgnoNew[i-1], 0);
if( rc ) goto balance_cleanup;
apNew[i] = pNew;
+ nNew++;
}
- nNew++;
zeroPage(pNew, pageFlags);
}
@@ -4938,16 +5236,16 @@ static int balance_nonroot(MemPage *pPage){
memcpy(&pNew->aData[8], pCell, 4);
pTemp = 0;
}else if( leafData ){
- /* If the tree is a leaf-data tree, and the siblings are leaves,
+ /* If the tree is a leaf-data tree, and the siblings are leaves,
** then there is no divider cell in apCell[]. Instead, the divider
** cell consists of the integer key for the right-most cell of
** the sibling-page assembled above only.
*/
CellInfo info;
j--;
- parseCellPtr(pNew, apCell[j], &info);
+ sqlite3BtreeParseCellPtr(pNew, apCell[j], &info);
pCell = &aSpace[iSpace];
- fillInCell(pParent, pCell, 0, info.nKey, 0, 0, &sz);
+ fillInCell(pParent, pCell, 0, info.nKey, 0, 0, 0, &sz);
iSpace += sz;
assert( iSpace<=pBt->pageSize*5 );
pTemp = 0;
@@ -4956,6 +5254,21 @@ static int balance_nonroot(MemPage *pPage){
pTemp = &aSpace[iSpace];
iSpace += sz;
assert( iSpace<=pBt->pageSize*5 );
+ /* Obscure case for non-leaf-data trees: If the cell at pCell was
+ ** previously stored on a leaf node, and its reported size was 4
+ ** bytes, then it may actually be smaller than this
+ ** (see sqlite3BtreeParseCellPtr(), 4 bytes is the minimum size of
+ ** any cell). But it is important to pass the correct size to
+ ** insertCell(), so reparse the cell now.
+ **
+ ** Note that this can never happen in an SQLite data file, as all
+ ** cells are at least 4 bytes. It only happens in b-trees used
+ ** to evaluate "IN (SELECT ...)" and similar clauses.
+ */
+ if( szCell[j]==4 ){
+ assert(leafCorrection==4);
+ sz = cellSizePtr(pParent, pCell);
+ }
}
rc = insertCell(pParent, nxDiv, pCell, sz, pTemp, 4);
if( rc!=SQLITE_OK ) goto balance_cleanup;
@@ -5007,15 +5320,13 @@ static int balance_nonroot(MemPage *pPage){
** But the parent page will always be initialized.
*/
assert( pParent->isInit );
- /* assert( pPage->isInit ); // No! pPage might have been added to freelist */
- /* pageIntegrity(pPage); // No! pPage might have been added to freelist */
rc = balance(pParent, 0);
/*
** Cleanup before returning.
*/
balance_cleanup:
- sqliteFree(apCell);
+ sqlite3_free(apCell);
for(i=0; i<nOld; i++){
releasePage(apOld[i]);
}
@@ -5044,9 +5355,10 @@ static int balance_shallower(MemPage *pPage){
assert( pPage->pParent==0 );
assert( pPage->nCell==0 );
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
pBt = pPage->pBt;
mxCellPerPage = MX_CELL(pBt);
- apCell = sqliteMallocRaw( mxCellPerPage*(sizeof(u8*)+sizeof(int)) );
+ apCell = sqlite3_malloc( mxCellPerPage*(sizeof(u8*)+sizeof(int)) );
if( apCell==0 ) return SQLITE_NOMEM;
szCell = (int*)&apCell[mxCellPerPage];
if( pPage->leaf ){
@@ -5067,11 +5379,11 @@ static int balance_shallower(MemPage *pPage){
*/
pgnoChild = get4byte(&pPage->aData[pPage->hdrOffset+8]);
assert( pgnoChild>0 );
- assert( pgnoChild<=sqlite3pager_pagecount(pPage->pBt->pPager) );
- rc = getPage(pPage->pBt, pgnoChild, &pChild);
+ assert( pgnoChild<=sqlite3PagerPagecount(pPage->pBt->pPager) );
+ rc = sqlite3BtreeGetPage(pPage->pBt, pgnoChild, &pChild, 0);
if( rc ) goto end_shallow_balance;
if( pPage->pgno==1 ){
- rc = initPage(pChild, pPage);
+ rc = sqlite3BtreeInitPage(pChild, pPage);
if( rc ) goto end_shallow_balance;
assert( pChild->nOverflow==0 );
if( pChild->nFree>=100 ){
@@ -5098,7 +5410,7 @@ static int balance_shallower(MemPage *pPage){
memcpy(pPage->aData, pChild->aData, pPage->pBt->usableSize);
pPage->isInit = 0;
pPage->pParent = 0;
- rc = initPage(pPage, 0);
+ rc = sqlite3BtreeInitPage(pPage, 0);
assert( rc==SQLITE_OK );
freePage(pChild);
TRACE(("BALANCE: transfer child %d into root %d\n",
@@ -5117,11 +5429,10 @@ static int balance_shallower(MemPage *pPage){
}
}
#endif
- if( rc!=SQLITE_OK ) goto end_shallow_balance;
releasePage(pChild);
}
end_shallow_balance:
- sqliteFree(apCell);
+ sqlite3_free(apCell);
return rc;
}
@@ -5149,9 +5460,10 @@ static int balance_deeper(MemPage *pPage){
assert( pPage->pParent==0 );
assert( pPage->nOverflow>0 );
pBt = pPage->pBt;
- rc = allocatePage(pBt, &pChild, &pgnoChild, pPage->pgno, 0);
+ assert( sqlite3_mutex_held(pBt->mutex) );
+ rc = allocateBtreePage(pBt, &pChild, &pgnoChild, pPage->pgno, 0);
if( rc ) return rc;
- assert( sqlite3pager_iswriteable(pChild->aData) );
+ assert( sqlite3PagerIswriteable(pChild->pDbPage) );
usableSize = pBt->usableSize;
data = pPage->aData;
hdr = pPage->hdrOffset;
@@ -5160,7 +5472,7 @@ static int balance_deeper(MemPage *pPage){
memcpy(cdata, &data[hdr], pPage->cellOffset+2*pPage->nCell-hdr);
memcpy(&cdata[brk], &data[brk], usableSize-brk);
assert( pChild->isInit==0 );
- rc = initPage(pChild, pPage);
+ rc = sqlite3BtreeInitPage(pChild, pPage);
if( rc ) goto balancedeeper_out;
memcpy(pChild->aOvfl, pPage->aOvfl, pPage->nOverflow*sizeof(pPage->aOvfl[0]));
pChild->nOverflow = pPage->nOverflow;
@@ -5197,8 +5509,10 @@ balancedeeper_out:
*/
static int balance(MemPage *pPage, int insert){
int rc = SQLITE_OK;
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
if( pPage->pParent==0 ){
- if( pPage->nOverflow>0 ){
+ rc = sqlite3PagerWrite(pPage->pDbPage);
+ if( rc==SQLITE_OK && pPage->nOverflow>0 ){
rc = balance_deeper(pPage);
}
if( rc==SQLITE_OK && pPage->nCell==0 ){
@@ -5215,27 +5529,36 @@ static int balance(MemPage *pPage, int insert){
/*
** This routine checks all cursors that point to table pgnoRoot.
-** If any of those cursors other than pExclude were opened with
-** wrFlag==0 then this routine returns SQLITE_LOCKED. If all
-** cursors that point to pgnoRoot were opened with wrFlag==1
-** then this routine returns SQLITE_OK.
+** If any of those cursors were opened with wrFlag==0 in a different
+** database connection (a database connection that shares the pager
+** cache with the current connection) and that other connection
+** is not in the ReadUncommmitted state, then this routine returns
+** SQLITE_LOCKED.
**
** In addition to checking for read-locks (where a read-lock
** means a cursor opened with wrFlag==0) this routine also moves
-** all cursors other than pExclude so that they are pointing to the
-** first Cell on root page. This is necessary because an insert
+** all write cursors so that they are pointing to the
+** first Cell on the root page. This is necessary because an insert
** or delete might change the number of cells on a page or delete
** a page entirely and we do not want to leave any cursors
** pointing to non-existant pages or cells.
*/
-static int checkReadLocks(BtShared *pBt, Pgno pgnoRoot, BtCursor *pExclude){
+static int checkReadLocks(Btree *pBtree, Pgno pgnoRoot, BtCursor *pExclude){
BtCursor *p;
+ BtShared *pBt = pBtree->pBt;
+ sqlite3 *db = pBtree->db;
+ assert( sqlite3BtreeHoldsMutex(pBtree) );
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 ){
+ if( p==pExclude ) continue;
+ if( p->eState!=CURSOR_VALID ) continue;
+ if( p->pgnoRoot!=pgnoRoot ) continue;
+ if( p->wrFlag==0 ){
+ sqlite3 *dbOther = p->pBtree->db;
+ if( dbOther==0 ||
+ (dbOther!=db && (dbOther->flags & SQLITE_ReadUncommitted)==0) ){
+ return SQLITE_LOCKED;
+ }
+ }else if( p->pPage->pgno!=p->pgnoRoot ){
moveToRoot(p);
}
}
@@ -5254,33 +5577,41 @@ static int checkReadLocks(BtShared *pBt, Pgno pgnoRoot, BtCursor *pExclude){
int sqlite3BtreeInsert(
BtCursor *pCur, /* Insert data into the table of this cursor */
const void *pKey, i64 nKey, /* The key of the new record */
- const void *pData, int nData /* The data of the new record */
+ const void *pData, int nData, /* The data of the new record */
+ int nZero, /* Number of extra 0 bytes to append to data */
+ int appendBias /* True if this is likely an append */
){
int rc;
int loc;
int szNew;
MemPage *pPage;
- BtShared *pBt = pCur->pBtree->pBt;
+ Btree *p = pCur->pBtree;
+ BtShared *pBt = p->pBt;
unsigned char *oldCell;
unsigned char *newCell = 0;
+ assert( cursorHoldsMutex(pCur) );
if( pBt->inTransaction!=TRANS_WRITE ){
/* Must start a transaction before doing an insert */
- return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+ rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+ return rc;
}
assert( !pBt->readOnly );
if( !pCur->wrFlag ){
return SQLITE_PERM; /* Cursor not open for writing */
}
- if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){
+ if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
}
+ if( pCur->eState==CURSOR_FAULT ){
+ return pCur->skip;
+ }
/* Save the positions of any other cursors open on this table */
- restoreOrClearCursorPosition(pCur, 0);
+ clearCursorPosition(pCur);
if(
SQLITE_OK!=(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) ||
- SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, nKey, &loc))
+ SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, nKey, appendBias, &loc))
){
return rc;
}
@@ -5292,17 +5623,19 @@ int sqlite3BtreeInsert(
pCur->pgnoRoot, nKey, nData, pPage->pgno,
loc==0 ? "overwrite" : "new entry"));
assert( pPage->isInit );
- rc = sqlite3pager_write(pPage->aData);
- if( rc ) return rc;
- newCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) );
+ newCell = sqlite3_malloc( MX_CELL_SIZE(pBt) );
if( newCell==0 ) return SQLITE_NOMEM;
- rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, &szNew);
+ rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew);
if( rc ) goto end_insert;
assert( szNew==cellSizePtr(pPage, newCell) );
assert( szNew<=MX_CELL_SIZE(pBt) );
if( loc==0 && CURSOR_VALID==pCur->eState ){
int szOld;
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
+ rc = sqlite3PagerWrite(pPage->pDbPage);
+ if( rc ){
+ goto end_insert;
+ }
oldCell = findCell(pPage, pCur->idx);
if( !pPage->leaf ){
memcpy(newCell, oldCell, 4);
@@ -5327,7 +5660,7 @@ int sqlite3BtreeInsert(
moveToRoot(pCur);
}
end_insert:
- sqliteFree(newCell);
+ sqlite3_free(newCell);
return rc;
}
@@ -5340,38 +5673,44 @@ int sqlite3BtreeDelete(BtCursor *pCur){
unsigned char *pCell;
int rc;
Pgno pgnoChild = 0;
- BtShared *pBt = pCur->pBtree->pBt;
+ Btree *p = pCur->pBtree;
+ BtShared *pBt = p->pBt;
+ assert( cursorHoldsMutex(pCur) );
assert( pPage->isInit );
if( pBt->inTransaction!=TRANS_WRITE ){
/* Must start a transaction before doing a delete */
- return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+ rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+ return rc;
}
assert( !pBt->readOnly );
+ if( pCur->eState==CURSOR_FAULT ){
+ return pCur->skip;
+ }
if( pCur->idx >= pPage->nCell ){
return SQLITE_ERROR; /* The cursor is not pointing to anything */
}
if( !pCur->wrFlag ){
return SQLITE_PERM; /* Did not open this cursor for writing */
}
- if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){
+ if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
}
/* 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
+ ** open on the same table. Then call sqlite3PagerWrite() on the page
** that the entry will be deleted from.
*/
if(
- (rc = restoreOrClearCursorPosition(pCur, 1))!=0 ||
+ (rc = restoreOrClearCursorPosition(pCur))!=0 ||
(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur))!=0 ||
- (rc = sqlite3pager_write(pPage->aData))!=0
+ (rc = sqlite3PagerWrite(pPage->pDbPage))!=0
){
return rc;
}
- /* Locate the cell within it's page and leave pCell pointing to the
+ /* Locate the cell within its page and leave pCell pointing to the
** data. The clearCell() call frees any overflow pages associated with the
** cell. The cell itself is still intact.
*/
@@ -5380,7 +5719,9 @@ int sqlite3BtreeDelete(BtCursor *pCur){
pgnoChild = get4byte(pCell);
}
rc = clearCell(pPage, pCell);
- if( rc ) return rc;
+ if( rc ){
+ return rc;
+ }
if( !pPage->leaf ){
/*
@@ -5392,47 +5733,40 @@ int sqlite3BtreeDelete(BtCursor *pCur){
*/
BtCursor leafCur;
unsigned char *pNext;
- 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 );
- getTempCursor(pCur, &leafCur);
+ sqlite3BtreeGetTempCursor(pCur, &leafCur);
rc = sqlite3BtreeNext(&leafCur, &notUsed);
- if( rc!=SQLITE_OK ){
- if( rc!=SQLITE_NOMEM ){
- rc = SQLITE_CORRUPT_BKPT;
- }
- }
if( rc==SQLITE_OK ){
- rc = sqlite3pager_write(leafCur.pPage->aData);
+ rc = sqlite3PagerWrite(leafCur.pPage->pDbPage);
}
if( rc==SQLITE_OK ){
+ int szNext;
TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n",
pCur->pgnoRoot, pPage->pgno, leafCur.pPage->pgno));
dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell));
pNext = findCell(leafCur.pPage, leafCur.idx);
szNext = cellSizePtr(leafCur.pPage, pNext);
assert( MX_CELL_SIZE(pBt)>=szNext+4 );
- tempCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) );
+ tempCell = sqlite3_malloc( MX_CELL_SIZE(pBt) );
if( tempCell==0 ){
rc = SQLITE_NOMEM;
}
+ if( rc==SQLITE_OK ){
+ rc = insertCell(pPage, pCur->idx, pNext-4, szNext+4, tempCell, 0);
+ }
+ if( rc==SQLITE_OK ){
+ put4byte(findOverflowCell(pPage, pCur->idx), pgnoChild);
+ rc = balance(pPage, 0);
+ }
+ if( rc==SQLITE_OK ){
+ dropCell(leafCur.pPage, leafCur.idx, szNext);
+ rc = balance(leafCur.pPage, 0);
+ }
}
- if( rc==SQLITE_OK ){
- rc = insertCell(pPage, pCur->idx, pNext-4, szNext+4, tempCell, 0);
- }
- if( rc==SQLITE_OK ){
- put4byte(findOverflowCell(pPage, pCur->idx), pgnoChild);
- rc = balance(pPage, 0);
- }
- if( rc==SQLITE_OK ){
- dropCell(leafCur.pPage, leafCur.idx, szNext);
- rc = balance(leafCur.pPage, 0);
- }
- sqliteFree(tempCell);
- releaseTempCursor(&leafCur);
+ sqlite3_free(tempCell);
+ sqlite3BtreeReleaseTempCursor(&leafCur);
}else{
TRACE(("DELETE: table=%d delete from leaf %d\n",
pCur->pgnoRoot, pPage->pgno));
@@ -5456,46 +5790,51 @@ int sqlite3BtreeDelete(BtCursor *pCur){
** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys
** BTREE_ZERODATA Used for SQL indices
*/
-int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
+static int btreeCreateTable(Btree *p, int *piTable, int flags){
BtShared *pBt = p->pBt;
MemPage *pRoot;
Pgno pgnoRoot;
int rc;
+
+ assert( sqlite3BtreeHoldsMutex(p) );
if( pBt->inTransaction!=TRANS_WRITE ){
/* Must start a transaction first */
- return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+ rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+ return rc;
}
assert( !pBt->readOnly );
- /* It is illegal to create a table if any cursors are open on the
- ** database. This is because in auto-vacuum mode the backend may
- ** need to move a database page to make room for the new root-page.
- ** If an open cursor was using the page a problem would occur.
- */
- if( pBt->pCursor ){
- return SQLITE_LOCKED;
- }
-
#ifdef SQLITE_OMIT_AUTOVACUUM
- rc = allocatePage(pBt, &pRoot, &pgnoRoot, 1, 0);
- if( rc ) return rc;
+ rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0);
+ if( rc ){
+ return rc;
+ }
#else
if( pBt->autoVacuum ){
Pgno pgnoMove; /* Move a page here to make room for the root-page */
MemPage *pPageMove; /* The page to move to. */
+ /* Creating a new table may probably require moving an existing database
+ ** to make room for the new tables root page. In case this page turns
+ ** out to be an overflow page, delete all overflow page-map caches
+ ** held by open cursors.
+ */
+ invalidateAllOverflowCache(pBt);
+
/* Read the value of meta[3] from the database to determine where the
** 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(p, 4, &pgnoRoot);
- if( rc!=SQLITE_OK ) return rc;
+ 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, pgnoRoot) ||
+ while( pgnoRoot==PTRMAP_PAGENO(pBt, pgnoRoot) ||
pgnoRoot==PENDING_BYTE_PAGE(pBt) ){
pgnoRoot++;
}
@@ -5505,17 +5844,25 @@ int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
** be moved to the allocated page (unless the allocated page happens
** to reside at pgnoRoot).
*/
- rc = allocatePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, 1);
+ rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, 1);
if( rc!=SQLITE_OK ){
return rc;
}
if( pgnoMove!=pgnoRoot ){
+ /* pgnoRoot is the page that will be used for the root-page of
+ ** the new table (assuming an error did not occur). But we were
+ ** allocated pgnoMove. If required (i.e. if it was not allocated
+ ** by extending the file), the current page at position pgnoMove
+ ** is already journaled.
+ */
u8 eType;
Pgno iPtrPage;
releasePage(pPageMove);
- rc = getPage(pBt, pgnoRoot, &pRoot);
+
+ /* Move the page currently at pgnoRoot to pgnoMove. */
+ rc = sqlite3BtreeGetPage(pBt, pgnoRoot, &pRoot, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -5526,21 +5873,23 @@ int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
}
assert( eType!=PTRMAP_ROOTPAGE );
assert( eType!=PTRMAP_FREEPAGE );
- rc = sqlite3pager_write(pRoot->aData);
+ rc = sqlite3PagerWrite(pRoot->pDbPage);
if( rc!=SQLITE_OK ){
releasePage(pRoot);
return rc;
}
rc = relocatePage(pBt, pRoot, eType, iPtrPage, pgnoMove);
releasePage(pRoot);
+
+ /* Obtain the page at pgnoRoot */
if( rc!=SQLITE_OK ){
return rc;
}
- rc = getPage(pBt, pgnoRoot, &pRoot);
+ rc = sqlite3BtreeGetPage(pBt, pgnoRoot, &pRoot, 0);
if( rc!=SQLITE_OK ){
return rc;
}
- rc = sqlite3pager_write(pRoot->aData);
+ rc = sqlite3PagerWrite(pRoot->pDbPage);
if( rc!=SQLITE_OK ){
releasePage(pRoot);
return rc;
@@ -5562,16 +5911,24 @@ int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
}
}else{
- rc = allocatePage(pBt, &pRoot, &pgnoRoot, 1, 0);
+ rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0);
if( rc ) return rc;
}
#endif
- assert( sqlite3pager_iswriteable(pRoot->aData) );
+ assert( sqlite3PagerIswriteable(pRoot->pDbPage) );
zeroPage(pRoot, flags | PTF_LEAF);
- sqlite3pager_unref(pRoot->aData);
+ sqlite3PagerUnref(pRoot->pDbPage);
*piTable = (int)pgnoRoot;
return SQLITE_OK;
}
+int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
+ int rc;
+ sqlite3BtreeEnter(p);
+ p->pBt->db = p->db;
+ rc = btreeCreateTable(p, piTable, flags);
+ sqlite3BtreeLeave(p);
+ return rc;
+}
/*
** Erase the given database page and all its children. Return
@@ -5588,14 +5945,13 @@ static int clearDatabasePage(
unsigned char *pCell;
int i;
- if( pgno>sqlite3pager_pagecount(pBt->pPager) ){
+ assert( sqlite3_mutex_held(pBt->mutex) );
+ if( pgno>sqlite3PagerPagecount(pBt->pPager) ){
return SQLITE_CORRUPT_BKPT;
}
rc = getAndInitPage(pBt, pgno, &pPage, pParent);
if( rc ) goto cleardatabasepage_out;
- rc = sqlite3pager_write(pPage->aData);
- if( rc ) goto cleardatabasepage_out;
for(i=0; i<pPage->nCell; i++){
pCell = findCell(pPage, i);
if( !pPage->leaf ){
@@ -5611,7 +5967,7 @@ static int clearDatabasePage(
}
if( freePageFlag ){
rc = freePage(pPage);
- }else{
+ }else if( (rc = sqlite3PagerWrite(pPage->pDbPage))==0 ){
zeroPage(pPage, pPage->aData[0] | PTF_LEAF);
}
@@ -5631,33 +5987,20 @@ cleardatabasepage_out:
*/
int sqlite3BtreeClearTable(Btree *p, int iTable){
int rc;
- BtCursor *pCur;
BtShared *pBt = p->pBt;
- sqlite3 *db = p->pSqlite;
+ sqlite3BtreeEnter(p);
+ pBt->db = p->db;
if( p->inTrans!=TRANS_WRITE ){
- return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
- }
-
- /* 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);
- }
- }
- }
-
- /* Save the position of all cursors open on this table */
- if( SQLITE_OK!=(rc = saveAllCursors(pBt, iTable, 0)) ){
- return rc;
+ rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+ }else if( (rc = checkReadLocks(p, iTable, 0))!=SQLITE_OK ){
+ /* nothing to do */
+ }else if( SQLITE_OK!=(rc = saveAllCursors(pBt, iTable, 0)) ){
+ /* nothing to do */
+ }else{
+ rc = clearDatabasePage(pBt, (Pgno)iTable, 0, 0);
}
-
- return clearDatabasePage(pBt, (Pgno)iTable, 0, 0);
+ sqlite3BtreeLeave(p);
+ return rc;
}
/*
@@ -5680,11 +6023,12 @@ int sqlite3BtreeClearTable(Btree *p, 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 *p, int iTable, int *piMoved){
+static int btreeDropTable(Btree *p, int iTable, int *piMoved){
int rc;
MemPage *pPage = 0;
BtShared *pBt = p->pBt;
+ assert( sqlite3BtreeHoldsMutex(p) );
if( p->inTrans!=TRANS_WRITE ){
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}
@@ -5699,7 +6043,7 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
return SQLITE_LOCKED;
}
- rc = getPage(pBt, (Pgno)iTable, &pPage);
+ rc = sqlite3BtreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
if( rc ) return rc;
rc = sqlite3BtreeClearTable(p, iTable);
if( rc ){
@@ -5738,7 +6082,7 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
*/
MemPage *pMove;
releasePage(pPage);
- rc = getPage(pBt, maxRootPgno, &pMove);
+ rc = sqlite3BtreeGetPage(pBt, maxRootPgno, &pMove, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -5747,7 +6091,7 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
if( rc!=SQLITE_OK ){
return rc;
}
- rc = getPage(pBt, maxRootPgno, &pMove);
+ rc = sqlite3BtreeGetPage(pBt, maxRootPgno, &pMove, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -5786,6 +6130,14 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
}
return rc;
}
+int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
+ int rc;
+ sqlite3BtreeEnter(p);
+ p->pBt->db = p->db;
+ rc = btreeDropTable(p, iTable, piMoved);
+ sqlite3BtreeLeave(p);
+ return rc;
+}
/*
@@ -5799,10 +6151,14 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
** free pages is not visible. So Cookie[0] is the same as Meta[1].
*/
int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
+ DbPage *pDbPage;
int rc;
unsigned char *pP1;
BtShared *pBt = p->pBt;
+ sqlite3BtreeEnter(p);
+ pBt->db = p->db;
+
/* 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
@@ -5810,14 +6166,19 @@ int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
*/
rc = queryTableLock(p, 1, READ_LOCK);
if( rc!=SQLITE_OK ){
+ sqlite3BtreeLeave(p);
return rc;
}
assert( idx>=0 && idx<=15 );
- rc = sqlite3pager_get(pBt->pPager, 1, (void**)&pP1);
- if( rc ) return rc;
+ rc = sqlite3PagerGet(pBt->pPager, 1, &pDbPage);
+ if( rc ){
+ sqlite3BtreeLeave(p);
+ return rc;
+ }
+ pP1 = (unsigned char *)sqlite3PagerGetData(pDbPage);
*pMeta = get4byte(&pP1[36 + idx*4]);
- sqlite3pager_unref(pP1);
+ sqlite3PagerUnref(pDbPage);
/* If autovacuumed is disabled in this build but we are trying to
** access an autovacuumed database, then make the database readonly.
@@ -5828,6 +6189,7 @@ int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
/* Grab the read-lock on page 1. */
rc = lockTable(p, 1, READ_LOCK);
+ sqlite3BtreeLeave(p);
return rc;
}
@@ -5840,15 +6202,27 @@ int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){
unsigned char *pP1;
int rc;
assert( idx>=1 && idx<=15 );
+ sqlite3BtreeEnter(p);
+ pBt->db = p->db;
if( p->inTrans!=TRANS_WRITE ){
- return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+ rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+ }else{
+ assert( pBt->pPage1!=0 );
+ pP1 = pBt->pPage1->aData;
+ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
+ if( rc==SQLITE_OK ){
+ put4byte(&pP1[36 + idx*4], iMeta);
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( idx==7 ){
+ assert( pBt->autoVacuum || iMeta==0 );
+ assert( iMeta==0 || iMeta==1 );
+ pBt->incrVacuum = iMeta;
+ }
+#endif
+ }
}
- assert( pBt->pPage1!=0 );
- pP1 = pBt->pPage1->aData;
- rc = sqlite3pager_write(pP1);
- if( rc ) return rc;
- put4byte(&pP1[36 + idx*4], iMeta);
- return SQLITE_OK;
+ sqlite3BtreeLeave(p);
+ return rc;
}
/*
@@ -5859,185 +6233,14 @@ 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;
-}
-
-#ifdef SQLITE_DEBUG
-/*
-** Print a disassembly of the given page on standard output. This routine
-** is used for debugging and testing only.
-*/
-static int btreePageDump(BtShared *pBt, int pgno, int recursive, MemPage *pParent){
- int rc;
MemPage *pPage;
- int i, j, c;
- int nFree;
- u16 idx;
- int hdr;
- int nCell;
- int isInit;
- unsigned char *data;
- char range[20];
- unsigned char payload[20];
-
- rc = getPage(pBt, (Pgno)pgno, &pPage);
- isInit = pPage->isInit;
- if( pPage->isInit==0 ){
- initPage(pPage, pParent);
- }
- if( rc ){
- return rc;
- }
- hdr = pPage->hdrOffset;
- data = pPage->aData;
- c = data[hdr];
- pPage->intKey = (c & (PTF_INTKEY|PTF_LEAFDATA))!=0;
- pPage->zeroData = (c & PTF_ZERODATA)!=0;
- pPage->leafData = (c & PTF_LEAFDATA)!=0;
- pPage->leaf = (c & PTF_LEAF)!=0;
- pPage->hasData = !(pPage->zeroData || (!pPage->leaf && pPage->leafData));
- nCell = get2byte(&data[hdr+3]);
- sqlite3DebugPrintf("PAGE %d: flags=0x%02x frag=%d parent=%d\n", pgno,
- data[hdr], data[hdr+7],
- (pPage->isInit && pPage->pParent) ? pPage->pParent->pgno : 0);
- assert( hdr == (pgno==1 ? 100 : 0) );
- idx = hdr + 12 - pPage->leaf*4;
- for(i=0; i<nCell; i++){
- CellInfo info;
- Pgno child;
- unsigned char *pCell;
- int sz;
- int addr;
-
- addr = get2byte(&data[idx + 2*i]);
- pCell = &data[addr];
- parseCellPtr(pPage, pCell, &info);
- sz = info.nSize;
- sprintf(range,"%d..%d", addr, addr+sz-1);
- if( pPage->leaf ){
- child = 0;
- }else{
- child = get4byte(pCell);
- }
- sz = info.nData;
- if( !pPage->intKey ) sz += info.nKey;
- if( sz>sizeof(payload)-1 ) sz = sizeof(payload)-1;
- memcpy(payload, &pCell[info.nHeader], sz);
- for(j=0; j<sz; j++){
- if( payload[j]<0x20 || payload[j]>0x7f ) payload[j] = '.';
- }
- payload[sz] = 0;
- sqlite3DebugPrintf(
- "cell %2d: i=%-10s chld=%-4d nk=%-4lld nd=%-4d payload=%s\n",
- i, range, child, info.nKey, info.nData, payload
- );
- }
- if( !pPage->leaf ){
- sqlite3DebugPrintf("right_child: %d\n", get4byte(&data[hdr+8]));
- }
- nFree = 0;
- i = 0;
- idx = get2byte(&data[hdr+1]);
- while( idx>0 && idx<pPage->pBt->usableSize ){
- int sz = get2byte(&data[idx+2]);
- sprintf(range,"%d..%d", idx, idx+sz-1);
- nFree += sz;
- sqlite3DebugPrintf("freeblock %2d: i=%-10s size=%-4d total=%d\n",
- i, range, sz, nFree);
- idx = get2byte(&data[idx]);
- i++;
- }
- if( idx!=0 ){
- sqlite3DebugPrintf("ERROR: next freeblock index out of range: %d\n", idx);
- }
- if( recursive && !pPage->leaf ){
- for(i=0; i<nCell; i++){
- unsigned char *pCell = findCell(pPage, i);
- btreePageDump(pBt, get4byte(pCell), 1, pPage);
- idx = get2byte(pCell);
- }
- btreePageDump(pBt, get4byte(&data[hdr+8]), 1, pPage);
- }
- pPage->isInit = isInit;
- sqlite3pager_unref(data);
- fflush(stdout);
- return SQLITE_OK;
-}
-int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){
- return btreePageDump(p->pBt, pgno, recursive, 0);
+ restoreOrClearCursorPosition(pCur);
+ pPage = pCur->pPage;
+ assert( cursorHoldsMutex(pCur) );
+ assert( pPage->pBt==pCur->pBt );
+ return pPage ? pPage->aData[pPage->hdrOffset] : 0;
}
-#endif
-
-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
-/*
-** Fill aResult[] with information about the entry and page that the
-** cursor is pointing to.
-**
-** aResult[0] = The page number
-** aResult[1] = The entry number
-** aResult[2] = Total number of entries on this page
-** aResult[3] = Cell size (local payload + header)
-** aResult[4] = Number of free bytes on this page
-** aResult[5] = Number of free blocks on the page
-** aResult[6] = Total payload size (local + overflow)
-** aResult[7] = Header size in bytes
-** aResult[8] = Local payload size
-** aResult[9] = Parent page number
-**
-** This routine is used for testing and debugging only.
-*/
-int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){
- int cnt, idx;
- 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);
- while( upCnt-- ){
- moveToParent(&tmpCur);
- }
- pPage = tmpCur.pPage;
- pageIntegrity(pPage);
- aResult[0] = sqlite3pager_pagenumber(pPage->aData);
- assert( aResult[0]==pPage->pgno );
- aResult[1] = tmpCur.idx;
- aResult[2] = pPage->nCell;
- if( tmpCur.idx>=0 && tmpCur.idx<pPage->nCell ){
- getCellInfo(&tmpCur);
- aResult[3] = tmpCur.info.nSize;
- aResult[6] = tmpCur.info.nData;
- aResult[7] = tmpCur.info.nHeader;
- aResult[8] = tmpCur.info.nLocal;
- }else{
- aResult[3] = 0;
- aResult[6] = 0;
- aResult[7] = 0;
- aResult[8] = 0;
- }
- aResult[4] = pPage->nFree;
- cnt = 0;
- idx = get2byte(&pPage->aData[pPage->hdrOffset+1]);
- while( idx>0 && idx<pPage->pBt->usableSize ){
- cnt++;
- idx = get2byte(&pPage->aData[idx]);
- }
- aResult[5] = cnt;
- if( pPage->pParent==0 || isRootPage(pPage) ){
- aResult[9] = 0;
- }else{
- aResult[9] = pPage->pParent->pgno;
- }
- releaseTempCursor(&tmpCur);
- return SQLITE_OK;
-}
-#endif
/*
** Return the pager associated with a BTree. This routine is used for
@@ -6047,19 +6250,6 @@ Pager *sqlite3BtreePager(Btree *p){
return p->pBt->pPager;
}
-/*
-** This structure is passed around through all the sanity checking routines
-** in order to keep track of some global state information.
-*/
-typedef struct IntegrityCk IntegrityCk;
-struct IntegrityCk {
- 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 */
- char *zErrMsg; /* An error message. NULL of no errors seen. */
-};
-
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
/*
** Append a message to the error message string.
@@ -6072,19 +6262,22 @@ static void checkAppendMsg(
){
va_list ap;
char *zMsg2;
+ if( !pCheck->mxErr ) return;
+ pCheck->mxErr--;
+ pCheck->nErr++;
va_start(ap, zFormat);
- zMsg2 = sqlite3VMPrintf(zFormat, ap);
+ zMsg2 = sqlite3VMPrintf(0, zFormat, ap);
va_end(ap);
if( zMsg1==0 ) zMsg1 = "";
if( pCheck->zErrMsg ){
char *zOld = pCheck->zErrMsg;
pCheck->zErrMsg = 0;
sqlite3SetString(&pCheck->zErrMsg, zOld, "\n", zMsg1, zMsg2, (char*)0);
- sqliteFree(zOld);
+ sqlite3_free(zOld);
}else{
sqlite3SetString(&pCheck->zErrMsg, zMsg1, zMsg2, (char*)0);
}
- sqliteFree(zMsg2);
+ sqlite3_free(zMsg2);
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -6155,8 +6348,9 @@ static void checkList(
int i;
int expected = N;
int iFirst = iPage;
- while( N-- > 0 ){
- unsigned char *pOvfl;
+ while( N-- > 0 && pCheck->mxErr ){
+ DbPage *pOvflPage;
+ unsigned char *pOvflData;
if( iPage<1 ){
checkAppendMsg(pCheck, zContext,
"%d of %d pages missing from overflow list starting at %d",
@@ -6164,12 +6358,13 @@ static void checkList(
break;
}
if( checkRef(pCheck, iPage, zContext) ) break;
- if( sqlite3pager_get(pCheck->pPager, (Pgno)iPage, (void**)&pOvfl) ){
+ if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage) ){
checkAppendMsg(pCheck, zContext, "failed to get page %d", iPage);
break;
}
+ pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage);
if( isFreeList ){
- int n = get4byte(&pOvfl[4]);
+ int n = get4byte(&pOvflData[4]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pCheck->pBt->autoVacuum ){
checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0, zContext);
@@ -6181,7 +6376,7 @@ static void checkList(
N--;
}else{
for(i=0; i<n; i++){
- Pgno iFreePage = get4byte(&pOvfl[8+i*4]);
+ Pgno iFreePage = get4byte(&pOvflData[8+i*4]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pCheck->pBt->autoVacuum ){
checkPtrmap(pCheck, iFreePage, PTRMAP_FREEPAGE, 0, zContext);
@@ -6199,13 +6394,13 @@ static void checkList(
** the following page matches iPage.
*/
if( pCheck->pBt->autoVacuum && N>0 ){
- i = get4byte(pOvfl);
+ i = get4byte(pOvflData);
checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage, zContext);
}
}
#endif
- iPage = get4byte(pOvfl);
- sqlite3pager_unref(pOvfl);
+ iPage = get4byte(pOvflData);
+ sqlite3PagerUnref(pOvflPage);
}
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -6245,7 +6440,7 @@ static int checkTreePage(
char zContext[100];
char *hit;
- sprintf(zContext, "Page %d: ", iPage);
+ sqlite3_snprintf(sizeof(zContext), zContext, "Page %d: ", iPage);
/* Check that the page exists
*/
@@ -6253,13 +6448,14 @@ static int checkTreePage(
usableSize = pBt->usableSize;
if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage, zParentContext) ) return 0;
- if( (rc = getPage(pBt, (Pgno)iPage, &pPage))!=0 ){
+ if( (rc = sqlite3BtreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
checkAppendMsg(pCheck, zContext,
"unable to get the page. error code=%d", rc);
return 0;
}
- if( (rc = initPage(pPage, pParent))!=0 ){
- checkAppendMsg(pCheck, zContext, "initPage() returns error code %d", rc);
+ if( (rc = sqlite3BtreeInitPage(pPage, pParent))!=0 ){
+ checkAppendMsg(pCheck, zContext,
+ "sqlite3BtreeInitPage() returns error code %d", rc);
releasePage(pPage);
return 0;
}
@@ -6267,18 +6463,20 @@ static int checkTreePage(
/* Check out all the cells.
*/
depth = 0;
- for(i=0; i<pPage->nCell; i++){
+ for(i=0; i<pPage->nCell && pCheck->mxErr; i++){
u8 *pCell;
int sz;
CellInfo info;
/* Check payload overflow pages
*/
- sprintf(zContext, "On tree page %d cell %d: ", iPage, i);
+ sqlite3_snprintf(sizeof(zContext), zContext,
+ "On tree page %d cell %d: ", iPage, i);
pCell = findCell(pPage,i);
- parseCellPtr(pPage, pCell, &info);
+ sqlite3BtreeParseCellPtr(pPage, pCell, &info);
sz = info.nData;
if( !pPage->intKey ) sz += info.nKey;
+ assert( sz==info.nPayload );
if( sz>info.nLocal ){
int nPage = (sz - info.nLocal + usableSize - 5)/(usableSize - 4);
Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]);
@@ -6308,7 +6506,8 @@ static int checkTreePage(
}
if( !pPage->leaf ){
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
- sprintf(zContext, "On page %d at right child: ", iPage);
+ sqlite3_snprintf(sizeof(zContext), zContext,
+ "On page %d at right child: ", iPage);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, 0);
@@ -6321,7 +6520,7 @@ static int checkTreePage(
*/
data = pPage->aData;
hdr = pPage->hdrOffset;
- hit = sqliteMalloc( usableSize );
+ hit = sqlite3MallocZero( usableSize );
if( hit ){
memset(hit, 1, get2byte(&data[hdr+5]));
nCell = get2byte(&data[hdr+3]);
@@ -6364,7 +6563,7 @@ static int checkTreePage(
cnt, data[hdr+7], iPage);
}
}
- sqliteFree(hit);
+ sqlite3_free(hit);
releasePage(pPage);
return depth+1;
@@ -6382,27 +6581,47 @@ 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 *p, int *aRoot, int nRoot){
+char *sqlite3BtreeIntegrityCheck(
+ Btree *p, /* The btree to be checked */
+ int *aRoot, /* An array of root pages numbers for individual trees */
+ int nRoot, /* Number of entries in aRoot[] */
+ int mxErr, /* Stop reporting errors after this many */
+ int *pnErr /* Write number of errors seen to this variable */
+){
int i;
int nRef;
IntegrityCk sCheck;
BtShared *pBt = p->pBt;
- nRef = sqlite3pager_refcount(pBt->pPager);
+ sqlite3BtreeEnter(p);
+ pBt->db = p->db;
+ nRef = sqlite3PagerRefcount(pBt->pPager);
if( lockBtreeWithRetry(p)!=SQLITE_OK ){
- return sqliteStrDup("Unable to acquire a read lock on the database");
+ sqlite3BtreeLeave(p);
+ return sqlite3StrDup("Unable to acquire a read lock on the database");
}
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
- sCheck.nPage = sqlite3pager_pagecount(sCheck.pPager);
+ sCheck.nPage = sqlite3PagerPagecount(sCheck.pPager);
+ sCheck.mxErr = mxErr;
+ sCheck.nErr = 0;
+ *pnErr = 0;
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( pBt->nTrunc!=0 ){
+ sCheck.nPage = pBt->nTrunc;
+ }
+#endif
if( sCheck.nPage==0 ){
unlockBtreeIfUnused(pBt);
+ sqlite3BtreeLeave(p);
return 0;
}
- sCheck.anRef = sqliteMallocRaw( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) );
+ sCheck.anRef = sqlite3_malloc( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) );
if( !sCheck.anRef ){
unlockBtreeIfUnused(pBt);
- return sqlite3MPrintf("Unable to malloc %d bytes",
+ *pnErr = 1;
+ sqlite3BtreeLeave(p);
+ return sqlite3MPrintf(p->db, "Unable to malloc %d bytes",
(sCheck.nPage+1)*sizeof(sCheck.anRef[0]));
}
for(i=0; i<=sCheck.nPage; i++){ sCheck.anRef[i] = 0; }
@@ -6419,7 +6638,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
/* Check all the tables.
*/
- for(i=0; i<nRoot; i++){
+ for(i=0; i<nRoot && sCheck.mxErr; i++){
if( aRoot[i]==0 ) continue;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum && aRoot[i]>1 ){
@@ -6431,7 +6650,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
/* Make sure every page in the file is referenced
*/
- for(i=1; i<=sCheck.nPage; i++){
+ for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
#ifdef SQLITE_OMIT_AUTOVACUUM
if( sCheck.anRef[i]==0 ){
checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
@@ -6454,44 +6673,55 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
/* Make sure this analysis did not leave any unref() pages
*/
unlockBtreeIfUnused(pBt);
- if( nRef != sqlite3pager_refcount(pBt->pPager) ){
+ if( nRef != sqlite3PagerRefcount(pBt->pPager) ){
checkAppendMsg(&sCheck, 0,
"Outstanding page count goes from %d to %d during this analysis",
- nRef, sqlite3pager_refcount(pBt->pPager)
+ nRef, sqlite3PagerRefcount(pBt->pPager)
);
}
/* Clean up and report errors.
*/
- sqliteFree(sCheck.anRef);
+ sqlite3BtreeLeave(p);
+ sqlite3_free(sCheck.anRef);
+ *pnErr = sCheck.nErr;
return sCheck.zErrMsg;
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
/*
** Return the full pathname of the underlying database file.
+**
+** The pager filename is invariant as long as the pager is
+** open so it is safe to access without the BtShared mutex.
*/
const char *sqlite3BtreeGetFilename(Btree *p){
assert( p->pBt->pPager!=0 );
- return sqlite3pager_filename(p->pBt->pPager);
+ return sqlite3PagerFilename(p->pBt->pPager);
}
/*
** Return the pathname of the directory that contains the database file.
+**
+** The pager directory name is invariant as long as the pager is
+** open so it is safe to access without the BtShared mutex.
*/
const char *sqlite3BtreeGetDirname(Btree *p){
assert( p->pBt->pPager!=0 );
- return sqlite3pager_dirname(p->pBt->pPager);
+ return sqlite3PagerDirname(p->pBt->pPager);
}
/*
** Return the pathname of the journal file for this database. The return
** value of this routine is the same regardless of whether the journal file
** has been created or not.
+**
+** The pager journal filename is invariant as long as the pager is
+** open so it is safe to access without the BtShared mutex.
*/
const char *sqlite3BtreeGetJournalname(Btree *p){
assert( p->pBt->pPager!=0 );
- return sqlite3pager_journalname(p->pBt->pPager);
+ return sqlite3PagerJournalname(p->pBt->pPager);
}
#ifndef SQLITE_OMIT_VACUUM
@@ -6502,52 +6732,78 @@ const char *sqlite3BtreeGetJournalname(Btree *p){
** 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 *pTo, Btree *pFrom){
+static int btreeCopyFile(Btree *pTo, Btree *pFrom){
int rc = SQLITE_OK;
Pgno i, nPage, nToPage, iSkip;
BtShared *pBtTo = pTo->pBt;
BtShared *pBtFrom = pFrom->pBt;
+ pBtTo->db = pTo->db;
+ pBtFrom->db = pFrom->db;
+
if( pTo->inTrans!=TRANS_WRITE || pFrom->inTrans!=TRANS_WRITE ){
return SQLITE_ERROR;
}
if( pBtTo->pCursor ) return SQLITE_BUSY;
- nToPage = sqlite3pager_pagecount(pBtTo->pPager);
- nPage = sqlite3pager_pagecount(pBtFrom->pPager);
+ nToPage = sqlite3PagerPagecount(pBtTo->pPager);
+ nPage = sqlite3PagerPagecount(pBtFrom->pPager);
iSkip = PENDING_BYTE_PAGE(pBtTo);
for(i=1; rc==SQLITE_OK && i<=nPage; i++){
- void *pPage;
+ DbPage *pDbPage;
if( i==iSkip ) continue;
- rc = sqlite3pager_get(pBtFrom->pPager, i, &pPage);
+ rc = sqlite3PagerGet(pBtFrom->pPager, i, &pDbPage);
if( rc ) break;
- rc = sqlite3pager_overwrite(pBtTo->pPager, i, pPage);
- if( rc ) break;
- sqlite3pager_unref(pPage);
+ rc = sqlite3PagerOverwrite(pBtTo->pPager, i, sqlite3PagerGetData(pDbPage));
+ sqlite3PagerUnref(pDbPage);
}
+
+ /* If the file is shrinking, journal the pages that are being truncated
+ ** so that they can be rolled back if the commit fails.
+ */
for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){
- void *pPage;
+ DbPage *pDbPage;
if( i==iSkip ) continue;
- rc = sqlite3pager_get(pBtTo->pPager, i, &pPage);
+ rc = sqlite3PagerGet(pBtTo->pPager, i, &pDbPage);
if( rc ) break;
- rc = sqlite3pager_write(pPage);
- sqlite3pager_unref(pPage);
- sqlite3pager_dont_write(pBtTo->pPager, i);
+ rc = sqlite3PagerWrite(pDbPage);
+ sqlite3PagerDontWrite(pDbPage);
+ /* Yeah. It seems wierd to call DontWrite() right after Write(). But
+ ** that is because the names of those procedures do not exactly
+ ** represent what they do. Write() really means "put this page in the
+ ** rollback journal and mark it as dirty so that it will be written
+ ** to the database file later." DontWrite() undoes the second part of
+ ** that and prevents the page from being written to the database. The
+ ** page is still on the rollback journal, though. And that is the whole
+ ** point of this loop: to put pages on the rollback journal. */
+ sqlite3PagerUnref(pDbPage);
}
if( !rc && nPage<nToPage ){
- rc = sqlite3pager_truncate(pBtTo->pPager, nPage);
+ rc = sqlite3PagerTruncate(pBtTo->pPager, nPage);
}
+
if( rc ){
sqlite3BtreeRollback(pTo);
}
return rc;
}
+int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
+ int rc;
+ sqlite3BtreeEnter(pTo);
+ sqlite3BtreeEnter(pFrom);
+ rc = btreeCopyFile(pTo, pFrom);
+ sqlite3BtreeLeave(pFrom);
+ sqlite3BtreeLeave(pTo);
+ return rc;
+}
+
#endif /* SQLITE_OMIT_VACUUM */
/*
** Return non-zero if a transaction is active.
*/
int sqlite3BtreeIsInTrans(Btree *p){
+ assert( p==0 || sqlite3_mutex_held(p->db->mutex) );
return (p && (p->inTrans==TRANS_WRITE));
}
@@ -6555,6 +6811,7 @@ int sqlite3BtreeIsInTrans(Btree *p){
** Return non-zero if a statement transaction is active.
*/
int sqlite3BtreeIsInStmt(Btree *p){
+ assert( sqlite3BtreeHoldsMutex(p) );
return (p->pBt && p->pBt->inStmt);
}
@@ -6562,44 +6819,13 @@ int sqlite3BtreeIsInStmt(Btree *p){
** Return non-zero if a read (or write) transaction is active.
*/
int sqlite3BtreeIsInReadTrans(Btree *p){
+ assert( sqlite3_mutex_held(p->db->mutex) );
return (p && (p->inTrans!=TRANS_NONE));
}
/*
-** This call is a no-op if no write-transaction is currently active on pBt.
-**
-** Otherwise, sync the database file for the btree pBt. zMaster points to
-** the name of a master journal file that should be written into the
-** individual journal file, or is NULL, indicating no master journal file
-** (single database transaction).
-**
-** When this is called, the master journal should already have been
-** created, populated with this journal pointer and synced to disk.
-**
-** 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 *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 ){
- rc = autoVacuumCommit(pBt, &nTrunc);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- }
-#endif
- rc = sqlite3pager_sync(pBt->pPager, zMaster, nTrunc);
- }
- 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
+** a single shared-btree. The memory is used by client code for its own
** purposes (for example, to store a high-level schema associated with
** the shared-btree). The btree layer manages reference counting issues.
**
@@ -6610,15 +6836,17 @@ int sqlite3BtreeSync(Btree *p, const char *zMaster){
**
** 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()
+** blob of allocated memory. This function should not call sqlite3_free()
** on the memory, the btree layer does that.
*/
void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){
BtShared *pBt = p->pBt;
+ sqlite3BtreeEnter(p);
if( !pBt->pSchema ){
- pBt->pSchema = sqliteMalloc(nBytes);
+ pBt->pSchema = sqlite3MallocZero(nBytes);
pBt->xFreeSchema = xFree;
}
+ sqlite3BtreeLeave(p);
return pBt->pSchema;
}
@@ -6627,7 +6855,12 @@ void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){
** handle holds an exclusive lock on the sqlite_master table.
*/
int sqlite3BtreeSchemaLocked(Btree *p){
- return (queryTableLock(p, MASTER_ROOT, READ_LOCK)!=SQLITE_OK);
+ int rc;
+ assert( sqlite3_mutex_held(p->db->mutex) );
+ sqlite3BtreeEnter(p);
+ rc = (queryTableLock(p, MASTER_ROOT, READ_LOCK)!=SQLITE_OK);
+ sqlite3BtreeLeave(p);
+ return rc;
}
@@ -6640,40 +6873,71 @@ int sqlite3BtreeSchemaLocked(Btree *p){
int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){
int rc = SQLITE_OK;
u8 lockType = (isWriteLock?WRITE_LOCK:READ_LOCK);
+ sqlite3BtreeEnter(p);
rc = queryTableLock(p, iTab, lockType);
if( rc==SQLITE_OK ){
rc = lockTable(p, iTab, lockType);
}
+ sqlite3BtreeLeave(p);
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));
+#ifndef SQLITE_OMIT_INCRBLOB
+/*
+** Argument pCsr must be a cursor opened for writing on an
+** INTKEY table currently pointing at a valid table entry.
+** This function modifies the data stored as part of that entry.
+** Only the data content may only be modified, it is not possible
+** to change the length of the data stored.
+*/
+int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
+ assert( cursorHoldsMutex(pCsr) );
+ assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
+ assert(pCsr->isIncrblobHandle);
+ if( pCsr->eState>=CURSOR_REQUIRESEEK ){
+ if( pCsr->eState==CURSOR_FAULT ){
+ return pCsr->skip;
+ }else{
+ return SQLITE_ABORT;
}
- Tcl_SetObjResult(interp, pRet);
}
-#endif
- return TCL_OK;
+
+ /* Check some preconditions:
+ ** (a) the cursor is open for writing,
+ ** (b) there is no read-lock on the table being modified and
+ ** (c) the cursor points at a valid row of an intKey table.
+ */
+ if( !pCsr->wrFlag ){
+ return SQLITE_READONLY;
+ }
+ assert( !pCsr->pBt->readOnly
+ && pCsr->pBt->inTransaction==TRANS_WRITE );
+ if( checkReadLocks(pCsr->pBtree, pCsr->pgnoRoot, pCsr) ){
+ return SQLITE_LOCKED; /* The table pCur points to has a read lock */
+ }
+ if( pCsr->eState==CURSOR_INVALID || !pCsr->pPage->intKey ){
+ return SQLITE_ERROR;
+ }
+
+ return accessPayload(pCsr, offset, amt, (unsigned char *)z, 0, 1);
+}
+
+/*
+** Set a flag on this cursor to cache the locations of pages from the
+** overflow list for the current row. This is used by cursors opened
+** for incremental blob IO only.
+**
+** This function sets a flag only. The actual page location cache
+** (stored in BtCursor.aOverflow[]) is allocated and used by function
+** accessPayload() (the worker function for sqlite3BtreeData() and
+** sqlite3BtreePutData()).
+*/
+void sqlite3BtreeCacheOverflow(BtCursor *pCur){
+ assert( cursorHoldsMutex(pCur) );
+ assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
+ assert(!pCur->isIncrblobHandle);
+ assert(!pCur->aOverflow);
+ pCur->isIncrblobHandle = 1;
}
#endif
diff --git a/ext/pdo_sqlite/sqlite/src/btree.h b/ext/pdo_sqlite/sqlite/src/btree.h
index 896ebf11b1..766e250829 100644
--- a/ext/pdo_sqlite/sqlite/src/btree.h
+++ b/ext/pdo_sqlite/sqlite/src/btree.h
@@ -31,19 +31,36 @@
#define SQLITE_DEFAULT_AUTOVACUUM 0
#endif
+#define BTREE_AUTOVACUUM_NONE 0 /* Do not do auto-vacuum */
+#define BTREE_AUTOVACUUM_FULL 1 /* Do full auto-vacuum */
+#define BTREE_AUTOVACUUM_INCR 2 /* Incremental vacuum */
+
/*
** Forward declarations of structure
*/
typedef struct Btree Btree;
typedef struct BtCursor BtCursor;
typedef struct BtShared BtShared;
+typedef struct BtreeMutexArray BtreeMutexArray;
+
+/*
+** This structure records all of the Btrees that need to hold
+** a mutex before we enter sqlite3VdbeExec(). The Btrees are
+** are placed in aBtree[] in order of aBtree[]->pBt. That way,
+** we can always lock and unlock them all quickly.
+*/
+struct BtreeMutexArray {
+ int nMutex;
+ Btree *aBtree[SQLITE_MAX_ATTACHED+1];
+};
int sqlite3BtreeOpen(
const char *zFilename, /* Name of database file to open */
sqlite3 *db, /* Associated database connection */
Btree **, /* Return open Btree* here */
- int flags /* Flags */
+ int flags, /* Flags */
+ int vfsFlags /* Flags passed through to VFS open */
);
/* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the
@@ -55,18 +72,28 @@ int sqlite3BtreeOpen(
#define BTREE_OMIT_JOURNAL 1 /* Do not use journal. No argument */
#define BTREE_NO_READLOCK 2 /* Omit readlocks on readonly files */
#define BTREE_MEMORY 4 /* In-memory DB. No argument */
+#define BTREE_READONLY 8 /* Open the database in read-only mode */
+#define BTREE_READWRITE 16 /* Open for both reading and writing */
+#define BTREE_CREATE 32 /* Create the database if it does not exist */
+
+/* Additional values for the 4th argument of sqlite3BtreeOpen that
+** are not associated with PAGER_ values.
+*/
+#define BTREE_PRIVATE 64 /* Never share with other connections */
int sqlite3BtreeClose(Btree*);
-int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*);
int sqlite3BtreeSetCacheSize(Btree*,int);
int sqlite3BtreeSetSafetyLevel(Btree*,int,int);
int sqlite3BtreeSyncDisabled(Btree*);
int sqlite3BtreeSetPageSize(Btree*,int,int);
int sqlite3BtreeGetPageSize(Btree*);
+int sqlite3BtreeMaxPageCount(Btree*,int);
int sqlite3BtreeGetReserve(Btree*);
int sqlite3BtreeSetAutoVacuum(Btree *, int);
int sqlite3BtreeGetAutoVacuum(Btree *);
int sqlite3BtreeBeginTrans(Btree*,int);
+int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
+int sqlite3BtreeCommitPhaseTwo(Btree*);
int sqlite3BtreeCommit(Btree*);
int sqlite3BtreeRollback(Btree*);
int sqlite3BtreeBeginStmt(Btree*);
@@ -76,7 +103,6 @@ int sqlite3BtreeCreateTable(Btree*, int*, int flags);
int sqlite3BtreeIsInTrans(Btree*);
int sqlite3BtreeIsInStmt(Btree*);
int sqlite3BtreeIsInReadTrans(Btree*);
-int sqlite3BtreeSync(Btree*, const char *zMaster);
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
int sqlite3BtreeSchemaLocked(Btree *);
int sqlite3BtreeLockTable(Btree *, int, u8);
@@ -86,6 +112,8 @@ const char *sqlite3BtreeGetDirname(Btree *);
const char *sqlite3BtreeGetJournalname(Btree *);
int sqlite3BtreeCopyFile(Btree *, Btree *);
+int sqlite3BtreeIncrVacuum(Btree *);
+
/* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR
** of the following flags:
*/
@@ -97,6 +125,7 @@ int sqlite3BtreeDropTable(Btree*, int, int*);
int sqlite3BtreeClearTable(Btree*, int);
int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue);
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
+void sqlite3BtreeTripAllCursors(Btree*, int);
int sqlite3BtreeCursor(
Btree*, /* BTree containing table to open */
@@ -107,17 +136,12 @@ int sqlite3BtreeCursor(
BtCursor **ppCursor /* Returned cursor */
);
-void sqlite3BtreeSetCompare(
- BtCursor *,
- int(*)(void*,int,const void*,int,const void*),
- void*
-);
-
int sqlite3BtreeCloseCursor(BtCursor*);
-int sqlite3BtreeMoveto(BtCursor*, const void *pKey, i64 nKey, int *pRes);
+int sqlite3BtreeMoveto(BtCursor*,const void *pKey,i64 nKey,int bias,int *pRes);
int sqlite3BtreeDelete(BtCursor*);
int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
- const void *pData, int nData);
+ const void *pData, int nData,
+ int nZero, int bias);
int sqlite3BtreeFirst(BtCursor*, int *pRes);
int sqlite3BtreeLast(BtCursor*, int *pRes);
int sqlite3BtreeNext(BtCursor*, int *pRes);
@@ -126,24 +150,54 @@ int sqlite3BtreeFlags(BtCursor*);
int sqlite3BtreePrevious(BtCursor*, int *pRes);
int sqlite3BtreeKeySize(BtCursor*, i64 *pSize);
int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
+sqlite3 *sqlite3BtreeCursorDb(const BtCursor*);
const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt);
const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
-char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot);
+char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
struct Pager *sqlite3BtreePager(Btree*);
+int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
+void sqlite3BtreeCacheOverflow(BtCursor *);
#ifdef SQLITE_TEST
int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
void sqlite3BtreeCursorList(Btree*);
+int sqlite3BtreePageDump(Btree*, int, int recursive);
#endif
-#ifdef SQLITE_DEBUG
-int sqlite3BtreePageDump(Btree*, int, int recursive);
+/*
+** If we are not using shared cache, then there is no need to
+** use mutexes to access the BtShared structures. So make the
+** Enter and Leave procedures no-ops.
+*/
+#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
+ void sqlite3BtreeEnter(Btree*);
+ void sqlite3BtreeLeave(Btree*);
+ int sqlite3BtreeHoldsMutex(Btree*);
+ void sqlite3BtreeEnterCursor(BtCursor*);
+ void sqlite3BtreeLeaveCursor(BtCursor*);
+ void sqlite3BtreeEnterAll(sqlite3*);
+ void sqlite3BtreeLeaveAll(sqlite3*);
+ int sqlite3BtreeHoldsAllMutexes(sqlite3*);
+ void sqlite3BtreeMutexArrayEnter(BtreeMutexArray*);
+ void sqlite3BtreeMutexArrayLeave(BtreeMutexArray*);
+ void sqlite3BtreeMutexArrayInsert(BtreeMutexArray*, Btree*);
#else
-#define sqlite3BtreePageDump(X,Y,Z) SQLITE_OK
+# define sqlite3BtreeEnter(X)
+# define sqlite3BtreeLeave(X)
+# define sqlite3BtreeHoldsMutex(X) 1
+# define sqlite3BtreeEnterCursor(X)
+# define sqlite3BtreeLeaveCursor(X)
+# define sqlite3BtreeEnterAll(X)
+# define sqlite3BtreeLeaveAll(X)
+# define sqlite3BtreeHoldsAllMutexes(X) 1
+# define sqlite3BtreeMutexArrayEnter(X)
+# define sqlite3BtreeMutexArrayLeave(X)
+# define sqlite3BtreeMutexArrayInsert(X,Y)
#endif
+
#endif /* _BTREE_H_ */
diff --git a/ext/pdo_sqlite/sqlite/src/btreeInt.h b/ext/pdo_sqlite/sqlite/src/btreeInt.h
new file mode 100644
index 0000000000..d329ce5e66
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/btreeInt.h
@@ -0,0 +1,650 @@
+/*
+** 2004 April 6
+**
+** 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.
+**
+*************************************************************************
+** $Id$
+**
+** This file implements a external (disk-based) database using BTrees.
+** For a detailed discussion of BTrees, refer to
+**
+** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
+** "Sorting And Searching", pages 473-480. Addison-Wesley
+** Publishing Company, Reading, Massachusetts.
+**
+** The basic idea is that each page of the file contains N database
+** entries and N+1 pointers to subpages.
+**
+** ----------------------------------------------------------------
+** | Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) |
+** ----------------------------------------------------------------
+**
+** All of the keys on the page that Ptr(0) points to have values less
+** than Key(0). All of the keys on page Ptr(1) and its subpages have
+** values greater than Key(0) and less than Key(1). All of the keys
+** on Ptr(N) and its subpages have values greater than Key(N-1). And
+** so forth.
+**
+** Finding a particular key requires reading O(log(M)) pages from the
+** disk where M is the number of entries in the tree.
+**
+** In this implementation, a single file can hold one or more separate
+** BTrees. Each BTree is identified by the index of its root page. The
+** key and data for any entry are combined to form the "payload". A
+** fixed amount of payload can be carried directly on the database
+** page. If the payload is larger than the preset amount then surplus
+** bytes are stored on overflow pages. The payload for an entry
+** and the preceding pointer are combined to form a "Cell". Each
+** page has a small header which contains the Ptr(N) pointer and other
+** information such as the size of key and data.
+**
+** FORMAT DETAILS
+**
+** The file is divided into pages. The first page is called page 1,
+** the second is page 2, and so forth. A page number of zero indicates
+** "no such page". The page size can be anything between 512 and 65536.
+** Each page can be either a btree page, a freelist page or an overflow
+** page.
+**
+** The first page is always a btree page. The first 100 bytes of the first
+** page contain a special header (the "file header") that describes the file.
+** The format of the file header is as follows:
+**
+** OFFSET SIZE DESCRIPTION
+** 0 16 Header string: "SQLite format 3\000"
+** 16 2 Page size in bytes.
+** 18 1 File format write version
+** 19 1 File format read version
+** 20 1 Bytes of unused space at the end of each page
+** 21 1 Max embedded payload fraction
+** 22 1 Min embedded payload fraction
+** 23 1 Min leaf payload fraction
+** 24 4 File change counter
+** 28 4 Reserved for future use
+** 32 4 First freelist page
+** 36 4 Number of freelist pages in the file
+** 40 60 15 4-byte meta values passed to higher layers
+**
+** All of the integer values are big-endian (most significant byte first).
+**
+** The file change counter is incremented when the database is changed
+** This counter allows other processes to know when the file has changed
+** and thus when they need to flush their cache.
+**
+** The max embedded payload fraction is the amount of the total usable
+** space in a page that can be consumed by a single cell for standard
+** B-tree (non-LEAFDATA) tables. A value of 255 means 100%. The default
+** is to limit the maximum cell size so that at least 4 cells will fit
+** on one page. Thus the default max embedded payload fraction is 64.
+**
+** If the payload for a cell is larger than the max payload, then extra
+** payload is spilled to overflow pages. Once an overflow page is allocated,
+** as many bytes as possible are moved into the overflow pages without letting
+** the cell size drop below the min embedded payload fraction.
+**
+** The min leaf payload fraction is like the min embedded payload fraction
+** except that it applies to leaf nodes in a LEAFDATA tree. The maximum
+** payload fraction for a LEAFDATA tree is always 100% (or 255) and it
+** not specified in the header.
+**
+** Each btree pages is divided into three sections: The header, the
+** cell pointer array, and the cell content area. Page 1 also has a 100-byte
+** file header that occurs before the page header.
+**
+** |----------------|
+** | file header | 100 bytes. Page 1 only.
+** |----------------|
+** | page header | 8 bytes for leaves. 12 bytes for interior nodes
+** |----------------|
+** | cell pointer | | 2 bytes per cell. Sorted order.
+** | array | | Grows downward
+** | | v
+** |----------------|
+** | unallocated |
+** | space |
+** |----------------| ^ Grows upwards
+** | cell content | | Arbitrary order interspersed with freeblocks.
+** | area | | and free space fragments.
+** |----------------|
+**
+** The page headers looks like this:
+**
+** OFFSET SIZE DESCRIPTION
+** 0 1 Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf
+** 1 2 byte offset to the first freeblock
+** 3 2 number of cells on this page
+** 5 2 first byte of the cell content area
+** 7 1 number of fragmented free bytes
+** 8 4 Right child (the Ptr(N) value). Omitted on leaves.
+**
+** The flags define the format of this btree page. The leaf flag means that
+** this page has no children. The zerodata flag means that this page carries
+** only keys and no data. The intkey flag means that the key is a integer
+** which is stored in the key size entry of the cell header rather than in
+** the payload area.
+**
+** The cell pointer array begins on the first byte after the page header.
+** The cell pointer array contains zero or more 2-byte numbers which are
+** offsets from the beginning of the page to the cell content in the cell
+** content area. The cell pointers occur in sorted order. The system strives
+** to keep free space after the last cell pointer so that new cells can
+** be easily added without having to defragment the page.
+**
+** Cell content is stored at the very end of the page and grows toward the
+** beginning of the page.
+**
+** Unused space within the cell content area is collected into a linked list of
+** freeblocks. Each freeblock is at least 4 bytes in size. The byte offset
+** to the first freeblock is given in the header. Freeblocks occur in
+** increasing order. Because a freeblock must be at least 4 bytes in size,
+** any group of 3 or fewer unused bytes in the cell content area cannot
+** exist on the freeblock chain. A group of 3 or fewer free bytes is called
+** a fragment. The total number of bytes in all fragments is recorded.
+** in the page header at offset 7.
+**
+** SIZE DESCRIPTION
+** 2 Byte offset of the next freeblock
+** 2 Bytes in this freeblock
+**
+** Cells are of variable length. Cells are stored in the cell content area at
+** the end of the page. Pointers to the cells are in the cell pointer array
+** that immediately follows the page header. Cells is not necessarily
+** contiguous or in order, but cell pointers are contiguous and in order.
+**
+** Cell content makes use of variable length integers. A variable
+** length integer is 1 to 9 bytes where the lower 7 bits of each
+** byte are used. The integer consists of all bytes that have bit 8 set and
+** the first byte with bit 8 clear. The most significant byte of the integer
+** appears first. A variable-length integer may not be more than 9 bytes long.
+** As a special case, all 8 bytes of the 9th byte are used as data. This
+** allows a 64-bit integer to be encoded in 9 bytes.
+**
+** 0x00 becomes 0x00000000
+** 0x7f becomes 0x0000007f
+** 0x81 0x00 becomes 0x00000080
+** 0x82 0x00 becomes 0x00000100
+** 0x80 0x7f becomes 0x0000007f
+** 0x8a 0x91 0xd1 0xac 0x78 becomes 0x12345678
+** 0x81 0x81 0x81 0x81 0x01 becomes 0x10204081
+**
+** Variable length integers are used for rowids and to hold the number of
+** bytes of key and data in a btree cell.
+**
+** The content of a cell looks like this:
+**
+** SIZE DESCRIPTION
+** 4 Page number of the left child. Omitted if leaf flag is set.
+** var Number of bytes of data. Omitted if the zerodata flag is set.
+** var Number of bytes of key. Or the key itself if intkey flag is set.
+** * Payload
+** 4 First page of the overflow chain. Omitted if no overflow
+**
+** Overflow pages form a linked list. Each page except the last is completely
+** filled with data (pagesize - 4 bytes). The last page can have as little
+** as 1 byte of data.
+**
+** SIZE DESCRIPTION
+** 4 Page number of next overflow page
+** * Data
+**
+** Freelist pages come in two subtypes: trunk pages and leaf pages. The
+** file header points to the first in a linked list of trunk page. Each trunk
+** page points to multiple leaf pages. The content of a leaf page is
+** unspecified. A trunk page looks like this:
+**
+** SIZE DESCRIPTION
+** 4 Page number of next trunk page
+** 4 Number of leaf pointers on this page
+** * zero or more pages numbers of leaves
+*/
+#include "sqliteInt.h"
+#include "pager.h"
+#include "btree.h"
+#include "os.h"
+#include <assert.h>
+
+/* Round up a number to the next larger multiple of 8. This is used
+** to force 8-byte alignment on 64-bit architectures.
+*/
+#define ROUND8(x) ((x+7)&~7)
+
+
+/* The following value is the maximum cell size assuming a maximum page
+** size give above.
+*/
+#define MX_CELL_SIZE(pBt) (pBt->pageSize-8)
+
+/* The maximum number of cells on a single page of the database. This
+** assumes a minimum cell size of 3 bytes. Such small cells will be
+** exceedingly rare, but they are possible.
+*/
+#define MX_CELL(pBt) ((pBt->pageSize-8)/3)
+
+/* Forward declarations */
+typedef struct MemPage MemPage;
+typedef struct BtLock BtLock;
+
+/*
+** This is a magic string that appears at the beginning of every
+** SQLite database in order to identify the file as a real database.
+**
+** You can change this value at compile-time by specifying a
+** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The
+** header must be exactly 16 bytes including the zero-terminator so
+** the string itself should be 15 characters long. If you change
+** the header, then your custom library will not be able to read
+** databases generated by the standard tools and the standard tools
+** will not be able to read databases created by your custom library.
+*/
+#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
+# define SQLITE_FILE_HEADER "SQLite format 3"
+#endif
+
+/*
+** Page type flags. An ORed combination of these flags appear as the
+** first byte of on-disk image of every BTree page.
+*/
+#define PTF_INTKEY 0x01
+#define PTF_ZERODATA 0x02
+#define PTF_LEAFDATA 0x04
+#define PTF_LEAF 0x08
+
+/*
+** As each page of the file is loaded into memory, an instance of the following
+** structure is appended and initialized to zero. This structure stores
+** information about the page that is decoded from the raw file page.
+**
+** The pParent field points back to the parent page. This allows us to
+** walk up the BTree from any leaf to the root. Care must be taken to
+** unref() the parent page pointer when this page is no longer referenced.
+** The pageDestructor() routine handles that chore.
+**
+** Access to all fields of this structure is controlled by the mutex
+** stored in MemPage.pBt->mutex.
+*/
+struct MemPage {
+ u8 isInit; /* True if previously initialized. MUST BE FIRST! */
+ u8 idxShift; /* True if Cell indices have changed */
+ u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
+ u8 intKey; /* True if intkey flag is set */
+ u8 leaf; /* True if leaf flag is set */
+ u8 zeroData; /* True if table stores keys only */
+ u8 leafData; /* True if tables stores data on leaves only */
+ u8 hasData; /* True if this page stores data */
+ u8 hdrOffset; /* 100 for page 1. 0 otherwise */
+ u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
+ u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
+ u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */
+ u16 cellOffset; /* Index in aData of first cell pointer */
+ u16 idxParent; /* Index in parent of this node */
+ 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 */
+ } aOvfl[5];
+ BtShared *pBt; /* Pointer to BtShared that this page is part of */
+ u8 *aData; /* Pointer to disk image of the page data */
+ DbPage *pDbPage; /* Pager page handle */
+ Pgno pgno; /* Page number for this page */
+ MemPage *pParent; /* The parent of this page. NULL for root */
+};
+
+/*
+** The in-memory image of a disk page has the auxiliary information appended
+** to the end. EXTRA_SIZE is the number of bytes of space needed to hold
+** that extra information.
+*/
+#define EXTRA_SIZE sizeof(MemPage)
+
+/* A Btree handle
+**
+** A database connection contains a pointer to an instance of
+** this object for every database file that it has open. This structure
+** is opaque to the database connection. The database connection cannot
+** see the internals of this structure and only deals with pointers to
+** this structure.
+**
+** For some database files, the same underlying database cache might be
+** shared between multiple connections. In that case, each contection
+** has it own pointer to this object. But each instance of this object
+** points to the same BtShared object. The database cache and the
+** schema associated with the database file are all contained within
+** the BtShared object.
+**
+** All fields in this structure are accessed under sqlite3.mutex.
+** The pBt pointer itself may not be changed while there exists cursors
+** in the referenced BtShared that point back to this Btree since those
+** cursors have to do go through this Btree to find their BtShared and
+** they often do so without holding sqlite3.mutex.
+*/
+struct Btree {
+ sqlite3 *db; /* The database connection holding this btree */
+ BtShared *pBt; /* Sharable content of this btree */
+ u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
+ u8 sharable; /* True if we can share pBt with another db */
+ u8 locked; /* True if db currently has pBt locked */
+ int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
+ Btree *pNext; /* List of other sharable Btrees from the same db */
+ Btree *pPrev; /* Back pointer of the same list */
+};
+
+/*
+** 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.
+*/
+#define TRANS_NONE 0
+#define TRANS_READ 1
+#define TRANS_WRITE 2
+
+/*
+** An instance of this object represents a single database file.
+**
+** A single database file can be in use as the same time by two
+** or more database connections. When two or more connections are
+** sharing the same database file, each connection has it own
+** private Btree object for the file and each of those Btrees points
+** to this one BtShared object. BtShared.nRef is the number of
+** connections currently sharing this database file.
+**
+** Fields in this structure are accessed under the BtShared.mutex
+** mutex, except for nRef and pNext which are accessed under the
+** global SQLITE_MUTEX_STATIC_MASTER mutex. The pPager field
+** may not be modified once it is initially set as long as nRef>0.
+** The pSchema field may be set once under BtShared.mutex and
+** thereafter is unchanged as long as nRef>0.
+*/
+struct BtShared {
+ Pager *pPager; /* The page cache */
+ sqlite3 *db; /* Database connection currently using this Btree */
+ BtCursor *pCursor; /* A list of all open cursors */
+ MemPage *pPage1; /* First page of the database */
+ 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 */
+ u8 minEmbedFrac; /* Minimum payload as % of total page size */
+ u8 minLeafFrac; /* Minimum leaf payload as % of total page size */
+ u8 pageSizeFixed; /* True if the page size can no longer be changed */
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ u8 autoVacuum; /* True if auto-vacuum is enabled */
+ u8 incrVacuum; /* True if incr-vacuum is enabled */
+ Pgno nTrunc; /* Non-zero if the db will be truncated (incr vacuum) */
+#endif
+ u16 pageSize; /* Total number of bytes on a page */
+ u16 usableSize; /* Number of usable bytes on each page */
+ int maxLocal; /* Maximum local payload in non-LEAFDATA tables */
+ int minLocal; /* Minimum local payload in non-LEAFDATA tables */
+ int maxLeaf; /* Maximum local payload in a LEAFDATA table */
+ int minLeaf; /* Minimum local payload in a LEAFDATA table */
+ u8 inTransaction; /* Transaction state */
+ int nTransaction; /* Number of open transactions (read + write) */
+ void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */
+ void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */
+ sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */
+ BusyHandler busyHdr; /* The busy handler for this btree */
+#ifndef SQLITE_OMIT_SHARED_CACHE
+ int nRef; /* Number of references to this structure */
+ BtShared *pNext; /* Next on a list of sharable BtShared structs */
+ BtLock *pLock; /* List of locks held on this shared-btree struct */
+ Btree *pExclusive; /* Btree with an EXCLUSIVE lock on the whole db */
+#endif
+};
+
+/*
+** An instance of the following structure is used to hold information
+** about a cell. The parseCellPtr() function fills in this structure
+** based on information extract from the raw disk page.
+*/
+typedef struct CellInfo CellInfo;
+struct CellInfo {
+ u8 *pCell; /* Pointer to the start of cell content */
+ i64 nKey; /* The key for INTKEY tables, or number of bytes in key */
+ u32 nData; /* Number of bytes of data */
+ u32 nPayload; /* Total amount of payload */
+ u16 nHeader; /* Size of the cell content header in bytes */
+ u16 nLocal; /* Amount of payload held locally */
+ u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */
+ u16 nSize; /* Size of the cell content on the main b-tree page */
+};
+
+/*
+** A cursor is a pointer to a particular entry within a particular
+** b-tree within a database file.
+**
+** The entry is identified by its MemPage and the index in
+** MemPage.aCell[] of the entry.
+**
+** When a single database file can shared by two more database connections,
+** but cursors cannot be shared. Each cursor is associated with a
+** particular database connection identified BtCursor.pBtree.db.
+**
+** Fields in this structure are accessed under the BtShared.mutex
+** found at self->pBt->mutex.
+*/
+struct BtCursor {
+ Btree *pBtree; /* The Btree to which this cursor belongs */
+ BtShared *pBt; /* The BtShared this cursor points to */
+ 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() */
+ Pgno pgnoRoot; /* The root page of this tree */
+ MemPage *pPage; /* Page that contains the entry */
+ 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 eState; /* One of the CURSOR_XXX constants (see below) */
+ void *pKey; /* Saved key that was cursor's last known position */
+ i64 nKey; /* Size of pKey, or last integer key */
+ int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */
+#ifndef SQLITE_OMIT_INCRBLOB
+ u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
+ Pgno *aOverflow; /* Cache of overflow page locations */
+#endif
+};
+
+/*
+** Potential values for BtCursor.eState.
+**
+** 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.
+**
+** CURSOR_FAULT:
+** A unrecoverable error (an I/O error or a malloc failure) has occurred
+** on a different connection that shares the BtShared cache with this
+** cursor. The error has left the cache in an inconsistent state.
+** Do nothing else with this cursor. Any attempt to use the cursor
+** should return the error code stored in BtCursor.skip
+*/
+#define CURSOR_INVALID 0
+#define CURSOR_VALID 1
+#define CURSOR_REQUIRESEEK 2
+#define CURSOR_FAULT 3
+
+/*
+** The TRACE macro will print high-level status information about the
+** btree operation when the global variable sqlite3_btree_trace is
+** enabled.
+*/
+#if SQLITE_TEST
+# define TRACE(X) if( sqlite3_btree_trace ){ printf X; fflush(stdout); }
+#else
+# define TRACE(X)
+#endif
+
+/*
+** Routines to read and write variable-length integers. These used to
+** be defined locally, but now we use the varint routines in the util.c
+** file.
+*/
+#define getVarint sqlite3GetVarint
+#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
+
+/*
+** These macros define the location of the pointer-map entry for a
+** database page. The first argument to each is the number of usable
+** bytes on each page of the database (often 1024). The second is the
+** page number to look up in the pointer map.
+**
+** PTRMAP_PAGENO returns the database page number of the pointer-map
+** page that stores the required pointer. PTRMAP_PTROFFSET returns
+** the offset of the requested map entry.
+**
+** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page,
+** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
+** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
+** this test.
+*/
+#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))
+
+/*
+** The pointer map is a lookup table that identifies the parent page for
+** each child page in the database file. The parent page is the page that
+** contains a pointer to the child. Every page in the database contains
+** 0 or 1 parent pages. (In this context 'database page' refers
+** to any page that is not part of the pointer map itself.) Each pointer map
+** entry consists of a single byte 'type' and a 4 byte parent page number.
+** The PTRMAP_XXX identifiers below are the valid types.
+**
+** The purpose of the pointer map is to facility moving pages from one
+** position in the file to another as part of autovacuum. When a page
+** is moved, the pointer in its parent must be updated to point to the
+** new location. The pointer map is used to locate the parent page quickly.
+**
+** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not
+** used in this case.
+**
+** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number
+** is not used in this case.
+**
+** PTRMAP_OVERFLOW1: The database page is the first page in a list of
+** overflow pages. The page number identifies the page that
+** contains the cell with a pointer to this overflow page.
+**
+** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of
+** overflow pages. The page-number identifies the previous
+** page in the overflow page list.
+**
+** PTRMAP_BTREE: The database page is a non-root btree page. The page number
+** identifies the parent page in the btree.
+*/
+#define PTRMAP_ROOTPAGE 1
+#define PTRMAP_FREEPAGE 2
+#define PTRMAP_OVERFLOW1 3
+#define PTRMAP_OVERFLOW2 4
+#define PTRMAP_BTREE 5
+
+/* A bunch of assert() statements to check the transaction state variables
+** of handle p (type Btree*) are internally consistent.
+*/
+#define btreeIntegrity(p) \
+ assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
+ assert( p->pBt->inTransaction>=p->inTrans );
+
+
+/*
+** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
+** if the database supports auto-vacuum or not. Because it is used
+** within an expression that is an argument to another macro
+** (sqliteMallocRaw), it is not possible to use conditional compilation.
+** So, this macro is defined instead.
+*/
+#ifndef SQLITE_OMIT_AUTOVACUUM
+#define ISAUTOVACUUM (pBt->autoVacuum)
+#else
+#define ISAUTOVACUUM 0
+#endif
+
+
+/*
+** This structure is passed around through all the sanity checking routines
+** in order to keep track of some global state information.
+*/
+typedef struct IntegrityCk IntegrityCk;
+struct IntegrityCk {
+ 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 */
+ int mxErr; /* Stop accumulating errors when this reaches zero */
+ char *zErrMsg; /* An error message. NULL if no errors seen. */
+ int nErr; /* Number of messages written to zErrMsg so far */
+};
+
+/*
+** Read or write a two- and four-byte big-endian integer values.
+*/
+#define get2byte(x) ((x)[0]<<8 | (x)[1])
+#define put2byte(p,v) ((p)[0] = (v)>>8, (p)[1] = (v))
+#define get4byte sqlite3Get4byte
+#define put4byte sqlite3Put4byte
+
+/*
+** Internal routines that should be accessed by the btree layer only.
+*/
+int sqlite3BtreeGetPage(BtShared*, Pgno, MemPage**, int);
+int sqlite3BtreeInitPage(MemPage *pPage, MemPage *pParent);
+void sqlite3BtreeParseCellPtr(MemPage*, u8*, CellInfo*);
+void sqlite3BtreeParseCell(MemPage*, int, CellInfo*);
+#ifdef SQLITE_TEST
+u8 *sqlite3BtreeFindCell(MemPage *pPage, int iCell);
+#endif
+int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur);
+void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur);
+void sqlite3BtreeReleaseTempCursor(BtCursor *pCur);
+int sqlite3BtreeIsRootPage(MemPage *pPage);
+void sqlite3BtreeMoveToParent(BtCursor *pCur);
diff --git a/ext/pdo_sqlite/sqlite/src/build.c b/ext/pdo_sqlite/sqlite/src/build.c
index 5294c1a316..6ee1cd0e07 100644
--- a/ext/pdo_sqlite/sqlite/src/build.c
+++ b/ext/pdo_sqlite/sqlite/src/build.c
@@ -69,7 +69,7 @@ void sqlite3TableLock(
int nBytes;
TableLock *p;
- if( 0==sqlite3ThreadDataReadOnly()->useSharedData || iDb<0 ){
+ if( iDb<0 ){
return;
}
@@ -82,13 +82,17 @@ void sqlite3TableLock(
}
nBytes = sizeof(TableLock) * (pParse->nTableLock+1);
- sqliteReallocOrFree((void **)&pParse->aTableLock, nBytes);
+ pParse->aTableLock =
+ sqlite3DbReallocOrFree(pParse->db, pParse->aTableLock, nBytes);
if( pParse->aTableLock ){
p = &pParse->aTableLock[pParse->nTableLock++];
p->iDb = iDb;
p->iTab = iTab;
p->isWriteLock = isWriteLock;
p->zName = zName;
+ }else{
+ pParse->nTableLock = 0;
+ pParse->db->mallocFailed = 1;
}
}
@@ -99,7 +103,6 @@ void sqlite3TableLock(
static void codeTableLocks(Parse *pParse){
int i;
Vdbe *pVdbe;
- assert( sqlite3ThreadDataReadOnly()->useSharedData || pParse->nTableLock==0 );
if( 0==(pVdbe = sqlite3GetVdbe(pParse)) ){
return;
@@ -111,7 +114,7 @@ static void codeTableLocks(Parse *pParse){
if( p->isWriteLock ){
p1 = -1*(p1+1);
}
- sqlite3VdbeOp3(pVdbe, OP_TableLock, p1, p->iTab, p->zName, P3_STATIC);
+ sqlite3VdbeAddOp4(pVdbe, OP_TableLock, p1, p->iTab, 0, p->zName, P4_STATIC);
}
}
#else
@@ -132,8 +135,10 @@ void sqlite3FinishCoding(Parse *pParse){
sqlite3 *db;
Vdbe *v;
- if( sqlite3MallocFailed() ) return;
+ db = pParse->db;
+ if( db->mallocFailed ) return;
if( pParse->nested ) return;
+ if( pParse->nErr ) return;
if( !pParse->pVdbe ){
if( pParse->rc==SQLITE_OK && pParse->nErr ){
pParse->rc = SQLITE_ERROR;
@@ -144,10 +149,9 @@ void sqlite3FinishCoding(Parse *pParse){
/* Begin by generating some termination code at the end of the
** vdbe program
*/
- db = pParse->db;
v = sqlite3GetVdbe(pParse);
if( v ){
- sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
+ sqlite3VdbeAddOp0(v, OP_Halt);
/* The cookie mask contains one bit for each database file open.
** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are
@@ -161,13 +165,14 @@ void sqlite3FinishCoding(Parse *pParse){
sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
if( (mask & pParse->cookieMask)==0 ) continue;
- sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
- sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
+ sqlite3VdbeUsesBtree(v, iDb);
+ sqlite3VdbeAddOp2(v,OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
+ sqlite3VdbeAddOp2(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);
+ sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
}
#endif
@@ -176,26 +181,30 @@ void sqlite3FinishCoding(Parse *pParse){
** shared-cache feature is enabled.
*/
codeTableLocks(pParse);
- sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->cookieGoto);
}
#ifndef SQLITE_OMIT_TRACE
- /* Add a No-op that contains the complete text of the compiled SQL
- ** statement as its P3 argument. This does not change the functionality
- ** of the program.
- **
- ** This is used to implement sqlite3_trace().
- */
- sqlite3VdbeOp3(v, OP_Noop, 0, 0, pParse->zSql, pParse->zTail-pParse->zSql);
+ if( !db->init.busy ){
+ /* Change the P4 argument of the first opcode (which will always be
+ ** an OP_Trace) to be the complete text of the current SQL statement.
+ */
+ VdbeOp *pOp = sqlite3VdbeGetOp(v, 0);
+ if( pOp && pOp->opcode==OP_Trace ){
+ sqlite3VdbeChangeP4(v, 0, pParse->zSql, pParse->zTail-pParse->zSql);
+ }
+ }
#endif /* SQLITE_OMIT_TRACE */
}
/* Get the VDBE program ready for execution
*/
- if( v && pParse->nErr==0 && !sqlite3MallocFailed() ){
+ if( v && pParse->nErr==0 && !db->mallocFailed ){
+#ifdef SQLITE_DEBUG
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
sqlite3VdbeTrace(v, trace);
+#endif
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3,
pParse->nTab+3, pParse->explain);
pParse->rc = SQLITE_DONE;
@@ -232,16 +241,17 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
if( pParse->nErr ) return;
assert( pParse->nested<10 ); /* Nesting should only be of limited depth */
va_start(ap, zFormat);
- zSql = sqlite3VMPrintf(zFormat, ap);
+ zSql = sqlite3VMPrintf(pParse->db, zFormat, ap);
va_end(ap);
if( zSql==0 ){
+ pParse->db->mallocFailed = 1;
return; /* A malloc must have failed */
}
pParse->nested++;
memcpy(saveBuf, &pParse->nVar, SAVE_SZ);
memset(&pParse->nVar, 0, SAVE_SZ);
sqlite3RunParser(pParse, zSql, 0);
- sqliteFree(zSql);
+ sqlite3_free(zSql);
memcpy(&pParse->nVar, saveBuf, SAVE_SZ);
pParse->nested--;
}
@@ -281,7 +291,12 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
** routine leaves an error message in pParse->zErrMsg where
** sqlite3FindTable() does not.
*/
-Table *sqlite3LocateTable(Parse *pParse, const char *zName, const char *zDbase){
+Table *sqlite3LocateTable(
+ Parse *pParse, /* context in which to report errors */
+ int isView, /* True if looking for a VIEW rather than a TABLE */
+ const char *zName, /* Name of the table we are looking for */
+ const char *zDbase /* Name of the database. Might be NULL */
+){
Table *p;
/* Read the database schema. If an error occurs, leave an error message
@@ -292,10 +307,11 @@ Table *sqlite3LocateTable(Parse *pParse, const char *zName, const char *zDbase){
p = sqlite3FindTable(pParse->db, zName, zDbase);
if( p==0 ){
+ const char *zMsg = isView ? "no such view" : "no such table";
if( zDbase ){
- sqlite3ErrorMsg(pParse, "no such table: %s.%s", zDbase, zName);
+ sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
}else{
- sqlite3ErrorMsg(pParse, "no such table: %s", zName);
+ sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
}
pParse->checkSchema = 1;
}
@@ -334,8 +350,8 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
** Reclaim the memory used by an index
*/
static void freeIndex(Index *p){
- sqliteFree(p->zColAff);
- sqliteFree(p);
+ sqlite3_free(p->zColAff);
+ sqlite3_free(p);
}
/*
@@ -396,17 +412,22 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
*/
void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
int i, j;
-
assert( iDb>=0 && iDb<db->nDb );
+
+ if( iDb==0 ){
+ sqlite3BtreeEnterAll(db);
+ }
for(i=iDb; i<db->nDb; i++){
Db *pDb = &db->aDb[i];
if( pDb->pSchema ){
+ assert(i==1 || (pDb->pBt && sqlite3BtreeHoldsMutex(pDb->pBt)));
sqlite3SchemaFree(pDb->pSchema);
}
if( iDb>0 ) return;
}
assert( iDb==0 );
db->flags &= ~SQLITE_InternChanges;
+ sqlite3BtreeLeaveAll(db);
/* If one or more of the auxiliary database files has been closed,
** then remove them from the auxiliary database list. We take the
@@ -424,7 +445,7 @@ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
for(i=j=2; i<db->nDb; i++){
struct Db *pDb = &db->aDb[i];
if( pDb->pBt==0 ){
- sqliteFree(pDb->zName);
+ sqlite3_free(pDb->zName);
pDb->zName = 0;
continue;
}
@@ -437,23 +458,12 @@ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
db->nDb = j;
if( db->nDb<=2 && db->aDb!=db->aDbStatic ){
memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0]));
- sqliteFree(db->aDb);
+ sqlite3_free(db->aDb);
db->aDb = db->aDbStatic;
}
}
/*
-** This routine is called whenever a rollback occurs. If there were
-** schema changes during the transaction, then we have to reset the
-** internal hash tables and reload them from disk.
-*/
-void sqlite3RollbackInternalChanges(sqlite3 *db){
- if( db->flags & SQLITE_InternChanges ){
- sqlite3ResetInternalSchema(db, 0);
- }
-}
-
-/*
** This routine is called when a commit occurs.
*/
void sqlite3CommitInternalChanges(sqlite3 *db){
@@ -469,12 +479,12 @@ static void sqliteResetColumnNames(Table *pTable){
assert( pTable!=0 );
if( (pCol = pTable->aCol)!=0 ){
for(i=0; i<pTable->nCol; i++, pCol++){
- sqliteFree(pCol->zName);
+ sqlite3_free(pCol->zName);
sqlite3ExprDelete(pCol->pDflt);
- sqliteFree(pCol->zType);
- sqliteFree(pCol->zColl);
+ sqlite3_free(pCol->zType);
+ sqlite3_free(pCol->zColl);
}
- sqliteFree(pTable->aCol);
+ sqlite3_free(pTable->aCol);
}
pTable->aCol = 0;
pTable->nCol = 0;
@@ -489,18 +499,11 @@ static void sqliteResetColumnNames(Table *pTable){
** foreign keys from the sqlite.aFKey hash table. But it does destroy
** memory structures of the indices and foreign keys associated with
** the table.
-**
-** Indices associated with the table are unlinked from the "db"
-** data structure if db!=NULL. If db==NULL, indices attached to
-** the table are deleted, but it is assumed they have already been
-** unlinked.
*/
-void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
+void sqlite3DeleteTable(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. */
@@ -520,27 +523,27 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
#ifndef SQLITE_OMIT_FOREIGN_KEY
/* Delete all foreign keys associated with this table. The keys
- ** should have already been unlinked from the db->aFKey hash table
+ ** should have already been unlinked from the pSchema->aFKey hash table
*/
for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){
pNextFKey = pFKey->pNextFrom;
assert( sqlite3HashFind(&pTable->pSchema->aFKey,
pFKey->zTo, strlen(pFKey->zTo)+1)!=pFKey );
- sqliteFree(pFKey);
+ sqlite3_free(pFKey);
}
#endif
/* Delete the Table structure itself.
*/
sqliteResetColumnNames(pTable);
- sqliteFree(pTable->zName);
- sqliteFree(pTable->zColAff);
+ sqlite3_free(pTable->zName);
+ sqlite3_free(pTable->zColAff);
sqlite3SelectDelete(pTable->pSelect);
#ifndef SQLITE_OMIT_CHECK
sqlite3ExprDelete(pTable->pCheck);
#endif
sqlite3VtabClear(pTable);
- sqliteFree(pTable);
+ sqlite3_free(pTable);
}
/*
@@ -572,7 +575,7 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
}
}
#endif
- sqlite3DeleteTable(db, p);
+ sqlite3DeleteTable(p);
}
db->flags |= SQLITE_InternChanges;
}
@@ -587,10 +590,10 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
** are not \000 terminated and are not persistent. The returned string
** is \000 terminated and is persistent.
*/
-char *sqlite3NameFromToken(Token *pName){
+char *sqlite3NameFromToken(sqlite3 *db, Token *pName){
char *zName;
if( pName ){
- zName = sqliteStrNDup((char*)pName->z, pName->n);
+ zName = sqlite3DbStrNDup(db, (char*)pName->z, pName->n);
sqlite3Dequote(zName);
}else{
zName = 0;
@@ -605,9 +608,8 @@ char *sqlite3NameFromToken(Token *pName){
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 */
+ sqlite3VdbeAddOp3(v, OP_OpenWrite, 0, MASTER_ROOT, iDb);
+ sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, 5); /* sqlite_master has 5 columns */
}
/*
@@ -622,7 +624,7 @@ int sqlite3FindDb(sqlite3 *db, Token *pName){
Db *pDb; /* A database whose name space is being searched */
char *zName; /* Name we are searching for */
- zName = sqlite3NameFromToken(pName);
+ zName = sqlite3NameFromToken(db, pName);
if( zName ){
n = strlen(zName);
for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){
@@ -631,7 +633,7 @@ int sqlite3FindDb(sqlite3 *db, Token *pName){
break;
}
}
- sqliteFree(zName);
+ sqlite3_free(zName);
}
return i;
}
@@ -754,7 +756,7 @@ void sqlite3StartTable(
if( !OMIT_TEMPDB && isTemp ) iDb = 1;
pParse->sNameToken = *pName;
- zName = sqlite3NameFromToken(pName);
+ zName = sqlite3NameFromToken(db, pName);
if( zName==0 ) return;
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
goto begin_table_error;
@@ -811,8 +813,9 @@ void sqlite3StartTable(
}
}
- pTable = sqliteMalloc( sizeof(Table) );
+ pTable = sqlite3DbMallocZero(db, sizeof(Table));
if( pTable==0 ){
+ db->mallocFailed = 1;
pParse->rc = SQLITE_NOMEM;
pParse->nErr++;
goto begin_table_error;
@@ -821,7 +824,7 @@ void sqlite3StartTable(
pTable->iPKey = -1;
pTable->pSchema = db->aDb[iDb].pSchema;
pTable->nRef = 1;
- if( pParse->pNewTable ) sqlite3DeleteTable(db, pParse->pNewTable);
+ if( pParse->pNewTable ) sqlite3DeleteTable(pParse->pNewTable);
pParse->pNewTable = pTable;
/* If this is the magic sqlite_sequence table used by autoincrement,
@@ -843,29 +846,33 @@ void sqlite3StartTable(
** now.
*/
if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){
- int lbl;
+ int j1;
int fileFormat;
+ int reg1, reg2, reg3;
sqlite3BeginWriteOperation(pParse, 0, iDb);
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( isVirtual ){
- sqlite3VdbeAddOp(v, OP_VBegin, 0, 0);
+ sqlite3VdbeAddOp0(v, OP_VBegin);
}
#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);
+ reg1 = pParse->regRowid = ++pParse->nMem;
+ reg2 = pParse->regRoot = ++pParse->nMem;
+ reg3 = ++pParse->nMem;
+ sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, 1); /* file_format */
+ sqlite3VdbeUsesBtree(v, iDb);
+ j1 = sqlite3VdbeAddOp1(v, OP_If, reg3);
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, ENC(db), 0);
- sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 4);
- sqlite3VdbeResolveLabel(v, lbl);
+ sqlite3VdbeAddOp2(v, OP_Integer, fileFormat, reg3);
+ sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, 1, reg3);
+ sqlite3VdbeAddOp2(v, OP_Integer, ENC(db), reg3);
+ sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, 4, reg3);
+ sqlite3VdbeJumpHere(v, j1);
/* This just creates a place-holder record in the sqlite_master table.
** The record created does not contain anything yet. It will be replaced
@@ -877,19 +884,18 @@ void sqlite3StartTable(
*/
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
if( isView || isVirtual ){
- sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, reg2);
}else
#endif
{
- sqlite3VdbeAddOp(v, OP_CreateTable, iDb, 0);
+ sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2);
}
sqlite3OpenMasterTable(pParse, iDb);
- sqlite3VdbeAddOp(v, OP_NewRowid, 0, 0);
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- sqlite3VdbeAddOp(v, OP_Null, 0, 0);
- sqlite3VdbeAddOp(v, OP_Insert, 0, 0);
- sqlite3VdbeAddOp(v, OP_Close, 0, 0);
- sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
+ sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, reg3);
+ sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1);
+ sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
+ sqlite3VdbeAddOp0(v, OP_Close);
}
/* Normal (non-error) return. */
@@ -897,7 +903,7 @@ void sqlite3StartTable(
/* If an error occurs, we jump here */
begin_table_error:
- sqliteFree(zName);
+ sqlite3_free(zName);
return;
}
@@ -928,20 +934,24 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){
char *z;
Column *pCol;
if( (p = pParse->pNewTable)==0 ) return;
- z = sqlite3NameFromToken(pName);
+ if( p->nCol+1>SQLITE_MAX_COLUMN ){
+ sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName);
+ return;
+ }
+ z = sqlite3NameFromToken(pParse->db, pName);
if( z==0 ) return;
for(i=0; i<p->nCol; i++){
if( STRICMP(z, p->aCol[i].zName) ){
sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
- sqliteFree(z);
+ sqlite3_free(z);
return;
}
}
if( (p->nCol & 0x7)==0 ){
Column *aNew;
- aNew = sqliteRealloc( p->aCol, (p->nCol+8)*sizeof(p->aCol[0]));
+ aNew = sqlite3DbRealloc(pParse->db,p->aCol,(p->nCol+8)*sizeof(p->aCol[0]));
if( aNew==0 ){
- sqliteFree(z);
+ sqlite3_free(z);
return;
}
p->aCol = aNew;
@@ -1053,8 +1063,8 @@ void sqlite3AddColumnType(Parse *pParse, Token *pType){
i = p->nCol-1;
if( i<0 ) return;
pCol = &p->aCol[i];
- sqliteFree(pCol->zType);
- pCol->zType = sqlite3NameFromToken(pType);
+ sqlite3_free(pCol->zType);
+ pCol->zType = sqlite3NameFromToken(pParse->db, pType);
pCol->affinity = sqlite3AffinityType(pType);
}
@@ -1077,8 +1087,13 @@ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
pCol->zName);
}else{
+ Expr *pCopy;
+ sqlite3 *db = pParse->db;
sqlite3ExprDelete(pCol->pDflt);
- pCol->pDflt = sqlite3ExprDup(pExpr);
+ pCol->pDflt = pCopy = sqlite3ExprDup(db, pExpr);
+ if( pCopy ){
+ sqlite3TokenCopy(db, &pCopy->span, &pExpr->span);
+ }
}
}
sqlite3ExprDelete(pExpr);
@@ -1167,11 +1182,13 @@ void sqlite3AddCheckConstraint(
){
#ifndef SQLITE_OMIT_CHECK
Table *pTab = pParse->pNewTable;
+ sqlite3 *db = pParse->db;
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));
+ pTab->pCheck = sqlite3ExprAnd(db, pTab->pCheck,
+ sqlite3ExprDup(db, pCheckExpr));
}
#endif
sqlite3ExprDelete(pCheckExpr);
@@ -1181,16 +1198,20 @@ void sqlite3AddCheckConstraint(
** Set the collation function of the most recently parsed table column
** to the CollSeq given.
*/
-void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){
+void sqlite3AddCollateType(Parse *pParse, Token *pToken){
Table *p;
int i;
+ char *zColl; /* Dequoted name of collation sequence */
if( (p = pParse->pNewTable)==0 ) return;
i = p->nCol-1;
- if( sqlite3LocateCollSeq(pParse, zType, nType) ){
+ zColl = sqlite3NameFromToken(pParse->db, pToken);
+ if( !zColl ) return;
+
+ if( sqlite3LocateCollSeq(pParse, zColl, -1) ){
Index *pIdx;
- p->aCol[i].zColl = sqliteStrNDup(zType, nType);
+ p->aCol[i].zColl = zColl;
/* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
** then an index may have been created on this column before the
@@ -1202,6 +1223,8 @@ void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){
pIdx->azColl[0] = p->aCol[i].zColl;
}
}
+ }else{
+ sqlite3_free(zColl);
}
}
@@ -1218,6 +1241,10 @@ void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){
** If no versions of the requested collations sequence are available, or
** another error occurs, NULL is returned and an error message written into
** pParse.
+**
+** This routine is a wrapper around sqlite3FindCollSeq(). This routine
+** invokes the collation factory if the named collation cannot be found
+** and generates an error message.
*/
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){
sqlite3 *db = pParse->db;
@@ -1257,9 +1284,13 @@ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){
** and the probability of hitting the same cookie value is only
** 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].pSchema->schema_cookie+1, 0);
- sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0);
+void sqlite3ChangeCookie(Parse *pParse, int iDb){
+ int r1 = sqlite3GetTempReg(pParse);
+ sqlite3 *db = pParse->db;
+ Vdbe *v = pParse->pVdbe;
+ sqlite3VdbeAddOp2(v, OP_Integer, db->aDb[iDb].pSchema->schema_cookie+1, r1);
+ sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, 0, r1);
+ sqlite3ReleaseTempReg(pParse, r1);
}
/*
@@ -1306,7 +1337,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, int isTemp){
+static char *createTableStmt(sqlite3 *db, Table *p, int isTemp){
int i, k, n;
char *zStmt;
char *zSep, *zSep2, *zEnd, *z;
@@ -1330,24 +1361,29 @@ static char *createTableStmt(Table *p, int isTemp){
zEnd = "\n)";
}
n += 35 + 6*p->nCol;
- zStmt = sqliteMallocRaw( n );
- if( zStmt==0 ) return 0;
- strcpy(zStmt, !OMIT_TEMPDB&&isTemp ? "CREATE TEMP TABLE ":"CREATE TABLE ");
+ zStmt = sqlite3_malloc( n );
+ if( zStmt==0 ){
+ db->mallocFailed = 1;
+ return 0;
+ }
+ sqlite3_snprintf(n, zStmt,
+ !OMIT_TEMPDB&&isTemp ? "CREATE TEMP TABLE ":"CREATE TABLE ");
k = strlen(zStmt);
identPut(zStmt, &k, p->zName);
zStmt[k++] = '(';
for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){
- strcpy(&zStmt[k], zSep);
+ sqlite3_snprintf(n-k, &zStmt[k], zSep);
k += strlen(&zStmt[k]);
zSep = zSep2;
identPut(zStmt, &k, pCol->zName);
if( (z = pCol->zType)!=0 ){
zStmt[k++] = ' ';
- strcpy(&zStmt[k], z);
+ assert( strlen(z)+k+1<=n );
+ sqlite3_snprintf(n-k, &zStmt[k], "%s", z);
k += strlen(z);
}
}
- strcpy(&zStmt[k], zEnd);
+ sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd);
return zStmt;
}
@@ -1381,7 +1417,7 @@ void sqlite3EndTable(
sqlite3 *db = pParse->db;
int iDb;
- if( (pEnd==0 && pSelect==0) || pParse->nErr || sqlite3MallocFailed() ) {
+ if( (pEnd==0 && pSelect==0) || pParse->nErr || db->mallocFailed ) {
return;
}
p = pParse->pNewTable;
@@ -1440,7 +1476,7 @@ void sqlite3EndTable(
v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
- sqlite3VdbeAddOp(v, OP_Close, 0, 0);
+ sqlite3VdbeAddOp1(v, OP_Close, 0);
/* Create the rootpage for the new table and push it onto the stack.
** A view has no rootpage, so just push a zero onto the stack for
@@ -1472,13 +1508,15 @@ void sqlite3EndTable(
** be redundant.
*/
if( pSelect ){
+ SelectDest dest;
Table *pSelTab;
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
- sqlite3VdbeAddOp(v, OP_OpenWrite, 1, 0);
+
+ sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
+ sqlite3VdbeChangeP5(v, 1);
pParse->nTab = 2;
- sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0, 0);
- sqlite3VdbeAddOp(v, OP_Close, 1, 0);
+ sqlite3SelectDestInit(&dest, SRT_Table, 1);
+ sqlite3Select(pParse, pSelect, &dest, 0, 0, 0, 0);
+ sqlite3VdbeAddOp1(v, OP_Close, 1);
if( pParse->nErr==0 ){
pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSelect);
if( pSelTab==0 ) return;
@@ -1487,16 +1525,18 @@ void sqlite3EndTable(
p->aCol = pSelTab->aCol;
pSelTab->nCol = 0;
pSelTab->aCol = 0;
- sqlite3DeleteTable(0, pSelTab);
+ sqlite3DeleteTable(pSelTab);
}
}
/* Compute the complete text of the CREATE statement */
if( pSelect ){
- zStmt = createTableStmt(p, p->pSchema==pParse->db->aDb[1].pSchema);
+ zStmt = createTableStmt(db, p, p->pSchema==db->aDb[1].pSchema);
}else{
n = pEnd->z - pParse->sNameToken.z + 1;
- zStmt = sqlite3MPrintf("CREATE %s %.*s", zType2, n, pParse->sNameToken.z);
+ zStmt = sqlite3MPrintf(db,
+ "CREATE %s %.*s", zType2, n, pParse->sNameToken.z
+ );
}
/* A slot for the record has already been allocated in the
@@ -1507,16 +1547,18 @@ void sqlite3EndTable(
*/
sqlite3NestedParse(pParse,
"UPDATE %Q.%s "
- "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#0, sql=%Q "
- "WHERE rowid=#1",
+ "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q "
+ "WHERE rowid=#%d",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
zType,
p->zName,
p->zName,
- zStmt
+ pParse->regRoot,
+ zStmt,
+ pParse->regRowid
);
- sqliteFree(zStmt);
- sqlite3ChangeCookie(db, v, iDb);
+ sqlite3_free(zStmt);
+ sqlite3ChangeCookie(pParse, iDb);
#ifndef SQLITE_OMIT_AUTOINCREMENT
/* Check to see if we need to create an sqlite_sequence table for
@@ -1534,8 +1576,8 @@ void sqlite3EndTable(
#endif
/* Reparse everything to update our internal data structures */
- sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0,
- sqlite3MPrintf("tbl_name='%q'",p->zName), P3_DYNAMIC);
+ sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0,
+ sqlite3MPrintf(db, "tbl_name='%q'",p->zName), P4_DYNAMIC);
}
@@ -1548,13 +1590,18 @@ void sqlite3EndTable(
pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, strlen(p->zName)+1,p);
if( pOld ){
assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
+ db->mallocFailed = 1;
return;
}
#ifndef SQLITE_OMIT_FOREIGN_KEY
for(pFKey=p->pFKey; pFKey; pFKey=pFKey->pNextFrom){
+ void *data;
int nTo = strlen(pFKey->zTo) + 1;
pFKey->pNextTo = sqlite3HashFind(&pSchema->aFKey, pFKey->zTo, nTo);
- sqlite3HashInsert(&pSchema->aFKey, pFKey->zTo, nTo, pFKey);
+ data = sqlite3HashInsert(&pSchema->aFKey, pFKey->zTo, nTo, pFKey);
+ if( data==(void *)pFKey ){
+ db->mallocFailed = 1;
+ }
}
#endif
pParse->pNewTable = 0;
@@ -1570,7 +1617,7 @@ void sqlite3EndTable(
pCons = pEnd;
}
nName = (const char *)pCons->z - zName;
- p->addColOffset = 13 + sqlite3utf8CharLen(zName, nName);
+ p->addColOffset = 13 + sqlite3Utf8CharLen(zName, nName);
}
#endif
}
@@ -1586,7 +1633,8 @@ void sqlite3CreateView(
Token *pName1, /* The token that holds the name of the view */
Token *pName2, /* The token that holds the name of the view */
Select *pSelect, /* A SELECT statement that will become the new view */
- int isTemp /* TRUE for a TEMPORARY view */
+ int isTemp, /* TRUE for a TEMPORARY view */
+ int noErr /* Suppress error messages if VIEW already exists */
){
Table *p;
int n;
@@ -1595,20 +1643,21 @@ void sqlite3CreateView(
DbFixer sFix;
Token *pName;
int iDb;
+ sqlite3 *db = pParse->db;
if( pParse->nVar>0 ){
sqlite3ErrorMsg(pParse, "parameters are not allowed in views");
sqlite3SelectDelete(pSelect);
return;
}
- sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, 0);
+ sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr);
p = pParse->pNewTable;
if( p==0 || pParse->nErr ){
sqlite3SelectDelete(pSelect);
return;
}
sqlite3TwoPartName(pParse, pName1, pName2, &pName);
- iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
+ iDb = sqlite3SchemaToIndex(db, p->pSchema);
if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName)
&& sqlite3FixSelect(&sFix, pSelect)
){
@@ -1621,12 +1670,12 @@ void sqlite3CreateView(
** allocated rather than point to the input string - which means that
** they will persist after the current sqlite3_exec() call returns.
*/
- p->pSelect = sqlite3SelectDup(pSelect);
+ p->pSelect = sqlite3SelectDup(db, pSelect);
sqlite3SelectDelete(pSelect);
- if( sqlite3MallocFailed() ){
+ if( db->mallocFailed ){
return;
}
- if( !pParse->db->init.busy ){
+ if( !db->init.busy ){
sqlite3ViewGetColumnNames(pParse, p);
}
@@ -1661,6 +1710,8 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
Select *pSel; /* Copy of the SELECT that implements the view */
int nErr = 0; /* Number of errors encountered */
int n; /* Temporarily holds the number of cursors assigned */
+ sqlite3 *db = pParse->db; /* Database connection for malloc errors */
+ int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
assert( pTable );
@@ -1701,12 +1752,19 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
** statement that defines the view.
*/
assert( pTable->pSelect );
- pSel = sqlite3SelectDup(pTable->pSelect);
+ pSel = sqlite3SelectDup(db, pTable->pSelect);
if( pSel ){
n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
pTable->nCol = -1;
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ xAuth = db->xAuth;
+ db->xAuth = 0;
pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel);
+ db->xAuth = xAuth;
+#else
+ pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel);
+#endif
pParse->nTab = n;
if( pSelTab ){
assert( pTable->aCol==0 );
@@ -1714,7 +1772,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
pTable->aCol = pSelTab->aCol;
pSelTab->nCol = 0;
pSelTab->aCol = 0;
- sqlite3DeleteTable(0, pSelTab);
+ sqlite3DeleteTable(pSelTab);
pTable->pSchema->flags |= DB_UnresetViews;
}else{
pTable->nCol = 0;
@@ -1795,20 +1853,22 @@ void sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){
*/
static void destroyRootPage(Parse *pParse, int iTable, int iDb){
Vdbe *v = sqlite3GetVdbe(pParse);
- sqlite3VdbeAddOp(v, OP_Destroy, iTable, iDb);
+ int r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb);
#ifndef SQLITE_OMIT_AUTOVACUUM
- /* OP_Destroy pushes an integer onto the stack. If this integer
+ /* OP_Destroy stores an in integer r1. If this integer
** is non-zero, then it is the root page number of a table moved to
** location iTable. The following code modifies the sqlite_master table to
** reflect this.
**
- ** The "#0" in the SQL is a special constant that means whatever value
+ ** The "#%d" in the SQL is a special constant that means whatever value
** is on the top of the stack. See sqlite3RegisterExpr().
*/
sqlite3NestedParse(pParse,
- "UPDATE %Q.%s SET rootpage=%d WHERE #0 AND rootpage=#0",
- pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable);
+ "UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d",
+ pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable, r1, r1);
#endif
+ sqlite3ReleaseTempReg(pParse, r1);
}
/*
@@ -1880,11 +1940,12 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
sqlite3 *db = pParse->db;
int iDb;
- if( pParse->nErr || sqlite3MallocFailed() ){
+ if( pParse->nErr || db->mallocFailed ){
goto exit_drop_table;
}
assert( pName->nSrc==1 );
- pTab = sqlite3LocateTable(pParse, pName->a[0].zName, pName->a[0].zDatabase);
+ pTab = sqlite3LocateTable(pParse, isView,
+ pName->a[0].zName, pName->a[0].zDatabase);
if( pTab==0 ){
if( noErr ){
@@ -1894,6 +1955,13 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb>=0 && iDb<db->nDb );
+
+ /* If pTab is a virtual table, call ViewGetColumnNames() to ensure
+ ** it is initialized.
+ */
+ if( IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, pTab) ){
+ goto exit_drop_table;
+ }
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code;
@@ -1911,9 +1979,6 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
}
#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
@@ -1958,13 +2023,13 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
if( v ){
Trigger *pTrigger;
Db *pDb = &db->aDb[iDb];
- sqlite3BeginWriteOperation(pParse, 0, iDb);
+ sqlite3BeginWriteOperation(pParse, 1, iDb);
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
Vdbe *v = sqlite3GetVdbe(pParse);
if( v ){
- sqlite3VdbeAddOp(v, OP_VBegin, 0, 0);
+ sqlite3VdbeAddOp0(v, OP_VBegin);
}
}
#endif
@@ -2013,10 +2078,10 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
** the schema cookie.
*/
if( IsVirtual(pTab) ){
- sqlite3VdbeOp3(v, OP_VDestroy, iDb, 0, pTab->zName, 0);
+ sqlite3VdbeAddOp4(v, OP_VDestroy, iDb, 0, 0, pTab->zName, 0);
}
- sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0);
- sqlite3ChangeCookie(db, v, iDb);
+ sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0);
+ sqlite3ChangeCookie(pParse, iDb);
}
sqliteViewResetAll(db, iDb);
@@ -2083,8 +2148,10 @@ void sqlite3CreateForeignKey(
nByte += strlen(pToCol->a[i].zName) + 1;
}
}
- pFKey = sqliteMalloc( nByte );
- if( pFKey==0 ) goto fk_end;
+ pFKey = sqlite3DbMallocZero(pParse->db, nByte );
+ if( pFKey==0 ){
+ goto fk_end;
+ }
pFKey->pFrom = p;
pFKey->pNextFrom = p->pFKey;
z = (char*)&pFKey[1];
@@ -2135,7 +2202,7 @@ void sqlite3CreateForeignKey(
pFKey = 0;
fk_end:
- sqliteFree(pFKey);
+ sqlite3_free(pFKey);
#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
sqlite3ExprListDelete(pFromCol);
sqlite3ExprListDelete(pToCol);
@@ -2163,7 +2230,7 @@ void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){
** content of an index in response to a REINDEX command.
**
** if memRootPage is not negative, it means that the index is newly
-** created. The memory cell specified by memRootPage contains the
+** created. The register specified by memRootPage contains the
** root page number of the index. If memRootPage is negative, then
** the index already exists and must be cleared before being refilled and
** the root page number of the index is taken from pIndex->tnum.
@@ -2176,11 +2243,14 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
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);
+ int regIdxKey; /* Registers containing the index key */
+ int regRecord; /* Register holding assemblied index record */
+ sqlite3 *db = pParse->db; /* The database connection */
+ int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
#ifndef SQLITE_OMIT_AUTHORIZATION
if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0,
- pParse->db->aDb[iDb].zName ) ){
+ db->aDb[iDb].zName ) ){
return;
}
#endif
@@ -2191,34 +2261,40 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
if( memRootPage>=0 ){
- sqlite3VdbeAddOp(v, OP_MemLoad, memRootPage, 0);
- tnum = 0;
+ tnum = memRootPage;
}else{
tnum = pIndex->tnum;
- sqlite3VdbeAddOp(v, OP_Clear, tnum, iDb);
+ sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
}
- sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
pKey = sqlite3IndexKeyinfo(pParse, pIndex);
- sqlite3VdbeOp3(v, OP_OpenWrite, iIdx, tnum, (char *)pKey, P3_KEYINFO_HANDOFF);
+ sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
+ (char *)pKey, P4_KEYINFO_HANDOFF);
+ if( memRootPage>=0 ){
+ sqlite3VdbeChangeP5(v, 1);
+ }
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
- addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0);
- sqlite3GenerateIndexKey(v, pIndex, iTab);
+ addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
+ regRecord = sqlite3GetTempReg(pParse);
+ regIdxKey = sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord);
if( pIndex->onError!=OE_None ){
- int curaddr = sqlite3VdbeCurrentAddr(v);
- int addr2 = curaddr+4;
- sqlite3VdbeChangeP2(v, curaddr-1, addr2);
- sqlite3VdbeAddOp(v, OP_Rowid, iTab, 0);
- sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
- sqlite3VdbeAddOp(v, OP_IsUnique, iIdx, addr2);
- sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort,
- "indexed columns are not unique", P3_STATIC);
- assert( addr2==sqlite3VdbeCurrentAddr(v) );
- }
- sqlite3VdbeAddOp(v, OP_IdxInsert, iIdx, 0);
- sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1);
+ int j1, j2;
+ int regRowid;
+
+ regRowid = regIdxKey + pIndex->nColumn;
+ j1 = sqlite3VdbeAddOp3(v, OP_IsNull, regIdxKey, 0, pIndex->nColumn);
+ j2 = sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx,
+ 0, regRowid, (char*)regRecord, P4_INT32);
+ sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort, 0,
+ "indexed columns are not unique", P4_STATIC);
+ sqlite3VdbeJumpHere(v, j1);
+ sqlite3VdbeJumpHere(v, j2);
+ }
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord);
+ sqlite3ReleaseTempReg(pParse, regRecord);
+ sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1);
sqlite3VdbeJumpHere(v, addr1);
- sqlite3VdbeAddOp(v, OP_Close, iTab, 0);
- sqlite3VdbeAddOp(v, OP_Close, iIdx, 0);
+ sqlite3VdbeAddOp1(v, OP_Close, iTab);
+ sqlite3VdbeAddOp1(v, OP_Close, iIdx);
}
/*
@@ -2240,7 +2316,7 @@ void sqlite3CreateIndex(
SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */
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 *pStart, /* The CREATE token that begins this 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 */
@@ -2262,7 +2338,7 @@ void sqlite3CreateIndex(
int nExtra = 0;
char *zExtra;
- if( pParse->nErr || sqlite3MallocFailed() || IN_DECLARE_VTAB ){
+ if( pParse->nErr || db->mallocFailed || IN_DECLARE_VTAB ){
goto exit_create_index;
}
@@ -2281,11 +2357,14 @@ void sqlite3CreateIndex(
#ifndef SQLITE_OMIT_TEMPDB
/* If the index name was unqualified, check if the the table
- ** is a temp table. If so, set the database to 1.
+ ** is a temp table. If so, set the database to 1. Do not do this
+ ** if initialising a database schema.
*/
- pTab = sqlite3SrcListLookup(pParse, pTblName);
- if( pName2 && pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){
- iDb = 1;
+ if( !db->init.busy ){
+ pTab = sqlite3SrcListLookup(pParse, pTblName);
+ if( pName2 && pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){
+ iDb = 1;
+ }
}
#endif
@@ -2296,7 +2375,7 @@ void sqlite3CreateIndex(
** sqlite3FixSrcList can never fail. */
assert(0);
}
- pTab = sqlite3LocateTable(pParse, pTblName->a[0].zName,
+ pTab = sqlite3LocateTable(pParse, 0, pTblName->a[0].zName,
pTblName->a[0].zDatabase);
if( !pTab ) goto exit_create_index;
assert( db->aDb[iDb].pSchema==pTab->pSchema );
@@ -2340,7 +2419,7 @@ void sqlite3CreateIndex(
** own name.
*/
if( pName ){
- zName = sqlite3NameFromToken(pName);
+ zName = sqlite3NameFromToken(db, pName);
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index;
if( zName==0 ) goto exit_create_index;
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
@@ -2348,26 +2427,29 @@ void sqlite3CreateIndex(
}
if( !db->init.busy ){
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index;
- 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 ){
sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
goto exit_create_index;
}
}
+ if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){
+ if( !ifNotExist ){
+ sqlite3ErrorMsg(pParse, "index %s already exists", zName);
+ }
+ goto exit_create_index;
+ }
}else{
char zBuf[30];
int n;
Index *pLoop;
for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){}
- sprintf(zBuf,"_%d",n);
+ sqlite3_snprintf(sizeof(zBuf),zBuf,"_%d",n);
zName = 0;
sqlite3SetString(&zName, "sqlite_autoindex_", pTab->zName, zBuf, (char*)0);
- if( zName==0 ) goto exit_create_index;
+ if( zName==0 ){
+ db->mallocFailed = 1;
+ goto exit_create_index;
+ }
}
/* Check for authorization to create an index.
@@ -2393,7 +2475,7 @@ void sqlite3CreateIndex(
if( pList==0 ){
nullId.z = (u8*)pTab->aCol[pTab->nCol-1].zName;
nullId.n = strlen((char*)nullId.z);
- pList = sqlite3ExprListAppend(0, 0, &nullId);
+ pList = sqlite3ExprListAppend(pParse, 0, 0, &nullId);
if( pList==0 ) goto exit_create_index;
pList->a[0].sortOrder = sortOrder;
}
@@ -2413,7 +2495,7 @@ void sqlite3CreateIndex(
*/
nName = strlen(zName);
nCol = pList->nExpr;
- pIndex = sqliteMalloc(
+ pIndex = sqlite3DbMallocZero(db,
sizeof(Index) + /* Index structure */
sizeof(int)*nCol + /* Index.aiColumn */
sizeof(int)*(nCol+1) + /* Index.aiRowEst */
@@ -2422,14 +2504,16 @@ void sqlite3CreateIndex(
nName + 1 + /* Index.zName */
nExtra /* Collation sequence names */
);
- if( sqlite3MallocFailed() ) goto exit_create_index;
+ if( db->mallocFailed ){
+ 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);
+ memcpy(pIndex->zName, zName, nName+1);
pIndex->pTable = pTab;
pIndex->nColumn = pList->nExpr;
pIndex->onError = onError;
@@ -2452,7 +2536,7 @@ void sqlite3CreateIndex(
const char *zColName = pListItem->zName;
Column *pTabCol;
int requestedSortOrder;
- char *zColl; /* Collation sequence */
+ char *zColl; /* Collation sequence name */
for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break;
@@ -2462,11 +2546,17 @@ void sqlite3CreateIndex(
pTab->zName, zColName);
goto exit_create_index;
}
+ /* TODO: Add a test to make sure that the same column is not named
+ ** more than once within the same index. Only the first instance of
+ ** the column will ever be used by the optimizer. Note that using the
+ ** same column more than once cannot be an error because that would
+ ** break backwards compatibility - it needs to be a warning.
+ */
pIndex->aiColumn[i] = j;
if( pListItem->pExpr ){
assert( pListItem->pExpr->pColl );
zColl = zExtra;
- strcpy(zExtra, pListItem->pExpr->pColl->zName);
+ sqlite3_snprintf(nExtra, zExtra, "%s", pListItem->pExpr->pColl->zName);
zExtra += (strlen(zColl) + 1);
}else{
zColl = pTab->aCol[j].zColl;
@@ -2543,6 +2633,7 @@ void sqlite3CreateIndex(
pIndex->zName, strlen(pIndex->zName)+1, pIndex);
if( p ){
assert( p==pIndex ); /* Malloc must have failed */
+ db->mallocFailed = 1;
goto exit_create_index;
}
db->flags |= SQLITE_InternChanges;
@@ -2569,7 +2660,7 @@ void sqlite3CreateIndex(
else if( db->init.busy==0 ){
Vdbe *v;
char *zStmt;
- int iMem = pParse->nMem++;
+ int iMem = ++pParse->nMem;
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto exit_create_index;
@@ -2578,15 +2669,14 @@ void sqlite3CreateIndex(
/* Create the rootpage for the index
*/
sqlite3BeginWriteOperation(pParse, 1, iDb);
- sqlite3VdbeAddOp(v, OP_CreateIndex, iDb, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, iMem, 0);
+ sqlite3VdbeAddOp2(v, OP_CreateIndex, iDb, iMem);
/* Gather the complete text of the CREATE INDEX statement into
** the zStmt variable
*/
if( pStart && pEnd ){
/* A named index with an explicit CREATE INDEX statement */
- zStmt = sqlite3MPrintf("CREATE%s INDEX %.*s",
+ zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s",
onError==OE_None ? "" : " UNIQUE",
pEnd->z - pName->z + 1,
pName->z);
@@ -2599,24 +2689,24 @@ void sqlite3CreateIndex(
/* Add an entry in sqlite_master for this index
*/
sqlite3NestedParse(pParse,
- "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#0,%Q);",
+ "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
pIndex->zName,
pTab->zName,
+ iMem,
zStmt
);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- sqliteFree(zStmt);
+ sqlite3_free(zStmt);
/* Fill the index with data and reparse the schema. Code an OP_Expire
** to invalidate all pre-compiled statements.
*/
if( pTblName ){
sqlite3RefillIndex(pParse, pIndex, iMem);
- sqlite3ChangeCookie(db, v, iDb);
- sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0,
- sqlite3MPrintf("name='%q'", pIndex->zName), P3_DYNAMIC);
- sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
+ sqlite3ChangeCookie(pParse, iDb);
+ sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0,
+ sqlite3MPrintf(db, "name='%q'", pIndex->zName), P4_DYNAMIC);
+ sqlite3VdbeAddOp1(v, OP_Expire, 0);
}
}
@@ -2648,7 +2738,7 @@ exit_create_index:
}
sqlite3ExprListDelete(pList);
sqlite3SrcListDelete(pTblName);
- sqliteFree(zName);
+ sqlite3_free(zName);
return;
}
@@ -2660,11 +2750,17 @@ 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);
+ int r1 = sqlite3GetTempReg(pParse);
+ int r2 = sqlite3GetTempReg(pParse);
+ int j1;
+ sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, 1);
+ sqlite3VdbeUsesBtree(v, iDb);
+ sqlite3VdbeAddOp2(v, OP_Integer, minFormat, r2);
+ j1 = sqlite3VdbeAddOp3(v, OP_Ge, r2, 0, r1);
+ sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, 1, r2);
+ sqlite3VdbeJumpHere(v, j1);
+ sqlite3ReleaseTempReg(pParse, r1);
+ sqlite3ReleaseTempReg(pParse, r2);
}
}
@@ -2713,7 +2809,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
sqlite3 *db = pParse->db;
int iDb;
- if( pParse->nErr || sqlite3MallocFailed() ){
+ if( pParse->nErr || db->mallocFailed ){
goto exit_drop_index;
}
assert( pName->nSrc==1 );
@@ -2753,14 +2849,15 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
/* Generate code to remove the index and from the master table */
v = sqlite3GetVdbe(pParse);
if( v ){
+ sqlite3BeginWriteOperation(pParse, 1, iDb);
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE name=%Q",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
pIndex->zName
);
- sqlite3ChangeCookie(db, v, iDb);
+ sqlite3ChangeCookie(pParse, iDb);
destroyRootPage(pParse, pIndex->tnum, iDb);
- sqlite3VdbeOp3(v, OP_DropIndex, iDb, 0, pIndex->zName, 0);
+ sqlite3VdbeAddOp4(v, OP_DropIndex, iDb, 0, 0, pIndex->zName, 0);
}
exit_drop_index:
@@ -2768,44 +2865,47 @@ exit_drop_index:
}
/*
-** ppArray points into a structure where there is an array pointer
-** followed by two integers. The first integer is the
-** number of elements in the structure array. The second integer
-** is the number of allocated slots in the array.
-**
-** In other words, the structure looks something like this:
+** pArray is a pointer to an array of objects. Each object in the
+** array is szEntry bytes in size. This routine allocates a new
+** object on the end of the array.
**
-** struct Example1 {
-** struct subElem *aEntry;
-** int nEntry;
-** int nAlloc;
-** }
+** *pnEntry is the number of entries already in use. *pnAlloc is
+** the previously allocated size of the array. initSize is the
+** suggested initial array size allocation.
**
-** The pnEntry parameter points to the equivalent of Example1.nEntry.
+** The index of the new entry is returned in *pIdx.
**
-** This routine allocates a new slot in the array, zeros it out,
-** and returns its index. If malloc fails a negative number is returned.
-**
-** szEntry is the sizeof of a single array entry. initSize is the
-** number of array entries allocated on the initial allocation.
+** This routine returns a pointer to the array of objects. This
+** might be the same as the pArray parameter or it might be a different
+** pointer if the array was resized.
*/
-int sqlite3ArrayAllocate(void **ppArray, int szEntry, int initSize){
- char *p;
- int *an = (int*)&ppArray[1];
- if( an[0]>=an[1] ){
+void *sqlite3ArrayAllocate(
+ sqlite3 *db, /* Connection to notify of malloc failures */
+ void *pArray, /* Array of objects. Might be reallocated */
+ int szEntry, /* Size of each object in the array */
+ int initSize, /* Suggested initial allocation, in elements */
+ int *pnEntry, /* Number of objects currently in use */
+ int *pnAlloc, /* Current size of the allocation, in elements */
+ int *pIdx /* Write the index of a new slot here */
+){
+ char *z;
+ if( *pnEntry >= *pnAlloc ){
void *pNew;
int newSize;
- newSize = an[1]*2 + initSize;
- pNew = sqliteRealloc(*ppArray, newSize*szEntry);
+ newSize = (*pnAlloc)*2 + initSize;
+ pNew = sqlite3DbRealloc(db, pArray, newSize*szEntry);
if( pNew==0 ){
- return -1;
+ *pIdx = -1;
+ return pArray;
}
- an[1] = newSize;
- *ppArray = pNew;
+ *pnAlloc = newSize;
+ pArray = pNew;
}
- p = *ppArray;
- memset(&p[an[0]*szEntry], 0, szEntry);
- return an[0]++;
+ z = (char*)pArray;
+ memset(&z[*pnEntry * szEntry], 0, szEntry);
+ *pIdx = *pnEntry;
+ ++*pnEntry;
+ return pArray;
}
/*
@@ -2814,19 +2914,27 @@ int sqlite3ArrayAllocate(void **ppArray, int szEntry, int initSize){
**
** A new IdList is returned, or NULL if malloc() fails.
*/
-IdList *sqlite3IdListAppend(IdList *pList, Token *pToken){
+IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){
int i;
if( pList==0 ){
- pList = sqliteMalloc( sizeof(IdList) );
+ pList = sqlite3DbMallocZero(db, sizeof(IdList) );
if( pList==0 ) return 0;
pList->nAlloc = 0;
}
- i = sqlite3ArrayAllocate((void**)&pList->a, sizeof(pList->a[0]), 5);
+ pList->a = sqlite3ArrayAllocate(
+ db,
+ pList->a,
+ sizeof(pList->a[0]),
+ 5,
+ &pList->nId,
+ &pList->nAlloc,
+ &i
+ );
if( i<0 ){
sqlite3IdListDelete(pList);
return 0;
}
- pList->a[i].zName = sqlite3NameFromToken(pToken);
+ pList->a[i].zName = sqlite3NameFromToken(db, pToken);
return pList;
}
@@ -2837,10 +2945,10 @@ void sqlite3IdListDelete(IdList *pList){
int i;
if( pList==0 ) return;
for(i=0; i<pList->nId; i++){
- sqliteFree(pList->a[i].zName);
+ sqlite3_free(pList->a[i].zName);
}
- sqliteFree(pList->a);
- sqliteFree(pList);
+ sqlite3_free(pList->a);
+ sqlite3_free(pList);
}
/*
@@ -2872,26 +2980,31 @@ int sqlite3IdListIndex(IdList *pList, const char *zName){
**
** In other words, if call like this:
**
-** sqlite3SrcListAppend(A,B,0);
+** sqlite3SrcListAppend(D,A,B,0);
**
** Then B is a table name and the database name is unspecified. If called
** like this:
**
-** sqlite3SrcListAppend(A,B,C);
+** sqlite3SrcListAppend(D,A,B,C);
**
** Then C is the table name and B is the database name.
*/
-SrcList *sqlite3SrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){
+SrcList *sqlite3SrcListAppend(
+ sqlite3 *db, /* Connection to notify of malloc failures */
+ SrcList *pList, /* Append to this SrcList. NULL creates a new SrcList */
+ Token *pTable, /* Table to append */
+ Token *pDatabase /* Database of the table */
+){
struct SrcList_item *pItem;
if( pList==0 ){
- pList = sqliteMalloc( sizeof(SrcList) );
+ pList = sqlite3DbMallocZero(db, sizeof(SrcList) );
if( pList==0 ) return 0;
pList->nAlloc = 1;
}
if( pList->nSrc>=pList->nAlloc ){
SrcList *pNew;
pList->nAlloc *= 2;
- pNew = sqliteRealloc(pList,
+ pNew = sqlite3DbRealloc(db, pList,
sizeof(*pList) + (pList->nAlloc-1)*sizeof(pList->a[0]) );
if( pNew==0 ){
sqlite3SrcListDelete(pList);
@@ -2909,8 +3022,8 @@ SrcList *sqlite3SrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){
pDatabase = pTable;
pTable = pTemp;
}
- pItem->zName = sqlite3NameFromToken(pTable);
- pItem->zDatabase = sqlite3NameFromToken(pDatabase);
+ pItem->zName = sqlite3NameFromToken(db, pTable);
+ pItem->zDatabase = sqlite3NameFromToken(db, pDatabase);
pItem->iCursor = -1;
pItem->isPopulated = 0;
pList->nSrc++;
@@ -2923,7 +3036,7 @@ SrcList *sqlite3SrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){
void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
int i;
struct SrcList_item *pItem;
- assert(pList || sqlite3MallocFailed() );
+ assert(pList || pParse->db->mallocFailed );
if( pList ){
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
if( pItem->iCursor>=0 ) break;
@@ -2936,15 +3049,6 @@ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
}
/*
-** Add an alias to the last identifier on the given identifier list.
-*/
-void sqlite3SrcListAddAlias(SrcList *pList, Token *pToken){
- if( pList && pList->nSrc>0 ){
- pList->a[pList->nSrc-1].zAlias = sqlite3NameFromToken(pToken);
- }
-}
-
-/*
** Delete an entire SrcList including all its substructure.
*/
void sqlite3SrcListDelete(SrcList *pList){
@@ -2952,15 +3056,85 @@ void sqlite3SrcListDelete(SrcList *pList){
struct SrcList_item *pItem;
if( pList==0 ) return;
for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
- sqliteFree(pItem->zDatabase);
- sqliteFree(pItem->zName);
- sqliteFree(pItem->zAlias);
- sqlite3DeleteTable(0, pItem->pTab);
+ sqlite3_free(pItem->zDatabase);
+ sqlite3_free(pItem->zName);
+ sqlite3_free(pItem->zAlias);
+ sqlite3DeleteTable(pItem->pTab);
sqlite3SelectDelete(pItem->pSelect);
sqlite3ExprDelete(pItem->pOn);
sqlite3IdListDelete(pItem->pUsing);
}
- sqliteFree(pList);
+ sqlite3_free(pList);
+}
+
+/*
+** This routine is called by the parser to add a new term to the
+** end of a growing FROM clause. The "p" parameter is the part of
+** the FROM clause that has already been constructed. "p" is NULL
+** if this is the first term of the FROM clause. pTable and pDatabase
+** are the name of the table and database named in the FROM clause term.
+** pDatabase is NULL if the database name qualifier is missing - the
+** usual case. If the term has a alias, then pAlias points to the
+** alias token. If the term is a subquery, then pSubquery is the
+** SELECT statement that the subquery encodes. The pTable and
+** pDatabase parameters are NULL for subqueries. The pOn and pUsing
+** parameters are the content of the ON and USING clauses.
+**
+** Return a new SrcList which encodes is the FROM with the new
+** term added.
+*/
+SrcList *sqlite3SrcListAppendFromTerm(
+ Parse *pParse, /* Parsing context */
+ SrcList *p, /* The left part of the FROM clause already seen */
+ Token *pTable, /* Name of the table to add to the FROM clause */
+ Token *pDatabase, /* Name of the database containing pTable */
+ Token *pAlias, /* The right-hand side of the AS subexpression */
+ Select *pSubquery, /* A subquery used in place of a table name */
+ Expr *pOn, /* The ON clause of a join */
+ IdList *pUsing /* The USING clause of a join */
+){
+ struct SrcList_item *pItem;
+ sqlite3 *db = pParse->db;
+ p = sqlite3SrcListAppend(db, p, pTable, pDatabase);
+ if( p==0 || p->nSrc==0 ){
+ sqlite3ExprDelete(pOn);
+ sqlite3IdListDelete(pUsing);
+ sqlite3SelectDelete(pSubquery);
+ return p;
+ }
+ pItem = &p->a[p->nSrc-1];
+ if( pAlias && pAlias->n ){
+ pItem->zAlias = sqlite3NameFromToken(db, pAlias);
+ }
+ pItem->pSelect = pSubquery;
+ pItem->pOn = pOn;
+ pItem->pUsing = pUsing;
+ return p;
+}
+
+/*
+** When building up a FROM clause in the parser, the join operator
+** is initially attached to the left operand. But the code generator
+** expects the join operator to be on the right operand. This routine
+** Shifts all join operators from left to right for an entire FROM
+** clause.
+**
+** Example: Suppose the join is like this:
+**
+** A natural cross join B
+**
+** The operator is "natural cross join". The A and B operands are stored
+** in p->a[0] and p->a[1], respectively. The parser initially stores the
+** operator with A. This routine shifts that operator over to B.
+*/
+void sqlite3SrcListShiftJoinType(SrcList *p){
+ if( p && p->a ){
+ int i;
+ for(i=p->nSrc-1; i>0; i--){
+ p->a[i].jointype = p->a[i-1].jointype;
+ }
+ p->a[0].jointype = 0;
+ }
}
/*
@@ -2972,17 +3146,18 @@ void sqlite3BeginTransaction(Parse *pParse, int type){
int i;
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
- if( pParse->nErr || sqlite3MallocFailed() ) return;
+ if( pParse->nErr || db->mallocFailed ) return;
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return;
v = sqlite3GetVdbe(pParse);
if( !v ) return;
if( type!=TK_DEFERRED ){
for(i=0; i<db->nDb; i++){
- sqlite3VdbeAddOp(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1);
+ sqlite3VdbeAddOp2(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1);
+ sqlite3VdbeUsesBtree(v, i);
}
}
- sqlite3VdbeAddOp(v, OP_AutoCommit, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_AutoCommit, 0, 0);
}
/*
@@ -2993,12 +3168,12 @@ void sqlite3CommitTransaction(Parse *pParse){
Vdbe *v;
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
- if( pParse->nErr || sqlite3MallocFailed() ) return;
+ if( pParse->nErr || db->mallocFailed ) return;
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return;
v = sqlite3GetVdbe(pParse);
if( v ){
- sqlite3VdbeAddOp(v, OP_AutoCommit, 1, 0);
+ sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 0);
}
}
@@ -3010,12 +3185,12 @@ void sqlite3RollbackTransaction(Parse *pParse){
Vdbe *v;
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
- if( pParse->nErr || sqlite3MallocFailed() ) return;
+ if( pParse->nErr || db->mallocFailed ) return;
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return;
v = sqlite3GetVdbe(pParse);
if( v ){
- sqlite3VdbeAddOp(v, OP_AutoCommit, 1, 1);
+ sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 1);
}
}
@@ -3026,22 +3201,23 @@ void sqlite3RollbackTransaction(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);
+ int rc;
+ static const int flags =
+ SQLITE_OPEN_READWRITE |
+ SQLITE_OPEN_CREATE |
+ SQLITE_OPEN_EXCLUSIVE |
+ SQLITE_OPEN_DELETEONCLOSE |
+ SQLITE_OPEN_TEMP_DB;
+
+ rc = sqlite3BtreeFactory(db, 0, 0, SQLITE_DEFAULT_CACHE_SIZE, flags,
+ &db->aDb[1].pBt);
if( rc!=SQLITE_OK ){
sqlite3ErrorMsg(pParse, "unable to open a temporary database "
"file for storing temporary tables");
pParse->rc = rc;
return 1;
}
- if( db->flags & !db->autoCommit ){
- rc = sqlite3BtreeBeginTrans(db->aDb[1].pBt, 1);
- if( rc!=SQLITE_OK ){
- sqlite3ErrorMsg(pParse, "unable to get a write lock on "
- "the temporary database file");
- pParse->rc = rc;
- return 1;
- }
- }
+ assert( (db->flags & SQLITE_InTrans)==0 || db->autoCommit );
assert( db->aDb[1].pSchema );
}
return 0;
@@ -3078,12 +3254,12 @@ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
if( v==0 ) return; /* This only happens if there was a prior error */
db = pParse->db;
if( pParse->cookieGoto==0 ){
- pParse->cookieGoto = sqlite3VdbeAddOp(v, OP_Goto, 0, 0)+1;
+ pParse->cookieGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0)+1;
}
if( iDb>=0 ){
assert( iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 || iDb==1 );
- assert( iDb<MAX_ATTACHED+2 );
+ assert( iDb<SQLITE_MAX_ATTACHED+2 );
mask = 1<<iDb;
if( (pParse->cookieMask & mask)==0 ){
pParse->cookieMask |= mask;
@@ -3119,7 +3295,7 @@ void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
sqlite3CodeVerifySchema(pParse, iDb);
pParse->writeMask |= 1<<iDb;
if( setStatement && pParse->nested==0 ){
- sqlite3VdbeAddOp(v, OP_Statement, iDb, 0);
+ sqlite3VdbeAddOp1(v, OP_Statement, iDb);
}
if( (OMIT_TEMPDB || iDb!=1) && pParse->db->aDb[1].pBt!=0 ){
sqlite3BeginWriteOperation(pParse, setStatement, 1);
@@ -3218,29 +3394,33 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
reindexDatabases(pParse, 0);
return;
}else if( pName2==0 || pName2->z==0 ){
+ char *zColl;
assert( pName1->z );
- pColl = sqlite3FindCollSeq(db, ENC(db), (char*)pName1->z, pName1->n, 0);
+ zColl = sqlite3NameFromToken(pParse->db, pName1);
+ if( !zColl ) return;
+ pColl = sqlite3FindCollSeq(db, ENC(db), zColl, -1, 0);
if( pColl ){
- char *zColl = sqliteStrNDup((const char *)pName1->z, pName1->n);
if( zColl ){
reindexDatabases(pParse, zColl);
- sqliteFree(zColl);
+ sqlite3_free(zColl);
}
return;
}
+ sqlite3_free(zColl);
}
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName);
if( iDb<0 ) return;
- z = sqlite3NameFromToken(pObjName);
+ z = sqlite3NameFromToken(db, pObjName);
+ if( z==0 ) return;
zDb = db->aDb[iDb].zName;
pTab = sqlite3FindTable(db, z, zDb);
if( pTab ){
reindexTable(pParse, pTab, 0);
- sqliteFree(z);
+ sqlite3_free(z);
return;
}
pIndex = sqlite3FindIndex(db, z, zDb);
- sqliteFree(z);
+ sqlite3_free(z);
if( pIndex ){
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3RefillIndex(pParse, pIndex, -1);
@@ -3255,7 +3435,7 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
** 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
+** the caller is responsible for calling sqlite3_free() 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.
@@ -3264,9 +3444,10 @@ 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);
+ KeyInfo *pKey = (KeyInfo *)sqlite3DbMallocZero(pParse->db, nBytes);
if( pKey ){
+ pKey->db = pParse->db;
pKey->aSortOrder = (u8 *)&(pKey->aColl[nCol]);
assert( &pKey->aSortOrder[nCol]==&(((u8 *)pKey)[nBytes]) );
for(i=0; i<nCol; i++){
@@ -3279,7 +3460,7 @@ KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){
}
if( pParse->nErr ){
- sqliteFree(pKey);
+ sqlite3_free(pKey);
pKey = 0;
}
return pKey;
diff --git a/ext/pdo_sqlite/sqlite/src/callback.c b/ext/pdo_sqlite/sqlite/src/callback.c
index ac748361bb..e5a41c72f0 100644
--- a/ext/pdo_sqlite/sqlite/src/callback.c
+++ b/ext/pdo_sqlite/sqlite/src/callback.c
@@ -27,15 +27,15 @@ static void callCollNeeded(sqlite3 *db, const char *zName, int nName){
assert( !db->xCollNeeded || !db->xCollNeeded16 );
if( nName<0 ) nName = strlen(zName);
if( db->xCollNeeded ){
- char *zExternal = sqliteStrNDup(zName, nName);
+ char *zExternal = sqlite3DbStrNDup(db, zName, nName);
if( !zExternal ) return;
db->xCollNeeded(db->pCollNeededArg, db, (int)ENC(db), zExternal);
- sqliteFree(zExternal);
+ sqlite3_free(zExternal);
}
#ifndef SQLITE_OMIT_UTF16
if( db->xCollNeeded16 ){
char const *zExternal;
- sqlite3_value *pTmp = sqlite3ValueNew();
+ sqlite3_value *pTmp = sqlite3ValueNew(db);
sqlite3ValueSetStr(pTmp, nName, zName, SQLITE_UTF8, SQLITE_STATIC);
zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE);
if( zExternal ){
@@ -63,6 +63,7 @@ static int synthCollSeq(sqlite3 *db, CollSeq *pColl){
pColl2 = sqlite3FindCollSeq(db, aEnc[i], z, n, 0);
if( pColl2->xCmp!=0 ){
memcpy(pColl, pColl2, sizeof(CollSeq));
+ pColl->xDel = 0; /* Do not copy the destructor */
return SQLITE_OK;
}
}
@@ -161,7 +162,7 @@ static CollSeq *findCollSeqEntry(
pColl = sqlite3HashFind(&db->aCollSeq, zName, nName);
if( 0==pColl && create ){
- pColl = sqliteMalloc( 3*sizeof(*pColl) + nName + 1 );
+ pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1 );
if( pColl ){
CollSeq *pDel = 0;
pColl[0].zName = (char*)&pColl[3];
@@ -178,9 +179,10 @@ static CollSeq *findCollSeqEntry(
** return the pColl pointer to be deleted (because it wasn't added
** to the hash table).
*/
- assert( !pDel || (sqlite3MallocFailed() && pDel==pColl) );
- if( pDel ){
- sqliteFree(pDel);
+ assert( pDel==0 || pDel==pColl );
+ if( pDel!=0 ){
+ db->mallocFailed = 1;
+ sqlite3_free(pDel);
pColl = 0;
}
}
@@ -195,6 +197,11 @@ static CollSeq *findCollSeqEntry(
**
** If the entry specified is not found and 'create' is true, then create a
** new entry. Otherwise return NULL.
+**
+** A separate function sqlite3LocateCollSeq() is a wrapper around
+** this routine. sqlite3LocateCollSeq() invokes the collation factory
+** if necessary and generates an error message if the collating sequence
+** cannot be found.
*/
CollSeq *sqlite3FindCollSeq(
sqlite3 *db,
@@ -297,14 +304,15 @@ FuncDef *sqlite3FindFunction(
** new entry to the hash table and return it.
*/
if( createFlag && bestmatch<6 &&
- (pBest = sqliteMalloc(sizeof(*pBest)+nName))!=0 ){
+ (pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName))!=0 ){
pBest->nArg = nArg;
pBest->pNext = pFirst;
pBest->iPrefEnc = enc;
memcpy(pBest->zName, zName, nName);
pBest->zName[nName] = 0;
if( pBest==sqlite3HashInsert(&db->aFunc,pBest->zName,nName,(void*)pBest) ){
- sqliteFree(pBest);
+ db->mallocFailed = 1;
+ sqlite3_free(pBest);
return 0;
}
}
@@ -317,7 +325,7 @@ FuncDef *sqlite3FindFunction(
/*
** Free all resources held by the schema structure. The void* argument points
-** at a Schema struct. This function does not call sqliteFree() on the
+** at a Schema struct. This function does not call sqlite3_free() on the
** pointer itself, it just cleans up subsiduary resources (i.e. the contents
** of the schema hash tables).
*/
@@ -339,7 +347,7 @@ void sqlite3SchemaFree(void *p){
sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
- sqlite3DeleteTable(0, pTab);
+ sqlite3DeleteTable(pTab);
}
sqlite3HashClear(&temp1);
pSchema->pSeqTab = 0;
@@ -350,14 +358,16 @@ void sqlite3SchemaFree(void *p){
** Find and return the schema associated with a BTree. Create
** a new one if necessary.
*/
-Schema *sqlite3SchemaGet(Btree *pBt){
+Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
Schema * p;
if( pBt ){
- p = (Schema *)sqlite3BtreeSchema(pBt,sizeof(Schema),sqlite3SchemaFree);
+ p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaFree);
}else{
- p = (Schema *)sqliteMalloc(sizeof(Schema));
+ p = (Schema *)sqlite3MallocZero(sizeof(Schema));
}
- if( p && 0==p->file_format ){
+ if( !p ){
+ db->mallocFailed = 1;
+ }else if ( 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);
diff --git a/ext/pdo_sqlite/sqlite/src/complete.c b/ext/pdo_sqlite/sqlite/src/complete.c
index 660417b066..f35ca86485 100644
--- a/ext/pdo_sqlite/sqlite/src/complete.c
+++ b/ext/pdo_sqlite/sqlite/src/complete.c
@@ -24,8 +24,16 @@
/*
** 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]))
+#ifndef SQLITE_AMALGAMATION
+#ifdef SQLITE_ASCII
+extern const char sqlite3IsAsciiIdChar[];
+#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsAsciiIdChar[c-0x20]))
+#endif
+#ifdef SQLITE_EBCDIC
+extern const char sqlite3IsEbcdicIdChar[];
+#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
+#endif
+#endif /* SQLITE_AMALGAMATION */
/*
@@ -248,9 +256,9 @@ int sqlite3_complete(const char *zSql){
int sqlite3_complete16(const void *zSql){
sqlite3_value *pVal;
char const *zSql8;
- int rc = 0;
+ int rc = SQLITE_NOMEM;
- pVal = sqlite3ValueNew();
+ pVal = sqlite3ValueNew(0);
sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8);
if( zSql8 ){
diff --git a/ext/pdo_sqlite/sqlite/src/date.c b/ext/pdo_sqlite/sqlite/src/date.c
index 10633e9afe..8da45d1614 100644
--- a/ext/pdo_sqlite/sqlite/src/date.c
+++ b/ext/pdo_sqlite/sqlite/src/date.c
@@ -18,12 +18,10 @@
**
** $Id$
**
-** NOTES:
-**
** SQLite processes all times and dates as Julian Day numbers. The
** dates and times are stored as the number of days since noon
** in Greenwich on November 24, 4714 B.C. according to the Gregorian
-** calendar system.
+** calendar system.
**
** 1970-01-01 00:00:00 is JD 2440587.5
** 2000-01-01 00:00:00 is JD 2451544.5
@@ -48,14 +46,10 @@
** Richmond, Virginia (USA)
*/
#include "sqliteInt.h"
-#include "os.h"
#include <ctype.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
-#ifndef PHP_WIN32
-#include "main/php_reentrancy.h"
-#endif
#ifndef SQLITE_OMIT_DATETIME_FUNCS
@@ -237,11 +231,11 @@ static void computeJD(DateTime *p){
X2 = 30.6001*(M+1);
p->rJD = X1 + X2 + D + B - 1524.5;
p->validJD = 1;
- p->validYMD = 0;
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->validYMD = 0;
p->validHMS = 0;
p->validTZ = 0;
}
@@ -308,7 +302,11 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
** as there is a time string. The time string can be omitted as long
** as there is a year and date.
*/
-static int parseDateOrTime(const char *zDate, DateTime *p){
+static int parseDateOrTime(
+ sqlite3_context *context,
+ const char *zDate,
+ DateTime *p
+){
memset(p, 0, sizeof(*p));
if( parseYyyyMmDd(zDate,p)==0 ){
return 0;
@@ -316,7 +314,7 @@ static int parseDateOrTime(const char *zDate, DateTime *p){
return 0;
}else if( sqlite3StrICmp(zDate,"now")==0){
double r;
- sqlite3OsCurrentTime(&r);
+ sqlite3OsCurrentTime((sqlite3_vfs *)sqlite3_user_data(context), &r);
p->rJD = r;
p->validJD = 1;
return 0;
@@ -360,6 +358,7 @@ static void computeYMD(DateTime *p){
static void computeHMS(DateTime *p){
int Z, s;
if( p->validHMS ) return;
+ computeJD(p);
Z = p->rJD + 0.5;
s = (p->rJD + 0.5 - Z)*86400000.0 + 0.5;
p->s = 0.001*s;
@@ -396,7 +395,6 @@ static void clearYMD_HMS_TZ(DateTime *p){
static double localtimeOffset(DateTime *p){
DateTime x, y;
time_t t;
- struct tm *pTm, tmbuf;
x = *p;
computeYMD_HMS(&x);
if( x.Y<1971 || x.Y>=2038 ){
@@ -414,18 +412,31 @@ static double localtimeOffset(DateTime *p){
x.validJD = 0;
computeJD(&x);
t = (x.rJD-2440587.5)*86400.0 + 0.5;
- sqlite3OsEnterMutex();
- pTm = php_localtime_r(&t, &tmbuf);
- if (!pTm) {
- return 0;
- }
- y.Y = pTm->tm_year + 1900;
- y.M = pTm->tm_mon + 1;
- y.D = pTm->tm_mday;
- y.h = pTm->tm_hour;
- y.m = pTm->tm_min;
- y.s = pTm->tm_sec;
- sqlite3OsLeaveMutex();
+#ifdef HAVE_LOCALTIME_R
+ {
+ struct tm sLocal;
+ localtime_r(&t, &sLocal);
+ y.Y = sLocal.tm_year + 1900;
+ y.M = sLocal.tm_mon + 1;
+ y.D = sLocal.tm_mday;
+ y.h = sLocal.tm_hour;
+ y.m = sLocal.tm_min;
+ y.s = sLocal.tm_sec;
+ }
+#else
+ {
+ struct tm *pTm;
+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+ pTm = localtime(&t);
+ y.Y = pTm->tm_year + 1900;
+ y.M = pTm->tm_mon + 1;
+ y.D = pTm->tm_mday;
+ y.h = pTm->tm_hour;
+ y.m = pTm->tm_min;
+ y.s = pTm->tm_sec;
+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+ }
+#endif
y.validYMD = 1;
y.validHMS = 1;
y.validJD = 0;
@@ -567,7 +578,7 @@ static int parseModifier(const char *zMod, DateTime *p){
case '8':
case '9': {
n = getValue(z, &r);
- if( n<=0 ) break;
+ assert( n>=1 );
if( z[n]==':' ){
/* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
** specified number of hours, minutes, seconds, and fractional seconds
@@ -587,7 +598,7 @@ static int parseModifier(const char *zMod, DateTime *p){
if( z[0]=='-' ) tx.rJD = -tx.rJD;
computeJD(p);
clearYMD_HMS_TZ(p);
- p->rJD += tx.rJD;
+ p->rJD += tx.rJD;
rc = 0;
break;
}
@@ -642,15 +653,31 @@ static int parseModifier(const char *zMod, DateTime *p){
** argv[1] and following are modifiers. Parse them all and write
** the resulting time into the DateTime structure p. Return 0
** on success and 1 if there are any errors.
+**
+** If there are zero parameters (if even argv[0] is undefined)
+** then assume a default value of "now" for argv[0].
*/
-static int isDate(int argc, sqlite3_value **argv, DateTime *p){
+static int isDate(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv,
+ DateTime *p
+){
int i;
- if( argc==0 ) return 1;
- if( SQLITE_NULL==sqlite3_value_type(argv[0]) ||
- parseDateOrTime((char*)sqlite3_value_text(argv[0]), p) ) return 1;
+ const unsigned char *z;
+ static const unsigned char zDflt[] = "now";
+ if( argc==0 ){
+ z = zDflt;
+ }else{
+ z = sqlite3_value_text(argv[0]);
+ }
+ if( !z || parseDateOrTime(context, (char*)z, p) ){
+ return 1;
+ }
for(i=1; i<argc; i++){
- if( SQLITE_NULL==sqlite3_value_type(argv[i]) ||
- parseModifier((char*)sqlite3_value_text(argv[i]), p) ) return 1;
+ if( (z = sqlite3_value_text(argv[i]))==0 || parseModifier((char*)z, p) ){
+ return 1;
+ }
}
return 0;
}
@@ -672,7 +699,7 @@ static void juliandayFunc(
sqlite3_value **argv
){
DateTime x;
- if( isDate(argc, argv, &x)==0 ){
+ if( isDate(context, argc, argv, &x)==0 ){
computeJD(&x);
sqlite3_result_double(context, x.rJD);
}
@@ -689,11 +716,11 @@ static void datetimeFunc(
sqlite3_value **argv
){
DateTime x;
- if( isDate(argc, argv, &x)==0 ){
+ if( isDate(context, argc, argv, &x)==0 ){
char zBuf[100];
computeYMD_HMS(&x);
- sprintf(zBuf, "%04d-%02d-%02d %02d:%02d:%02d",x.Y, x.M, x.D, x.h, x.m,
- (int)(x.s));
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d",
+ x.Y, x.M, x.D, x.h, x.m, (int)(x.s));
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}
}
@@ -709,10 +736,10 @@ static void timeFunc(
sqlite3_value **argv
){
DateTime x;
- if( isDate(argc, argv, &x)==0 ){
+ if( isDate(context, argc, argv, &x)==0 ){
char zBuf[100];
computeHMS(&x);
- sprintf(zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s);
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}
}
@@ -728,10 +755,10 @@ static void dateFunc(
sqlite3_value **argv
){
DateTime x;
- if( isDate(argc, argv, &x)==0 ){
+ if( isDate(context, argc, argv, &x)==0 ){
char zBuf[100];
computeYMD(&x);
- sprintf(zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D);
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}
}
@@ -761,11 +788,12 @@ static void strftimeFunc(
sqlite3_value **argv
){
DateTime x;
- int n, i, j;
+ u64 n;
+ int i, j;
char *z;
const char *zFmt = (const char*)sqlite3_value_text(argv[0]);
char zBuf[100];
- if( zFmt==0 || isDate(argc-1, argv+1, &x) ) return;
+ if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
for(i=0, n=1; zFmt[i]; i++, n++){
if( zFmt[i]=='%' ){
switch( zFmt[i+1] ){
@@ -801,9 +829,15 @@ static void strftimeFunc(
}
if( n<sizeof(zBuf) ){
z = zBuf;
+ }else if( n>SQLITE_MAX_LENGTH ){
+ sqlite3_result_error_toobig(context);
+ return;
}else{
- z = sqliteMalloc( n );
- if( z==0 ) return;
+ z = sqlite3_malloc( n );
+ if( z==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
}
computeJD(&x);
computeYMD_HMS(&x);
@@ -813,15 +847,15 @@ static void strftimeFunc(
}else{
i++;
switch( zFmt[i] ){
- case 'd': sprintf(&z[j],"%02d",x.D); j+=2; break;
+ case 'd': sqlite3_snprintf(3, &z[j],"%02d",x.D); j+=2; break;
case 'f': {
- int s = x.s;
- int ms = (x.s - s)*1000.0;
- sprintf(&z[j],"%02d.%03d",s,ms);
+ double s = x.s;
+ if( s>59.999 ) s = 59.999;
+ sqlite3_snprintf(7, &z[j],"%06.3f", s);
j += strlen(&z[j]);
break;
}
- case 'H': sprintf(&z[j],"%02d",x.h); j+=2; break;
+ case 'H': sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; break;
case 'W': /* Fall thru */
case 'j': {
int nDay; /* Number of days since 1st day of year */
@@ -830,38 +864,41 @@ static void strftimeFunc(
y.M = 1;
y.D = 1;
computeJD(&y);
- nDay = x.rJD - y.rJD;
+ nDay = x.rJD - y.rJD + 0.5;
if( zFmt[i]=='W' ){
int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
wd = ((int)(x.rJD+0.5)) % 7;
- sprintf(&z[j],"%02d",(nDay+7-wd)/7);
+ sqlite3_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7);
j += 2;
}else{
- sprintf(&z[j],"%03d",nDay+1);
+ sqlite3_snprintf(4, &z[j],"%03d",nDay+1);
j += 3;
}
break;
}
- case 'J': sprintf(&z[j],"%.16g",x.rJD); j+=strlen(&z[j]); break;
- case 'm': sprintf(&z[j],"%02d",x.M); j+=2; break;
- case 'M': sprintf(&z[j],"%02d",x.m); j+=2; break;
+ case 'J': {
+ sqlite3_snprintf(20, &z[j],"%.16g",x.rJD);
+ j+=strlen(&z[j]);
+ break;
+ }
+ case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break;
+ case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break;
case 's': {
- sprintf(&z[j],"%d",(int)((x.rJD-2440587.5)*86400.0 + 0.5));
+ sqlite3_snprintf(30,&z[j],"%d",
+ (int)((x.rJD-2440587.5)*86400.0 + 0.5));
j += strlen(&z[j]);
break;
}
- case 'S': sprintf(&z[j],"%02d",(int)(x.s+0.5)); j+=2; break;
+ case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break;
case 'w': z[j++] = (((int)(x.rJD+1.5)) % 7) + '0'; break;
- case 'Y': sprintf(&z[j],"%04d",x.Y); j+=strlen(&z[j]); break;
- case '%': z[j++] = '%'; break;
+ case 'Y': sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=strlen(&z[j]);break;
+ default: z[j++] = '%'; break;
}
}
}
z[j] = 0;
- sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
- if( z!=zBuf ){
- sqliteFree(z);
- }
+ sqlite3_result_text(context, z, -1,
+ z==zBuf ? SQLITE_TRANSIENT : sqlite3_free);
}
/*
@@ -874,12 +911,7 @@ static void ctimeFunc(
int argc,
sqlite3_value **argv
){
- sqlite3_value *pVal = sqlite3ValueNew();
- if( pVal ){
- sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC);
- timeFunc(context, 1, &pVal);
- sqlite3ValueFree(pVal);
- }
+ timeFunc(context, 0, 0);
}
/*
@@ -892,12 +924,7 @@ static void cdateFunc(
int argc,
sqlite3_value **argv
){
- sqlite3_value *pVal = sqlite3ValueNew();
- if( pVal ){
- sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC);
- dateFunc(context, 1, &pVal);
- sqlite3ValueFree(pVal);
- }
+ dateFunc(context, 0, 0);
}
/*
@@ -910,12 +937,7 @@ static void ctimestampFunc(
int argc,
sqlite3_value **argv
){
- sqlite3_value *pVal = sqlite3ValueNew();
- if( pVal ){
- sqlite3ValueSetStr(pVal, -1, "now", SQLITE_UTF8, SQLITE_STATIC);
- datetimeFunc(context, 1, &pVal);
- sqlite3ValueFree(pVal);
- }
+ datetimeFunc(context, 0, 0);
}
#endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */
@@ -950,9 +972,21 @@ static void currentTimeFunc(
}
#endif
- sqlite3OsEnterMutex();
- strftime(zBuf, 20, zFormat, gmtime(&t));
- sqlite3OsLeaveMutex();
+#ifdef HAVE_GMTIME_R
+ {
+ struct tm sNow;
+ gmtime_r(&t, &sNow);
+ strftime(zBuf, 20, zFormat, &sNow);
+ }
+#else
+ {
+ struct tm *pTm;
+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+ pTm = gmtime(&t);
+ strftime(zBuf, 20, zFormat, pTm);
+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+ }
+#endif
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}
@@ -983,7 +1017,7 @@ void sqlite3RegisterDateTimeFunctions(sqlite3 *db){
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
- SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
+ SQLITE_UTF8, (void *)(db->pVfs), aFuncs[i].xFunc, 0, 0);
}
#else
static const struct {
diff --git a/ext/pdo_sqlite/sqlite/src/delete.c b/ext/pdo_sqlite/sqlite/src/delete.c
index ee1bc930b2..cace3b1915 100644
--- a/ext/pdo_sqlite/sqlite/src/delete.c
+++ b/ext/pdo_sqlite/sqlite/src/delete.c
@@ -26,8 +26,8 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
int i;
struct SrcList_item *pItem;
for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){
- pTab = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase);
- sqlite3DeleteTable(pParse->db, pItem->pTab);
+ pTab = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase);
+ sqlite3DeleteTable(pItem->pTab);
pItem->pTab = pTab;
if( pTab ){
pTab->nRef++;
@@ -75,10 +75,9 @@ void sqlite3OpenTable(
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, opcode, iCur, pTab->tnum);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
+ sqlite3VdbeAddOp3(v, opcode, iCur, pTab->tnum, iDb);
+ VdbeComment((v, "%s", pTab->zName));
+ sqlite3VdbeAddOp2(v, OP_SetNumColumns, iCur, pTab->nCol);
}
@@ -106,18 +105,24 @@ 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;
+ int iDb; /* Database number */
+ int memCnt = 0; /* Memory cell used for change counting */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to delete from a view */
int triggers_exist = 0; /* True if any triggers exist */
#endif
+ int iBeginAfterTrigger; /* Address of after trigger program */
+ int iEndAfterTrigger; /* Exit of after trigger program */
+ int iBeginBeforeTrigger; /* Address of before trigger program */
+ int iEndBeforeTrigger; /* Exit of before trigger program */
+ u32 old_col_mask = 0; /* Mask of OLD.* columns in use */
sContext.pParse = 0;
- if( pParse->nErr || sqlite3MallocFailed() ){
+ db = pParse->db;
+ if( pParse->nErr || db->mallocFailed ){
goto delete_from_cleanup;
}
- db = pParse->db;
assert( pTabList->nSrc==1 );
/* Locate the table which we want to delete. This table has to be
@@ -169,6 +174,9 @@ void sqlite3DeleteFrom(
*/
assert( pTabList->nSrc==1 );
iCur = pTabList->a[0].iCursor = pParse->nTab++;
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ pParse->nTab++;
+ }
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
@@ -191,12 +199,35 @@ void sqlite3DeleteFrom(
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, triggers_exist, iDb);
+ if( triggers_exist ){
+ int orconf = ((pParse->trigStack)?pParse->trigStack->orconf:OE_Default);
+ int iGoto = sqlite3VdbeAddOp0(v, OP_Goto);
+ addr = sqlite3VdbeMakeLabel(v);
+
+ iBeginBeforeTrigger = sqlite3VdbeCurrentAddr(v);
+ (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_BEFORE, pTab,
+ -1, oldIdx, orconf, addr, &old_col_mask, 0);
+ iEndBeforeTrigger = sqlite3VdbeAddOp0(v, OP_Goto);
+
+ iBeginAfterTrigger = sqlite3VdbeCurrentAddr(v);
+ (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1,
+ oldIdx, orconf, addr, &old_col_mask, 0);
+ iEndAfterTrigger = sqlite3VdbeAddOp0(v, OP_Goto);
+
+ sqlite3VdbeJumpHere(v, iGoto);
+ }
+
/* 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_EphemTab, iCur, 0, 0, 0, 0);
+ SelectDest dest;
+ Select *pView;
+
+ pView = sqlite3SelectDup(db, pTab->pSelect);
+ sqlite3SelectMask(pParse, pView, old_col_mask);
+ sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
+ sqlite3Select(pParse, pView, &dest, 0, 0, 0, 0);
sqlite3SelectDelete(pView);
}
@@ -204,7 +235,8 @@ void sqlite3DeleteFrom(
** we are counting rows.
*/
if( db->flags & SQLITE_CountRows ){
- sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
+ memCnt = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt);
}
/* Special case: A DELETE without a WHERE clause deletes everything.
@@ -215,25 +247,23 @@ void sqlite3DeleteFrom(
if( db->flags & SQLITE_CountRows ){
/* If counting rows deleted, just count the total number of
** entries in the table. */
- int endOfLoop = sqlite3VdbeMakeLabel(v);
int addr2;
if( !isView ){
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
}
- sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2);
- addr2 = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
- sqlite3VdbeAddOp(v, OP_Next, iCur, addr2);
- sqlite3VdbeResolveLabel(v, endOfLoop);
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
+ sqlite3VdbeAddOp2(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2);
+ addr2 = sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
+ sqlite3VdbeAddOp2(v, OP_Next, iCur, addr2);
+ sqlite3VdbeAddOp1(v, OP_Close, iCur);
}
if( !isView ){
- sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, iDb);
+ sqlite3VdbeAddOp2(v, OP_Clear, pTab->tnum, iDb);
if( !pParse->nested ){
- sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
+ sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
}
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pIdx->pSchema==pTab->pSchema );
- sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, iDb);
+ sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb);
}
}
}
@@ -241,17 +271,19 @@ void sqlite3DeleteFrom(
** the table and pick which records to delete.
*/
else{
+ int iRowid = ++pParse->nMem; /* Used for storing rowid values. */
+
/* Begin the database scan
*/
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0);
if( pWInfo==0 ) goto delete_from_cleanup;
/* Remember the rowid of every item to be deleted.
*/
- sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0);
- sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
+ sqlite3VdbeAddOp2(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, iRowid);
+ sqlite3VdbeAddOp1(v, OP_FifoWrite, iRowid);
if( db->flags & SQLITE_CountRows ){
- sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
+ sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
}
/* End the database scan loop.
@@ -261,8 +293,8 @@ void sqlite3DeleteFrom(
/* Open the pseudo-table used to store OLD if there are triggers.
*/
if( triggers_exist ){
- sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
+ sqlite3VdbeAddOp1(v, OP_OpenPseudo, oldIdx);
+ sqlite3VdbeAddOp2(v, OP_SetNumColumns, oldIdx, pTab->nCol);
}
/* Delete every item whose key was written to the list during the
@@ -271,52 +303,53 @@ void sqlite3DeleteFrom(
*/
end = sqlite3VdbeMakeLabel(v);
- /* This is the beginning of the delete loop when there are
- ** row triggers.
+ if( !isView ){
+ /* Open cursors for the table we are deleting from and
+ ** all its indices.
+ */
+ sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
+ }
+
+ /* This is the beginning of the delete loop. If a trigger encounters
+ ** an IGNORE constraint, it jumps back to here.
*/
if( triggers_exist ){
- addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
- if( !isView ){
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
- }
- sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
- sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
- sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
- sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0);
- if( !isView ){
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }
-
- (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_BEFORE, pTab,
- -1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
- addr);
+ sqlite3VdbeResolveLabel(v, addr);
}
+ addr = sqlite3VdbeAddOp2(v, OP_FifoRead, iRowid, end);
- if( !isView ){
- /* Open cursors for the table we are deleting from and all its
- ** indices. If there are row triggers, this happens inside the
- ** OP_FifoRead loop because the cursor have to all be closed
- ** before the trigger fires. If there are no row triggers, the
- ** cursors are opened only once on the outside the loop.
+ if( triggers_exist ){
+ int iData = ++pParse->nMem; /* For storing row data of OLD table */
+
+ /* If the record is no longer present in the table, jump to the
+ ** next iteration of the loop through the contents of the fifo.
*/
- sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
+ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, iRowid);
- /* This is the beginning of the delete loop when there are no
- ** row triggers */
- if( !triggers_exist ){
- addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
+ /* Populate the OLD.* pseudo-table */
+ if( old_col_mask ){
+ sqlite3VdbeAddOp2(v, OP_RowData, iCur, iData);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Null, 0, iData);
}
+ sqlite3VdbeAddOp3(v, OP_Insert, oldIdx, iData, iRowid);
+ /* Jump back and run the BEFORE triggers */
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginBeforeTrigger);
+ sqlite3VdbeJumpHere(v, iEndBeforeTrigger);
+ }
+
+ if( !isView ){
/* Delete the row */
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
+ const char *pVtab = (const char *)pTab->pVtab;
pParse->pVirtualLock = pTab;
- sqlite3VdbeOp3(v, OP_VUpdate, 0, 1, (const char*)pTab->pVtab, P3_VTAB);
+ sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, pVtab, P4_VTAB);
}else
#endif
{
- sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0);
+ sqlite3GenerateRowDelete(pParse, pTab, iCur, iRowid, pParse->nested==0);
}
}
@@ -324,27 +357,21 @@ void sqlite3DeleteFrom(
** the AFTER triggers
*/
if( triggers_exist ){
- if( !isView ){
- for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
- sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
- }
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }
- (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1,
- oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
- addr);
+ /* Jump back and run the AFTER triggers */
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginAfterTrigger);
+ sqlite3VdbeJumpHere(v, iEndAfterTrigger);
}
/* End of the delete loop */
- sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
sqlite3VdbeResolveLabel(v, end);
/* Close the cursors after the loop if there are no row triggers */
- if( !triggers_exist && !IsVirtual(pTab) ){
+ if( !isView && !IsVirtual(pTab) ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
- sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
+ sqlite3VdbeAddOp2(v, OP_Close, iCur + i, pIdx->tnum);
}
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
+ sqlite3VdbeAddOp1(v, OP_Close, iCur);
}
}
@@ -354,9 +381,9 @@ void sqlite3DeleteFrom(
** invoke the callback function.
*/
if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
- sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1);
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P4_STATIC);
}
delete_from_cleanup:
@@ -379,26 +406,29 @@ delete_from_cleanup:
** 2. Read/write cursors for all indices of pTab must be open as
** cursor number base+i for the i-th index.
**
-** 3. The record number of the row to be deleted must be on the top
-** of the stack.
+** 3. The record number of the row to be deleted must be stored in
+** memory cell iRowid.
**
** This routine pops the top of the stack to remove the record number
** and then generates code to remove both the table record and all index
** entries that point to that record.
*/
void sqlite3GenerateRowDelete(
- sqlite3 *db, /* The database containing the index */
- Vdbe *v, /* Generate code into this VDBE */
+ Parse *pParse, /* Parsing context */
Table *pTab, /* Table containing the row to be deleted */
int iCur, /* Cursor number for the table */
+ int iRowid, /* Memory cell that contains the rowid to delete */
int count /* Increment the row change counter */
){
int addr;
- addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
- sqlite3GenerateRowIndexDelete(v, pTab, iCur, 0);
- sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
+ Vdbe *v;
+
+ v = pParse->pVdbe;
+ addr = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowid);
+ sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, 0);
+ sqlite3VdbeAddOp2(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
if( count ){
- sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
+ sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
}
sqlite3VdbeJumpHere(v, addr);
}
@@ -420,19 +450,22 @@ void sqlite3GenerateRowDelete(
** deleted.
*/
void sqlite3GenerateRowIndexDelete(
- Vdbe *v, /* Generate code into this VDBE */
+ Parse *pParse, /* Parsing and code generating context */
Table *pTab, /* Table containing the row to be deleted */
int iCur, /* Cursor number for the table */
- char *aIdxUsed /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */
+ int *aRegIdx /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
){
int i;
Index *pIdx;
+ int r1;
+ r1 = sqlite3GetTempReg(pParse);
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
- if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue;
- sqlite3GenerateIndexKey(v, pIdx, iCur);
- sqlite3VdbeAddOp(v, OP_IdxDelete, iCur+i, 0);
+ if( aRegIdx!=0 && aRegIdx[i-1]==0 ) continue;
+ sqlite3GenerateIndexKey(pParse, pIdx, iCur, r1);
+ sqlite3VdbeAddOp2(pParse->pVdbe, OP_IdxDelete, iCur+i, r1);
}
+ sqlite3ReleaseTempReg(pParse, r1);
}
/*
@@ -440,25 +473,38 @@ void sqlite3GenerateRowIndexDelete(
** of the tack. The key with be for index pIdx which is an index on pTab.
** iCur is the index of a cursor open on the pTab table and pointing to
** the entry that needs indexing.
+**
+** Return a register number which is the first in a block of
+** registers that holds the elements of the index key. The
+** block of registers has already been deallocated by the time
+** this routine returns.
*/
-void sqlite3GenerateIndexKey(
- Vdbe *v, /* Generate code into this VDBE */
+int sqlite3GenerateIndexKey(
+ Parse *pParse, /* Parsing context */
Index *pIdx, /* The index for which to generate a key */
- int iCur /* Cursor number for the pIdx->pTable table */
+ int iCur, /* Cursor number for the pIdx->pTable table */
+ int regOut /* Write the new index key to this register */
){
+ Vdbe *v = pParse->pVdbe;
int j;
Table *pTab = pIdx->pTable;
+ int regBase;
+ int nCol;
- sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
- for(j=0; j<pIdx->nColumn; j++){
+ nCol = pIdx->nColumn;
+ regBase = sqlite3GetTempRange(pParse, nCol+1);
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regBase+nCol);
+ for(j=0; j<nCol; j++){
int idx = pIdx->aiColumn[j];
if( idx==pTab->iPKey ){
- sqlite3VdbeAddOp(v, OP_Dup, j, 0);
+ sqlite3VdbeAddOp2(v, OP_SCopy, regBase+nCol, regBase+j);
}else{
- sqlite3VdbeAddOp(v, OP_Column, iCur, idx);
+ sqlite3VdbeAddOp3(v, OP_Column, iCur, idx, regBase+j);
sqlite3ColumnDefault(v, pTab, idx);
}
}
- sqlite3VdbeAddOp(v, OP_MakeIdxRec, pIdx->nColumn, 0);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol+1, regOut);
sqlite3IndexAffinityStr(v, pIdx);
+ sqlite3ReleaseTempRange(pParse, regBase, nCol+1);
+ return regBase;
}
diff --git a/ext/pdo_sqlite/sqlite/src/expr.c b/ext/pdo_sqlite/sqlite/src/expr.c
index e26aba5b38..88db4dd232 100644
--- a/ext/pdo_sqlite/sqlite/src/expr.c
+++ b/ext/pdo_sqlite/sqlite/src/expr.c
@@ -35,9 +35,6 @@
*/
char sqlite3ExprAffinity(Expr *pExpr){
int op = pExpr->op;
- if( op==TK_AS ){
- return sqlite3ExprAffinity(pExpr->pLeft);
- }
if( op==TK_SELECT ){
return sqlite3ExprAffinity(pExpr->pSelect->pEList->a[0].pExpr);
}
@@ -50,14 +47,38 @@ char sqlite3ExprAffinity(Expr *pExpr){
}
/*
+** Set the collating sequence for expression pExpr to be the collating
+** sequence named by pToken. Return a pointer to the revised expression.
+** The collating sequence is marked as "explicit" using the EP_ExpCollate
+** flag. An explicit collating sequence will override implicit
+** collating sequences.
+*/
+Expr *sqlite3ExprSetColl(Parse *pParse, Expr *pExpr, Token *pName){
+ char *zColl = 0; /* Dequoted name of collation sequence */
+ CollSeq *pColl;
+ zColl = sqlite3NameFromToken(pParse->db, pName);
+ if( pExpr && zColl ){
+ pColl = sqlite3LocateCollSeq(pParse, zColl, -1);
+ if( pColl ){
+ pExpr->pColl = pColl;
+ pExpr->flags |= EP_ExpCollate;
+ }
+ }
+ sqlite3_free(zColl);
+ return pExpr;
+}
+
+/*
** Return the default collation sequence for the expression pExpr. If
** there is no default collation type, return 0.
*/
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
CollSeq *pColl = 0;
if( pExpr ){
+ int op;
pColl = pExpr->pColl;
- if( (pExpr->op==TK_AS || pExpr->op==TK_CAST) && !pColl ){
+ op = pExpr->op;
+ if( (op==TK_CAST || op==TK_UPLUS) && !pColl ){
return sqlite3ExprCollSeq(pParse, pExpr->pLeft);
}
}
@@ -113,7 +134,7 @@ static char comparisonAffinity(Expr *pExpr){
aff = sqlite3CompareAffinity(pExpr->pSelect->pEList->a[0].pExpr, aff);
}
else if( !aff ){
- aff = SQLITE_AFF_NUMERIC;
+ aff = SQLITE_AFF_NONE;
}
return aff;
}
@@ -137,15 +158,13 @@ int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){
}
/*
-** Return the P1 value that should be used for a binary comparison
+** Return the P5 value that should be used for a binary comparison
** opcode (OP_Eq, OP_Ge etc.) used to compare pExpr1 and pExpr2.
-** If jumpIfNull is true, then set the low byte of the returned
-** P1 value to tell the opcode to jump if either expression
-** evaluates to NULL.
*/
-static int binaryCompareP1(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
- char aff = sqlite3ExprAffinity(pExpr2);
- return ((int)sqlite3CompareAffinity(pExpr1, aff))+(jumpIfNull?0x100:0);
+static u8 binaryCompareP5(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
+ u8 aff = (char)sqlite3ExprAffinity(pExpr2);
+ aff = sqlite3CompareAffinity(pExpr1, aff) | jumpIfNull;
+ return aff;
}
/*
@@ -156,11 +175,28 @@ static int binaryCompareP1(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
** used. Otherwise the collation sequence for the right hand expression
** is used, or the default (BINARY) if neither expression has a collating
** type.
+**
+** Argument pRight (but not pLeft) may be a null pointer. In this case,
+** it is not considered.
*/
-static CollSeq* binaryCompareCollSeq(Parse *pParse, Expr *pLeft, Expr *pRight){
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pLeft);
- if( !pColl ){
- pColl = sqlite3ExprCollSeq(pParse, pRight);
+CollSeq *sqlite3BinaryCompareCollSeq(
+ Parse *pParse,
+ Expr *pLeft,
+ Expr *pRight
+){
+ CollSeq *pColl;
+ assert( pLeft );
+ if( pLeft->flags & EP_ExpCollate ){
+ assert( pLeft->pColl );
+ pColl = pLeft->pColl;
+ }else if( pRight && pRight->flags & EP_ExpCollate ){
+ assert( pRight->pColl );
+ pColl = pRight->pColl;
+ }else{
+ pColl = sqlite3ExprCollSeq(pParse, pLeft);
+ if( !pColl ){
+ pColl = sqlite3ExprCollSeq(pParse, pRight);
+ }
}
return pColl;
}
@@ -173,22 +209,36 @@ static int codeCompare(
Expr *pLeft, /* The left operand */
Expr *pRight, /* The right operand */
int opcode, /* The comparison opcode */
+ int in1, int in2, /* Register holding operands */
int dest, /* Jump here if true. */
int jumpIfNull /* If true, jump if either operand is NULL */
){
- int p1 = binaryCompareP1(pLeft, pRight, jumpIfNull);
- CollSeq *p3 = binaryCompareCollSeq(pParse, pLeft, pRight);
- return sqlite3VdbeOp3(pParse->pVdbe, opcode, p1, dest, (void*)p3, P3_COLLSEQ);
+ int p5;
+ int addr;
+ CollSeq *p4;
+
+ p4 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight);
+ p5 = binaryCompareP5(pLeft, pRight, jumpIfNull);
+ addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1,
+ (void*)p4, P4_COLLSEQ);
+ sqlite3VdbeChangeP5(pParse->pVdbe, p5);
+ return addr;
}
/*
** Construct a new expression node and return a pointer to it. Memory
-** for this node is obtained from sqliteMalloc(). The calling function
+** for this node is obtained from sqlite3_malloc(). The calling function
** is responsible for making sure the node eventually gets freed.
*/
-Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, const Token *pToken){
+Expr *sqlite3Expr(
+ sqlite3 *db, /* Handle for sqlite3DbMallocZero() (may be null) */
+ int op, /* Expression opcode */
+ Expr *pLeft, /* Left operand */
+ Expr *pRight, /* Right operand */
+ const Token *pToken /* Argument token */
+){
Expr *pNew;
- pNew = sqliteMalloc( sizeof(Expr) );
+ pNew = sqlite3DbMallocZero(db, sizeof(Expr));
if( pNew==0 ){
/* When malloc fails, delete pLeft and pRight. Expressions passed to
** this function must always be allocated with sqlite3Expr() for this
@@ -205,30 +255,42 @@ Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, const Token *pToken){
if( pToken ){
assert( pToken->dyn==0 );
pNew->span = pNew->token = *pToken;
- }else if( pLeft && pRight ){
- sqlite3ExprSpan(pNew, &pLeft->span, &pRight->span);
+ }else if( pLeft ){
+ if( pRight ){
+ sqlite3ExprSpan(pNew, &pLeft->span, &pRight->span);
+ if( pRight->flags & EP_ExpCollate ){
+ pNew->flags |= EP_ExpCollate;
+ pNew->pColl = pRight->pColl;
+ }
+ }
+ if( pLeft->flags & EP_ExpCollate ){
+ pNew->flags |= EP_ExpCollate;
+ pNew->pColl = pLeft->pColl;
+ }
}
+
+ sqlite3ExprSetHeight(pNew);
return pNew;
}
/*
-** Works like sqlite3Expr() but frees its pLeft and pRight arguments
-** if it fails due to a malloc problem.
+** Works like sqlite3Expr() except that it takes an extra Parse*
+** argument and notifies the associated connection object if malloc fails.
*/
-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;
+Expr *sqlite3PExpr(
+ Parse *pParse, /* Parsing context */
+ int op, /* Expression opcode */
+ Expr *pLeft, /* Left operand */
+ Expr *pRight, /* Right operand */
+ const Token *pToken /* Argument token */
+){
+ return sqlite3Expr(pParse->db, op, pLeft, pRight, pToken);
}
/*
** 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.
-** "#1" means the next down on the stack. And so forth.
+** that look like this: #1 #2 ... These terms refer to registers
+** in the virtual machine. #N is the N-th register.
**
** This routine is called by the parser to deal with on of those terms.
** It immediately generates code to store the value in a memory location.
@@ -238,20 +300,16 @@ Expr *sqlite3ExprOrFree(int op, Expr *pLeft, Expr *pRight, const Token *pToken){
Expr *sqlite3RegisterExpr(Parse *pParse, Token *pToken){
Vdbe *v = pParse->pVdbe;
Expr *p;
- int depth;
if( pParse->nested==0 ){
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", pToken);
- return 0;
+ return sqlite3PExpr(pParse, TK_NULL, 0, 0, 0);
}
if( v==0 ) return 0;
- p = sqlite3Expr(TK_REGISTER, 0, 0, pToken);
+ p = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, pToken);
if( p==0 ){
return 0; /* Malloc failed */
}
- depth = atoi((char*)&pToken->z[1]);
- p->iTable = pParse->nMem++;
- sqlite3VdbeAddOp(v, OP_Dup, depth, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, p->iTable, 1);
+ p->iTable = atoi((char*)&pToken->z[1]);
return p;
}
@@ -259,13 +317,13 @@ Expr *sqlite3RegisterExpr(Parse *pParse, Token *pToken){
** Join two expressions using an AND operator. If either expression is
** NULL, then just return the other expression.
*/
-Expr *sqlite3ExprAnd(Expr *pLeft, Expr *pRight){
+Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){
if( pLeft==0 ){
return pRight;
}else if( pRight==0 ){
return pLeft;
}else{
- return sqlite3Expr(TK_AND, pLeft, pRight, 0);
+ return sqlite3Expr(db, TK_AND, pLeft, pRight, 0);
}
}
@@ -276,7 +334,7 @@ Expr *sqlite3ExprAnd(Expr *pLeft, Expr *pRight){
void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
assert( pRight!=0 );
assert( pLeft!=0 );
- if( !sqlite3MallocFailed() && pRight->z && pLeft->z ){
+ if( pExpr && 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;
@@ -291,10 +349,10 @@ void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
** Construct a new expression node for a function with multiple
** arguments.
*/
-Expr *sqlite3ExprFunction(ExprList *pList, Token *pToken){
+Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){
Expr *pNew;
assert( pToken );
- pNew = sqliteMalloc( sizeof(Expr) );
+ pNew = sqlite3DbMallocZero(pParse->db, sizeof(Expr) );
if( pNew==0 ){
sqlite3ExprListDelete(pList); /* Avoid leaking memory when malloc fails */
return 0;
@@ -304,6 +362,8 @@ Expr *sqlite3ExprFunction(ExprList *pList, Token *pToken){
assert( pToken->dyn==0 );
pNew->token = *pToken;
pNew->span = pNew->token;
+
+ sqlite3ExprSetHeight(pNew);
return pNew;
}
@@ -325,6 +385,8 @@ Expr *sqlite3ExprFunction(ExprList *pList, Token *pToken){
*/
void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
Token *pToken;
+ sqlite3 *db = pParse->db;
+
if( pExpr==0 ) return;
pToken = &pExpr->token;
assert( pToken->n>=1 );
@@ -365,15 +427,22 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
pExpr->iTable = ++pParse->nVar;
if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){
pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10;
- sqliteReallocOrFree((void**)&pParse->apVarExpr,
- pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) );
+ pParse->apVarExpr =
+ sqlite3DbReallocOrFree(
+ db,
+ pParse->apVarExpr,
+ pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0])
+ );
}
- if( !sqlite3MallocFailed() ){
+ if( !db->mallocFailed ){
assert( pParse->apVarExpr!=0 );
pParse->apVarExpr[pParse->nVarExpr++] = pExpr;
}
}
}
+ if( !pParse->nErr && pParse->nVar>SQLITE_MAX_VARIABLE_NUMBER ){
+ sqlite3ErrorMsg(pParse, "too many SQL variables");
+ }
}
/*
@@ -381,26 +450,26 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
*/
void sqlite3ExprDelete(Expr *p){
if( p==0 ) return;
- if( p->span.dyn ) sqliteFree((char*)p->span.z);
- if( p->token.dyn ) sqliteFree((char*)p->token.z);
+ if( p->span.dyn ) sqlite3_free((char*)p->span.z);
+ if( p->token.dyn ) sqlite3_free((char*)p->token.z);
sqlite3ExprDelete(p->pLeft);
sqlite3ExprDelete(p->pRight);
sqlite3ExprListDelete(p->pList);
sqlite3SelectDelete(p->pSelect);
- sqliteFree(p);
+ sqlite3_free(p);
}
/*
** The Expr.token field might be a string literal that is quoted.
** If so, remove the quotation marks.
*/
-void sqlite3DequoteExpr(Expr *p){
+void sqlite3DequoteExpr(sqlite3 *db, Expr *p){
if( ExprHasAnyProperty(p, EP_Dequoted) ){
return;
}
ExprSetProperty(p, EP_Dequoted);
if( p->token.dyn==0 ){
- sqlite3TokenCopy(&p->token, &p->token);
+ sqlite3TokenCopy(db, &p->token, &p->token);
}
sqlite3Dequote((char*)p->token.z);
}
@@ -418,63 +487,63 @@ void sqlite3DequoteExpr(Expr *p){
**
** Any tables that the SrcList might point to are not duplicated.
*/
-Expr *sqlite3ExprDup(Expr *p){
+Expr *sqlite3ExprDup(sqlite3 *db, Expr *p){
Expr *pNew;
if( p==0 ) return 0;
- pNew = sqliteMallocRaw( sizeof(*p) );
+ pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
if( pNew==0 ) return 0;
memcpy(pNew, p, sizeof(*pNew));
if( p->token.z!=0 ){
- pNew->token.z = (u8*)sqliteStrNDup((char*)p->token.z, p->token.n);
+ pNew->token.z = (u8*)sqlite3DbStrNDup(db, (char*)p->token.z, p->token.n);
pNew->token.dyn = 1;
}else{
assert( pNew->token.z==0 );
}
pNew->span.z = 0;
- pNew->pLeft = sqlite3ExprDup(p->pLeft);
- pNew->pRight = sqlite3ExprDup(p->pRight);
- pNew->pList = sqlite3ExprListDup(p->pList);
- pNew->pSelect = sqlite3SelectDup(p->pSelect);
- pNew->pTab = p->pTab;
+ pNew->pLeft = sqlite3ExprDup(db, p->pLeft);
+ pNew->pRight = sqlite3ExprDup(db, p->pRight);
+ pNew->pList = sqlite3ExprListDup(db, p->pList);
+ pNew->pSelect = sqlite3SelectDup(db, p->pSelect);
return pNew;
}
-void sqlite3TokenCopy(Token *pTo, Token *pFrom){
- if( pTo->dyn ) sqliteFree((char*)pTo->z);
+void sqlite3TokenCopy(sqlite3 *db, Token *pTo, Token *pFrom){
+ if( pTo->dyn ) sqlite3_free((char*)pTo->z);
if( pFrom->z ){
pTo->n = pFrom->n;
- pTo->z = (u8*)sqliteStrNDup((char*)pFrom->z, pFrom->n);
+ pTo->z = (u8*)sqlite3DbStrNDup(db, (char*)pFrom->z, pFrom->n);
pTo->dyn = 1;
}else{
pTo->z = 0;
}
}
-ExprList *sqlite3ExprListDup(ExprList *p){
+ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p){
ExprList *pNew;
struct ExprList_item *pItem, *pOldItem;
int i;
if( p==0 ) return 0;
- pNew = sqliteMalloc( sizeof(*pNew) );
+ pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
if( pNew==0 ) return 0;
+ pNew->iECursor = 0;
pNew->nExpr = pNew->nAlloc = p->nExpr;
- pNew->a = pItem = sqliteMalloc( p->nExpr*sizeof(p->a[0]) );
+ pNew->a = pItem = sqlite3DbMallocRaw(db, p->nExpr*sizeof(p->a[0]) );
if( pItem==0 ){
- sqliteFree(pNew);
+ sqlite3_free(pNew);
return 0;
}
pOldItem = p->a;
for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
Expr *pNewExpr, *pOldExpr;
- pItem->pExpr = pNewExpr = sqlite3ExprDup(pOldExpr = pOldItem->pExpr);
+ pItem->pExpr = pNewExpr = sqlite3ExprDup(db, pOldExpr = pOldItem->pExpr);
if( pOldExpr->span.z!=0 && pNewExpr ){
/* Always make a copy of the span for top-level expressions in the
** expression list. The logic in SELECT processing that determines
** the names of columns in the result set needs this information */
- sqlite3TokenCopy(&pNewExpr->span, &pOldExpr->span);
+ sqlite3TokenCopy(db, &pNewExpr->span, &pOldExpr->span);
}
assert( pNewExpr==0 || pNewExpr->span.z!=0
|| pOldExpr->span.z==0
- || sqlite3MallocFailed() );
- pItem->zName = sqliteStrDup(pOldItem->zName);
+ || db->mallocFailed );
+ pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pItem->sortOrder = pOldItem->sortOrder;
pItem->isAgg = pOldItem->isAgg;
pItem->done = 0;
@@ -490,22 +559,22 @@ ExprList *sqlite3ExprListDup(ExprList *p){
*/
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \
|| !defined(SQLITE_OMIT_SUBQUERY)
-SrcList *sqlite3SrcListDup(SrcList *p){
+SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p){
SrcList *pNew;
int i;
int nByte;
if( p==0 ) return 0;
nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0);
- pNew = sqliteMallocRaw( nByte );
+ pNew = sqlite3DbMallocRaw(db, nByte );
if( pNew==0 ) return 0;
pNew->nSrc = pNew->nAlloc = p->nSrc;
for(i=0; i<p->nSrc; i++){
struct SrcList_item *pNewItem = &pNew->a[i];
struct SrcList_item *pOldItem = &p->a[i];
Table *pTab;
- pNewItem->zDatabase = sqliteStrDup(pOldItem->zDatabase);
- pNewItem->zName = sqliteStrDup(pOldItem->zName);
- pNewItem->zAlias = sqliteStrDup(pOldItem->zAlias);
+ pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
+ pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
+ pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
pNewItem->jointype = pOldItem->jointype;
pNewItem->iCursor = pOldItem->iCursor;
pNewItem->isPopulated = pOldItem->isPopulated;
@@ -513,49 +582,49 @@ SrcList *sqlite3SrcListDup(SrcList *p){
if( pTab ){
pTab->nRef++;
}
- pNewItem->pSelect = sqlite3SelectDup(pOldItem->pSelect);
- pNewItem->pOn = sqlite3ExprDup(pOldItem->pOn);
- pNewItem->pUsing = sqlite3IdListDup(pOldItem->pUsing);
+ pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect);
+ pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn);
+ pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing);
pNewItem->colUsed = pOldItem->colUsed;
}
return pNew;
}
-IdList *sqlite3IdListDup(IdList *p){
+IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
IdList *pNew;
int i;
if( p==0 ) return 0;
- pNew = sqliteMallocRaw( sizeof(*pNew) );
+ pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
if( pNew==0 ) return 0;
pNew->nId = pNew->nAlloc = p->nId;
- pNew->a = sqliteMallocRaw( p->nId*sizeof(p->a[0]) );
+ pNew->a = sqlite3DbMallocRaw(db, p->nId*sizeof(p->a[0]) );
if( pNew->a==0 ){
- sqliteFree(pNew);
+ sqlite3_free(pNew);
return 0;
}
for(i=0; i<p->nId; i++){
struct IdList_item *pNewItem = &pNew->a[i];
struct IdList_item *pOldItem = &p->a[i];
- pNewItem->zName = sqliteStrDup(pOldItem->zName);
+ pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pNewItem->idx = pOldItem->idx;
}
return pNew;
}
-Select *sqlite3SelectDup(Select *p){
+Select *sqlite3SelectDup(sqlite3 *db, Select *p){
Select *pNew;
if( p==0 ) return 0;
- pNew = sqliteMallocRaw( sizeof(*p) );
+ pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
if( pNew==0 ) return 0;
pNew->isDistinct = p->isDistinct;
- pNew->pEList = sqlite3ExprListDup(p->pEList);
- pNew->pSrc = sqlite3SrcListDup(p->pSrc);
- pNew->pWhere = sqlite3ExprDup(p->pWhere);
- pNew->pGroupBy = sqlite3ExprListDup(p->pGroupBy);
- pNew->pHaving = sqlite3ExprDup(p->pHaving);
- pNew->pOrderBy = sqlite3ExprListDup(p->pOrderBy);
+ pNew->pEList = sqlite3ExprListDup(db, p->pEList);
+ pNew->pSrc = sqlite3SrcListDup(db, p->pSrc);
+ pNew->pWhere = sqlite3ExprDup(db, p->pWhere);
+ pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy);
+ pNew->pHaving = sqlite3ExprDup(db, p->pHaving);
+ pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy);
pNew->op = p->op;
- pNew->pPrior = sqlite3SelectDup(p->pPrior);
- pNew->pLimit = sqlite3ExprDup(p->pLimit);
- pNew->pOffset = sqlite3ExprDup(p->pOffset);
+ pNew->pPrior = sqlite3SelectDup(db, p->pPrior);
+ pNew->pLimit = sqlite3ExprDup(db, p->pLimit);
+ pNew->pOffset = sqlite3ExprDup(db, p->pOffset);
pNew->iLimit = -1;
pNew->iOffset = -1;
pNew->isResolved = p->isResolved;
@@ -569,7 +638,7 @@ Select *sqlite3SelectDup(Select *p){
return pNew;
}
#else
-Select *sqlite3SelectDup(Select *p){
+Select *sqlite3SelectDup(sqlite3 *db, Select *p){
assert( p==0 );
return 0;
}
@@ -580,9 +649,15 @@ Select *sqlite3SelectDup(Select *p){
** Add a new element to the end of an expression list. If pList is
** initially NULL, then create a new expression list.
*/
-ExprList *sqlite3ExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){
+ExprList *sqlite3ExprListAppend(
+ Parse *pParse, /* Parsing context */
+ ExprList *pList, /* List to which to append. Might be NULL */
+ Expr *pExpr, /* Expression to be appended */
+ Token *pName /* AS keyword for the expression */
+){
+ sqlite3 *db = pParse->db;
if( pList==0 ){
- pList = sqliteMalloc( sizeof(ExprList) );
+ pList = sqlite3DbMallocZero(db, sizeof(ExprList) );
if( pList==0 ){
goto no_mem;
}
@@ -591,7 +666,7 @@ ExprList *sqlite3ExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){
if( pList->nAlloc<=pList->nExpr ){
struct ExprList_item *a;
int n = pList->nAlloc*2 + 4;
- a = sqliteRealloc(pList->a, n*sizeof(pList->a[0]));
+ a = sqlite3DbRealloc(db, pList->a, n*sizeof(pList->a[0]));
if( a==0 ){
goto no_mem;
}
@@ -602,7 +677,7 @@ ExprList *sqlite3ExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){
if( pExpr || pName ){
struct ExprList_item *pItem = &pList->a[pList->nExpr++];
memset(pItem, 0, sizeof(*pItem));
- pItem->zName = sqlite3NameFromToken(pName);
+ pItem->zName = sqlite3NameFromToken(db, pName);
pItem->pExpr = pExpr;
}
return pList;
@@ -615,6 +690,87 @@ no_mem:
}
/*
+** If the expression list pEList contains more than iLimit elements,
+** leave an error message in pParse.
+*/
+void sqlite3ExprListCheckLength(
+ Parse *pParse,
+ ExprList *pEList,
+ int iLimit,
+ const char *zObject
+){
+ if( pEList && pEList->nExpr>iLimit ){
+ sqlite3ErrorMsg(pParse, "too many columns in %s", zObject);
+ }
+}
+
+
+#if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0
+/* The following three functions, heightOfExpr(), heightOfExprList()
+** and heightOfSelect(), are used to determine the maximum height
+** of any expression tree referenced by the structure passed as the
+** first argument.
+**
+** If this maximum height is greater than the current value pointed
+** to by pnHeight, the second parameter, then set *pnHeight to that
+** value.
+*/
+static void heightOfExpr(Expr *p, int *pnHeight){
+ if( p ){
+ if( p->nHeight>*pnHeight ){
+ *pnHeight = p->nHeight;
+ }
+ }
+}
+static void heightOfExprList(ExprList *p, int *pnHeight){
+ if( p ){
+ int i;
+ for(i=0; i<p->nExpr; i++){
+ heightOfExpr(p->a[i].pExpr, pnHeight);
+ }
+ }
+}
+static void heightOfSelect(Select *p, int *pnHeight){
+ if( p ){
+ heightOfExpr(p->pWhere, pnHeight);
+ heightOfExpr(p->pHaving, pnHeight);
+ heightOfExpr(p->pLimit, pnHeight);
+ heightOfExpr(p->pOffset, pnHeight);
+ heightOfExprList(p->pEList, pnHeight);
+ heightOfExprList(p->pGroupBy, pnHeight);
+ heightOfExprList(p->pOrderBy, pnHeight);
+ heightOfSelect(p->pPrior, pnHeight);
+ }
+}
+
+/*
+** Set the Expr.nHeight variable in the structure passed as an
+** argument. An expression with no children, Expr.pList or
+** Expr.pSelect member has a height of 1. Any other expression
+** has a height equal to the maximum height of any other
+** referenced Expr plus one.
+*/
+void sqlite3ExprSetHeight(Expr *p){
+ int nHeight = 0;
+ heightOfExpr(p->pLeft, &nHeight);
+ heightOfExpr(p->pRight, &nHeight);
+ heightOfExprList(p->pList, &nHeight);
+ heightOfSelect(p->pSelect, &nHeight);
+ p->nHeight = nHeight + 1;
+}
+
+/*
+** Return the maximum height of any expression tree referenced
+** by the select statement passed as an argument.
+*/
+int sqlite3SelectExprHeight(Select *p){
+ int nHeight = 0;
+ heightOfSelect(p, &nHeight);
+ return nHeight;
+}
+#endif
+
+/*
** Delete an entire expression list.
*/
void sqlite3ExprListDelete(ExprList *pList){
@@ -625,10 +781,10 @@ void sqlite3ExprListDelete(ExprList *pList){
assert( pList->nExpr<=pList->nAlloc );
for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
sqlite3ExprDelete(pItem->pExpr);
- sqliteFree(pItem->zName);
+ sqlite3_free(pItem->zName);
}
- sqliteFree(pList->a);
- sqliteFree(pList);
+ sqlite3_free(pList->a);
+ sqlite3_free(pList);
}
/*
@@ -681,6 +837,9 @@ static int walkSelectExpr(Select *p, int (*xFunc)(void *, Expr*), void *pArg){
walkExprList(p->pGroupBy, xFunc, pArg);
walkExprTree(p->pHaving, xFunc, pArg);
walkExprList(p->pOrderBy, xFunc, pArg);
+ if( p->pPrior ){
+ walkSelectExpr(p->pPrior, xFunc, pArg);
+ }
return 0;
}
@@ -699,11 +858,21 @@ static int walkSelectExpr(Select *p, int (*xFunc)(void *, Expr*), void *pArg){
** is constant. See sqlite3ExprIsConstant() for additional information.
*/
static int exprNodeIsConstant(void *pArg, Expr *pExpr){
+ int *pN = (int*)pArg;
+
+ /* If *pArg is 3 then any term of the expression that comes from
+ ** the ON or USING clauses of a join disqualifies the expression
+ ** from being considered constant. */
+ if( (*pN)==3 && ExprHasAnyProperty(pExpr, EP_FromJoin) ){
+ *pN = 0;
+ return 2;
+ }
+
switch( pExpr->op ){
/* Consider functions to be constant if all their arguments are constant
** and *pArg==2 */
case TK_FUNCTION:
- if( *((int*)pArg)==2 ) return 0;
+ if( (*pN)==2 ) return 0;
/* Fall through */
case TK_ID:
case TK_COLUMN:
@@ -714,11 +883,11 @@ static int exprNodeIsConstant(void *pArg, Expr *pExpr){
case TK_SELECT:
case TK_EXISTS:
#endif
- *((int*)pArg) = 0;
+ *pN = 0;
return 2;
case TK_IN:
if( pExpr->pSelect ){
- *((int*)pArg) = 0;
+ *pN = 0;
return 2;
}
default:
@@ -742,6 +911,18 @@ int sqlite3ExprIsConstant(Expr *p){
/*
** Walk an expression tree. Return 1 if the expression is constant
+** that does no originate from the ON or USING clauses of a join.
+** Return 0 if it involves variables or function calls or terms from
+** an ON or USING clause.
+*/
+int sqlite3ExprIsConstantNotJoin(Expr *p){
+ int isConst = 3;
+ walkExprTree(p, exprNodeIsConstant, &isConst);
+ return isConst!=0;
+}
+
+/*
+** Walk an expression tree. Return 1 if the expression is constant
** or a function call with constant arguments. Return and 0 if there
** are any variables.
**
@@ -838,12 +1019,13 @@ static int lookupName(
struct SrcList_item *pItem; /* Use for looping over pSrcList items */
struct SrcList_item *pMatch = 0; /* The matching pSrcList item */
NameContext *pTopNC = pNC; /* First namecontext in the list */
+ Schema *pSchema = 0; /* Schema of the expression */
assert( pColumnToken && pColumnToken->z ); /* The Z in X.Y.Z cannot be NULL */
- zDb = sqlite3NameFromToken(pDbToken);
- zTab = sqlite3NameFromToken(pTableToken);
- zCol = sqlite3NameFromToken(pColumnToken);
- if( sqlite3MallocFailed() ){
+ zDb = sqlite3NameFromToken(db, pDbToken);
+ zTab = sqlite3NameFromToken(db, pTableToken);
+ zCol = sqlite3NameFromToken(db, pColumnToken);
+ if( db->mallocFailed ){
goto lookupname_end;
}
@@ -876,7 +1058,7 @@ static int lookupName(
}
if( 0==(cntTab++) ){
pExpr->iTable = pItem->iCursor;
- pExpr->pSchema = pTab->pSchema;
+ pSchema = pTab->pSchema;
pMatch = pItem;
}
for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
@@ -886,27 +1068,30 @@ static int lookupName(
cnt++;
pExpr->iTable = pItem->iCursor;
pMatch = pItem;
- pExpr->pSchema = pTab->pSchema;
+ 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 = 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 */
- pItem++;
- i++;
+ if( (pExpr->flags & EP_ExpCollate)==0 ){
+ pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
}
- if( (pUsing = pItem->pUsing)!=0 ){
- /* If this match occurs on a column that is in the USING clause
- ** of a join, skip the search of the right table of the join
- ** to avoid a duplicate match there. */
- int k;
- for(k=0; k<pUsing->nId; k++){
- if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ){
- pItem++;
- i++;
- break;
+ if( i<pSrcList->nSrc-1 ){
+ if( pItem[1].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 */
+ pItem++;
+ i++;
+ }else if( (pUsing = pItem[1].pUsing)!=0 ){
+ /* If this match occurs on a column that is in the USING clause
+ ** of a join, skip the search of the right table of the join
+ ** to avoid a duplicate match there. */
+ int k;
+ for(k=0; k<pUsing->nId; k++){
+ if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ){
+ pItem++;
+ i++;
+ break;
+ }
}
}
}
@@ -923,21 +1108,24 @@ static int lookupName(
if( zDb==0 && zTab!=0 && cnt==0 && pParse->trigStack!=0 ){
TriggerStack *pTriggerStack = pParse->trigStack;
Table *pTab = 0;
+ u32 *piColMask;
if( pTriggerStack->newIdx != -1 && sqlite3StrICmp("new", zTab) == 0 ){
pExpr->iTable = pTriggerStack->newIdx;
assert( pTriggerStack->pTab );
pTab = pTriggerStack->pTab;
+ piColMask = &(pTriggerStack->newColMask);
}else if( pTriggerStack->oldIdx != -1 && sqlite3StrICmp("old", zTab)==0 ){
pExpr->iTable = pTriggerStack->oldIdx;
assert( pTriggerStack->pTab );
pTab = pTriggerStack->pTab;
+ piColMask = &(pTriggerStack->oldColMask);
}
if( pTab ){
int iCol;
Column *pCol = pTab->aCol;
- pExpr->pSchema = pTab->pSchema;
+ pSchema = pTab->pSchema;
cntTab++;
for(iCol=0; iCol < pTab->nCol; iCol++, pCol++) {
if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
@@ -945,8 +1133,13 @@ static int lookupName(
cnt++;
pExpr->iColumn = iCol==pTab->iPKey ? -1 : iCol;
pExpr->affinity = pTab->aCol[iCol].affinity;
- pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
+ if( (pExpr->flags & EP_ExpCollate)==0 ){
+ pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
+ }
pExpr->pTab = pTab;
+ if( iCol>=0 ){
+ *piColMask |= ((u32)1<<iCol) | (iCol>=32?0xffffffff:0);
+ }
break;
}
}
@@ -979,11 +1172,27 @@ static int lookupName(
for(j=0; j<pEList->nExpr; j++){
char *zAs = pEList->a[j].zName;
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
+ Expr *pDup, *pOrig;
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
- pExpr->op = TK_AS;
- pExpr->iColumn = j;
- pExpr->pLeft = sqlite3ExprDup(pEList->a[j].pExpr);
+ assert( pExpr->pList==0 );
+ assert( pExpr->pSelect==0 );
+ pOrig = pEList->a[j].pExpr;
+ if( !pNC->allowAgg && ExprHasProperty(pOrig, EP_Agg) ){
+ sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
+ sqlite3_free(zCol);
+ return 2;
+ }
+ pDup = sqlite3ExprDup(db, pOrig);
+ if( pExpr->flags & EP_ExpCollate ){
+ pDup->pColl = pExpr->pColl;
+ pDup->flags |= EP_ExpCollate;
+ }
+ if( pExpr->span.dyn ) sqlite3_free((char*)pExpr->span.z);
+ if( pExpr->token.dyn ) sqlite3_free((char*)pExpr->token.z);
+ memcpy(pExpr, pDup, sizeof(*pExpr));
+ sqlite3_free(pDup);
cnt = 1;
+ pMatch = 0;
assert( zTab==0 && zDb==0 );
goto lookupname_end_2;
}
@@ -1009,7 +1218,7 @@ static int lookupName(
** fields are not changed in any context.
*/
if( cnt==0 && zTab==0 && pColumnToken->z[0]=='"' ){
- sqliteFree(zCol);
+ sqlite3_free(zCol);
return 0;
}
@@ -1018,18 +1227,15 @@ static int lookupName(
** more matches. Either way, we have an error.
*/
if( cnt!=1 ){
- char *z = 0;
- char *zErr;
- zErr = cnt==0 ? "no such column: %s" : "ambiguous column name: %s";
+ const char *zErr;
+ zErr = cnt==0 ? "no such column" : "ambiguous column name";
if( zDb ){
- sqlite3SetString(&z, zDb, ".", zTab, ".", zCol, (char*)0);
+ sqlite3ErrorMsg(pParse, "%s: %s.%s.%s", zErr, zDb, zTab, zCol);
}else if( zTab ){
- sqlite3SetString(&z, zTab, ".", zCol, (char*)0);
+ sqlite3ErrorMsg(pParse, "%s: %s.%s", zErr, zTab, zCol);
}else{
- z = sqliteStrDup(zCol);
+ sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol);
}
- sqlite3ErrorMsg(pParse, zErr, z);
- sqliteFree(z);
pTopNC->nErr++;
}
@@ -1045,24 +1251,24 @@ static int lookupName(
n = sizeof(Bitmask)*8-1;
}
assert( pMatch->iCursor==pExpr->iTable );
- pMatch->colUsed |= 1<<n;
+ pMatch->colUsed |= ((Bitmask)1)<<n;
}
lookupname_end:
/* Clean up and return
*/
- sqliteFree(zDb);
- sqliteFree(zTab);
+ sqlite3_free(zDb);
+ sqlite3_free(zTab);
sqlite3ExprDelete(pExpr->pLeft);
pExpr->pLeft = 0;
sqlite3ExprDelete(pExpr->pRight);
pExpr->pRight = 0;
pExpr->op = TK_COLUMN;
lookupname_end_2:
- sqliteFree(zCol);
+ sqlite3_free(zCol);
if( cnt==1 ){
assert( pNC!=0 );
- sqlite3AuthRead(pParse, pExpr, pNC->pSrcList);
+ sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList);
if( pMatch && !pMatch->pSelect ){
pExpr->pTab = pMatch->pTab;
}
@@ -1161,6 +1367,7 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
int wrong_num_args = 0; /* True if wrong number of arguments */
int is_agg = 0; /* True if is an aggregate function */
int i;
+ int auth; /* Authorization to use the function */
int nId; /* Number of characters in function name */
const char *zId; /* The function name. */
FuncDef *pDef; /* Information about the function */
@@ -1179,6 +1386,20 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
}else{
is_agg = pDef->xFunc==0;
}
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ if( pDef ){
+ auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0);
+ if( auth!=SQLITE_OK ){
+ if( auth==SQLITE_DENY ){
+ sqlite3ErrorMsg(pParse, "not authorized to use function: %s",
+ pDef->zName);
+ pNC->nErr++;
+ }
+ pExpr->op = TK_NULL;
+ return 1;
+ }
+ }
+#endif
if( is_agg && !pNC->allowAgg ){
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
pNC->nErr++;
@@ -1258,15 +1479,28 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
** If the expression contains aggregate functions then set the EP_Agg
** property on the expression.
*/
-int sqlite3ExprResolveNames(
+int sqlite3ExprResolveNames(
NameContext *pNC, /* Namespace to resolve expressions in. */
Expr *pExpr /* The expression to be analyzed. */
){
int savedHasAgg;
if( pExpr==0 ) return 0;
+#if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0
+ if( (pExpr->nHeight+pNC->pParse->nHeight)>SQLITE_MAX_EXPR_DEPTH ){
+ sqlite3ErrorMsg(pNC->pParse,
+ "Expression tree is too large (maximum depth %d)",
+ SQLITE_MAX_EXPR_DEPTH
+ );
+ return 1;
+ }
+ pNC->pParse->nHeight += pExpr->nHeight;
+#endif
savedHasAgg = pNC->hasAgg;
pNC->hasAgg = 0;
walkExprTree(pExpr, nameResolverStep, pNC);
+#if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0
+ pNC->pParse->nHeight -= pExpr->nHeight;
+#endif
if( pNC->nErr>0 ){
ExprSetProperty(pExpr, EP_Error);
}
@@ -1288,6 +1522,143 @@ struct QueryCoder {
NameContext *pNC; /* Namespace of first enclosing query */
};
+#ifdef SQLITE_TEST
+ int sqlite3_enable_in_opt = 1;
+#else
+ #define sqlite3_enable_in_opt 1
+#endif
+
+/*
+** This function is used by the implementation of the IN (...) operator.
+** It's job is to find or create a b-tree structure that may be used
+** either to test for membership of the (...) set or to iterate through
+** its members, skipping duplicates.
+**
+** The cursor opened on the structure (database table, database index
+** or ephermal table) is stored in pX->iTable before this function returns.
+** The returned value indicates the structure type, as follows:
+**
+** IN_INDEX_ROWID - The cursor was opened on a database table.
+** IN_INDEX_INDEX - The cursor was opened on a database index.
+** IN_INDEX_EPH - The cursor was opened on a specially created and
+** populated epheremal table.
+**
+** An existing structure may only be used if the SELECT is of the simple
+** form:
+**
+** SELECT <column> FROM <table>
+**
+** If the mustBeUnique parameter is false, the structure will be used
+** for fast set membership tests. In this case an epheremal table must
+** be used unless <column> is an INTEGER PRIMARY KEY or an index can
+** be found with <column> as its left-most column.
+**
+** If mustBeUnique is true, then the structure will be used to iterate
+** through the set members, skipping any duplicates. In this case an
+** epheremal table must be used unless the selected <column> is guaranteed
+** to be unique - either because it is an INTEGER PRIMARY KEY or it
+** is unique by virtue of a constraint or implicit index.
+*/
+#ifndef SQLITE_OMIT_SUBQUERY
+int sqlite3FindInIndex(Parse *pParse, Expr *pX, int mustBeUnique){
+ Select *p;
+ int eType = 0;
+ int iTab = pParse->nTab++;
+
+ /* The follwing if(...) expression is true if the SELECT is of the
+ ** simple form:
+ **
+ ** SELECT <column> FROM <table>
+ **
+ ** If this is the case, it may be possible to use an existing table
+ ** or index instead of generating an epheremal table.
+ */
+ if( sqlite3_enable_in_opt
+ && (p=pX->pSelect) && !p->pPrior
+ && !p->isDistinct && !p->isAgg && !p->pGroupBy
+ && p->pSrc && p->pSrc->nSrc==1 && !p->pSrc->a[0].pSelect
+ && !p->pSrc->a[0].pTab->pSelect
+ && p->pEList->nExpr==1 && p->pEList->a[0].pExpr->op==TK_COLUMN
+ && !p->pLimit && !p->pOffset && !p->pWhere
+ ){
+ sqlite3 *db = pParse->db;
+ Index *pIdx;
+ Expr *pExpr = p->pEList->a[0].pExpr;
+ int iCol = pExpr->iColumn;
+ Vdbe *v = sqlite3GetVdbe(pParse);
+
+ /* This function is only called from two places. In both cases the vdbe
+ ** has already been allocated. So assume sqlite3GetVdbe() is always
+ ** successful here.
+ */
+ assert(v);
+ if( iCol<0 ){
+ int iMem = ++pParse->nMem;
+ int iAddr;
+ Table *pTab = p->pSrc->a[0].pTab;
+ int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ sqlite3VdbeUsesBtree(v, iDb);
+
+ iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem);
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem);
+
+ sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
+ eType = IN_INDEX_ROWID;
+
+ sqlite3VdbeJumpHere(v, iAddr);
+ }else{
+ /* The collation sequence used by the comparison. If an index is to
+ ** be used in place of a temp-table, it must be ordered according
+ ** to this collation sequence.
+ */
+ CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pExpr);
+
+ /* Check that the affinity that will be used to perform the
+ ** comparison is the same as the affinity of the column. If
+ ** it is not, it is not possible to use any index.
+ */
+ Table *pTab = p->pSrc->a[0].pTab;
+ char aff = comparisonAffinity(pX);
+ int affinity_ok = (pTab->aCol[iCol].affinity==aff||aff==SQLITE_AFF_NONE);
+
+ for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){
+ if( (pIdx->aiColumn[0]==iCol)
+ && (pReq==sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], -1, 0))
+ && (!mustBeUnique || (pIdx->nColumn==1 && pIdx->onError!=OE_None))
+ ){
+ int iDb;
+ int iMem = ++pParse->nMem;
+ int iAddr;
+ char *pKey;
+
+ pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx);
+ iDb = sqlite3SchemaToIndex(db, pIdx->pSchema);
+ sqlite3VdbeUsesBtree(v, iDb);
+
+ iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem);
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem);
+
+ sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
+ pKey,P4_KEYINFO_HANDOFF);
+ VdbeComment((v, "%s", pIdx->zName));
+ eType = IN_INDEX_INDEX;
+ sqlite3VdbeAddOp2(v, OP_SetNumColumns, iTab, pIdx->nColumn);
+
+ sqlite3VdbeJumpHere(v, iAddr);
+ }
+ }
+ }
+ }
+
+ if( eType==0 ){
+ sqlite3CodeSubselect(pParse, pX);
+ eType = IN_INDEX_EPH;
+ }else{
+ pX->iTable = iTab;
+ }
+ return eType;
+}
+#endif
/*
** Generate code for scalar subqueries used as an expression
@@ -1307,6 +1678,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
Vdbe *v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
+
/* This code must be run in its entirety every time it is encountered
** if any of the following is true:
**
@@ -1318,11 +1690,10 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
** save the results, and reuse the same result on subsequent invocations.
*/
if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->trigStack ){
- int mem = pParse->nMem++;
- sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0);
- testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0);
- assert( testAddr>0 || sqlite3MallocFailed() );
- sqlite3VdbeAddOp(v, OP_MemInt, 1, mem);
+ int mem = ++pParse->nMem;
+ sqlite3VdbeAddOp1(v, OP_If, mem);
+ testAddr = sqlite3VdbeAddOp2(v, OP_Integer, 1, mem);
+ assert( testAddr>0 || pParse->db->mallocFailed );
}
switch( pExpr->op ){
@@ -1347,10 +1718,10 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
** is used.
*/
pExpr->iTable = pParse->nTab++;
- addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, pExpr->iTable, 0);
+ addr = sqlite3VdbeAddOp1(v, OP_OpenEphemeral, pExpr->iTable);
memset(&keyInfo, 0, sizeof(keyInfo));
keyInfo.nField = 1;
- sqlite3VdbeAddOp(v, OP_SetNumColumns, pExpr->iTable, 1);
+ sqlite3VdbeAddOp2(v, OP_SetNumColumns, pExpr->iTable, 1);
if( pExpr->pSelect ){
/* Case 1: expr IN (SELECT ...)
@@ -1358,19 +1729,24 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
** Generate code to write the results of the select into the temporary
** table allocated and opened above.
*/
- int iParm = pExpr->iTable + (((int)affinity)<<16);
+ SelectDest dest;
ExprList *pEList;
+
+ sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
+ dest.affinity = (int)affinity;
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
- sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0);
+ if( sqlite3Select(pParse, pExpr->pSelect, &dest, 0, 0, 0, 0) ){
+ return;
+ }
pEList = pExpr->pSelect->pEList;
if( pEList && pEList->nExpr>0 ){
- keyInfo.aColl[0] = binaryCompareCollSeq(pParse, pExpr->pLeft,
+ keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
pEList->a[0].pExpr);
}
}else if( pExpr->pList ){
/* Case 2: expr IN (exprlist)
**
- ** For each expression, build an index key from the evaluation and
+ ** For each expression, build an index key from the evaluation and
** store it in the temporary table. If <expr> is a column, then use
** that columns affinity when building index keys. If <expr> is not
** a column, use numeric affinity.
@@ -1378,6 +1754,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
int i;
ExprList *pList = pExpr->pList;
struct ExprList_item *pItem;
+ int r1, r2;
if( !affinity ){
affinity = SQLITE_AFF_NONE;
@@ -1385,6 +1762,8 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
keyInfo.aColl[0] = pExpr->pLeft->pColl;
/* Loop through each expression in <exprlist>. */
+ r1 = sqlite3GetTempReg(pParse);
+ r2 = sqlite3GetTempReg(pParse);
for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
Expr *pE2 = pItem->pExpr;
@@ -1393,18 +1772,20 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
** this code only executes once. Because for a non-constant
** expression we need to rerun this code each time.
*/
- if( testAddr>0 && !sqlite3ExprIsConstant(pE2) ){
- sqlite3VdbeChangeToNoop(v, testAddr-1, 3);
+ if( testAddr && !sqlite3ExprIsConstant(pE2) ){
+ sqlite3VdbeChangeToNoop(v, testAddr-1, 2);
testAddr = 0;
}
/* Evaluate the expression and insert it into the temp table */
- sqlite3ExprCode(pParse, pE2);
- sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1);
- sqlite3VdbeAddOp(v, OP_IdxInsert, pExpr->iTable, 0);
+ sqlite3ExprCode(pParse, pE2, r1);
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2);
}
+ sqlite3ReleaseTempReg(pParse, r1);
+ sqlite3ReleaseTempReg(pParse, r2);
}
- sqlite3VdbeChangeP3(v, addr, (void *)&keyInfo, P3_KEYINFO);
+ sqlite3VdbeChangeP4(v, addr, (void *)&keyInfo, P4_KEYINFO);
break;
}
@@ -1416,80 +1797,169 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
*/
static const Token one = { (u8*)"1", 0, 1 };
Select *pSel;
- int iMem;
- int sop;
+ SelectDest dest;
- pExpr->iColumn = iMem = pParse->nMem++;
pSel = pExpr->pSelect;
+ sqlite3SelectDestInit(&dest, 0, ++pParse->nMem);
if( pExpr->op==TK_SELECT ){
- sop = SRT_Mem;
- sqlite3VdbeAddOp(v, OP_MemNull, iMem, 0);
- VdbeComment((v, "# Init subquery result"));
+ dest.eDest = SRT_Mem;
+ sqlite3VdbeAddOp2(v, OP_Null, 0, dest.iParm);
+ VdbeComment((v, "Init subquery result"));
}else{
- sop = SRT_Exists;
- sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem);
- VdbeComment((v, "# Init EXISTS result"));
+ dest.eDest = SRT_Exists;
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iParm);
+ VdbeComment((v, "Init EXISTS result"));
}
sqlite3ExprDelete(pSel->pLimit);
- pSel->pLimit = sqlite3Expr(TK_INTEGER, 0, 0, &one);
- sqlite3Select(pParse, pSel, sop, iMem, 0, 0, 0, 0);
+ pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &one);
+ if( sqlite3Select(pParse, pSel, &dest, 0, 0, 0, 0) ){
+ return;
+ }
+ pExpr->iColumn = dest.iParm;
break;
}
}
if( testAddr ){
- sqlite3VdbeJumpHere(v, testAddr);
+ sqlite3VdbeJumpHere(v, testAddr-1);
}
+
return;
}
#endif /* SQLITE_OMIT_SUBQUERY */
/*
+** Duplicate an 8-byte value
+*/
+static char *dup8bytes(Vdbe *v, const char *in){
+ char *out = sqlite3DbMallocRaw(sqlite3VdbeDb(v), 8);
+ if( out ){
+ memcpy(out, in, 8);
+ }
+ return out;
+}
+
+/*
+** Generate an instruction that will put the floating point
+** value described by z[0..n-1] into register iMem.
+**
+** The z[] string will probably not be zero-terminated. But the
+** z[n] character is guaranteed to be something that does not look
+** like the continuation of the number.
+*/
+static void codeReal(Vdbe *v, const char *z, int n, int negateFlag, int iMem){
+ assert( z || v==0 || sqlite3VdbeDb(v)->mallocFailed );
+ if( z ){
+ double value;
+ char *zV;
+ assert( !isdigit(z[n]) );
+ sqlite3AtoF(z, &value);
+ if( negateFlag ) value = -value;
+ zV = dup8bytes(v, (char*)&value);
+ sqlite3VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL);
+ }
+}
+
+
+/*
** Generate an instruction that will put the integer describe by
-** text z[0..n-1] on the stack.
+** text z[0..n-1] into register iMem.
+**
+** The z[] string will probably not be zero-terminated. But the
+** z[n] character is guaranteed to be something that does not look
+** like the continuation of the number.
*/
-static void codeInteger(Vdbe *v, const char *z, int n){
- int i;
- if( sqlite3GetInt32(z, &i) ){
- sqlite3VdbeAddOp(v, OP_Integer, i, 0);
- }else if( sqlite3FitsIn64Bits(z) ){
- sqlite3VdbeOp3(v, OP_Int64, 0, 0, z, n);
+static void codeInteger(Vdbe *v, const char *z, int n, int negFlag, int iMem){
+ assert( z || v==0 || sqlite3VdbeDb(v)->mallocFailed );
+ if( z ){
+ int i;
+ assert( !isdigit(z[n]) );
+ if( sqlite3GetInt32(z, &i) ){
+ if( negFlag ) i = -i;
+ sqlite3VdbeAddOp2(v, OP_Integer, i, iMem);
+ }else if( sqlite3FitsIn64Bits(z, negFlag) ){
+ i64 value;
+ char *zV;
+ sqlite3Atoi64(z, &value);
+ if( negFlag ) value = -value;
+ zV = dup8bytes(v, (char*)&value);
+ sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
+ }else{
+ codeReal(v, z, n, negFlag, iMem);
+ }
+ }
+}
+
+
+/*
+** Generate code that will extract the iColumn-th column from
+** table pTab and store the column value in register iReg.
+** There is an open cursor to pTab in
+** iTable. If iColumn<0 then code is generated that extracts the rowid.
+*/
+void sqlite3ExprCodeGetColumn(
+ Vdbe *v, /* The VM being created */
+ Table *pTab, /* Description of the table we are reading from */
+ int iColumn, /* Index of the table column */
+ int iTable, /* The cursor pointing to the table */
+ int iReg /* Store results here */
+){
+ if( iColumn<0 ){
+ int op = (pTab && IsVirtual(pTab)) ? OP_VRowid : OP_Rowid;
+ sqlite3VdbeAddOp2(v, op, iTable, iReg);
+ }else if( pTab==0 ){
+ sqlite3VdbeAddOp3(v, OP_Column, iTable, iColumn, iReg);
}else{
- sqlite3VdbeOp3(v, OP_Real, 0, 0, z, n);
+ int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
+ sqlite3VdbeAddOp3(v, op, iTable, iColumn, iReg);
+ sqlite3ColumnDefault(v, pTab, iColumn);
+#ifndef SQLITE_OMIT_FLOATING_POINT
+ if( pTab->aCol[iColumn].affinity==SQLITE_AFF_REAL ){
+ sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
+ }
+#endif
}
}
/*
** Generate code into the current Vdbe to evaluate the given
-** expression and leave the result on the top of stack.
+** expression. Attempt to store the results in register "target".
+** Return the register where results are stored.
**
-** This code depends on the fact that certain token values (ex: TK_EQ)
-** are the same as opcode values (ex: OP_Eq) that implement the corresponding
-** operation. Special comments in vdbe.c and the mkopcodeh.awk script in
-** the make process cause these values to align. Assert()s in the code
-** below verify that the numbers are aligned correctly.
+** With this routine, there is no guaranteed that results will
+** be stored in target. The result might be stored in some other
+** register if it is convenient to do so. The calling function
+** must check the return code and move the results to the desired
+** register.
*/
-void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
- Vdbe *v = pParse->pVdbe;
- int op;
- int stackChng = 1; /* Amount of change to stack depth */
+static int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
+ Vdbe *v = pParse->pVdbe; /* The VM under construction */
+ int op; /* The opcode being coded */
+ int inReg = target; /* Results stored in register inReg */
+ int regFree1 = 0; /* If non-zero free this temporary register */
+ int regFree2 = 0; /* If non-zero free this temporary register */
+ int r1, r2, r3; /* Various register numbers */
+
+ assert( v!=0 || pParse->db->mallocFailed );
+ assert( target>0 && target<=pParse->nMem );
+ if( v==0 ) return 0;
- if( v==0 ) return;
if( pExpr==0 ){
- sqlite3VdbeAddOp(v, OP_Null, 0, 0);
- return;
+ op = TK_NULL;
+ }else{
+ op = pExpr->op;
}
- op = pExpr->op;
switch( op ){
case TK_AGG_COLUMN: {
AggInfo *pAggInfo = pExpr->pAggInfo;
struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
if( !pAggInfo->directMode ){
- sqlite3VdbeAddOp(v, OP_MemLoad, pCol->iMem, 0);
+ assert( pCol->iMem>0 );
+ inReg = pCol->iMem;
break;
}else if( pAggInfo->useSortingIdx ){
- sqlite3VdbeAddOp(v, OP_Column, pAggInfo->sortingIdx,
- pCol->iSorterColumn);
+ sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdx,
+ pCol->iSorterColumn, target);
break;
}
/* Otherwise, fall thru into the TK_COLUMN case */
@@ -1497,73 +1967,64 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
case TK_COLUMN: {
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
+ assert( pParse->ckBase>0 );
+ inReg = pExpr->iColumn + pParse->ckBase;
}else{
- Table *pTab = pExpr->pTab;
- int op = (pTab && IsVirtual(pTab)) ? OP_VRowid : OP_Rowid;
- sqlite3VdbeAddOp(v, op, pExpr->iTable, 0);
+ sqlite3ExprCodeGetColumn(v, pExpr->pTab,
+ pExpr->iColumn, pExpr->iTable, target);
}
break;
}
case TK_INTEGER: {
- codeInteger(v, (char*)pExpr->token.z, pExpr->token.n);
+ codeInteger(v, (char*)pExpr->token.z, pExpr->token.n, 0, target);
+ break;
+ }
+ case TK_FLOAT: {
+ codeReal(v, (char*)pExpr->token.z, pExpr->token.n, 0, target);
break;
}
- case TK_FLOAT:
case TK_STRING: {
- assert( TK_FLOAT==OP_Real );
- assert( TK_STRING==OP_String8 );
- sqlite3DequoteExpr(pExpr);
- sqlite3VdbeOp3(v, op, 0, 0, (char*)pExpr->token.z, pExpr->token.n);
+ sqlite3DequoteExpr(pParse->db, pExpr);
+ sqlite3VdbeAddOp4(v,OP_String8, 0, target, 0,
+ (char*)pExpr->token.z, pExpr->token.n);
break;
}
case TK_NULL: {
- sqlite3VdbeAddOp(v, OP_Null, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, target);
break;
}
#ifndef SQLITE_OMIT_BLOB_LITERAL
case TK_BLOB: {
int n;
const char *z;
- assert( TK_BLOB==OP_HexBlob );
+ char *zBlob;
+ assert( pExpr->token.n>=3 );
+ assert( pExpr->token.z[0]=='x' || pExpr->token.z[0]=='X' );
+ assert( pExpr->token.z[1]=='\'' );
+ assert( pExpr->token.z[pExpr->token.n-1]=='\'' );
n = pExpr->token.n - 3;
z = (char*)pExpr->token.z + 2;
- assert( n>=0 );
- if( n==0 ){
- z = "";
- }
- sqlite3VdbeOp3(v, op, 0, 0, z, n);
+ zBlob = sqlite3HexToBlob(sqlite3VdbeDb(v), z, n);
+ sqlite3VdbeAddOp4(v, OP_Blob, n/2, target, 0, zBlob, P4_DYNAMIC);
break;
}
#endif
case TK_VARIABLE: {
- sqlite3VdbeAddOp(v, OP_Variable, pExpr->iTable, 0);
+ sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iTable, target);
if( pExpr->token.n>1 ){
- sqlite3VdbeChangeP3(v, -1, (char*)pExpr->token.z, pExpr->token.n);
+ sqlite3VdbeChangeP4(v, -1, (char*)pExpr->token.z, pExpr->token.n);
}
break;
}
case TK_REGISTER: {
- sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iTable, 0);
+ inReg = pExpr->iTable;
break;
}
#ifndef SQLITE_OMIT_CAST
case TK_CAST: {
/* Expressions of the form: CAST(pLeft AS token) */
int aff, to_op;
- sqlite3ExprCode(pParse, pExpr->pLeft);
+ inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
aff = sqlite3AffinityType(&pExpr->token);
to_op = aff - SQLITE_AFF_TEXT + OP_ToText;
assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT );
@@ -1571,8 +2032,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
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;
+ sqlite3VdbeAddOp1(v, to_op, inReg);
break;
}
#endif /* SQLITE_OMIT_CAST */
@@ -1588,10 +2048,10 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
assert( TK_GE==OP_Ge );
assert( TK_EQ==OP_Eq );
assert( TK_NE==OP_Ne );
- sqlite3ExprCode(pParse, pExpr->pLeft);
- sqlite3ExprCode(pParse, pExpr->pRight);
- codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0);
- stackChng = -1;
+ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
+ codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
+ r1, r2, inReg, SQLITE_STOREP2);
break;
}
case TK_AND:
@@ -1617,10 +2077,9 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
assert( TK_LSHIFT==OP_ShiftLeft );
assert( TK_RSHIFT==OP_ShiftRight );
assert( TK_CONCAT==OP_Concat );
- sqlite3ExprCode(pParse, pExpr->pLeft);
- sqlite3ExprCode(pParse, pExpr->pRight);
- sqlite3VdbeAddOp(v, op, 0, 0);
- stackChng = -1;
+ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
+ sqlite3VdbeAddOp3(v, op, r2, r1, target);
break;
}
case TK_UMINUS: {
@@ -1628,37 +2087,38 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
assert( pLeft );
if( pLeft->op==TK_FLOAT || pLeft->op==TK_INTEGER ){
Token *p = &pLeft->token;
- char *z = sqlite3MPrintf("-%.*s", p->n, p->z);
if( pLeft->op==TK_FLOAT ){
- sqlite3VdbeOp3(v, OP_Real, 0, 0, z, p->n+1);
+ codeReal(v, (char*)p->z, p->n, 1, target);
}else{
- codeInteger(v, z, p->n+1);
+ codeInteger(v, (char*)p->z, p->n, 1, target);
}
- sqliteFree(z);
- break;
+ }else{
+ regFree1 = r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, r1);
+ r2 = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
+ sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target);
}
- /* Fall through into TK_NOT */
+ inReg = target;
+ break;
}
case TK_BITNOT:
case TK_NOT: {
assert( TK_BITNOT==OP_BitNot );
assert( TK_NOT==OP_Not );
- sqlite3ExprCode(pParse, pExpr->pLeft);
- sqlite3VdbeAddOp(v, op, 0, 0);
- stackChng = 0;
+ inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
+ sqlite3VdbeAddOp1(v, op, inReg);
break;
}
case TK_ISNULL:
case TK_NOTNULL: {
- int dest;
+ int addr;
assert( TK_ISNULL==OP_IsNull );
assert( TK_NOTNULL==OP_NotNull );
- sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
- sqlite3ExprCode(pParse, pExpr->pLeft);
- dest = sqlite3VdbeCurrentAddr(v) + 2;
- sqlite3VdbeAddOp(v, op, 1, dest);
- sqlite3VdbeAddOp(v, OP_AddImm, -1, 0);
- stackChng = 0;
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, target);
+ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ addr = sqlite3VdbeAddOp1(v, op, r1);
+ sqlite3VdbeAddOp2(v, OP_AddImm, target, -1);
+ sqlite3VdbeJumpHere(v, addr);
break;
}
case TK_AGG_FUNCTION: {
@@ -1667,7 +2127,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
sqlite3ErrorMsg(pParse, "misuse of aggregate: %T",
&pExpr->span);
}else{
- sqlite3VdbeAddOp(v, OP_MemLoad, pInfo->aFunc[pExpr->iAgg].iMem, 0);
+ inReg = pInfo->aFunc[pExpr->iAgg].iMem;
}
break;
}
@@ -1680,13 +2140,21 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
const char *zId;
int constMask = 0;
int i;
- u8 enc = ENC(pParse->db);
+ sqlite3 *db = pParse->db;
+ u8 enc = ENC(db);
CollSeq *pColl = 0;
+
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);
+ if( pList ){
+ nExpr = pList->nExpr;
+ r1 = sqlite3GetTempRange(pParse, nExpr);
+ sqlite3ExprCodeExprList(pParse, pList, r1);
+ }else{
+ nExpr = r1 = 0;
+ }
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Possibly overload the function if the first argument is
** a virtual table column.
@@ -1701,9 +2169,9 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
** 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);
+ pDef = sqlite3VtabOverloadFunction(db, pDef, nExpr, pList->a[1].pExpr);
}else if( nExpr>0 ){
- pDef = sqlite3VtabOverloadFunction(pDef, nExpr, pList->a[0].pExpr);
+ pDef = sqlite3VtabOverloadFunction(db, pDef, nExpr, pList->a[0].pExpr);
}
#endif
for(i=0; i<nExpr && i<32; i++){
@@ -1716,10 +2184,14 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
}
if( pDef->needCollSeq ){
if( !pColl ) pColl = pParse->db->pDfltColl;
- sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ);
+ sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
+ }
+ sqlite3VdbeAddOp4(v, OP_Function, constMask, r1, target,
+ (char*)pDef, P4_FUNCDEF);
+ sqlite3VdbeChangeP5(v, nExpr);
+ if( nExpr ){
+ sqlite3ReleaseTempRange(pParse, r1, nExpr);
}
- sqlite3VdbeOp3(v, OP_Function, constMask, nExpr, (char*)pDef, P3_FUNCDEF);
- stackChng = 1-nExpr;
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
@@ -1728,70 +2200,116 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
if( pExpr->iColumn==0 ){
sqlite3CodeSubselect(pParse, pExpr);
}
- sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0);
- VdbeComment((v, "# load subquery result"));
+ inReg = pExpr->iColumn;
break;
}
case TK_IN: {
- int addr;
+ int j1, j2, j3, j4, j5;
char affinity;
- int ckOffset = pParse->ckOffset;
- sqlite3CodeSubselect(pParse, pExpr);
+ int eType;
+
+ eType = sqlite3FindInIndex(pParse, pExpr, 0);
/* Figure out the affinity to use to create a key from the results
** of the expression. affinityStr stores a static string suitable for
- ** P3 of OP_MakeRecord.
+ ** P4 of OP_MakeRecord.
*/
affinity = comparisonAffinity(pExpr);
- sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
- pParse->ckOffset = ckOffset+1;
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, target);
/* Code the <expr> from "<expr> IN (...)". The temporary table
** pExpr->iTable contains the values that make up the (...) set.
*/
- sqlite3ExprCode(pParse, pExpr->pLeft);
- addr = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeAddOp(v, OP_NotNull, -1, addr+4); /* addr + 0 */
- sqlite3VdbeAddOp(v, OP_Pop, 2, 0);
- sqlite3VdbeAddOp(v, OP_Null, 0, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, addr+7);
- sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1); /* addr + 4 */
- sqlite3VdbeAddOp(v, OP_Found, pExpr->iTable, addr+7);
- sqlite3VdbeAddOp(v, OP_AddImm, -1, 0); /* addr + 6 */
-
+ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ j1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, target);
+ j2 = sqlite3VdbeAddOp0(v, OP_Goto);
+ sqlite3VdbeJumpHere(v, j1);
+ if( eType==IN_INDEX_ROWID ){
+ j3 = sqlite3VdbeAddOp3(v, OP_MustBeInt, r1, 0, 1);
+ j4 = sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, 0, r1);
+ j5 = sqlite3VdbeAddOp0(v, OP_Goto);
+ sqlite3VdbeJumpHere(v, j3);
+ sqlite3VdbeJumpHere(v, j4);
+ }else{
+ r2 = regFree2 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1);
+ j5 = sqlite3VdbeAddOp3(v, OP_Found, pExpr->iTable, 0, r2);
+ }
+ sqlite3VdbeAddOp2(v, OP_AddImm, target, -1);
+ sqlite3VdbeJumpHere(v, j2);
+ sqlite3VdbeJumpHere(v, j5);
break;
}
#endif
+ /*
+ ** x BETWEEN y AND z
+ **
+ ** This is equivalent to
+ **
+ ** x>=y AND x<=z
+ **
+ ** X is stored in pExpr->pLeft.
+ ** Y is stored in pExpr->pList->a[0].pExpr.
+ ** Z is stored in pExpr->pList->a[1].pExpr.
+ */
case TK_BETWEEN: {
Expr *pLeft = pExpr->pLeft;
struct ExprList_item *pLItem = pExpr->pList->a;
Expr *pRight = pLItem->pExpr;
- sqlite3ExprCode(pParse, pLeft);
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- sqlite3ExprCode(pParse, pRight);
- codeCompare(pParse, pLeft, pRight, OP_Ge, 0, 0);
- sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
+
+ r1 = sqlite3ExprCodeTemp(pParse, pLeft, &regFree1);
+ r2 = sqlite3ExprCodeTemp(pParse, pRight, &regFree2);
+ r3 = sqlite3GetTempReg(pParse);
+ codeCompare(pParse, pLeft, pRight, OP_Ge,
+ r1, r2, r3, SQLITE_STOREP2);
pLItem++;
pRight = pLItem->pExpr;
- sqlite3ExprCode(pParse, pRight);
- codeCompare(pParse, pLeft, pRight, OP_Le, 0, 0);
- sqlite3VdbeAddOp(v, OP_And, 0, 0);
+ sqlite3ReleaseTempReg(pParse, regFree2);
+ r2 = sqlite3ExprCodeTemp(pParse, pRight, &regFree2);
+ codeCompare(pParse, pLeft, pRight, OP_Le, r1, r2, r2, SQLITE_STOREP2);
+ sqlite3VdbeAddOp3(v, OP_And, r3, r2, target);
+ sqlite3ReleaseTempReg(pParse, r3);
break;
}
- case TK_UPLUS:
- case TK_AS: {
- sqlite3ExprCode(pParse, pExpr->pLeft);
- stackChng = 0;
+ case TK_UPLUS: {
+ inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
break;
}
+
+ /*
+ ** Form A:
+ ** CASE x WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END
+ **
+ ** Form B:
+ ** CASE WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END
+ **
+ ** Form A is can be transformed into the equivalent form B as follows:
+ ** CASE WHEN x=e1 THEN r1 WHEN x=e2 THEN r2 ...
+ ** WHEN x=eN THEN rN ELSE y END
+ **
+ ** X (if it exists) is in pExpr->pLeft.
+ ** Y is in pExpr->pRight. The Y is also optional. If there is no
+ ** ELSE clause and no other term matches, then the result of the
+ ** exprssion is NULL.
+ ** Ei is in pExpr->pList->a[i*2] and Ri is pExpr->pList->a[i*2+1].
+ **
+ ** The result of the expression is the Ri for the first matching Ei,
+ ** or if there is no matching Ei, the ELSE term Y, or if there is
+ ** no ELSE term, NULL.
+ */
case TK_CASE: {
- int expr_end_label;
- int jumpInst;
- int nExpr;
- int i;
- ExprList *pEList;
- struct ExprList_item *aListelem;
+ int endLabel; /* GOTO label for end of CASE stmt */
+ int nextCase; /* GOTO label for next WHEN clause */
+ int nExpr; /* 2x number of WHEN terms */
+ int i; /* Loop counter */
+ ExprList *pEList; /* List of WHEN terms */
+ struct ExprList_item *aListelem; /* Array of WHEN terms */
+ Expr opCompare; /* The X==Ei expression */
+ Expr cacheX; /* Cached expression X */
+ Expr *pX; /* The X expression */
+ Expr *pTest; /* X==Ei (form A) or just Ei (form B) */
assert(pExpr->pList);
assert((pExpr->pList->nExpr % 2) == 0);
@@ -1799,33 +2317,33 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
pEList = pExpr->pList;
aListelem = pEList->a;
nExpr = pEList->nExpr;
- expr_end_label = sqlite3VdbeMakeLabel(v);
- if( pExpr->pLeft ){
- sqlite3ExprCode(pParse, pExpr->pLeft);
+ endLabel = sqlite3VdbeMakeLabel(v);
+ if( (pX = pExpr->pLeft)!=0 ){
+ cacheX = *pX;
+ cacheX.iTable = sqlite3ExprCodeTemp(pParse, pX, &regFree1);
+ cacheX.op = TK_REGISTER;
+ opCompare.op = TK_EQ;
+ opCompare.pLeft = &cacheX;
+ pTest = &opCompare;
}
for(i=0; i<nExpr; i=i+2){
- sqlite3ExprCode(pParse, aListelem[i].pExpr);
- if( pExpr->pLeft ){
- sqlite3VdbeAddOp(v, OP_Dup, 1, 1);
- jumpInst = codeCompare(pParse, pExpr->pLeft, aListelem[i].pExpr,
- OP_Ne, 0, 1);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
+ if( pX ){
+ opCompare.pRight = aListelem[i].pExpr;
}else{
- jumpInst = sqlite3VdbeAddOp(v, OP_IfNot, 1, 0);
+ pTest = aListelem[i].pExpr;
}
- sqlite3ExprCode(pParse, aListelem[i+1].pExpr);
- sqlite3VdbeAddOp(v, OP_Goto, 0, expr_end_label);
- sqlite3VdbeJumpHere(v, jumpInst);
- }
- if( pExpr->pLeft ){
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
+ nextCase = sqlite3VdbeMakeLabel(v);
+ sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL);
+ sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel);
+ sqlite3VdbeResolveLabel(v, nextCase);
}
if( pExpr->pRight ){
- sqlite3ExprCode(pParse, pExpr->pRight);
+ sqlite3ExprCode(pParse, pExpr->pRight, target);
}else{
- sqlite3VdbeAddOp(v, OP_Null, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, target);
}
- sqlite3VdbeResolveLabel(v, expr_end_label);
+ sqlite3VdbeResolveLabel(v, endLabel);
break;
}
#ifndef SQLITE_OMIT_TRIGGER
@@ -1833,76 +2351,118 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
if( !pParse->trigStack ){
sqlite3ErrorMsg(pParse,
"RAISE() may only be used within a trigger-program");
- return;
+ return 0;
}
if( pExpr->iColumn!=OE_Ignore ){
assert( pExpr->iColumn==OE_Rollback ||
pExpr->iColumn == OE_Abort ||
pExpr->iColumn == OE_Fail );
- sqlite3DequoteExpr(pExpr);
- sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn,
+ sqlite3DequoteExpr(pParse->db, pExpr);
+ sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn, 0,
(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)"));
+ sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->trigStack->ignoreJump);
+ VdbeComment((v, "raise(IGNORE)"));
}
- stackChng = 0;
break;
}
#endif
}
+ sqlite3ReleaseTempReg(pParse, regFree1);
+ sqlite3ReleaseTempReg(pParse, regFree2);
+ return inReg;
+}
- if( pParse->ckOffset ){
- pParse->ckOffset += stackChng;
- assert( pParse->ckOffset );
+/*
+** Generate code to evaluate an expression and store the results
+** into a register. Return the register number where the results
+** are stored.
+**
+** If the register is a temporary register that can be deallocated,
+** then write its number into *pReg. If the result register is no
+** a temporary, then set *pReg to zero.
+*/
+int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
+ int r1 = sqlite3GetTempReg(pParse);
+ int r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
+ if( r2==r1 ){
+ *pReg = r1;
+ }else{
+ sqlite3ReleaseTempReg(pParse, r1);
+ *pReg = 0;
}
+ return r2;
+}
+
+/*
+** Generate code that will evaluate expression pExpr and store the
+** results in register target. The results are guaranteed to appear
+** in register target.
+*/
+int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
+ int inReg;
+
+ assert( target>0 && target<=pParse->nMem );
+ inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
+ assert( pParse->pVdbe || pParse->db->mallocFailed );
+ if( inReg!=target && pParse->pVdbe ){
+ sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
+ }
+ return target;
}
-#ifndef SQLITE_OMIT_TRIGGER
/*
-** Generate code that evalutes the given expression and leaves the result
-** on the stack. See also sqlite3ExprCode().
+** Generate code that evalutes the given expression and puts the result
+** in register target.
+**
+** Also make a copy of the expression results into another "cache" register
+** and modify the expression so that the next time it is evaluated,
+** the result is a copy of the cache register.
**
-** This routine might also cache the result and modify the pExpr tree
-** so that it will make use of the cached result on subsequent evaluations
-** rather than evaluate the whole expression again. Trivial expressions are
-** not cached. If the expression is cached, its result is stored in a
-** memory location.
+** This routine is used for expressions that are used multiple
+** times. They are evaluated once and the results of the expression
+** are reused.
*/
-void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr){
+int sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
Vdbe *v = pParse->pVdbe;
- int iMem;
- int addr1, addr2;
- if( v==0 ) return;
- addr1 = sqlite3VdbeCurrentAddr(v);
- sqlite3ExprCode(pParse, pExpr);
- addr2 = sqlite3VdbeCurrentAddr(v);
- if( addr2>addr1+1 || sqlite3VdbeGetOp(v, addr1)->opcode==OP_Function ){
- iMem = pExpr->iTable = pParse->nMem++;
- sqlite3VdbeAddOp(v, OP_MemStore, iMem, 0);
+ int inReg;
+ inReg = sqlite3ExprCode(pParse, pExpr, target);
+ assert( target>0 );
+ if( pExpr->op!=TK_REGISTER ){
+ int iMem;
+ iMem = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Copy, inReg, iMem);
+ pExpr->iTable = iMem;
pExpr->op = TK_REGISTER;
}
+ return inReg;
}
-#endif
+
/*
** Generate code that pushes the value of every element of the given
-** expression list onto the stack.
+** expression list into a sequence of registers beginning at target.
**
-** Return the number of elements pushed onto the stack.
+** Return the number of elements evaluated.
*/
int sqlite3ExprCodeExprList(
Parse *pParse, /* Parsing context */
- ExprList *pList /* The expression list to be coded */
+ ExprList *pList, /* The expression list to be coded */
+ int target /* Where to write results */
){
struct ExprList_item *pItem;
int i, n;
- if( pList==0 ) return 0;
+ assert( pList!=0 || pParse->db->mallocFailed );
+ if( pList==0 ){
+ return 0;
+ }
+ assert( target>0 );
n = pList->nExpr;
for(pItem=pList->a, i=n; i>0; i--, pItem++){
- sqlite3ExprCode(pParse, pItem->pExpr);
+ sqlite3ExprCode(pParse, pItem->pExpr, target);
+ target++;
}
return n;
}
@@ -1913,7 +2473,7 @@ int sqlite3ExprCodeExprList(
** continues straight thru if the expression is false.
**
** If the expression evaluates to NULL (neither true nor false), then
-** take the jump if the jumpIfNull flag is true.
+** take the jump if the jumpIfNull flag is SQLITE_JUMPIFNULL.
**
** This code depends on the fact that certain token values (ex: TK_EQ)
** are the same as opcode values (ex: OP_Eq) that implement the corresponding
@@ -1924,13 +2484,17 @@ int sqlite3ExprCodeExprList(
void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Vdbe *v = pParse->pVdbe;
int op = 0;
- int ckOffset = pParse->ckOffset;
+ int regFree1 = 0;
+ int regFree2 = 0;
+ int r1, r2;
+
+ assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
if( v==0 || pExpr==0 ) return;
op = pExpr->op;
switch( op ){
case TK_AND: {
int d2 = sqlite3VdbeMakeLabel(v);
- sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2, !jumpIfNull);
+ sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL);
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
sqlite3VdbeResolveLabel(v, d2);
break;
@@ -1956,50 +2520,58 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
assert( TK_GE==OP_Ge );
assert( TK_EQ==OP_Eq );
assert( TK_NE==OP_Ne );
- sqlite3ExprCode(pParse, pExpr->pLeft);
- sqlite3ExprCode(pParse, pExpr->pRight);
- codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, dest, jumpIfNull);
+ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
+ codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
+ r1, r2, dest, jumpIfNull);
break;
}
case TK_ISNULL:
case TK_NOTNULL: {
assert( TK_ISNULL==OP_IsNull );
assert( TK_NOTNULL==OP_NotNull );
- sqlite3ExprCode(pParse, pExpr->pLeft);
- sqlite3VdbeAddOp(v, op, 1, dest);
+ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ sqlite3VdbeAddOp2(v, op, r1, dest);
break;
}
case TK_BETWEEN: {
- /* The expression "x BETWEEN y AND z" is implemented as:
+ /* x BETWEEN y AND z
+ **
+ ** Is equivalent to
**
- ** 1 IF (x < y) GOTO 3
- ** 2 IF (x <= z) GOTO <dest>
- ** 3 ...
+ ** x>=y AND x<=z
+ **
+ ** Code it as such, taking care to do the common subexpression
+ ** elementation of x.
*/
- int addr;
- Expr *pLeft = pExpr->pLeft;
- Expr *pRight = pExpr->pList->a[0].pExpr;
- sqlite3ExprCode(pParse, pLeft);
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- sqlite3ExprCode(pParse, pRight);
- addr = codeCompare(pParse, pLeft, pRight, OP_Lt, 0, !jumpIfNull);
-
- pRight = pExpr->pList->a[1].pExpr;
- sqlite3ExprCode(pParse, pRight);
- codeCompare(pParse, pLeft, pRight, OP_Le, dest, jumpIfNull);
-
- sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
- sqlite3VdbeJumpHere(v, addr);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
+ Expr exprAnd;
+ Expr compLeft;
+ Expr compRight;
+ Expr exprX;
+
+ exprX = *pExpr->pLeft;
+ exprAnd.op = TK_AND;
+ exprAnd.pLeft = &compLeft;
+ exprAnd.pRight = &compRight;
+ compLeft.op = TK_GE;
+ compLeft.pLeft = &exprX;
+ compLeft.pRight = pExpr->pList->a[0].pExpr;
+ compRight.op = TK_LE;
+ compRight.pLeft = &exprX;
+ compRight.pRight = pExpr->pList->a[1].pExpr;
+ exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, &regFree1);
+ exprX.op = TK_REGISTER;
+ sqlite3ExprIfTrue(pParse, &exprAnd, dest, jumpIfNull);
break;
}
default: {
- sqlite3ExprCode(pParse, pExpr);
- sqlite3VdbeAddOp(v, OP_If, jumpIfNull, dest);
+ r1 = sqlite3ExprCodeTemp(pParse, pExpr, &regFree1);
+ sqlite3VdbeAddOp3(v, OP_If, r1, dest, jumpIfNull!=0);
break;
}
}
- pParse->ckOffset = ckOffset;
+ sqlite3ReleaseTempReg(pParse, regFree1);
+ sqlite3ReleaseTempReg(pParse, regFree2);
}
/*
@@ -2008,12 +2580,17 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
** continues straight thru if the expression is true.
**
** If the expression evaluates to NULL (neither true nor false) then
-** jump if jumpIfNull is true or fall through if jumpIfNull is false.
+** jump if jumpIfNull is SQLITE_JUMPIFNULL or fall through if jumpIfNull
+** is 0.
*/
void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Vdbe *v = pParse->pVdbe;
int op = 0;
- int ckOffset = pParse->ckOffset;
+ int regFree1 = 0;
+ int regFree2 = 0;
+ int r1, r2;
+
+ assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
if( v==0 || pExpr==0 ) return;
/* The value of pExpr->op and op are related as follows:
@@ -2055,7 +2632,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
}
case TK_OR: {
int d2 = sqlite3VdbeMakeLabel(v);
- sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, !jumpIfNull);
+ sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL);
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
sqlite3VdbeResolveLabel(v, d2);
break;
@@ -2070,52 +2647,71 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
case TK_GE:
case TK_NE:
case TK_EQ: {
- sqlite3ExprCode(pParse, pExpr->pLeft);
- sqlite3ExprCode(pParse, pExpr->pRight);
- codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, dest, jumpIfNull);
+ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
+ codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
+ r1, r2, dest, jumpIfNull);
break;
}
case TK_ISNULL:
case TK_NOTNULL: {
- sqlite3ExprCode(pParse, pExpr->pLeft);
- sqlite3VdbeAddOp(v, op, 1, dest);
+ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ sqlite3VdbeAddOp2(v, op, r1, dest);
break;
}
case TK_BETWEEN: {
- /* The expression is "x BETWEEN y AND z". It is implemented as:
+ /* x BETWEEN y AND z
+ **
+ ** Is equivalent to
**
- ** 1 IF (x >= y) GOTO 3
- ** 2 GOTO <dest>
- ** 3 IF (x > z) GOTO <dest>
+ ** x>=y AND x<=z
+ **
+ ** Code it as such, taking care to do the common subexpression
+ ** elementation of x.
*/
- int addr;
- Expr *pLeft = pExpr->pLeft;
- Expr *pRight = pExpr->pList->a[0].pExpr;
- sqlite3ExprCode(pParse, pLeft);
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- sqlite3ExprCode(pParse, pRight);
- addr = sqlite3VdbeCurrentAddr(v);
- codeCompare(pParse, pLeft, pRight, OP_Ge, addr+3, !jumpIfNull);
-
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, dest);
- pRight = pExpr->pList->a[1].pExpr;
- sqlite3ExprCode(pParse, pRight);
- codeCompare(pParse, pLeft, pRight, OP_Gt, dest, jumpIfNull);
+ Expr exprAnd;
+ Expr compLeft;
+ Expr compRight;
+ Expr exprX;
+
+ exprX = *pExpr->pLeft;
+ exprAnd.op = TK_AND;
+ exprAnd.pLeft = &compLeft;
+ exprAnd.pRight = &compRight;
+ compLeft.op = TK_GE;
+ compLeft.pLeft = &exprX;
+ compLeft.pRight = pExpr->pList->a[0].pExpr;
+ compRight.op = TK_LE;
+ compRight.pLeft = &exprX;
+ compRight.pRight = pExpr->pList->a[1].pExpr;
+ exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, &regFree1);
+ exprX.op = TK_REGISTER;
+ sqlite3ExprIfFalse(pParse, &exprAnd, dest, jumpIfNull);
break;
}
default: {
- sqlite3ExprCode(pParse, pExpr);
- sqlite3VdbeAddOp(v, OP_IfNot, jumpIfNull, dest);
+ r1 = sqlite3ExprCodeTemp(pParse, pExpr, &regFree1);
+ sqlite3VdbeAddOp3(v, OP_IfNot, r1, dest, jumpIfNull!=0);
break;
}
}
- pParse->ckOffset = ckOffset;
+ sqlite3ReleaseTempReg(pParse, regFree1);
+ sqlite3ReleaseTempReg(pParse, regFree2);
}
/*
** Do a deep comparison of two expression trees. Return TRUE (non-zero)
** if they are identical and return FALSE if they differ in any way.
+**
+** Sometimes this routine will return FALSE even if the two expressions
+** really are equivalent. If we cannot prove that the expressions are
+** identical, we return FALSE just to be safe. So if this routine
+** returns false, then you do not really know for certain if the two
+** expressions are the same. But if you get a TRUE return, then you
+** can be sure the expressions are the same. In the places where
+** this routine is used, it does not hurt to get an extra FALSE - that
+** just might result in some slightly slower code. But returning
+** an incorrect TRUE could lead to a malfunction.
*/
int sqlite3ExprCompare(Expr *pA, Expr *pB){
int i;
@@ -2139,7 +2735,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
}
if( pA->pSelect || pB->pSelect ) return 0;
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0;
- if( pA->token.z ){
+ if( pA->op!=TK_COLUMN && pA->token.z ){
if( pB->token.z==0 ) return 0;
if( pB->token.n!=pA->token.n ) return 0;
if( sqlite3StrNICmp((char*)pA->token.z,(char*)pB->token.z,pB->token.n)!=0 ){
@@ -2154,12 +2750,17 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
** Add a new element to the pAggInfo->aCol[] array. Return the index of
** the new element. Return a negative number if malloc fails.
*/
-static int addAggInfoColumn(AggInfo *pInfo){
+static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){
int i;
- i = sqlite3ArrayAllocate((void**)&pInfo->aCol, sizeof(pInfo->aCol[0]), 3);
- if( i<0 ){
- return -1;
- }
+ pInfo->aCol = sqlite3ArrayAllocate(
+ db,
+ pInfo->aCol,
+ sizeof(pInfo->aCol[0]),
+ 3,
+ &pInfo->nColumn,
+ &pInfo->nColumnAlloc,
+ &i
+ );
return i;
}
@@ -2167,12 +2768,17 @@ static int addAggInfoColumn(AggInfo *pInfo){
** Add a new element to the pAggInfo->aFunc[] array. Return the index of
** the new element. Return a negative number if malloc fails.
*/
-static int addAggInfoFunc(AggInfo *pInfo){
+static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){
int i;
- i = sqlite3ArrayAllocate((void**)&pInfo->aFunc, sizeof(pInfo->aFunc[0]), 2);
- if( i<0 ){
- return -1;
- }
+ pInfo->aFunc = sqlite3ArrayAllocate(
+ db,
+ pInfo->aFunc,
+ sizeof(pInfo->aFunc[0]),
+ 3,
+ &pInfo->nFunc,
+ &pInfo->nFuncAlloc,
+ &i
+ );
return i;
}
@@ -2189,9 +2795,9 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){
Parse *pParse = pNC->pParse;
SrcList *pSrcList = pNC->pSrcList;
AggInfo *pAggInfo = pNC->pAggInfo;
-
switch( pExpr->op ){
+ case TK_AGG_COLUMN:
case TK_COLUMN: {
/* Check to see if the column is in one of the tables in the FROM
** clause of the aggregate query */
@@ -2206,18 +2812,22 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){
** Make an entry for the column in pAggInfo->aCol[] if there
** is not an entry there already.
*/
+ int k;
pCol = pAggInfo->aCol;
- for(i=0; i<pAggInfo->nColumn; i++, pCol++){
+ for(k=0; k<pAggInfo->nColumn; k++, pCol++){
if( pCol->iTable==pExpr->iTable &&
pCol->iColumn==pExpr->iColumn ){
break;
}
}
- if( i>=pAggInfo->nColumn && (i = addAggInfoColumn(pAggInfo))>=0 ){
- pCol = &pAggInfo->aCol[i];
+ if( (k>=pAggInfo->nColumn)
+ && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0
+ ){
+ pCol = &pAggInfo->aCol[k];
+ pCol->pTab = pExpr->pTab;
pCol->iTable = pExpr->iTable;
pCol->iColumn = pExpr->iColumn;
- pCol->iMem = pParse->nMem++;
+ pCol->iMem = ++pParse->nMem;
pCol->iSorterColumn = -1;
pCol->pExpr = pExpr;
if( pAggInfo->pGroupBy ){
@@ -2245,7 +2855,7 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){
*/
pExpr->pAggInfo = pAggInfo;
pExpr->op = TK_AGG_COLUMN;
- pExpr->iAgg = i;
+ pExpr->iAgg = k;
break;
} /* endif pExpr->iTable==pItem->iCursor */
} /* end loop over pSrcList */
@@ -2269,11 +2879,11 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){
/* pExpr is original. Make a new entry in pAggInfo->aFunc[]
*/
u8 enc = ENC(pParse->db);
- i = addAggInfoFunc(pAggInfo);
+ i = addAggInfoFunc(pParse->db, pAggInfo);
if( i>=0 ){
pItem = &pAggInfo->aFunc[i];
pItem->pExpr = pExpr;
- pItem->iMem = pParse->nMem++;
+ pItem->iMem = ++pParse->nMem;
pItem->pFunc = sqlite3FindFunction(pParse->db,
(char*)pExpr->token.z, pExpr->token.n,
pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
@@ -2312,14 +2922,9 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){
**
** This routine should only be called after the expression has been
** analyzed by sqlite3ExprResolveNames().
-**
-** If errors are seen, leave an error message in zErrMsg and return
-** the number of errors.
*/
-int sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
- int nErr = pNC->pParse->nErr;
+void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
walkExprTree(pExpr, analyzeAggregate, pNC);
- return pNC->pParse->nErr - nErr;
}
/*
@@ -2328,14 +2933,51 @@ int sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
**
** If an error is found, the analysis is cut short.
*/
-int sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){
+void sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){
struct ExprList_item *pItem;
int i;
- int nErr = 0;
if( pList ){
- for(pItem=pList->a, i=0; nErr==0 && i<pList->nExpr; i++, pItem++){
- nErr += sqlite3ExprAnalyzeAggregates(pNC, pItem->pExpr);
+ for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
+ sqlite3ExprAnalyzeAggregates(pNC, pItem->pExpr);
}
}
- return nErr;
+}
+
+/*
+** Allocate or deallocate temporary use registers during code generation.
+*/
+int sqlite3GetTempReg(Parse *pParse){
+ if( pParse->nTempReg ){
+ return pParse->aTempReg[--pParse->nTempReg];
+ }else{
+ return ++pParse->nMem;
+ }
+}
+void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
+ if( iReg && pParse->nTempReg<ArraySize(pParse->aTempReg) ){
+ assert( iReg>0 );
+ pParse->aTempReg[pParse->nTempReg++] = iReg;
+ }
+}
+
+/*
+** Allocate or deallocate a block of nReg consecutive registers
+*/
+int sqlite3GetTempRange(Parse *pParse, int nReg){
+ int i;
+ if( nReg<=pParse->nRangeReg ){
+ i = pParse->iRangeReg;
+ pParse->iRangeReg += nReg;
+ pParse->nRangeReg -= nReg;
+ }else{
+ i = pParse->nMem+1;
+ pParse->nMem += nReg;
+ }
+ return i;
+}
+void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
+ if( nReg>pParse->nRangeReg ){
+ pParse->nRangeReg = nReg;
+ pParse->iRangeReg = iReg;
+ }
}
diff --git a/ext/pdo_sqlite/sqlite/src/fault.c b/ext/pdo_sqlite/sqlite/src/fault.c
new file mode 100644
index 0000000000..4cc369eece
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/fault.c
@@ -0,0 +1,147 @@
+/*
+** 2008 Jan 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 to implement a fault-injector used for
+** testing and verification of SQLite.
+**
+** Subsystems within SQLite can call sqlite3FaultStep() to see if
+** they should simulate a fault. sqlite3FaultStep() normally returns
+** zero but will return non-zero if a fault should be simulated.
+** Fault injectors can be used, for example, to simulate memory
+** allocation failures or I/O errors.
+**
+** The fault injector is omitted from the code if SQLite is
+** compiled with -DSQLITE_OMIT_FAULTINJECTOR=1. There is a very
+** small performance hit for leaving the fault injector in the code.
+** Commerical products will probably want to omit the fault injector
+** from production builds. But safety-critical systems who work
+** under the motto "fly what you test and test what you fly" may
+** choose to leave the fault injector enabled even in production.
+*/
+#include "sqliteInt.h"
+
+#ifndef SQLITE_OMIT_FAULTINJECTOR
+
+/*
+** There can be various kinds of faults. For example, there can be
+** a memory allocation failure. Or an I/O failure. For each different
+** fault type, there is a separate FaultInjector structure to keep track
+** of the status of that fault.
+*/
+static struct FaultInjector {
+ int iCountdown; /* Number of pending successes before we hit a failure */
+ int nRepeat; /* Number of times to repeat the failure */
+ int nBenign; /* Number of benign failures seen since last config */
+ int nFail; /* Number of failures seen since last config */
+ u8 enable; /* True if enabled */
+ u8 benign; /* Ture if next failure will be benign */
+} aFault[SQLITE_FAULTINJECTOR_COUNT];
+
+/*
+** This routine configures and enables a fault injector. After
+** calling this routine, aFaultStep() will return false (zero)
+** nDelay times, then it will return true nRepeat times,
+** then it will again begin returning false.
+*/
+void sqlite3FaultConfig(int id, int nDelay, int nRepeat){
+ assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
+ aFault[id].iCountdown = nDelay;
+ aFault[id].nRepeat = nRepeat;
+ aFault[id].nBenign = 0;
+ aFault[id].nFail = 0;
+ aFault[id].enable = nDelay>=0;
+ aFault[id].benign = 0;
+}
+
+/*
+** Return the number of faults (both hard and benign faults) that have
+** occurred since the injector was last configured.
+*/
+int sqlite3FaultFailures(int id){
+ assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
+ return aFault[id].nFail;
+}
+
+/*
+** Return the number of benign faults that have occurred since the
+** injector was last configured.
+*/
+int sqlite3FaultBenignFailures(int id){
+ assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
+ return aFault[id].nBenign;
+}
+
+/*
+** Return the number of successes that will occur before the next failure.
+** If no failures are scheduled, return -1.
+*/
+int sqlite3FaultPending(int id){
+ assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
+ if( aFault[id].enable ){
+ return aFault[id].iCountdown;
+ }else{
+ return -1;
+ }
+}
+
+/*
+** After this routine causes subsequent faults to be either benign
+** or hard (not benign), according to the "enable" parameter.
+**
+** Most faults are hard. In other words, most faults cause
+** an error to be propagated back up to the application interface.
+** However, sometimes a fault is easily recoverable. For example,
+** if a malloc fails while resizing a hash table, this is completely
+** recoverable simply by not carrying out the resize. The hash table
+** will continue to function normally. So a malloc failure during
+** a hash table resize is a benign fault.
+*/
+void sqlite3FaultBenign(int id, int enable){
+ assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
+ aFault[id].benign = enable;
+}
+
+/*
+** This routine exists as a place to set a breakpoint that will
+** fire on any simulated fault.
+*/
+static void sqlite3Fault(void){
+ static int cnt = 0;
+ cnt++;
+}
+
+
+/*
+** Check to see if a fault should be simulated. Return true to simulate
+** the fault. Return false if the fault should not be simulated.
+*/
+int sqlite3FaultStep(int id){
+ assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
+ if( likely(!aFault[id].enable) ){
+ return 0;
+ }
+ if( aFault[id].iCountdown>0 ){
+ aFault[id].iCountdown--;
+ return 0;
+ }
+ sqlite3Fault();
+ aFault[id].nFail++;
+ if( aFault[id].benign ){
+ aFault[id].nBenign++;
+ }
+ aFault[id].nRepeat--;
+ if( aFault[id].nRepeat<=0 ){
+ aFault[id].enable = 0;
+ }
+ return 1;
+}
+
+#endif /* SQLITE_OMIT_FAULTINJECTOR */
diff --git a/ext/pdo_sqlite/sqlite/src/func.c b/ext/pdo_sqlite/sqlite/src/func.c
index bf422f92c5..427b7bd09d 100644
--- a/ext/pdo_sqlite/sqlite/src/func.c
+++ b/ext/pdo_sqlite/sqlite/src/func.c
@@ -23,7 +23,7 @@
#include <stdlib.h>
#include <assert.h>
#include "vdbeInt.h"
-#include "os.h"
+
/*
** Return the collating function associated with a function.
@@ -101,7 +101,12 @@ static void lengthFunc(
}
case SQLITE_TEXT: {
const unsigned char *z = sqlite3_value_text(argv[0]);
- for(len=0; *z; z++){ if( (0xc0&*z)!=0x80 ) len++; }
+ if( z==0 ) return;
+ len = 0;
+ while( *z ){
+ len++;
+ SQLITE_SKIP_UTF8(z);
+ }
sqlite3_result_int(context, len);
break;
}
@@ -144,7 +149,14 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}
/*
-** Implementation of the substr() function
+** Implementation of the substr() function.
+**
+** substr(x,p1,p2) returns p2 characters of x[] beginning with p1.
+** p1 is 1-indexed. So substr(x,1,1) returns the first character
+** of x. If x is text, then we actually count UTF-8 characters.
+** If x is a blob, then we count bytes.
+**
+** If p1 is negative, then we begin abs(p1) from the end of x[].
*/
static void substrFunc(
sqlite3_context *context,
@@ -153,15 +165,31 @@ static void substrFunc(
){
const unsigned char *z;
const unsigned char *z2;
- int i;
- int p1, p2, len;
+ int len;
+ int p0type;
+ i64 p1, p2;
- assert( argc==3 );
- z = sqlite3_value_text(argv[0]);
- if( z==0 ) return;
+ assert( argc==3 || argc==2 );
+ p0type = sqlite3_value_type(argv[0]);
+ if( p0type==SQLITE_BLOB ){
+ len = sqlite3_value_bytes(argv[0]);
+ z = sqlite3_value_blob(argv[0]);
+ if( z==0 ) return;
+ assert( len==sqlite3_value_bytes(argv[0]) );
+ }else{
+ z = sqlite3_value_text(argv[0]);
+ if( z==0 ) return;
+ len = 0;
+ for(z2=z; *z2; len++){
+ SQLITE_SKIP_UTF8(z2);
+ }
+ }
p1 = sqlite3_value_int(argv[1]);
- p2 = sqlite3_value_int(argv[2]);
- for(len=0, z2=z; *z2; z2++){ if( (0xc0&*z2)!=0x80 ) len++; }
+ if( argc==3 ){
+ p2 = sqlite3_value_int(argv[2]);
+ }else{
+ p2 = SQLITE_MAX_LENGTH;
+ }
if( p1<0 ){
p1 += len;
if( p1<0 ){
@@ -174,16 +202,19 @@ static void substrFunc(
if( p1+p2>len ){
p2 = len-p1;
}
- for(i=0; i<p1 && z[i]; i++){
- if( (z[i]&0xc0)==0x80 ) p1++;
- }
- while( z[i] && (z[i]&0xc0)==0x80 ){ i++; p1++; }
- for(; i<p1+p2 && z[i]; i++){
- if( (z[i]&0xc0)==0x80 ) p2++;
+ if( p0type!=SQLITE_BLOB ){
+ while( *z && p1 ){
+ SQLITE_SKIP_UTF8(z);
+ p1--;
+ }
+ for(z2=z; *z2 && p2; p2--){
+ SQLITE_SKIP_UTF8(z2);
+ }
+ sqlite3_result_text(context, (char*)z, z2-z, SQLITE_TRANSIENT);
+ }else{
+ if( p2<0 ) p2 = 0;
+ sqlite3_result_blob(context, (char*)&z[p1], p2, SQLITE_TRANSIENT);
}
- while( z[i] && (z[i]&0xc0)==0x80 ){ i++; p2++; }
- if( p2<0 ) p2 = 0;
- sqlite3_result_text(context, (char*)&z[p1], p2, SQLITE_TRANSIENT);
}
/*
@@ -208,33 +239,60 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}
/*
+** Allocate nByte bytes of space using sqlite3_malloc(). If the
+** allocation fails, call sqlite3_result_error_nomem() to notify
+** the database handle that malloc() has failed.
+*/
+static void *contextMalloc(sqlite3_context *context, int nByte){
+ char *z = sqlite3_malloc(nByte);
+ if( !z && nByte>0 ){
+ sqlite3_result_error_nomem(context);
+ }
+ return z;
+}
+
+/*
** Implementation of the upper() and lower() SQL functions.
*/
static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
- unsigned char *z;
- int i;
+ char *z1;
+ const char *z2;
+ int i, n;
if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
- z = sqliteMalloc(sqlite3_value_bytes(argv[0])+1);
- if( z==0 ) return;
- strcpy((char*)z, (char*)sqlite3_value_text(argv[0]));
- for(i=0; z[i]; i++){
- z[i] = toupper(z[i]);
+ z2 = (char*)sqlite3_value_text(argv[0]);
+ n = sqlite3_value_bytes(argv[0]);
+ /* Verify that the call to _bytes() does not invalidate the _text() pointer */
+ assert( z2==(char*)sqlite3_value_text(argv[0]) );
+ if( z2 ){
+ z1 = contextMalloc(context, n+1);
+ if( z1 ){
+ memcpy(z1, z2, n+1);
+ for(i=0; z1[i]; i++){
+ z1[i] = toupper(z1[i]);
+ }
+ sqlite3_result_text(context, z1, -1, sqlite3_free);
+ }
}
- sqlite3_result_text(context, (char*)z, -1, SQLITE_TRANSIENT);
- sqliteFree(z);
}
static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
- unsigned char *z;
- int i;
+ char *z1;
+ const char *z2;
+ int i, n;
if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
- z = sqliteMalloc(sqlite3_value_bytes(argv[0])+1);
- if( z==0 ) return;
- strcpy((char*)z, (char*)sqlite3_value_text(argv[0]));
- for(i=0; z[i]; i++){
- z[i] = tolower(z[i]);
+ z2 = (char*)sqlite3_value_text(argv[0]);
+ n = sqlite3_value_bytes(argv[0]);
+ /* Verify that the call to _bytes() does not invalidate the _text() pointer */
+ assert( z2==(char*)sqlite3_value_text(argv[0]) );
+ if( z2 ){
+ z1 = contextMalloc(context, n+1);
+ if( z1 ){
+ memcpy(z1, z2, n+1);
+ for(i=0; z1[i]; i++){
+ z1[i] = tolower(z1[i]);
+ }
+ sqlite3_result_text(context, z1, -1, sqlite3_free);
+ }
}
- sqlite3_result_text(context, (char*)z, -1, SQLITE_TRANSIENT);
- sqliteFree(z);
}
/*
@@ -272,6 +330,33 @@ static void randomFunc(
}
/*
+** Implementation of randomblob(N). Return a random blob
+** that is N bytes long.
+*/
+static void randomBlob(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int n;
+ unsigned char *p;
+ assert( argc==1 );
+ n = sqlite3_value_int(argv[0]);
+ if( n<1 ){
+ n = 1;
+ }
+ if( n>SQLITE_MAX_LENGTH ){
+ sqlite3_result_error_toobig(context);
+ return;
+ }
+ p = contextMalloc(context, n);
+ if( p ){
+ sqlite3Randomness(n, p);
+ sqlite3_result_blob(context, (char*)p, n, sqlite3_free);
+ }
+}
+
+/*
** Implementation of the last_insert_rowid() SQL function. The return
** value is the same as the sqlite3_last_insert_rowid() API function.
*/
@@ -320,6 +405,19 @@ struct compareInfo {
u8 noCase;
};
+/*
+** For LIKE and GLOB matching on EBCDIC machines, assume that every
+** character is exactly one byte in size. Also, all characters are
+** able to participate in upper-case-to-lower-case mappings in EBCDIC
+** whereas only characters less than 0x80 do in ASCII.
+*/
+#if defined(SQLITE_EBCDIC)
+# define sqlite3Utf8Read(A,B,C) (*(A++))
+# define GlogUpperToLower(A) A = sqlite3UpperToLower[A]
+#else
+# define GlogUpperToLower(A) if( A<0x80 ){ A = sqlite3UpperToLower[A]; }
+#endif
+
static const struct compareInfo globInfo = { '*', '?', '[', 0 };
/* The correct SQL-92 behavior is for the LIKE operator to ignore
** case. Thus 'a' LIKE 'A' would be true. */
@@ -329,15 +427,6 @@ static const struct compareInfo likeInfoNorm = { '%', '_', 0, 1 };
static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };
/*
-** X is a pointer to the first byte of a UTF-8 character. Increment
-** X so that it points to the next character. This only works right
-** if X points to a well-formed UTF-8 string.
-*/
-#define sqliteNextChar(X) while( (0xc0&*++(X))==0x80 ){}
-#define sqliteCharVal(X) sqlite3ReadUtf8(X)
-
-
-/*
** Compare two UTF-8 strings for equality where the first string can
** potentially be a "glob" expression. Return true (1) if they
** are the same and false (0) if they are different.
@@ -371,97 +460,102 @@ static int patternCompare(
const struct compareInfo *pInfo, /* Information about how to do the compare */
const int esc /* The escape character */
){
- register int c;
+ int c, c2;
int invert;
int seen;
- int c2;
u8 matchOne = pInfo->matchOne;
u8 matchAll = pInfo->matchAll;
u8 matchSet = pInfo->matchSet;
u8 noCase = pInfo->noCase;
int prevEscape = 0; /* True if the previous character was 'escape' */
- while( (c = *zPattern)!=0 ){
+ while( (c = sqlite3Utf8Read(zPattern,0,&zPattern))!=0 ){
if( !prevEscape && c==matchAll ){
- while( (c=zPattern[1]) == matchAll || c == matchOne ){
- if( c==matchOne ){
- if( *zString==0 ) return 0;
- sqliteNextChar(zString);
+ while( (c=sqlite3Utf8Read(zPattern,0,&zPattern)) == matchAll
+ || c == matchOne ){
+ if( c==matchOne && sqlite3Utf8Read(zString, 0, &zString)==0 ){
+ return 0;
}
- zPattern++;
- }
- if( c && esc && sqlite3ReadUtf8(&zPattern[1])==esc ){
- u8 const *zTemp = &zPattern[1];
- sqliteNextChar(zTemp);
- c = *zTemp;
}
- if( c==0 ) return 1;
- if( c==matchSet ){
- assert( esc==0 ); /* This is GLOB, not LIKE */
- while( *zString && patternCompare(&zPattern[1],zString,pInfo,esc)==0 ){
- sqliteNextChar(zString);
+ if( c==0 ){
+ return 1;
+ }else if( c==esc ){
+ c = sqlite3Utf8Read(zPattern, 0, &zPattern);
+ if( c==0 ){
+ return 0;
+ }
+ }else if( c==matchSet ){
+ assert( esc==0 ); /* This is GLOB, not LIKE */
+ assert( matchSet<0x80 ); /* '[' is a single-byte character */
+ while( *zString && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){
+ SQLITE_SKIP_UTF8(zString);
}
return *zString!=0;
- }else{
- while( (c2 = *zString)!=0 ){
- if( noCase ){
- c2 = sqlite3UpperToLower[c2];
- c = sqlite3UpperToLower[c];
- while( c2 != 0 && c2 != c ){ c2 = sqlite3UpperToLower[*++zString]; }
- }else{
- while( c2 != 0 && c2 != c ){ c2 = *++zString; }
+ }
+ while( (c2 = sqlite3Utf8Read(zString,0,&zString))!=0 ){
+ if( noCase ){
+ GlogUpperToLower(c2);
+ GlogUpperToLower(c);
+ while( c2 != 0 && c2 != c ){
+ c2 = sqlite3Utf8Read(zString, 0, &zString);
+ GlogUpperToLower(c2);
+ }
+ }else{
+ while( c2 != 0 && c2 != c ){
+ c2 = sqlite3Utf8Read(zString, 0, &zString);
}
- if( c2==0 ) return 0;
- if( patternCompare(&zPattern[1],zString,pInfo,esc) ) return 1;
- sqliteNextChar(zString);
}
- return 0;
+ if( c2==0 ) return 0;
+ if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
}
+ return 0;
}else if( !prevEscape && c==matchOne ){
- if( *zString==0 ) return 0;
- sqliteNextChar(zString);
- zPattern++;
+ if( sqlite3Utf8Read(zString, 0, &zString)==0 ){
+ return 0;
+ }
}else if( c==matchSet ){
int prior_c = 0;
assert( esc==0 ); /* This only occurs for GLOB, not LIKE */
seen = 0;
invert = 0;
- c = sqliteCharVal(zString);
+ c = sqlite3Utf8Read(zString, 0, &zString);
if( c==0 ) return 0;
- c2 = *++zPattern;
- if( c2=='^' ){ invert = 1; c2 = *++zPattern; }
+ c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
+ if( c2=='^' ){
+ invert = 1;
+ c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
+ }
if( c2==']' ){
if( c==']' ) seen = 1;
- c2 = *++zPattern;
+ c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
}
- while( (c2 = sqliteCharVal(zPattern))!=0 && c2!=']' ){
- if( c2=='-' && zPattern[1]!=']' && zPattern[1]!=0 && prior_c>0 ){
- zPattern++;
- c2 = sqliteCharVal(zPattern);
+ while( c2 && c2!=']' ){
+ if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){
+ c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
if( c>=prior_c && c<=c2 ) seen = 1;
prior_c = 0;
- }else if( c==c2 ){
- seen = 1;
- prior_c = c2;
}else{
+ if( c==c2 ){
+ seen = 1;
+ }
prior_c = c2;
}
- sqliteNextChar(zPattern);
+ c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
}
- if( c2==0 || (seen ^ invert)==0 ) return 0;
- sqliteNextChar(zString);
- zPattern++;
- }else if( esc && !prevEscape && sqlite3ReadUtf8(zPattern)==esc){
+ if( c2==0 || (seen ^ invert)==0 ){
+ return 0;
+ }
+ }else if( esc==c && !prevEscape ){
prevEscape = 1;
- sqliteNextChar(zPattern);
}else{
+ c2 = sqlite3Utf8Read(zString, 0, &zString);
if( noCase ){
- if( sqlite3UpperToLower[c] != sqlite3UpperToLower[*zString] ) return 0;
- }else{
- if( c != *zString ) return 0;
+ GlogUpperToLower(c);
+ GlogUpperToLower(c2);
+ }
+ if( c!=c2 ){
+ return 0;
}
- zPattern++;
- zString++;
prevEscape = 0;
}
}
@@ -495,27 +589,41 @@ static void likeFunc(
int argc,
sqlite3_value **argv
){
- const unsigned char *zA = sqlite3_value_text(argv[0]);
- const unsigned char *zB = sqlite3_value_text(argv[1]);
+ const unsigned char *zA, *zB;
int escape = 0;
+
+ zB = sqlite3_value_text(argv[0]);
+ zA = sqlite3_value_text(argv[1]);
+
+ /* Limit the length of the LIKE or GLOB pattern to avoid problems
+ ** of deep recursion and N*N behavior in patternCompare().
+ */
+ if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){
+ sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1);
+ return;
+ }
+ assert( zB==sqlite3_value_text(argv[0]) ); /* Encoding did not change */
+
if( argc==3 ){
/* The escape character string must consist of a single UTF-8 character.
** Otherwise, return an error.
*/
const unsigned char *zEsc = sqlite3_value_text(argv[2]);
- if( sqlite3utf8CharLen((char*)zEsc, -1)!=1 ){
+ if( zEsc==0 ) return;
+ if( sqlite3Utf8CharLen((char*)zEsc, -1)!=1 ){
sqlite3_result_error(context,
"ESCAPE expression must be a single character", -1);
return;
}
- escape = sqlite3ReadUtf8(zEsc);
+ escape = sqlite3Utf8Read(zEsc, 0, &zEsc);
}
if( zA && zB ){
struct compareInfo *pInfo = sqlite3_user_data(context);
#ifdef SQLITE_TEST
sqlite3_like_count++;
#endif
- sqlite3_result_int(context, patternCompare(zA, zB, pInfo, escape));
+
+ sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape));
}
}
@@ -547,19 +655,12 @@ 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);
-}
-
+/* Array for converting from half-bytes (nybbles) into ASCII hex
+** digits. */
+static const char hexdigits[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
/*
** EXPERIMENTAL - This is not an official function. The interface may
@@ -585,18 +686,17 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
break;
}
case SQLITE_BLOB: {
- static const char hexdigits[] = {
- '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
- };
char *zText = 0;
- int nBlob = sqlite3_value_bytes(argv[0]);
char const *zBlob = sqlite3_value_blob(argv[0]);
+ int nBlob = sqlite3_value_bytes(argv[0]);
+ assert( zBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */
- zText = (char *)sqliteMalloc((2*nBlob)+4);
- if( !zText ){
- sqlite3_result_error(context, "out of memory", -1);
- }else{
+ if( 2*nBlob+4>SQLITE_MAX_LENGTH ){
+ sqlite3_result_error_toobig(context);
+ return;
+ }
+ zText = (char *)contextMalloc(context, (2*nBlob)+4);
+ if( zText ){
int i;
for(i=0; i<nBlob; i++){
zText[(i*2)+2] = hexdigits[(zBlob[i]>>4)&0x0F];
@@ -607,38 +707,255 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
zText[0] = 'X';
zText[1] = '\'';
sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT);
- sqliteFree(zText);
+ sqlite3_free(zText);
}
break;
}
case SQLITE_TEXT: {
- int i,j,n;
+ int i,j;
+ u64 n;
const unsigned char *zArg = sqlite3_value_text(argv[0]);
char *z;
- for(i=n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; }
- z = sqliteMalloc( i+n+3 );
- if( z==0 ) return;
- z[0] = '\'';
- for(i=0, j=1; zArg[i]; i++){
- z[j++] = zArg[i];
- if( zArg[i]=='\'' ){
- z[j++] = '\'';
+ if( zArg==0 ) return;
+ for(i=0, n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; }
+ if( i+n+3>SQLITE_MAX_LENGTH ){
+ sqlite3_result_error_toobig(context);
+ return;
+ }
+ z = contextMalloc(context, i+n+3);
+ if( z ){
+ z[0] = '\'';
+ for(i=0, j=1; zArg[i]; i++){
+ z[j++] = zArg[i];
+ if( zArg[i]=='\'' ){
+ z[j++] = '\'';
+ }
}
+ z[j++] = '\'';
+ z[j] = 0;
+ sqlite3_result_text(context, z, j, sqlite3_free);
}
- z[j++] = '\'';
- z[j] = 0;
- sqlite3_result_text(context, z, j, SQLITE_TRANSIENT);
- sqliteFree(z);
}
}
}
+/*
+** The hex() function. Interpret the argument as a blob. Return
+** a hexadecimal rendering as text.
+*/
+static void hexFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int i, n;
+ const unsigned char *pBlob;
+ char *zHex, *z;
+ assert( argc==1 );
+ pBlob = sqlite3_value_blob(argv[0]);
+ n = sqlite3_value_bytes(argv[0]);
+ if( n*2+1>SQLITE_MAX_LENGTH ){
+ sqlite3_result_error_toobig(context);
+ return;
+ }
+ assert( pBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */
+ z = zHex = contextMalloc(context, n*2 + 1);
+ if( zHex ){
+ for(i=0; i<n; i++, pBlob++){
+ unsigned char c = *pBlob;
+ *(z++) = hexdigits[(c>>4)&0xf];
+ *(z++) = hexdigits[c&0xf];
+ }
+ *z = 0;
+ sqlite3_result_text(context, zHex, n*2, sqlite3_free);
+ }
+}
+
+/*
+** The zeroblob(N) function returns a zero-filled blob of size N bytes.
+*/
+static void zeroblobFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ i64 n;
+ assert( argc==1 );
+ n = sqlite3_value_int64(argv[0]);
+ if( n>SQLITE_MAX_LENGTH ){
+ sqlite3_result_error_toobig(context);
+ }else{
+ sqlite3_result_zeroblob(context, n);
+ }
+}
+
+/*
+** The replace() function. Three arguments are all strings: call
+** them A, B, and C. The result is also a string which is derived
+** from A by replacing every occurance of B with C. The match
+** must be exact. Collating sequences are not used.
+*/
+static void replaceFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const unsigned char *zStr; /* The input string A */
+ const unsigned char *zPattern; /* The pattern string B */
+ const unsigned char *zRep; /* The replacement string C */
+ unsigned char *zOut; /* The output */
+ int nStr; /* Size of zStr */
+ int nPattern; /* Size of zPattern */
+ int nRep; /* Size of zRep */
+ i64 nOut; /* Maximum size of zOut */
+ int loopLimit; /* Last zStr[] that might match zPattern[] */
+ int i, j; /* Loop counters */
+
+ assert( argc==3 );
+ zStr = sqlite3_value_text(argv[0]);
+ if( zStr==0 ) return;
+ nStr = sqlite3_value_bytes(argv[0]);
+ assert( zStr==sqlite3_value_text(argv[0]) ); /* No encoding change */
+ zPattern = sqlite3_value_text(argv[1]);
+ if( zPattern==0 || zPattern[0]==0 ) return;
+ nPattern = sqlite3_value_bytes(argv[1]);
+ assert( zPattern==sqlite3_value_text(argv[1]) ); /* No encoding change */
+ zRep = sqlite3_value_text(argv[2]);
+ if( zRep==0 ) return;
+ nRep = sqlite3_value_bytes(argv[2]);
+ assert( zRep==sqlite3_value_text(argv[2]) );
+ nOut = nStr + 1;
+ assert( nOut<SQLITE_MAX_LENGTH );
+ zOut = contextMalloc(context, (int)nOut);
+ if( zOut==0 ){
+ return;
+ }
+ loopLimit = nStr - nPattern;
+ for(i=j=0; i<=loopLimit; i++){
+ if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){
+ zOut[j++] = zStr[i];
+ }else{
+ u8 *zOld;
+ nOut += nRep - nPattern;
+ if( nOut>=SQLITE_MAX_LENGTH ){
+ sqlite3_result_error_toobig(context);
+ sqlite3_free(zOut);
+ return;
+ }
+ zOld = zOut;
+ zOut = sqlite3_realloc(zOut, (int)nOut);
+ if( zOut==0 ){
+ sqlite3_result_error_nomem(context);
+ sqlite3_free(zOld);
+ return;
+ }
+ memcpy(&zOut[j], zRep, nRep);
+ j += nRep;
+ i += nPattern-1;
+ }
+ }
+ assert( j+nStr-i+1==nOut );
+ memcpy(&zOut[j], &zStr[i], nStr-i);
+ j += nStr - i;
+ assert( j<=nOut );
+ zOut[j] = 0;
+ sqlite3_result_text(context, (char*)zOut, j, sqlite3_free);
+}
+
+/*
+** Implementation of the TRIM(), LTRIM(), and RTRIM() functions.
+** The userdata is 0x1 for left trim, 0x2 for right trim, 0x3 for both.
+*/
+static void trimFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const unsigned char *zIn; /* Input string */
+ const unsigned char *zCharSet; /* Set of characters to trim */
+ int nIn; /* Number of bytes in input */
+ int flags; /* 1: trimleft 2: trimright 3: trim */
+ int i; /* Loop counter */
+ unsigned char *aLen; /* Length of each character in zCharSet */
+ unsigned char **azChar; /* Individual characters in zCharSet */
+ int nChar; /* Number of characters in zCharSet */
+
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
+ return;
+ }
+ zIn = sqlite3_value_text(argv[0]);
+ if( zIn==0 ) return;
+ nIn = sqlite3_value_bytes(argv[0]);
+ assert( zIn==sqlite3_value_text(argv[0]) );
+ if( argc==1 ){
+ static const unsigned char lenOne[] = { 1 };
+ static const unsigned char *azOne[] = { (u8*)" " };
+ nChar = 1;
+ aLen = (u8*)lenOne;
+ azChar = (unsigned char **)azOne;
+ zCharSet = 0;
+ }else if( (zCharSet = sqlite3_value_text(argv[1]))==0 ){
+ return;
+ }else{
+ const unsigned char *z;
+ for(z=zCharSet, nChar=0; *z; nChar++){
+ SQLITE_SKIP_UTF8(z);
+ }
+ if( nChar>0 ){
+ azChar = contextMalloc(context, nChar*(sizeof(char*)+1));
+ if( azChar==0 ){
+ return;
+ }
+ aLen = (unsigned char*)&azChar[nChar];
+ for(z=zCharSet, nChar=0; *z; nChar++){
+ azChar[nChar] = (unsigned char *)z;
+ SQLITE_SKIP_UTF8(z);
+ aLen[nChar] = z - azChar[nChar];
+ }
+ }
+ }
+ if( nChar>0 ){
+ flags = (int)sqlite3_user_data(context);
+ if( flags & 1 ){
+ while( nIn>0 ){
+ int len;
+ for(i=0; i<nChar; i++){
+ len = aLen[i];
+ if( memcmp(zIn, azChar[i], len)==0 ) break;
+ }
+ if( i>=nChar ) break;
+ zIn += len;
+ nIn -= len;
+ }
+ }
+ if( flags & 2 ){
+ while( nIn>0 ){
+ int len;
+ for(i=0; i<nChar; i++){
+ len = aLen[i];
+ if( len<=nIn && memcmp(&zIn[nIn-len],azChar[i],len)==0 ) break;
+ }
+ if( i>=nChar ) break;
+ nIn -= len;
+ }
+ }
+ if( zCharSet ){
+ sqlite3_free(azChar);
+ }
+ }
+ sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT);
+}
+
#ifdef SQLITE_SOUNDEX
/*
** Compute the soundex encoding of a word.
*/
-static void soundexFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
+static void soundexFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
char zResult[8];
const u8 *zIn;
int i, j;
@@ -654,14 +971,20 @@ 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 = "";
+ if( zIn==0 ) zIn = (u8*)"";
for(i=0; zIn[i] && !isalpha(zIn[i]); i++){}
if( zIn[i] ){
+ u8 prevcode = iCode[zIn[i]&0x7f];
zResult[0] = toupper(zIn[i]);
for(j=1; j<4 && zIn[i]; i++){
int code = iCode[zIn[i]&0x7f];
if( code>0 ){
- zResult[j++] = code + '0';
+ if( code!=prevcode ){
+ prevcode = code;
+ zResult[j++] = code + '0';
+ }
+ }else{
+ prevcode = 0;
}
}
while( j<4 ){
@@ -681,14 +1004,16 @@ static void soundexFunc(sqlite3_context *context, int argc, sqlite3_value **argv
*/
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;
+ const char *zProc;
sqlite3 *db = sqlite3_user_data(context);
char *zErrMsg = 0;
if( argc==2 ){
zProc = (const char *)sqlite3_value_text(argv[1]);
+ }else{
+ zProc = 0;
}
- if( sqlite3_load_extension(db, zFile, zProc, &zErrMsg) ){
+ if( zFile && sqlite3_load_extension(db, zFile, zProc, &zErrMsg) ){
sqlite3_result_error(context, zErrMsg, -1);
sqlite3_free(zErrMsg);
}
@@ -708,20 +1033,18 @@ static void randStr(sqlite3_context *context, int argc, sqlite3_value **argv){
".-!,:*^+=_|?/<> ";
int iMin, iMax, n, r, i;
unsigned char zBuf[1000];
- if( argc>=1 ){
- iMin = sqlite3_value_int(argv[0]);
- if( iMin<0 ) iMin = 0;
- if( iMin>=sizeof(zBuf) ) iMin = sizeof(zBuf)-1;
- }else{
- iMin = 1;
- }
- if( argc>=2 ){
- iMax = sqlite3_value_int(argv[1]);
- if( iMax<iMin ) iMax = iMin;
- if( iMax>=sizeof(zBuf) ) iMax = sizeof(zBuf)-1;
- }else{
- iMax = 50;
- }
+
+ /* It used to be possible to call randstr() with any number of arguments,
+ ** but now it is registered with SQLite as requiring exactly 2.
+ */
+ assert(argc==2);
+
+ iMin = sqlite3_value_int(argv[0]);
+ if( iMin<0 ) iMin = 0;
+ if( iMin>=sizeof(zBuf) ) iMin = sizeof(zBuf)-1;
+ iMax = sqlite3_value_int(argv[1]);
+ if( iMax<iMin ) iMax = iMin;
+ if( iMax>=sizeof(zBuf) ) iMax = sizeof(zBuf)-1;
n = iMin;
if( iMax>iMin ){
sqlite3Randomness(sizeof(r), &r);
@@ -755,7 +1078,7 @@ static void destructor(void *p){
char *zVal = (char *)p;
assert(zVal);
zVal--;
- sqliteFree(zVal);
+ sqlite3_free(zVal);
test_destructor_count_var--;
}
static void test_destructor(
@@ -771,10 +1094,12 @@ static void test_destructor(
assert( nArg==1 );
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
len = sqlite3ValueBytes(argv[0], ENC(db));
- zVal = sqliteMalloc(len+3);
- zVal[len] = 0;
- zVal[len-1] = 0;
- assert( zVal );
+ zVal = contextMalloc(pCtx, len+3);
+ if( !zVal ){
+ return;
+ }
+ zVal[len+1] = 0;
+ zVal[len+2] = 0;
zVal++;
memcpy(zVal, sqlite3ValueText(argv[0], ENC(db)), len);
if( ENC(db)==SQLITE_UTF8 ){
@@ -808,28 +1133,30 @@ static void test_destructor_count(
** registration, the result for that argument is 1. The overall result
** is the individual argument results separated by spaces.
*/
-static void free_test_auxdata(void *p) {sqliteFree(p);}
+static void free_test_auxdata(void *p) {sqlite3_free(p);}
static void test_auxdata(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **argv
){
int i;
- char *zRet = sqliteMalloc(nArg*2);
+ char *zRet = contextMalloc(pCtx, nArg*2);
if( !zRet ) return;
+ memset(zRet, 0, nArg*2);
for(i=0; i<nArg; i++){
char const *z = (char*)sqlite3_value_text(argv[i]);
if( z ){
char *zAux = sqlite3_get_auxdata(pCtx, i);
if( zAux ){
zRet[i*2] = '1';
- if( strcmp(zAux, z) ){
- sqlite3_result_error(pCtx, "Auxilary data corruption", -1);
- return;
- }
- }else{
+ assert( strcmp(zAux,z)==0 );
+ }else {
zRet[i*2] = '0';
- zAux = sqliteStrDup(z);
+ }
+
+ zAux = contextMalloc(pCtx, strlen(z)+1);
+ if( zAux ){
+ strcpy(zAux, z);
sqlite3_set_auxdata(pCtx, i, zAux, free_test_auxdata);
}
zRet[i*2+1] = ' ';
@@ -842,7 +1169,7 @@ static void test_auxdata(
#ifdef SQLITE_TEST
/*
** A function to test error reporting from user functions. This function
-** returns a copy of it's first argument as an error.
+** returns a copy of its first argument as an error.
*/
static void test_error(
sqlite3_context *pCtx,
@@ -975,7 +1302,7 @@ static void minmaxStep(sqlite3_context *context, int argc, sqlite3_value **argv)
** Therefore the next statement sets variable 'max' to 1 for the max()
** aggregate, or 0 for min().
*/
- max = ((sqlite3_user_data(context)==(void *)-1)?1:0);
+ max = sqlite3_user_data(context)!=0;
cmp = sqlite3MemCompare(pBest, pArg, pColl);
if( (max && cmp<0) || (!max && cmp>0) ){
sqlite3VdbeMemCopy(pBest, pArg);
@@ -995,6 +1322,52 @@ static void minMaxFinalize(sqlite3_context *context){
}
}
+/*
+** group_concat(EXPR, ?SEPARATOR?)
+*/
+static void groupConcatStep(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zVal;
+ StrAccum *pAccum;
+ const char *zSep;
+ int nVal, nSep;
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
+ pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum));
+
+ if( pAccum ){
+ pAccum->useMalloc = 1;
+ if( pAccum->nChar ){
+ if( argc==2 ){
+ zSep = (char*)sqlite3_value_text(argv[1]);
+ nSep = sqlite3_value_bytes(argv[1]);
+ }else{
+ zSep = ",";
+ nSep = 1;
+ }
+ sqlite3StrAccumAppend(pAccum, zSep, nSep);
+ }
+ zVal = (char*)sqlite3_value_text(argv[0]);
+ nVal = sqlite3_value_bytes(argv[0]);
+ sqlite3StrAccumAppend(pAccum, zVal, nVal);
+ }
+}
+static void groupConcatFinalize(sqlite3_context *context){
+ StrAccum *pAccum;
+ pAccum = sqlite3_aggregate_context(context, 0);
+ if( pAccum ){
+ if( pAccum->tooBig ){
+ sqlite3_result_error_toobig(context);
+ }else if( pAccum->mallocFailed ){
+ sqlite3_result_error_nomem(context);
+ }else{
+ sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1,
+ sqlite3_free);
+ }
+ }
+}
/*
** This function registered all of the above C functions as SQL
@@ -1005,21 +1378,19 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
static const struct {
char *zName;
signed char nArg;
- u8 argType; /* 0: none. 1: db 2: (-1) */
+ u8 argType; /* ff: db 1: 0, 2: 1, 3: 2,... N: N-1. */
u8 eTextRep; /* 1: UTF-16. 0: UTF-8 */
u8 needCollSeq;
void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
} aFuncs[] = {
{ "min", -1, 0, SQLITE_UTF8, 1, minmaxFunc },
{ "min", 0, 0, SQLITE_UTF8, 1, 0 },
- { "max", -1, 2, SQLITE_UTF8, 1, minmaxFunc },
- { "max", 0, 2, SQLITE_UTF8, 1, 0 },
+ { "max", -1, 1, SQLITE_UTF8, 1, minmaxFunc },
+ { "max", 0, 1, SQLITE_UTF8, 1, 0 },
{ "typeof", 1, 0, SQLITE_UTF8, 0, typeofFunc },
{ "length", 1, 0, SQLITE_UTF8, 0, lengthFunc },
+ { "substr", 2, 0, SQLITE_UTF8, 0, substrFunc },
{ "substr", 3, 0, SQLITE_UTF8, 0, substrFunc },
-#ifndef SQLITE_OMIT_UTF16
- { "substr", 3, 0, SQLITE_UTF16LE, 0, sqlite3utf16Substr },
-#endif
{ "abs", 1, 0, SQLITE_UTF8, 0, absFunc },
{ "round", 1, 0, SQLITE_UTF8, 0, roundFunc },
{ "round", 2, 0, SQLITE_UTF8, 0, roundFunc },
@@ -1028,28 +1399,37 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
{ "coalesce", -1, 0, SQLITE_UTF8, 0, ifnullFunc },
{ "coalesce", 0, 0, SQLITE_UTF8, 0, 0 },
{ "coalesce", 1, 0, SQLITE_UTF8, 0, 0 },
+ { "hex", 1, 0, SQLITE_UTF8, 0, hexFunc },
{ "ifnull", 2, 0, SQLITE_UTF8, 1, ifnullFunc },
{ "random", -1, 0, SQLITE_UTF8, 0, randomFunc },
+ { "randomblob", 1, 0, SQLITE_UTF8, 0, randomBlob },
{ "nullif", 2, 0, SQLITE_UTF8, 1, nullifFunc },
{ "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc},
{ "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc },
- { "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 },
+ { "last_insert_rowid", 0, 0xff, SQLITE_UTF8, 0, last_insert_rowid },
+ { "changes", 0, 0xff, SQLITE_UTF8, 0, changes },
+ { "total_changes", 0, 0xff, SQLITE_UTF8, 0, total_changes },
+ { "replace", 3, 0, SQLITE_UTF8, 0, replaceFunc },
+ { "ltrim", 1, 1, SQLITE_UTF8, 0, trimFunc },
+ { "ltrim", 2, 1, SQLITE_UTF8, 0, trimFunc },
+ { "rtrim", 1, 2, SQLITE_UTF8, 0, trimFunc },
+ { "rtrim", 2, 2, SQLITE_UTF8, 0, trimFunc },
+ { "trim", 1, 3, SQLITE_UTF8, 0, trimFunc },
+ { "trim", 2, 3, SQLITE_UTF8, 0, trimFunc },
+ { "zeroblob", 1, 0, SQLITE_UTF8, 0, zeroblobFunc },
#ifdef SQLITE_SOUNDEX
- { "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
+ { "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 },
+ { "load_extension", 1, 0xff, SQLITE_UTF8, 0, loadExt },
+ { "load_extension", 2, 0xff, SQLITE_UTF8, 0, loadExt },
#endif
#ifdef SQLITE_TEST
- { "randstr", 2, 0, SQLITE_UTF8, 0, randStr },
- { "test_destructor", 1, 1, SQLITE_UTF8, 0, test_destructor},
- { "test_destructor_count", 0, 0, SQLITE_UTF8, 0, test_destructor_count},
- { "test_auxdata", -1, 0, SQLITE_UTF8, 0, test_auxdata},
- { "test_error", 1, 0, SQLITE_UTF8, 0, test_error},
+ { "randstr", 2, 0, SQLITE_UTF8, 0, randStr },
+ { "test_destructor", 1, 0xff, SQLITE_UTF8, 0, test_destructor},
+ { "test_destructor_count", 0, 0, SQLITE_UTF8, 0, test_destructor_count},
+ { "test_auxdata", -1, 0, SQLITE_UTF8, 0, test_auxdata},
+ { "test_error", 1, 0, SQLITE_UTF8, 0, test_error},
#endif
};
static const struct {
@@ -1061,20 +1441,24 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
void (*xFinalize)(sqlite3_context*);
} aAggs[] = {
{ "min", 1, 0, 1, minmaxStep, minMaxFinalize },
- { "max", 1, 2, 1, minmaxStep, minMaxFinalize },
+ { "max", 1, 1, 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 },
+ { "group_concat", 1, 0, 0, groupConcatStep, groupConcatFinalize },
+ { "group_concat", 2, 0, 0, groupConcatStep, groupConcatFinalize },
};
int i;
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
- void *pArg = 0;
- switch( aFuncs[i].argType ){
- case 1: pArg = db; break;
- case 2: pArg = (void *)(-1); break;
+ void *pArg;
+ u8 argType = aFuncs[i].argType;
+ if( argType==0xff ){
+ pArg = db;
+ }else{
+ pArg = (void*)(int)argType;
}
sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
aFuncs[i].eTextRep, pArg, aFuncs[i].xFunc, 0, 0);
@@ -1093,11 +1477,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
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;
- }
+ void *pArg = (void*)(int)aAggs[i].argType;
sqlite3CreateFunc(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8,
pArg, 0, aAggs[i].xStep, aAggs[i].xFinalize);
if( aAggs[i].needCollSeq ){
@@ -1109,6 +1489,13 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
}
}
sqlite3RegisterDateTimeFunctions(db);
+ if( !db->mallocFailed ){
+ int rc = sqlite3_overload_function(db, "MATCH", 2);
+ assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
+ if( rc==SQLITE_NOMEM ){
+ db->mallocFailed = 1;
+ }
+ }
#ifdef SQLITE_SSE
(void)sqlite3SseFunctions(db);
#endif
@@ -1160,7 +1547,7 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
*/
int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
FuncDef *pDef;
- if( pExpr->op!=TK_FUNCTION ){
+ if( pExpr->op!=TK_FUNCTION || !pExpr->pList ){
return 0;
}
if( pExpr->pList->nExpr!=2 ){
diff --git a/ext/pdo_sqlite/sqlite/src/hash.c b/ext/pdo_sqlite/sqlite/src/hash.c
index 1c32c1b7cc..d6ddc6435d 100644
--- a/ext/pdo_sqlite/sqlite/src/hash.c
+++ b/ext/pdo_sqlite/sqlite/src/hash.c
@@ -41,8 +41,6 @@ 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.
@@ -55,15 +53,15 @@ void sqlite3HashClear(Hash *pH){
assert( pH!=0 );
elem = pH->first;
pH->first = 0;
- if( pH->ht ) pH->xFree(pH->ht);
+ if( pH->ht ) sqlite3_free(pH->ht);
pH->ht = 0;
pH->htsize = 0;
while( elem ){
HashElem *next_elem = elem->next;
if( pH->copyKey && elem->pKey ){
- pH->xFree(elem->pKey);
+ sqlite3_free(elem->pKey);
}
- pH->xFree(elem);
+ sqlite3_free(elem);
elem = next_elem;
}
pH->count = 0;
@@ -216,7 +214,7 @@ static void insertElement(
/* Resize the hash table so that it cantains "new_size" buckets.
** "new_size" must be a power of 2. The hash table might fail
-** to resize if sqliteMalloc() fails.
+** to resize if sqlite3_malloc() fails.
*/
static void rehash(Hash *pH, int new_size){
struct _ht *new_ht; /* The new hash table */
@@ -224,9 +222,18 @@ 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 *)pH->xMalloc( new_size*sizeof(struct _ht) );
+
+ /* There is a call to sqlite3_malloc() inside rehash(). If there is
+ ** already an allocation at pH->ht, then if this malloc() fails it
+ ** is benign (since failing to resize a hash table is a performance
+ ** hit only, not a fatal error).
+ */
+ sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, pH->htsize>0);
+ new_ht = (struct _ht *)sqlite3MallocZero( new_size*sizeof(struct _ht) );
+ sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 0);
+
if( new_ht==0 ) return;
- if( pH->ht ) pH->xFree(pH->ht);
+ if( pH->ht ) sqlite3_free(pH->ht);
pH->ht = new_ht;
pH->htsize = new_size;
xHash = hashFunction(pH->keyClass);
@@ -291,10 +298,10 @@ static void removeElementGivenHash(
if( pEntry->count<=0 ){
pEntry->chain = 0;
}
- if( pH->copyKey && elem->pKey ){
- pH->xFree(elem->pKey);
+ if( pH->copyKey ){
+ sqlite3_free(elem->pKey);
}
- pH->xFree( elem );
+ sqlite3_free( elem );
pH->count--;
if( pH->count<=0 ){
assert( pH->first==0 );
@@ -304,10 +311,11 @@ static void removeElementGivenHash(
}
/* Attempt to locate an element of the hash table pH with a key
-** that matches pKey,nKey. Return the data for this element if it is
-** found, or NULL if there is no match.
+** that matches pKey,nKey. Return a pointer to the corresponding
+** HashElem structure for this element if it is found, or NULL
+** otherwise.
*/
-void *sqlite3HashFind(const Hash *pH, const void *pKey, int nKey){
+HashElem *sqlite3HashFindElem(const Hash *pH, const void *pKey, int nKey){
int h; /* A hash on key */
HashElem *elem; /* The element that matches key */
int (*xHash)(const void*,int); /* The hash function */
@@ -318,6 +326,16 @@ void *sqlite3HashFind(const Hash *pH, const void *pKey, int nKey){
h = (*xHash)(pKey,nKey);
assert( (pH->htsize & (pH->htsize-1))==0 );
elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1));
+ return elem;
+}
+
+/* Attempt to locate an element of the hash table pH with a key
+** that matches pKey,nKey. Return the data for this element if it is
+** found, or NULL if there is no match.
+*/
+void *sqlite3HashFind(const Hash *pH, const void *pKey, int nKey){
+ HashElem *elem; /* The element that matches key */
+ elem = sqlite3HashFindElem(pH, pKey, nKey);
return elem ? elem->data : 0;
}
@@ -356,16 +374,20 @@ void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){
removeElementGivenHash(pH,elem,h);
}else{
elem->data = data;
+ if( !pH->copyKey ){
+ elem->pKey = (void *)pKey;
+ }
+ assert(nKey==elem->nKey);
}
return old_data;
}
if( data==0 ) return 0;
- new_elem = (HashElem*)pH->xMalloc( sizeof(HashElem) );
+ new_elem = (HashElem*)sqlite3_malloc( sizeof(HashElem) );
if( new_elem==0 ) return data;
if( pH->copyKey && pKey!=0 ){
- new_elem->pKey = pH->xMalloc( nKey );
+ new_elem->pKey = sqlite3_malloc( nKey );
if( new_elem->pKey==0 ){
- pH->xFree(new_elem);
+ sqlite3_free(new_elem);
return data;
}
memcpy((void*)new_elem->pKey, pKey, nKey);
@@ -378,7 +400,10 @@ void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){
rehash(pH,8);
if( pH->htsize==0 ){
pH->count = 0;
- pH->xFree(new_elem);
+ if( pH->copyKey ){
+ sqlite3_free(new_elem->pKey);
+ }
+ sqlite3_free(new_elem);
return data;
}
}
diff --git a/ext/pdo_sqlite/sqlite/src/hash.h b/ext/pdo_sqlite/sqlite/src/hash.h
index 4707649489..84a45270af 100644
--- a/ext/pdo_sqlite/sqlite/src/hash.h
+++ b/ext/pdo_sqlite/sqlite/src/hash.h
@@ -33,10 +33,8 @@ struct Hash {
char keyClass; /* SQLITE_HASH_INT, _POINTER, _STRING, _BINARY */
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 */
+ HashElem *first; /* The first element of the array */
struct _ht { /* the hash table */
int count; /* Number of entries with this hash */
HashElem *chain; /* Pointer to first entry with this hash */
@@ -83,6 +81,7 @@ struct HashElem {
void sqlite3HashInit(Hash*, int keytype, int copyKey);
void *sqlite3HashInsert(Hash*, const void *pKey, int nKey, void *pData);
void *sqlite3HashFind(const Hash*, const void *pKey, int nKey);
+HashElem *sqlite3HashFindElem(const Hash*, const void *pKey, int nKey);
void sqlite3HashClear(Hash*);
/*
diff --git a/ext/pdo_sqlite/sqlite/src/insert.c b/ext/pdo_sqlite/sqlite/src/insert.c
index d4cf74a3d7..22697eb4dd 100644
--- a/ext/pdo_sqlite/sqlite/src/insert.c
+++ b/ext/pdo_sqlite/sqlite/src/insert.c
@@ -17,7 +17,7 @@
#include "sqliteInt.h"
/*
-** Set P3 of the most recently inserted opcode to a column affinity
+** Set P4 of the most recently inserted opcode to a column affinity
** string for index pIdx. A column affinity string has one character
** for each column in the table, according to the affinity of the column:
**
@@ -28,6 +28,9 @@
** 'c' NUMERIC
** 'd' INTEGER
** 'e' REAL
+**
+** An extra 'b' is appended to the end of the string to cover the
+** rowid that appears as the last column in every index.
*/
void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
if( !pIdx->zColAff ){
@@ -41,21 +44,23 @@ void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
*/
int n;
Table *pTab = pIdx->pTable;
- pIdx->zColAff = (char *)sqliteMalloc(pIdx->nColumn+1);
+ sqlite3 *db = sqlite3VdbeDb(v);
+ pIdx->zColAff = (char *)sqlite3DbMallocZero(db, pIdx->nColumn+2);
if( !pIdx->zColAff ){
return;
}
for(n=0; n<pIdx->nColumn; n++){
pIdx->zColAff[n] = pTab->aCol[pIdx->aiColumn[n]].affinity;
}
- pIdx->zColAff[pIdx->nColumn] = '\0';
+ pIdx->zColAff[n++] = SQLITE_AFF_NONE;
+ pIdx->zColAff[n] = 0;
}
- sqlite3VdbeChangeP3(v, -1, pIdx->zColAff, 0);
+ sqlite3VdbeChangeP4(v, -1, pIdx->zColAff, 0);
}
/*
-** Set P3 of the most recently inserted opcode to a column affinity
+** Set P4 of the most recently inserted opcode to a column affinity
** string for table pTab. A column affinity string has one character
** for each column indexed by the index, according to the affinity of the
** column:
@@ -79,8 +84,9 @@ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
if( !pTab->zColAff ){
char *zColAff;
int i;
+ sqlite3 *db = sqlite3VdbeDb(v);
- zColAff = (char *)sqliteMalloc(pTab->nCol+1);
+ zColAff = (char *)sqlite3DbMallocZero(db, pTab->nCol+1);
if( !zColAff ){
return;
}
@@ -93,31 +99,157 @@ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
pTab->zColAff = zColAff;
}
- sqlite3VdbeChangeP3(v, -1, pTab->zColAff, 0);
+ sqlite3VdbeChangeP4(v, -1, pTab->zColAff, 0);
}
/*
-** Return non-zero if SELECT statement p opens the table with rootpage
-** iTab in database iDb. This is used to see if a statement of the form
-** "INSERT INTO <iDb, iTab> SELECT ..." can run without using temporary
-** table for the results of the SELECT.
-**
-** No checking is done for sub-selects that are part of expressions.
+** Return non-zero if the table pTab in database iDb or any of its indices
+** have been opened at any point in the VDBE program beginning at location
+** iStartAddr throught the end of the program. This is used to see if
+** a statement of the form "INSERT INTO <iDb, pTab> SELECT ..." can
+** run without using temporary table for the results of the SELECT.
*/
-static int selectReadsTable(Select *p, Schema *pSchema, int iTab){
+static int readsTable(Vdbe *v, int iStartAddr, int iDb, Table *pTab){
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, pSchema, iTab) ) return 1;
- }else{
- if( pItem->pTab->pSchema==pSchema && pItem->pTab->tnum==iTab ) return 1;
+ int iEnd = sqlite3VdbeCurrentAddr(v);
+ for(i=iStartAddr; i<iEnd; i++){
+ VdbeOp *pOp = sqlite3VdbeGetOp(v, i);
+ assert( pOp!=0 );
+ if( pOp->opcode==OP_OpenRead && pOp->p3==iDb ){
+ Index *pIndex;
+ int tnum = pOp->p2;
+ if( tnum==pTab->tnum ){
+ return 1;
+ }
+ for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
+ if( tnum==pIndex->tnum ){
+ return 1;
+ }
+ }
+ }
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( pOp->opcode==OP_VOpen && pOp->p4.pVtab==pTab->pVtab ){
+ assert( pOp->p4.pVtab!=0 );
+ assert( pOp->p4type==P4_VTAB );
+ return 1;
}
+#endif
}
return 0;
}
+#ifndef SQLITE_OMIT_AUTOINCREMENT
+/*
+** Write out code to initialize the autoincrement logic. This code
+** looks up the current autoincrement value in the sqlite_sequence
+** table and stores that value in a register. Code generated by
+** autoIncStep() will keep that register holding the largest
+** rowid value. Code generated by autoIncEnd() will write the new
+** largest value of the counter back into the sqlite_sequence table.
+**
+** This routine returns the index of the mem[] cell that contains
+** the maximum rowid counter.
+**
+** Three consecutive registers are allocated by this routine. The
+** first two hold the name of the target table and the maximum rowid
+** inserted into the target table, respectively.
+** The third holds the rowid in sqlite_sequence where we will
+** write back the revised maximum rowid. This routine returns the
+** index of the second of these three registers.
+*/
+static int autoIncBegin(
+ Parse *pParse, /* Parsing context */
+ int iDb, /* Index of the database holding pTab */
+ Table *pTab /* The table we are writing to */
+){
+ int memId = 0; /* Register holding maximum rowid */
+ if( pTab->autoInc ){
+ Vdbe *v = pParse->pVdbe;
+ Db *pDb = &pParse->db->aDb[iDb];
+ int iCur = pParse->nTab;
+ int addr; /* Address of the top of the loop */
+ assert( v );
+ pParse->nMem++; /* Holds name of table */
+ memId = ++pParse->nMem;
+ pParse->nMem++;
+ sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
+ addr = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, pTab->zName, 0);
+ sqlite3VdbeAddOp2(v, OP_Rewind, iCur, addr+8);
+ sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, memId);
+ sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId);
+ sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, memId+1);
+ sqlite3VdbeAddOp3(v, OP_Column, iCur, 1, memId);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr+8);
+ sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+2);
+ sqlite3VdbeAddOp2(v, OP_Close, iCur, 0);
+ }
+ return memId;
+}
+
+/*
+** Update the maximum rowid for an autoincrement calculation.
+**
+** This routine should be called when the top of the stack holds a
+** new rowid that is about to be inserted. If that new rowid is
+** larger than the maximum rowid in the memId memory cell, then the
+** memory cell is updated. The stack is unchanged.
+*/
+static void autoIncStep(Parse *pParse, int memId, int regRowid){
+ if( memId>0 ){
+ sqlite3VdbeAddOp2(pParse->pVdbe, OP_MemMax, memId, regRowid);
+ }
+}
+
+/*
+** After doing one or more inserts, the maximum rowid is stored
+** in reg[memId]. Generate code to write this value back into the
+** the sqlite_sequence table.
+*/
+static void autoIncEnd(
+ Parse *pParse, /* The parsing context */
+ int iDb, /* Index of the database holding pTab */
+ Table *pTab, /* Table we are inserting into */
+ int memId /* Memory cell holding the maximum rowid */
+){
+ if( pTab->autoInc ){
+ int iCur = pParse->nTab;
+ Vdbe *v = pParse->pVdbe;
+ Db *pDb = &pParse->db->aDb[iDb];
+ int j1;
+
+ assert( v );
+ sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
+ j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1);
+ sqlite3VdbeAddOp2(v, OP_NewRowid, iCur, memId+1);
+ sqlite3VdbeJumpHere(v, j1);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, memId-1);
+ sqlite3VdbeAddOp3(v, OP_Insert, iCur, memId-1, memId+1);
+ sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
+ sqlite3VdbeAddOp1(v, OP_Close, iCur);
+ }
+}
+#else
+/*
+** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines
+** above are all no-ops
+*/
+# define autoIncBegin(A,B,C) (0)
+# define autoIncStep(A,B,C)
+# define autoIncEnd(A,B,C,D)
+#endif /* SQLITE_OMIT_AUTOINCREMENT */
+
+
+/* Forward declaration */
+static int xferOptimization(
+ Parse *pParse, /* Parser context */
+ Table *pDest, /* The table we are inserting into */
+ Select *pSelect, /* A SELECT statement to use as the data source */
+ int onError, /* How to handle constraint errors */
+ int iDbDest /* The database of pDest */
+);
+
/*
** This routine is call to handle SQL of the following forms:
**
@@ -133,7 +265,7 @@ static int selectReadsTable(Select *p, Schema *pSchema, int iTab){
** NULL and pSelect is a pointer to the select statement used to generate
** data for the insert.
**
-** The code generated follows one of three templates. For a simple
+** The code generated follows one of four templates. For a simple
** select with data coming from a VALUES clause, the code executes
** once straight down through. The template looks like this:
**
@@ -142,16 +274,37 @@ static int selectReadsTable(Select *p, Schema *pSchema, int iTab){
** write the resulting record into <table>
** cleanup
**
-** If the statement is of the form
+** The three remaining templates assume the statement is of the form
**
** INSERT INTO <table> SELECT ...
**
-** And the SELECT clause does not read from <table> at any time, then
-** the generated code follows this template:
+** If the SELECT clause is of the restricted form "SELECT * FROM <table2>" -
+** in other words if the SELECT pulls all columns from a single table
+** and there is no WHERE or LIMIT or GROUP BY or ORDER BY clauses, and
+** if <table2> and <table1> are distinct tables but have identical
+** schemas, including all the same indices, then a special optimization
+** is invoked that copies raw records from <table2> over to <table1>.
+** See the xferOptimization() function for the implementation of this
+** template. This is the second template.
+**
+** open a write cursor to <table>
+** open read cursor on <table2>
+** transfer all records in <table2> over to <table>
+** close cursors
+** foreach index on <table>
+** open a write cursor on the <table> index
+** open a read cursor on the corresponding <table2> index
+** transfer all records from the read to the write cursors
+** close cursors
+** end foreach
+**
+** The third template is for when the second template does not apply
+** and the SELECT clause does not read from <table> at any time.
+** The generated code follows this template:
**
** goto B
** A: setup for the SELECT
-** loop over the tables in the SELECT
+** loop over the rows in the SELECT
** gosub C
** end loop
** cleanup after the SELECT
@@ -162,7 +315,7 @@ static int selectReadsTable(Select *p, Schema *pSchema, int iTab){
** return
** D: cleanup
**
-** The third template is used if the insert statement takes its
+** The fourth template is used if the insert statement takes its
** values from a SELECT but the data is being inserted into a table
** that is also read as part of the SELECT. In the third form,
** we have to use a intermediate table to store the results of
@@ -193,42 +346,49 @@ void sqlite3Insert(
IdList *pColumn, /* Column names corresponding to IDLIST. */
int onError /* How to handle constraint errors */
){
- Table *pTab; /* The table to insert into */
+ sqlite3 *db; /* The main database structure */
+ Table *pTab; /* The table to insert into. aka TABLE */
char *zTab; /* Name of the table into which we are inserting */
const char *zDb; /* Name of the database holding this table */
int i, j, idx; /* Loop counters */
Vdbe *v; /* Generate code into this virtual machine */
Index *pIdx; /* For looping over indices of the table */
int nColumn; /* Number of columns in the data */
- int base = 0; /* VDBE Cursor number for pTab */
- int iCont=0,iBreak=0; /* Beginning and end of the loop over srcTab */
- sqlite3 *db; /* The main database structure */
+ int nHidden = 0; /* Number of hidden columns if TABLE is virtual */
+ int baseCur = 0; /* VDBE Cursor number for pTab */
int keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */
int endOfLoop; /* Label for the end of the insertion loop */
int useTempTable = 0; /* Store SELECT results in intermediate table */
int srcTab = 0; /* Data comes from this temporary cursor if >=0 */
+ int iCont=0,iBreak=0; /* Beginning and end of the loop over srcTab */
int iSelectLoop = 0; /* Address of code that implements the SELECT */
int iCleanup = 0; /* Address of the cleanup code */
int iInsertBlock = 0; /* Address of the subroutine used to insert data */
- int iCntMem = 0; /* Memory cell used for the row counter */
- int newIdx = -1; /* Cursor for the NEW table */
+ int newIdx = -1; /* Cursor for the NEW pseudo-table */
+ int iDb; /* Index of database holding TABLE */
Db *pDb; /* The database containing table being inserted into */
- int counterMem = 0; /* Memory cell holding AUTOINCREMENT counter */
- int iDb;
+ int appendFlag = 0; /* True if the insert is likely to be an append */
+
+ /* Register allocations */
+ int regFromSelect; /* Base register for data coming from SELECT */
+ int regAutoinc = 0; /* Register holding the AUTOINCREMENT counter */
+ int regRowCount = 0; /* Memory cell used for the row counter */
+ int regIns; /* Block of regs holding rowid+data being inserted */
+ int regRowid; /* registers holding insert rowid */
+ int regData; /* register holding first column to insert */
+ int regRecord; /* Holds the assemblied row record */
+ int *aRegIdx = 0; /* One register allocated to each index */
+
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to insert into a view */
int triggers_exist = 0; /* True if there are FOR EACH ROW triggers */
#endif
-#ifndef SQLITE_OMIT_AUTOINCREMENT
- int counterRowid = 0; /* Memory cell holding rowid of autoinc counter */
-#endif
-
- if( pParse->nErr || sqlite3MallocFailed() ){
+ db = pParse->db;
+ if( pParse->nErr || db->mallocFailed ){
goto insert_cleanup;
}
- db = pParse->db;
/* Locate the table into which we will be inserting new information.
*/
@@ -291,31 +451,25 @@ void sqlite3Insert(
newIdx = pParse->nTab++;
}
-#ifndef SQLITE_OMIT_AUTOINCREMENT
- /* If this is an AUTOINCREMENT table, look up the sequence number in the
- ** sqlite_sequence table and store it in memory cell counterMem. Also
- ** remember the rowid of the sqlite_sequence table entry in memory cell
- ** counterRowid.
+#ifndef SQLITE_OMIT_XFER_OPT
+ /* If the statement is of the form
+ **
+ ** INSERT INTO <table1> SELECT * FROM <table2>;
+ **
+ ** Then special optimizations can be applied that make the transfer
+ ** very fast and which reduce fragmentation of indices.
*/
- if( pTab->autoInc ){
- int iCur = pParse->nTab;
- int addr = sqlite3VdbeCurrentAddr(v);
- counterRowid = pParse->nMem++;
- counterMem = pParse->nMem++;
- 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, 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, addr+13);
- sqlite3VdbeAddOp(v, OP_Next, iCur, addr+4);
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
+ if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){
+ assert( !triggers_exist );
+ assert( pList==0 );
+ goto insert_cleanup;
}
-#endif /* SQLITE_OMIT_AUTOINCREMENT */
+#endif /* SQLITE_OMIT_XFER_OPT */
+
+ /* If this is an AUTOINCREMENT table, look up the sequence number in the
+ ** sqlite_sequence table and store it in memory cell regAutoinc.
+ */
+ regAutoinc = autoIncBegin(pParse, iDb, pTab);
/* Figure out how many columns of data are supplied. If the data
** is coming from a SELECT statement, then this step also generates
@@ -328,19 +482,23 @@ void sqlite3Insert(
if( pSelect ){
/* Data is coming from a SELECT. Generate code to implement that SELECT
*/
+ SelectDest dest;
int rc, iInitCode;
- iInitCode = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
+
+ iInitCode = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
iSelectLoop = sqlite3VdbeCurrentAddr(v);
iInsertBlock = sqlite3VdbeMakeLabel(v);
+ sqlite3SelectDestInit(&dest, SRT_Subroutine, iInsertBlock);
/* 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 || sqlite3MallocFailed() ){
+ rc = sqlite3Select(pParse, pSelect, &dest, 0, 0, 0, 0);
+ if( rc || pParse->nErr || db->mallocFailed ){
goto insert_cleanup;
}
+ regFromSelect = dest.iMem;
iCleanup = sqlite3VdbeMakeLabel(v);
- sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, iCleanup);
assert( pSelect->pEList );
nColumn = pSelect->pEList->nExpr;
@@ -352,7 +510,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->pSchema,pTab->tnum) ){
+ if( triggers_exist || readsTable(v, iSelectLoop, iDb, pTab) ){
useTempTable = 1;
}
@@ -360,22 +518,27 @@ void sqlite3Insert(
/* Generate the subroutine that SELECT calls to process each row of
** the result. Store the result in a temporary table
*/
+ int regRec, regRowid;
+
srcTab = pParse->nTab++;
+ regRec = sqlite3GetTempReg(pParse);
+ regRowid = sqlite3GetTempReg(pParse);
sqlite3VdbeResolveLabel(v, iInsertBlock);
- sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
- sqlite3VdbeAddOp(v, OP_NewRowid, srcTab, 0);
- sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
- sqlite3VdbeAddOp(v, OP_Insert, srcTab, 0);
- sqlite3VdbeAddOp(v, OP_Return, 0, 0);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
+ sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regRowid);
+ sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regRowid);
+ sqlite3VdbeAddOp2(v, OP_Return, 0, 0);
+ sqlite3ReleaseTempReg(pParse, regRec);
+ sqlite3ReleaseTempReg(pParse, regRowid);
/* The following code runs first because the GOTO at the very top
** of the program jumps to it. Create the temporary table, then jump
** back up and execute the SELECT code above.
*/
sqlite3VdbeJumpHere(v, iInitCode);
- sqlite3VdbeAddOp(v, OP_OpenEphemeral, srcTab, 0);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, srcTab, nColumn);
- sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop);
+ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, 0);
+ sqlite3VdbeAddOp2(v, OP_SetNumColumns, srcTab, nColumn);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, iSelectLoop);
sqlite3VdbeResolveLabel(v, iCleanup);
}else{
sqlite3VdbeJumpHere(v, iInitCode);
@@ -387,11 +550,9 @@ void sqlite3Insert(
NameContext sNC;
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
- assert( pList!=0 );
srcTab = -1;
- useTempTable = 0;
- assert( pList );
- nColumn = pList->nExpr;
+ assert( useTempTable==0 );
+ nColumn = pList ? pList->nExpr : 0;
for(i=0; i<nColumn; i++){
if( sqlite3ExprResolveNames(&sNC, pList->a[i].pExpr) ){
goto insert_cleanup;
@@ -402,7 +563,12 @@ void sqlite3Insert(
/* Make sure the number of columns in the source data matches the number
** of columns to be inserted into the table.
*/
- if( pColumn==0 && nColumn!=pTab->nCol ){
+ if( IsVirtual(pTab) ){
+ for(i=0; i<pTab->nCol; i++){
+ nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0);
+ }
+ }
+ if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){
sqlite3ErrorMsg(pParse,
"table %S has %d columns but %d values were supplied",
pTabList, 0, pTab->nCol, nColumn);
@@ -455,28 +621,38 @@ void sqlite3Insert(
** key, the set the keyColumn variable to the primary key column index
** in the original table definition.
*/
- if( pColumn==0 ){
+ if( pColumn==0 && nColumn>0 ){
keyColumn = pTab->iPKey;
}
/* Open the temp table for FOR EACH ROW triggers
*/
if( triggers_exist ){
- sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
+ sqlite3VdbeAddOp2(v, OP_OpenPseudo, newIdx, 0);
+ sqlite3VdbeAddOp2(v, OP_SetNumColumns, newIdx, pTab->nCol);
}
/* Initialize the count of rows to be inserted
*/
if( db->flags & SQLITE_CountRows ){
- iCntMem = pParse->nMem++;
- sqlite3VdbeAddOp(v, OP_MemInt, 0, iCntMem);
+ regRowCount = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
}
- /* Open tables and indices if there are no row triggers */
- if( !triggers_exist ){
- base = pParse->nTab;
- sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite);
+ /* If this is not a view, open the table and and all indices */
+ if( !isView ){
+ int nIdx;
+ int i;
+
+ baseCur = pParse->nTab;
+ nIdx = sqlite3OpenTableAndIndices(pParse, pTab, baseCur, OP_OpenWrite);
+ aRegIdx = sqlite3DbMallocZero(db, sizeof(int)*(nIdx+1));
+ if( aRegIdx==0 ){
+ goto insert_cleanup;
+ }
+ for(i=0; i<nIdx; i++){
+ aRegIdx[i] = ++pParse->nMem;
+ }
}
/* If the data source is a temporary table, then we have to create
@@ -486,17 +662,32 @@ void sqlite3Insert(
*/
if( useTempTable ){
iBreak = sqlite3VdbeMakeLabel(v);
- sqlite3VdbeAddOp(v, OP_Rewind, srcTab, iBreak);
+ sqlite3VdbeAddOp2(v, OP_Rewind, srcTab, iBreak);
iCont = sqlite3VdbeCurrentAddr(v);
}else if( pSelect ){
- sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, iSelectLoop);
sqlite3VdbeResolveLabel(v, iInsertBlock);
}
+ /* Allocate registers for holding the rowid of the new row,
+ ** the content of the new row, and the assemblied row record.
+ */
+ regRecord = ++pParse->nMem;
+ regRowid = regIns = pParse->nMem+1;
+ pParse->nMem += pTab->nCol + 1;
+ if( IsVirtual(pTab) ){
+ regRowid++;
+ pParse->nMem++;
+ }
+ regData = regRowid+1;
+
/* Run the BEFORE and INSTEAD OF triggers, if there are any
*/
endOfLoop = sqlite3VdbeMakeLabel(v);
if( triggers_exist & TRIGGER_BEFORE ){
+ int regRowid;
+ int regCols;
+ int regRec;
/* build the NEW.* reference row. Note that if there is an INTEGER
** PRIMARY KEY into which a NULL is being inserted, that NULL will be
@@ -504,21 +695,29 @@ void sqlite3Insert(
** we do not know what the unique ID will be (because the insert has
** not happened yet) so we substitute a rowid of -1
*/
+ regRowid = sqlite3GetTempReg(pParse);
if( keyColumn<0 ){
- sqlite3VdbeAddOp(v, OP_Integer, -1, 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid);
}else if( useTempTable ){
- sqlite3VdbeAddOp(v, OP_Column, srcTab, keyColumn);
+ sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regRowid);
}else{
+ int j1;
assert( pSelect==0 ); /* Otherwise useTempTable is true */
- sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr);
- sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- sqlite3VdbeAddOp(v, OP_Integer, -1, 0);
- sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
+ sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regRowid);
+ j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid);
+ sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid);
+ sqlite3VdbeJumpHere(v, j1);
+ sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid);
}
+ /* Cannot have triggers on a virtual table. If it were possible,
+ ** this block would have to account for hidden column.
+ */
+ assert(!IsVirtual(pTab));
+
/* Create the new column data
*/
+ regCols = sqlite3GetTempRange(pParse, pTab->nCol);
for(i=0; i<pTab->nCol; i++){
if( pColumn==0 ){
j = i;
@@ -528,15 +727,16 @@ void sqlite3Insert(
}
}
if( pColumn && j>=pColumn->nId ){
- sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);
+ sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i);
}else if( useTempTable ){
- sqlite3VdbeAddOp(v, OP_Column, srcTab, j);
+ sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i);
}else{
assert( pSelect==0 ); /* Otherwise useTempTable is true */
- sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr);
+ sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i);
}
}
- sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
+ regRec = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regCols, pTab->nCol, regRec);
/* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
** do not attempt any conversions before assembling the record.
@@ -546,23 +746,18 @@ void sqlite3Insert(
if( !isView ){
sqlite3TableAffinityStr(v, pTab);
}
- sqlite3VdbeAddOp(v, OP_Insert, newIdx, 0);
+ sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRec, regRowid);
+ sqlite3ReleaseTempReg(pParse, regRec);
+ sqlite3ReleaseTempReg(pParse, regRowid);
+ sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol);
/* Fire BEFORE or INSTEAD OF triggers */
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_BEFORE, pTab,
- newIdx, -1, onError, endOfLoop) ){
+ newIdx, -1, onError, endOfLoop, 0, 0) ){
goto insert_cleanup;
}
}
- /* If any triggers exists, the opening of tables and indices is deferred
- ** until now.
- */
- if( triggers_exist && !isView ){
- base = pParse->nTab;
- sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite);
- }
-
/* Push the record number for the new entry onto the stack. The
** record number is a randomly generate integer created by NewRowid
** except when the table has an INTEGER PRIMARY KEY column, in which
@@ -570,62 +765,79 @@ void sqlite3Insert(
*/
if( !isView ){
if( IsVirtual(pTab) ){
- /* The row that the VUpdate opcode will delete: none */
- sqlite3VdbeAddOp(v, OP_Null, 0, 0);
+ /* The row that the VUpdate opcode will delete: none */
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regIns);
}
if( keyColumn>=0 ){
if( useTempTable ){
- sqlite3VdbeAddOp(v, OP_Column, srcTab, keyColumn);
+ sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regRowid);
}else if( pSelect ){
- sqlite3VdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1);
+ sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+keyColumn, regRowid);
}else{
- sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr);
+ VdbeOp *pOp;
+ sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regRowid);
+ pOp = sqlite3VdbeGetOp(v, sqlite3VdbeCurrentAddr(v) - 1);
+ if( pOp && pOp->opcode==OP_Null ){
+ appendFlag = 1;
+ pOp->opcode = OP_NewRowid;
+ pOp->p1 = baseCur;
+ pOp->p2 = regRowid;
+ pOp->p3 = regAutoinc;
+ }
}
/* If the PRIMARY KEY expression is NULL, then use OP_NewRowid
** to generate a unique primary key value.
*/
- sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem);
- sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
+ if( !appendFlag ){
+ int j1;
+ j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid);
+ sqlite3VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc);
+ sqlite3VdbeJumpHere(v, j1);
+ sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid);
+ }
}else if( IsVirtual(pTab) ){
- sqlite3VdbeAddOp(v, OP_Null, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid);
}else{
- sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem);
- }
-#ifndef SQLITE_OMIT_AUTOINCREMENT
- if( pTab->autoInc ){
- sqlite3VdbeAddOp(v, OP_MemMax, counterMem, 0);
+ sqlite3VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc);
+ appendFlag = 1;
}
-#endif /* SQLITE_OMIT_AUTOINCREMENT */
+ autoIncStep(pParse, regAutoinc, regRowid);
/* Push onto the stack, data for all columns of the new entry, beginning
** with the first column.
*/
+ nHidden = 0;
for(i=0; i<pTab->nCol; i++){
+ int iRegStore = regRowid+1+i;
if( i==pTab->iPKey ){
/* The value of the INTEGER PRIMARY KEY column is always a NULL.
** Whenever this column is read, the record number will be substituted
** in its place. So will fill this column with a NULL to avoid
** taking up data space with information that will never be used. */
- sqlite3VdbeAddOp(v, OP_Null, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, iRegStore);
continue;
}
if( pColumn==0 ){
- j = i;
+ if( IsHiddenColumn(&pTab->aCol[i]) ){
+ assert( IsVirtual(pTab) );
+ j = -1;
+ nHidden++;
+ }else{
+ j = i - nHidden;
+ }
}else{
for(j=0; j<pColumn->nId; j++){
if( pColumn->a[j].idx==i ) break;
}
}
- if( pColumn && j>=pColumn->nId ){
- sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);
+ if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){
+ sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore);
}else if( useTempTable ){
- sqlite3VdbeAddOp(v, OP_Column, srcTab, j);
+ sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore);
}else if( pSelect ){
- sqlite3VdbeAddOp(v, OP_Dup, i+nColumn-j, 1);
+ sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore);
}else{
- sqlite3ExprCode(pParse, pList->a[j].pExpr);
+ sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore);
}
}
@@ -635,36 +847,46 @@ void sqlite3Insert(
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
pParse->pVirtualLock = pTab;
- sqlite3VdbeOp3(v, OP_VUpdate, 1, pTab->nCol+2,
- (const char*)pTab->pVtab, P3_VTAB);
+ sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns,
+ (const char*)pTab->pVtab, P4_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);
+ sqlite3GenerateConstraintChecks(
+ pParse,
+ pTab,
+ baseCur,
+ regIns,
+ aRegIdx,
+ keyColumn>=0,
+ 0,
+ onError,
+ endOfLoop
+ );
+ sqlite3CompleteInsertion(
+ pParse,
+ pTab,
+ baseCur,
+ regIns,
+ aRegIdx,
+ 0,
+ 0,
+ (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1,
+ appendFlag
+ );
}
}
/* Update the count of rows that are inserted
*/
if( (db->flags & SQLITE_CountRows)!=0 ){
- sqlite3VdbeAddOp(v, OP_MemIncr, 1, iCntMem);
+ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
}
if( triggers_exist ){
- /* Close all tables opened */
- if( !isView ){
- sqlite3VdbeAddOp(v, OP_Close, base, 0);
- for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
- sqlite3VdbeAddOp(v, OP_Close, idx+base, 0);
- }
- }
-
/* Code AFTER triggers */
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_AFTER, pTab,
- newIdx, -1, onError, endOfLoop) ){
+ newIdx, -1, onError, endOfLoop, 0, 0) ){
goto insert_cleanup;
}
}
@@ -673,43 +895,27 @@ void sqlite3Insert(
*/
sqlite3VdbeResolveLabel(v, endOfLoop);
if( useTempTable ){
- sqlite3VdbeAddOp(v, OP_Next, srcTab, iCont);
+ sqlite3VdbeAddOp2(v, OP_Next, srcTab, iCont);
sqlite3VdbeResolveLabel(v, iBreak);
- sqlite3VdbeAddOp(v, OP_Close, srcTab, 0);
+ sqlite3VdbeAddOp2(v, OP_Close, srcTab, 0);
}else if( pSelect ){
- sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0);
- sqlite3VdbeAddOp(v, OP_Return, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_Return, 0, 0);
sqlite3VdbeResolveLabel(v, iCleanup);
}
- if( !triggers_exist && !IsVirtual(pTab) ){
+ if( !IsVirtual(pTab) && !isView ){
/* Close all tables opened */
- sqlite3VdbeAddOp(v, OP_Close, base, 0);
+ sqlite3VdbeAddOp2(v, OP_Close, baseCur, 0);
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
- sqlite3VdbeAddOp(v, OP_Close, idx+base, 0);
+ sqlite3VdbeAddOp2(v, OP_Close, idx+baseCur, 0);
}
}
-#ifndef SQLITE_OMIT_AUTOINCREMENT
/* Update the sqlite_sequence table by storing the content of the
- ** counter value in memory counterMem back into the sqlite_sequence
+ ** counter value in memory regAutoinc back into the sqlite_sequence
** table.
*/
- if( pTab->autoInc ){
- int iCur = pParse->nTab;
- int addr = sqlite3VdbeCurrentAddr(v);
- sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
- sqlite3VdbeAddOp(v, OP_MemLoad, counterRowid, 0);
- 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);
- sqlite3VdbeAddOp(v, OP_MemLoad, counterMem, 0);
- sqlite3VdbeAddOp(v, OP_MakeRecord, 2, 0);
- sqlite3VdbeAddOp(v, OP_Insert, iCur, 0);
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }
-#endif
+ autoIncEnd(pParse, iDb, pTab, regAutoinc);
/*
** Return the number of rows inserted. If this routine is
@@ -717,10 +923,9 @@ void sqlite3Insert(
** invoke the callback function.
*/
if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
- sqlite3VdbeAddOp(v, OP_MemLoad, iCntMem, 0);
- sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", P4_STATIC);
}
insert_cleanup:
@@ -728,17 +933,17 @@ insert_cleanup:
sqlite3ExprListDelete(pList);
sqlite3SelectDelete(pSelect);
sqlite3IdListDelete(pColumn);
+ sqlite3_free(aRegIdx);
}
/*
-** Generate code to do a constraint check prior to an INSERT or an UPDATE.
+** Generate code to do constraint checks prior to an INSERT or an UPDATE.
**
-** When this routine is called, the stack contains (from bottom to top)
-** the following values:
+** The input is a range of consecutive registers as follows:
**
** 1. The rowid of the row to be updated before the update. This
** value is omitted unless we are doing an UPDATE that involves a
-** change to the record number.
+** change to the record number or writing to a virtual table.
**
** 2. The rowid of the row after the update.
**
@@ -748,15 +953,20 @@ insert_cleanup:
**
** N. The data in the last column of the entry after the update.
**
+** The regRowid parameter is the index of the register containing (2).
+**
** The old rowid shown as entry (1) above is omitted unless both isUpdate
** and rowidChng are 1. isUpdate is true for UPDATEs and false for
-** INSERTs and rowidChng is true if the record number is being changed.
+** INSERTs. RowidChng means that the new rowid is explicitly specified by
+** the update or insert statement. If rowidChng is false, it means that
+** the rowid is computed automatically in an insert or that the rowid value
+** is not modified by the update.
**
-** The code generated by this routine pushes additional entries onto
-** the stack which are the keys for new index entries for the new record.
-** The order of index keys is the same as the order of the indices on
-** the pTable->pIndex list. A key is only created for index i if
-** aIdxUsed!=0 and aIdxUsed[i]!=0.
+** The code generated by this routine store new index entries into
+** registers identified by aRegIdx[]. No index entry is created for
+** indices where aRegIdx[i]==0. The order of indices in aRegIdx[] is
+** the same as the order of indices on the linked list of indices
+** attached to the table.
**
** This routine also generates code to check constraints. NOT NULL,
** CHECK, and UNIQUE constraints are all checked. If a constraint fails,
@@ -798,23 +1008,18 @@ insert_cleanup:
** for the constraint is used.
**
** The calling routine must open a read/write cursor for pTab with
-** cursor number "base". All indices of pTab must also have open
-** read/write cursors with cursor number base+i for the i-th cursor.
+** cursor number "baseCur". All indices of pTab must also have open
+** read/write cursors with cursor number baseCur+i for the i-th cursor.
** Except, if there is no possibility of a REPLACE action then
-** cursors do not need to be open for indices where aIdxUsed[i]==0.
-**
-** If the isUpdate flag is true, it means that the "base" cursor is
-** initially pointing to an entry that is being updated. The isUpdate
-** flag causes extra code to be generated so that the "base" cursor
-** is still pointing at the same entry after the routine returns.
-** Without the isUpdate flag, the "base" cursor might be moved.
+** cursors do not need to be open for indices where aRegIdx[i]==0.
*/
void sqlite3GenerateConstraintChecks(
Parse *pParse, /* The parser context */
Table *pTab, /* the table into which we are inserting */
- int base, /* Index of a read/write cursor pointing at pTab */
- char *aIdxUsed, /* Which indices are used. NULL means all are used */
- int rowidChng, /* True if the record number will change */
+ int baseCur, /* Index of a read/write cursor pointing at pTab */
+ int regRowid, /* Index of the range of input registers */
+ int *aRegIdx, /* Register used by each index. 0 for unused indices */
+ int rowidChng, /* True if the rowid might collide with existing entry */
int isUpdate, /* True for UPDATE, False for INSERT */
int overrideError, /* Override onError to this if not OE_Default */
int ignoreDest /* Jump to this label on an OE_Ignore resolution */
@@ -823,18 +1028,19 @@ void sqlite3GenerateConstraintChecks(
Vdbe *v;
int nCol;
int onError;
- int addr;
- int extra;
+ int j1, j2, j3; /* Addresses of jump instructions */
+ int regData; /* Register containing first data column */
int iCur;
Index *pIdx;
int seenReplace = 0;
- int jumpInst1=0, jumpInst2;
int hasTwoRowids = (isUpdate && rowidChng);
v = sqlite3GetVdbe(pParse);
assert( v!=0 );
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
nCol = pTab->nCol;
+ regData = regRowid + 1;
+
/* Test all NOT NULL constraints.
*/
@@ -852,8 +1058,7 @@ void sqlite3GenerateConstraintChecks(
if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){
onError = OE_Abort;
}
- sqlite3VdbeAddOp(v, OP_Dup, nCol-1-i, 1);
- addr = sqlite3VdbeAddOp(v, OP_NotNull, 1, 0);
+ j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regData+i);
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|| onError==OE_Ignore || onError==OE_Replace );
switch( onError ){
@@ -861,24 +1066,22 @@ void sqlite3GenerateConstraintChecks(
case OE_Abort:
case OE_Fail: {
char *zMsg = 0;
- sqlite3VdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError);
+ sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_CONSTRAINT, onError);
sqlite3SetString(&zMsg, pTab->zName, ".", pTab->aCol[i].zName,
" may not be NULL", (char*)0);
- sqlite3VdbeChangeP3(v, -1, zMsg, P3_DYNAMIC);
+ sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC);
break;
}
case OE_Ignore: {
- sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRowids, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
break;
}
case OE_Replace: {
- sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);
- sqlite3VdbeAddOp(v, OP_Push, nCol-i, 0);
+ sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regData+i);
break;
}
}
- sqlite3VdbeJumpHere(v, addr);
+ sqlite3VdbeJumpHere(v, j1);
}
/* Test all CHECK constraints
@@ -886,17 +1089,13 @@ void sqlite3GenerateConstraintChecks(
#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;
+ pParse->ckBase = regData;
+ sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, SQLITE_JUMPIFNULL);
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);
+ if( onError==OE_Ignore ){
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
}else{
- sqlite3VdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError);
+ sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_CONSTRAINT, onError);
}
sqlite3VdbeResolveLabel(v, allOk);
}
@@ -914,70 +1113,65 @@ void sqlite3GenerateConstraintChecks(
onError = OE_Abort;
}
- if( isUpdate ){
- sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1);
- sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1);
- jumpInst1 = sqlite3VdbeAddOp(v, OP_Eq, 0, 0);
- }
- sqlite3VdbeAddOp(v, OP_Dup, nCol, 1);
- jumpInst2 = sqlite3VdbeAddOp(v, OP_NotExists, base, 0);
- switch( onError ){
- default: {
- onError = OE_Abort;
- /* Fall thru into the next case */
- }
- case OE_Rollback:
- case OE_Abort:
- case OE_Fail: {
- sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError,
- "PRIMARY KEY must be unique", P3_STATIC);
- break;
+ if( onError!=OE_Replace || pTab->pIndex ){
+ if( isUpdate ){
+ j2 = sqlite3VdbeAddOp3(v, OP_Eq, regRowid, 0, regRowid-1);
}
- case OE_Replace: {
- sqlite3GenerateRowIndexDelete(v, pTab, base, 0);
- if( isUpdate ){
- sqlite3VdbeAddOp(v, OP_Dup, nCol+hasTwoRowids, 1);
- sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);
+ j3 = sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, 0, regRowid);
+ switch( onError ){
+ default: {
+ onError = OE_Abort;
+ /* Fall thru into the next case */
+ }
+ case OE_Rollback:
+ case OE_Abort:
+ case OE_Fail: {
+ sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0,
+ "PRIMARY KEY must be unique", P4_STATIC);
+ break;
+ }
+ case OE_Replace: {
+ sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0);
+ seenReplace = 1;
+ break;
+ }
+ case OE_Ignore: {
+ assert( seenReplace==0 );
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
+ break;
}
- seenReplace = 1;
- break;
}
- case OE_Ignore: {
- assert( seenReplace==0 );
- sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRowids, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest);
- break;
+ sqlite3VdbeJumpHere(v, j3);
+ if( isUpdate ){
+ sqlite3VdbeJumpHere(v, j2);
}
}
- sqlite3VdbeJumpHere(v, jumpInst2);
- if( isUpdate ){
- sqlite3VdbeJumpHere(v, jumpInst1);
- sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1);
- sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);
- }
}
/* Test all UNIQUE constraints by creating entries for each UNIQUE
** index and making sure that duplicate entries do not already exist.
** Add the new records to the indices as we go.
*/
- extra = -1;
for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
- if( aIdxUsed && aIdxUsed[iCur]==0 ) continue; /* Skip unused indices */
- extra++;
+ int regIdx;
+ int regR;
+
+ if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */
/* Create a key for accessing the index entry */
- sqlite3VdbeAddOp(v, OP_Dup, nCol+extra, 1);
+ regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn+1);
for(i=0; i<pIdx->nColumn; i++){
int idx = pIdx->aiColumn[i];
if( idx==pTab->iPKey ){
- sqlite3VdbeAddOp(v, OP_Dup, i+extra+nCol+1, 1);
+ sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
}else{
- sqlite3VdbeAddOp(v, OP_Dup, i+extra+nCol-idx, 1);
+ sqlite3VdbeAddOp2(v, OP_SCopy, regData+idx, regIdx+i);
}
}
- jumpInst1 = sqlite3VdbeAddOp(v, OP_MakeIdxRec, pIdx->nColumn, 0);
+ sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn+1, aRegIdx[iCur]);
sqlite3IndexAffinityStr(v, pIdx);
+ sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1);
/* Find out what action to take in case there is an indexing conflict */
onError = pIdx->onError;
@@ -994,8 +1188,11 @@ void sqlite3GenerateConstraintChecks(
/* Check to see if the new index entry will be unique */
- sqlite3VdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRowids, 1);
- jumpInst2 = sqlite3VdbeAddOp(v, OP_IsUnique, base+iCur+1, 0);
+ j2 = sqlite3VdbeAddOp3(v, OP_IsNull, regIdx, 0, pIdx->nColumn);
+ regR = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp2(v, OP_SCopy, regRowid-hasTwoRowids, regR);
+ j3 = sqlite3VdbeAddOp4(v, OP_IsUnique, baseCur+iCur+1, 0,
+ regR, (char*)aRegIdx[iCur], P4_INT32);
/* Generate code that executes if the new index entry is not unique */
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
@@ -1006,58 +1203,52 @@ void sqlite3GenerateConstraintChecks(
case OE_Fail: {
int j, n1, n2;
char zErrMsg[200];
- strcpy(zErrMsg, pIdx->nColumn>1 ? "columns " : "column ");
+ sqlite3_snprintf(sizeof(zErrMsg), zErrMsg,
+ pIdx->nColumn>1 ? "columns " : "column ");
n1 = strlen(zErrMsg);
for(j=0; j<pIdx->nColumn && n1<sizeof(zErrMsg)-30; j++){
char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
n2 = strlen(zCol);
if( j>0 ){
- strcpy(&zErrMsg[n1], ", ");
+ sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], ", ");
n1 += 2;
}
if( n1+n2>sizeof(zErrMsg)-30 ){
- strcpy(&zErrMsg[n1], "...");
+ sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], "...");
n1 += 3;
break;
}else{
- strcpy(&zErrMsg[n1], zCol);
+ sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], "%s", zCol);
n1 += n2;
}
}
- strcpy(&zErrMsg[n1],
+ sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1],
pIdx->nColumn>1 ? " are not unique" : " is not unique");
- sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, zErrMsg, 0);
+ sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, zErrMsg,0);
break;
}
case OE_Ignore: {
assert( seenReplace==0 );
- sqlite3VdbeAddOp(v, OP_Pop, nCol+extra+3+hasTwoRowids, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
break;
}
case OE_Replace: {
- sqlite3GenerateRowDelete(pParse->db, v, pTab, base, 0);
- if( isUpdate ){
- sqlite3VdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRowids, 1);
- sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);
- }
+ sqlite3GenerateRowDelete(pParse, pTab, baseCur, regR, 0);
seenReplace = 1;
break;
}
}
-#if NULL_DISTINCT_FOR_UNIQUE
- sqlite3VdbeJumpHere(v, jumpInst1);
-#endif
- sqlite3VdbeJumpHere(v, jumpInst2);
+ sqlite3VdbeJumpHere(v, j2);
+ sqlite3VdbeJumpHere(v, j3);
+ sqlite3ReleaseTempReg(pParse, regR);
}
}
/*
** This routine generates code to finish the INSERT or UPDATE operation
** that was started by a prior call to sqlite3GenerateConstraintChecks.
-** The stack must contain keys for all active indices followed by data
-** and the rowid for the new entry. This routine creates the new
-** entries in all indices and in the main table.
+** A consecutive range of registers starting at regRowid contains the
+** rowid and the content to be inserted.
**
** The arguments to this routine should be the same as the first six
** arguments to sqlite3GenerateConstraintChecks.
@@ -1065,33 +1256,37 @@ void sqlite3GenerateConstraintChecks(
void sqlite3CompleteInsertion(
Parse *pParse, /* The parser context */
Table *pTab, /* the table into which we are inserting */
- int base, /* Index of a read/write cursor pointing at pTab */
- char *aIdxUsed, /* Which indices are used. NULL means all are used */
+ int baseCur, /* Index of a read/write cursor pointing at pTab */
+ int regRowid, /* Range of content */
+ int *aRegIdx, /* Register used by each index. 0 for unused indices */
int rowidChng, /* True if the record number will change */
int isUpdate, /* True for UPDATE, False for INSERT */
- int newIdx /* Index of NEW table for triggers. -1 if none */
+ int newIdx, /* Index of NEW table for triggers. -1 if none */
+ int appendBias /* True if this is likely to be an append */
){
int i;
Vdbe *v;
int nIdx;
Index *pIdx;
int pik_flags;
+ int regData;
+ int regRec;
v = sqlite3GetVdbe(pParse);
assert( v!=0 );
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){}
for(i=nIdx-1; i>=0; i--){
- if( aIdxUsed && aIdxUsed[i]==0 ) continue;
- sqlite3VdbeAddOp(v, OP_IdxInsert, base+i+1, 0);
+ if( aRegIdx[i]==0 ) continue;
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, baseCur+i+1, aRegIdx[i]);
}
- sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
+ regData = regRowid + 1;
+ regRec = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec);
sqlite3TableAffinityStr(v, pTab);
#ifndef SQLITE_OMIT_TRIGGER
if( newIdx>=0 ){
- sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
- sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
- sqlite3VdbeAddOp(v, OP_Insert, newIdx, 0);
+ sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRec, regRowid);
}
#endif
if( pParse->nested ){
@@ -1100,25 +1295,27 @@ void sqlite3CompleteInsertion(
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( appendBias ){
+ pik_flags |= OPFLAG_APPEND;
}
-
- if( isUpdate && rowidChng ){
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
+ sqlite3VdbeAddOp3(v, OP_Insert, baseCur, regRec, regRowid);
+ if( !pParse->nested ){
+ sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
}
+ sqlite3VdbeChangeP5(v, pik_flags);
}
/*
** Generate code that will open cursors for a table and for all
-** indices of that table. The "base" parameter is the cursor number used
+** indices of that table. The "baseCur" parameter is the cursor number used
** for the table. Indices are opened on subsequent cursors.
+**
+** Return the number of indices on the table.
*/
-void sqlite3OpenTableAndIndices(
+int sqlite3OpenTableAndIndices(
Parse *pParse, /* Parsing context */
Table *pTab, /* Table to be opened */
- int base, /* Cursor number assigned to the table */
+ int baseCur, /* Cursor number assigned to the table */
int op /* OP_OpenRead or OP_OpenWrite */
){
int i;
@@ -1126,19 +1323,341 @@ void sqlite3OpenTableAndIndices(
Index *pIdx;
Vdbe *v;
- if( IsVirtual(pTab) ) return;
+ if( IsVirtual(pTab) ) return 0;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
v = sqlite3GetVdbe(pParse);
assert( v!=0 );
- sqlite3OpenTable(pParse, base, iDb, pTab, op);
+ sqlite3OpenTable(pParse, baseCur, iDb, pTab, op);
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
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*)pKey, P3_KEYINFO_HANDOFF);
+ sqlite3VdbeAddOp4(v, op, i+baseCur, pIdx->tnum, iDb,
+ (char*)pKey, P4_KEYINFO_HANDOFF);
+ VdbeComment((v, "%s", pIdx->zName));
+ }
+ if( pParse->nTab<=baseCur+i ){
+ pParse->nTab = baseCur+i;
+ }
+ return i-1;
+}
+
+
+#ifdef SQLITE_TEST
+/*
+** The following global variable is incremented whenever the
+** transfer optimization is used. This is used for testing
+** purposes only - to make sure the transfer optimization really
+** is happening when it is suppose to.
+*/
+int sqlite3_xferopt_count;
+#endif /* SQLITE_TEST */
+
+
+#ifndef SQLITE_OMIT_XFER_OPT
+/*
+** Check to collation names to see if they are compatible.
+*/
+static int xferCompatibleCollation(const char *z1, const char *z2){
+ if( z1==0 ){
+ return z2==0;
+ }
+ if( z2==0 ){
+ return 0;
+ }
+ return sqlite3StrICmp(z1, z2)==0;
+}
+
+
+/*
+** Check to see if index pSrc is compatible as a source of data
+** for index pDest in an insert transfer optimization. The rules
+** for a compatible index:
+**
+** * The index is over the same set of columns
+** * The same DESC and ASC markings occurs on all columns
+** * The same onError processing (OE_Abort, OE_Ignore, etc)
+** * The same collating sequence on each column
+*/
+static int xferCompatibleIndex(Index *pDest, Index *pSrc){
+ int i;
+ assert( pDest && pSrc );
+ assert( pDest->pTable!=pSrc->pTable );
+ if( pDest->nColumn!=pSrc->nColumn ){
+ return 0; /* Different number of columns */
+ }
+ if( pDest->onError!=pSrc->onError ){
+ return 0; /* Different conflict resolution strategies */
+ }
+ for(i=0; i<pSrc->nColumn; i++){
+ if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){
+ return 0; /* Different columns indexed */
+ }
+ if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){
+ return 0; /* Different sort orders */
+ }
+ if( pSrc->azColl[i]!=pDest->azColl[i] ){
+ return 0; /* Different collating sequences */
+ }
}
- if( pParse->nTab<=base+i ){
- pParse->nTab = base+i;
+
+ /* If no test above fails then the indices must be compatible */
+ return 1;
+}
+
+/*
+** Attempt the transfer optimization on INSERTs of the form
+**
+** INSERT INTO tab1 SELECT * FROM tab2;
+**
+** This optimization is only attempted if
+**
+** (1) tab1 and tab2 have identical schemas including all the
+** same indices and constraints
+**
+** (2) tab1 and tab2 are different tables
+**
+** (3) There must be no triggers on tab1
+**
+** (4) The result set of the SELECT statement is "*"
+**
+** (5) The SELECT statement has no WHERE, HAVING, ORDER BY, GROUP BY,
+** or LIMIT clause.
+**
+** (6) The SELECT statement is a simple (not a compound) select that
+** contains only tab2 in its FROM clause
+**
+** This method for implementing the INSERT transfers raw records from
+** tab2 over to tab1. The columns are not decoded. Raw records from
+** the indices of tab2 are transfered to tab1 as well. In so doing,
+** the resulting tab1 has much less fragmentation.
+**
+** This routine returns TRUE if the optimization is attempted. If any
+** of the conditions above fail so that the optimization should not
+** be attempted, then this routine returns FALSE.
+*/
+static int xferOptimization(
+ Parse *pParse, /* Parser context */
+ Table *pDest, /* The table we are inserting into */
+ Select *pSelect, /* A SELECT statement to use as the data source */
+ int onError, /* How to handle constraint errors */
+ int iDbDest /* The database of pDest */
+){
+ ExprList *pEList; /* The result set of the SELECT */
+ Table *pSrc; /* The table in the FROM clause of SELECT */
+ Index *pSrcIdx, *pDestIdx; /* Source and destination indices */
+ struct SrcList_item *pItem; /* An element of pSelect->pSrc */
+ int i; /* Loop counter */
+ int iDbSrc; /* The database of pSrc */
+ int iSrc, iDest; /* Cursors from source and destination */
+ int addr1, addr2; /* Loop addresses */
+ int emptyDestTest; /* Address of test for empty pDest */
+ int emptySrcTest; /* Address of test for empty pSrc */
+ Vdbe *v; /* The VDBE we are building */
+ KeyInfo *pKey; /* Key information for an index */
+ int regAutoinc; /* Memory register used by AUTOINC */
+ int destHasUniqueIdx = 0; /* True if pDest has a UNIQUE index */
+ int regData, regRowid; /* Registers holding data and rowid */
+
+ if( pSelect==0 ){
+ return 0; /* Must be of the form INSERT INTO ... SELECT ... */
+ }
+ if( pDest->pTrigger ){
+ return 0; /* tab1 must not have triggers */
+ }
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( pDest->isVirtual ){
+ return 0; /* tab1 must not be a virtual table */
+ }
+#endif
+ if( onError==OE_Default ){
+ onError = OE_Abort;
+ }
+ if( onError!=OE_Abort && onError!=OE_Rollback ){
+ return 0; /* Cannot do OR REPLACE or OR IGNORE or OR FAIL */
+ }
+ assert(pSelect->pSrc); /* allocated even if there is no FROM clause */
+ if( pSelect->pSrc->nSrc!=1 ){
+ return 0; /* FROM clause must have exactly one term */
+ }
+ if( pSelect->pSrc->a[0].pSelect ){
+ return 0; /* FROM clause cannot contain a subquery */
+ }
+ if( pSelect->pWhere ){
+ return 0; /* SELECT may not have a WHERE clause */
+ }
+ if( pSelect->pOrderBy ){
+ return 0; /* SELECT may not have an ORDER BY clause */
+ }
+ /* Do not need to test for a HAVING clause. If HAVING is present but
+ ** there is no ORDER BY, we will get an error. */
+ if( pSelect->pGroupBy ){
+ return 0; /* SELECT may not have a GROUP BY clause */
+ }
+ if( pSelect->pLimit ){
+ return 0; /* SELECT may not have a LIMIT clause */
+ }
+ assert( pSelect->pOffset==0 ); /* Must be so if pLimit==0 */
+ if( pSelect->pPrior ){
+ return 0; /* SELECT may not be a compound query */
+ }
+ if( pSelect->isDistinct ){
+ return 0; /* SELECT may not be DISTINCT */
+ }
+ pEList = pSelect->pEList;
+ assert( pEList!=0 );
+ if( pEList->nExpr!=1 ){
+ return 0; /* The result set must have exactly one column */
+ }
+ assert( pEList->a[0].pExpr );
+ if( pEList->a[0].pExpr->op!=TK_ALL ){
+ return 0; /* The result set must be the special operator "*" */
+ }
+
+ /* At this point we have established that the statement is of the
+ ** correct syntactic form to participate in this optimization. Now
+ ** we have to check the semantics.
+ */
+ pItem = pSelect->pSrc->a;
+ pSrc = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase);
+ if( pSrc==0 ){
+ return 0; /* FROM clause does not contain a real table */
+ }
+ if( pSrc==pDest ){
+ return 0; /* tab1 and tab2 may not be the same table */
+ }
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( pSrc->isVirtual ){
+ return 0; /* tab2 must not be a virtual table */
+ }
+#endif
+ if( pSrc->pSelect ){
+ return 0; /* tab2 may not be a view */
+ }
+ if( pDest->nCol!=pSrc->nCol ){
+ return 0; /* Number of columns must be the same in tab1 and tab2 */
+ }
+ if( pDest->iPKey!=pSrc->iPKey ){
+ return 0; /* Both tables must have the same INTEGER PRIMARY KEY */
+ }
+ for(i=0; i<pDest->nCol; i++){
+ if( pDest->aCol[i].affinity!=pSrc->aCol[i].affinity ){
+ return 0; /* Affinity must be the same on all columns */
+ }
+ if( !xferCompatibleCollation(pDest->aCol[i].zColl, pSrc->aCol[i].zColl) ){
+ return 0; /* Collating sequence must be the same on all columns */
+ }
+ if( pDest->aCol[i].notNull && !pSrc->aCol[i].notNull ){
+ return 0; /* tab2 must be NOT NULL if tab1 is */
+ }
+ }
+ for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
+ if( pDestIdx->onError!=OE_None ){
+ destHasUniqueIdx = 1;
+ }
+ for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){
+ if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
+ }
+ if( pSrcIdx==0 ){
+ return 0; /* pDestIdx has no corresponding index in pSrc */
+ }
+ }
+#ifndef SQLITE_OMIT_CHECK
+ if( pDest->pCheck && !sqlite3ExprCompare(pSrc->pCheck, pDest->pCheck) ){
+ return 0; /* Tables have different CHECK constraints. Ticket #2252 */
+ }
+#endif
+
+ /* If we get this far, it means either:
+ **
+ ** * We can always do the transfer if the table contains an
+ ** an integer primary key
+ **
+ ** * We can conditionally do the transfer if the destination
+ ** table is empty.
+ */
+#ifdef SQLITE_TEST
+ sqlite3_xferopt_count++;
+#endif
+ iDbSrc = sqlite3SchemaToIndex(pParse->db, pSrc->pSchema);
+ v = sqlite3GetVdbe(pParse);
+ sqlite3CodeVerifySchema(pParse, iDbSrc);
+ iSrc = pParse->nTab++;
+ iDest = pParse->nTab++;
+ regAutoinc = autoIncBegin(pParse, iDbDest, pDest);
+ sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
+ if( (pDest->iPKey<0 && pDest->pIndex!=0) || destHasUniqueIdx ){
+ /* If tables do not have an INTEGER PRIMARY KEY and there
+ ** are indices to be copied and the destination is not empty,
+ ** we have to disallow the transfer optimization because the
+ ** the rowids might change which will mess up indexing.
+ **
+ ** Or if the destination has a UNIQUE index and is not empty,
+ ** we also disallow the transfer optimization because we cannot
+ ** insure that all entries in the union of DEST and SRC will be
+ ** unique.
+ */
+ addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0);
+ emptyDestTest = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
+ sqlite3VdbeJumpHere(v, addr1);
+ }else{
+ emptyDestTest = 0;
+ }
+ sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
+ emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
+ regData = sqlite3GetTempReg(pParse);
+ regRowid = sqlite3GetTempReg(pParse);
+ if( pDest->iPKey>=0 ){
+ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
+ addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
+ sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0,
+ "PRIMARY KEY must be unique", P4_STATIC);
+ sqlite3VdbeJumpHere(v, addr2);
+ autoIncStep(pParse, regAutoinc, regRowid);
+ }else if( pDest->pIndex==0 ){
+ addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
+ }else{
+ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
+ assert( pDest->autoInc==0 );
+ }
+ sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
+ sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
+ sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
+ sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
+ sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1);
+ autoIncEnd(pParse, iDbDest, pDest, regAutoinc);
+ for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
+ for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){
+ if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
+ }
+ assert( pSrcIdx );
+ sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
+ sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
+ pKey = sqlite3IndexKeyinfo(pParse, pSrcIdx);
+ sqlite3VdbeAddOp4(v, OP_OpenRead, iSrc, pSrcIdx->tnum, iDbSrc,
+ (char*)pKey, P4_KEYINFO_HANDOFF);
+ VdbeComment((v, "%s", pSrcIdx->zName));
+ pKey = sqlite3IndexKeyinfo(pParse, pDestIdx);
+ sqlite3VdbeAddOp4(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest,
+ (char*)pKey, P4_KEYINFO_HANDOFF);
+ VdbeComment((v, "%s", pDestIdx->zName));
+ addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
+ sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);
+ sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
+ sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1);
+ sqlite3VdbeJumpHere(v, addr1);
+ }
+ sqlite3VdbeJumpHere(v, emptySrcTest);
+ sqlite3ReleaseTempReg(pParse, regRowid);
+ sqlite3ReleaseTempReg(pParse, regData);
+ sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
+ sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
+ if( emptyDestTest ){
+ sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_OK, 0);
+ sqlite3VdbeJumpHere(v, emptyDestTest);
+ sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
+ return 0;
+ }else{
+ return 1;
}
}
+#endif /* SQLITE_OMIT_XFER_OPT */
diff --git a/ext/pdo_sqlite/sqlite/src/journal.c b/ext/pdo_sqlite/sqlite/src/journal.c
new file mode 100644
index 0000000000..9e2b3b8ea7
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/journal.c
@@ -0,0 +1,238 @@
+/*
+** 2007 August 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.
+**
+*************************************************************************
+**
+** @(#) $Id$
+*/
+
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+
+/*
+** This file implements a special kind of sqlite3_file object used
+** by SQLite to create journal files if the atomic-write optimization
+** is enabled.
+**
+** The distinctive characteristic of this sqlite3_file is that the
+** actual on disk file is created lazily. When the file is created,
+** the caller specifies a buffer size for an in-memory buffer to
+** be used to service read() and write() requests. The actual file
+** on disk is not created or populated until either:
+**
+** 1) The in-memory representation grows too large for the allocated
+** buffer, or
+** 2) The xSync() method is called.
+*/
+
+#include "sqliteInt.h"
+
+
+/*
+** A JournalFile object is a subclass of sqlite3_file used by
+** as an open file handle for journal files.
+*/
+struct JournalFile {
+ sqlite3_io_methods *pMethod; /* I/O methods on journal files */
+ int nBuf; /* Size of zBuf[] in bytes */
+ char *zBuf; /* Space to buffer journal writes */
+ int iSize; /* Amount of zBuf[] currently used */
+ int flags; /* xOpen flags */
+ sqlite3_vfs *pVfs; /* The "real" underlying VFS */
+ sqlite3_file *pReal; /* The "real" underlying file descriptor */
+ const char *zJournal; /* Name of the journal file */
+};
+typedef struct JournalFile JournalFile;
+
+/*
+** If it does not already exists, create and populate the on-disk file
+** for JournalFile p.
+*/
+static int createFile(JournalFile *p){
+ int rc = SQLITE_OK;
+ if( !p->pReal ){
+ sqlite3_file *pReal = (sqlite3_file *)&p[1];
+ rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0);
+ if( rc==SQLITE_OK ){
+ p->pReal = pReal;
+ if( p->iSize>0 ){
+ assert(p->iSize<=p->nBuf);
+ rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0);
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+** Close the file.
+*/
+static int jrnlClose(sqlite3_file *pJfd){
+ JournalFile *p = (JournalFile *)pJfd;
+ if( p->pReal ){
+ sqlite3OsClose(p->pReal);
+ }
+ sqlite3_free(p->zBuf);
+ return SQLITE_OK;
+}
+
+/*
+** Read data from the file.
+*/
+static int jrnlRead(
+ sqlite3_file *pJfd, /* The journal file from which to read */
+ void *zBuf, /* Put the results here */
+ int iAmt, /* Number of bytes to read */
+ sqlite_int64 iOfst /* Begin reading at this offset */
+){
+ int rc = SQLITE_OK;
+ JournalFile *p = (JournalFile *)pJfd;
+ if( p->pReal ){
+ rc = sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
+ }else{
+ assert( iAmt+iOfst<=p->iSize );
+ memcpy(zBuf, &p->zBuf[iOfst], iAmt);
+ }
+ return rc;
+}
+
+/*
+** Write data to the file.
+*/
+static int jrnlWrite(
+ sqlite3_file *pJfd, /* The journal file into which to write */
+ const void *zBuf, /* Take data to be written from here */
+ int iAmt, /* Number of bytes to write */
+ sqlite_int64 iOfst /* Begin writing at this offset into the file */
+){
+ int rc = SQLITE_OK;
+ JournalFile *p = (JournalFile *)pJfd;
+ if( !p->pReal && (iOfst+iAmt)>p->nBuf ){
+ rc = createFile(p);
+ }
+ if( rc==SQLITE_OK ){
+ if( p->pReal ){
+ rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
+ }else{
+ memcpy(&p->zBuf[iOfst], zBuf, iAmt);
+ if( p->iSize<(iOfst+iAmt) ){
+ p->iSize = (iOfst+iAmt);
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+** Truncate the file.
+*/
+static int jrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
+ int rc = SQLITE_OK;
+ JournalFile *p = (JournalFile *)pJfd;
+ if( p->pReal ){
+ rc = sqlite3OsTruncate(p->pReal, size);
+ }else if( size<p->iSize ){
+ p->iSize = size;
+ }
+ return rc;
+}
+
+/*
+** Sync the file.
+*/
+static int jrnlSync(sqlite3_file *pJfd, int flags){
+ int rc;
+ JournalFile *p = (JournalFile *)pJfd;
+ rc = createFile(p);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsSync(p->pReal, flags);
+ }
+ return rc;
+}
+
+/*
+** Query the size of the file in bytes.
+*/
+static int jrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
+ int rc = SQLITE_OK;
+ JournalFile *p = (JournalFile *)pJfd;
+ if( p->pReal ){
+ rc = sqlite3OsFileSize(p->pReal, pSize);
+ }else{
+ *pSize = (sqlite_int64) p->iSize;
+ }
+ return rc;
+}
+
+/*
+** Table of methods for JournalFile sqlite3_file object.
+*/
+static struct sqlite3_io_methods JournalFileMethods = {
+ 1, /* iVersion */
+ jrnlClose, /* xClose */
+ jrnlRead, /* xRead */
+ jrnlWrite, /* xWrite */
+ jrnlTruncate, /* xTruncate */
+ jrnlSync, /* xSync */
+ jrnlFileSize, /* xFileSize */
+ 0, /* xLock */
+ 0, /* xUnlock */
+ 0, /* xCheckReservedLock */
+ 0, /* xFileControl */
+ 0, /* xSectorSize */
+ 0 /* xDeviceCharacteristics */
+};
+
+/*
+** Open a journal file.
+*/
+int sqlite3JournalOpen(
+ sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */
+ const char *zName, /* Name of the journal file */
+ sqlite3_file *pJfd, /* Preallocated, blank file handle */
+ int flags, /* Opening flags */
+ int nBuf /* Bytes buffered before opening the file */
+){
+ JournalFile *p = (JournalFile *)pJfd;
+ memset(p, 0, sqlite3JournalSize(pVfs));
+ if( nBuf>0 ){
+ p->zBuf = sqlite3MallocZero(nBuf);
+ if( !p->zBuf ){
+ return SQLITE_NOMEM;
+ }
+ }else{
+ return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
+ }
+ p->pMethod = &JournalFileMethods;
+ p->nBuf = nBuf;
+ p->flags = flags;
+ p->zJournal = zName;
+ p->pVfs = pVfs;
+ return SQLITE_OK;
+}
+
+/*
+** If the argument p points to a JournalFile structure, and the underlying
+** file has not yet been created, create it now.
+*/
+int sqlite3JournalCreate(sqlite3_file *p){
+ if( p->pMethods!=&JournalFileMethods ){
+ return SQLITE_OK;
+ }
+ return createFile((JournalFile *)p);
+}
+
+/*
+** Return the number of bytes required to store a JournalFile that uses vfs
+** pVfs to create the underlying on-disk files.
+*/
+int sqlite3JournalSize(sqlite3_vfs *pVfs){
+ return (pVfs->szOsFile+sizeof(JournalFile));
+}
+#endif
diff --git a/ext/pdo_sqlite/sqlite/src/keywordhash.h b/ext/pdo_sqlite/sqlite/src/keywordhash.h
index bc0898f3be..09a4e2a092 100644
--- a/ext/pdo_sqlite/sqlite/src/keywordhash.h
+++ b/ext/pdo_sqlite/sqlite/src/keywordhash.h
@@ -1,85 +1,99 @@
-/* Hash score: 167 */
+/***** This file contains automatically generated code ******
+**
+** The code in this file has been automatically generated by
+**
+** $Header$
+**
+** The code in this file implements a function that determines whether
+** or not a given identifier is really an SQL keyword. The same thing
+** might be implemented more directly using a hand-written hash table.
+** But by using this automatically generated code, the size of the code
+** is substantially reduced. This is important for embedded applications
+** on platforms with limited memory.
+*/
+/* Hash score: 165 */
static int keywordCode(const char *z, int n){
- static const char zText[544] =
- "ABORTABLEFTEMPORARYADDATABASELECTHENDEFAULTRANSACTIONATURALTER"
- "AISEACHECKEYAFTEREFERENCESCAPELSEXCEPTRIGGEREGEXPLAINITIALLYANALYZE"
- "XCLUSIVEXISTSTATEMENTANDEFERRABLEATTACHAVINGLOBEFOREIGNOREINDEX"
- "AUTOINCREMENTBEGINNERENAMEBETWEENOTNULLIKEBYCASCADEFERREDELETE"
- "CASECASTCOLLATECOLUMNCOMMITCONFLICTCONSTRAINTERSECTCREATECROSS"
- "CURRENT_DATECURRENT_TIMESTAMPLANDESCDETACHDISTINCTDROPRAGMATCH"
- "FAILIMITFROMFULLGROUPDATEIFIMMEDIATEINSERTINSTEADINTOFFSETISNULL"
- "JOINORDEREPLACEOUTERESTRICTPRIMARYQUERYRIGHTROLLBACKROWHENUNION"
- "UNIQUEUSINGVACUUMVALUESVIEWHEREVIRTUAL";
+ /* zText[] encodes 775 bytes of keywords in 526 bytes */
+ static const char zText[526] =
+ "BEFOREIGNOREGEXPLAINSTEADDESCAPEACHECKEYCONSTRAINTERSECTABLEFT"
+ "HENDATABASELECTRANSACTIONATURALTERAISELSEXCEPTRIGGEREFERENCES"
+ "UNIQUERYATTACHAVINGROUPDATEMPORARYBEGINNEREINDEXCLUSIVEXISTSBETWEEN"
+ "OTNULLIKECASCADEFERRABLECASECOLLATECREATECURRENT_DATEDELETEDETACH"
+ "IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN"
+ "WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMITCONFLICT"
+ "CROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAILFROMFULLGLOB"
+ "YIFINTOFFSETISNULLORDERESTRICTOUTERIGHTROLLBACKROWUNIONUSINGVACUUM"
+ "VIEWINITIALLY";
static const unsigned char aHash[127] = {
- 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, 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,
+ 63, 92, 109, 61, 0, 38, 0, 0, 69, 0, 64, 0, 0,
+ 102, 4, 65, 7, 0, 108, 72, 103, 99, 0, 22, 0, 0,
+ 113, 0, 111, 106, 0, 18, 80, 0, 1, 0, 0, 56, 57,
+ 0, 55, 11, 0, 33, 77, 89, 0, 110, 88, 0, 0, 45,
+ 0, 90, 54, 0, 20, 0, 114, 34, 19, 0, 10, 97, 28,
+ 83, 0, 0, 116, 93, 47, 115, 41, 12, 44, 0, 78, 0,
+ 87, 29, 0, 86, 0, 0, 0, 82, 79, 84, 75, 96, 6,
+ 14, 95, 0, 68, 0, 21, 76, 98, 27, 0, 112, 67, 104,
+ 49, 40, 71, 0, 0, 81, 100, 0, 107, 0, 15, 0, 0,
+ 24, 0, 73, 42, 50, 0, 16, 48, 0, 37,
};
- 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, 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 aNext[116] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0,
+ 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0,
+ 17, 0, 0, 0, 36, 39, 0, 0, 25, 0, 0, 31, 0,
+ 0, 0, 43, 52, 0, 0, 0, 53, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 51, 0, 0, 0, 0, 26, 0, 8, 46,
+ 2, 0, 0, 0, 0, 0, 0, 0, 3, 58, 66, 0, 13,
+ 0, 91, 85, 0, 94, 0, 74, 0, 0, 62, 0, 35, 101,
+ 0, 0, 105, 23, 30, 60, 70, 0, 0, 59, 0, 0,
};
- 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, 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 char aLen[116] = {
+ 6, 7, 3, 6, 6, 7, 7, 3, 4, 6, 4, 5, 3,
+ 10, 9, 5, 4, 4, 3, 8, 2, 6, 11, 2, 7, 5,
+ 5, 4, 6, 7, 10, 6, 5, 6, 6, 5, 6, 4, 9,
+ 2, 5, 5, 7, 5, 9, 6, 7, 7, 3, 4, 4, 7,
+ 3, 10, 4, 7, 6, 12, 6, 6, 9, 4, 6, 5, 4,
+ 7, 6, 5, 6, 7, 5, 4, 5, 6, 5, 7, 3, 7,
+ 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 8, 8,
+ 2, 4, 4, 4, 4, 4, 2, 2, 4, 6, 2, 3, 6,
+ 5, 8, 5, 5, 8, 3, 5, 5, 6, 4, 9, 3,
};
- 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, 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 short int aOffset[116] = {
+ 0, 2, 2, 6, 10, 13, 18, 23, 25, 26, 31, 33, 37,
+ 40, 47, 55, 58, 61, 63, 65, 70, 71, 76, 85, 86, 91,
+ 95, 99, 102, 107, 113, 123, 126, 131, 136, 141, 144, 148, 148,
+ 152, 157, 160, 164, 166, 169, 177, 183, 189, 189, 192, 195, 199,
+ 200, 204, 214, 218, 225, 231, 243, 249, 255, 264, 266, 272, 277,
+ 279, 286, 291, 296, 302, 308, 313, 317, 320, 326, 330, 337, 339,
+ 346, 348, 350, 359, 363, 369, 375, 383, 388, 388, 404, 411, 418,
+ 419, 426, 430, 434, 438, 442, 445, 447, 449, 452, 452, 455, 458,
+ 464, 468, 476, 480, 485, 493, 496, 501, 506, 512, 516, 521,
};
- 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,
- TK_JOIN_KW, TK_ALTER, TK_RAISE, TK_EACH, TK_CHECK,
- TK_KEY, TK_AFTER, TK_REFERENCES, TK_ESCAPE, TK_ELSE,
- TK_EXCEPT, TK_TRIGGER, TK_LIKE_KW, TK_EXPLAIN, TK_INITIALLY,
- TK_ALL, TK_ANALYZE, TK_EXCLUSIVE, TK_EXISTS, TK_STATEMENT,
- TK_AND, TK_DEFERRABLE, TK_ATTACH, TK_HAVING, TK_LIKE_KW,
- TK_BEFORE, TK_FOR, TK_FOREIGN, TK_IGNORE, TK_REINDEX,
- TK_INDEX, TK_AUTOINCR, TK_TO, TK_IN, TK_BEGIN,
- TK_JOIN_KW, TK_RENAME, TK_BETWEEN, TK_NOT, TK_NOTNULL,
- TK_NULL, TK_LIKE_KW, TK_BY, TK_CASCADE, TK_ASC,
- 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_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,
+ static const unsigned char aCode[116] = {
+ TK_BEFORE, TK_FOREIGN, TK_FOR, TK_IGNORE, TK_LIKE_KW,
+ TK_EXPLAIN, TK_INSTEAD, TK_ADD, TK_DESC, TK_ESCAPE,
+ TK_EACH, TK_CHECK, TK_KEY, TK_CONSTRAINT, TK_INTERSECT,
+ TK_TABLE, TK_JOIN_KW, TK_THEN, TK_END, TK_DATABASE,
+ TK_AS, TK_SELECT, TK_TRANSACTION,TK_ON, TK_JOIN_KW,
+ TK_ALTER, TK_RAISE, TK_ELSE, TK_EXCEPT, TK_TRIGGER,
+ TK_REFERENCES, TK_UNIQUE, TK_QUERY, TK_ATTACH, TK_HAVING,
+ TK_GROUP, TK_UPDATE, TK_TEMP, TK_TEMP, TK_OR,
+ TK_BEGIN, TK_JOIN_KW, TK_REINDEX, TK_INDEX, TK_EXCLUSIVE,
+ TK_EXISTS, TK_BETWEEN, TK_NOTNULL, TK_NOT, TK_NULL,
+ TK_LIKE_KW, TK_CASCADE, TK_ASC, TK_DEFERRABLE, TK_CASE,
+ TK_COLLATE, TK_CREATE, TK_CTIME_KW, TK_DELETE, TK_DETACH,
+ TK_IMMEDIATE, TK_JOIN, TK_INSERT, TK_MATCH, TK_PLAN,
+ TK_ANALYZE, TK_PRAGMA, TK_ABORT, TK_VALUES, TK_VIRTUAL,
+ TK_LIMIT, TK_WHEN, TK_WHERE, TK_RENAME, TK_AFTER,
+ TK_REPLACE, TK_AND, TK_DEFAULT, TK_AUTOINCR, TK_TO,
+ TK_IN, TK_CAST, TK_COLUMNKW, TK_COMMIT, TK_CONFLICT,
+ TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, TK_PRIMARY, TK_DEFERRED,
+ TK_DISTINCT, TK_IS, TK_DROP, TK_FAIL, TK_FROM,
+ TK_JOIN_KW, TK_LIKE_KW, TK_BY, TK_IF, TK_INTO,
+ TK_OFFSET, TK_OF, TK_SET, TK_ISNULL, TK_ORDER,
+ TK_RESTRICT, TK_JOIN_KW, TK_JOIN_KW, TK_ROLLBACK, TK_ROW,
+ TK_UNION, TK_USING, TK_VACUUM, TK_VIEW, TK_INITIALLY,
+ TK_ALL,
};
int h, i;
if( n<2 ) return TK_ID;
diff --git a/ext/pdo_sqlite/sqlite/src/legacy.c b/ext/pdo_sqlite/sqlite/src/legacy.c
index c75791e1bd..4f23ede0c2 100644
--- a/ext/pdo_sqlite/sqlite/src/legacy.c
+++ b/ext/pdo_sqlite/sqlite/src/legacy.c
@@ -18,7 +18,6 @@
*/
#include "sqliteInt.h"
-#include "os.h"
#include <ctype.h>
/*
@@ -44,10 +43,11 @@ int sqlite3_exec(
char **azCols = 0;
int nRetry = 0;
- int nChange = 0;
int nCallback;
if( zSql==0 ) return SQLITE_OK;
+
+ sqlite3_mutex_enter(db->mutex);
while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){
int nCol;
char **azVals = 0;
@@ -64,11 +64,10 @@ int sqlite3_exec(
continue;
}
- db->nChange += nChange;
nCallback = 0;
nCol = sqlite3_column_count(pStmt);
- azCols = sqliteMalloc(2*nCol*sizeof(const char *) + 1);
+ azCols = sqlite3DbMallocZero(db, 2*nCol*sizeof(const char *) + 1);
if( azCols==0 ){
goto exec_out;
}
@@ -101,9 +100,6 @@ int sqlite3_exec(
if( rc!=SQLITE_ROW ){
rc = sqlite3_finalize(pStmt);
pStmt = 0;
- if( db->pVdbe==0 ){
- nChange = db->nChange;
- }
if( rc!=SQLITE_SCHEMA ){
nRetry = 0;
zSql = zLeftover;
@@ -113,23 +109,26 @@ int sqlite3_exec(
}
}
- sqliteFree(azCols);
+ sqlite3_free(azCols);
azCols = 0;
}
exec_out:
if( pStmt ) sqlite3_finalize(pStmt);
- if( azCols ) sqliteFree(azCols);
+ if( azCols ) sqlite3_free(azCols);
- rc = sqlite3ApiExit(0, rc);
+ rc = sqlite3ApiExit(db, rc);
if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){
- *pzErrMsg = sqlite3_malloc(1+strlen(sqlite3_errmsg(db)));
+ int nErrMsg = 1 + strlen(sqlite3_errmsg(db));
+ *pzErrMsg = sqlite3_malloc(nErrMsg);
if( *pzErrMsg ){
- strcpy(*pzErrMsg, sqlite3_errmsg(db));
+ memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg);
}
}else if( pzErrMsg ){
*pzErrMsg = 0;
}
+ assert( (rc&db->errMask)==rc );
+ sqlite3_mutex_leave(db->mutex);
return rc;
}
diff --git a/ext/pdo_sqlite/sqlite/src/limits.h b/ext/pdo_sqlite/sqlite/src/limits.h
new file mode 100644
index 0000000000..823ec3da9b
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/limits.h
@@ -0,0 +1,158 @@
+/*
+** 2007 May 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 defines various limits of what SQLite can process.
+**
+** @(#) $Id$
+*/
+
+/*
+** The maximum length of a TEXT or BLOB in bytes. This also
+** limits the size of a row in a table or index.
+**
+** The hard limit is the ability of a 32-bit signed integer
+** to count the size: 2^31-1 or 2147483647.
+*/
+#ifndef SQLITE_MAX_LENGTH
+# define SQLITE_MAX_LENGTH 1000000000
+#endif
+
+/*
+** This is the maximum number of
+**
+** * Columns in a table
+** * Columns in an index
+** * Columns in a view
+** * Terms in the SET clause of an UPDATE statement
+** * Terms in the result set of a SELECT statement
+** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement.
+** * Terms in the VALUES clause of an INSERT statement
+**
+** The hard upper limit here is 32676. Most database people will
+** tell you that in a well-normalized database, you usually should
+** not have more than a dozen or so columns in any table. And if
+** that is the case, there is no point in having more than a few
+** dozen values in any of the other situations described above.
+*/
+#ifndef SQLITE_MAX_COLUMN
+# define SQLITE_MAX_COLUMN 2000
+#endif
+
+/*
+** The maximum length of a single SQL statement in bytes.
+** The hard limit here is the same as SQLITE_MAX_LENGTH.
+*/
+#ifndef SQLITE_MAX_SQL_LENGTH
+# define SQLITE_MAX_SQL_LENGTH 1000000
+#endif
+
+/*
+** The maximum depth of an expression tree. This is limited to
+** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
+** want to place more severe limits on the complexity of an
+** expression. A value of 0 (the default) means do not enforce
+** any limitation on expression tree depth.
+*/
+#ifndef SQLITE_MAX_EXPR_DEPTH
+# define SQLITE_MAX_EXPR_DEPTH 1000
+#endif
+
+/*
+** The maximum number of terms in a compound SELECT statement.
+** The code generator for compound SELECT statements does one
+** level of recursion for each term. A stack overflow can result
+** if the number of terms is too large. In practice, most SQL
+** never has more than 3 or 4 terms. Use a value of 0 to disable
+** any limit on the number of terms in a compount SELECT.
+*/
+#ifndef SQLITE_MAX_COMPOUND_SELECT
+# define SQLITE_MAX_COMPOUND_SELECT 500
+#endif
+
+/*
+** The maximum number of opcodes in a VDBE program.
+** Not currently enforced.
+*/
+#ifndef SQLITE_MAX_VDBE_OP
+# define SQLITE_MAX_VDBE_OP 25000
+#endif
+
+/*
+** The maximum number of arguments to an SQL function.
+*/
+#ifndef SQLITE_MAX_FUNCTION_ARG
+# define SQLITE_MAX_FUNCTION_ARG 100
+#endif
+
+/*
+** The maximum number of in-memory pages to use for the main database
+** table and for temporary tables. The SQLITE_DEFAULT_CACHE_SIZE
+*/
+#ifndef SQLITE_DEFAULT_CACHE_SIZE
+# define SQLITE_DEFAULT_CACHE_SIZE 2000
+#endif
+#ifndef SQLITE_DEFAULT_TEMP_CACHE_SIZE
+# define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500
+#endif
+
+/*
+** The maximum number of attached databases. This must be at least 2
+** in order to support the main database file (0) and the file used to
+** hold temporary tables (1). And it must be less than 32 because
+** we use a bitmask of databases with a u32 in places (for example
+** the Parse.cookieMask field).
+*/
+#ifndef SQLITE_MAX_ATTACHED
+# define SQLITE_MAX_ATTACHED 10
+#endif
+
+
+/*
+** The maximum value of a ?nnn wildcard that the parser will accept.
+*/
+#ifndef SQLITE_MAX_VARIABLE_NUMBER
+# define SQLITE_MAX_VARIABLE_NUMBER 999
+#endif
+
+/*
+** The default size of a database page.
+*/
+#ifndef SQLITE_DEFAULT_PAGE_SIZE
+# define SQLITE_DEFAULT_PAGE_SIZE 1024
+#endif
+
+/* Maximum page size. The upper bound on this value is 32768. This a limit
+** imposed by the necessity of storing the value in a 2-byte unsigned integer
+** and the fact that the page size must be a power of 2.
+*/
+#ifndef SQLITE_MAX_PAGE_SIZE
+# define SQLITE_MAX_PAGE_SIZE 32768
+#endif
+
+/*
+** Maximum number of pages in one database file.
+**
+** This is really just the default value for the max_page_count pragma.
+** This value can be lowered (or raised) at run-time using that the
+** max_page_count macro.
+*/
+#ifndef SQLITE_MAX_PAGE_COUNT
+# define SQLITE_MAX_PAGE_COUNT 1073741823
+#endif
+
+/*
+** Maximum length (in bytes) of the pattern in a LIKE or GLOB
+** operator.
+*/
+#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
+# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000
+#endif
diff --git a/ext/pdo_sqlite/sqlite/src/loadext.c b/ext/pdo_sqlite/sqlite/src/loadext.c
index 46ae2a9387..8293486996 100644
--- a/ext/pdo_sqlite/sqlite/src/loadext.c
+++ b/ext/pdo_sqlite/sqlite/src/loadext.c
@@ -1,5 +1,5 @@
/*
-** 2007 June 7
+** 2006 June 7
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -14,7 +14,9 @@
*/
#ifndef SQLITE_OMIT_LOAD_EXTENSION
-#define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */
+#ifndef SQLITE_CORE
+ #define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */
+#endif
#include "sqlite3ext.h"
#include "sqliteInt.h"
#include <string.h>
@@ -36,28 +38,32 @@
#endif
#ifdef SQLITE_OMIT_AUTHORIZATION
-# define sqlite3_set_authorizer 0
+# 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
+# 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_prepare16_v2 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
+# define sqlite3_column_database_name16 0
+# define sqlite3_column_table_name16 0
+# define sqlite3_column_origin_name16 0
#endif
#ifdef SQLITE_OMIT_COMPLETE
@@ -71,9 +77,33 @@
#ifdef SQLITE_OMIT_VIRTUALTABLE
# define sqlite3_create_module 0
+# define sqlite3_create_module_v2 0
# define sqlite3_declare_vtab 0
#endif
+#ifdef SQLITE_OMIT_SHARED_CACHE
+# define sqlite3_enable_shared_cache 0
+#endif
+
+#ifdef SQLITE_OMIT_TRACE
+# define sqlite3_profile 0
+# define sqlite3_trace 0
+#endif
+
+#ifdef SQLITE_OMIT_GET_TABLE
+# define sqlite3_free_table 0
+# define sqlite3_get_table 0
+#endif
+
+#ifdef SQLITE_OMIT_INCRBLOB
+#define sqlite3_bind_zeroblob 0
+#define sqlite3_blob_bytes 0
+#define sqlite3_blob_close 0
+#define sqlite3_blob_open 0
+#define sqlite3_blob_read 0
+#define sqlite3_blob_write 0
+#endif
+
/*
** The following structure contains pointers to all SQLite API routines.
** A pointer to this structure is passed into extensions when they are
@@ -89,7 +119,7 @@
** also check to make sure that the pointer to the function is
** not NULL before calling it.
*/
-const sqlite3_api_routines sqlite3_api = {
+const sqlite3_api_routines sqlite3_apis = {
sqlite3_aggregate_context,
sqlite3_aggregate_count,
sqlite3_bind_blob,
@@ -153,7 +183,7 @@ const sqlite3_api_routines sqlite3_api = {
sqlite3_get_autocommit,
sqlite3_get_auxdata,
sqlite3_get_table,
- sqlite3_global_recover,
+ 0, /* Was sqlite3_global_recover(), but that function is deprecated */
sqlite3_interrupt,
sqlite3_last_insert_rowid,
sqlite3_libversion,
@@ -213,29 +243,56 @@ const sqlite3_api_routines sqlite3_api = {
** a library that is new enough to support that API.
*************************************************************************
*/
-};
+ sqlite3_overload_function,
-/*
-** 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 */
+ /*
+ ** Added after 3.3.13
+ */
+ sqlite3_prepare_v2,
+ sqlite3_prepare16_v2,
+ sqlite3_clear_bindings,
-/*
-** 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)
+ /*
+ ** Added for 3.4.1
+ */
+ sqlite3_create_module_v2,
+
+ /*
+ ** Added for 3.5.0
+ */
+ sqlite3_bind_zeroblob,
+ sqlite3_blob_bytes,
+ sqlite3_blob_close,
+ sqlite3_blob_open,
+ sqlite3_blob_read,
+ sqlite3_blob_write,
+ sqlite3_create_collation_v2,
+ sqlite3_file_control,
+ sqlite3_memory_highwater,
+ sqlite3_memory_used,
+#ifdef SQLITE_MUTEX_NOOP
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+#else
+ sqlite3_mutex_alloc,
+ sqlite3_mutex_enter,
+ sqlite3_mutex_free,
+ sqlite3_mutex_leave,
+ sqlite3_mutex_try,
#endif
+ sqlite3_open_v2,
+ sqlite3_release_memory,
+ sqlite3_result_error_nomem,
+ sqlite3_result_error_toobig,
+ sqlite3_sleep,
+ sqlite3_soft_heap_limit,
+ sqlite3_vfs_find,
+ sqlite3_vfs_register,
+ sqlite3_vfs_unregister,
+};
/*
** Attempt to load an SQLite extension library contained in the file
@@ -249,17 +306,17 @@ const sqlite3_api_routines sqlite3_api = {
** error message text. The calling function should free this memory
** by calling sqlite3_free().
*/
-int sqlite3_load_extension(
+static int sqlite3LoadExtension(
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;
+ sqlite3_vfs *pVfs = db->pVfs;
+ void *handle;
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
char *zErrmsg = 0;
- SQLITE_LIBRARY_TYPE *aHandle;
+ void **aHandle;
/* Ticket #1863. To avoid a creating security problems for older
** applications that relink against newer versions of SQLite, the
@@ -278,51 +335,66 @@ int sqlite3_load_extension(
zProc = "sqlite3_extension_init";
}
- handle = SQLITE_OPEN_LIBRARY(zFile);
+ handle = sqlite3OsDlOpen(pVfs, zFile);
if( handle==0 ){
if( pzErrMsg ){
- *pzErrMsg = sqlite3_mprintf("unable to open shared library [%s]", zFile);
+ char zErr[256];
+ zErr[sizeof(zErr)-1] = '\0';
+ sqlite3_snprintf(sizeof(zErr)-1, zErr,
+ "unable to open shared library [%s]", zFile);
+ sqlite3OsDlError(pVfs, sizeof(zErr)-1, zErr);
+ *pzErrMsg = sqlite3DbStrDup(db, zErr);
}
return SQLITE_ERROR;
}
xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
- SQLITE_FIND_SYMBOL(handle, zProc);
+ sqlite3OsDlSym(pVfs, handle, zProc);
if( xInit==0 ){
if( pzErrMsg ){
- *pzErrMsg = sqlite3_mprintf("no entry point [%s] in shared library [%s]",
- zProc, zFile);
+ char zErr[256];
+ zErr[sizeof(zErr)-1] = '\0';
+ sqlite3_snprintf(sizeof(zErr)-1, zErr,
+ "no entry point [%s] in shared library [%s]", zProc,zFile);
+ sqlite3OsDlError(pVfs, sizeof(zErr)-1, zErr);
+ *pzErrMsg = sqlite3DbStrDup(db, zErr);
+ sqlite3OsDlClose(pVfs, handle);
}
- SQLITE_CLOSE_LIBRARY(handle);
return SQLITE_ERROR;
- }else if( xInit(db, &zErrmsg, &sqlite3_api) ){
+ }else if( xInit(db, &zErrmsg, &sqlite3_apis) ){
if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
}
sqlite3_free(zErrmsg);
- SQLITE_CLOSE_LIBRARY(handle);
+ sqlite3OsDlClose(pVfs, handle);
return SQLITE_ERROR;
}
/* Append the new shared library handle to the db->aExtension array. */
db->nExtension++;
- aHandle = sqliteMalloc(sizeof(handle)*db->nExtension);
+ aHandle = sqlite3DbMallocZero(db, 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);
+ sqlite3_free(db->aExtension);
db->aExtension = aHandle;
- ((SQLITE_LIBRARY_TYPE*)db->aExtension)[db->nExtension-1] = handle;
+ db->aExtension[db->nExtension-1] = handle;
return SQLITE_OK;
-#else
- if( pzErrMsg ){
- *pzErrMsg = sqlite3_mprintf("extension loading is disabled");
- }
- return SQLITE_ERROR;
-#endif
+}
+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 */
+){
+ int rc;
+ sqlite3_mutex_enter(db->mutex);
+ rc = sqlite3LoadExtension(db, zFile, zProc, pzErrMsg);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
}
/*
@@ -330,13 +402,12 @@ int sqlite3_load_extension(
** to clean up loaded extensions
*/
void sqlite3CloseExtensions(sqlite3 *db){
-#ifdef SQLITE_LIBRARY_TYPE
int i;
+ assert( sqlite3_mutex_held(db->mutex) );
for(i=0; i<db->nExtension; i++){
- SQLITE_CLOSE_LIBRARY(((SQLITE_LIBRARY_TYPE*)db->aExtension)[i]);
+ sqlite3OsDlClose(db->pVfs, db->aExtension[i]);
}
- sqliteFree(db->aExtension);
-#endif
+ sqlite3_free(db->aExtension);
}
/*
@@ -344,12 +415,104 @@ void sqlite3CloseExtensions(sqlite3 *db){
** default so as not to open security holes in older applications.
*/
int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
+ sqlite3_mutex_enter(db->mutex);
if( onoff ){
db->flags |= SQLITE_LoadExtension;
}else{
db->flags &= ~SQLITE_LoadExtension;
}
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
+/*
+** The following object holds the list of automatically loaded
+** extensions.
+**
+** This list is shared across threads. The SQLITE_MUTEX_STATIC_MASTER
+** mutex must be held while accessing this list.
+*/
+static struct {
+ int nExt; /* Number of entries in aExt[] */
+ void **aExt; /* Pointers to the extension init functions */
+} autoext = { 0, 0 };
+
+
+/*
+** Register a statically linked extension that is automatically
+** loaded by every new database connection.
+*/
+int sqlite3_auto_extension(void *xInit){
+ int i;
+ int rc = SQLITE_OK;
+ sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex_enter(mutex);
+ for(i=0; i<autoext.nExt; i++){
+ if( autoext.aExt[i]==xInit ) break;
+ }
+ if( i==autoext.nExt ){
+ int nByte = (autoext.nExt+1)*sizeof(autoext.aExt[0]);
+ void **aNew;
+ aNew = sqlite3_realloc(autoext.aExt, nByte);
+ if( aNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ autoext.aExt = aNew;
+ autoext.aExt[autoext.nExt] = xInit;
+ autoext.nExt++;
+ }
+ }
+ sqlite3_mutex_leave(mutex);
+ assert( (rc&0xff)==rc );
+ return rc;
+}
+
+/*
+** Reset the automatic extension loading mechanism.
+*/
+void sqlite3_reset_auto_extension(void){
+ sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex_enter(mutex);
+ sqlite3_free(autoext.aExt);
+ autoext.aExt = 0;
+ autoext.nExt = 0;
+ sqlite3_mutex_leave(mutex);
+}
+
+/*
+** Load all automatic extensions.
+*/
+int sqlite3AutoLoadExtensions(sqlite3 *db){
+ int i;
+ int go = 1;
+ int rc = SQLITE_OK;
+ int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
+
+ if( autoext.nExt==0 ){
+ /* Common case: early out without every having to acquire a mutex */
+ return SQLITE_OK;
+ }
+ for(i=0; go; i++){
+ char *zErrmsg = 0;
+ sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex_enter(mutex);
+ if( i>=autoext.nExt ){
+ xInit = 0;
+ go = 0;
+ }else{
+ xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
+ autoext.aExt[i];
+ }
+ sqlite3_mutex_leave(mutex);
+ if( xInit && xInit(db, &zErrmsg, &sqlite3_apis) ){
+ sqlite3Error(db, SQLITE_ERROR,
+ "automatic extension loading failed: %s", zErrmsg);
+ go = 0;
+ rc = SQLITE_ERROR;
+ sqlite3_free(zErrmsg);
+ }
+ }
+ return rc;
+}
+
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
diff --git a/ext/pdo_sqlite/sqlite/src/main.c b/ext/pdo_sqlite/sqlite/src/main.c
index eccf83be69..a6617ead74 100644
--- a/ext/pdo_sqlite/sqlite/src/main.c
+++ b/ext/pdo_sqlite/sqlite/src/main.c
@@ -17,14 +17,10 @@
** $Id$
*/
#include "sqliteInt.h"
-#include "os.h"
#include <ctype.h>
-
-/*
-** The following constant value is used by the SQLITE_BIGENDIAN and
-** SQLITE_LITTLEENDIAN macros.
-*/
-const int sqlite3one = 1;
+#ifdef SQLITE_ENABLE_FTS3
+# include "fts3.h"
+#endif
/*
** The version of the library
@@ -32,13 +28,43 @@ const int sqlite3one = 1;
const char sqlite3_version[] = SQLITE_VERSION;
const char *sqlite3_libversion(void){ return sqlite3_version; }
int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
+int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
+
+/*
+** If the following function pointer is not NULL and if
+** SQLITE_ENABLE_IOTRACE is enabled, then messages describing
+** I/O active are written using this function. These messages
+** are intended for debugging activity only.
+*/
+void (*sqlite3_io_trace)(const char*, ...) = 0;
+
+/*
+** 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;
+
+
+/*
+** Return true if the buffer z[0..n-1] contains all spaces.
+*/
+static int allSpaces(const char *z, int n){
+ while( n>0 && z[--n]==' ' ){}
+ return n==0;
+}
/*
** This is the default collating function named "BINARY" which is always
** available.
+**
+** If the padFlag argument is not NULL then space padding at the end
+** of strings is ignored. This implements the RTRIM collation.
*/
static int binCollFunc(
- void *NotUsed,
+ void *padFlag,
int nKey1, const void *pKey1,
int nKey2, const void *pKey2
){
@@ -46,7 +72,14 @@ static int binCollFunc(
n = nKey1<nKey2 ? nKey1 : nKey2;
rc = memcmp(pKey1, pKey2, n);
if( rc==0 ){
- rc = nKey1 - nKey2;
+ if( padFlag
+ && allSpaces(((char*)pKey1)+n, nKey1-n)
+ && allSpaces(((char*)pKey2)+n, nKey2-n)
+ ){
+ /* Leave rc unchanged at 0 */
+ }else{
+ rc = nKey1 - nKey2;
+ }
}
return rc;
}
@@ -104,9 +137,10 @@ int sqlite3_close(sqlite3 *db){
if( !db ){
return SQLITE_OK;
}
- if( sqlite3SafetyCheck(db) ){
+ if( !sqlite3SafetyCheckSickOrOk(db) ){
return SQLITE_MISUSE;
}
+ sqlite3_mutex_enter(db->mutex);
#ifdef SQLITE_SSE
{
@@ -115,26 +149,25 @@ int sqlite3_close(sqlite3 *db){
}
#endif
- /* If there are any outstanding VMs, return SQLITE_BUSY. */
sqlite3ResetInternalSchema(db, 0);
+
+ /* If a transaction is open, the ResetInternalSchema() call above
+ ** will not have called the xDisconnect() method on any virtual
+ ** tables in the db->aVTrans[] array. The following sqlite3VtabRollback()
+ ** call will do so. We need to do this before the check for active
+ ** SQL statements below, as the v-table implementation may be storing
+ ** some prepared statements internally.
+ */
+ sqlite3VtabRollback(db);
+
+ /* If there are any outstanding VMs, return SQLITE_BUSY. */
if( db->pVdbe ){
sqlite3Error(db, SQLITE_BUSY,
"Unable to close due to unfinalised statements");
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_BUSY;
}
- assert( !sqlite3SafetyCheck(db) );
-
- /* FIX ME: db->magic may be set to SQLITE_MAGIC_CLOSED if the database
- ** cannot be opened for some reason. So this routine needs to run in
- ** that case. But maybe there should be an extra magic value for the
- ** "failed to open" state.
- */
- if( db->magic!=SQLITE_MAGIC_CLOSED && sqlite3SafetyOn(db) ){
- /* printf("DID NOT CLOSE\n"); fflush(stdout); */
- return SQLITE_ERROR;
- }
-
- sqlite3VtabRollback(db);
+ assert( sqlite3SafetyCheckSickOrOk(db) );
for(j=0; j<db->nDb; j++){
struct Db *pDb = &db->aDb[j];
@@ -153,19 +186,28 @@ int sqlite3_close(sqlite3 *db){
FuncDef *pFunc, *pNext;
for(pFunc = (FuncDef*)sqliteHashData(i); pFunc; pFunc=pNext){
pNext = pFunc->pNext;
- sqliteFree(pFunc);
+ sqlite3_free(pFunc);
}
}
for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){
CollSeq *pColl = (CollSeq *)sqliteHashData(i);
- sqliteFree(pColl);
+ /* Invoke any destructors registered for collation sequence user data. */
+ for(j=0; j<3; j++){
+ if( pColl[j].xDel ){
+ pColl[j].xDel(pColl[j].pUser);
+ }
+ }
+ sqlite3_free(pColl);
}
sqlite3HashClear(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){
Module *pMod = (Module *)sqliteHashData(i);
- sqliteFree(pMod);
+ if( pMod->xDestroy ){
+ pMod->xDestroy(pMod->pAux);
+ }
+ sqlite3_free(pMod);
}
sqlite3HashClear(&db->aModule);
#endif
@@ -185,9 +227,11 @@ int sqlite3_close(sqlite3 *db){
** the same sqliteMalloc() as the one that allocates the database
** structure?
*/
- sqliteFree(db->aDb[1].pSchema);
- sqliteFree(db);
- sqlite3ReleaseThreadData();
+ sqlite3_free(db->aDb[1].pSchema);
+ sqlite3_mutex_leave(db->mutex);
+ db->magic = SQLITE_MAGIC_CLOSED;
+ sqlite3_mutex_free(db->mutex);
+ sqlite3_free(db);
return SQLITE_OK;
}
@@ -197,6 +241,8 @@ int sqlite3_close(sqlite3 *db){
void sqlite3RollbackAll(sqlite3 *db){
int i;
int inTrans = 0;
+ assert( sqlite3_mutex_held(db->mutex) );
+ sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 1);
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt ){
if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){
@@ -207,7 +253,10 @@ void sqlite3RollbackAll(sqlite3 *db){
}
}
sqlite3VtabRollback(db);
+ sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 0);
+
if( db->flags&SQLITE_InternChanges ){
+ sqlite3ExpirePreparedStatements(db);
sqlite3ResetInternalSchema(db, 0);
}
@@ -223,7 +272,7 @@ void sqlite3RollbackAll(sqlite3 *db){
*/
const char *sqlite3ErrStr(int rc){
const char *z;
- switch( rc ){
+ switch( rc & 0xff ){
case SQLITE_ROW:
case SQLITE_DONE:
case SQLITE_OK: z = "not an error"; break;
@@ -239,9 +288,9 @@ const char *sqlite3ErrStr(int rc){
case SQLITE_CORRUPT: z = "database disk image is malformed"; break;
case SQLITE_FULL: z = "database or disk is full"; break;
case SQLITE_CANTOPEN: z = "unable to open database file"; break;
- case SQLITE_PROTOCOL: z = "database locking protocol failure"; break;
case SQLITE_EMPTY: z = "table contains no data"; break;
case SQLITE_SCHEMA: z = "database schema has changed"; break;
+ case SQLITE_TOOBIG: z = "String or BLOB exceeded size limit"; break;
case SQLITE_CONSTRAINT: z = "constraint failed"; break;
case SQLITE_MISMATCH: z = "datatype mismatch"; break;
case SQLITE_MISUSE: z = "library routine called out of sequence";break;
@@ -271,7 +320,8 @@ static int sqliteDefaultBusyCallback(
static const u8 totals[] =
{ 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228 };
# define NDELAY (sizeof(delays)/sizeof(delays[0]))
- int timeout = ((sqlite3 *)ptr)->busyTimeout;
+ sqlite3 *db = (sqlite3 *)ptr;
+ int timeout = db->busyTimeout;
int delay, prior;
assert( count>=0 );
@@ -286,14 +336,15 @@ static int sqliteDefaultBusyCallback(
delay = timeout - prior;
if( delay<=0 ) return 0;
}
- sqlite3OsSleep(delay);
+ sqlite3OsSleep(db->pVfs, delay*1000);
return 1;
#else
+ sqlite3 *db = (sqlite3 *)ptr;
int timeout = ((sqlite3 *)ptr)->busyTimeout;
if( (count+1)*1000 > timeout ){
return 0;
}
- sqlite3OsSleep(1000);
+ sqlite3OsSleep(db->pVfs, 1000000);
return 1;
#endif
}
@@ -326,12 +377,11 @@ int sqlite3_busy_handler(
int (*xBusy)(void*,int),
void *pArg
){
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
+ sqlite3_mutex_enter(db->mutex);
db->busyHandler.xFunc = xBusy;
db->busyHandler.pArg = pArg;
db->busyHandler.nBusy = 0;
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
@@ -347,7 +397,8 @@ void sqlite3_progress_handler(
int (*xProgress)(void*),
void *pArg
){
- if( !sqlite3SafetyCheck(db) ){
+ if( sqlite3SafetyCheckOk(db) ){
+ sqlite3_mutex_enter(db->mutex);
if( nOps>0 ){
db->xProgress = xProgress;
db->nProgressOps = nOps;
@@ -357,6 +408,7 @@ void sqlite3_progress_handler(
db->nProgressOps = 0;
db->pProgressArg = 0;
}
+ sqlite3_mutex_leave(db->mutex);
}
}
#endif
@@ -367,9 +419,6 @@ 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);
@@ -383,35 +432,11 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){
** Cause any pending operation to stop at its earliest opportunity.
*/
void sqlite3_interrupt(sqlite3 *db){
- if( db && (db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_BUSY) ){
+ if( sqlite3SafetyCheckOk(db) ){
db->u1.isInterrupted = 1;
}
}
-/*
-** 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.
-**
-** Use sqlite3_free() to free memory returned by sqlite3_mprintf().
-*/
-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);
- }
-}
/*
** This function is exactly the same as sqlite3_create_function(), except
@@ -432,9 +457,7 @@ int sqlite3CreateFunc(
FuncDef *p;
int nName;
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
+ assert( sqlite3_mutex_held(db->mutex) );
if( zFunctionName==0 ||
(xFunc && (xFinal || xStep)) ||
(!xFunc && (xFinal && !xStep)) ||
@@ -459,10 +482,13 @@ int sqlite3CreateFunc(
int rc;
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8,
pUserData, xFunc, xStep, xFinal);
- if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE,
- pUserData, xFunc, xStep, xFinal);
- if( rc!=SQLITE_OK ) return rc;
+ if( rc==SQLITE_OK ){
+ rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE,
+ pUserData, xFunc, xStep, xFinal);
+ }
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
enc = SQLITE_UTF16BE;
}
#else
@@ -479,7 +505,7 @@ int sqlite3CreateFunc(
if( db->activeVdbeCnt ){
sqlite3Error(db, SQLITE_BUSY,
"Unable to delete/modify user-function due to active statements");
- assert( !sqlite3MallocFailed() );
+ assert( !db->mallocFailed );
return SQLITE_BUSY;
}else{
sqlite3ExpirePreparedStatements(db);
@@ -487,14 +513,16 @@ int sqlite3CreateFunc(
}
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 1);
- if( p ){
- p->flags = 0;
- p->xFunc = xFunc;
- p->xStep = xStep;
- p->xFinalize = xFinal;
- p->pUserData = pUserData;
- p->nArg = nArg;
+ assert(p || db->mallocFailed);
+ if( !p ){
+ return SQLITE_NOMEM;
}
+ p->flags = 0;
+ p->xFunc = xFunc;
+ p->xStep = xStep;
+ p->xFinalize = xFinal;
+ p->pUserData = pUserData;
+ p->nArg = nArg;
return SQLITE_OK;
}
@@ -512,10 +540,12 @@ int sqlite3_create_function(
void (*xFinal)(sqlite3_context*)
){
int rc;
- assert( !sqlite3MallocFailed() );
+ sqlite3_mutex_enter(db->mutex);
+ assert( !db->mallocFailed );
rc = sqlite3CreateFunc(db, zFunctionName, nArg, enc, p, xFunc, xStep, xFinal);
-
- return sqlite3ApiExit(db, rc);
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
}
#ifndef SQLITE_OMIT_UTF16
@@ -531,16 +561,47 @@ int sqlite3_create_function16(
){
int rc;
char *zFunc8;
- assert( !sqlite3MallocFailed() );
-
- zFunc8 = sqlite3utf16to8(zFunctionName, -1);
+ sqlite3_mutex_enter(db->mutex);
+ assert( !db->mallocFailed );
+ zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1);
rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal);
- sqliteFree(zFunc8);
-
- return sqlite3ApiExit(db, rc);
+ sqlite3_free(zFunc8);
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
}
#endif
+
+/*
+** Declare that a function has been overloaded by a virtual table.
+**
+** If the function already exists as a regular global function, then
+** this routine is a no-op. If the function does not exist, then create
+** a new one that always throws a run-time error.
+**
+** When virtual tables intend to provide an overloaded function, they
+** should call this routine to make sure the global function exists.
+** A global function must exist in order for name resolution to work
+** properly.
+*/
+int sqlite3_overload_function(
+ sqlite3 *db,
+ const char *zName,
+ int nArg
+){
+ int nName = strlen(zName);
+ int rc;
+ sqlite3_mutex_enter(db->mutex);
+ if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
+ sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
+ 0, sqlite3InvalidFunction, 0, 0);
+ }
+ rc = sqlite3ApiExit(db, SQLITE_OK);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
+}
+
#ifndef SQLITE_OMIT_TRACE
/*
** Register a trace function. The pArg from the previously registered trace
@@ -551,9 +612,12 @@ int sqlite3_create_function16(
** SQL statement.
*/
void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
- void *pOld = db->pTraceArg;
+ void *pOld;
+ sqlite3_mutex_enter(db->mutex);
+ pOld = db->pTraceArg;
db->xTrace = xTrace;
db->pTraceArg = pArg;
+ sqlite3_mutex_leave(db->mutex);
return pOld;
}
/*
@@ -569,9 +633,12 @@ void *sqlite3_profile(
void (*xProfile)(void*,const char*,sqlite_uint64),
void *pArg
){
- void *pOld = db->pProfileArg;
+ void *pOld;
+ sqlite3_mutex_enter(db->mutex);
+ pOld = db->pProfileArg;
db->xProfile = xProfile;
db->pProfileArg = pArg;
+ sqlite3_mutex_leave(db->mutex);
return pOld;
}
#endif /* SQLITE_OMIT_TRACE */
@@ -587,9 +654,12 @@ void *sqlite3_commit_hook(
int (*xCallback)(void*), /* Function to invoke on each commit */
void *pArg /* Argument to the function */
){
- void *pOld = db->pCommitArg;
+ void *pOld;
+ sqlite3_mutex_enter(db->mutex);
+ pOld = db->pCommitArg;
db->xCommitCallback = xCallback;
db->pCommitArg = pArg;
+ sqlite3_mutex_leave(db->mutex);
return pOld;
}
@@ -602,9 +672,12 @@ void *sqlite3_update_hook(
void (*xCallback)(void*,int,char const *,char const *,sqlite_int64),
void *pArg /* Argument to the function */
){
- void *pRet = db->pUpdateArg;
+ void *pRet;
+ sqlite3_mutex_enter(db->mutex);
+ pRet = db->pUpdateArg;
db->xUpdateCallback = xCallback;
db->pUpdateArg = pArg;
+ sqlite3_mutex_leave(db->mutex);
return pRet;
}
@@ -617,9 +690,12 @@ void *sqlite3_rollback_hook(
void (*xCallback)(void*), /* Callback function */
void *pArg /* Argument to the function */
){
- void *pRet = db->pRollbackArg;
+ void *pRet;
+ sqlite3_mutex_enter(db->mutex);
+ pRet = db->pRollbackArg;
db->xRollbackCallback = xCallback;
db->pRollbackArg = pArg;
+ sqlite3_mutex_leave(db->mutex);
return pRet;
}
@@ -653,17 +729,19 @@ int sqlite3BtreeFactory(
const char *zFilename, /* Name of the file containing the BTree database */
int omitJournal, /* if TRUE then do not journal this file */
int nCache, /* How many pages in the page cache */
+ int vfsFlags, /* Flags passed through to vfsOpen */
Btree **ppBtree /* Pointer to new Btree object written here */
){
- int btree_flags = 0;
+ int btFlags = 0;
int rc;
+ assert( sqlite3_mutex_held(db->mutex) );
assert( ppBtree != 0);
if( omitJournal ){
- btree_flags |= BTREE_OMIT_JOURNAL;
+ btFlags |= BTREE_OMIT_JOURNAL;
}
if( db->flags & SQLITE_NoReadlock ){
- btree_flags |= BTREE_NO_READLOCK;
+ btFlags |= BTREE_NO_READLOCK;
}
if( zFilename==0 ){
#if TEMP_STORE==0
@@ -682,9 +760,11 @@ int sqlite3BtreeFactory(
#endif /* SQLITE_OMIT_MEMORYDB */
}
- rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btree_flags);
+ if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (zFilename==0 || *zFilename==0) ){
+ vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB;
+ }
+ rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btFlags, vfsFlags);
if( rc==SQLITE_OK ){
- sqlite3BtreeSetBusyHandler(*ppBtree, (void*)&db->busyHandler);
sqlite3BtreeSetCacheSize(*ppBtree, nCache);
}
return rc;
@@ -696,16 +776,19 @@ int sqlite3BtreeFactory(
*/
const char *sqlite3_errmsg(sqlite3 *db){
const char *z;
- if( !db || sqlite3MallocFailed() ){
+ if( !db ){
return sqlite3ErrStr(SQLITE_NOMEM);
}
- if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
+ if( !sqlite3SafetyCheckSickOrOk(db) || db->errCode==SQLITE_MISUSE ){
return sqlite3ErrStr(SQLITE_MISUSE);
}
+ sqlite3_mutex_enter(db->mutex);
+ assert( !db->mallocFailed );
z = (char*)sqlite3_value_text(db->pErr);
if( z==0 ){
z = sqlite3ErrStr(db->errCode);
}
+ sqlite3_mutex_leave(db->mutex);
return z;
}
@@ -735,12 +818,14 @@ const void *sqlite3_errmsg16(sqlite3 *db){
};
const void *z;
- if( sqlite3MallocFailed() ){
+ if( !db ){
return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
}
- if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
+ if( !sqlite3SafetyCheckSickOrOk(db) || db->errCode==SQLITE_MISUSE ){
return (void *)(&misuseBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
}
+ sqlite3_mutex_enter(db->mutex);
+ assert( !db->mallocFailed );
z = sqlite3_value_text16(db->pErr);
if( z==0 ){
sqlite3ValueSetStr(db->pErr, -1, sqlite3ErrStr(db->errCode),
@@ -748,6 +833,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){
z = sqlite3_value_text16(db->pErr);
}
sqlite3ApiExit(0, 0);
+ sqlite3_mutex_leave(db->mutex);
return z;
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -757,13 +843,13 @@ const void *sqlite3_errmsg16(sqlite3 *db){
** passed to this function, we assume a malloc() failed during sqlite3_open().
*/
int sqlite3_errcode(sqlite3 *db){
- if( !db || sqlite3MallocFailed() ){
- return SQLITE_NOMEM;
- }
- if( sqlite3SafetyCheck(db) ){
+ if( db && !sqlite3SafetyCheckSickOrOk(db) ){
return SQLITE_MISUSE;
}
- return db->errCode;
+ if( !db || db->mallocFailed ){
+ return SQLITE_NOMEM;
+ }
+ return db->errCode & db->errMask;
}
/*
@@ -775,14 +861,13 @@ static int createCollation(
const char *zName,
int enc,
void* pCtx,
- int(*xCompare)(void*,int,const void*,int,const void*)
+ int(*xCompare)(void*,int,const void*,int,const void*),
+ void(*xDel)(void*)
){
CollSeq *pColl;
int enc2;
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
+ assert( sqlite3_mutex_held(db->mutex) );
/* If SQLITE_UTF16 is specified as the encoding type, transform this
** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
@@ -810,12 +895,33 @@ static int createCollation(
return SQLITE_BUSY;
}
sqlite3ExpirePreparedStatements(db);
+
+ /* If collation sequence pColl was created directly by a call to
+ ** sqlite3_create_collation, and not generated by synthCollSeq(),
+ ** then any copies made by synthCollSeq() need to be invalidated.
+ ** Also, collation destructor - CollSeq.xDel() - function may need
+ ** to be called.
+ */
+ if( (pColl->enc & ~SQLITE_UTF16_ALIGNED)==enc2 ){
+ CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName, strlen(zName));
+ int j;
+ for(j=0; j<3; j++){
+ CollSeq *p = &aColl[j];
+ if( p->enc==pColl->enc ){
+ if( p->xDel ){
+ p->xDel(p->pUser);
+ }
+ p->xCmp = 0;
+ }
+ }
+ }
}
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, strlen(zName), 1);
if( pColl ){
pColl->xCmp = xCompare;
pColl->pUser = pCtx;
+ pColl->xDel = xDel;
pColl->enc = enc2 | (enc & SQLITE_UTF16_ALIGNED);
}
sqlite3Error(db, SQLITE_OK, 0);
@@ -830,26 +936,38 @@ static int createCollation(
*/
static int openDatabase(
const char *zFilename, /* Database filename UTF-8 encoded */
- sqlite3 **ppDb /* OUT: Returned database handle */
+ sqlite3 **ppDb, /* OUT: Returned database handle */
+ unsigned flags, /* Operational flags */
+ const char *zVfs /* Name of the VFS to use */
){
sqlite3 *db;
int rc;
CollSeq *pColl;
- assert( !sqlite3MallocFailed() );
-
/* Allocate the sqlite data structure */
- db = sqliteMalloc( sizeof(sqlite3) );
+ db = sqlite3MallocZero( sizeof(sqlite3) );
if( db==0 ) goto opendb_out;
+ db->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE);
+ if( db->mutex==0 ){
+ sqlite3_free(db);
+ db = 0;
+ goto opendb_out;
+ }
+ sqlite3_mutex_enter(db->mutex);
+ db->errMask = 0xff;
db->priorNewRowid = 0;
- db->magic = SQLITE_MAGIC_BUSY;
db->nDb = 2;
+ db->magic = SQLITE_MAGIC_BUSY;
db->aDb = db->aDbStatic;
db->autoCommit = 1;
+ db->nextAutovac = -1;
db->flags |= SQLITE_ShortColNames
#if SQLITE_DEFAULT_FILE_FORMAT<4
| SQLITE_LegacyFileFmt
#endif
+#ifdef SQLITE_ENABLE_LOAD_EXTENSION
+ | SQLITE_LoadExtension
+#endif
;
sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0);
@@ -857,22 +975,31 @@ static int openDatabase(
sqlite3HashInit(&db->aModule, SQLITE_HASH_STRING, 0);
#endif
+ db->pVfs = sqlite3_vfs_find(zVfs);
+ if( !db->pVfs ){
+ rc = SQLITE_ERROR;
+ db->magic = SQLITE_MAGIC_SICK;
+ sqlite3Error(db, rc, "no such vfs: %s", (zVfs?zVfs:"(null)"));
+ goto opendb_out;
+ }
+
/* 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( createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc) ||
- createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc) ||
- createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc) ||
+ if( createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc, 0) ||
+ createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc, 0) ||
+ createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc, 0) ||
+ createCollation(db, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0) ||
(db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0))==0
){
- assert( sqlite3MallocFailed() );
- db->magic = SQLITE_MAGIC_CLOSED;
+ assert( db->mallocFailed );
+ db->magic = SQLITE_MAGIC_SICK;
goto opendb_out;
}
/* Also add a UTF-8 case-insensitive collation sequence. */
- createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc);
+ createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
/* Set flags on the built-in collating sequences */
db->pDfltColl->type = SQLITE_COLL_BINARY;
@@ -882,14 +1009,17 @@ static int openDatabase(
}
/* Open the backend database driver */
- rc = sqlite3BtreeFactory(db, zFilename, 0, MAX_PAGES, &db->aDb[0].pBt);
+ db->openFlags = flags;
+ rc = sqlite3BtreeFactory(db, zFilename, 0, SQLITE_DEFAULT_CACHE_SIZE,
+ flags | SQLITE_OPEN_MAIN_DB,
+ &db->aDb[0].pBt);
if( rc!=SQLITE_OK ){
sqlite3Error(db, rc, 0);
- db->magic = SQLITE_MAGIC_CLOSED;
+ db->magic = SQLITE_MAGIC_SICK;
goto opendb_out;
}
- db->aDb[0].pSchema = sqlite3SchemaGet(db->aDb[0].pBt);
- db->aDb[1].pSchema = sqlite3SchemaGet(0);
+ db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
+ db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
/* The default safety_level for the main database is 'full'; for the temp
@@ -902,17 +1032,68 @@ static int openDatabase(
db->aDb[1].safety_level = 1;
#endif
+ db->magic = SQLITE_MAGIC_OPEN;
+ if( db->mallocFailed ){
+ goto opendb_out;
+ }
+
/* 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.
*/
- if( !sqlite3MallocFailed() ){
- sqlite3RegisterBuiltinFunctions(db);
- sqlite3Error(db, SQLITE_OK, 0);
+ sqlite3Error(db, SQLITE_OK, 0);
+ sqlite3RegisterBuiltinFunctions(db);
+
+ /* Load automatic extensions - extensions that have been registered
+ ** using the sqlite3_automatic_extension() API.
+ */
+ (void)sqlite3AutoLoadExtensions(db);
+ if( sqlite3_errcode(db)!=SQLITE_OK ){
+ goto opendb_out;
}
- db->magic = SQLITE_MAGIC_OPEN;
+
+#ifdef SQLITE_ENABLE_FTS1
+ if( !db->mallocFailed ){
+ extern int sqlite3Fts1Init(sqlite3*);
+ rc = sqlite3Fts1Init(db);
+ }
+#endif
+
+#ifdef SQLITE_ENABLE_FTS2
+ if( !db->mallocFailed && rc==SQLITE_OK ){
+ extern int sqlite3Fts2Init(sqlite3*);
+ rc = sqlite3Fts2Init(db);
+ }
+#endif
+
+#ifdef SQLITE_ENABLE_FTS3
+ if( !db->mallocFailed && rc==SQLITE_OK ){
+ rc = sqlite3Fts3Init(db);
+ }
+#endif
+
+#ifdef SQLITE_ENABLE_ICU
+ if( !db->mallocFailed && rc==SQLITE_OK ){
+ extern int sqlite3IcuInit(sqlite3*);
+ rc = sqlite3IcuInit(db);
+ }
+#endif
+ sqlite3Error(db, rc, 0);
+
+ /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
+ ** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking
+ ** mode. Doing nothing at all also makes NORMAL the default.
+ */
+#ifdef SQLITE_DEFAULT_LOCKING_MODE
+ db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE;
+ sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt),
+ SQLITE_DEFAULT_LOCKING_MODE);
+#endif
opendb_out:
+ if( db && db->mutex ){
+ sqlite3_mutex_leave(db->mutex);
+ }
if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){
sqlite3_close(db);
db = 0;
@@ -928,7 +1109,16 @@ int sqlite3_open(
const char *zFilename,
sqlite3 **ppDb
){
- return openDatabase(zFilename, ppDb);
+ return openDatabase(zFilename, ppDb,
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
+}
+int sqlite3_open_v2(
+ const char *filename, /* Database filename (UTF-8) */
+ sqlite3 **ppDb, /* OUT: SQLite db handle */
+ int flags, /* Flags */
+ const char *zVfs /* Name of VFS module to use */
+){
+ return openDatabase(filename, ppDb, flags, zVfs);
}
#ifndef SQLITE_OMIT_UTF16
@@ -940,17 +1130,18 @@ int sqlite3_open16(
sqlite3 **ppDb
){
char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */
- int rc = SQLITE_OK;
sqlite3_value *pVal;
+ int rc = SQLITE_NOMEM;
assert( zFilename );
assert( ppDb );
*ppDb = 0;
- pVal = sqlite3ValueNew();
+ pVal = sqlite3ValueNew(0);
sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC);
zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8);
if( zFilename8 ){
- rc = openDatabase(zFilename8, ppDb);
+ rc = openDatabase(zFilename8, ppDb,
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
if( rc==SQLITE_OK && *ppDb ){
rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
if( rc!=SQLITE_OK ){
@@ -966,57 +1157,42 @@ int sqlite3_open16(
#endif /* SQLITE_OMIT_UTF16 */
/*
-** The following routine destroys a virtual machine that is created by
-** the sqlite3_compile() routine. The integer returned is an SQLITE_
-** success/failure code that describes the result of executing the virtual
-** machine.
-**
-** This routine sets the error code and string returned by
-** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
-*/
-int sqlite3_finalize(sqlite3_stmt *pStmt){
- int rc;
- if( pStmt==0 ){
- rc = SQLITE_OK;
- }else{
- rc = sqlite3VdbeFinalize((Vdbe*)pStmt);
- }
- return rc;
-}
-
-/*
-** Terminate the current execution of an SQL statement and reset it
-** back to its starting state so that it can be reused. A success code from
-** the prior execution is returned.
-**
-** This routine sets the error code and string returned by
-** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
+** Register a new collation sequence with the database handle db.
*/
-int sqlite3_reset(sqlite3_stmt *pStmt){
+int sqlite3_create_collation(
+ sqlite3* db,
+ const char *zName,
+ int enc,
+ void* pCtx,
+ int(*xCompare)(void*,int,const void*,int,const void*)
+){
int rc;
- if( pStmt==0 ){
- rc = SQLITE_OK;
- }else{
- rc = sqlite3VdbeReset((Vdbe*)pStmt);
- sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0);
- }
+ sqlite3_mutex_enter(db->mutex);
+ assert( !db->mallocFailed );
+ rc = createCollation(db, zName, enc, pCtx, xCompare, 0);
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
return rc;
}
/*
** Register a new collation sequence with the database handle db.
*/
-int sqlite3_create_collation(
+int sqlite3_create_collation_v2(
sqlite3* db,
const char *zName,
int enc,
void* pCtx,
- int(*xCompare)(void*,int,const void*,int,const void*)
+ int(*xCompare)(void*,int,const void*,int,const void*),
+ void(*xDel)(void*)
){
int rc;
- assert( !sqlite3MallocFailed() );
- rc = createCollation(db, zName, enc, pCtx, xCompare);
- return sqlite3ApiExit(db, rc);
+ sqlite3_mutex_enter(db->mutex);
+ assert( !db->mallocFailed );
+ rc = createCollation(db, zName, enc, pCtx, xCompare, xDel);
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
}
#ifndef SQLITE_OMIT_UTF16
@@ -1031,14 +1207,17 @@ int sqlite3_create_collation16(
int(*xCompare)(void*,int,const void*,int,const void*)
){
int rc = SQLITE_OK;
- char *zName8;
- assert( !sqlite3MallocFailed() );
- zName8 = sqlite3utf16to8(zName, -1);
+ char *zName8;
+ sqlite3_mutex_enter(db->mutex);
+ assert( !db->mallocFailed );
+ zName8 = sqlite3Utf16to8(db, zName, -1);
if( zName8 ){
- rc = createCollation(db, zName8, enc, pCtx, xCompare);
- sqliteFree(zName8);
+ rc = createCollation(db, zName8, enc, pCtx, xCompare, 0);
+ sqlite3_free(zName8);
}
- return sqlite3ApiExit(db, rc);
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -1051,12 +1230,11 @@ int sqlite3_collation_needed(
void *pCollNeededArg,
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*)
){
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
+ sqlite3_mutex_enter(db->mutex);
db->xCollNeeded = xCollNeeded;
db->xCollNeeded16 = 0;
db->pCollNeededArg = pCollNeededArg;
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
@@ -1070,12 +1248,11 @@ int sqlite3_collation_needed16(
void *pCollNeededArg,
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*)
){
- if( sqlite3SafetyCheck(db) ){
- return SQLITE_MISUSE;
- }
+ sqlite3_mutex_enter(db->mutex);
db->xCollNeeded = 0;
db->xCollNeeded16 = xCollNeeded16;
db->pCollNeededArg = pCollNeededArg;
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -1085,7 +1262,7 @@ int sqlite3_collation_needed16(
** 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 sqlite3_global_recover(void){
return SQLITE_OK;
}
#endif
@@ -1113,45 +1290,14 @@ int sqlite3Corrupt(void){
}
#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.
+**
+** SQLite no longer uses thread-specific data so this routine is now a
+** no-op. It is retained for historical compatibility.
*/
void sqlite3_thread_cleanup(void){
- ThreadData *pTd = sqlite3OsThreadSpecificData(0);
- if( pTd ){
- memset(pTd, 0, sizeof(*pTd));
- sqlite3OsThreadSpecificData(-1);
- }
}
/*
@@ -1183,9 +1329,8 @@ int sqlite3_table_column_metadata(
int autoinc = 0;
/* Ensure the database schema has been loaded */
- if( sqlite3SafetyOn(db) ){
- return SQLITE_MISUSE;
- }
+ (void)sqlite3SafetyOn(db);
+ sqlite3_mutex_enter(db->mutex);
rc = sqlite3Init(db, &zErrMsg);
if( SQLITE_OK!=rc ){
goto error_out;
@@ -1242,9 +1387,7 @@ int sqlite3_table_column_metadata(
}
error_out:
- if( sqlite3SafetyOff(db) ){
- rc = SQLITE_MISUSE;
- }
+ (void)sqlite3SafetyOff(db);
/* Whether the function call succeeded or failed, set the output parameters
** to whatever their local counterparts contain. If an error did occur,
@@ -1262,26 +1405,105 @@ error_out:
rc = SQLITE_ERROR;
}
sqlite3Error(db, rc, (zErrMsg?"%s":0), zErrMsg);
- sqliteFree(zErrMsg);
- return sqlite3ApiExit(db, rc);
+ sqlite3_free(zErrMsg);
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
}
#endif
/*
-** Set all the parameters in the compiled SQL statement to NULL.
+** Sleep for a little while. Return the amount of time slept.
*/
-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);
- }
+int sqlite3_sleep(int ms){
+ sqlite3_vfs *pVfs;
+ int rc;
+ pVfs = sqlite3_vfs_find(0);
+
+ /* This function works in milliseconds, but the underlying OsSleep()
+ ** API uses microseconds. Hence the 1000's.
+ */
+ rc = (sqlite3OsSleep(pVfs, 1000*ms)/1000);
return rc;
}
/*
-** Sleep for a little while. Return the amount of time slept.
+** Enable or disable the extended result codes.
*/
-int sqlite3_sleep(int ms){
- return sqlite3OsSleep(ms);
+int sqlite3_extended_result_codes(sqlite3 *db, int onoff){
+ sqlite3_mutex_enter(db->mutex);
+ db->errMask = onoff ? 0xffffffff : 0xff;
+ sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+}
+
+/*
+** Invoke the xFileControl method on a particular database.
+*/
+int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
+ int rc = SQLITE_ERROR;
+ int iDb;
+ sqlite3_mutex_enter(db->mutex);
+ if( zDbName==0 ){
+ iDb = 0;
+ }else{
+ for(iDb=0; iDb<db->nDb; iDb++){
+ if( strcmp(db->aDb[iDb].zName, zDbName)==0 ) break;
+ }
+ }
+ if( iDb<db->nDb ){
+ Btree *pBtree = db->aDb[iDb].pBt;
+ if( pBtree ){
+ Pager *pPager;
+ sqlite3_file *fd;
+ sqlite3BtreeEnter(pBtree);
+ pPager = sqlite3BtreePager(pBtree);
+ assert( pPager!=0 );
+ fd = sqlite3PagerFile(pPager);
+ assert( fd!=0 );
+ if( fd->pMethods ){
+ rc = sqlite3OsFileControl(fd, op, pArg);
+ }
+ sqlite3BtreeLeave(pBtree);
+ }
+ }
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
+}
+
+/*
+** Interface to the testing logic.
+*/
+int sqlite3_test_control(int op, ...){
+ va_list ap;
+ int rc = 0;
+ va_start(ap, op);
+ switch( op ){
+#ifndef SQLITE_OMIT_FAULTINJECTOR
+ case SQLITE_TESTCTRL_FAULT_CONFIG: {
+ int id = va_arg(ap, int);
+ int nDelay = va_arg(ap, int);
+ int nRepeat = va_arg(ap, int);
+ sqlite3FaultConfig(id, nDelay, nRepeat);
+ break;
+ }
+ case SQLITE_TESTCTRL_FAULT_FAILURES: {
+ int id = va_arg(ap, int);
+ rc = sqlite3FaultFailures(id);
+ break;
+ }
+ case SQLITE_TESTCTRL_FAULT_BENIGN_FAILURES: {
+ int id = va_arg(ap, int);
+ rc = sqlite3FaultBenignFailures(id);
+ break;
+ }
+ case SQLITE_TESTCTRL_FAULT_PENDING: {
+ int id = va_arg(ap, int);
+ rc = sqlite3FaultPending(id);
+ break;
+ }
+#endif /* SQLITE_OMIT_FAULTINJECTOR */
+ }
+ va_end(ap);
+ return rc;
}
diff --git a/ext/pdo_sqlite/sqlite/src/malloc.c b/ext/pdo_sqlite/sqlite/src/malloc.c
new file mode 100644
index 0000000000..3f9d96612e
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/malloc.c
@@ -0,0 +1,239 @@
+/*
+** 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.
+**
+*************************************************************************
+** Memory allocation functions used throughout sqlite.
+**
+**
+** $Id$
+*/
+#include "sqliteInt.h"
+#include <stdarg.h>
+#include <ctype.h>
+
+/*
+** This routine runs when the memory allocator sees that the
+** total memory allocation is about to exceed the soft heap
+** limit.
+*/
+static void softHeapLimitEnforcer(
+ void *NotUsed,
+ sqlite3_int64 inUse,
+ int allocSize
+){
+ sqlite3_release_memory(allocSize);
+}
+
+/*
+** Set the soft heap-size limit for the current thread. Passing a
+** zero or negative value indicates no limit.
+*/
+void sqlite3_soft_heap_limit(int n){
+ sqlite3_uint64 iLimit;
+ int overage;
+ if( n<0 ){
+ iLimit = 0;
+ }else{
+ iLimit = n;
+ }
+ if( iLimit>0 ){
+ sqlite3_memory_alarm(softHeapLimitEnforcer, 0, iLimit);
+ }else{
+ sqlite3_memory_alarm(0, 0, 0);
+ }
+ overage = sqlite3_memory_used() - n;
+ if( overage>0 ){
+ sqlite3_release_memory(overage);
+ }
+}
+
+/*
+** Release memory held by SQLite instances created by the current thread.
+*/
+int sqlite3_release_memory(int n){
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ return sqlite3PagerReleaseMemory(n);
+#else
+ return SQLITE_OK;
+#endif
+}
+
+
+/*
+** Allocate and zero memory.
+*/
+void *sqlite3MallocZero(unsigned n){
+ void *p = sqlite3_malloc(n);
+ if( p ){
+ memset(p, 0, n);
+ }
+ return p;
+}
+
+/*
+** Allocate and zero memory. If the allocation fails, make
+** the mallocFailed flag in the connection pointer.
+*/
+void *sqlite3DbMallocZero(sqlite3 *db, unsigned n){
+ void *p = sqlite3DbMallocRaw(db, n);
+ if( p ){
+ memset(p, 0, n);
+ }
+ return p;
+}
+
+/*
+** Allocate and zero memory. If the allocation fails, make
+** the mallocFailed flag in the connection pointer.
+*/
+void *sqlite3DbMallocRaw(sqlite3 *db, unsigned n){
+ void *p = 0;
+ if( !db || db->mallocFailed==0 ){
+ p = sqlite3_malloc(n);
+ if( !p && db ){
+ db->mallocFailed = 1;
+ }
+ }
+ return p;
+}
+
+/*
+** Resize the block of memory pointed to by p to n bytes. If the
+** resize fails, set the mallocFailed flag inthe connection object.
+*/
+void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){
+ void *pNew = 0;
+ if( db->mallocFailed==0 ){
+ pNew = sqlite3_realloc(p, n);
+ if( !pNew ){
+ db->mallocFailed = 1;
+ }
+ }
+ return pNew;
+}
+
+/*
+** Attempt to reallocate p. If the reallocation fails, then free p
+** and set the mallocFailed flag in the database connection.
+*/
+void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, int n){
+ void *pNew;
+ pNew = sqlite3DbRealloc(db, p, n);
+ if( !pNew ){
+ sqlite3_free(p);
+ }
+ return pNew;
+}
+
+/*
+** 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;
+ int n;
+ if( z==0 ) return 0;
+ n = strlen(z)+1;
+ zNew = sqlite3_malloc(n);
+ if( zNew ) memcpy(zNew, z, n);
+ return zNew;
+}
+char *sqlite3StrNDup(const char *z, int n){
+ char *zNew;
+ if( z==0 ) return 0;
+ zNew = sqlite3_malloc(n+1);
+ if( zNew ){
+ memcpy(zNew, z, n);
+ zNew[n] = 0;
+ }
+ return zNew;
+}
+
+char *sqlite3DbStrDup(sqlite3 *db, const char *z){
+ char *zNew = sqlite3StrDup(z);
+ if( z && !zNew ){
+ db->mallocFailed = 1;
+ }
+ return zNew;
+}
+char *sqlite3DbStrNDup(sqlite3 *db, const char *z, int n){
+ char *zNew = sqlite3StrNDup(z, n);
+ if( z && !zNew ){
+ db->mallocFailed = 1;
+ }
+ return zNew;
+}
+
+/*
+** Create a string from the 2nd and subsequent arguments (up to the
+** first NULL argument), store the string in memory obtained from
+** sqliteMalloc() and make the pointer indicated by the 1st argument
+** point to that string. The 1st argument must either be NULL or
+** point to memory obtained from sqliteMalloc().
+*/
+void sqlite3SetString(char **pz, ...){
+ va_list ap;
+ int nByte;
+ const char *z;
+ char *zResult;
+
+ assert( pz!=0 );
+ nByte = 1;
+ va_start(ap, pz);
+ while( (z = va_arg(ap, const char*))!=0 ){
+ nByte += strlen(z);
+ }
+ va_end(ap);
+ sqlite3_free(*pz);
+ *pz = zResult = sqlite3_malloc(nByte);
+ if( zResult==0 ){
+ return;
+ }
+ *zResult = 0;
+ va_start(ap, pz);
+ while( (z = va_arg(ap, const char*))!=0 ){
+ int n = strlen(z);
+ memcpy(zResult, z, n);
+ zResult += n;
+ }
+ zResult[0] = 0;
+ va_end(ap);
+}
+
+
+/*
+** This function must be called before exiting any API function (i.e.
+** returning control to the user) that has called sqlite3_malloc or
+** sqlite3_realloc.
+**
+** 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.
+*/
+int sqlite3ApiExit(sqlite3* db, int rc){
+ /* If the db handle is not NULL, then we must hold the connection handle
+ ** mutex here. Otherwise the read (and possible write) of db->mallocFailed
+ ** is unsafe, as is the call to sqlite3Error().
+ */
+ assert( !db || sqlite3_mutex_held(db->mutex) );
+ if( db && db->mallocFailed ){
+ sqlite3Error(db, SQLITE_NOMEM, 0);
+ db->mallocFailed = 0;
+ rc = SQLITE_NOMEM;
+ }
+ return rc & (db ? db->errMask : 0xff);
+}
diff --git a/ext/pdo_sqlite/sqlite/src/md5.c b/ext/pdo_sqlite/sqlite/src/md5.c
index 32fcb6b680..a4c9931fba 100644
--- a/ext/pdo_sqlite/sqlite/src/md5.c
+++ b/ext/pdo_sqlite/sqlite/src/md5.c
@@ -366,9 +366,9 @@ static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){
MD5Init(p);
}
for(i=0; i<argc; i++){
- const char *zData = sqlite3_value_text(argv[i]);
+ const char *zData = (char*)sqlite3_value_text(argv[i]);
if( zData ){
- MD5Update(p, zData, strlen(zData));
+ MD5Update(p, (unsigned char*)zData, strlen(zData));
}
}
}
diff --git a/ext/pdo_sqlite/sqlite/src/mem1.c b/ext/pdo_sqlite/sqlite/src/mem1.c
new file mode 100644
index 0000000000..95835d9568
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/mem1.c
@@ -0,0 +1,232 @@
+/*
+** 2007 August 14
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file contains the C functions that implement a memory
+** allocation subsystem for use by SQLite.
+**
+** $Id$
+*/
+
+/*
+** This version of the memory allocator is the default. It is
+** used when no other memory allocator is specified using compile-time
+** macros.
+*/
+#if !defined(SQLITE_MEMDEBUG) && !defined(SQLITE_MEMORY_SIZE) \
+ && !defined(SQLITE_MMAP_HEAP_SIZE)
+
+/*
+** We will eventually construct multiple memory allocation subsystems
+** suitable for use in various contexts:
+**
+** * Normal multi-threaded builds
+** * Normal single-threaded builds
+** * Debugging builds
+**
+** This initial version is suitable for use in normal multi-threaded
+** builds. We envision that alternative versions will be stored in
+** separate source files. #ifdefs will be used to select the code from
+** one of the various memN.c source files for use in any given build.
+*/
+#include "sqliteInt.h"
+
+/*
+** All of the static variables used by this module are collected
+** into a single structure named "mem". This is to keep the
+** static variables organized and to reduce namespace pollution
+** when this module is combined with other in the amalgamation.
+*/
+static struct {
+ /*
+ ** The alarm callback and its arguments. The mem.mutex lock will
+ ** be held while the callback is running. Recursive calls into
+ ** the memory subsystem are allowed, but no new callbacks will be
+ ** issued. The alarmBusy variable is set to prevent recursive
+ ** callbacks.
+ */
+ sqlite3_int64 alarmThreshold;
+ void (*alarmCallback)(void*, sqlite3_int64,int);
+ void *alarmArg;
+ int alarmBusy;
+
+ /*
+ ** Mutex to control access to the memory allocation subsystem.
+ */
+ sqlite3_mutex *mutex;
+
+ /*
+ ** Current allocation and high-water mark.
+ */
+ sqlite3_int64 nowUsed;
+ sqlite3_int64 mxUsed;
+
+
+} mem;
+
+/*
+** Enter the mutex mem.mutex. Allocate it if it is not already allocated.
+*/
+static void enterMem(void){
+ if( mem.mutex==0 ){
+ mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
+ }
+ sqlite3_mutex_enter(mem.mutex);
+}
+
+/*
+** Return the amount of memory currently checked out.
+*/
+sqlite3_int64 sqlite3_memory_used(void){
+ sqlite3_int64 n;
+ enterMem();
+ n = mem.nowUsed;
+ sqlite3_mutex_leave(mem.mutex);
+ return n;
+}
+
+/*
+** Return the maximum amount of memory that has ever been
+** checked out since either the beginning of this process
+** or since the most recent reset.
+*/
+sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
+ sqlite3_int64 n;
+ enterMem();
+ n = mem.mxUsed;
+ if( resetFlag ){
+ mem.mxUsed = mem.nowUsed;
+ }
+ sqlite3_mutex_leave(mem.mutex);
+ return n;
+}
+
+/*
+** Change the alarm callback
+*/
+int sqlite3_memory_alarm(
+ void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
+ void *pArg,
+ sqlite3_int64 iThreshold
+){
+ enterMem();
+ mem.alarmCallback = xCallback;
+ mem.alarmArg = pArg;
+ mem.alarmThreshold = iThreshold;
+ sqlite3_mutex_leave(mem.mutex);
+ return SQLITE_OK;
+}
+
+/*
+** Trigger the alarm
+*/
+static void sqlite3MemsysAlarm(int nByte){
+ void (*xCallback)(void*,sqlite3_int64,int);
+ sqlite3_int64 nowUsed;
+ void *pArg;
+ if( mem.alarmCallback==0 || mem.alarmBusy ) return;
+ mem.alarmBusy = 1;
+ xCallback = mem.alarmCallback;
+ nowUsed = mem.nowUsed;
+ pArg = mem.alarmArg;
+ sqlite3_mutex_leave(mem.mutex);
+ xCallback(pArg, nowUsed, nByte);
+ sqlite3_mutex_enter(mem.mutex);
+ mem.alarmBusy = 0;
+}
+
+/*
+** Allocate nBytes of memory
+*/
+void *sqlite3_malloc(int nBytes){
+ sqlite3_int64 *p = 0;
+ if( nBytes>0 ){
+ enterMem();
+ if( mem.alarmCallback!=0 && mem.nowUsed+nBytes>=mem.alarmThreshold ){
+ sqlite3MemsysAlarm(nBytes);
+ }
+ p = malloc(nBytes+8);
+ if( p==0 ){
+ sqlite3MemsysAlarm(nBytes);
+ p = malloc(nBytes+8);
+ }
+ if( p ){
+ p[0] = nBytes;
+ p++;
+ mem.nowUsed += nBytes;
+ if( mem.nowUsed>mem.mxUsed ){
+ mem.mxUsed = mem.nowUsed;
+ }
+ }
+ sqlite3_mutex_leave(mem.mutex);
+ }
+ return (void*)p;
+}
+
+/*
+** Free memory.
+*/
+void sqlite3_free(void *pPrior){
+ sqlite3_int64 *p;
+ int nByte;
+ if( pPrior==0 ){
+ return;
+ }
+ assert( mem.mutex!=0 );
+ p = pPrior;
+ p--;
+ nByte = (int)*p;
+ sqlite3_mutex_enter(mem.mutex);
+ mem.nowUsed -= nByte;
+ free(p);
+ sqlite3_mutex_leave(mem.mutex);
+}
+
+/*
+** Change the size of an existing memory allocation
+*/
+void *sqlite3_realloc(void *pPrior, int nBytes){
+ int nOld;
+ sqlite3_int64 *p;
+ if( pPrior==0 ){
+ return sqlite3_malloc(nBytes);
+ }
+ if( nBytes<=0 ){
+ sqlite3_free(pPrior);
+ return 0;
+ }
+ p = pPrior;
+ p--;
+ nOld = (int)p[0];
+ assert( mem.mutex!=0 );
+ sqlite3_mutex_enter(mem.mutex);
+ if( mem.nowUsed+nBytes-nOld>=mem.alarmThreshold ){
+ sqlite3MemsysAlarm(nBytes-nOld);
+ }
+ p = realloc(p, nBytes+8);
+ if( p==0 ){
+ sqlite3MemsysAlarm(nBytes);
+ p = pPrior;
+ p--;
+ p = realloc(p, nBytes+8);
+ }
+ if( p ){
+ p[0] = nBytes;
+ p++;
+ mem.nowUsed += nBytes-nOld;
+ if( mem.nowUsed>mem.mxUsed ){
+ mem.mxUsed = mem.nowUsed;
+ }
+ }
+ sqlite3_mutex_leave(mem.mutex);
+ return (void*)p;
+}
+
+#endif /* !SQLITE_MEMDEBUG && !SQLITE_OMIT_MEMORY_ALLOCATION */
diff --git a/ext/pdo_sqlite/sqlite/src/mutex.c b/ext/pdo_sqlite/sqlite/src/mutex.c
new file mode 100644
index 0000000000..687ee5496a
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/mutex.c
@@ -0,0 +1,126 @@
+/*
+** 2007 August 14
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file contains the C functions that implement mutexes.
+**
+** The implementation in this file does not provide any mutual
+** exclusion and is thus suitable for use only in applications
+** that use SQLite in a single thread. But this implementation
+** does do a lot of error checking on mutexes to make sure they
+** are called correctly and at appropriate times. Hence, this
+** implementation is suitable for testing.
+** debugging purposes
+**
+** $Id$
+*/
+#include "sqliteInt.h"
+
+#ifdef SQLITE_MUTEX_NOOP_DEBUG
+/*
+** In this implementation, mutexes do not provide any mutual exclusion.
+** But the error checking is provided. This implementation is useful
+** for test purposes.
+*/
+
+/*
+** The mutex object
+*/
+struct sqlite3_mutex {
+ int id; /* The mutex type */
+ int cnt; /* Number of entries without a matching leave */
+};
+
+/*
+** The sqlite3_mutex_alloc() routine allocates a new
+** mutex and returns a pointer to it. If it returns NULL
+** that means that a mutex could not be allocated.
+*/
+sqlite3_mutex *sqlite3_mutex_alloc(int id){
+ static sqlite3_mutex aStatic[5];
+ sqlite3_mutex *pNew = 0;
+ switch( id ){
+ case SQLITE_MUTEX_FAST:
+ case SQLITE_MUTEX_RECURSIVE: {
+ pNew = sqlite3_malloc(sizeof(*pNew));
+ if( pNew ){
+ pNew->id = id;
+ pNew->cnt = 0;
+ }
+ break;
+ }
+ default: {
+ assert( id-2 >= 0 );
+ assert( id-2 < sizeof(aStatic)/sizeof(aStatic[0]) );
+ pNew = &aStatic[id-2];
+ pNew->id = id;
+ break;
+ }
+ }
+ return pNew;
+}
+
+/*
+** This routine deallocates a previously allocated mutex.
+*/
+void sqlite3_mutex_free(sqlite3_mutex *p){
+ assert( p );
+ assert( p->cnt==0 );
+ assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
+ sqlite3_free(p);
+}
+
+/*
+** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
+** to enter a mutex. If another thread is already within the mutex,
+** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
+** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK
+** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can
+** be entered multiple times by the same thread. In such cases the,
+** mutex must be exited an equal number of times before another thread
+** can enter. If the same thread tries to enter any other kind of mutex
+** more than once, the behavior is undefined.
+*/
+void sqlite3_mutex_enter(sqlite3_mutex *p){
+ assert( p );
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
+ p->cnt++;
+}
+int sqlite3_mutex_try(sqlite3_mutex *p){
+ assert( p );
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
+ p->cnt++;
+ return SQLITE_OK;
+}
+
+/*
+** The sqlite3_mutex_leave() routine exits a mutex that was
+** previously entered by the same thread. The behavior
+** is undefined if the mutex is not currently entered or
+** is not currently allocated. SQLite will never do either.
+*/
+void sqlite3_mutex_leave(sqlite3_mutex *p){
+ assert( p );
+ assert( sqlite3_mutex_held(p) );
+ p->cnt--;
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
+}
+
+/*
+** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
+** intended for use inside assert() statements.
+*/
+int sqlite3_mutex_held(sqlite3_mutex *p){
+ return p==0 || p->cnt>0;
+}
+int sqlite3_mutex_notheld(sqlite3_mutex *p){
+ return p==0 || p->cnt==0;
+}
+#endif /* SQLITE_MUTEX_NOOP_DEBUG */
diff --git a/ext/pdo_sqlite/sqlite/src/mutex.h b/ext/pdo_sqlite/sqlite/src/mutex.h
new file mode 100644
index 0000000000..008a1e52e3
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/mutex.h
@@ -0,0 +1,82 @@
+/*
+** 2007 August 28
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file contains the common header for all mutex implementations.
+** The sqliteInt.h header #includes this file so that it is available
+** to all source files. We break it out in an effort to keep the code
+** better organized.
+**
+** NOTE: source files should *not* #include this header file directly.
+** Source files should #include the sqliteInt.h file and let that file
+** include this one indirectly.
+**
+** $Id$
+*/
+
+
+#ifdef SQLITE_MUTEX_APPDEF
+/*
+** If SQLITE_MUTEX_APPDEF is defined, then this whole module is
+** omitted and equivalent functionality must be provided by the
+** application that links against the SQLite library.
+*/
+#else
+/*
+** Figure out what version of the code to use. The choices are
+**
+** SQLITE_MUTEX_NOOP For single-threaded applications that
+** do not desire error checking.
+**
+** SQLITE_MUTEX_NOOP_DEBUG For single-threaded applications with
+** error checking to help verify that mutexes
+** are being used correctly even though they
+** are not needed. Used when SQLITE_DEBUG is
+** defined on single-threaded builds.
+**
+** SQLITE_MUTEX_PTHREADS For multi-threaded applications on Unix.
+**
+** SQLITE_MUTEX_W32 For multi-threaded applications on Win32.
+**
+** SQLITE_MUTEX_OS2 For multi-threaded applications on OS/2.
+*/
+#define SQLITE_MUTEX_NOOP 1 /* The default */
+#if defined(SQLITE_DEBUG) && !SQLITE_THREADSAFE
+# undef SQLITE_MUTEX_NOOP
+# define SQLITE_MUTEX_NOOP_DEBUG
+#endif
+#if defined(SQLITE_MUTEX_NOOP) && SQLITE_THREADSAFE && OS_UNIX
+# undef SQLITE_MUTEX_NOOP
+# define SQLITE_MUTEX_PTHREADS
+#endif
+#if defined(SQLITE_MUTEX_NOOP) && SQLITE_THREADSAFE && OS_WIN
+# undef SQLITE_MUTEX_NOOP
+# define SQLITE_MUTEX_W32
+#endif
+#if defined(SQLITE_MUTEX_NOOP) && SQLITE_THREADSAFE && OS_OS2
+# undef SQLITE_MUTEX_NOOP
+# define SQLITE_MUTEX_OS2
+#endif
+
+#ifdef SQLITE_MUTEX_NOOP
+/*
+** If this is a no-op implementation, implement everything as macros.
+*/
+#define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8)
+#define sqlite3_mutex_free(X)
+#define sqlite3_mutex_enter(X)
+#define sqlite3_mutex_try(X) SQLITE_OK
+#define sqlite3_mutex_leave(X)
+#define sqlite3_mutex_held(X) 1
+#define sqlite3_mutex_notheld(X) 1
+#endif
+
+#endif /* SQLITE_MUTEX_APPDEF */
diff --git a/ext/pdo_sqlite/sqlite/src/mutex_unix.c b/ext/pdo_sqlite/sqlite/src/mutex_unix.c
new file mode 100644
index 0000000000..e8c0da6a2d
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/mutex_unix.c
@@ -0,0 +1,298 @@
+/*
+** 2007 August 28
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file contains the C functions that implement mutexes for pthreads
+**
+** $Id$
+*/
+#include "sqliteInt.h"
+
+/*
+** The code in this file is only used if we are compiling threadsafe
+** under unix with pthreads.
+**
+** Note that this implementation requires a version of pthreads that
+** supports recursive mutexes.
+*/
+#ifdef SQLITE_MUTEX_PTHREADS
+
+#include <pthread.h>
+
+
+/*
+** Each recursive mutex is an instance of the following structure.
+*/
+struct sqlite3_mutex {
+ pthread_mutex_t mutex; /* Mutex controlling the lock */
+ int id; /* Mutex type */
+ int nRef; /* Number of entrances */
+ pthread_t owner; /* Thread that is within this mutex */
+#ifdef SQLITE_DEBUG
+ int trace; /* True to trace changes */
+#endif
+};
+
+/*
+** The sqlite3_mutex_alloc() routine allocates a new
+** mutex and returns a pointer to it. If it returns NULL
+** that means that a mutex could not be allocated. SQLite
+** will unwind its stack and return an error. The argument
+** to sqlite3_mutex_alloc() is one of these integer constants:
+**
+** <ul>
+** <li> SQLITE_MUTEX_FAST
+** <li> SQLITE_MUTEX_RECURSIVE
+** <li> SQLITE_MUTEX_STATIC_MASTER
+** <li> SQLITE_MUTEX_STATIC_MEM
+** <li> SQLITE_MUTEX_STATIC_MEM2
+** <li> SQLITE_MUTEX_STATIC_PRNG
+** <li> SQLITE_MUTEX_STATIC_LRU
+** </ul>
+**
+** The first two constants cause sqlite3_mutex_alloc() to create
+** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
+** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
+** The mutex implementation does not need to make a distinction
+** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
+** not want to. But SQLite will only request a recursive mutex in
+** cases where it really needs one. If a faster non-recursive mutex
+** implementation is available on the host platform, the mutex subsystem
+** might return such a mutex in response to SQLITE_MUTEX_FAST.
+**
+** The other allowed parameters to sqlite3_mutex_alloc() each return
+** a pointer to a static preexisting mutex. Three static mutexes are
+** used by the current version of SQLite. Future versions of SQLite
+** may add additional static mutexes. Static mutexes are for internal
+** use by SQLite only. Applications that use SQLite mutexes should
+** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
+** SQLITE_MUTEX_RECURSIVE.
+**
+** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
+** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
+** returns a different mutex on every call. But for the static
+** mutex types, the same mutex is returned on every call that has
+** the same type number.
+*/
+sqlite3_mutex *sqlite3_mutex_alloc(int iType){
+ static sqlite3_mutex staticMutexes[] = {
+ { PTHREAD_MUTEX_INITIALIZER, },
+ { PTHREAD_MUTEX_INITIALIZER, },
+ { PTHREAD_MUTEX_INITIALIZER, },
+ { PTHREAD_MUTEX_INITIALIZER, },
+ { PTHREAD_MUTEX_INITIALIZER, },
+ };
+ sqlite3_mutex *p;
+ switch( iType ){
+ case SQLITE_MUTEX_RECURSIVE: {
+ p = sqlite3MallocZero( sizeof(*p) );
+ if( p ){
+#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
+ /* If recursive mutexes are not available, we will have to
+ ** build our own. See below. */
+ pthread_mutex_init(&p->mutex, 0);
+#else
+ /* Use a recursive mutex if it is available */
+ pthread_mutexattr_t recursiveAttr;
+ pthread_mutexattr_init(&recursiveAttr);
+ pthread_mutexattr_settype(&recursiveAttr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&p->mutex, &recursiveAttr);
+ pthread_mutexattr_destroy(&recursiveAttr);
+#endif
+ p->id = iType;
+ }
+ break;
+ }
+ case SQLITE_MUTEX_FAST: {
+ p = sqlite3MallocZero( sizeof(*p) );
+ if( p ){
+ p->id = iType;
+ pthread_mutex_init(&p->mutex, 0);
+ }
+ break;
+ }
+ default: {
+ assert( iType-2 >= 0 );
+ assert( iType-2 < sizeof(staticMutexes)/sizeof(staticMutexes[0]) );
+ p = &staticMutexes[iType-2];
+ p->id = iType;
+ break;
+ }
+ }
+ return p;
+}
+
+
+/*
+** This routine deallocates a previously
+** allocated mutex. SQLite is careful to deallocate every
+** mutex that it allocates.
+*/
+void sqlite3_mutex_free(sqlite3_mutex *p){
+ assert( p );
+ assert( p->nRef==0 );
+ assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
+ pthread_mutex_destroy(&p->mutex);
+ sqlite3_free(p);
+}
+
+/*
+** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
+** to enter a mutex. If another thread is already within the mutex,
+** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
+** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK
+** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can
+** be entered multiple times by the same thread. In such cases the,
+** mutex must be exited an equal number of times before another thread
+** can enter. If the same thread tries to enter any other kind of mutex
+** more than once, the behavior is undefined.
+*/
+void sqlite3_mutex_enter(sqlite3_mutex *p){
+ assert( p );
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
+
+#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
+ /* If recursive mutexes are not available, then we have to grow
+ ** our own. This implementation assumes that pthread_equal()
+ ** is atomic - that it cannot be deceived into thinking self
+ ** and p->owner are equal if p->owner changes between two values
+ ** that are not equal to self while the comparison is taking place.
+ ** This implementation also assumes a coherent cache - that
+ ** separate processes cannot read different values from the same
+ ** address at the same time. If either of these two conditions
+ ** are not met, then the mutexes will fail and problems will result.
+ */
+ {
+ pthread_t self = pthread_self();
+ if( p->nRef>0 && pthread_equal(p->owner, self) ){
+ p->nRef++;
+ }else{
+ pthread_mutex_lock(&p->mutex);
+ assert( p->nRef==0 );
+ p->owner = self;
+ p->nRef = 1;
+ }
+ }
+#else
+ /* Use the built-in recursive mutexes if they are available.
+ */
+ pthread_mutex_lock(&p->mutex);
+ p->owner = pthread_self();
+ p->nRef++;
+#endif
+
+#ifdef SQLITE_DEBUG
+ if( p->trace ){
+ printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+ }
+#endif
+}
+int sqlite3_mutex_try(sqlite3_mutex *p){
+ int rc;
+ assert( p );
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
+
+#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
+ /* If recursive mutexes are not available, then we have to grow
+ ** our own. This implementation assumes that pthread_equal()
+ ** is atomic - that it cannot be deceived into thinking self
+ ** and p->owner are equal if p->owner changes between two values
+ ** that are not equal to self while the comparison is taking place.
+ ** This implementation also assumes a coherent cache - that
+ ** separate processes cannot read different values from the same
+ ** address at the same time. If either of these two conditions
+ ** are not met, then the mutexes will fail and problems will result.
+ */
+ {
+ pthread_t self = pthread_self();
+ if( p->nRef>0 && pthread_equal(p->owner, self) ){
+ p->nRef++;
+ rc = SQLITE_OK;
+ }else if( pthread_mutex_lock(&p->mutex)==0 ){
+ assert( p->nRef==0 );
+ p->owner = self;
+ p->nRef = 1;
+ rc = SQLITE_OK;
+ }else{
+ rc = SQLITE_BUSY;
+ }
+ }
+#else
+ /* Use the built-in recursive mutexes if they are available.
+ */
+ if( pthread_mutex_trylock(&p->mutex)==0 ){
+ p->owner = pthread_self();
+ p->nRef++;
+ rc = SQLITE_OK;
+ }else{
+ rc = SQLITE_BUSY;
+ }
+#endif
+
+#ifdef SQLITE_DEBUG
+ if( rc==SQLITE_OK && p->trace ){
+ printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+ }
+#endif
+ return rc;
+}
+
+/*
+** The sqlite3_mutex_leave() routine exits a mutex that was
+** previously entered by the same thread. The behavior
+** is undefined if the mutex is not currently entered or
+** is not currently allocated. SQLite will never do either.
+*/
+void sqlite3_mutex_leave(sqlite3_mutex *p){
+ assert( p );
+ assert( sqlite3_mutex_held(p) );
+ p->nRef--;
+ assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
+
+#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
+ if( p->nRef==0 ){
+ pthread_mutex_unlock(&p->mutex);
+ }
+#else
+ pthread_mutex_unlock(&p->mutex);
+#endif
+
+#ifdef SQLITE_DEBUG
+ if( p->trace ){
+ printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+ }
+#endif
+}
+
+/*
+** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
+** intended for use only inside assert() statements. On some platforms,
+** there might be race conditions that can cause these routines to
+** deliver incorrect results. In particular, if pthread_equal() is
+** not an atomic operation, then these routines might delivery
+** incorrect results. On most platforms, pthread_equal() is a
+** comparison of two integers and is therefore atomic. But we are
+** told that HPUX is not such a platform. If so, then these routines
+** will not always work correctly on HPUX.
+**
+** On those platforms where pthread_equal() is not atomic, SQLite
+** should be compiled without -DSQLITE_DEBUG and with -DNDEBUG to
+** make sure no assert() statements are evaluated and hence these
+** routines are never called.
+*/
+#ifndef NDEBUG
+int sqlite3_mutex_held(sqlite3_mutex *p){
+ return p==0 || (p->nRef!=0 && pthread_equal(p->owner, pthread_self()));
+}
+int sqlite3_mutex_notheld(sqlite3_mutex *p){
+ return p==0 || p->nRef==0 || pthread_equal(p->owner, pthread_self())==0;
+}
+#endif
+#endif /* SQLITE_MUTEX_PTHREAD */
diff --git a/ext/pdo_sqlite/sqlite/src/mutex_w32.c b/ext/pdo_sqlite/sqlite/src/mutex_w32.c
new file mode 100644
index 0000000000..9843c5222d
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/mutex_w32.c
@@ -0,0 +1,219 @@
+/*
+** 2007 August 14
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file contains the C functions that implement mutexes for win32
+**
+** $Id$
+*/
+#include "sqliteInt.h"
+
+/*
+** The code in this file is only used if we are compiling multithreaded
+** on a win32 system.
+*/
+#ifdef SQLITE_MUTEX_W32
+
+/*
+** Each recursive mutex is an instance of the following structure.
+*/
+struct sqlite3_mutex {
+ CRITICAL_SECTION mutex; /* Mutex controlling the lock */
+ int id; /* Mutex type */
+ int nRef; /* Number of enterances */
+ DWORD owner; /* Thread holding this mutex */
+};
+
+/*
+** 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
+** API as long as we don't call it win running Win95/98/ME. A call to
+** this routine is used to determine if the host is Win95/98/ME or
+** WinNT/2K/XP so that we will know whether or not we can safely call
+** the LockFileEx() API.
+*/
+#if OS_WINCE
+# define mutexIsNT() (1)
+#else
+ static int mutexIsNT(void){
+ static int osType = 0;
+ if( osType==0 ){
+ OSVERSIONINFO sInfo;
+ sInfo.dwOSVersionInfoSize = sizeof(sInfo);
+ GetVersionEx(&sInfo);
+ osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
+ }
+ return osType==2;
+ }
+#endif /* OS_WINCE */
+
+
+/*
+** The sqlite3_mutex_alloc() routine allocates a new
+** mutex and returns a pointer to it. If it returns NULL
+** that means that a mutex could not be allocated. SQLite
+** will unwind its stack and return an error. The argument
+** to sqlite3_mutex_alloc() is one of these integer constants:
+**
+** <ul>
+** <li> SQLITE_MUTEX_FAST 0
+** <li> SQLITE_MUTEX_RECURSIVE 1
+** <li> SQLITE_MUTEX_STATIC_MASTER 2
+** <li> SQLITE_MUTEX_STATIC_MEM 3
+** <li> SQLITE_MUTEX_STATIC_PRNG 4
+** </ul>
+**
+** The first two constants cause sqlite3_mutex_alloc() to create
+** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
+** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
+** The mutex implementation does not need to make a distinction
+** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
+** not want to. But SQLite will only request a recursive mutex in
+** cases where it really needs one. If a faster non-recursive mutex
+** implementation is available on the host platform, the mutex subsystem
+** might return such a mutex in response to SQLITE_MUTEX_FAST.
+**
+** The other allowed parameters to sqlite3_mutex_alloc() each return
+** a pointer to a static preexisting mutex. Three static mutexes are
+** used by the current version of SQLite. Future versions of SQLite
+** may add additional static mutexes. Static mutexes are for internal
+** use by SQLite only. Applications that use SQLite mutexes should
+** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
+** SQLITE_MUTEX_RECURSIVE.
+**
+** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
+** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
+** returns a different mutex on every call. But for the static
+** mutex types, the same mutex is returned on every call that has
+** the same type number.
+*/
+sqlite3_mutex *sqlite3_mutex_alloc(int iType){
+ sqlite3_mutex *p;
+
+ switch( iType ){
+ case SQLITE_MUTEX_FAST:
+ case SQLITE_MUTEX_RECURSIVE: {
+ p = sqlite3MallocZero( sizeof(*p) );
+ if( p ){
+ p->id = iType;
+ InitializeCriticalSection(&p->mutex);
+ }
+ break;
+ }
+ default: {
+ static sqlite3_mutex staticMutexes[5];
+ static int isInit = 0;
+ while( !isInit ){
+ static long lock = 0;
+ if( InterlockedIncrement(&lock)==1 ){
+ int i;
+ for(i=0; i<sizeof(staticMutexes)/sizeof(staticMutexes[0]); i++){
+ InitializeCriticalSection(&staticMutexes[i].mutex);
+ }
+ isInit = 1;
+ }else{
+ Sleep(1);
+ }
+ }
+ assert( iType-2 >= 0 );
+ assert( iType-2 < sizeof(staticMutexes)/sizeof(staticMutexes[0]) );
+ p = &staticMutexes[iType-2];
+ p->id = iType;
+ break;
+ }
+ }
+ return p;
+}
+
+
+/*
+** This routine deallocates a previously
+** allocated mutex. SQLite is careful to deallocate every
+** mutex that it allocates.
+*/
+void sqlite3_mutex_free(sqlite3_mutex *p){
+ assert( p );
+ assert( p->nRef==0 );
+ assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
+ DeleteCriticalSection(&p->mutex);
+ sqlite3_free(p);
+}
+
+/*
+** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
+** to enter a mutex. If another thread is already within the mutex,
+** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
+** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK
+** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can
+** be entered multiple times by the same thread. In such cases the,
+** mutex must be exited an equal number of times before another thread
+** can enter. If the same thread tries to enter any other kind of mutex
+** more than once, the behavior is undefined.
+*/
+void sqlite3_mutex_enter(sqlite3_mutex *p){
+ assert( p );
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
+ EnterCriticalSection(&p->mutex);
+ p->owner = GetCurrentThreadId();
+ p->nRef++;
+}
+int sqlite3_mutex_try(sqlite3_mutex *p){
+ int rc = SQLITE_BUSY;
+ assert( p );
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || sqlite3_mutex_notheld(p) );
+ /*
+ ** The sqlite3_mutex_try() routine is very rarely used, and when it
+ ** is used it is merely an optimization. So it is OK for it to always
+ ** fail.
+ **
+ ** The TryEnterCriticalSection() interface is only available on WinNT.
+ ** And some windows compilers complain if you try to use it without
+ ** first doing some #defines that prevent SQLite from building on Win98.
+ ** For that reason, we will omit this optimization for now. See
+ ** ticket #2685.
+ */
+#if 0
+ if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){
+ p->owner = GetCurrentThreadId();
+ p->nRef++;
+ rc = SQLITE_OK;
+ }
+#endif
+ return rc;
+}
+
+/*
+** The sqlite3_mutex_leave() routine exits a mutex that was
+** previously entered by the same thread. The behavior
+** is undefined if the mutex is not currently entered or
+** is not currently allocated. SQLite will never do either.
+*/
+void sqlite3_mutex_leave(sqlite3_mutex *p){
+ assert( p->nRef>0 );
+ assert( p->owner==GetCurrentThreadId() );
+ p->nRef--;
+ assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
+ LeaveCriticalSection(&p->mutex);
+}
+
+/*
+** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
+** intended for use only inside assert() statements.
+*/
+int sqlite3_mutex_held(sqlite3_mutex *p){
+ return p==0 || (p->nRef!=0 && p->owner==GetCurrentThreadId());
+}
+int sqlite3_mutex_notheld(sqlite3_mutex *p){
+ return p==0 || p->nRef==0 || p->owner!=GetCurrentThreadId();
+}
+#endif /* SQLITE_MUTEX_W32 */
diff --git a/ext/pdo_sqlite/sqlite/src/opcodes.c b/ext/pdo_sqlite/sqlite/src/opcodes.c
index 734d1a5409..eadb3a16bc 100644
--- a/ext/pdo_sqlite/sqlite/src/opcodes.c
+++ b/ext/pdo_sqlite/sqlite/src/opcodes.c
@@ -1,137 +1,151 @@
/* Automatically generated. Do not edit */
/* See the mkopcodec.awk script for details. */
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
-const char *const sqlite3OpcodeNames[] = { "?",
- /* 1 */ "MemLoad",
- /* 2 */ "Column",
- /* 3 */ "SetCookie",
- /* 4 */ "IfMemPos",
- /* 5 */ "MoveGt",
- /* 6 */ "AggFocus",
- /* 7 */ "RowKey",
- /* 8 */ "IdxRecno",
- /* 9 */ "AggNext",
- /* 10 */ "OpenWrite",
- /* 11 */ "If",
- /* 12 */ "PutStrKey",
- /* 13 */ "Pop",
- /* 14 */ "SortPut",
- /* 15 */ "AggContextPush",
- /* 16 */ "CollSeq",
- /* 17 */ "OpenRead",
- /* 18 */ "Expire",
- /* 19 */ "SortReset",
- /* 20 */ "AutoCommit",
- /* 21 */ "Sort",
- /* 22 */ "ListRewind",
- /* 23 */ "IntegrityCk",
- /* 24 */ "Function",
- /* 25 */ "Noop",
- /* 26 */ "Return",
- /* 27 */ "Variable",
- /* 28 */ "String",
- /* 29 */ "ParseSchema",
- /* 30 */ "PutIntKey",
- /* 31 */ "AggFunc",
- /* 32 */ "Close",
- /* 33 */ "ListWrite",
- /* 34 */ "CreateIndex",
- /* 35 */ "IsUnique",
- /* 36 */ "IdxIsNull",
- /* 37 */ "NotFound",
- /* 38 */ "MustBeInt",
- /* 39 */ "Halt",
- /* 40 */ "IdxLT",
- /* 41 */ "AddImm",
- /* 42 */ "Statement",
- /* 43 */ "RowData",
- /* 44 */ "MemMax",
- /* 45 */ "Push",
- /* 46 */ "KeyAsData",
- /* 47 */ "NotExists",
- /* 48 */ "OpenTemp",
- /* 49 */ "MemIncr",
- /* 50 */ "Gosub",
- /* 51 */ "AggSet",
- /* 52 */ "Integer",
- /* 53 */ "SortNext",
- /* 54 */ "Prev",
- /* 55 */ "CreateTable",
- /* 56 */ "Last",
- /* 57 */ "ResetCount",
- /* 58 */ "Callback",
- /* 59 */ "ContextPush",
- /* 60 */ "DropTrigger",
- /* 61 */ "DropIndex",
- /* 62 */ "FullKey",
- /* 63 */ "IdxGE",
- /* 64 */ "Or",
- /* 65 */ "And",
- /* 66 */ "Not",
- /* 67 */ "IdxDelete",
- /* 68 */ "Vacuum",
- /* 69 */ "MoveLe",
- /* 70 */ "IsNull",
- /* 71 */ "NotNull",
- /* 72 */ "Ne",
- /* 73 */ "Eq",
- /* 74 */ "Gt",
- /* 75 */ "Le",
- /* 76 */ "Lt",
- /* 77 */ "Ge",
- /* 78 */ "IfNot",
- /* 79 */ "BitAnd",
- /* 80 */ "BitOr",
- /* 81 */ "ShiftLeft",
- /* 82 */ "ShiftRight",
- /* 83 */ "Add",
- /* 84 */ "Subtract",
- /* 85 */ "Multiply",
- /* 86 */ "Divide",
- /* 87 */ "Remainder",
- /* 88 */ "Concat",
- /* 89 */ "Negative",
- /* 90 */ "DropTable",
- /* 91 */ "BitNot",
- /* 92 */ "String8",
- /* 93 */ "MakeRecord",
- /* 94 */ "Delete",
- /* 95 */ "AggContextPop",
- /* 96 */ "ListRead",
- /* 97 */ "ListReset",
- /* 98 */ "Dup",
- /* 99 */ "Goto",
- /* 100 */ "Clear",
- /* 101 */ "IdxGT",
- /* 102 */ "MoveLt",
- /* 103 */ "VerifyCookie",
- /* 104 */ "Pull",
- /* 105 */ "SetNumColumns",
- /* 106 */ "AbsValue",
- /* 107 */ "Transaction",
- /* 108 */ "AggGet",
- /* 109 */ "ContextPop",
- /* 110 */ "Next",
- /* 111 */ "AggInit",
- /* 112 */ "Distinct",
- /* 113 */ "NewRecno",
- /* 114 */ "AggReset",
- /* 115 */ "Destroy",
- /* 116 */ "ReadCookie",
- /* 117 */ "ForceInt",
- /* 118 */ "Recno",
- /* 119 */ "OpenPseudo",
- /* 120 */ "Blob",
- /* 121 */ "MemStore",
- /* 122 */ "Rewind",
- /* 123 */ "MoveGe",
- /* 124 */ "IdxPut",
- /* 125 */ "Found",
- /* 126 */ "NullRow",
- /* 127 */ "NotUsed_127",
- /* 128 */ "NotUsed_128",
- /* 129 */ "NotUsed_129",
- /* 130 */ "Real",
- /* 131 */ "HexBlob",
-};
+const char *sqlite3OpcodeName(int i){
+ static const char *const azName[] = { "?",
+ /* 1 */ "VNext",
+ /* 2 */ "Column",
+ /* 3 */ "SetCookie",
+ /* 4 */ "Sequence",
+ /* 5 */ "MoveGt",
+ /* 6 */ "RowKey",
+ /* 7 */ "SCopy",
+ /* 8 */ "OpenWrite",
+ /* 9 */ "If",
+ /* 10 */ "VRowid",
+ /* 11 */ "CollSeq",
+ /* 12 */ "OpenRead",
+ /* 13 */ "Expire",
+ /* 14 */ "AutoCommit",
+ /* 15 */ "IntegrityCk",
+ /* 16 */ "Not",
+ /* 17 */ "Sort",
+ /* 18 */ "Copy",
+ /* 19 */ "Trace",
+ /* 20 */ "Function",
+ /* 21 */ "IfNeg",
+ /* 22 */ "Noop",
+ /* 23 */ "Return",
+ /* 24 */ "NewRowid",
+ /* 25 */ "Variable",
+ /* 26 */ "String",
+ /* 27 */ "RealAffinity",
+ /* 28 */ "VRename",
+ /* 29 */ "ParseSchema",
+ /* 30 */ "VOpen",
+ /* 31 */ "Close",
+ /* 32 */ "CreateIndex",
+ /* 33 */ "IsUnique",
+ /* 34 */ "NotFound",
+ /* 35 */ "Int64",
+ /* 36 */ "MustBeInt",
+ /* 37 */ "Halt",
+ /* 38 */ "Rowid",
+ /* 39 */ "IdxLT",
+ /* 40 */ "AddImm",
+ /* 41 */ "Statement",
+ /* 42 */ "RowData",
+ /* 43 */ "MemMax",
+ /* 44 */ "NotExists",
+ /* 45 */ "Gosub",
+ /* 46 */ "Integer",
+ /* 47 */ "Prev",
+ /* 48 */ "VColumn",
+ /* 49 */ "CreateTable",
+ /* 50 */ "Last",
+ /* 51 */ "IncrVacuum",
+ /* 52 */ "IdxRowid",
+ /* 53 */ "ResetCount",
+ /* 54 */ "FifoWrite",
+ /* 55 */ "ContextPush",
+ /* 56 */ "DropTrigger",
+ /* 57 */ "DropIndex",
+ /* 58 */ "IdxGE",
+ /* 59 */ "IdxDelete",
+ /* 60 */ "Or",
+ /* 61 */ "And",
+ /* 62 */ "Vacuum",
+ /* 63 */ "MoveLe",
+ /* 64 */ "IfNot",
+ /* 65 */ "IsNull",
+ /* 66 */ "NotNull",
+ /* 67 */ "Ne",
+ /* 68 */ "Eq",
+ /* 69 */ "Gt",
+ /* 70 */ "Le",
+ /* 71 */ "Lt",
+ /* 72 */ "Ge",
+ /* 73 */ "DropTable",
+ /* 74 */ "BitAnd",
+ /* 75 */ "BitOr",
+ /* 76 */ "ShiftLeft",
+ /* 77 */ "ShiftRight",
+ /* 78 */ "Add",
+ /* 79 */ "Subtract",
+ /* 80 */ "Multiply",
+ /* 81 */ "Divide",
+ /* 82 */ "Remainder",
+ /* 83 */ "Concat",
+ /* 84 */ "MakeRecord",
+ /* 85 */ "ResultRow",
+ /* 86 */ "Delete",
+ /* 87 */ "BitNot",
+ /* 88 */ "String8",
+ /* 89 */ "AggFinal",
+ /* 90 */ "Goto",
+ /* 91 */ "TableLock",
+ /* 92 */ "FifoRead",
+ /* 93 */ "Clear",
+ /* 94 */ "MoveLt",
+ /* 95 */ "VerifyCookie",
+ /* 96 */ "AggStep",
+ /* 97 */ "SetNumColumns",
+ /* 98 */ "Transaction",
+ /* 99 */ "VFilter",
+ /* 100 */ "VDestroy",
+ /* 101 */ "ContextPop",
+ /* 102 */ "Next",
+ /* 103 */ "IdxInsert",
+ /* 104 */ "Insert",
+ /* 105 */ "Destroy",
+ /* 106 */ "ReadCookie",
+ /* 107 */ "ForceInt",
+ /* 108 */ "LoadAnalysis",
+ /* 109 */ "Explain",
+ /* 110 */ "OpenPseudo",
+ /* 111 */ "OpenEphemeral",
+ /* 112 */ "Null",
+ /* 113 */ "Move",
+ /* 114 */ "Blob",
+ /* 115 */ "Rewind",
+ /* 116 */ "MoveGe",
+ /* 117 */ "VBegin",
+ /* 118 */ "VUpdate",
+ /* 119 */ "IfZero",
+ /* 120 */ "VCreate",
+ /* 121 */ "Found",
+ /* 122 */ "IfPos",
+ /* 123 */ "NullRow",
+ /* 124 */ "NotUsed_124",
+ /* 125 */ "Real",
+ /* 126 */ "NotUsed_126",
+ /* 127 */ "NotUsed_127",
+ /* 128 */ "NotUsed_128",
+ /* 129 */ "NotUsed_129",
+ /* 130 */ "NotUsed_130",
+ /* 131 */ "NotUsed_131",
+ /* 132 */ "NotUsed_132",
+ /* 133 */ "NotUsed_133",
+ /* 134 */ "NotUsed_134",
+ /* 135 */ "NotUsed_135",
+ /* 136 */ "NotUsed_136",
+ /* 137 */ "NotUsed_137",
+ /* 138 */ "ToText",
+ /* 139 */ "ToBlob",
+ /* 140 */ "ToNumeric",
+ /* 141 */ "ToInt",
+ /* 142 */ "ToReal",
+ };
+ return azName[i];
+}
#endif
diff --git a/ext/pdo_sqlite/sqlite/src/opcodes.h b/ext/pdo_sqlite/sqlite/src/opcodes.h
index c113f8f1c1..4c6597555b 100644
--- a/ext/pdo_sqlite/sqlite/src/opcodes.h
+++ b/ext/pdo_sqlite/sqlite/src/opcodes.h
@@ -1,49 +1,48 @@
/* Automatically generated. Do not edit */
/* See the mkopcodeh.awk script for details */
-#define OP_MemLoad 1
-#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_VNext 1
+#define OP_Column 2
+#define OP_SetCookie 3
+#define OP_Real 125 /* same as TK_FLOAT */
+#define OP_Sequence 4
+#define OP_MoveGt 5
+#define OP_Ge 72 /* same as TK_GE */
+#define OP_RowKey 6
+#define OP_SCopy 7
+#define OP_Eq 68 /* same as TK_EQ */
+#define OP_OpenWrite 8
+#define OP_NotNull 66 /* same as TK_NOTNULL */
+#define OP_If 9
+#define OP_ToInt 141 /* same as TK_TO_INT */
#define OP_String8 88 /* same as TK_STRING */
-#define OP_Pop 11
-#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_VRowid 10
+#define OP_CollSeq 11
+#define OP_OpenRead 12
+#define OP_Expire 13
+#define OP_AutoCommit 14
+#define OP_Gt 69 /* same as TK_GT */
+#define OP_IntegrityCk 15
+#define OP_Sort 17
+#define OP_Copy 18
+#define OP_Trace 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_IfNeg 21
+#define OP_And 61 /* same as TK_AND */
+#define OP_Subtract 79 /* same as TK_MINUS */
+#define OP_Noop 22
+#define OP_Return 23
+#define OP_Remainder 82 /* same as TK_REM */
+#define OP_NewRowid 24
+#define OP_Multiply 80 /* same as TK_STAR */
#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_VRename 28
+#define OP_ParseSchema 29
+#define OP_VOpen 30
+#define OP_Close 31
+#define OP_CreateIndex 32
+#define OP_IsUnique 33
#define OP_NotFound 34
#define OP_Int64 35
#define OP_MustBeInt 36
@@ -54,108 +53,125 @@
#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_Or 60 /* same as TK_OR */
+#define OP_NotExists 44
+#define OP_Gosub 45
+#define OP_Divide 81 /* same as TK_SLASH */
+#define OP_Integer 46
+#define OP_ToNumeric 140 /* same as TK_TO_NUMERIC*/
+#define OP_Prev 47
+#define OP_Concat 83 /* same as TK_CONCAT */
+#define OP_BitAnd 74 /* same as TK_BITAND */
+#define OP_VColumn 48
+#define OP_CreateTable 49
+#define OP_Last 50
+#define OP_IsNull 65 /* same as TK_ISNULL */
+#define OP_IncrVacuum 51
+#define OP_IdxRowid 52
+#define OP_ShiftRight 77 /* same as TK_RSHIFT */
+#define OP_ResetCount 53
+#define OP_FifoWrite 54
+#define OP_ContextPush 55
+#define OP_DropTrigger 56
+#define OP_DropIndex 57
+#define OP_IdxGE 58
+#define OP_IdxDelete 59
+#define OP_Vacuum 62
+#define OP_MoveLe 63
+#define OP_IfNot 64
+#define OP_DropTable 73
+#define OP_MakeRecord 84
+#define OP_ToBlob 139 /* same as TK_TO_BLOB */
+#define OP_ResultRow 85
+#define OP_Delete 86
+#define OP_AggFinal 89
+#define OP_ShiftLeft 76 /* same as TK_LSHIFT */
+#define OP_Goto 90
+#define OP_TableLock 91
+#define OP_FifoRead 92
+#define OP_Clear 93
+#define OP_MoveLt 94
+#define OP_Le 70 /* same as TK_LE */
+#define OP_VerifyCookie 95
+#define OP_AggStep 96
+#define OP_ToText 138 /* 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_ToReal 142 /* same as TK_TO_REAL */
+#define OP_SetNumColumns 97
+#define OP_Transaction 98
+#define OP_VFilter 99
+#define OP_Ne 67 /* same as TK_NE */
+#define OP_VDestroy 100
+#define OP_ContextPop 101
+#define OP_BitOr 75 /* same as TK_BITOR */
+#define OP_Next 102
+#define OP_IdxInsert 103
+#define OP_Lt 71 /* same as TK_LT */
+#define OP_Insert 104
+#define OP_Destroy 105
+#define OP_ReadCookie 106
+#define OP_ForceInt 107
+#define OP_LoadAnalysis 108
+#define OP_Explain 109
+#define OP_OpenPseudo 110
+#define OP_OpenEphemeral 111
+#define OP_Null 112
+#define OP_Move 113
+#define OP_Blob 114
+#define OP_Add 78 /* same as TK_PLUS */
+#define OP_Rewind 115
+#define OP_MoveGe 116
+#define OP_VBegin 117
+#define OP_VUpdate 118
+#define OP_IfZero 119
#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
+#define OP_VCreate 120
+#define OP_Found 121
+#define OP_IfPos 122
+#define OP_NullRow 123
/* The following opcode values are never used */
+#define OP_NotUsed_124 124
+#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_133 133
+#define OP_NotUsed_134 134
+#define OP_NotUsed_135 135
#define OP_NotUsed_136 136
#define OP_NotUsed_137 137
-#define OP_NotUsed_138 138
-/* 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
+
+/* Properties such as "out2" or "jump" that are specified in
+** comments following the "case" for each opcode in the vdbe.c
+** are encoded into bitvectors as follows:
+*/
+#define OPFLG_JUMP 0x0001 /* jump: P2 holds jmp target */
+#define OPFLG_OUT2_PRERELEASE 0x0002 /* out2-prerelease: */
+#define OPFLG_IN1 0x0004 /* in1: P1 is an input */
+#define OPFLG_IN2 0x0008 /* in2: P2 is an input */
+#define OPFLG_IN3 0x0010 /* in3: P3 is an input */
+#define OPFLG_OUT3 0x0020 /* out3: P3 is an output */
+#define OPFLG_INITIALIZER {\
+/* 0 */ 0x00, 0x01, 0x00, 0x10, 0x02, 0x11, 0x02, 0x00,\
+/* 8 */ 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 16 */ 0x04, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,\
+/* 24 */ 0x02, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00,\
+/* 32 */ 0x02, 0x11, 0x11, 0x02, 0x05, 0x00, 0x02, 0x11,\
+/* 40 */ 0x04, 0x00, 0x02, 0x0c, 0x11, 0x01, 0x02, 0x01,\
+/* 48 */ 0x00, 0x02, 0x01, 0x01, 0x02, 0x00, 0x04, 0x00,\
+/* 56 */ 0x00, 0x00, 0x11, 0x08, 0x2c, 0x2c, 0x00, 0x11,\
+/* 64 */ 0x05, 0x05, 0x05, 0x15, 0x15, 0x15, 0x15, 0x15,\
+/* 72 */ 0x15, 0x00, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,\
+/* 80 */ 0x2c, 0x2c, 0x2c, 0x2c, 0x00, 0x00, 0x00, 0x04,\
+/* 88 */ 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x11, 0x00,\
+/* 96 */ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x08,\
+/* 104 */ 0x00, 0x02, 0x02, 0x05, 0x00, 0x00, 0x00, 0x00,\
+/* 112 */ 0x02, 0x00, 0x02, 0x01, 0x11, 0x00, 0x00, 0x05,\
+/* 120 */ 0x00, 0x11, 0x05, 0x00, 0x00, 0x02, 0x00, 0x00,\
+/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 136 */ 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04,}
diff --git a/ext/pdo_sqlite/sqlite/src/os.c b/ext/pdo_sqlite/sqlite/src/os.c
index ec482fe0e7..57e2d0fdd0 100644
--- a/ext/pdo_sqlite/sqlite/src/os.c
+++ b/ext/pdo_sqlite/sqlite/src/os.c
@@ -1,4 +1,4 @@
-/*
+ /*
** 2005 November 29
**
** The author disclaims copyright to this source code. In place of
@@ -15,78 +15,253 @@
*/
#define _SQLITE_OS_C_ 1
#include "sqliteInt.h"
-#include "os.h"
+#undef _SQLITE_OS_C_
+
+/*
+** The default SQLite sqlite3_vfs implementations do not allocate
+** memory (actually, os_unix.c allocates a small amount of memory
+** from within OsOpen()), but some third-party implementations may.
+** So we test the effects of a malloc() failing and the sqlite3OsXXX()
+** function returning SQLITE_IOERR_NOMEM using the DO_OS_MALLOC_TEST macro.
+**
+** The following functions are instrumented for malloc() failure
+** testing:
+**
+** sqlite3OsOpen()
+** sqlite3OsRead()
+** sqlite3OsWrite()
+** sqlite3OsSync()
+** sqlite3OsLock()
+**
+*/
+#ifdef SQLITE_TEST
+ #define DO_OS_MALLOC_TEST if (1) { \
+ void *pTstAlloc = sqlite3_malloc(10); \
+ if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \
+ sqlite3_free(pTstAlloc); \
+ }
+#else
+ #define DO_OS_MALLOC_TEST
+#endif
/*
** The following routines are convenience wrappers around methods
-** of the OsFile object. This is mostly just syntactic sugar. All
+** of the sqlite3_file 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 sqlite3OsClose(sqlite3_file *pId){
+ int rc = SQLITE_OK;
+ if( pId->pMethods ){
+ rc = pId->pMethods->xClose(pId);
+ pId->pMethods = 0;
}
+ return rc;
}
-int sqlite3OsOpenDirectory(OsFile *id, const char *zName){
- return id->pMethod->xOpenDirectory(id, zName);
+int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){
+ DO_OS_MALLOC_TEST;
+ return id->pMethods->xRead(id, pBuf, amt, offset);
}
-int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
- return id->pMethod->xRead(id, pBuf, amt);
+int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){
+ DO_OS_MALLOC_TEST;
+ return id->pMethods->xWrite(id, pBuf, amt, offset);
}
-int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
- return id->pMethod->xWrite(id, pBuf, amt);
+int sqlite3OsTruncate(sqlite3_file *id, i64 size){
+ return id->pMethods->xTruncate(id, size);
}
-int sqlite3OsSeek(OsFile *id, i64 offset){
- return id->pMethod->xSeek(id, offset);
+int sqlite3OsSync(sqlite3_file *id, int flags){
+ DO_OS_MALLOC_TEST;
+ return id->pMethods->xSync(id, flags);
}
-int sqlite3OsTruncate(OsFile *id, i64 size){
- return id->pMethod->xTruncate(id, size);
+int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
+ return id->pMethods->xFileSize(id, pSize);
}
-int sqlite3OsSync(OsFile *id, int fullsync){
- return id->pMethod->xSync(id, fullsync);
+int sqlite3OsLock(sqlite3_file *id, int lockType){
+ DO_OS_MALLOC_TEST;
+ return id->pMethods->xLock(id, lockType);
}
-void sqlite3OsSetFullSync(OsFile *id, int value){
- id->pMethod->xSetFullSync(id, value);
+int sqlite3OsUnlock(sqlite3_file *id, int lockType){
+ return id->pMethods->xUnlock(id, lockType);
}
-#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);
+int sqlite3OsCheckReservedLock(sqlite3_file *id){
+ return id->pMethods->xCheckReservedLock(id);
}
-#endif
-int sqlite3OsFileSize(OsFile *id, i64 *pSize){
- return id->pMethod->xFileSize(id, pSize);
+int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
+ return id->pMethods->xFileControl(id,op,pArg);
+}
+int sqlite3OsSectorSize(sqlite3_file *id){
+ int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize;
+ return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE);
+}
+int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
+ return id->pMethods->xDeviceCharacteristics(id);
}
-int sqlite3OsLock(OsFile *id, int lockType){
- return id->pMethod->xLock(id, lockType);
+
+/*
+** The next group of routines are convenience wrappers around the
+** VFS methods.
+*/
+int sqlite3OsOpen(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ sqlite3_file *pFile,
+ int flags,
+ int *pFlagsOut
+){
+ DO_OS_MALLOC_TEST;
+ return pVfs->xOpen(pVfs, zPath, pFile, flags, pFlagsOut);
+}
+int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+ return pVfs->xDelete(pVfs, zPath, dirSync);
+}
+int sqlite3OsAccess(sqlite3_vfs *pVfs, const char *zPath, int flags){
+ return pVfs->xAccess(pVfs, zPath, flags);
+}
+int sqlite3OsGetTempname(sqlite3_vfs *pVfs, int nBufOut, char *zBufOut){
+ return pVfs->xGetTempname(pVfs, nBufOut, zBufOut);
+}
+int sqlite3OsFullPathname(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nPathOut,
+ char *zPathOut
+){
+ return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
}
-int sqlite3OsUnlock(OsFile *id, int lockType){
- return id->pMethod->xUnlock(id, lockType);
+void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
+ return pVfs->xDlOpen(pVfs, zPath);
}
-int sqlite3OsLockState(OsFile *id){
- return id->pMethod->xLockState(id);
+void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+ pVfs->xDlError(pVfs, nByte, zBufOut);
}
-int sqlite3OsCheckReservedLock(OsFile *id){
- return id->pMethod->xCheckReservedLock(id);
+void *sqlite3OsDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
+ return pVfs->xDlSym(pVfs, pHandle, zSymbol);
+}
+void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){
+ pVfs->xDlClose(pVfs, pHandle);
+}
+int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+ return pVfs->xRandomness(pVfs, nByte, zBufOut);
+}
+int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
+ return pVfs->xSleep(pVfs, nMicro);
+}
+int sqlite3OsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
+ return pVfs->xCurrentTime(pVfs, pTimeOut);
+}
+
+int sqlite3OsOpenMalloc(
+ sqlite3_vfs *pVfs,
+ const char *zFile,
+ sqlite3_file **ppFile,
+ int flags,
+ int *pOutFlags
+){
+ int rc = SQLITE_NOMEM;
+ sqlite3_file *pFile;
+ pFile = (sqlite3_file *)sqlite3_malloc(pVfs->szOsFile);
+ if( pFile ){
+ rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags);
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(pFile);
+ }else{
+ *ppFile = pFile;
+ }
+ }
+ return rc;
+}
+int sqlite3OsCloseFree(sqlite3_file *pFile){
+ int rc = SQLITE_OK;
+ if( pFile ){
+ rc = sqlite3OsClose(pFile);
+ sqlite3_free(pFile);
+ }
+ return rc;
}
-#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.
+** The list of all registered VFS implementations. This list is
+** initialized to the single VFS returned by sqlite3OsDefaultVfs()
+** upon the first call to sqlite3_vfs_find().
*/
-struct sqlite3OsVtbl *sqlite3_os_switch(void){
- return &sqlite3Os;
+static sqlite3_vfs *vfsList = 0;
+
+/*
+** Locate a VFS by name. If no name is given, simply return the
+** first VFS on the list.
+*/
+sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){
+#ifndef SQLITE_MUTEX_NOOP
+ sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
+#endif
+ sqlite3_vfs *pVfs = 0;
+ static int isInit = 0;
+ sqlite3_mutex_enter(mutex);
+ if( !isInit ){
+ vfsList = sqlite3OsDefaultVfs();
+ isInit = 1;
+ }
+ for(pVfs = vfsList; pVfs; pVfs=pVfs->pNext){
+ if( zVfs==0 ) break;
+ if( strcmp(zVfs, pVfs->zName)==0 ) break;
+ }
+ sqlite3_mutex_leave(mutex);
+ return pVfs;
}
+
+/*
+** Unlink a VFS from the linked list
+*/
+static void vfsUnlink(sqlite3_vfs *pVfs){
+ assert( sqlite3_mutex_held(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)) );
+ if( pVfs==0 ){
+ /* No-op */
+ }else if( vfsList==pVfs ){
+ vfsList = pVfs->pNext;
+ }else if( vfsList ){
+ sqlite3_vfs *p = vfsList;
+ while( p->pNext && p->pNext!=pVfs ){
+ p = p->pNext;
+ }
+ if( p->pNext==pVfs ){
+ p->pNext = pVfs->pNext;
+ }
+ }
+}
+
+/*
+** Register a VFS with the system. It is harmless to register the same
+** VFS multiple times. The new VFS becomes the default if makeDflt is
+** true.
+*/
+int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
+#ifndef SQLITE_MUTEX_NOOP
+ sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
+#endif
+ sqlite3_vfs_find(0); /* Make sure we are initialized */
+ sqlite3_mutex_enter(mutex);
+ vfsUnlink(pVfs);
+ if( makeDflt || vfsList==0 ){
+ pVfs->pNext = vfsList;
+ vfsList = pVfs;
+ }else{
+ pVfs->pNext = vfsList->pNext;
+ vfsList->pNext = pVfs;
+ }
+ assert(vfsList);
+ sqlite3_mutex_leave(mutex);
+ return SQLITE_OK;
+}
+
+/*
+** Unregister a VFS so that it is no longer accessible.
+*/
+int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
+#ifndef SQLITE_MUTEX_NOOP
+ sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
+ sqlite3_mutex_enter(mutex);
+ vfsUnlink(pVfs);
+ sqlite3_mutex_leave(mutex);
+ return SQLITE_OK;
+}
diff --git a/ext/pdo_sqlite/sqlite/src/os.h b/ext/pdo_sqlite/sqlite/src/os.h
index 4433f5d022..026e2c430d 100644
--- a/ext/pdo_sqlite/sqlite/src/os.h
+++ b/ext/pdo_sqlite/sqlite/src/os.h
@@ -13,14 +13,31 @@
** This header file (together with is companion C source-code file
** "os.c") attempt to abstract the underlying operating system so that
** the SQLite library will work on both POSIX and windows systems.
+**
+** This header file is #include-ed by sqliteInt.h and thus ends up
+** being included by every source file.
*/
#ifndef _SQLITE_OS_H_
#define _SQLITE_OS_H_
/*
** Figure out if we are dealing with Unix, Windows, or some other
-** operating system.
+** operating system. After the following block of preprocess macros,
+** all of OS_UNIX, OS_WIN, OS_OS2, and OS_OTHER will defined to either
+** 1 or 0. One of the four will be 1. The other three will be 0.
*/
+#if defined(OS_OTHER)
+# if OS_OTHER==1
+# undef OS_UNIX
+# define OS_UNIX 0
+# undef OS_WIN
+# define OS_WIN 0
+# undef OS_OS2
+# define OS_OS2 0
+# else
+# undef OS_OTHER
+# endif
+#endif
#if !defined(OS_UNIX) && !defined(OS_OTHER)
# define OS_OTHER 0
# ifndef OS_WIN
@@ -28,7 +45,7 @@
# define OS_WIN 1
# define OS_UNIX 0
# define OS_OS2 0
-# elif defined(_EMX_) || defined(_OS2) || defined(OS2) || defined(_OS2_) || defined(__OS2__)
+# elif defined(__EMX__) || defined(_OS2) || defined(OS2) || defined(_OS2_) || defined(__OS2__)
# define OS_WIN 0
# define OS_UNIX 0
# define OS_OS2 1
@@ -48,6 +65,7 @@
#endif
+
/*
** Define the maximum size of a temporary filename
*/
@@ -55,11 +73,16 @@
# include <windows.h>
# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
#elif OS_OS2
+# if (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 3) && defined(OS2_HIGH_MEMORY)
+# include <os2safe.h> /* has to be included before os2.h for linking to work */
+# endif
# define INCL_DOSDATETIME
# define INCL_DOSFILEMGR
# define INCL_DOSERRORS
# define INCL_DOSMISC
# define INCL_DOSPROCESS
+# define INCL_DOSMODULEMGR
+# define INCL_DOSSEMAPHORES
# include <os2.h>
# define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP)
#else
@@ -74,141 +97,37 @@
#endif
/*
+** The default size of a disk sector
+*/
+#ifndef SQLITE_DEFAULT_SECTOR_SIZE
+# define SQLITE_DEFAULT_SECTOR_SIZE 512
+#endif
+
+/*
** Temporary files are named starting with this prefix followed by 16 random
** alphanumeric characters, and no file extension. They are stored in the
** OS's standard temporary file directory, and are deleted prior to exit.
** If sqlite is being embedded in another program, you may wish to change the
** prefix to reflect your program's name, so that if your program exits
** prematurely, old temporary files can be easily identified. This can be done
-** using -DTEMP_FILE_PREFIX=myprefix_ on the compiler command line.
-*/
-#ifndef TEMP_FILE_PREFIX
-# define TEMP_FILE_PREFIX "sqlite_"
-#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.
+** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line.
+**
+** 2006-10-31: The default prefix used to be "sqlite_". But then
+** Mcafee started using SQLite in their anti-virus product and it
+** started putting files with the "sqlite" name in the c:/temp folder.
+** This annoyed many windows users. Those users would then do a
+** Google search for "sqlite", find the telephone numbers of the
+** developers and call to wake them up at night and complain.
+** For this reason, the default name prefix is changed to be "sqlite"
+** spelled backwards. So the temp files are still identified, but
+** anybody smart enough to figure out the code is also likely smart
+** enough to know that calling the developer will not help get rid
+** of the file.
*/
-#if OS_OTHER
-# include "os_other.h"
+#ifndef SQLITE_TEMP_FILE_PREFIX
+# define SQLITE_TEMP_FILE_PREFIX "etilqs_"
#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:
@@ -300,181 +219,57 @@ extern unsigned int sqlite3_pending_byte;
#define SHARED_FIRST (PENDING_BYTE+2)
#define SHARED_SIZE 510
-/*
-** Prototypes for operating system interface routines.
+/*
+** Functions for accessing sqlite3_file methods
*/
-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 sqlite3OsTruncate(OsFile*, i64 size);
-int sqlite3OsSync(OsFile*, int);
-void sqlite3OsSetFullSync(OsFile *id, int setting);
-int sqlite3OsFileHandle(OsFile *id);
-int sqlite3OsFileSize(OsFile*, i64 *pSize);
-int sqlite3OsLock(OsFile*, int);
-int sqlite3OsUnlock(OsFile*, int);
-int sqlite3OsLockState(OsFile *id);
-int sqlite3OsCheckReservedLock(OsFile *id);
-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.
+int sqlite3OsClose(sqlite3_file*);
+int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
+int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
+int sqlite3OsTruncate(sqlite3_file*, i64 size);
+int sqlite3OsSync(sqlite3_file*, int);
+int sqlite3OsFileSize(sqlite3_file*, i64 *pSize);
+int sqlite3OsLock(sqlite3_file*, int);
+int sqlite3OsUnlock(sqlite3_file*, int);
+int sqlite3OsCheckReservedLock(sqlite3_file *id);
+int sqlite3OsFileControl(sqlite3_file*,int,void*);
+int sqlite3OsSectorSize(sqlite3_file *id);
+int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
+
+/*
+** Functions for accessing sqlite3_vfs methods
*/
-#ifdef SQLITE_ENABLE_REDEF_IO
+int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *);
+int sqlite3OsDelete(sqlite3_vfs *, const char *, int);
+int sqlite3OsAccess(sqlite3_vfs *, const char *, int);
+int sqlite3OsGetTempname(sqlite3_vfs *, int, char *);
+int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *);
+void *sqlite3OsDlOpen(sqlite3_vfs *, const char *);
+void sqlite3OsDlError(sqlite3_vfs *, int, char *);
+void *sqlite3OsDlSym(sqlite3_vfs *, void *, const char *);
+void sqlite3OsDlClose(sqlite3_vfs *, void *);
+int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
+int sqlite3OsSleep(sqlite3_vfs *, int);
+int sqlite3OsCurrentTime(sqlite3_vfs *, double*);
/*
-** 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.
+** Convenience functions for opening and closing files using
+** sqlite3_malloc() to obtain space for the file-handle structure.
*/
-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 sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
+int sqlite3OsCloseFree(sqlite3_file *);
- 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
+/*
+** Each OS-specific backend defines an instance of the following
+** structure for returning a pointer to its sqlite3_vfs. If OS_OTHER
+** is defined (meaning that the application-defined OS interface layer
+** is used) then there is no default VFS. The application must
+** register one or more VFS structures using sqlite3_vfs_register()
+** before attempting to use SQLite.
*/
-#ifdef SQLITE_OMIT_DISKIO
-# define IF_DISKIO(X) 0
+#if OS_UNIX || OS_WIN || OS_OS2
+sqlite3_vfs *sqlite3OsDefaultVfs(void);
#else
-# define IF_DISKIO(X) X
+# define sqlite3OsDefaultVfs(X) 0
#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 d65c352ddf..8de4be9718 100644
--- a/ext/pdo_sqlite/sqlite/src/os_common.h
+++ b/ext/pdo_sqlite/sqlite/src/os_common.h
@@ -36,27 +36,25 @@
unsigned int sqlite3_pending_byte = 0x40000000;
#endif
-int sqlite3_os_trace = 0;
#ifdef SQLITE_DEBUG
-static int last_page = 0;
-#define SEEK(X) last_page=(X)
-#define TRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X)
-#define TRACE2(X,Y) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y)
-#define TRACE3(X,Y,Z) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z)
-#define TRACE4(X,Y,Z,A) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A)
-#define TRACE5(X,Y,Z,A,B) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A,B)
-#define TRACE6(X,Y,Z,A,B,C) if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
-#define TRACE7(X,Y,Z,A,B,C,D) \
+int sqlite3_os_trace = 0;
+#define OSTRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X)
+#define OSTRACE2(X,Y) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y)
+#define OSTRACE3(X,Y,Z) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z)
+#define OSTRACE4(X,Y,Z,A) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A)
+#define OSTRACE5(X,Y,Z,A,B) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A,B)
+#define OSTRACE6(X,Y,Z,A,B,C) \
+ if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
+#define OSTRACE7(X,Y,Z,A,B,C,D) \
if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
#else
-#define SEEK(X)
-#define TRACE1(X)
-#define TRACE2(X,Y)
-#define TRACE3(X,Y,Z)
-#define TRACE4(X,Y,Z,A)
-#define TRACE5(X,Y,Z,A,B)
-#define TRACE6(X,Y,Z,A,B,C)
-#define TRACE7(X,Y,Z,A,B,C,D)
+#define OSTRACE1(X)
+#define OSTRACE2(X,Y)
+#define OSTRACE3(X,Y,Z)
+#define OSTRACE4(X,Y,Z,A)
+#define OSTRACE5(X,Y,Z,A,B)
+#define OSTRACE6(X,Y,Z,A,B,C)
+#define OSTRACE7(X,Y,Z,A,B,C,D)
#endif
/*
@@ -90,27 +88,32 @@ static unsigned int elapse;
#ifdef SQLITE_TEST
int sqlite3_io_error_hit = 0;
int sqlite3_io_error_pending = 0;
+int sqlite3_io_error_persist = 0;
int sqlite3_diskfull_pending = 0;
int sqlite3_diskfull = 0;
-#define SimulateIOError(A) \
- if( sqlite3_io_error_pending ) \
- if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; }
+#define SimulateIOError(CODE) \
+ if( sqlite3_io_error_pending || sqlite3_io_error_hit ) \
+ if( sqlite3_io_error_pending-- == 1 \
+ || (sqlite3_io_error_persist && sqlite3_io_error_hit) ) \
+ { local_ioerr(); CODE; }
static void local_ioerr(){
- sqlite3_io_error_hit = 1; /* Really just a place to set a breakpoint */
+ IOTRACE(("IOERR\n"));
+ sqlite3_io_error_hit = 1;
}
-#define SimulateDiskfullError \
+#define SimulateDiskfullError(CODE) \
if( sqlite3_diskfull_pending ){ \
if( sqlite3_diskfull_pending == 1 ){ \
local_ioerr(); \
sqlite3_diskfull = 1; \
- return SQLITE_FULL; \
+ sqlite3_io_error_hit = 1; \
+ CODE; \
}else{ \
sqlite3_diskfull_pending--; \
} \
}
#else
#define SimulateIOError(A)
-#define SimulateDiskfullError
+#define SimulateDiskfullError(A)
#endif
/*
@@ -122,67 +125,3 @@ 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_unix.c b/ext/pdo_sqlite/sqlite/src/os_unix.c
index dd94bbb2db..6f9b3c02db 100644
--- a/ext/pdo_sqlite/sqlite/src/os_unix.c
+++ b/ext/pdo_sqlite/sqlite/src/os_unix.c
@@ -13,9 +13,10 @@
** This file contains code that is specific to Unix systems.
*/
#include "sqliteInt.h"
-#include "os.h"
#if OS_UNIX /* This file is used on unix only */
+/* #define SQLITE_ENABLE_LOCKING_STYLE 0 */
+
/*
** These #defines should enable >2GB file support on Posix if the
** underlying operating system supports it. If the OS lacks
@@ -47,12 +48,17 @@
#include <time.h>
#include <sys/time.h>
#include <errno.h>
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
/*
** If we are to be thread-safe, include the pthreads header and define
** the SQLITE_UNIX_THREADS macro.
*/
-#if defined(THREADSAFE) && THREADSAFE
+#if SQLITE_THREADSAFE
# include <pthread.h>
# define SQLITE_UNIX_THREADS 1
#endif
@@ -64,59 +70,44 @@
# define SQLITE_DEFAULT_FILE_PERMISSIONS 0644
#endif
+/*
+** Maximum supported path-length.
+*/
+#define MAX_PATHNAME 512
/*
-** The unixFile structure is subclass of OsFile specific for the unix
+** The unixFile structure is subclass of sqlite3_file specific for the unix
** protability layer.
*/
typedef struct unixFile unixFile;
struct unixFile {
- IoMethod const *pMethod; /* Always the first entry */
+ sqlite3_io_methods const *pMethod; /* Always the first entry */
+#ifdef SQLITE_TEST
+ /* In test mode, increase the size of this structure a bit so that
+ ** it is larger than the struct CrashFile defined in test6.c.
+ */
+ char aPadding[32];
+#endif
struct openCnt *pOpen; /* Info about all open fd's on this inode */
struct lockInfo *pLock; /* Info about locks on this inode */
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+ void *lockingContext; /* Locking style specific state */
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
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 */
+#if SQLITE_THREADSAFE
+ pthread_t tid; /* The thread that "owns" this unixFile */
#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 the database
-** will be in-memory only)
-*/
-#ifndef SQLITE_OMIT_DISKIO
-
-
-/*
** Define various macros that are missing from some systems.
*/
#ifndef O_LARGEFILE
@@ -137,7 +128,7 @@ struct unixFile {
** 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 it's DOS - what did you expect?
+** DJGPP. But it is DOS - what did you expect?
*/
#ifdef __DJGPP__
# define fcntl(A,B,C) 0
@@ -147,29 +138,29 @@ struct unixFile {
** The threadid macro resolves to the thread-id or to 0. Used for
** testing and debugging only.
*/
-#ifdef SQLITE_UNIX_THREADS
+#if SQLITE_THREADSAFE
#define threadid pthread_self()
#else
#define threadid 0
#endif
/*
-** Set or check the OsFile.tid field. This field is set when an OsFile
-** is first opened. All subsequent uses of the OsFile verify that the
-** same thread is operating on the OsFile. Some operating systems do
+** Set or check the unixFile.tid field. This field is set when an unixFile
+** is first opened. All subsequent uses of the unixFile verify that the
+** same thread is operating on the unixFile. Some operating systems do
** not allow locks to be overridden by other threads and that restriction
** 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 (2007-01-15): OsFiles can be moved from one thread to
+** Version 3.3.1 (2006-01-15): unixFile 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
+** or if no locks are held. But the unixFile.pLock field needs to be
** recomputed because its key includes the thread-id. See the
** transferOwnership() function below for additional information
*/
-#if defined(SQLITE_UNIX_THREADS)
+#if SQLITE_THREADSAFE
# define SET_THREADID(X) (X)->tid = pthread_self()
# define CHECK_THREADID(X) (threadsOverrideEachOthersLocks==0 && \
!pthread_equal((X)->tid, pthread_self()))
@@ -213,11 +204,11 @@ struct unixFile {
** locks to see if another thread has previously set a lock on that same
** inode.
**
-** The OsFile structure for POSIX is no longer just an integer file
+** The sqlite3_file structure for POSIX is no longer just an integer file
** descriptor. It is now a structure that holds the integer file
** descriptor and a pointer to a structure that describes the internal
** locks on the corresponding inode. There is one locking structure
-** per inode, so if the same inode is opened twice, both OsFile structures
+** per inode, so if the same inode is opened twice, both unixFile structures
** point to the same locking structure. The locking structure keeps
** a reference count (so we will know when to delete it) and a "cnt"
** field that tells us its internal lock status. cnt==0 means the
@@ -236,11 +227,11 @@ struct unixFile {
**
** If you close a file descriptor that points to a file that has locks,
** all locks on that file that are owned by the current process are
-** released. To work around this problem, each OsFile structure contains
+** released. To work around this problem, each unixFile structure contains
** a pointer to an openCnt structure. There is one openCnt structure
-** per open inode, which means that multiple OsFiles can point to a single
-** openCnt. When an attempt is made to close an OsFile, if there are
-** other OsFiles open on the same inode that are holding locks, the call
+** per open inode, which means that multiple unixFile can point to a single
+** openCnt. When an attempt is made to close an unixFile, if there are
+** other unixFile open on the same inode that are holding locks, the call
** to close() the file descriptor is deferred until all of the locks clear.
** The openCnt structure keeps a list of file descriptors that need to
** be closed and that list is walked (and cleared) when the last lock
@@ -290,7 +281,7 @@ struct unixFile {
struct lockKey {
dev_t dev; /* Device number */
ino_t ino; /* Inode number */
-#ifdef SQLITE_UNIX_THREADS
+#if SQLITE_THREADSAFE
pthread_t tid; /* Thread ID or zero if threads can override each other */
#endif
};
@@ -300,9 +291,9 @@ struct lockKey {
** inode on each thread with a different process ID. (Threads have
** different process IDs on linux, but not on most other unixes.)
**
-** A single inode can have multiple file descriptors, so each OsFile
+** A single inode can have multiple file descriptors, so each unixFile
** structure contains a pointer to an instance of this object and this
-** object keeps a count of the number of OsFiles pointing to it.
+** object keeps a count of the number of unixFile pointing to it.
*/
struct lockInfo {
struct lockKey key; /* The lookup key */
@@ -341,12 +332,46 @@ struct openCnt {
** 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,
- sqlite3ThreadSafeMalloc, sqlite3ThreadSafeFree, 0, 0};
-static Hash openHash = {SQLITE_HASH_BINARY, 0, 0, 0,
- sqlite3ThreadSafeMalloc, sqlite3ThreadSafeFree, 0, 0};
+static Hash lockHash = {SQLITE_HASH_BINARY, 0, 0, 0, 0, 0};
+static Hash openHash = {SQLITE_HASH_BINARY, 0, 0, 0, 0, 0};
+
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+/*
+** The locking styles are associated with the different file locking
+** capabilities supported by different file systems.
+**
+** POSIX locking style fully supports shared and exclusive byte-range locks
+** ADP locking only supports exclusive byte-range locks
+** FLOCK only supports a single file-global exclusive lock
+** DOTLOCK isn't a true locking style, it refers to the use of a special
+** file named the same as the database file with a '.lock' extension, this
+** can be used on file systems that do not offer any reliable file locking
+** NO locking means that no locking will be attempted, this is only used for
+** read-only file systems currently
+** UNSUPPORTED means that no locking will be attempted, this is only used for
+** file systems that are known to be unsupported
+*/
+typedef enum {
+ posixLockingStyle = 0, /* standard posix-advisory locks */
+ afpLockingStyle, /* use afp locks */
+ flockLockingStyle, /* use flock() */
+ dotlockLockingStyle, /* use <file>.lock files */
+ noLockingStyle, /* useful for read-only file system */
+ unsupportedLockingStyle /* indicates unsupported file system */
+} sqlite3LockingStyle;
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
+
+/*
+** Helper functions to obtain and relinquish the global mutex.
+*/
+static void enterMutex(){
+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+static void leaveMutex(){
+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+}
-#ifdef SQLITE_UNIX_THREADS
+#if SQLITE_THREADSAFE
/*
** This variable records whether or not threads can override each others
** locks.
@@ -421,7 +446,7 @@ static int lockTrace(int fd, int op, struct flock *p){
sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n",
threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len,
(int)p->l_pid, s);
- if( s && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){
+ if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){
struct flock l2;
l2 = *p;
fcntl(fd, F_GETLK, &l2);
@@ -483,17 +508,18 @@ static void testThreadLockingBehavior(int fd_orig){
close(fd);
threadsOverrideEachOthersLocks = d[0].result==0 && d[1].result==0;
}
-#endif /* SQLITE_UNIX_THREADS */
+#endif /* SQLITE_THREADSAFE */
/*
** Release a lockInfo structure previously allocated by findLockInfo().
*/
static void releaseLockInfo(struct lockInfo *pLock){
- assert( sqlite3OsInMutex(1) );
+ if (pLock == NULL)
+ return;
pLock->nRef--;
if( pLock->nRef==0 ){
sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0);
- sqlite3ThreadSafeFree(pLock);
+ sqlite3_free(pLock);
}
}
@@ -501,15 +527,91 @@ static void releaseLockInfo(struct lockInfo *pLock){
** Release a openCnt structure previously allocated by findLockInfo().
*/
static void releaseOpenCnt(struct openCnt *pOpen){
- assert( sqlite3OsInMutex(1) );
+ if (pOpen == NULL)
+ return;
pOpen->nRef--;
if( pOpen->nRef==0 ){
sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0);
free(pOpen->aPending);
- sqlite3ThreadSafeFree(pOpen);
+ sqlite3_free(pOpen);
}
}
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+/*
+** Tests a byte-range locking query to see if byte range locks are
+** supported, if not we fall back to dotlockLockingStyle.
+*/
+static sqlite3LockingStyle sqlite3TestLockingStyle(
+ const char *filePath,
+ int fd
+){
+ /* test byte-range lock using fcntl */
+ struct flock lockInfo;
+
+ lockInfo.l_len = 1;
+ lockInfo.l_start = 0;
+ lockInfo.l_whence = SEEK_SET;
+ lockInfo.l_type = F_RDLCK;
+
+ if( fcntl(fd, F_GETLK, &lockInfo)!=-1 ) {
+ return posixLockingStyle;
+ }
+
+ /* testing for flock can give false positives. So if if the above test
+ ** fails, then we fall back to using dot-lock style locking.
+ */
+ return dotlockLockingStyle;
+}
+
+/*
+** Examines the f_fstypename entry in the statfs structure as returned by
+** stat() for the file system hosting the database file, assigns the
+** appropriate locking style based on its value. These values and
+** assignments are based on Darwin/OSX behavior and have not been tested on
+** other systems.
+*/
+static sqlite3LockingStyle sqlite3DetectLockingStyle(
+ const char *filePath,
+ int fd
+){
+
+#ifdef SQLITE_FIXED_LOCKING_STYLE
+ return (sqlite3LockingStyle)SQLITE_FIXED_LOCKING_STYLE;
+#else
+ struct statfs fsInfo;
+
+ if (statfs(filePath, &fsInfo) == -1)
+ return sqlite3TestLockingStyle(filePath, fd);
+
+ if (fsInfo.f_flags & MNT_RDONLY)
+ return noLockingStyle;
+
+ if( (!strcmp(fsInfo.f_fstypename, "hfs")) ||
+ (!strcmp(fsInfo.f_fstypename, "ufs")) )
+ return posixLockingStyle;
+
+ if(!strcmp(fsInfo.f_fstypename, "afpfs"))
+ return afpLockingStyle;
+
+ if(!strcmp(fsInfo.f_fstypename, "nfs"))
+ return sqlite3TestLockingStyle(filePath, fd);
+
+ if(!strcmp(fsInfo.f_fstypename, "smbfs"))
+ return flockLockingStyle;
+
+ if(!strcmp(fsInfo.f_fstypename, "msdos"))
+ return dotlockLockingStyle;
+
+ if(!strcmp(fsInfo.f_fstypename, "webdav"))
+ return unsupportedLockingStyle;
+
+ return sqlite3TestLockingStyle(filePath, fd);
+#endif /* SQLITE_FIXED_LOCKING_STYLE */
+}
+
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
+
/*
** Given a file descriptor, locate lockInfo and openCnt structures that
** describes that file descriptor. Create new ones if necessary. The
@@ -531,11 +633,10 @@ static int findLockInfo(
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;
-#ifdef SQLITE_UNIX_THREADS
+#if SQLITE_THREADSAFE
if( threadsOverrideEachOthersLocks<0 ){
testThreadLockingBehavior(fd);
}
@@ -547,7 +648,7 @@ static int findLockInfo(
pLock = (struct lockInfo*)sqlite3HashFind(&lockHash, &key1, sizeof(key1));
if( pLock==0 ){
struct lockInfo *pOld;
- pLock = sqlite3ThreadSafeMalloc( sizeof(*pLock) );
+ pLock = sqlite3_malloc( sizeof(*pLock) );
if( pLock==0 ){
rc = 1;
goto exit_findlockinfo;
@@ -559,7 +660,7 @@ static int findLockInfo(
pOld = sqlite3HashInsert(&lockHash, &pLock->key, sizeof(key1), pLock);
if( pOld!=0 ){
assert( pOld==pLock );
- sqlite3ThreadSafeFree(pLock);
+ sqlite3_free(pLock);
rc = 1;
goto exit_findlockinfo;
}
@@ -571,7 +672,7 @@ static int findLockInfo(
pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2));
if( pOpen==0 ){
struct openCnt *pOld;
- pOpen = sqlite3ThreadSafeMalloc( sizeof(*pOpen) );
+ pOpen = sqlite3_malloc( sizeof(*pOpen) );
if( pOpen==0 ){
releaseLockInfo(pLock);
rc = 1;
@@ -585,7 +686,7 @@ static int findLockInfo(
pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen);
if( pOld!=0 ){
assert( pOld==pOpen );
- sqlite3ThreadSafeFree(pOpen);
+ sqlite3_free(pOpen);
releaseLockInfo(pLock);
rc = 1;
goto exit_findlockinfo;
@@ -631,7 +732,7 @@ static const char *locktypeName(int locktype){
** 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
+#if SQLITE_THREADSAFE
static int transferOwnership(unixFile *pFile){
int rc;
pthread_t hSelf;
@@ -642,21 +743,26 @@ static int transferOwnership(unixFile *pFile){
hSelf = pthread_self();
if( pthread_equal(pFile->tid, hSelf) ){
/* We are still in the same thread */
- TRACE1("No-transfer, same thread\n");
+ OSTRACE1("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);
+ OSTRACE4("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;
+ if (pFile->pLock != NULL) {
+ releaseLockInfo(pFile->pLock);
+ rc = findLockInfo(pFile->h, &pFile->pLock, 0);
+ OSTRACE5("LOCK %d is now %s(%s,%d)\n", pFile->h,
+ locktypeName(pFile->locktype),
+ locktypeName(pFile->pLock->locktype), pFile->pLock->cnt);
+ return rc;
+ } else {
+ return SQLITE_OK;
+ }
}
#else
/* On single-threaded builds, ownership transfer is a no-op */
@@ -664,259 +770,35 @@ static int transferOwnership(unixFile *pFile){
#endif
/*
-** Delete the named file
-*/
-int sqlite3UnixDelete(const char *zFilename){
- unlink(zFilename);
- return SQLITE_OK;
-}
-
-/*
-** Return TRUE if the named file exists.
-*/
-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,
-** 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.
+** Seek to the offset passed as the second argument, then read cnt
+** bytes into pBuf. Return the number of bytes actually read.
**
-** On failure, the function returns SQLITE_CANTOPEN and leaves
-** *id and *pReadonly unchanged.
+** NB: If you define USE_PREAD or USE_PREAD64, then it might also
+** be necessary to define _XOPEN_SOURCE to be 500. This varies from
+** one system to another. Since SQLite does not define USE_PREAD
+** any any form by default, we will not attempt to define _XOPEN_SOURCE.
+** See tickets #2741 and #2681.
*/
-int sqlite3UnixOpenReadWrite(
- const char *zFilename,
- OsFile **pId,
- int *pReadonly
-){
- int rc;
- 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( f.h<0 ){
-#ifdef EISDIR
- if( errno==EISDIR ){
- return SQLITE_CANTOPEN;
- }
-#endif
- f.h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
- if( f.h<0 ){
- return SQLITE_CANTOPEN;
- }
- *pReadonly = 1;
- }else{
- *pReadonly = 0;
- }
- sqlite3OsEnterMutex();
- rc = findLockInfo(f.h, &f.pLock, &f.pOpen);
- sqlite3OsLeaveMutex();
- if( rc ){
- close(f.h);
- return SQLITE_NOMEM;
- }
- TRACE3("OPEN %-3d %s\n", f.h, zFilename);
- return allocateUnixFile(&f, pId);
-}
-
-
-/*
-** 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 sqlite3UnixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
- int rc;
- 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( f.h<0 ){
- return SQLITE_CANTOPEN;
- }
- sqlite3OsEnterMutex();
- rc = findLockInfo(f.h, &f.pLock, &f.pOpen);
- sqlite3OsLeaveMutex();
- if( rc ){
- close(f.h);
- unlink(zFilename);
- return SQLITE_NOMEM;
- }
- if( delFlag ){
- unlink(zFilename);
- }
- TRACE3("OPEN-EX %-3d %s\n", f.h, zFilename);
- return allocateUnixFile(&f, pId);
-}
-
-/*
-** 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 sqlite3UnixOpenReadOnly(const char *zFilename, OsFile **pId){
- int rc;
- 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(f.h, &f.pLock, &f.pOpen);
- sqlite3OsLeaveMutex();
- if( rc ){
- close(f.h);
- return SQLITE_NOMEM;
- }
- TRACE3("OPEN-RO %-3d %s\n", f.h, zFilename);
- return allocateUnixFile(&f, pId);
-}
-
-/*
-** 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 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.
-*/
-static int unixOpenDirectory(
- OsFile *id,
- const char *zDirname
-){
- 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(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", pFile->dirfd, zDirname);
- return SQLITE_OK;
-}
-
-/*
-** 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;
-
-/*
-** Create a temporary file name in zBuf. zBuf must be big enough to
-** hold at least SQLITE_TEMPNAME_SIZE characters.
-*/
-int sqlite3UnixTempFileName(char *zBuf){
- static const char *azDirs[] = {
- 0,
- "/var/tmp",
- "/usr/tmp",
- "/tmp",
- ".",
- };
- static const unsigned char zChars[] =
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "0123456789";
- int i, j;
- struct stat buf;
- const char *zDir = ".";
- azDirs[0] = sqlite3_temp_directory;
- for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
- if( azDirs[i]==0 ) continue;
- if( stat(azDirs[i], &buf) ) continue;
- if( !S_ISDIR(buf.st_mode) ) continue;
- if( access(azDirs[i], 07) ) continue;
- zDir = azDirs[i];
- break;
- }
- do{
- sprintf(zBuf, "%s/"TEMP_FILE_PREFIX, zDir);
- 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;
- }while( access(zBuf,0)==0 );
- return SQLITE_OK;
-}
-
-/*
-** Check that a given pathname is a directory and is writable
-**
-*/
-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;
-}
-
-/*
-** 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){
+static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
int got;
-#ifdef USE_PREAD
- got = pread(id->h, pBuf, cnt, id->offset);
+ i64 newOffset;
+ TIMER_START;
+#if defined(USE_PREAD)
+ got = pread(id->h, pBuf, cnt, offset);
+ SimulateIOError( got = -1 );
+#elif defined(USE_PREAD64)
+ got = pread64(id->h, pBuf, cnt, offset);
+ SimulateIOError( got = -1 );
#else
- lseek(id->h, id->offset, SEEK_SET);
+ newOffset = lseek(id->h, offset, SEEK_SET);
+ SimulateIOError( newOffset-- );
+ if( newOffset!=offset ){
+ return -1;
+ }
got = read(id->h, pBuf, cnt);
#endif
- if( got>0 ){
- id->offset += got;
- }
+ TIMER_END;
+ OSTRACE5("READ %-3d %5d %7lld %d\n", id->h, got, offset, TIMER_ELAPSED);
return got;
}
@@ -925,21 +807,22 @@ static int seekAndRead(unixFile *id, void *pBuf, int cnt){
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
-static int unixRead(OsFile *id, void *pBuf, int amt){
+static int unixRead(
+ sqlite3_file *id,
+ void *pBuf,
+ int amt,
+ sqlite3_int64 offset
+){
int got;
assert( id );
- SimulateIOError(SQLITE_IOERR);
- TIMER_START;
- got = seekAndRead((unixFile*)id, pBuf, amt);
- TIMER_END;
- TRACE5("READ %-3d %5d %7d %d\n", ((unixFile*)id)->h, got,
- last_page, TIMER_ELAPSED);
- SEEK(0);
- /* if( got<0 ) got = 0; */
+ got = seekAndRead((unixFile*)id, offset, pBuf, amt);
if( got==amt ){
return SQLITE_OK;
+ }else if( got<0 ){
+ return SQLITE_IOERR_READ;
}else{
- return SQLITE_IOERR;
+ memset(&((char*)pBuf)[got], 0, amt-got);
+ return SQLITE_IOERR_SHORT_READ;
}
}
@@ -947,17 +830,23 @@ static int unixRead(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){
+static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
int got;
-#ifdef USE_PREAD
- got = pwrite(id->h, pBuf, cnt, id->offset);
+ i64 newOffset;
+ TIMER_START;
+#if defined(USE_PREAD)
+ got = pwrite(id->h, pBuf, cnt, offset);
+#elif defined(USE_PREAD64)
+ got = pwrite64(id->h, pBuf, cnt, offset);
#else
- lseek(id->h, id->offset, SEEK_SET);
+ newOffset = lseek(id->h, offset, SEEK_SET);
+ if( newOffset!=offset ){
+ return -1;
+ }
got = write(id->h, pBuf, cnt);
#endif
- if( got>0 ){
- id->offset += got;
- }
+ TIMER_END;
+ OSTRACE5("WRITE %-3d %5d %7lld %d\n", id->h, got, offset, TIMER_ELAPSED);
return got;
}
@@ -966,40 +855,32 @@ static int seekAndWrite(unixFile *id, const void *pBuf, int cnt){
** Write data from a buffer into a file. Return SQLITE_OK on success
** or some other error code on failure.
*/
-static int unixWrite(OsFile *id, const void *pBuf, int amt){
+static int unixWrite(
+ sqlite3_file *id,
+ const void *pBuf,
+ int amt,
+ sqlite3_int64 offset
+){
int wrote = 0;
assert( id );
assert( amt>0 );
- SimulateIOError(SQLITE_IOERR);
- SimulateDiskfullError;
- TIMER_START;
- while( amt>0 && (wrote = seekAndWrite((unixFile*)id, pBuf, amt))>0 ){
+ while( amt>0 && (wrote = seekAndWrite((unixFile*)id, offset, pBuf, amt))>0 ){
amt -= wrote;
+ offset += wrote;
pBuf = &((char*)pBuf)[wrote];
}
- TIMER_END;
- TRACE5("WRITE %-3d %5d %7d %d\n", ((unixFile*)id)->h, wrote,
- last_page, TIMER_ELAPSED);
- SEEK(0);
+ SimulateIOError(( wrote=(-1), amt=1 ));
+ SimulateDiskfullError(( wrote=0, amt=1 ));
if( amt>0 ){
- return SQLITE_FULL;
+ if( wrote<0 ){
+ return SQLITE_IOERR_WRITE;
+ }else{
+ return SQLITE_FULL;
+ }
}
return SQLITE_OK;
}
-/*
-** Move the read/write pointer in a file.
-*/
-static int unixSeek(OsFile *id, i64 offset){
- assert( id );
- SEEK(offset/1024 + 1);
-#ifdef SQLITE_TEST
- if( offset ) SimulateDiskfullError
-#endif
- ((unixFile*)id)->offset = offset;
- return SQLITE_OK;
-}
-
#ifdef SQLITE_TEST
/*
** Count the number of fullsyncs and normal syncs. This is used to test
@@ -1065,16 +946,23 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
}else{
rc = 1;
}
- /* If the FULLSYNC failed, try to do a normal fsync() */
+ /* If the FULLFSYNC failed, fall back to attempting an fsync().
+ * It shouldn't be possible for fullfsync to fail on the local
+ * file system (on OSX), so failure indicates that FULLFSYNC
+ * isn't supported for this file system. So, attempt an fsync
+ * and (for now) ignore the overhead of a superfluous fcntl call.
+ * It'd be better to detect fullfsync support once and avoid
+ * the fcntl call every time sync is called.
+ */
if( rc ) rc = fsync(fd);
-#else /* if !defined(F_FULLSYNC) */
+#else
if( dataOnly ){
rc = fdatasync(fd);
}else{
rc = fsync(fd);
}
-#endif /* defined(F_FULLFSYNC) */
+#endif /* HAVE_FULLFSYNC */
#endif /* defined(SQLITE_NO_SYNC) */
return rc;
@@ -1095,23 +983,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.
*/
-static int unixSync(OsFile *id, int dataOnly){
+static int unixSync(sqlite3_file *id, int flags){
+ int rc;
unixFile *pFile = (unixFile*)id;
+
+ int isDataOnly = (flags&SQLITE_SYNC_DATAONLY);
+ int isFullsync = (flags&0x0F)==SQLITE_SYNC_FULL;
+
+ /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */
+ assert((flags&0x0F)==SQLITE_SYNC_NORMAL
+ || (flags&0x0F)==SQLITE_SYNC_FULL
+ );
+
assert( pFile );
- SimulateIOError(SQLITE_IOERR);
- TRACE2("SYNC %-3d\n", pFile->h);
- if( full_fsync(pFile->h, pFile->fullSync, dataOnly) ){
- return SQLITE_IOERR;
+ OSTRACE2("SYNC %-3d\n", pFile->h);
+ rc = full_fsync(pFile->h, isFullsync, isDataOnly);
+ SimulateIOError( rc=1 );
+ if( rc ){
+ return SQLITE_IOERR_FSYNC;
}
if( pFile->dirfd>=0 ){
- TRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd,
- HAVE_FULLFSYNC, pFile->fullSync);
+ OSTRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd,
+ HAVE_FULLFSYNC, isFullsync);
#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) ){
+ if( (!HAVE_FULLFSYNC || !isFullsync) && full_fsync(pFile->dirfd,0,0) ){
/*
** We have received multiple reports of fsync() returning
** errors when applied to directories on certain file systems.
@@ -1128,49 +1027,31 @@ static int unixSync(OsFile *id, int dataOnly){
}
/*
-** Sync the directory zDirname. This is a no-op on operating systems other
-** than UNIX.
-**
-** This is used to make sure the master journal file has truely been deleted
-** before making changes to individual journals on a multi-database commit.
-** The F_FULLFSYNC option is not needed here.
-*/
-int sqlite3UnixSyncDirectory(const char *zDirname){
-#ifdef SQLITE_DISABLE_DIRSYNC
- return SQLITE_OK;
-#else
- int fd;
- int r;
- SimulateIOError(SQLITE_IOERR);
- fd = open(zDirname, O_RDONLY|O_BINARY, 0);
- TRACE3("DIRSYNC %-3d (%s)\n", fd, zDirname);
- if( fd<0 ){
- return SQLITE_CANTOPEN;
- }
- r = fsync(fd);
- close(fd);
- return ((r==0)?SQLITE_OK:SQLITE_IOERR);
-#endif
-}
-
-/*
** Truncate an open file to a specified size
*/
-static int unixTruncate(OsFile *id, i64 nByte){
+static int unixTruncate(sqlite3_file *id, i64 nByte){
+ int rc;
assert( id );
- SimulateIOError(SQLITE_IOERR);
- return ftruncate(((unixFile*)id)->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
+ SimulateIOError( return SQLITE_IOERR_TRUNCATE );
+ rc = ftruncate(((unixFile*)id)->h, (off_t)nByte);
+ if( rc ){
+ return SQLITE_IOERR_TRUNCATE;
+ }else{
+ return SQLITE_OK;
+ }
}
/*
** Determine the current size of a file in bytes
*/
-static int unixFileSize(OsFile *id, i64 *pSize){
+static int unixFileSize(sqlite3_file *id, i64 *pSize){
+ int rc;
struct stat buf;
assert( id );
- SimulateIOError(SQLITE_IOERR);
- if( fstat(((unixFile*)id)->h, &buf)!=0 ){
- return SQLITE_IOERR;
+ rc = fstat(((unixFile*)id)->h, &buf);
+ SimulateIOError( rc=1 );
+ if( rc!=0 ){
+ return SQLITE_IOERR_FSTAT;
}
*pSize = buf.st_size;
return SQLITE_OK;
@@ -1182,12 +1063,12 @@ static int unixFileSize(OsFile *id, i64 *pSize){
** non-zero. If the file is unlocked or holds only SHARED locks, then
** return zero.
*/
-static int unixCheckReservedLock(OsFile *id){
+static int unixCheckReservedLock(sqlite3_file *id){
int r = 0;
unixFile *pFile = (unixFile*)id;
assert( pFile );
- sqlite3OsEnterMutex(); /* Because pFile->pLock is shared across threads */
+ enterMutex(); /* Because pFile->pLock is shared across threads */
/* Check if a thread in this process holds such a lock */
if( pFile->pLock->locktype>SHARED_LOCK ){
@@ -1208,8 +1089,8 @@ static int unixCheckReservedLock(OsFile *id){
}
}
- sqlite3OsLeaveMutex();
- TRACE3("TEST WR-LOCK %d %d\n", pFile->h, r);
+ leaveMutex();
+ OSTRACE3("TEST WR-LOCK %d %d\n", pFile->h, r);
return r;
}
@@ -1238,7 +1119,7 @@ static int unixCheckReservedLock(OsFile *id){
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int unixLock(OsFile *id, int locktype){
+static int unixLock(sqlite3_file *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
@@ -1284,16 +1165,16 @@ static int unixLock(OsFile *id, int locktype){
int s;
assert( pFile );
- TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", pFile->h,
+ OSTRACE7("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.
+ ** unixFile, do nothing. Don't use the end_lock: exit path, as
+ ** enterMutex() hasn't been called yet.
*/
if( pFile->locktype>=locktype ){
- TRACE3("LOCK %d %s ok (already held)\n", pFile->h,
+ OSTRACE3("LOCK %d %s ok (already held)\n", pFile->h,
locktypeName(locktype));
return SQLITE_OK;
}
@@ -1306,18 +1187,18 @@ static int unixLock(OsFile *id, int locktype){
/* This mutex is needed because pFile->pLock is shared across threads
*/
- sqlite3OsEnterMutex();
+ enterMutex();
/* Make sure the current thread owns the pFile.
*/
rc = transferOwnership(pFile);
if( rc!=SQLITE_OK ){
- sqlite3OsLeaveMutex();
+ leaveMutex();
return rc;
}
pLock = pFile->pLock;
- /* If some thread using this PID has a lock via a different OsFile*
+ /* If some thread using this PID has a lock via a different unixFile*
** handle that precludes the requested lock, return BUSY.
*/
if( (pFile->locktype!=pLock->locktype &&
@@ -1356,7 +1237,7 @@ static int unixLock(OsFile *id, int locktype){
lock.l_type = (locktype==SHARED_LOCK?F_RDLCK:F_WRLCK);
lock.l_start = PENDING_BYTE;
s = fcntl(pFile->h, F_SETLK, &lock);
- if( s ){
+ if( s==(-1) ){
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
goto end_lock;
}
@@ -1380,10 +1261,10 @@ static int unixLock(OsFile *id, int locktype){
lock.l_len = 1L;
lock.l_type = F_UNLCK;
if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){
- rc = SQLITE_IOERR; /* This should never happen */
+ rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
goto end_lock;
}
- if( s ){
+ if( s==(-1) ){
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
}else{
pFile->locktype = SHARED_LOCK;
@@ -1413,7 +1294,7 @@ static int unixLock(OsFile *id, int locktype){
assert(0);
}
s = fcntl(pFile->h, F_SETLK, &lock);
- if( s ){
+ if( s==(-1) ){
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
}
}
@@ -1427,8 +1308,8 @@ static int unixLock(OsFile *id, int locktype){
}
end_lock:
- sqlite3OsLeaveMutex();
- TRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype),
+ leaveMutex();
+ OSTRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype),
rc==SQLITE_OK ? "ok" : "failed");
return rc;
}
@@ -1440,14 +1321,14 @@ end_lock:
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
*/
-static int unixUnlock(OsFile *id, int locktype){
+static int unixUnlock(sqlite3_file *id, int locktype){
struct lockInfo *pLock;
struct flock lock;
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
assert( pFile );
- TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", pFile->h, locktype,
+ OSTRACE7("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 );
@@ -1457,7 +1338,7 @@ static int unixUnlock(OsFile *id, int locktype){
if( CHECK_THREADID(pFile) ){
return SQLITE_MISUSE;
}
- sqlite3OsEnterMutex();
+ enterMutex();
pLock = pFile->pLock;
assert( pLock->cnt!=0 );
if( pFile->locktype>SHARED_LOCK ){
@@ -1467,19 +1348,19 @@ static int unixUnlock(OsFile *id, int locktype){
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST;
lock.l_len = SHARED_SIZE;
- if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){
+ if( fcntl(pFile->h, F_SETLK, &lock)==(-1) ){
/* This should never happen */
- rc = SQLITE_IOERR;
+ rc = SQLITE_IOERR_RDLOCK;
}
}
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = PENDING_BYTE;
lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE );
- if( fcntl(pFile->h, F_SETLK, &lock)==0 ){
+ if( fcntl(pFile->h, F_SETLK, &lock)!=(-1) ){
pLock->locktype = SHARED_LOCK;
}else{
- rc = SQLITE_IOERR; /* This should never happen */
+ rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
}
}
if( locktype==NO_LOCK ){
@@ -1494,10 +1375,10 @@ static int unixUnlock(OsFile *id, int locktype){
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = lock.l_len = 0L;
- if( fcntl(pFile->h, F_SETLK, &lock)==0 ){
+ if( fcntl(pFile->h, F_SETLK, &lock)!=(-1) ){
pLock->locktype = NO_LOCK;
}else{
- rc = SQLITE_IOERR; /* This should never happen */
+ rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
}
}
@@ -1518,7 +1399,7 @@ static int unixUnlock(OsFile *id, int locktype){
pOpen->aPending = 0;
}
}
- sqlite3OsLeaveMutex();
+ leaveMutex();
pFile->locktype = locktype;
return rc;
}
@@ -1526,184 +1407,1239 @@ static int unixUnlock(OsFile *id, int locktype){
/*
** Close a file.
*/
-static int unixClose(OsFile **pId){
- unixFile *id = (unixFile*)*pId;
+static int unixClose(sqlite3_file *id){
+ unixFile *pFile = (unixFile *)id;
+ if( !pFile ) return SQLITE_OK;
+ unixUnlock(id, NO_LOCK);
+ if( pFile->dirfd>=0 ) close(pFile->dirfd);
+ pFile->dirfd = -1;
+ enterMutex();
- 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( pFile->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
** descriptor to pOpen->aPending. It will be automatically closed when
** the last lock is cleared.
*/
int *aNew;
- struct openCnt *pOpen = id->pOpen;
+ struct openCnt *pOpen = pFile->pOpen;
aNew = realloc( pOpen->aPending, (pOpen->nPending+1)*sizeof(int) );
if( aNew==0 ){
/* If a malloc fails, just leak the file descriptor */
}else{
pOpen->aPending = aNew;
- pOpen->aPending[pOpen->nPending] = id->h;
+ pOpen->aPending[pOpen->nPending] = pFile->h;
pOpen->nPending++;
}
}else{
/* There are no outstanding locks so we can close the file immediately */
- close(id->h);
+ close(pFile->h);
}
- releaseLockInfo(id->pLock);
- releaseOpenCnt(id->pOpen);
+ releaseLockInfo(pFile->pLock);
+ releaseOpenCnt(pFile->pOpen);
- sqlite3OsLeaveMutex();
- id->isOpen = 0;
- TRACE2("CLOSE %-3d\n", id->h);
+ leaveMutex();
+ OSTRACE2("CLOSE %-3d\n", pFile->h);
OpenCounter(-1);
- sqlite3ThreadSafeFree(id);
- *pId = 0;
+ memset(pFile, 0, sizeof(unixFile));
return SQLITE_OK;
}
+
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+#pragma mark AFP Support
+
/*
-** 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 *sqlite3UnixFullPathname(const char *zRelative){
- char *zFull = 0;
- if( zRelative[0]=='/' ){
- sqlite3SetString(&zFull, zRelative, (char*)0);
- }else{
- char *zBuf = sqliteMalloc(5000);
- if( zBuf==0 ){
- return 0;
+ ** The afpLockingContext structure contains all afp lock specific state
+ */
+typedef struct afpLockingContext afpLockingContext;
+struct afpLockingContext {
+ unsigned long long sharedLockByte;
+ char *filePath;
+};
+
+struct ByteRangeLockPB2
+{
+ unsigned long long offset; /* offset to first byte to lock */
+ unsigned long long length; /* nbr of bytes to lock */
+ unsigned long long retRangeStart; /* nbr of 1st byte locked if successful */
+ unsigned char unLockFlag; /* 1 = unlock, 0 = lock */
+ unsigned char startEndFlag; /* 1=rel to end of fork, 0=rel to start */
+ int fd; /* file desc to assoc this lock with */
+};
+
+#define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2)
+
+/*
+** Return 0 on success, 1 on failure. To match the behavior of the
+** normal posix file locking (used in unixLock for example), we should
+** provide 'richer' return codes - specifically to differentiate between
+** 'file busy' and 'file system error' results.
+*/
+static int _AFPFSSetLock(
+ const char *path,
+ int fd,
+ unsigned long long offset,
+ unsigned long long length,
+ int setLockFlag
+){
+ struct ByteRangeLockPB2 pb;
+ int err;
+
+ pb.unLockFlag = setLockFlag ? 0 : 1;
+ pb.startEndFlag = 0;
+ pb.offset = offset;
+ pb.length = length;
+ pb.fd = fd;
+ OSTRACE5("AFPLOCK setting lock %s for %d in range %llx:%llx\n",
+ (setLockFlag?"ON":"OFF"), fd, offset, length);
+ err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0);
+ if ( err==-1 ) {
+ OSTRACE4("AFPLOCK failed to fsctl() '%s' %d %s\n", path, errno,
+ strerror(errno));
+ return 1; /* error */
+ } else {
+ return 0;
+ }
+}
+
+/*
+ ** This routine checks if there is a RESERVED lock held on the specified
+ ** file by this or any other process. If such a lock is held, return
+ ** non-zero. If the file is unlocked or holds only SHARED locks, then
+ ** return zero.
+ */
+static int afpUnixCheckReservedLock(sqlite3_file *id){
+ int r = 0;
+ unixFile *pFile = (unixFile*)id;
+
+ assert( pFile );
+ afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
+
+ /* Check if a thread in this process holds such a lock */
+ if( pFile->locktype>SHARED_LOCK ){
+ r = 1;
+ }
+
+ /* Otherwise see if some other process holds it.
+ */
+ if ( !r ) {
+ /* lock the byte */
+ int failed = _AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1,1);
+ if (failed) {
+ /* if we failed to get the lock then someone else must have it */
+ r = 1;
+ } else {
+ /* if we succeeded in taking the reserved lock, unlock it to restore
+ ** the original state */
+ _AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1, 0);
}
- zBuf[0] = 0;
- sqlite3SetString(&zFull, getcwd(zBuf, 5000), "/", zRelative,
- (char*)0);
- sqliteFree(zBuf);
}
+ OSTRACE3("TEST WR-LOCK %d %d\n", pFile->h, r);
+
+ return r;
+}
-#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;
+/* AFP-style locking following the behavior of unixLock, see the unixLock
+** function comments for details of lock management. */
+static int afpUnixLock(sqlite3_file *id, int locktype)
+{
+ int rc = SQLITE_OK;
+ unixFile *pFile = (unixFile*)id;
+ afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
+ int gotPendingLock = 0;
+
+ assert( pFile );
+ OSTRACE5("LOCK %d %s was %s pid=%d\n", pFile->h,
+ locktypeName(locktype), locktypeName(pFile->locktype), getpid());
+ /* If there is already a lock of this type or more restrictive on the
+ ** unixFile, do nothing. Don't use the afp_end_lock: exit path, as
+ ** enterMutex() hasn't been called yet.
+ */
+ if( pFile->locktype>=locktype ){
+ OSTRACE3("LOCK %d %s ok (already held)\n", pFile->h,
+ locktypeName(locktype));
+ return SQLITE_OK;
+ }
+
+ /* Make sure the locking sequence is correct
+ */
+ assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
+ assert( locktype!=PENDING_LOCK );
+ assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
+
+ /* This mutex is needed because pFile->pLock is shared across threads
+ */
+ enterMutex();
+
+ /* Make sure the current thread owns the pFile.
+ */
+ rc = transferOwnership(pFile);
+ if( rc!=SQLITE_OK ){
+ leaveMutex();
+ return rc;
+ }
+
+ /* A PENDING lock is needed before acquiring a SHARED lock and before
+ ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will
+ ** be released.
+ */
+ if( locktype==SHARED_LOCK
+ || (locktype==EXCLUSIVE_LOCK && pFile->locktype<PENDING_LOCK)
+ ){
+ int failed = _AFPFSSetLock(context->filePath, pFile->h,
+ PENDING_BYTE, 1, 1);
+ if (failed) {
+ rc = SQLITE_BUSY;
+ goto afp_end_lock;
+ }
+ }
+
+ /* If control gets to this point, then actually go ahead and make
+ ** operating system calls for the specified lock.
+ */
+ if( locktype==SHARED_LOCK ){
+ int lk, failed;
+ int tries = 0;
+
+ /* Now get the read-lock */
+ /* note that the quality of the randomness doesn't matter that much */
+ lk = random();
+ context->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1);
+ failed = _AFPFSSetLock(context->filePath, pFile->h,
+ SHARED_FIRST+context->sharedLockByte, 1, 1);
+
+ /* Drop the temporary PENDING lock */
+ if (_AFPFSSetLock(context->filePath, pFile->h, PENDING_BYTE, 1, 0)) {
+ rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
+ goto afp_end_lock;
+ }
+
+ if( failed ){
+ rc = SQLITE_BUSY;
+ } else {
+ pFile->locktype = SHARED_LOCK;
+ }
+ }else{
+ /* The request was for a RESERVED or EXCLUSIVE lock. It is
+ ** assumed that there is a SHARED or greater lock on the file
+ ** already.
+ */
+ int failed = 0;
+ assert( 0!=pFile->locktype );
+ if (locktype >= RESERVED_LOCK && pFile->locktype < RESERVED_LOCK) {
+ /* Acquire a RESERVED lock */
+ failed = _AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1,1);
+ }
+ if (!failed && locktype == EXCLUSIVE_LOCK) {
+ /* Acquire an EXCLUSIVE lock */
+
+ /* Remove the shared lock before trying the range. we'll need to
+ ** reestablish the shared lock if we can't get the afpUnixUnlock
+ */
+ if (!_AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST +
+ context->sharedLockByte, 1, 0)) {
+ /* now attemmpt to get the exclusive lock range */
+ failed = _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST,
+ SHARED_SIZE, 1);
+ if (failed && _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST +
+ context->sharedLockByte, 1, 1)) {
+ rc = SQLITE_IOERR_RDLOCK; /* this should never happen */
}
+ } else {
+ /* */
+ rc = SQLITE_IOERR_UNLOCK; /* this should never happen */
}
- zFull[j++] = zFull[i];
}
- zFull[j] = 0;
+ if( failed && rc == SQLITE_OK){
+ rc = SQLITE_BUSY;
+ }
}
-#endif
+
+ if( rc==SQLITE_OK ){
+ pFile->locktype = locktype;
+ }else if( locktype==EXCLUSIVE_LOCK ){
+ pFile->locktype = PENDING_LOCK;
+ }
+
+afp_end_lock:
+ leaveMutex();
+ OSTRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype),
+ rc==SQLITE_OK ? "ok" : "failed");
+ return rc;
+}
+
+/*
+ ** 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.
+ */
+static int afpUnixUnlock(sqlite3_file *id, int locktype) {
+ struct flock lock;
+ int rc = SQLITE_OK;
+ unixFile *pFile = (unixFile*)id;
+ afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
- return zFull;
+ assert( pFile );
+ OSTRACE5("UNLOCK %d %d was %d pid=%d\n", pFile->h, locktype,
+ pFile->locktype, getpid());
+
+ assert( locktype<=SHARED_LOCK );
+ if( pFile->locktype<=locktype ){
+ return SQLITE_OK;
+ }
+ if( CHECK_THREADID(pFile) ){
+ return SQLITE_MISUSE;
+ }
+ enterMutex();
+ if( pFile->locktype>SHARED_LOCK ){
+ if( locktype==SHARED_LOCK ){
+ int failed = 0;
+
+ /* unlock the exclusive range - then re-establish the shared lock */
+ if (pFile->locktype==EXCLUSIVE_LOCK) {
+ failed = _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST,
+ SHARED_SIZE, 0);
+ if (!failed) {
+ /* successfully removed the exclusive lock */
+ if (_AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST+
+ context->sharedLockByte, 1, 1)) {
+ /* failed to re-establish our shared lock */
+ rc = SQLITE_IOERR_RDLOCK; /* This should never happen */
+ }
+ } else {
+ /* This should never happen - failed to unlock the exclusive range */
+ rc = SQLITE_IOERR_UNLOCK;
+ }
+ }
+ }
+ if (rc == SQLITE_OK && pFile->locktype>=PENDING_LOCK) {
+ if (_AFPFSSetLock(context->filePath, pFile->h, PENDING_BYTE, 1, 0)){
+ /* failed to release the pending lock */
+ rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
+ }
+ }
+ if (rc == SQLITE_OK && pFile->locktype>=RESERVED_LOCK) {
+ if (_AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1, 0)) {
+ /* failed to release the reserved lock */
+ rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
+ }
+ }
+ }
+ if( locktype==NO_LOCK ){
+ int failed = _AFPFSSetLock(context->filePath, pFile->h,
+ SHARED_FIRST + context->sharedLockByte, 1, 0);
+ if (failed) {
+ rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
+ }
+ }
+ if (rc == SQLITE_OK)
+ pFile->locktype = locktype;
+ leaveMutex();
+ return rc;
+}
+
+/*
+ ** Close a file & cleanup AFP specific locking context
+ */
+static int afpUnixClose(sqlite3_file *id) {
+ unixFile *pFile = (unixFile*)pId;
+
+ if( !pFile ) return SQLITE_OK;
+ afpUnixUnlock(*pId, NO_LOCK);
+ /* free the AFP locking structure */
+ if (pFile->lockingContext != NULL) {
+ if (((afpLockingContext *)pFile->lockingContext)->filePath != NULL)
+ sqlite3_free(((afpLockingContext*)pFile->lockingContext)->filePath);
+ sqlite3_free(pFile->lockingContext);
+ }
+
+ if( pFile->dirfd>=0 ) close(pFile->dirfd);
+ pFile->dirfd = -1;
+ close(pFile->h);
+ OSTRACE2("CLOSE %-3d\n", pFile->h);
+ OpenCounter(-1);
+ return SQLITE_OK;
}
+
+#pragma mark flock() style locking
+
/*
-** Change the value of the fullsync flag in the given file descriptor.
+ ** The flockLockingContext is not used
+ */
+typedef void flockLockingContext;
+
+static int flockUnixCheckReservedLock(sqlite3_file *id) {
+ unixFile *pFile = (unixFile*)id;
+
+ if (pFile->locktype == RESERVED_LOCK) {
+ return 1; /* already have a reserved lock */
+ } else {
+ /* attempt to get the lock */
+ int rc = flock(pFile->h, LOCK_EX | LOCK_NB);
+ if (!rc) {
+ /* got the lock, unlock it */
+ flock(pFile->h, LOCK_UN);
+ return 0; /* no one has it reserved */
+ }
+ return 1; /* someone else might have it reserved */
+ }
+}
+
+static int flockUnixLock(sqlite3_file *id, int locktype) {
+ unixFile *pFile = (unixFile*)id;
+
+ /* if we already have a lock, it is exclusive.
+ ** Just adjust level and punt on outta here. */
+ if (pFile->locktype > NO_LOCK) {
+ pFile->locktype = locktype;
+ return SQLITE_OK;
+ }
+
+ /* grab an exclusive lock */
+ int rc = flock(pFile->h, LOCK_EX | LOCK_NB);
+ if (rc) {
+ /* didn't get, must be busy */
+ return SQLITE_BUSY;
+ } else {
+ /* got it, set the type and return ok */
+ pFile->locktype = locktype;
+ return SQLITE_OK;
+ }
+}
+
+static int flockUnixUnlock(sqlite3_file *id, int locktype) {
+ unixFile *pFile = (unixFile*)id;
+
+ assert( locktype<=SHARED_LOCK );
+
+ /* no-op if possible */
+ if( pFile->locktype==locktype ){
+ return SQLITE_OK;
+ }
+
+ /* shared can just be set because we always have an exclusive */
+ if (locktype==SHARED_LOCK) {
+ pFile->locktype = locktype;
+ return SQLITE_OK;
+ }
+
+ /* no, really, unlock. */
+ int rc = flock(pFile->h, LOCK_UN);
+ if (rc)
+ return SQLITE_IOERR_UNLOCK;
+ else {
+ pFile->locktype = NO_LOCK;
+ return SQLITE_OK;
+ }
+}
+
+/*
+ ** Close a file.
+ */
+static int flockUnixClose(sqlite3_file *pId) {
+ unixFile *pFile = (unixFile*)*pId;
+
+ if( !pFile ) return SQLITE_OK;
+ flockUnixUnlock(*pId, NO_LOCK);
+
+ if( pFile->dirfd>=0 ) close(pFile->dirfd);
+ pFile->dirfd = -1;
+ enterMutex();
+
+ close(pFile->h);
+ leaveMutex();
+ OSTRACE2("CLOSE %-3d\n", pFile->h);
+ OpenCounter(-1);
+ return SQLITE_OK;
+}
+
+#pragma mark Old-School .lock file based locking
+
+/*
+ ** The dotlockLockingContext structure contains all dotlock (.lock) lock
+ ** specific state
+ */
+typedef struct dotlockLockingContext dotlockLockingContext;
+struct dotlockLockingContext {
+ char *lockPath;
+};
+
+
+static int dotlockUnixCheckReservedLock(sqlite3_file *id) {
+ unixFile *pFile = (unixFile*)id;
+ dotlockLockingContext *context =
+ (dotlockLockingContext *) pFile->lockingContext;
+
+ if (pFile->locktype == RESERVED_LOCK) {
+ return 1; /* already have a reserved lock */
+ } else {
+ struct stat statBuf;
+ if (lstat(context->lockPath,&statBuf) == 0)
+ /* file exists, someone else has the lock */
+ return 1;
+ else
+ /* file does not exist, we could have it if we want it */
+ return 0;
+ }
+}
+
+static int dotlockUnixLock(sqlite3_file *id, int locktype) {
+ unixFile *pFile = (unixFile*)id;
+ dotlockLockingContext *context =
+ (dotlockLockingContext *) pFile->lockingContext;
+
+ /* if we already have a lock, it is exclusive.
+ ** Just adjust level and punt on outta here. */
+ if (pFile->locktype > NO_LOCK) {
+ pFile->locktype = locktype;
+
+ /* Always update the timestamp on the old file */
+ utimes(context->lockPath,NULL);
+ return SQLITE_OK;
+ }
+
+ /* check to see if lock file already exists */
+ struct stat statBuf;
+ if (lstat(context->lockPath,&statBuf) == 0){
+ return SQLITE_BUSY; /* it does, busy */
+ }
+
+ /* grab an exclusive lock */
+ int fd = open(context->lockPath,O_RDONLY|O_CREAT|O_EXCL,0600);
+ if (fd < 0) {
+ /* failed to open/create the file, someone else may have stolen the lock */
+ return SQLITE_BUSY;
+ }
+ close(fd);
+
+ /* got it, set the type and return ok */
+ pFile->locktype = locktype;
+ return SQLITE_OK;
+}
+
+static int dotlockUnixUnlock(sqlite3_file *id, int locktype) {
+ unixFile *pFile = (unixFile*)id;
+ dotlockLockingContext *context =
+ (dotlockLockingContext *) pFile->lockingContext;
+
+ assert( locktype<=SHARED_LOCK );
+
+ /* no-op if possible */
+ if( pFile->locktype==locktype ){
+ return SQLITE_OK;
+ }
+
+ /* shared can just be set because we always have an exclusive */
+ if (locktype==SHARED_LOCK) {
+ pFile->locktype = locktype;
+ return SQLITE_OK;
+ }
+
+ /* no, really, unlock. */
+ unlink(context->lockPath);
+ pFile->locktype = NO_LOCK;
+ return SQLITE_OK;
+}
+
+/*
+ ** Close a file.
+ */
+static int dotlockUnixClose(sqlite3_file *id) {
+ unixFile *pFile = (unixFile*)id;
+
+ if( !pFile ) return SQLITE_OK;
+ dotlockUnixUnlock(*pId, NO_LOCK);
+ /* free the dotlock locking structure */
+ if (pFile->lockingContext != NULL) {
+ if (((dotlockLockingContext *)pFile->lockingContext)->lockPath != NULL)
+ sqlite3_free( ( (dotlockLockingContext *)
+ pFile->lockingContext)->lockPath);
+ sqlite3_free(pFile->lockingContext);
+ }
+
+ if( pFile->dirfd>=0 ) close(pFile->dirfd);
+ pFile->dirfd = -1;
+ enterMutex();
+
+ close(pFile->h);
+
+ leaveMutex();
+ OSTRACE2("CLOSE %-3d\n", pFile->h);
+ OpenCounter(-1);
+ return SQLITE_OK;
+}
+
+
+#pragma mark No locking
+
+/*
+ ** The nolockLockingContext is void
+ */
+typedef void nolockLockingContext;
+
+static int nolockUnixCheckReservedLock(sqlite3_file *id) {
+ return 0;
+}
+
+static int nolockUnixLock(sqlite3_file *id, int locktype) {
+ return SQLITE_OK;
+}
+
+static int nolockUnixUnlock(sqlite3_file *id, int locktype) {
+ return SQLITE_OK;
+}
+
+/*
+ ** Close a file.
+ */
+static int nolockUnixClose(sqlite3_file *id) {
+ unixFile *pFile = (unixFile*)id;
+
+ if( !pFile ) return SQLITE_OK;
+ if( pFile->dirfd>=0 ) close(pFile->dirfd);
+ pFile->dirfd = -1;
+ enterMutex();
+
+ close(pFile->h);
+
+ leaveMutex();
+ OSTRACE2("CLOSE %-3d\n", pFile->h);
+ OpenCounter(-1);
+ return SQLITE_OK;
+}
+
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
+
+
+/*
+** Information and control of an open file handle.
*/
-static void unixSetFullSync(OsFile *id, int v){
- ((unixFile*)id)->fullSync = v;
+static int unixFileControl(sqlite3_file *id, int op, void *pArg){
+ switch( op ){
+ case SQLITE_FCNTL_LOCKSTATE: {
+ *(int*)pArg = ((unixFile*)id)->locktype;
+ return SQLITE_OK;
+ }
+ }
+ return SQLITE_ERROR;
}
/*
-** Return the underlying file handle for an OsFile
+** Return the sector size in bytes of the underlying block device for
+** the specified file. This is almost always 512 bytes, but may be
+** larger for some devices.
+**
+** SQLite code assumes this function cannot fail. It also assumes that
+** if two files are created in the same file-system directory (i.e.
+** a database and its journal file) that the sector size will be the
+** same for both.
*/
-static int unixFileHandle(OsFile *id){
- return ((unixFile*)id)->h;
+static int unixSectorSize(sqlite3_file *id){
+ return SQLITE_DEFAULT_SECTOR_SIZE;
}
/*
-** Return an integer that indices the type of lock currently held
-** by this handle. (Used for testing and analysis only.)
+** Return the device characteristics for the file. This is always 0.
*/
-static int unixLockState(OsFile *id){
- return ((unixFile*)id)->locktype;
+static int unixDeviceCharacteristics(sqlite3_file *id){
+ return 0;
}
/*
-** This vector defines all the methods that can operate on an OsFile
+** This vector defines all the methods that can operate on an sqlite3_file
** for unix.
*/
-static const IoMethod sqlite3UnixIoMethod = {
+static const sqlite3_io_methods sqlite3UnixIoMethod = {
+ 1, /* iVersion */
unixClose,
- unixOpenDirectory,
unixRead,
unixWrite,
- unixSeek,
unixTruncate,
unixSync,
- unixSetFullSync,
- unixFileHandle,
unixFileSize,
unixLock,
unixUnlock,
- unixLockState,
unixCheckReservedLock,
+ unixFileControl,
+ unixSectorSize,
+ unixDeviceCharacteristics
+};
+
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+/*
+** This vector defines all the methods that can operate on an sqlite3_file
+** for unix with AFP style file locking.
+*/
+static const sqlite3_io_methods sqlite3AFPLockingUnixIoMethod = {
+ 1, /* iVersion */
+ unixClose,
+ unixRead,
+ unixWrite,
+ unixTruncate,
+ unixSync,
+ unixFileSize,
+ afpUnixLock,
+ afpUnixUnlock,
+ afpUnixCheckReservedLock,
+ unixFileControl,
+ unixSectorSize,
+ unixDeviceCharacteristics
};
/*
-** 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.
+** This vector defines all the methods that can operate on an sqlite3_file
+** for unix with flock() style file locking.
*/
-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) );
+static const sqlite3_io_methods sqlite3FlockLockingUnixIoMethod = {
+ 1, /* iVersion */
+ flockUnixClose,
+ unixRead,
+ unixWrite,
+ unixTruncate,
+ unixSync,
+ unixFileSize,
+ flockUnixLock,
+ flockUnixUnlock,
+ flockUnixCheckReservedLock,
+ unixFileControl,
+ unixSectorSize,
+ unixDeviceCharacteristics
+};
+
+/*
+** This vector defines all the methods that can operate on an sqlite3_file
+** for unix with dotlock style file locking.
+*/
+static const sqlite3_io_methods sqlite3DotlockLockingUnixIoMethod = {
+ 1, /* iVersion */
+ dotlockUnixClose,
+ unixRead,
+ unixWrite,
+ unixTruncate,
+ unixSync,
+ unixFileSize,
+ dotlockUnixLock,
+ dotlockUnixUnlock,
+ dotlockUnixCheckReservedLock,
+ unixFileControl,
+ unixSectorSize,
+ unixDeviceCharacteristics
+};
+
+/*
+** This vector defines all the methods that can operate on an sqlite3_file
+** for unix with dotlock style file locking.
+*/
+static const sqlite3_io_methods sqlite3NolockLockingUnixIoMethod = {
+ 1, /* iVersion */
+ nolockUnixClose,
+ unixRead,
+ unixWrite,
+ unixTruncate,
+ unixSync,
+ unixFileSize,
+ nolockUnixLock,
+ nolockUnixUnlock,
+ nolockUnixCheckReservedLock,
+ unixFileControl,
+ unixSectorSize,
+ unixDeviceCharacteristics
+};
+
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
+
+/*
+** Allocate memory for a new unixFile and initialize that unixFile.
+** Write a pointer to the new unixFile into *pId.
+** If we run out of memory, close the file and return an error.
+*/
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+/*
+** When locking extensions are enabled, the filepath and locking style
+** are needed to determine the unixFile pMethod to use for locking operations.
+** The locking-style specific lockingContext data structure is created
+** and assigned here also.
+*/
+static int fillInUnixFile(
+ int h, /* Open file descriptor of file being opened */
+ int dirfd, /* Directory file descriptor */
+ sqlite3_file *pId, /* Write completed initialization here */
+ const char *zFilename, /* Name of the file being opened */
+){
+ sqlite3LockingStyle lockingStyle;
+ unixFile *pNew = (unixFile *)pId;
+ int rc;
+
+ memset(pNew, 0, sizeof(unixFile));
+ lockingStyle = sqlite3DetectLockingStyle(zFilename, h);
+ if ( lockingStyle == posixLockingStyle ) {
+ enterMutex();
+ rc = findLockInfo(h, &pNew->pLock, &pNew->pOpen);
+ leaveMutex();
+ if( rc ){
+ close(h);
+ unlink(zFilename);
+ return SQLITE_NOMEM;
+ }
+ } else {
+ /* pLock and pOpen are only used for posix advisory locking */
+ pNew->pLock = NULL;
+ pNew->pOpen = NULL;
+ }
+ pNew->dirfd = -1;
+ pNew->h = h;
+ SET_THREADID(pNew);
+ pNew = sqlite3_malloc( sizeof(unixFile) );
if( pNew==0 ){
- close(pInit->h);
- sqlite3OsEnterMutex();
- releaseLockInfo(pInit->pLock);
- releaseOpenCnt(pInit->pOpen);
- sqlite3OsLeaveMutex();
- *pId = 0;
+ close(h);
+ enterMutex();
+ releaseLockInfo(pNew->pLock);
+ releaseOpenCnt(pNew->pOpen);
+ leaveMutex();
return SQLITE_NOMEM;
}else{
- *pNew = *pInit;
- pNew->pMethod = &sqlite3UnixIoMethod;
- *pId = (OsFile*)pNew;
+ switch(lockingStyle) {
+ case afpLockingStyle: {
+ /* afp locking uses the file path so it needs to be included in
+ ** the afpLockingContext */
+ int nFilename;
+ pNew->pMethod = &sqlite3AFPLockingUnixIoMethod;
+ pNew->lockingContext =
+ sqlite3_malloc(sizeof(afpLockingContext));
+ nFilename = strlen(zFilename)+1;
+ ((afpLockingContext *)pNew->lockingContext)->filePath =
+ sqlite3_malloc(nFilename);
+ memcpy(((afpLockingContext *)pNew->lockingContext)->filePath,
+ zFilename, nFilename);
+ srandomdev();
+ break;
+ }
+ case flockLockingStyle:
+ /* flock locking doesn't need additional lockingContext information */
+ pNew->pMethod = &sqlite3FlockLockingUnixIoMethod;
+ break;
+ case dotlockLockingStyle: {
+ /* dotlock locking uses the file path so it needs to be included in
+ ** the dotlockLockingContext */
+ int nFilename;
+ pNew->pMethod = &sqlite3DotlockLockingUnixIoMethod;
+ pNew->lockingContext = sqlite3_malloc(
+ sizeof(dotlockLockingContext));
+ nFilename = strlen(zFilename) + 6;
+ ((dotlockLockingContext *)pNew->lockingContext)->lockPath =
+ sqlite3_malloc( nFilename );
+ sqlite3_snprintf(nFilename,
+ ((dotlockLockingContext *)pNew->lockingContext)->lockPath,
+ "%s.lock", zFilename);
+ break;
+ }
+ case posixLockingStyle:
+ /* posix locking doesn't need additional lockingContext information */
+ pNew->pMethod = &sqlite3UnixIoMethod;
+ break;
+ case noLockingStyle:
+ case unsupportedLockingStyle:
+ default:
+ pNew->pMethod = &sqlite3NolockLockingUnixIoMethod;
+ }
OpenCounter(+1);
return SQLITE_OK;
}
}
+#else /* SQLITE_ENABLE_LOCKING_STYLE */
+static int fillInUnixFile(
+ int h, /* Open file descriptor on file being opened */
+ int dirfd,
+ sqlite3_file *pId, /* Write to the unixFile structure here */
+ const char *zFilename /* Name of the file being opened */
+){
+ unixFile *pNew = (unixFile *)pId;
+ int rc;
+
+#ifdef FD_CLOEXEC
+ fcntl(h, F_SETFD, fcntl(h, F_GETFD, 0) | FD_CLOEXEC);
+#endif
+
+ enterMutex();
+ rc = findLockInfo(h, &pNew->pLock, &pNew->pOpen);
+ leaveMutex();
+ if( rc ){
+ if( dirfd>=0 ) close(dirfd);
+ close(h);
+ return SQLITE_NOMEM;
+ }
+
+ OSTRACE3("OPEN %-3d %s\n", h, zFilename);
+ pNew->dirfd = -1;
+ pNew->h = h;
+ pNew->dirfd = dirfd;
+ SET_THREADID(pNew);
+
+ pNew->pMethod = &sqlite3UnixIoMethod;
+ OpenCounter(+1);
+ return SQLITE_OK;
+}
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
+
+/*
+** Open a file descriptor to the directory containing file zFilename.
+** If successful, *pFd is set to the opened file descriptor and
+** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM
+** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined
+** value.
+**
+** If SQLITE_OK is returned, the caller is responsible for closing
+** the file descriptor *pFd using close().
+*/
+static int openDirectory(const char *zFilename, int *pFd){
+ int ii;
+ int fd = -1;
+ char zDirname[MAX_PATHNAME+1];
+
+ sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
+ for(ii=strlen(zDirname); ii>=0 && zDirname[ii]!='/'; ii--);
+ if( ii>0 ){
+ zDirname[ii] = '\0';
+ fd = open(zDirname, O_RDONLY|O_BINARY, 0);
+ if( fd>=0 ){
+#ifdef FD_CLOEXEC
+ fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
+#endif
+ OSTRACE3("OPENDIR %-3d %s\n", fd, zDirname);
+ }
+ }
+ *pFd = fd;
+ return (fd>=0?SQLITE_OK:SQLITE_CANTOPEN);
+}
+
+/*
+** Open the file zPath.
+**
+** Previously, the SQLite OS layer used three functions in place of this
+** one:
+**
+** sqlite3OsOpenReadWrite();
+** sqlite3OsOpenReadOnly();
+** sqlite3OsOpenExclusive();
+**
+** These calls correspond to the following combinations of flags:
+**
+** ReadWrite() -> (READWRITE | CREATE)
+** ReadOnly() -> (READONLY)
+** OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE)
+**
+** The old OpenExclusive() accepted a boolean argument - "delFlag". If
+** true, the file was configured to be automatically deleted when the
+** file handle closed. To achieve the same effect using this new
+** interface, add the DELETEONCLOSE flag to those specified above for
+** OpenExclusive().
+*/
+static int unixOpen(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ sqlite3_file *pFile,
+ int flags,
+ int *pOutFlags
+){
+ int fd = 0; /* File descriptor returned by open() */
+ int dirfd = -1; /* Directory file descriptor */
+ int oflags = 0; /* Flags to pass to open() */
+ int eType = flags&0xFFFFFF00; /* Type of file to open */
+
+ int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
+ int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
+ int isCreate = (flags & SQLITE_OPEN_CREATE);
+ int isReadonly = (flags & SQLITE_OPEN_READONLY);
+ int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
+
+ /* If creating a master or main-file journal, this function will open
+ ** a file-descriptor on the directory too. The first time unixSync()
+ ** is called the directory file descriptor will be fsync()ed and close()d.
+ */
+ int isOpenDirectory = (isCreate &&
+ (eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL)
+ );
+
+ /* Check the following statements are true:
+ **
+ ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
+ ** (b) if CREATE is set, then READWRITE must also be set, and
+ ** (c) if EXCLUSIVE is set, then CREATE must also be set.
+ ** (d) if DELETEONCLOSE is set, then CREATE must also be set.
+ */
+ assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
+ assert(isCreate==0 || isReadWrite);
+ assert(isExclusive==0 || isCreate);
+ assert(isDelete==0 || isCreate);
+
+
+ /* The main DB, main journal, and master journal are never automatically
+ ** deleted
+ */
+ assert( eType!=SQLITE_OPEN_MAIN_DB || !isDelete );
+ assert( eType!=SQLITE_OPEN_MAIN_JOURNAL || !isDelete );
+ assert( eType!=SQLITE_OPEN_MASTER_JOURNAL || !isDelete );
+
+ /* Assert that the upper layer has set one of the "file-type" flags. */
+ assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
+ || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
+ || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
+ || eType==SQLITE_OPEN_TRANSIENT_DB
+ );
+
+ if( isReadonly ) oflags |= O_RDONLY;
+ if( isReadWrite ) oflags |= O_RDWR;
+ if( isCreate ) oflags |= O_CREAT;
+ if( isExclusive ) oflags |= (O_EXCL|O_NOFOLLOW);
+ oflags |= (O_LARGEFILE|O_BINARY);
+
+ memset(pFile, 0, sizeof(unixFile));
+ fd = open(zPath, oflags, isDelete?0600:SQLITE_DEFAULT_FILE_PERMISSIONS);
+ if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
+ /* Failed to open the file for read/write access. Try read-only. */
+ flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
+ flags |= SQLITE_OPEN_READONLY;
+ return unixOpen(pVfs, zPath, pFile, flags, pOutFlags);
+ }
+ if( fd<0 ){
+ return SQLITE_CANTOPEN;
+ }
+ if( isDelete ){
+ unlink(zPath);
+ }
+ if( pOutFlags ){
+ *pOutFlags = flags;
+ }
+
+ assert(fd!=0);
+ if( isOpenDirectory ){
+ int rc = openDirectory(zPath, &dirfd);
+ if( rc!=SQLITE_OK ){
+ close(fd);
+ return rc;
+ }
+ }
+ return fillInUnixFile(fd, dirfd, pFile, zPath);
+}
+
+/*
+** Delete the file at zPath. If the dirSync argument is true, fsync()
+** the directory after deleting the file.
+*/
+static int unixDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+ int rc = SQLITE_OK;
+ SimulateIOError(return SQLITE_IOERR_DELETE);
+ unlink(zPath);
+ if( dirSync ){
+ int fd;
+ rc = openDirectory(zPath, &fd);
+ if( rc==SQLITE_OK ){
+ if( fsync(fd) ){
+ rc = SQLITE_IOERR_DIR_FSYNC;
+ }
+ close(fd);
+ }
+ }
+ return rc;
+}
+
+/*
+** Test the existance of or access permissions of file zPath. The
+** test performed depends on the value of flags:
+**
+** SQLITE_ACCESS_EXISTS: Return 1 if the file exists
+** SQLITE_ACCESS_READWRITE: Return 1 if the file is read and writable.
+** SQLITE_ACCESS_READONLY: Return 1 if the file is readable.
+**
+** Otherwise return 0.
+*/
+static int unixAccess(sqlite3_vfs *pVfs, const char *zPath, int flags){
+ int amode = 0;
+ switch( flags ){
+ case SQLITE_ACCESS_EXISTS:
+ amode = F_OK;
+ break;
+ case SQLITE_ACCESS_READWRITE:
+ amode = W_OK|R_OK;
+ break;
+ case SQLITE_ACCESS_READ:
+ amode = R_OK;
+ break;
+
+ default:
+ assert(!"Invalid flags argument");
+ }
+ return (access(zPath, amode)==0);
+}
+
+/*
+** Create a temporary file name in zBuf. zBuf must be allocated
+** by the calling process and must be big enough to hold at least
+** pVfs->mxPathname bytes.
+*/
+static int unixGetTempname(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+ static const char *azDirs[] = {
+ 0,
+ "/var/tmp",
+ "/usr/tmp",
+ "/tmp",
+ ".",
+ };
+ static const unsigned char zChars[] =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789";
+ int i, j;
+ struct stat buf;
+ const char *zDir = ".";
+
+ /* It's odd to simulate an io-error here, but really this is just
+ ** using the io-error infrastructure to test that SQLite handles this
+ ** function failing.
+ */
+ SimulateIOError( return SQLITE_ERROR );
+
+ azDirs[0] = sqlite3_temp_directory;
+ for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
+ if( azDirs[i]==0 ) continue;
+ if( stat(azDirs[i], &buf) ) continue;
+ if( !S_ISDIR(buf.st_mode) ) continue;
+ if( access(azDirs[i], 07) ) continue;
+ zDir = azDirs[i];
+ break;
+ }
+ if( strlen(zDir) - sizeof(SQLITE_TEMP_FILE_PREFIX) - 17 <=0 ){
+ return SQLITE_ERROR;
+ }
+ do{
+ assert( pVfs->mxPathname==MAX_PATHNAME );
+ sqlite3_snprintf(nBuf-17, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir);
+ 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;
+ }while( access(zBuf,0)==0 );
+ return SQLITE_OK;
+}
+
+
+/*
+** Turn a relative pathname into a full pathname. The relative path
+** is stored as a nul-terminated string in the buffer pointed to by
+** zPath.
+**
+** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes
+** (in this case, MAX_PATHNAME bytes). The full-path is written to
+** this buffer before returning.
+*/
+static int unixFullPathname(
+ sqlite3_vfs *pVfs, /* Pointer to vfs object */
+ const char *zPath, /* Possibly relative input path */
+ int nOut, /* Size of output buffer in bytes */
+ char *zOut /* Output buffer */
+){
+
+ /* It's odd to simulate an io-error here, but really this is just
+ ** using the io-error infrastructure to test that SQLite handles this
+ ** function failing. This function could fail if, for example, the
+ ** current working directly has been unlinked.
+ */
+ SimulateIOError( return SQLITE_ERROR );
+
+ assert( pVfs->mxPathname==MAX_PATHNAME );
+ zOut[nOut-1] = '\0';
+ if( zPath[0]=='/' ){
+ sqlite3_snprintf(nOut, zOut, "%s", zPath);
+ }else{
+ int nCwd;
+ if( getcwd(zOut, nOut-1)==0 ){
+ return SQLITE_CANTOPEN;
+ }
+ nCwd = strlen(zOut);
+ sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath);
+ }
+ return SQLITE_OK;
+
+#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
+}
-#endif /* SQLITE_OMIT_DISKIO */
-/***************************************************************************
-** Everything above deals with file I/O. Everything that follows deals
-** with other miscellanous aspects of the operating system interface
-****************************************************************************/
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+/*
+** Interfaces for opening a shared library, finding entry points
+** within the shared library, and closing the shared library.
+*/
+#include <dlfcn.h>
+static void *unixDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
+ return dlopen(zFilename, RTLD_NOW | RTLD_GLOBAL);
+}
+/*
+** SQLite calls this function immediately after a call to unixDlSym() or
+** unixDlOpen() fails (returns a null pointer). If a more detailed error
+** message is available, it is written to zBufOut. If no error message
+** is available, zBufOut is left unmodified and SQLite uses a default
+** error message.
+*/
+static void unixDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
+ char *zErr;
+ enterMutex();
+ zErr = dlerror();
+ if( zErr ){
+ sqlite3_snprintf(nBuf, zBufOut, "%s", zErr);
+ }
+ leaveMutex();
+}
+static void *unixDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
+ return dlsym(pHandle, zSymbol);
+}
+static void unixDlClose(sqlite3_vfs *pVfs, void *pHandle){
+ dlclose(pHandle);
+}
+#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
+ #define unixDlOpen 0
+ #define unixDlError 0
+ #define unixDlSym 0
+ #define unixDlClose 0
+#endif
/*
-** 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.
+** Write nBuf bytes of random data to the supplied buffer zBuf.
*/
-int sqlite3UnixRandomSeed(char *zBuf){
+static int unixRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+
+ assert(nBuf>=(sizeof(time_t)+sizeof(int)));
+
/* 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
@@ -1716,7 +2652,7 @@ int sqlite3UnixRandomSeed(char *zBuf){
** that we always use the same random number sequence. This makes the
** tests repeatable.
*/
- memset(zBuf, 0, 256);
+ memset(zBuf, 0, nBuf);
#if !defined(SQLITE_TEST)
{
int pid, fd;
@@ -1726,9 +2662,9 @@ int sqlite3UnixRandomSeed(char *zBuf){
time(&t);
memcpy(zBuf, &t, sizeof(t));
pid = getpid();
- memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid));
+ memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid));
}else{
- read(fd, zBuf, 256);
+ read(fd, zBuf, nBuf);
close(fd);
}
}
@@ -1736,224 +2672,23 @@ int sqlite3UnixRandomSeed(char *zBuf){
return SQLITE_OK;
}
+
/*
** Sleep for a little while. Return the amount of time slept.
-** The argument is the number of milliseconds we want to sleep.
+** The argument is the number of microseconds we want to sleep.
+** The return value is the number of microseconds of sleep actually
+** requested from the underlying operating system, a number which
+** might be greater than or equal to the argument, but not less
+** than the argument.
*/
-int sqlite3UnixSleep(int ms){
+static int unixSleep(sqlite3_vfs *pVfs, int microseconds){
#if defined(HAVE_USLEEP) && HAVE_USLEEP
- usleep(ms*1000);
- return ms;
+ usleep(microseconds);
+ return microseconds;
#else
- sleep((ms+999)/1000);
- return 1000*((ms+999)/1000);
-#endif
-}
-
-/*
-** 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_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
-
-/*
-** 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.
-**
-** As of version 3.3.2, this mutex must be recursive.
-*/
-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(&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
-}
-
-/*
-** 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
- 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;
+ int seconds = (microseconds+999999)/1000000;
+ sleep(seconds);
+ return seconds*1000000;
#endif
}
@@ -1970,15 +2705,14 @@ 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 sqlite3UnixCurrentTime(double *prNow){
+static int unixCurrentTime(sqlite3_vfs *pVfs, double *prNow){
#ifdef NO_GETTOD
time_t t;
time(&t);
*prNow = t/86400.0 + 2440587.5;
#else
struct timeval sNow;
- struct timezone sTz; /* Not used */
- gettimeofday(&sNow, &sTz);
+ gettimeofday(&sNow, 0);
*prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_usec/86400000000.0;
#endif
#ifdef SQLITE_TEST
@@ -1989,4 +2723,36 @@ int sqlite3UnixCurrentTime(double *prNow){
return 0;
}
+/*
+** Return a pointer to the sqlite3DefaultVfs structure. We use
+** a function rather than give the structure global scope because
+** some compilers (MSVC) do not allow forward declarations of
+** initialized structures.
+*/
+sqlite3_vfs *sqlite3OsDefaultVfs(void){
+ static sqlite3_vfs unixVfs = {
+ 1, /* iVersion */
+ sizeof(unixFile), /* szOsFile */
+ MAX_PATHNAME, /* mxPathname */
+ 0, /* pNext */
+ "unix", /* zName */
+ 0, /* pAppData */
+
+ unixOpen, /* xOpen */
+ unixDelete, /* xDelete */
+ unixAccess, /* xAccess */
+ unixGetTempname, /* xGetTempName */
+ unixFullPathname, /* xFullPathname */
+ unixDlOpen, /* xDlOpen */
+ unixDlError, /* xDlError */
+ unixDlSym, /* xDlSym */
+ unixDlClose, /* xDlClose */
+ unixRandomness, /* xRandomness */
+ unixSleep, /* xSleep */
+ unixCurrentTime /* xCurrentTime */
+ };
+
+ return &unixVfs;
+}
+
#endif /* OS_UNIX */
diff --git a/ext/pdo_sqlite/sqlite/src/os_win.c b/ext/pdo_sqlite/sqlite/src/os_win.c
index 6c167ab5b8..e5555f1275 100644
--- a/ext/pdo_sqlite/sqlite/src/os_win.c
+++ b/ext/pdo_sqlite/sqlite/src/os_win.c
@@ -13,9 +13,35 @@
** This file contains code that is specific to windows.
*/
#include "sqliteInt.h"
-#include "os.h"
#if OS_WIN /* This file is used for windows only */
+
+/*
+** A Note About Memory Allocation:
+**
+** This driver uses malloc()/free() directly rather than going through
+** the SQLite-wrappers sqlite3_malloc()/sqlite3_free(). Those wrappers
+** are designed for use on embedded systems where memory is scarce and
+** malloc failures happen frequently. Win32 does not typically run on
+** embedded systems, and when it does the developers normally have bigger
+** problems to worry about than running out of memory. So there is not
+** a compelling need to use the wrappers.
+**
+** But there is a good reason to not use the wrappers. If we use the
+** wrappers then we will get simulated malloc() failures within this
+** driver. And that causes all kinds of problems for our tests. We
+** could enhance SQLite to deal with simulated malloc failures within
+** the OS driver, but the code to deal with those failure would not
+** be exercised on Linux (which does not need to malloc() in the driver)
+** and so we would have difficulty writing coverage tests for that
+** code. Better to leave the code out, we think.
+**
+** The point of this discussion is as follows: When creating a new
+** OS layer for an embedded system, if you use this file as an example,
+** avoid the use of malloc()/free(). Those routines work ok on windows
+** desktops but not so well in embedded systems.
+*/
+
#include <winbase.h>
#ifdef __CYGWIN__
@@ -40,6 +66,7 @@
*/
#if defined(_WIN32_WCE)
# define OS_WINCE 1
+# define AreFileApisANSI() 1
#else
# define OS_WINCE 0
#endif
@@ -58,12 +85,12 @@ typedef struct winceLock {
#endif
/*
-** The winFile structure is a subclass of OsFile specific to the win32
+** The winFile structure is a subclass of sqlite3_file* specific to the win32
** portability layer.
*/
typedef struct winFile winFile;
struct winFile {
- IoMethod const *pMethod;/* Must be first */
+ const sqlite3_io_methods *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 */
@@ -78,13 +105,6 @@ struct winFile {
/*
-** 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)
-*/
-#ifndef SQLITE_OMIT_DISKIO
-
-/*
** The following variable is (normally) set once and never changes
** thereafter. It records whether the operating system is Win95
** or WinNT.
@@ -96,7 +116,11 @@ struct winFile {
** In order to facilitate testing on a WinNT system, the test fixture
** can manually set this value to 1 to emulate Win98 behavior.
*/
+#ifdef SQLITE_TEST
int sqlite3_os_type = 0;
+#else
+static int sqlite3_os_type = 0;
+#endif
/*
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
@@ -124,51 +148,134 @@ int sqlite3_os_type = 0;
#endif /* OS_WINCE */
/*
-** Convert a UTF-8 string to UTF-32. Space to hold the returned string
-** is obtained from sqliteMalloc.
+** Convert a UTF-8 string to microsoft unicode (UTF-16?).
+**
+** Space to hold the returned string is obtained from malloc.
*/
static WCHAR *utf8ToUnicode(const char *zFilename){
int nChar;
WCHAR *zWideFilename;
- if( !isNT() ){
- return 0;
- }
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
- zWideFilename = sqliteMalloc( nChar*sizeof(zWideFilename[0]) );
+ zWideFilename = malloc( nChar*sizeof(zWideFilename[0]) );
if( zWideFilename==0 ){
return 0;
}
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar);
if( nChar==0 ){
- sqliteFree(zWideFilename);
+ free(zWideFilename);
zWideFilename = 0;
}
return zWideFilename;
}
/*
-** Convert UTF-32 to UTF-8. Space to hold the returned string is
-** obtained from sqliteMalloc().
+** Convert microsoft unicode to UTF-8. Space to hold the returned string is
+** obtained from malloc().
*/
static char *unicodeToUtf8(const WCHAR *zWideFilename){
int nByte;
char *zFilename;
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
- zFilename = sqliteMalloc( nByte );
+ zFilename = malloc( nByte );
if( zFilename==0 ){
return 0;
}
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
0, 0);
if( nByte == 0 ){
- sqliteFree(zFilename);
+ free(zFilename);
+ zFilename = 0;
+ }
+ return zFilename;
+}
+
+/*
+** Convert an ansi string to microsoft unicode, based on the
+** current codepage settings for file apis.
+**
+** Space to hold the returned string is obtained
+** from malloc.
+*/
+static WCHAR *mbcsToUnicode(const char *zFilename){
+ int nByte;
+ WCHAR *zMbcsFilename;
+ int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
+
+ nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, NULL,0)*sizeof(WCHAR);
+ zMbcsFilename = malloc( nByte*sizeof(zMbcsFilename[0]) );
+ if( zMbcsFilename==0 ){
+ return 0;
+ }
+ nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename, nByte);
+ if( nByte==0 ){
+ free(zMbcsFilename);
+ zMbcsFilename = 0;
+ }
+ return zMbcsFilename;
+}
+
+/*
+** Convert microsoft unicode to multibyte character string, based on the
+** user's Ansi codepage.
+**
+** Space to hold the returned string is obtained from
+** malloc().
+*/
+static char *unicodeToMbcs(const WCHAR *zWideFilename){
+ int nByte;
+ char *zFilename;
+ int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
+
+ nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
+ zFilename = malloc( nByte );
+ if( zFilename==0 ){
+ return 0;
+ }
+ nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename, nByte,
+ 0, 0);
+ if( nByte == 0 ){
+ free(zFilename);
zFilename = 0;
}
return zFilename;
}
+/*
+** Convert multibyte character string to UTF-8. Space to hold the
+** returned string is obtained from malloc().
+*/
+static char *mbcsToUtf8(const char *zFilename){
+ char *zFilenameUtf8;
+ WCHAR *zTmpWide;
+
+ zTmpWide = mbcsToUnicode(zFilename);
+ if( zTmpWide==0 ){
+ return 0;
+ }
+ zFilenameUtf8 = unicodeToUtf8(zTmpWide);
+ free(zTmpWide);
+ return zFilenameUtf8;
+}
+
+/*
+** Convert UTF-8 to multibyte character string. Space to hold the
+** returned string is obtained from malloc().
+*/
+static char *utf8ToMbcs(const char *zFilename){
+ char *zFilenameMbcs;
+ WCHAR *zTmpWide;
+
+ zTmpWide = utf8ToUnicode(zFilename);
+ if( zTmpWide==0 ){
+ return 0;
+ }
+ zFilenameMbcs = unicodeToMbcs(zTmpWide);
+ free(zTmpWide);
+ return zFilenameMbcs;
+}
+
#if OS_WINCE
/*************************************************************************
** This section contains code for WinCE only.
@@ -183,7 +290,7 @@ struct tm *__cdecl localtime(const time_t *t)
static struct tm y;
FILETIME uTm, lTm;
SYSTEMTIME pTm;
- i64 t64;
+ sqlite3_int64 t64;
t64 = *t;
t64 = (t64 + 11644473600)*10000000;
uTm.dwLowDateTime = t64 & 0xFFFFFFFF;
@@ -245,7 +352,7 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
/* Create/open the named mutex */
pFile->hMutex = CreateMutexW(NULL, FALSE, zName);
if (!pFile->hMutex){
- sqliteFree(zName);
+ free(zName);
return FALSE;
}
@@ -267,7 +374,7 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
bInit = FALSE;
}
- sqliteFree(zName);
+ free(zName);
/* If we succeeded in making the shared memory handle, map it. */
if (pFile->hShared){
@@ -475,352 +582,10 @@ static BOOL winceLockFileEx(
*****************************************************************************/
#endif /* OS_WINCE */
-/*
-** 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.
-*/
-#define MX_DELETION_ATTEMPTS 3
-int sqlite3WinDelete(const char *zFilename){
- WCHAR *zWide = utf8ToUnicode(zFilename);
- int cnt = 0;
- int rc;
- if( zWide ){
- do{
- rc = DeleteFileW(zWide);
- }while( rc==0 && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
- sqliteFree(zWide);
- }else{
-#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 rc==0 ? SQLITE_OK : SQLITE_IOERR;
-}
-
-/*
-** Return TRUE if the named file exists.
-*/
-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,
-** 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 sqlite3WinOpenReadWrite(
- const char *zFilename,
- OsFile **pId,
- int *pReadonly
-){
- winFile f;
- HANDLE h;
- WCHAR *zWide = utf8ToUnicode(zFilename);
- assert( *pId==0 );
- if( zWide ){
- h = CreateFileW(zWide,
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
- NULL
- );
- if( h==INVALID_HANDLE_VALUE ){
- h = CreateFileW(zWide,
- GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
- NULL
- );
- if( h==INVALID_HANDLE_VALUE ){
- sqliteFree(zWide);
- return SQLITE_CANTOPEN;
- }
- *pReadonly = 1;
- }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,
- NULL,
- OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
- NULL
- );
- if( h==INVALID_HANDLE_VALUE ){
- h = CreateFileA(zFilename,
- GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
- NULL
- );
- if( h==INVALID_HANDLE_VALUE ){
- return SQLITE_CANTOPEN;
- }
- *pReadonly = 1;
- }else{
- *pReadonly = 0;
- }
-#endif /* OS_WINCE */
- }
- f.h = h;
-#if OS_WINCE
- f.zDeleteOnClose = 0;
-#endif
- TRACE3("OPEN R/W %d \"%s\"\n", h, zFilename);
- return allocateWinFile(&f, pId);
-}
-
-
-/*
-** 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.
-**
-** 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 sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
- winFile f;
- HANDLE h;
- int fileflags;
- WCHAR *zWide = utf8ToUnicode(zFilename);
- assert( *pId == 0 );
- fileflags = FILE_FLAG_RANDOM_ACCESS;
-#if !OS_WINCE
- if( delFlag ){
- fileflags |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE;
- }
-#endif
- if( zWide ){
- 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{
-#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;
- }
- 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 allocateWinFile(&f, pId);
-}
-
-/*
-** 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 sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){
- winFile f;
- HANDLE h;
- WCHAR *zWide = utf8ToUnicode(zFilename);
- assert( *pId==0 );
- if( zWide ){
- h = CreateFileW(zWide,
- GENERIC_READ,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
- NULL
- );
- sqliteFree(zWide);
- }else{
-#if OS_WINCE
- return SQLITE_NOMEM;
-#else
- h = CreateFileA(zFilename,
- GENERIC_READ,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
- NULL
- );
-#endif
- }
- if( h==INVALID_HANDLE_VALUE ){
- return SQLITE_CANTOPEN;
- }
- f.h = h;
-#if OS_WINCE
- f.zDeleteOnClose = 0;
- f.hMutex = NULL;
-#endif
- TRACE3("OPEN RO %d \"%s\"\n", h, zFilename);
- return allocateWinFile(&f, pId);
-}
-
-/*
-** 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.
-*/
-static int winOpenDirectory(
- OsFile *id,
- const char *zDirname
-){
- return SQLITE_OK;
-}
-
-/*
-** 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.
-*/
-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 sqlite3WinTempFileName(char *zBuf){
- static char zChars[] =
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "0123456789";
- int i, j;
- char zTempPath[SQLITE_TEMPNAME_SIZE];
- if( sqlite3_temp_directory ){
- strncpy(zTempPath, sqlite3_temp_directory, SQLITE_TEMPNAME_SIZE-30);
- zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
- }else if( isNT() ){
- char *zMulti;
- WCHAR zWidePath[SQLITE_TEMPNAME_SIZE];
- GetTempPathW(SQLITE_TEMPNAME_SIZE-30, zWidePath);
- zMulti = unicodeToUtf8(zWidePath);
- if( zMulti ){
- strncpy(zTempPath, zMulti, SQLITE_TEMPNAME_SIZE-30);
- zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
- sqliteFree(zMulti);
- }
- }else{
- GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zTempPath);
- }
- for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
- zTempPath[i] = 0;
- 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;
- }
- TRACE2("TEMP FILENAME: %s\n", zBuf);
- return SQLITE_OK;
-}
+/*****************************************************************************
+** The next group of routines implement the I/O methods specified
+** by the sqlite3_io_methods object.
+******************************************************************************/
/*
** Close a file.
@@ -833,46 +598,62 @@ int sqlite3WinTempFileName(char *zBuf){
** giving up and returning an error.
*/
#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) );
+static int winClose(sqlite3_file *id){
+ int rc, cnt = 0;
+ winFile *pFile = (winFile*)id;
+ OSTRACE2("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);
- sqliteFree(pFile);
- *pId = 0;
+ winceDestroyLock(pFile);
+ if( pFile->zDeleteOnClose ){
+ DeleteFileW(pFile->zDeleteOnClose);
+ free(pFile->zDeleteOnClose);
}
+#endif
+ OpenCounter(-1);
return rc ? SQLITE_OK : SQLITE_IOERR;
}
/*
+** Some microsoft compilers lack this definition.
+*/
+#ifndef INVALID_SET_FILE_POINTER
+# define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
+
+/*
** Read data from a file into a buffer. Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
-static int winRead(OsFile *id, void *pBuf, int amt){
+static int winRead(
+ sqlite3_file *id, /* File to read from */
+ void *pBuf, /* Write content into this buffer */
+ int amt, /* Number of bytes to read */
+ sqlite3_int64 offset /* Begin reading at this offset */
+){
+ LONG upperBits = (offset>>32) & 0x7fffffff;
+ LONG lowerBits = offset & 0xffffffff;
+ DWORD rc;
DWORD got;
+ winFile *pFile = (winFile*)id;
assert( id!=0 );
- SimulateIOError(SQLITE_IOERR);
- TRACE3("READ %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
- if( !ReadFile(((winFile*)id)->h, pBuf, amt, &got, 0) ){
- got = 0;
+ SimulateIOError(return SQLITE_IOERR_READ);
+ OSTRACE3("READ %d lock=%d\n", pFile->h, pFile->locktype);
+ rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
+ if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){
+ return SQLITE_FULL;
+ }
+ if( !ReadFile(pFile->h, pBuf, amt, &got, 0) ){
+ return SQLITE_IOERR_READ;
}
if( got==(DWORD)amt ){
return SQLITE_OK;
}else{
- return SQLITE_IOERR;
+ memset(&((char*)pBuf)[got], 0, amt-got);
+ return SQLITE_IOERR_SHORT_READ;
}
}
@@ -880,16 +661,31 @@ static int winRead(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.
*/
-static int winWrite(OsFile *id, const void *pBuf, int amt){
- int rc = 0;
+static int winWrite(
+ sqlite3_file *id, /* File to write into */
+ const void *pBuf, /* The bytes to be written */
+ int amt, /* Number of bytes to write */
+ sqlite3_int64 offset /* Offset into the file to begin writing at */
+){
+ LONG upperBits = (offset>>32) & 0x7fffffff;
+ LONG lowerBits = offset & 0xffffffff;
+ DWORD rc;
DWORD wrote;
+ winFile *pFile = (winFile*)id;
assert( id!=0 );
- SimulateIOError(SQLITE_IOERR);
- SimulateDiskfullError;
- TRACE3("WRITE %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
+ SimulateIOError(return SQLITE_IOERR_WRITE);
+ SimulateDiskfullError(return SQLITE_FULL);
+ OSTRACE3("WRITE %d lock=%d\n", pFile->h, pFile->locktype);
+ rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
+ if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){
+ return SQLITE_FULL;
+ }
assert( amt>0 );
- while( amt>0 && (rc = WriteFile(((winFile*)id)->h, pBuf, amt, &wrote, 0))!=0
- && wrote>0 ){
+ while(
+ amt>0
+ && (rc = WriteFile(pFile->h, pBuf, amt, &wrote, 0))!=0
+ && wrote>0
+ ){
amt -= wrote;
pBuf = &((char*)pBuf)[wrote];
}
@@ -900,39 +696,41 @@ static int winWrite(OsFile *id, const void *pBuf, int amt){
}
/*
-** Some microsoft compilers lack this definition.
+** Truncate an open file to a specified size
*/
-#ifndef INVALID_SET_FILE_POINTER
-# define INVALID_SET_FILE_POINTER ((DWORD)-1)
-#endif
+static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
+ LONG upperBits = (nByte>>32) & 0x7fffffff;
+ LONG lowerBits = nByte & 0xffffffff;
+ winFile *pFile = (winFile*)id;
+ OSTRACE3("TRUNCATE %d %lld\n", pFile->h, nByte);
+ SimulateIOError(return SQLITE_IOERR_TRUNCATE);
+ SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
+ SetEndOfFile(pFile->h);
+ return SQLITE_OK;
+}
+#ifdef SQLITE_TEST
/*
-** Move the read/write pointer in a file.
+** Count the number of fullsyncs and normal syncs. This is used to test
+** that syncs and fullsyncs are occuring at the right times.
*/
-static int winSeek(OsFile *id, i64 offset){
- LONG upperBits = offset>>32;
- LONG lowerBits = offset & 0xffffffff;
- DWORD rc;
- assert( id!=0 );
-#ifdef SQLITE_TEST
- if( offset ) SimulateDiskfullError
+int sqlite3_sync_count = 0;
+int sqlite3_fullsync_count = 0;
#endif
- SEEK(offset/1024 + 1);
- 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;
- }
- return SQLITE_OK;
-}
/*
** Make sure all writes to a particular file are committed to disk.
*/
-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) ){
+static int winSync(sqlite3_file *id, int flags){
+ winFile *pFile = (winFile*)id;
+ OSTRACE3("SYNC %d lock=%d\n", pFile->h, pFile->locktype);
+#ifdef SQLITE_TEST
+ if( flags & SQLITE_SYNC_FULL ){
+ sqlite3_fullsync_count++;
+ }
+ sqlite3_sync_count++;
+#endif
+ if( FlushFileBuffers(pFile->h) ){
return SQLITE_OK;
}else{
return SQLITE_IOERR;
@@ -940,36 +738,14 @@ static int winSync(OsFile *id, int dataOnly){
}
/*
-** Sync the directory zDirname. This is a no-op on operating systems other
-** than UNIX.
-*/
-int sqlite3WinSyncDirectory(const char *zDirname){
- SimulateIOError(SQLITE_IOERR);
- return SQLITE_OK;
-}
-
-/*
-** Truncate an open file to a specified size
-*/
-static int winTruncate(OsFile *id, i64 nByte){
- LONG upperBits = nByte>>32;
- assert( id!=0 );
- TRACE3("TRUNCATE %d %lld\n", ((winFile*)id)->h, nByte);
- SimulateIOError(SQLITE_IOERR);
- SetFilePointer(((winFile*)id)->h, nByte, &upperBits, FILE_BEGIN);
- SetEndOfFile(((winFile*)id)->h);
- return SQLITE_OK;
-}
-
-/*
** Determine the current size of a file in bytes
*/
-static int winFileSize(OsFile *id, i64 *pSize){
+static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
+ winFile *pFile = (winFile*)id;
DWORD upperBits, lowerBits;
- assert( id!=0 );
- SimulateIOError(SQLITE_IOERR);
- lowerBits = GetFileSize(((winFile*)id)->h, &upperBits);
- *pSize = (((i64)upperBits)<<32) + lowerBits;
+ SimulateIOError(return SQLITE_IOERR_FSTAT);
+ lowerBits = GetFileSize(pFile->h, &upperBits);
+ *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits;
return SQLITE_OK;
}
@@ -985,19 +761,20 @@ static int winFileSize(OsFile *id, i64 *pSize){
** Different API routines are called depending on whether or not this
** is Win95 or WinNT.
*/
-static int getReadLock(winFile *id){
+static int getReadLock(winFile *pFile){
int res;
if( isNT() ){
OVERLAPPED ovlp;
ovlp.Offset = SHARED_FIRST;
ovlp.OffsetHigh = 0;
ovlp.hEvent = 0;
- res = LockFileEx(id->h, LOCKFILE_FAIL_IMMEDIATELY, 0, SHARED_SIZE,0,&ovlp);
+ res = LockFileEx(pFile->h, LOCKFILE_FAIL_IMMEDIATELY,
+ 0, SHARED_SIZE, 0, &ovlp);
}else{
int lk;
sqlite3Randomness(sizeof(lk), &lk);
- id->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1);
- res = LockFile(id->h, SHARED_FIRST+id->sharedLockByte, 0, 1, 0);
+ pFile->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1);
+ res = LockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
}
return res;
}
@@ -1015,35 +792,6 @@ static int unlockReadLock(winFile *pFile){
return res;
}
-#ifndef SQLITE_OMIT_PAGER_PRAGMAS
-/*
-** Check that a given pathname is a directory and is writable
-**
-*/
-int sqlite3WinIsDirWritable(char *zDirname){
- int fileAttr;
- WCHAR *zWide;
- if( zDirname==0 ) return 0;
- if( !isNT() && strlen(zDirname)>MAX_PATH ) return 0;
- zWide = utf8ToUnicode(zDirname);
- if( zWide ){
- 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 ){
- return 0;
- }
- return 1;
-}
-#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
-
/*
** Lock the file with the lock specified by parameter locktype - one
** of the following:
@@ -1070,15 +818,15 @@ int sqlite3WinIsDirWritable(char *zDirname){
** It is not possible to lower the locking level one step at a time. You
** must go straight to locking level 0.
*/
-static int winLock(OsFile *id, int locktype){
+static int winLock(sqlite3_file *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 newLocktype; /* Set pFile->locktype to this value before exiting */
int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
winFile *pFile = (winFile*)id;
assert( pFile!=0 );
- TRACE5("LOCK %d %d was %d(%d)\n",
+ OSTRACE5("LOCK %d %d was %d(%d)\n",
pFile->h, locktype, pFile->locktype, pFile->sharedLockByte);
/* If there is already a lock of this type or more restrictive on the
@@ -1108,7 +856,7 @@ static int winLock(OsFile *id, int locktype){
/* Try 3 times to get the pending lock. The pending lock might be
** held by another reader process who will release it momentarily.
*/
- TRACE2("could not get a PENDING lock. cnt=%d\n", cnt);
+ OSTRACE2("could not get a PENDING lock. cnt=%d\n", cnt);
Sleep(1);
}
gotPendingLock = res;
@@ -1146,12 +894,13 @@ static int winLock(OsFile *id, int locktype){
if( locktype==EXCLUSIVE_LOCK && res ){
assert( pFile->locktype>=SHARED_LOCK );
res = unlockReadLock(pFile);
- TRACE2("unreadlock = %d\n", res);
+ OSTRACE2("unreadlock = %d\n", res);
res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
if( res ){
newLocktype = EXCLUSIVE_LOCK;
}else{
- TRACE2("error-code = %d\n", GetLastError());
+ OSTRACE2("error-code = %d\n", GetLastError());
+ getReadLock(pFile);
}
}
@@ -1168,7 +917,7 @@ static int winLock(OsFile *id, int locktype){
if( res ){
rc = SQLITE_OK;
}else{
- TRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
+ OSTRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
locktype, newLocktype);
rc = SQLITE_BUSY;
}
@@ -1181,20 +930,20 @@ static int winLock(OsFile *id, int locktype){
** file by this or any other process. If such a lock is held, return
** non-zero, otherwise zero.
*/
-static int winCheckReservedLock(OsFile *id){
+static int winCheckReservedLock(sqlite3_file *id){
int rc;
winFile *pFile = (winFile*)id;
assert( pFile!=0 );
if( pFile->locktype>=RESERVED_LOCK ){
rc = 1;
- TRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc);
+ OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc);
}else{
rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
if( rc ){
UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
}
rc = !rc;
- TRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc);
+ OSTRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc);
}
return rc;
}
@@ -1210,13 +959,13 @@ static int winCheckReservedLock(OsFile *id){
** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
** might return SQLITE_IOERR;
*/
-static int winUnlock(OsFile *id, int locktype){
+static int winUnlock(sqlite3_file *id, int locktype){
int type;
- int rc = SQLITE_OK;
winFile *pFile = (winFile*)id;
+ int rc = SQLITE_OK;
assert( pFile!=0 );
assert( locktype<=SHARED_LOCK );
- TRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
+ OSTRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
pFile->locktype, pFile->sharedLockByte);
type = pFile->locktype;
if( type>=EXCLUSIVE_LOCK ){
@@ -1224,7 +973,7 @@ static int winUnlock(OsFile *id, int locktype){
if( locktype==SHARED_LOCK && !getReadLock(pFile) ){
/* This should never happen. We should always be able to
** reacquire the read lock */
- rc = SQLITE_IOERR;
+ rc = SQLITE_IOERR_UNLOCK;
}
}
if( type>=RESERVED_LOCK ){
@@ -1241,216 +990,502 @@ static int winUnlock(OsFile *id, int locktype){
}
/*
-** 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.
+** Control and query of the open file handle.
*/
-char *sqlite3WinFullPathname(const char *zRelative){
- char *zFull;
-#if defined(__CYGWIN__)
- int nByte;
- 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;
- nByte = GetFullPathNameW(zWide, 0, 0, &zNotUsedW) + 1;
- zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) );
- if( zTemp==0 ) return 0;
- GetFullPathNameW(zWide, nByte, zTemp, &zNotUsedW);
- sqliteFree(zWide);
- zFull = unicodeToUtf8(zTemp);
- sqliteFree(zTemp);
- }else{
- nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1;
- zFull = sqliteMalloc( nByte*sizeof(zFull[0]) );
- if( zFull==0 ) return 0;
- GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed);
+static int winFileControl(sqlite3_file *id, int op, void *pArg){
+ switch( op ){
+ case SQLITE_FCNTL_LOCKSTATE: {
+ *(int*)pArg = ((winFile*)id)->locktype;
+ return SQLITE_OK;
+ }
}
-#endif
- return zFull;
+ return SQLITE_ERROR;
}
/*
-** 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
+** Return the sector size in bytes of the underlying block device for
+** the specified file. This is almost always 512 bytes, but may be
+** larger for some devices.
+**
+** SQLite code assumes this function cannot fail. It also assumes that
+** if two files are created in the same file-system directory (i.e.
+** a database and its journal file) that the sector size will be the
+** same for both.
*/
-static int winFileHandle(OsFile *id){
- return (int)((winFile*)id)->h;
+static int winSectorSize(sqlite3_file *id){
+ return SQLITE_DEFAULT_SECTOR_SIZE;
}
/*
-** Return an integer that indices the type of lock currently held
-** by this handle. (Used for testing and analysis only.)
+** Return a vector of device characteristics.
*/
-static int winLockState(OsFile *id){
- return ((winFile*)id)->locktype;
+static int winDeviceCharacteristics(sqlite3_file *id){
+ return 0;
}
/*
-** This vector defines all the methods that can operate on an OsFile
-** for win32.
+** This vector defines all the methods that can operate on an
+** sqlite3_file for win32.
*/
-static const IoMethod sqlite3WinIoMethod = {
+static const sqlite3_io_methods winIoMethod = {
+ 1, /* iVersion */
winClose,
- winOpenDirectory,
winRead,
winWrite,
- winSeek,
winTruncate,
winSync,
- winSetFullSync,
- winFileHandle,
winFileSize,
winLock,
winUnlock,
- winLockState,
winCheckReservedLock,
+ winFileControl,
+ winSectorSize,
+ winDeviceCharacteristics
};
+/***************************************************************************
+** Here ends the I/O methods that form the sqlite3_io_methods object.
+**
+** The next block of code implements the VFS methods.
+****************************************************************************/
+
/*
-** 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.
+** Convert a UTF-8 filename into whatever form the underlying
+** operating system wants filenames in. Space to hold the result
+** is obtained from malloc and must be freed by the calling
+** function.
*/
-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;
+static void *convertUtf8Filename(const char *zFilename){
+ void *zConverted = 0;
+ if( isNT() ){
+ zConverted = utf8ToUnicode(zFilename);
}else{
- *pNew = *pInit;
- pNew->pMethod = &sqlite3WinIoMethod;
- pNew->locktype = NO_LOCK;
- pNew->sharedLockByte = 0;
- *pId = (OsFile*)pNew;
- OpenCounter(+1);
- return SQLITE_OK;
+ zConverted = utf8ToMbcs(zFilename);
}
+ /* caller will handle out of memory */
+ return zConverted;
}
-
-#endif /* SQLITE_OMIT_DISKIO */
-/***************************************************************************
-** Everything above deals with file I/O. Everything that follows deals
-** with other miscellanous aspects of the operating system interface
-****************************************************************************/
-
/*
-** 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.
+** Open a file.
*/
-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
- ** 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);
- GetSystemTime((LPSYSTEMTIME)zBuf);
+static int winOpen(
+ sqlite3_vfs *pVfs, /* Not used */
+ const char *zName, /* Name of the file (UTF-8) */
+ sqlite3_file *id, /* Write the SQLite file handle here */
+ int flags, /* Open mode flags */
+ int *pOutFlags /* Status return flags */
+){
+ HANDLE h;
+ DWORD dwDesiredAccess;
+ DWORD dwShareMode;
+ DWORD dwCreationDisposition;
+ DWORD dwFlagsAndAttributes = 0;
+ int isTemp;
+ winFile *pFile = (winFile*)id;
+ void *zConverted = convertUtf8Filename(zName);
+ if( zConverted==0 ){
+ return SQLITE_NOMEM;
+ }
+
+ if( flags & SQLITE_OPEN_READWRITE ){
+ dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
+ }else{
+ dwDesiredAccess = GENERIC_READ;
+ }
+ if( flags & SQLITE_OPEN_CREATE ){
+ dwCreationDisposition = OPEN_ALWAYS;
+ }else{
+ dwCreationDisposition = OPEN_EXISTING;
+ }
+ if( flags & SQLITE_OPEN_MAIN_DB ){
+ dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ }else{
+ dwShareMode = 0;
+ }
+ if( flags & SQLITE_OPEN_DELETEONCLOSE ){
+#if OS_WINCE
+ dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN;
+#else
+ dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY
+ | FILE_ATTRIBUTE_HIDDEN
+ | FILE_FLAG_DELETE_ON_CLOSE;
+#endif
+ isTemp = 1;
+ }else{
+ dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
+ isTemp = 0;
+ }
+ /* Reports from the internet are that performance is always
+ ** better if FILE_FLAG_RANDOM_ACCESS is used. Ticket #2699. */
+ dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
+ if( isNT() ){
+ h = CreateFileW((WCHAR*)zConverted,
+ dwDesiredAccess,
+ dwShareMode,
+ NULL,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ NULL
+ );
+ }else{
+#if OS_WINCE
+ return SQLITE_NOMEM;
+#else
+ h = CreateFileA((char*)zConverted,
+ dwDesiredAccess,
+ dwShareMode,
+ NULL,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ NULL
+ );
+#endif
+ }
+ if( h==INVALID_HANDLE_VALUE ){
+ free(zConverted);
+ if( flags & SQLITE_OPEN_READWRITE ){
+ return winOpen(0, zName, id,
+ ((flags|SQLITE_OPEN_READONLY)&~SQLITE_OPEN_READWRITE), pOutFlags);
+ }else{
+ return SQLITE_CANTOPEN;
+ }
+ }
+ if( pOutFlags ){
+ if( flags & SQLITE_OPEN_READWRITE ){
+ *pOutFlags = SQLITE_OPEN_READWRITE;
+ }else{
+ *pOutFlags = SQLITE_OPEN_READONLY;
+ }
+ }
+ memset(pFile, 0, sizeof(*pFile));
+ pFile->pMethod = &winIoMethod;
+ pFile->h = h;
+#if OS_WINCE
+ if( (flags & (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)) ==
+ (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)
+ && !winceCreateLock(zName, pFile)
+ ){
+ CloseHandle(h);
+ free(zConverted);
+ return SQLITE_CANTOPEN;
+ }
+ if( isTemp ){
+ pFile->zDeleteOnClose = zConverted;
+ }else
+#endif
+ {
+ free(zConverted);
+ }
+ OpenCounter(+1);
return SQLITE_OK;
}
/*
-** Sleep for a little while. Return the amount of time slept.
+** 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 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 sqlite3WinSleep(int ms){
- Sleep(ms);
- return ms;
+#define MX_DELETION_ATTEMPTS 5
+static int winDelete(
+ sqlite3_vfs *pVfs, /* Not used on win32 */
+ const char *zFilename, /* Name of file to delete */
+ int syncDir /* Not used on win32 */
+){
+ int cnt = 0;
+ int rc;
+ void *zConverted = convertUtf8Filename(zFilename);
+ if( zConverted==0 ){
+ return SQLITE_NOMEM;
+ }
+ SimulateIOError(return SQLITE_IOERR_DELETE);
+ if( isNT() ){
+ do{
+ DeleteFileW(zConverted);
+ }while( (rc = GetFileAttributesW(zConverted))!=0xffffffff
+ && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
+ }else{
+#if OS_WINCE
+ return SQLITE_NOMEM;
+#else
+ do{
+ DeleteFileA(zConverted);
+ }while( (rc = GetFileAttributesA(zConverted))!=0xffffffff
+ && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
+#endif
+ }
+ free(zConverted);
+ OSTRACE2("DELETE \"%s\"\n", zFilename);
+ return rc==0xffffffff ? SQLITE_OK : SQLITE_IOERR_DELETE;
}
/*
-** Static variables used for thread synchronization
+** Check the existance and status of a file.
*/
-static int inMutex = 0;
-#ifdef SQLITE_W32_THREADS
- static DWORD mutexOwner;
- static CRITICAL_SECTION cs;
+static int winAccess(
+ sqlite3_vfs *pVfs, /* Not used on win32 */
+ const char *zFilename, /* Name of file to check */
+ int flags /* Type of test to make on this file */
+){
+ DWORD attr;
+ int rc;
+ void *zConverted = convertUtf8Filename(zFilename);
+ if( zConverted==0 ){
+ return SQLITE_NOMEM;
+ }
+ if( isNT() ){
+ attr = GetFileAttributesW((WCHAR*)zConverted);
+ }else{
+#if OS_WINCE
+ return SQLITE_NOMEM;
+#else
+ attr = GetFileAttributesA((char*)zConverted);
#endif
+ }
+ free(zConverted);
+ switch( flags ){
+ case SQLITE_ACCESS_READ:
+ case SQLITE_ACCESS_EXISTS:
+ rc = attr!=0xffffffff;
+ break;
+ case SQLITE_ACCESS_READWRITE:
+ rc = (attr & FILE_ATTRIBUTE_READONLY)==0;
+ break;
+ default:
+ assert(!"Invalid flags argument");
+ }
+ return rc;
+}
+
/*
-** 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.
+** Create a temporary file name in zBuf. zBuf must be big enough to
+** hold at pVfs->mxPathname characters.
*/
-void sqlite3WinEnterMutex(){
-#ifdef SQLITE_W32_THREADS
- static int isInit = 0;
- while( !isInit ){
- static long lock = 0;
- if( InterlockedIncrement(&lock)==1 ){
- InitializeCriticalSection(&cs);
- isInit = 1;
+static int winGetTempname(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+ static char zChars[] =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789";
+ int i, j;
+ char zTempPath[MAX_PATH+1];
+ if( sqlite3_temp_directory ){
+ sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory);
+ }else if( isNT() ){
+ char *zMulti;
+ WCHAR zWidePath[MAX_PATH];
+ GetTempPathW(MAX_PATH-30, zWidePath);
+ zMulti = unicodeToUtf8(zWidePath);
+ if( zMulti ){
+ sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti);
+ free(zMulti);
}else{
- Sleep(1);
+ return SQLITE_NOMEM;
+ }
+ }else{
+ char *zUtf8;
+ char zMbcsPath[MAX_PATH];
+ GetTempPathA(MAX_PATH-30, zMbcsPath);
+ zUtf8 = mbcsToUtf8(zMbcsPath);
+ if( zUtf8 ){
+ sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8);
+ free(zUtf8);
+ }else{
+ return SQLITE_NOMEM;
}
}
- EnterCriticalSection(&cs);
- mutexOwner = GetCurrentThreadId();
-#endif
- inMutex++;
+ for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
+ zTempPath[i] = 0;
+ sqlite3_snprintf(nBuf-30, zBuf,
+ "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath);
+ j = strlen(zBuf);
+ sqlite3Randomness(20, &zBuf[j]);
+ for(i=0; i<20; i++, j++){
+ zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
+ }
+ zBuf[j] = 0;
+ OSTRACE2("TEMP FILENAME: %s\n", zBuf);
+ return SQLITE_OK;
}
-void sqlite3WinLeaveMutex(){
- assert( inMutex );
- inMutex--;
-#ifdef SQLITE_W32_THREADS
- assert( mutexOwner==GetCurrentThreadId() );
- LeaveCriticalSection(&cs);
+
+/*
+** Turn a relative pathname into a full pathname. Write the full
+** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname
+** bytes in size.
+*/
+static int winFullPathname(
+ sqlite3_vfs *pVfs, /* Pointer to vfs object */
+ const char *zRelative, /* Possibly relative input path */
+ int nFull, /* Size of output buffer in bytes */
+ char *zFull /* Output buffer */
+){
+
+#if defined(__CYGWIN__)
+ cygwin_conv_to_full_win32_path(zRelative, zFull);
+ return SQLITE_OK;
+#endif
+
+#if OS_WINCE
+ /* WinCE has no concept of a relative pathname, or so I am told. */
+ sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zRelative);
+ return SQLITE_OK;
+#endif
+
+#if !OS_WINCE && !defined(__CYGWIN__)
+ int nByte;
+ void *zConverted;
+ char *zOut;
+ zConverted = convertUtf8Filename(zRelative);
+ if( isNT() ){
+ WCHAR *zTemp;
+ nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, 0) + 3;
+ zTemp = malloc( nByte*sizeof(zTemp[0]) );
+ if( zTemp==0 ){
+ free(zConverted);
+ return SQLITE_NOMEM;
+ }
+ GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, 0);
+ free(zConverted);
+ zOut = unicodeToUtf8(zTemp);
+ free(zTemp);
+ }else{
+ char *zTemp;
+ nByte = GetFullPathNameA((char*)zConverted, 0, 0, 0) + 3;
+ zTemp = malloc( nByte*sizeof(zTemp[0]) );
+ if( zTemp==0 ){
+ free(zConverted);
+ return SQLITE_NOMEM;
+ }
+ GetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
+ free(zConverted);
+ zOut = mbcsToUtf8(zTemp);
+ free(zTemp);
+ }
+ if( zOut ){
+ sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zOut);
+ free(zOut);
+ return SQLITE_OK;
+ }else{
+ return SQLITE_NOMEM;
+ }
#endif
}
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
-** 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.
+** Interfaces for opening a shared library, finding entry points
+** within the shared library, and closing the shared library.
+*/
+/*
+** Interfaces for opening a shared library, finding entry points
+** within the shared library, and closing the shared library.
*/
-int sqlite3WinInMutex(int thisThreadOnly){
-#ifdef SQLITE_W32_THREADS
- return inMutex>0 && (thisThreadOnly==0 || mutexOwner==GetCurrentThreadId());
+static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
+ HANDLE h;
+ void *zConverted = convertUtf8Filename(zFilename);
+ if( zConverted==0 ){
+ return 0;
+ }
+ if( isNT() ){
+ h = LoadLibraryW((WCHAR*)zConverted);
+ }else{
+#if OS_WINCE
+ return 0;
#else
- return inMutex>0;
+ h = LoadLibraryA((char*)zConverted);
#endif
+ }
+ free(zConverted);
+ return (void*)h;
}
+static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
+#if OS_WINCE
+ int error = GetLastError();
+ if( error>0x7FFFFFF ){
+ sqlite3_snprintf(nBuf, zBufOut, "OsError 0x%x", error);
+ }else{
+ sqlite3_snprintf(nBuf, zBufOut, "OsError %d", error);
+ }
+#else
+ FormatMessageA(
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError(),
+ 0,
+ zBufOut,
+ nBuf-1,
+ 0
+ );
+#endif
+}
+void *winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
+#if OS_WINCE
+ /* The GetProcAddressA() routine is only available on wince. */
+ return GetProcAddressA((HANDLE)pHandle, zSymbol);
+#else
+ /* All other windows platforms expect GetProcAddress() to take
+ ** an Ansi string regardless of the _UNICODE setting */
+ return GetProcAddress((HANDLE)pHandle, zSymbol);
+#endif
+}
+void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
+ FreeLibrary((HANDLE)pHandle);
+}
+#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
+ #define winDlOpen 0
+ #define winDlError 0
+ #define winDlSym 0
+ #define winDlClose 0
+#endif
/*
+** Write up to nBuf bytes of randomness into zBuf.
+*/
+static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+ int n = 0;
+ if( sizeof(SYSTEMTIME)<=nBuf-n ){
+ SYSTEMTIME x;
+ GetSystemTime(&x);
+ memcpy(&zBuf[n], &x, sizeof(x));
+ n += sizeof(x);
+ }
+ if( sizeof(DWORD)<=nBuf-n ){
+ DWORD pid = GetCurrentProcessId();
+ memcpy(&zBuf[n], &pid, sizeof(pid));
+ n += sizeof(pid);
+ }
+ if( sizeof(DWORD)<=nBuf-n ){
+ DWORD cnt = GetTickCount();
+ memcpy(&zBuf[n], &cnt, sizeof(cnt));
+ n += sizeof(cnt);
+ }
+ if( sizeof(LARGE_INTEGER)<=nBuf-n ){
+ LARGE_INTEGER i;
+ QueryPerformanceCounter(&i);
+ memcpy(&zBuf[n], &i, sizeof(i));
+ n += sizeof(i);
+ }
+ return n;
+}
+
+
+/*
+** Sleep for a little while. Return the amount of time slept.
+*/
+static int winSleep(sqlite3_vfs *pVfs, int microsec){
+ Sleep((microsec+999)/1000);
+ return ((microsec+999)/1000)*1000;
+}
+
+/*
** The following variable, if set to a non-zero value, becomes the result
** returned from sqlite3OsCurrentTime(). This is used for testing.
*/
@@ -1463,7 +1498,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 sqlite3WinCurrentTime(double *prNow){
+int winCurrentTime(sqlite3_vfs *pVfs, 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).
@@ -1486,71 +1521,37 @@ int sqlite3WinCurrentTime(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.
+** Return a pointer to the sqlite3DefaultVfs structure. We use
+** a function rather than give the structure global scope because
+** some compilers (MSVC) do not allow forward declarations of
+** initialized structures.
*/
-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;
+sqlite3_vfs *sqlite3OsDefaultVfs(void){
+ static sqlite3_vfs winVfs = {
+ 1, /* iVersion */
+ sizeof(winFile), /* szOsFile */
+ MAX_PATH, /* mxPathname */
+ 0, /* pNext */
+ "win32", /* zName */
+ 0, /* pAppData */
+
+ winOpen, /* xOpen */
+ winDelete, /* xDelete */
+ winAccess, /* xAccess */
+ winGetTempname, /* xGetTempName */
+ winFullPathname, /* xFullPathname */
+ winDlOpen, /* xDlOpen */
+ winDlError, /* xDlError */
+ winDlSym, /* xDlSym */
+ winDlClose, /* xDlClose */
+ winRandomness, /* xRandomness */
+ winSleep, /* xSleep */
+ winCurrentTime /* xCurrentTime */
+ };
+
+ return &winVfs;
}
+
#endif /* OS_WIN */
diff --git a/ext/pdo_sqlite/sqlite/src/pager.c b/ext/pdo_sqlite/sqlite/src/pager.c
index 7f4b6f952f..ef7683db89 100644
--- a/ext/pdo_sqlite/sqlite/src/pager.c
+++ b/ext/pdo_sqlite/sqlite/src/pager.c
@@ -22,8 +22,6 @@
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
-#include "os.h"
-#include "pager.h"
#include <assert.h>
#include <string.h>
@@ -31,26 +29,27 @@
** Macros for troubleshooting. Normally turned off
*/
#if 0
-#define TRACE1(X) sqlite3DebugPrintf(X)
-#define TRACE2(X,Y) sqlite3DebugPrintf(X,Y)
-#define TRACE3(X,Y,Z) sqlite3DebugPrintf(X,Y,Z)
-#define TRACE4(X,Y,Z,W) sqlite3DebugPrintf(X,Y,Z,W)
-#define TRACE5(X,Y,Z,W,V) sqlite3DebugPrintf(X,Y,Z,W,V)
+#define sqlite3DebugPrintf printf
+#define PAGERTRACE1(X) sqlite3DebugPrintf(X)
+#define PAGERTRACE2(X,Y) sqlite3DebugPrintf(X,Y)
+#define PAGERTRACE3(X,Y,Z) sqlite3DebugPrintf(X,Y,Z)
+#define PAGERTRACE4(X,Y,Z,W) sqlite3DebugPrintf(X,Y,Z,W)
+#define PAGERTRACE5(X,Y,Z,W,V) sqlite3DebugPrintf(X,Y,Z,W,V)
#else
-#define TRACE1(X)
-#define TRACE2(X,Y)
-#define TRACE3(X,Y,Z)
-#define TRACE4(X,Y,Z,W)
-#define TRACE5(X,Y,Z,W,V)
+#define PAGERTRACE1(X)
+#define PAGERTRACE2(X,Y)
+#define PAGERTRACE3(X,Y,Z)
+#define PAGERTRACE4(X,Y,Z,W)
+#define PAGERTRACE5(X,Y,Z,W,V)
#endif
/*
-** The following two macros are used within the TRACEX() macros above
+** The following two macros are used within the PAGERTRACEX() macros above
** 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.
+** PAGERID() takes a pointer to a Pager struct as its argument. The
+** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file
+** struct as its argument.
*/
#define PAGERID(p) ((int)(p->fd))
#define FILEHANDLEID(fd) ((int)fd)
@@ -84,21 +83,24 @@
** PAGER_SYNCED The pager moves to this state from PAGER_EXCLUSIVE
** after all dirty pages have been written to the
** database file and the file has been synced to
-** disk. All that remains to do is to remove the
-** journal file and the transaction will be
-** committed.
+** disk. All that remains to do is to remove or
+** truncate the journal file and the transaction
+** will be committed.
**
** The page cache comes up in PAGER_UNLOCK. The first time a
-** sqlite3pager_get() occurs, the state transitions to PAGER_SHARED.
+** sqlite3PagerGet() occurs, the state transitions to PAGER_SHARED.
** After all pages have been released using sqlite_page_unref(),
** the state transitions back to PAGER_UNLOCK. The first time
-** that sqlite3pager_write() is called, the state transitions to
-** PAGER_RESERVED. (Note that sqlite_page_write() can only be
+** that sqlite3PagerWrite() is called, the state transitions to
+** PAGER_RESERVED. (Note that sqlite3PagerWrite() can only be
** called on an outstanding page which means that the pager must
** be in PAGER_SHARED before it transitions to PAGER_RESERVED.)
-** The transition to PAGER_EXCLUSIVE occurs when before any changes
-** are made to the database file. After an sqlite3pager_rollback()
-** or sqlite_pager_commit(), the state goes back to PAGER_SHARED.
+** PAGER_RESERVED means that there is an open rollback journal.
+** The transition to PAGER_EXCLUSIVE occurs before any changes
+** are made to the database file, though writes to the rollback
+** journal occurs with just PAGER_RESERVED. After an sqlite3PagerRollback()
+** or sqlite3PagerCommitPhaseTwo(), the state can go back to PAGER_SHARED,
+** or it can stay at PAGER_EXCLUSIVE if we are in exclusive access mode.
*/
#define PAGER_UNLOCK 0
#define PAGER_SHARED 1 /* same as SHARED_LOCK */
@@ -129,13 +131,47 @@
*/
#define FORCE_ALIGNMENT(X) (((X)+7)&~7)
+typedef struct PgHdr PgHdr;
+
+/*
+** Each pager stores all currently unreferenced pages in a list sorted
+** in least-recently-used (LRU) order (i.e. the first item on the list has
+** not been referenced in a long time, the last item has been recently
+** used). An instance of this structure is included as part of each
+** pager structure for this purpose (variable Pager.lru).
+**
+** Additionally, if memory-management is enabled, all unreferenced pages
+** are stored in a global LRU list (global variable sqlite3LruPageList).
+**
+** In both cases, the PagerLruList.pFirstSynced variable points to
+** the first page in the corresponding list that does not require an
+** fsync() operation before its memory can be reclaimed. If no such
+** page exists, PagerLruList.pFirstSynced is set to NULL.
+*/
+typedef struct PagerLruList PagerLruList;
+struct PagerLruList {
+ PgHdr *pFirst; /* First page in LRU list */
+ PgHdr *pLast; /* Last page in LRU list (the most recently used) */
+ PgHdr *pFirstSynced; /* First page in list with PgHdr.needSync==0 */
+};
+
+/*
+** The following structure contains the next and previous pointers used
+** to link a PgHdr structure into a PagerLruList linked list.
+*/
+typedef struct PagerLruLink PagerLruLink;
+struct PagerLruLink {
+ PgHdr *pNext;
+ PgHdr *pPrev;
+};
+
/*
** Each in-memory image of a page begins with the following header.
** This header is only visible to this pager module. The client
** code that calls pager sees only the data that follows the header.
**
-** Client code should call sqlite3pager_write() on a page prior to making
-** any modifications to that page. The first time sqlite3pager_write()
+** Client code should call sqlite3PagerWrite() on a page prior to making
+** any modifications to that page. The first time sqlite3PagerWrite()
** is called, the original page contents are written into the rollback
** journal and PgHdr.inJournal and PgHdr.needSync are set. Later, once
** the journal page has made it onto the disk surface, PgHdr.needSync
@@ -143,31 +179,103 @@
** database file until the journal pages has been synced to disk and the
** PgHdr.needSync has been cleared.
**
-** The PgHdr.dirty flag is set when sqlite3pager_write() is called and
+** The PgHdr.dirty flag is set when sqlite3PagerWrite() is called and
** is cleared again when the page content is written back to the original
** database file.
+**
+** Details of important structure elements:
+**
+** needSync
+**
+** If this is true, this means that it is not safe to write the page
+** content to the database because the original content needed
+** for rollback has not by synced to the main rollback journal.
+** The original content may have been written to the rollback journal
+** but it has not yet been synced. So we cannot write to the database
+** file because power failure might cause the page in the journal file
+** to never reach the disk. It is as if the write to the journal file
+** does not occur until the journal file is synced.
+**
+** This flag is false if the page content exactly matches what
+** currently exists in the database file. The needSync flag is also
+** false if the original content has been written to the main rollback
+** journal and synced. If the page represents a new page that has
+** been added onto the end of the database during the current
+** transaction, the needSync flag is true until the original database
+** size in the journal header has been synced to disk.
+**
+** inJournal
+**
+** This is true if the original page has been written into the main
+** rollback journal. This is always false for new pages added to
+** the end of the database file during the current transaction.
+** And this flag says nothing about whether or not the journal
+** has been synced to disk. For pages that are in the original
+** database file, the following expression should always be true:
+**
+** inJournal = (pPager->aInJournal[(pgno-1)/8] & (1<<((pgno-1)%8))!=0
+**
+** The pPager->aInJournal[] array is only valid for the original
+** pages of the database, not new pages that are added to the end
+** of the database, so obviously the above expression cannot be
+** valid for new pages. For new pages inJournal is always 0.
+**
+** dirty
+**
+** When true, this means that the content of the page has been
+** modified and needs to be written back to the database file.
+** If false, it means that either the content of the page is
+** unchanged or else the content is unimportant and we do not
+** care whether or not it is preserved.
+**
+** alwaysRollback
+**
+** This means that the sqlite3PagerDontRollback() API should be
+** ignored for this page. The DontRollback() API attempts to say
+** that the content of the page on disk is unimportant (it is an
+** unused page on the freelist) so that it is unnecessary to
+** rollback changes to this page because the content of the page
+** can change without changing the meaning of the database. This
+** flag overrides any DontRollback() attempt. This flag is set
+** when a page that originally contained valid data is added to
+** the freelist. Later in the same transaction, this page might
+** be pulled from the freelist and reused for something different
+** and at that point the DontRollback() API will be called because
+** pages taken from the freelist do not need to be protected by
+** the rollback journal. But this flag says that the page was
+** not originally part of the freelist so that it still needs to
+** be rolled back in spite of any subsequent DontRollback() calls.
+**
+** needRead
+**
+** This flag means (when true) that the content of the page has
+** not yet been loaded from disk. The in-memory content is just
+** garbage. (Actually, we zero the content, but you should not
+** make any assumptions about the content nevertheless.) If the
+** content is needed in the future, it should be read from the
+** original database file.
*/
-typedef struct PgHdr PgHdr;
struct PgHdr {
Pager *pPager; /* The pager to which this page belongs */
Pgno pgno; /* The page number for this page */
PgHdr *pNextHash, *pPrevHash; /* Hash collision chain for PgHdr.pgno */
- PgHdr *pNextFree, *pPrevFree; /* Freelist of pages where nRef==0 */
+ PagerLruLink free; /* Next and previous free pages */
PgHdr *pNextAll; /* A list of all pages */
- PgHdr *pNextStmt, *pPrevStmt; /* List of pages in the statement journal */
u8 inJournal; /* TRUE if has been written to journal */
- u8 inStmt; /* TRUE if in the statement subjournal */
u8 dirty; /* TRUE if we need to write back changes */
u8 needSync; /* Sync journal before writing this page */
- u8 alwaysRollback; /* Disable dont_rollback() for this page */
+ u8 alwaysRollback; /* Disable DontRollback() for this page */
+ u8 needRead; /* Read content if PagerWrite() is called */
short int nRef; /* Number of users of this page */
PgHdr *pDirty, *pPrevDirty; /* Dirty pages */
- u32 notUsed; /* Buffer space */
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ PagerLruLink gfree; /* Global list of nRef==0 pages */
+#endif
#ifdef SQLITE_CHECK_PAGES
u32 pageHash;
#endif
- /* pPager->pageSize bytes of page data follow this header */
- /* Pager.nExtra bytes of local data follow the page data */
+ void *pData; /* Page data */
+ /* Pager.nExtra bytes of local data appended to this header */
};
/*
@@ -185,6 +293,8 @@ typedef struct PgHistory PgHistory;
struct PgHistory {
u8 *pOrig; /* Original page text. Restore to this on a full rollback */
u8 *pStmt; /* Text as it was at the beginning of the current statement */
+ PgHdr *pNextStmt, *pPrevStmt; /* List of pages in the statement journal */
+ u8 inStmt; /* TRUE if in the statement subjournal */
};
/*
@@ -202,24 +312,24 @@ struct PgHistory {
** Convert a pointer to a PgHdr into a pointer to its data
** and back again.
*/
-#define PGHDR_TO_DATA(P) ((void*)(&(P)[1]))
-#define DATA_TO_PGHDR(D) (&((PgHdr*)(D))[-1])
-#define PGHDR_TO_EXTRA(G,P) ((void*)&((char*)(&(G)[1]))[(P)->pageSize])
+#define PGHDR_TO_DATA(P) ((P)->pData)
+#define PGHDR_TO_EXTRA(G,P) ((void*)&((G)[1]))
#define PGHDR_TO_HIST(P,PGR) \
- ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->pageSize+(PGR)->nExtra])
+ ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->nExtra])
/*
** A open page cache is an instance of the following structure.
**
-** Pager.errCode may be set to SQLITE_IOERR, SQLITE_CORRUPT, SQLITE_PROTOCOL
+** Pager.errCode may be set to SQLITE_IOERR, SQLITE_CORRUPT, or
** 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()
+** SQLITE_FULL does not affect the sqlite3PagerGet() and sqlite3PagerLookup()
** APIs, they may still be used successfully.
*/
struct Pager {
+ sqlite3_vfs *pVfs; /* OS functions to use for IO */
u8 journalOpen; /* True if journal file descriptors is valid */
u8 journalStarted; /* True if header of journal is synced */
u8 useJournal; /* Use a rollback journal on this file */
@@ -229,16 +339,20 @@ 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 sync_flags; /* One of SYNC_NORMAL or SYNC_FULL */
u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */
- 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 */
u8 dirtyCache; /* True if cached pages have changed */
- u8 alwaysRollback; /* Disable dont_rollback() for all pages */
+ u8 alwaysRollback; /* Disable DontRollback() for all pages */
u8 memDb; /* True to inhibit all file I/O */
u8 setMaster; /* True if a m-j name has been written to jrnl */
+ u8 doNotSync; /* Boolean. While true, do not spill the cache */
+ u8 exclusiveMode; /* Boolean. True if locking_mode==EXCLUSIVE */
+ u8 changeCountDone; /* Set after incrementing the change-counter */
+ u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */
+ int errCode; /* One of several kinds of errors */
int dbSize; /* Number of pages in the file */
int origDbSize; /* dbSize before the current change */
int stmtSize; /* Size of database (in pages) at stmt_begin() */
@@ -248,19 +362,19 @@ struct Pager {
int nExtra; /* Add this many bytes to each in-memory page */
int pageSize; /* Number of bytes in a page */
int nPage; /* Total number of in-memory pages */
- int nMaxPage; /* High water mark of nPage */
int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */
int mxPage; /* Maximum number of pages to hold in cache */
+ Pgno mxPgno; /* Maximum allowed size of the database */
u8 *aInJournal; /* One bit for each page in the database file */
u8 *aInStmt; /* One bit for each page in the database */
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*/
+ char *zStmtJrnl; /* Name of the statement journal file */
+ sqlite3_file *fd, *jfd; /* File descriptors for database and journal */
+ sqlite3_file *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 */
+ PagerLruList lru; /* LRU list of free pages */
PgHdr *pAll; /* List of all pages */
PgHdr *pStmt; /* List of pages in the statement subjournal */
PgHdr *pDirty; /* List of all dirty pages */
@@ -271,31 +385,55 @@ struct Pager {
i64 stmtJSize; /* Size of journal at stmt_begin() */
int sectorSize; /* Assumed sector size during rollback */
#ifdef SQLITE_TEST
- int nHit, nMiss, nOvfl; /* Cache hits, missing, and LRU overflows */
- int nRead,nWrite; /* Database pages read/written */
+ int nHit, nMiss; /* Cache hits and missing */
+ int nRead, nWrite; /* Database pages read/written */
#endif
- void (*xDestructor)(void*,int); /* Call this routine when freeing pages */
- void (*xReiniter)(void*,int); /* Call this routine when reloading pages */
+ void (*xDestructor)(DbPage*,int); /* Call this routine when freeing pages */
+ void (*xReiniter)(DbPage*,int); /* Call this routine when reloading pages */
+#ifdef SQLITE_HAS_CODEC
void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
void *pCodecArg; /* First argument to xCodec() */
+#endif
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 */
+ Pager *pNext; /* Doubly linked list of pagers on which */
+ Pager *pPrev; /* sqlite3_release_memory() will work */
+ int iInUseMM; /* Non-zero if unavailable to MM */
+ int iInUseDB; /* Non-zero if in sqlite3_release_memory() */
#endif
+ char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */
+ char dbFileVers[16]; /* Changes whenever database file changes */
};
/*
-** If SQLITE_TEST is defined then increment the variable given in
-** the argument
+** The following global variables hold counters used for
+** testing purposes only. These variables do not exist in
+** a non-testing build. These variables are not thread-safe.
*/
#ifdef SQLITE_TEST
-# define TEST_INCR(x) x++
+int sqlite3_pager_readdb_count = 0; /* Number of full pages read from DB */
+int sqlite3_pager_writedb_count = 0; /* Number of full pages written to DB */
+int sqlite3_pager_writej_count = 0; /* Number of pages written to journal */
+int sqlite3_pager_pgfree_count = 0; /* Number of cache pages freed */
+# define PAGER_INCR(v) v++
#else
-# define TEST_INCR(x)
+# define PAGER_INCR(v)
#endif
/*
+** The following variable points to the head of a double-linked list
+** of all pagers that are eligible for page stealing by the
+** sqlite3_release_memory() interface. Access to this list is
+** protected by the SQLITE_MUTEX_STATIC_MEM2 mutex.
+*/
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+static Pager *sqlite3PagerList = 0;
+static PagerLruList sqlite3LruPageList = {0, 0, 0};
+#endif
+
+
+/*
** Journal files begin with the following magic string. The data
** was obtained from /dev/random. It is used only as a sanity check.
**
@@ -348,11 +486,6 @@ static const unsigned char aJournalMagic[] = {
#endif
/*
-** The default size of a disk sector
-*/
-#define PAGER_SECTOR_SIZE 512
-
-/*
** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is
** reserved for working around a windows/posix incompatibility). It is
** used in the journal to signify that the remainder of the journal file
@@ -368,24 +501,176 @@ static const unsigned char aJournalMagic[] = {
#define PAGER_MAX_PGNO 2147483647
/*
-** Enable reference count tracking (for debugging) here:
+** The pagerEnter() and pagerLeave() routines acquire and release
+** a mutex on each pager. The mutex is recursive.
+**
+** This is a special-purpose mutex. It only provides mutual exclusion
+** between the Btree and the Memory Management sqlite3_release_memory()
+** function. It does not prevent, for example, two Btrees from accessing
+** the same pager at the same time. Other general-purpose mutexes in
+** the btree layer handle that chore.
*/
-#ifdef SQLITE_TEST
- int pager3_refinfo_enable = 0;
- static void pager_refinfo(PgHdr *p){
- static int cnt = 0;
- if( !pager3_refinfo_enable ) return;
- sqlite3DebugPrintf(
- "REFCNT: %4d addr=%p nRef=%d\n",
- p->pgno, PGHDR_TO_DATA(p), p->nRef
- );
- cnt++; /* Something to set a breakpoint on */
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ static void pagerEnter(Pager *p){
+ p->iInUseDB++;
+ if( p->iInUseMM && p->iInUseDB==1 ){
+ sqlite3_mutex *mutex;
+ mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2);
+ p->iInUseDB = 0;
+ sqlite3_mutex_enter(mutex);
+ p->iInUseDB = 1;
+ sqlite3_mutex_leave(mutex);
+ }
+ assert( p->iInUseMM==0 );
+ }
+ static void pagerLeave(Pager *p){
+ p->iInUseDB--;
+ assert( p->iInUseDB>=0 );
}
-# define REFINFO(X) pager_refinfo(X)
#else
-# define REFINFO(X)
+# define pagerEnter(X)
+# define pagerLeave(X)
+#endif
+
+/*
+** Add page pPg to the end of the linked list managed by structure
+** pList (pPg becomes the last entry in the list - the most recently
+** used). Argument pLink should point to either pPg->free or pPg->gfree,
+** depending on whether pPg is being added to the pager-specific or
+** global LRU list.
+*/
+static void listAdd(PagerLruList *pList, PagerLruLink *pLink, PgHdr *pPg){
+ pLink->pNext = 0;
+ pLink->pPrev = pList->pLast;
+
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ assert(pLink==&pPg->free || pLink==&pPg->gfree);
+ assert(pLink==&pPg->gfree || pList!=&sqlite3LruPageList);
#endif
+ if( pList->pLast ){
+ int iOff = (char *)pLink - (char *)pPg;
+ PagerLruLink *pLastLink = (PagerLruLink *)(&((u8 *)pList->pLast)[iOff]);
+ pLastLink->pNext = pPg;
+ }else{
+ assert(!pList->pFirst);
+ pList->pFirst = pPg;
+ }
+
+ pList->pLast = pPg;
+ if( !pList->pFirstSynced && pPg->needSync==0 ){
+ pList->pFirstSynced = pPg;
+ }
+}
+
+/*
+** Remove pPg from the list managed by the structure pointed to by pList.
+**
+** Argument pLink should point to either pPg->free or pPg->gfree, depending
+** on whether pPg is being added to the pager-specific or global LRU list.
+*/
+static void listRemove(PagerLruList *pList, PagerLruLink *pLink, PgHdr *pPg){
+ int iOff = (char *)pLink - (char *)pPg;
+
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ assert(pLink==&pPg->free || pLink==&pPg->gfree);
+ assert(pLink==&pPg->gfree || pList!=&sqlite3LruPageList);
+#endif
+
+ if( pPg==pList->pFirst ){
+ pList->pFirst = pLink->pNext;
+ }
+ if( pPg==pList->pLast ){
+ pList->pLast = pLink->pPrev;
+ }
+ if( pLink->pPrev ){
+ PagerLruLink *pPrevLink = (PagerLruLink *)(&((u8 *)pLink->pPrev)[iOff]);
+ pPrevLink->pNext = pLink->pNext;
+ }
+ if( pLink->pNext ){
+ PagerLruLink *pNextLink = (PagerLruLink *)(&((u8 *)pLink->pNext)[iOff]);
+ pNextLink->pPrev = pLink->pPrev;
+ }
+ if( pPg==pList->pFirstSynced ){
+ PgHdr *p = pLink->pNext;
+ while( p && p->needSync ){
+ PagerLruLink *pL = (PagerLruLink *)(&((u8 *)p)[iOff]);
+ p = pL->pNext;
+ }
+ pList->pFirstSynced = p;
+ }
+
+ pLink->pNext = pLink->pPrev = 0;
+}
+
+/*
+** Add page pPg to the list of free pages for the pager. If
+** memory-management is enabled, also add the page to the global
+** list of free pages.
+*/
+static void lruListAdd(PgHdr *pPg){
+ listAdd(&pPg->pPager->lru, &pPg->free, pPg);
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ if( !pPg->pPager->memDb ){
+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU));
+ listAdd(&sqlite3LruPageList, &pPg->gfree, pPg);
+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU));
+ }
+#endif
+}
+
+/*
+** Remove page pPg from the list of free pages for the associated pager.
+** If memory-management is enabled, also remove pPg from the global list
+** of free pages.
+*/
+static void lruListRemove(PgHdr *pPg){
+ listRemove(&pPg->pPager->lru, &pPg->free, pPg);
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ if( !pPg->pPager->memDb ){
+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU));
+ listRemove(&sqlite3LruPageList, &pPg->gfree, pPg);
+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU));
+ }
+#endif
+}
+
+/*
+** This function is called just after the needSync flag has been cleared
+** from all pages managed by pPager (usually because the journal file
+** has just been synced). It updates the pPager->lru.pFirstSynced variable
+** and, if memory-management is enabled, the sqlite3LruPageList.pFirstSynced
+** variable also.
+*/
+static void lruListSetFirstSynced(Pager *pPager){
+ pPager->lru.pFirstSynced = pPager->lru.pFirst;
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ if( !pPager->memDb ){
+ PgHdr *p;
+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU));
+ for(p=sqlite3LruPageList.pFirst; p && p->needSync; p=p->gfree.pNext);
+ assert(p==pPager->lru.pFirstSynced || p==sqlite3LruPageList.pFirstSynced);
+ sqlite3LruPageList.pFirstSynced = p;
+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU));
+ }
+#endif
+}
+
+/*
+** Return true if page *pPg has already been written to the statement
+** journal (or statement snapshot has been created, if *pPg is part
+** of an in-memory database).
+*/
+static int pageInStatement(PgHdr *pPg){
+ Pager *pPager = pPg->pPager;
+ if( MEMDB ){
+ return PGHDR_TO_HIST(pPg, pPager)->inStmt;
+ }else{
+ Pgno pgno = pPg->pgno;
+ u8 *a = pPager->aInStmt;
+ return (a && (int)pgno<=pPager->stmtSize && (a[pgno/8] & (1<<(pgno&7))));
+ }
+}
/*
** Change the size of the pager hash table to N. N must be a power
@@ -394,12 +679,16 @@ static const unsigned char aJournalMagic[] = {
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 );
+ pagerLeave(pPager);
+ sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, pPager->aHash!=0);
+ aHash = sqlite3MallocZero( sizeof(aHash[0])*N );
+ sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 0);
+ pagerEnter(pPager);
if( aHash==0 ){
/* Failure to rehash is not an error. It is only a performance hit. */
return;
}
- sqliteFree(pPager->aHash);
+ sqlite3_free(pPager->aHash);
pPager->nHash = N;
pPager->aHash = aHash;
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
@@ -425,11 +714,11 @@ static void pager_resize_hash_table(Pager *pPager, int N){
**
** All values are stored on disk as big-endian.
*/
-static int read32bits(OsFile *fd, u32 *pRes){
+static int read32bits(sqlite3_file *fd, i64 offset, u32 *pRes){
unsigned char ac[4];
- int rc = sqlite3OsRead(fd, ac, sizeof(ac));
+ int rc = sqlite3OsRead(fd, ac, sizeof(ac), offset);
if( rc==SQLITE_OK ){
- *pRes = (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3];
+ *pRes = sqlite3Get4byte(ac);
}
return rc;
}
@@ -437,33 +726,63 @@ static int read32bits(OsFile *fd, u32 *pRes){
/*
** Write a 32-bit integer into a string buffer in big-endian byte order.
*/
-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;
-}
+#define put32bits(A,B) sqlite3Put4byte((u8*)A,B)
/*
** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK
** on success or an error code is something goes wrong.
*/
-static int write32bits(OsFile *fd, u32 val){
+static int write32bits(sqlite3_file *fd, i64 offset, u32 val){
char ac[4];
put32bits(ac, val);
- return sqlite3OsWrite(fd, ac, 4);
+ return sqlite3OsWrite(fd, ac, 4, offset);
}
/*
-** Read a 32-bit integer at offset 'offset' from the page identified by
-** page header 'p'.
+** If file pFd is open, call sqlite3OsUnlock() on it.
*/
-static u32 retrieve32bits(PgHdr *p, int offset){
- unsigned char *ac;
- ac = &((unsigned char*)PGHDR_TO_DATA(p))[offset];
- return (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3];
+static int osUnlock(sqlite3_file *pFd, int eLock){
+ if( !pFd->pMethods ){
+ return SQLITE_OK;
+ }
+ return sqlite3OsUnlock(pFd, eLock);
}
+/*
+** This function determines whether or not the atomic-write optimization
+** can be used with this pager. The optimization can be used if:
+**
+** (a) the value returned by OsDeviceCharacteristics() indicates that
+** a database page may be written atomically, and
+** (b) the value returned by OsSectorSize() is less than or equal
+** to the page size.
+**
+** If the optimization cannot be used, 0 is returned. If it can be used,
+** then the value returned is the size of the journal file when it
+** contains rollback data for exactly one page.
+*/
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+static int jrnlBufferSize(Pager *pPager){
+ int dc; /* Device characteristics */
+ int nSector; /* Sector size */
+ int nPage; /* Page size */
+ sqlite3_file *fd = pPager->fd;
+
+ if( fd->pMethods ){
+ dc = sqlite3OsDeviceCharacteristics(fd);
+ nSector = sqlite3OsSectorSize(fd);
+ nPage = pPager->pageSize;
+ }
+
+ assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
+ assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
+
+ if( !fd->pMethods || (dc&(SQLITE_IOCAP_ATOMIC|(nPage>>8))&&nSector<=nPage) ){
+ return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
+ }
+ return 0;
+}
+#endif
/*
** This function should be called when an error occurs within the pager
@@ -471,36 +790,63 @@ static u32 retrieve32bits(PgHdr *p, int offset){
** 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.
+** If the second argument is SQLITE_IOERR, SQLITE_CORRUPT, or SQLITE_FULL
+** the error becomes persistent. Until the persisten error is cleared,
+** subsequent API calls on this Pager will immediately return the same
+** error code.
+**
+** A persistent error indicates that the contents of the pager-cache
+** cannot be trusted. This state can be cleared by completely discarding
+** the contents of the pager-cache. If a transaction was active when
+** the persistent error occured, then the rollback journal may need
+** to be replayed.
*/
+static void pager_unlock(Pager *pPager);
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
+ int rc2 = rc & 0xff;
+ assert(
+ pPager->errCode==SQLITE_FULL ||
+ pPager->errCode==SQLITE_OK ||
+ (pPager->errCode & 0xff)==SQLITE_IOERR
+ );
+ if(
+ rc2==SQLITE_FULL ||
+ rc2==SQLITE_IOERR ||
+ rc2==SQLITE_CORRUPT
){
pPager->errCode = rc;
+ if( pPager->state==PAGER_UNLOCK && pPager->nRef==0 ){
+ /* If the pager is already unlocked, call pager_unlock() now to
+ ** clear the error state and ensure that the pager-cache is
+ ** completely empty.
+ */
+ pager_unlock(pPager);
+ }
}
return rc;
}
+/*
+** If SQLITE_CHECK_PAGES is defined then we do some sanity checking
+** on the cache using a hash function. This is used for testing
+** and debugging only.
+*/
#ifdef SQLITE_CHECK_PAGES
/*
** Return a 32-bit hash of the page data for pPage.
*/
-static u32 pager_pagehash(PgHdr *pPage){
+static u32 pager_datahash(int nByte, unsigned char *pData){
u32 hash = 0;
int i;
- unsigned char *pData = (unsigned char *)PGHDR_TO_DATA(pPage);
- for(i=0; i<pPage->pPager->pageSize; i++){
- hash = (hash+i)^pData[i];
+ for(i=0; i<nByte; i++){
+ hash = (hash*1039) + pData[i];
}
return hash;
}
+static u32 pager_pagehash(PgHdr *pPage){
+ return pager_datahash(pPage->pPager->pageSize,
+ (unsigned char *)PGHDR_TO_DATA(pPage));
+}
/*
** The CHECK_PAGE macro takes a PgHdr* as an argument. If SQLITE_CHECK_PAGES
@@ -515,20 +861,27 @@ static void checkPage(PgHdr *pPg){
}
#else
+#define pager_datahash(X,Y) 0
+#define pager_pagehash(X) 0
#define CHECK_PAGE(x)
#endif
/*
** When this is called the journal file for pager pPager must be open.
** The master journal file name is read from the end of the file and
-** written into memory obtained from sqliteMalloc(). *pzMaster is
-** set to point at the memory and SQLITE_OK returned. The caller must
-** sqliteFree() *pzMaster.
+** written into memory supplied by the caller.
+**
+** zMaster must point to a buffer of at least nMaster bytes allocated by
+** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is
+** enough space to write the master journal name). If the master journal
+** name in the journal is longer than nMaster bytes (including a
+** nul-terminator), then this is handled as if no master journal name
+** were present in the journal.
**
-** If no master journal file name is present *pzMaster is set to 0 and
+** If no master journal file name is present zMaster[0] is set to 0 and
** SQLITE_OK returned.
*/
-static int readMasterJournal(OsFile *pJrnl, char **pzMaster){
+static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, int nMaster){
int rc;
u32 len;
i64 szJ;
@@ -536,51 +889,41 @@ static int readMasterJournal(OsFile *pJrnl, char **pzMaster){
int i;
unsigned char aMagic[8]; /* A buffer to hold the magic header */
- *pzMaster = 0;
+ zMaster[0] = '\0';
rc = sqlite3OsFileSize(pJrnl, &szJ);
if( rc!=SQLITE_OK || szJ<16 ) return rc;
- rc = sqlite3OsSeek(pJrnl, szJ-16);
- if( rc!=SQLITE_OK ) return rc;
-
- rc = read32bits(pJrnl, &len);
+ rc = read32bits(pJrnl, szJ-16, &len);
if( rc!=SQLITE_OK ) return rc;
- rc = read32bits(pJrnl, &cksum);
+ if( len>=nMaster ){
+ return SQLITE_OK;
+ }
+
+ rc = read32bits(pJrnl, szJ-12, &cksum);
if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3OsRead(pJrnl, aMagic, 8);
+ rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8);
if( rc!=SQLITE_OK || memcmp(aMagic, aJournalMagic, 8) ) return rc;
- rc = sqlite3OsSeek(pJrnl, szJ-16-len);
- if( rc!=SQLITE_OK ) return rc;
-
- *pzMaster = (char *)sqliteMalloc(len+1);
- if( !*pzMaster ){
- return SQLITE_NOMEM;
- }
- rc = sqlite3OsRead(pJrnl, *pzMaster, len);
+ rc = sqlite3OsRead(pJrnl, zMaster, len, szJ-16-len);
if( rc!=SQLITE_OK ){
- sqliteFree(*pzMaster);
- *pzMaster = 0;
return rc;
}
+ zMaster[len] = '\0';
/* See if the checksum matches the master journal name */
for(i=0; i<len; i++){
- cksum -= (*pzMaster)[i];
- }
+ cksum -= zMaster[i];
+ }
if( cksum ){
/* If the checksum doesn't add up, then one or more of the disk sectors
** containing the master journal filename is corrupted. This means
** definitely roll back, so just return SQLITE_OK and report a (nul)
** master-journal filename.
*/
- sqliteFree(*pzMaster);
- *pzMaster = 0;
- }else{
- (*pzMaster)[len] = '\0';
+ zMaster[0] = '\0';
}
return SQLITE_OK;
@@ -601,7 +944,7 @@ static int readMasterJournal(OsFile *pJrnl, char **pzMaster){
** 2000 2048
**
*/
-static int seekJournalHdr(Pager *pPager){
+static void seekJournalHdr(Pager *pPager){
i64 offset = 0;
i64 c = pPager->journalOff;
if( c ){
@@ -611,7 +954,6 @@ static int seekJournalHdr(Pager *pPager){
assert( offset>=c );
assert( (offset-c)<JOURNAL_HDR_SZ(pPager) );
pPager->journalOff = offset;
- return sqlite3OsSeek(pPager->jfd, pPager->journalOff);
}
/*
@@ -630,27 +972,46 @@ static int seekJournalHdr(Pager *pPager){
*/
static int writeJournalHdr(Pager *pPager){
char zHeader[sizeof(aJournalMagic)+16];
+ int rc;
- int rc = seekJournalHdr(pPager);
- if( rc ) return rc;
-
- pPager->journalHdr = pPager->journalOff;
if( pPager->stmtHdrOff==0 ){
- pPager->stmtHdrOff = pPager->journalHdr;
+ pPager->stmtHdrOff = pPager->journalOff;
}
- pPager->journalOff += JOURNAL_HDR_SZ(pPager);
- /* FIX ME:
+ seekJournalHdr(pPager);
+ pPager->journalHdr = pPager->journalOff;
+
+ memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
+
+ /*
+ ** Write the nRec Field - the number of page records that follow this
+ ** journal header. Normally, zero is written to this value at this time.
+ ** After the records are added to the journal (and the journal synced,
+ ** if in full-sync mode), the zero is overwritten with the true number
+ ** of records (see syncJournal()).
+ **
+ ** A faster alternative is to write 0xFFFFFFFF to the nRec field. When
+ ** reading the journal this value tells SQLite to assume that the
+ ** rest of the journal file contains valid page records. This assumption
+ ** is dangerous, as if a failure occured whilst writing to the journal
+ ** file it may contain some garbage data. There are two scenarios
+ ** where this risk can be ignored:
**
- ** Possibly for a pager not in no-sync mode, the journal magic should not
- ** be written until nRec is filled in as part of next syncJournal().
+ ** * When the pager is in no-sync mode. Corruption can follow a
+ ** power failure in this case anyway.
**
- ** Actually maybe the whole journal header should be delayed until that
- ** point. Think about this.
+ ** * When the SQLITE_IOCAP_SAFE_APPEND flag is set. This guarantees
+ ** that garbage data is never appended to the journal file.
*/
- memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
- /* The nRec Field. 0xFFFFFFFF for no-sync journals. */
- put32bits(&zHeader[sizeof(aJournalMagic)], pPager->noSync ? 0xffffffff : 0);
+ assert(pPager->fd->pMethods||pPager->noSync);
+ if( (pPager->noSync)
+ || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
+ ){
+ put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff);
+ }else{
+ put32bits(&zHeader[sizeof(aJournalMagic)], 0);
+ }
+
/* The random check-hash initialiser */
sqlite3Randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit);
@@ -658,16 +1019,16 @@ static int writeJournalHdr(Pager *pPager){
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));
+ IOTRACE(("JHDR %p %lld %d\n", pPager, pPager->journalHdr, sizeof(zHeader)))
+ rc = sqlite3OsWrite(pPager->jfd, zHeader, sizeof(zHeader),pPager->journalOff);
+ pPager->journalOff += JOURNAL_HDR_SZ(pPager);
/* 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);
- if( rc==SQLITE_OK ){
- rc = sqlite3OsWrite(pPager->jfd, "\000", 1);
- }
+ IOTRACE(("JTAIL %p %lld\n", pPager, pPager->journalOff-1))
+ rc = sqlite3OsWrite(pPager->jfd, "\000", 1, pPager->journalOff-1);
}
return rc;
}
@@ -696,28 +1057,29 @@ static int readJournalHdr(
){
int rc;
unsigned char aMagic[8]; /* A buffer to hold the magic header */
+ i64 jrnlOff;
- rc = seekJournalHdr(pPager);
- if( rc ) return rc;
-
+ seekJournalHdr(pPager);
if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){
return SQLITE_DONE;
}
+ jrnlOff = pPager->journalOff;
- rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic));
+ rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic), jrnlOff);
if( rc ) return rc;
+ jrnlOff += sizeof(aMagic);
if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){
return SQLITE_DONE;
}
- rc = read32bits(pPager->jfd, pNRec);
+ rc = read32bits(pPager->jfd, jrnlOff, pNRec);
if( rc ) return rc;
- rc = read32bits(pPager->jfd, &pPager->cksumInit);
+ rc = read32bits(pPager->jfd, jrnlOff+4, &pPager->cksumInit);
if( rc ) return rc;
- rc = read32bits(pPager->jfd, pDbSize);
+ rc = read32bits(pPager->jfd, jrnlOff+8, pDbSize);
if( rc ) return rc;
/* Update the assumed sector-size to match the value used by
@@ -726,12 +1088,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, jrnlOff+12, (u32 *)&pPager->sectorSize);
if( rc ) return rc;
pPager->journalOff += JOURNAL_HDR_SZ(pPager);
- rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff);
- return rc;
+ return SQLITE_OK;
}
@@ -758,6 +1119,7 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
int rc;
int len;
int i;
+ i64 jrnlOff;
u32 cksum = 0;
char zBuf[sizeof(aJournalMagic)+2*4];
@@ -774,21 +1136,23 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
** the journal has already been synced.
*/
if( pPager->fullSync ){
- rc = seekJournalHdr(pPager);
- if( rc!=SQLITE_OK ) return rc;
+ seekJournalHdr(pPager);
}
+ jrnlOff = pPager->journalOff;
pPager->journalOff += (len+20);
- rc = write32bits(pPager->jfd, PAGER_MJ_PGNO(pPager));
+ rc = write32bits(pPager->jfd, jrnlOff, PAGER_MJ_PGNO(pPager));
if( rc!=SQLITE_OK ) return rc;
+ jrnlOff += 4;
- rc = sqlite3OsWrite(pPager->jfd, zMaster, len);
+ rc = sqlite3OsWrite(pPager->jfd, zMaster, len, jrnlOff);
if( rc!=SQLITE_OK ) return rc;
+ jrnlOff += len;
put32bits(zBuf, len);
put32bits(&zBuf[4], cksum);
memcpy(&zBuf[8], aJournalMagic, sizeof(aJournalMagic));
- rc = sqlite3OsWrite(pPager->jfd, zBuf, 8+sizeof(aJournalMagic));
+ rc = sqlite3OsWrite(pPager->jfd, zBuf, 8+sizeof(aJournalMagic), jrnlOff);
pPager->needSync = !pPager->noSync;
return rc;
}
@@ -798,38 +1162,23 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
** statement journal.
**
** The Pager keeps a separate list of pages that are currently in
-** the statement journal. This helps the sqlite3pager_stmt_commit()
+** the statement journal. This helps the sqlite3PagerStmtCommit()
** routine run MUCH faster for the common case where there are many
** pages in memory but only a few are in the statement journal.
*/
static void page_add_to_stmt_list(PgHdr *pPg){
Pager *pPager = pPg->pPager;
- if( pPg->inStmt ) return;
- assert( pPg->pPrevStmt==0 && pPg->pNextStmt==0 );
- pPg->pPrevStmt = 0;
- if( pPager->pStmt ){
- pPager->pStmt->pPrevStmt = pPg;
- }
- pPg->pNextStmt = pPager->pStmt;
- pPager->pStmt = pPg;
- pPg->inStmt = 1;
-}
-static void page_remove_from_stmt_list(PgHdr *pPg){
- if( !pPg->inStmt ) return;
- if( pPg->pPrevStmt ){
- assert( pPg->pPrevStmt->pNextStmt==pPg );
- pPg->pPrevStmt->pNextStmt = pPg->pNextStmt;
- }else{
- assert( pPg->pPager->pStmt==pPg );
- pPg->pPager->pStmt = pPg->pNextStmt;
- }
- if( pPg->pNextStmt ){
- assert( pPg->pNextStmt->pPrevStmt==pPg );
- pPg->pNextStmt->pPrevStmt = pPg->pPrevStmt;
+ PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
+ assert( MEMDB );
+ if( !pHist->inStmt ){
+ assert( pHist->pPrevStmt==0 && pHist->pNextStmt==0 );
+ if( pPager->pStmt ){
+ PGHDR_TO_HIST(pPager->pStmt, pPager)->pPrevStmt = pPg;
+ }
+ pHist->pNextStmt = pPager->pStmt;
+ pPager->pStmt = pPg;
+ pHist->inStmt = 1;
}
- pPg->pNextStmt = 0;
- pPg->pPrevStmt = 0;
- pPg->inStmt = 0;
}
/*
@@ -847,7 +1196,7 @@ static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
}
/*
-** Unlock the database and clear the in-memory cache. This routine
+** Clear the in-memory cache. This routine
** sets the state of the pager back to what it was when it was first
** opened. Any outstanding pages are invalidated and subsequent attempts
** to access those pages will likely result in a coredump.
@@ -856,59 +1205,141 @@ static void pager_reset(Pager *pPager){
PgHdr *pPg, *pNext;
if( pPager->errCode ) return;
for(pPg=pPager->pAll; pPg; pPg=pNext){
+ IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno));
+ PAGER_INCR(sqlite3_pager_pgfree_count);
pNext = pPg->pNextAll;
- sqliteFree(pPg);
+ lruListRemove(pPg);
+ sqlite3_free(pPg);
}
- pPager->pFirst = 0;
- pPager->pFirstSynced = 0;
- pPager->pLast = 0;
+ assert(pPager->lru.pFirst==0);
+ assert(pPager->lru.pFirstSynced==0);
+ assert(pPager->lru.pLast==0);
+ pPager->pStmt = 0;
pPager->pAll = 0;
+ pPager->pDirty = 0;
pPager->nHash = 0;
- sqliteFree(pPager->aHash);
+ sqlite3_free(pPager->aHash);
pPager->nPage = 0;
pPager->aHash = 0;
- if( pPager->state>=PAGER_RESERVED ){
- sqlite3pager_rollback(pPager);
- }
- sqlite3OsUnlock(pPager->fd, NO_LOCK);
- pPager->state = PAGER_UNLOCK;
- pPager->dbSize = -1;
pPager->nRef = 0;
- assert( pPager->journalOpen==0 );
}
/*
+** Unlock the database file.
+**
+** If the pager is currently in error state, discard the contents of
+** the cache and reset the Pager structure internal state. If there is
+** an open journal-file, then the next time a shared-lock is obtained
+** on the pager file (by this or any other process), it will be
+** treated as a hot-journal and rolled back.
+*/
+static void pager_unlock(Pager *pPager){
+ if( !pPager->exclusiveMode ){
+ if( !MEMDB ){
+ if( pPager->fd->pMethods ){
+ osUnlock(pPager->fd, NO_LOCK);
+ }
+ pPager->dbSize = -1;
+ IOTRACE(("UNLOCK %p\n", pPager))
+
+ /* If Pager.errCode is set, the contents of the pager cache cannot be
+ ** trusted. Now that the pager file is unlocked, the contents of the
+ ** cache can be discarded and the error code safely cleared.
+ */
+ if( pPager->errCode ){
+ pPager->errCode = SQLITE_OK;
+ pager_reset(pPager);
+ if( pPager->stmtOpen ){
+ sqlite3OsClose(pPager->stfd);
+ sqlite3_free(pPager->aInStmt);
+ pPager->aInStmt = 0;
+ }
+ if( pPager->journalOpen ){
+ sqlite3OsClose(pPager->jfd);
+ pPager->journalOpen = 0;
+ sqlite3_free(pPager->aInJournal);
+ pPager->aInJournal = 0;
+ }
+ pPager->stmtOpen = 0;
+ pPager->stmtInUse = 0;
+ pPager->journalOff = 0;
+ pPager->journalStarted = 0;
+ pPager->stmtAutoopen = 0;
+ pPager->origDbSize = 0;
+ }
+ }
+
+ if( !MEMDB || pPager->errCode==SQLITE_OK ){
+ pPager->state = PAGER_UNLOCK;
+ pPager->changeCountDone = 0;
+ }
+ }
+}
+
+/*
+** Execute a rollback if a transaction is active and unlock the
+** database file. If the pager has already entered the error state,
+** do not attempt the rollback.
+*/
+static void pagerUnlockAndRollback(Pager *p){
+ assert( p->state>=PAGER_RESERVED || p->journalOpen==0 );
+ if( p->errCode==SQLITE_OK && p->state>=PAGER_RESERVED ){
+ sqlite3PagerRollback(p);
+ }
+ pager_unlock(p);
+ assert( p->errCode || !p->journalOpen || (p->exclusiveMode&&!p->journalOff) );
+ assert( p->errCode || !p->stmtOpen || p->exclusiveMode );
+}
+
+/*
+** This routine ends a transaction. A transaction is ended by either
+** a COMMIT or a ROLLBACK.
+**
** 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
-** file is deleted and closed.
+** a RESERVED or EXCLUSIVE lock on the database. This routine will release
+** the database lock and acquires a SHARED lock in its place if that is
+** the appropriate thing to do. Release locks usually is appropriate,
+** unless we are in exclusive access mode or unless this is a
+** COMMIT AND BEGIN or ROLLBACK AND BEGIN operation.
+**
+** The journal file is either deleted or truncated.
**
** TODO: Consider keeping the journal file open for temporary databases.
** This might give a performance improvement on windows where opening
** a file is an expensive operation.
*/
-static int pager_unwritelock(Pager *pPager){
+static int pager_end_transaction(Pager *pPager){
PgHdr *pPg;
- int rc;
+ int rc = SQLITE_OK;
+ int rc2 = SQLITE_OK;
assert( !MEMDB );
if( pPager->state<PAGER_RESERVED ){
return SQLITE_OK;
}
- sqlite3pager_stmt_commit(pPager);
- if( pPager->stmtOpen ){
- sqlite3OsClose(&pPager->stfd);
+ sqlite3PagerStmtCommit(pPager);
+ if( pPager->stmtOpen && !pPager->exclusiveMode ){
+ sqlite3OsClose(pPager->stfd);
pPager->stmtOpen = 0;
}
if( pPager->journalOpen ){
- sqlite3OsClose(&pPager->jfd);
- pPager->journalOpen = 0;
- sqlite3OsDelete(pPager->zJournal);
- sqliteFree( pPager->aInJournal );
+ if( pPager->exclusiveMode
+ && (rc = sqlite3OsTruncate(pPager->jfd, 0))==SQLITE_OK ){;
+ pPager->journalOff = 0;
+ pPager->journalStarted = 0;
+ }else{
+ sqlite3OsClose(pPager->jfd);
+ pPager->journalOpen = 0;
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
+ }
+ }
+ sqlite3_free( pPager->aInJournal );
pPager->aInJournal = 0;
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
pPg->inJournal = 0;
pPg->dirty = 0;
pPg->needSync = 0;
+ pPg->alwaysRollback = 0;
#ifdef SQLITE_CHECK_PAGES
pPg->pageHash = pager_pagehash(pPg);
#endif
@@ -920,13 +1351,20 @@ static int pager_unwritelock(Pager *pPager){
assert( pPager->aInJournal==0 );
assert( pPager->dirtyCache==0 || pPager->useJournal==0 );
}
- rc = sqlite3OsUnlock(pPager->fd, SHARED_LOCK);
- pPager->state = PAGER_SHARED;
+
+ if( !pPager->exclusiveMode ){
+ rc2 = osUnlock(pPager->fd, SHARED_LOCK);
+ pPager->state = PAGER_SHARED;
+ }else if( pPager->state==PAGER_SYNCED ){
+ pPager->state = PAGER_EXCLUSIVE;
+ }
pPager->origDbSize = 0;
pPager->setMaster = 0;
pPager->needSync = 0;
- pPager->pFirstSynced = pPager->pFirst;
- return rc;
+ lruListSetFirstSynced(pPager);
+ pPager->dbSize = -1;
+
+ return (rc==SQLITE_OK?rc2:rc);
}
/*
@@ -970,22 +1408,27 @@ static void makeClean(PgHdr*);
** are not used in statement journals because statement journals do not
** need to survive power failures.
*/
-static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
+static int pager_playback_one_page(
+ Pager *pPager,
+ sqlite3_file *jfd,
+ i64 offset,
+ int useCksum
+){
int rc;
PgHdr *pPg; /* An existing page in the cache */
Pgno pgno; /* The page number of a page in journal */
u32 cksum; /* Checksum used for sanity checking */
- u8 aData[SQLITE_MAX_PAGE_SIZE]; /* Temp storage for a page */
+ u8 *aData = (u8 *)pPager->pTmpSpace; /* Temp storage for a page */
/* 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( aData );
-
- rc = read32bits(jfd, &pgno);
+ rc = read32bits(jfd, offset, &pgno);
if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3OsRead(jfd, &aData, pPager->pageSize);
+ rc = sqlite3OsRead(jfd, aData, pPager->pageSize, offset+4);
if( rc!=SQLITE_OK ) return rc;
pPager->journalOff += pPager->pageSize + 4;
@@ -1001,7 +1444,7 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
return SQLITE_OK;
}
if( useCksum ){
- rc = read32bits(jfd, &cksum);
+ rc = read32bits(jfd, offset+pPager->pageSize+4, &cksum);
if( rc ) return rc;
pPager->journalOff += 4;
if( pager_cksum(pPager, aData)!=cksum ){
@@ -1015,6 +1458,13 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
** page in the pager cache. In this case just update the pager cache,
** not the database file. The page is left marked dirty in this case.
**
+ ** An exception to the above rule: If the database is in no-sync mode
+ ** and a page is moved during an incremental vacuum then the page may
+ ** not be in the pager cache. Later: if a malloc() or IO error occurs
+ ** during a Movepage() call, then the page may not be in the cache
+ ** either. So the condition described in the above paragraph is not
+ ** assert()able.
+ **
** If in EXCLUSIVE state, then we update the pager cache if it exists
** and the main file. The page is then marked not dirty.
**
@@ -1023,22 +1473,21 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
** This occurs when a page is changed prior to the start of a statement
** then changed again within the statement. When rolling back such a
** statement we must not write to the original database unless we know
- ** for certain that original page contents are in the main rollback
- ** journal. Otherwise, if a full ROLLBACK occurs after the statement
- ** rollback the full ROLLBACK will not restore the page to its original
- ** content. Two conditions must be met before writing to the database
- ** files. (1) the database must be locked. (2) we know that the original
- ** page content is in the main journal either because the page is not in
- ** cache or else it is marked as needSync==0.
+ ** for certain that original page contents are synced into the main rollback
+ ** journal. Otherwise, a power loss might leave modified data in the
+ ** database file without an entry in the rollback journal that can
+ ** restore the database to its original form. Two conditions must be
+ ** met before writing to the database files. (1) the database must be
+ ** locked. (2) we know that the original page content is fully synced
+ ** in the main journal either because the page is not in cache or else
+ ** the page is marked as needSync==0.
*/
pPg = pager_lookup(pPager, pgno);
- assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 );
- TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno);
+ PAGERTRACE4("PLAYBACK %d page %d hash(%08x)\n",
+ PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, aData));
if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){
- rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize);
- if( rc==SQLITE_OK ){
- rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize);
- }
+ i64 offset = (pgno-1)*(i64)pPager->pageSize;
+ rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize, offset);
if( pPg ){
makeClean(pPg);
}
@@ -1048,18 +1497,25 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
** for page 1 which is held in use in order to keep the lock on the
** database active. However such a page may be rolled back as a result
** of an internal error resulting in an automatic call to
- ** sqlite3pager_rollback().
+ ** sqlite3PagerRollback().
*/
void *pData;
/* assert( pPg->nRef==0 || pPg->pgno==1 ); */
pData = PGHDR_TO_DATA(pPg);
memcpy(pData, aData, pPager->pageSize);
- if( pPager->xDestructor ){ /*** FIX ME: Should this be xReinit? ***/
- pPager->xDestructor(pData, pPager->pageSize);
+ if( pPager->xReiniter ){
+ pPager->xReiniter(pPg, pPager->pageSize);
}
#ifdef SQLITE_CHECK_PAGES
pPg->pageHash = pager_pagehash(pPg);
#endif
+ /* If this was page 1, then restore the value of Pager.dbFileVers.
+ ** Do this before any decoding. */
+ if( pgno==1 ){
+ memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers));
+ }
+
+ /* Decode the page just read from disk */
CODEC1(pPager, pData, pPg->pgno, 3);
}
return rc;
@@ -1071,65 +1527,79 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
** This routine checks if it is possible to delete the master journal file,
** and does so if it is.
**
+** Argument zMaster may point to Pager.pTmpSpace. So that buffer is not
+** available for use within this function.
+**
+**
** The master journal file contains the names of all child journals.
** To tell if a master journal can be deleted, check to each of the
** children. If all children are either missing or do not refer to
** a different master journal, then this master journal can be deleted.
*/
-static int pager_delmaster(const char *zMaster){
+static int pager_delmaster(Pager *pPager, const char *zMaster){
+ sqlite3_vfs *pVfs = pPager->pVfs;
int rc;
int master_open = 0;
- OsFile *master = 0;
+ sqlite3_file *pMaster;
+ sqlite3_file *pJournal;
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.
*/
- rc = sqlite3OsOpenReadOnly(zMaster, &master);
+ pMaster = (sqlite3_file *)sqlite3_malloc(pVfs->szOsFile * 2);
+ pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
+ if( !pMaster ){
+ rc = SQLITE_NOMEM;
+ }else{
+ int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
+ rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
+ }
if( rc!=SQLITE_OK ) goto delmaster_out;
master_open = 1;
- rc = sqlite3OsFileSize(master, &nMasterJournal);
+
+ rc = sqlite3OsFileSize(pMaster, &nMasterJournal);
if( rc!=SQLITE_OK ) goto delmaster_out;
if( nMasterJournal>0 ){
char *zJournal;
char *zMasterPtr = 0;
+ int nMasterPtr = pPager->pVfs->mxPathname+1;
/* Load the entire master journal file into space obtained from
- ** sqliteMalloc() and pointed to by zMasterJournal.
+ ** sqlite3_malloc() and pointed to by zMasterJournal.
*/
- zMasterJournal = (char *)sqliteMalloc(nMasterJournal);
+ zMasterJournal = (char *)sqlite3_malloc(nMasterJournal + nMasterPtr);
if( !zMasterJournal ){
rc = SQLITE_NOMEM;
goto delmaster_out;
}
- rc = sqlite3OsRead(master, zMasterJournal, nMasterJournal);
+ zMasterPtr = &zMasterJournal[nMasterJournal];
+ rc = sqlite3OsRead(pMaster, zMasterJournal, nMasterJournal, 0);
if( rc!=SQLITE_OK ) goto delmaster_out;
zJournal = zMasterJournal;
while( (zJournal-zMasterJournal)<nMasterJournal ){
- if( sqlite3OsFileExists(zJournal) ){
+ if( sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS) ){
/* One of the journals pointed to by the master journal exists.
** Open it and check if it points at the master journal. If
** so, return without deleting the master journal file.
*/
- OsFile *journal = 0;
int c;
-
- rc = sqlite3OsOpenReadOnly(zJournal, &journal);
+ int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
+ rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
if( rc!=SQLITE_OK ){
goto delmaster_out;
}
- rc = readMasterJournal(journal, &zMasterPtr);
- sqlite3OsClose(&journal);
+ rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr);
+ sqlite3OsClose(pJournal);
if( rc!=SQLITE_OK ){
goto delmaster_out;
}
- c = zMasterPtr!=0 && strcmp(zMasterPtr, zMaster)==0;
- sqliteFree(zMasterPtr);
+ c = zMasterPtr[0]!=0 && strcmp(zMasterPtr, zMaster)==0;
if( c ){
/* We have a match. Do not delete the master journal file. */
goto delmaster_out;
@@ -1139,69 +1609,69 @@ static int pager_delmaster(const char *zMaster){
}
}
- sqlite3OsDelete(zMaster);
+ rc = sqlite3OsDelete(pVfs, zMaster, 0);
delmaster_out:
if( zMasterJournal ){
- sqliteFree(zMasterJournal);
+ sqlite3_free(zMasterJournal);
}
if( master_open ){
- sqlite3OsClose(&master);
+ sqlite3OsClose(pMaster);
}
+ sqlite3_free(pMaster);
return rc;
}
+
+static void pager_truncate_cache(Pager *pPager);
+
/*
-** Make every page in the cache agree with what is on disk. In other words,
-** reread the disk to reset the state of the cache.
+** Truncate the main file of the given pager to the number of pages
+** indicated. Also truncate the cached representation of the file.
**
-** This routine is called after a rollback in which some of the dirty cache
-** pages had never been written out to disk. We need to roll back the
-** cache content and the easiest way to do that is to reread the old content
-** back from the disk.
+** Might might be the case that the file on disk is smaller than nPage.
+** This can happen, for example, if we are in the middle of a transaction
+** which has extended the file size and the new pages are still all held
+** in cache, then an INSERT or UPDATE does a statement rollback. Some
+** operating system implementations can get confused if you try to
+** truncate a file to some size that is larger than it currently is,
+** so detect this case and do not do the truncation.
*/
-static int pager_reload_cache(Pager *pPager){
- PgHdr *pPg;
+static int pager_truncate(Pager *pPager, int nPage){
int rc = SQLITE_OK;
- for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
- 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));
- if( rc==SQLITE_OK ){
- rc = sqlite3OsRead(pPager->fd, zBuf, pPager->pageSize);
- }
- TRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
- if( rc ) break;
- CODEC1(pPager, zBuf, pPg->pgno, 2);
- }else{
- memset(zBuf, 0, pPager->pageSize);
+ if( pPager->state>=PAGER_EXCLUSIVE && pPager->fd->pMethods ){
+ i64 currentSize, newSize;
+ rc = sqlite3OsFileSize(pPager->fd, &currentSize);
+ newSize = pPager->pageSize*(i64)nPage;
+ if( rc==SQLITE_OK && currentSize>newSize ){
+ rc = sqlite3OsTruncate(pPager->fd, newSize);
}
- if( pPg->nRef==0 || memcmp(zBuf, PGHDR_TO_DATA(pPg), pPager->pageSize) ){
- memcpy(PGHDR_TO_DATA(pPg), zBuf, pPager->pageSize);
- if( pPager->xReiniter ){
- pPager->xReiniter(PGHDR_TO_DATA(pPg), pPager->pageSize);
- }else{
- memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
- }
- }
- pPg->needSync = 0;
- pPg->dirty = 0;
-#ifdef SQLITE_CHECK_PAGES
- pPg->pageHash = pager_pagehash(pPg);
-#endif
}
- pPager->pDirty = 0;
+ if( rc==SQLITE_OK ){
+ pPager->dbSize = nPage;
+ pager_truncate_cache(pPager);
+ }
return rc;
}
/*
-** Truncate the main file of the given pager to the number of pages
-** indicated.
+** Set the sectorSize for the given pager.
+**
+** The sector size is the larger of the sector size reported
+** by sqlite3OsSectorSize() and the pageSize.
*/
-static int pager_truncate(Pager *pPager, int nPage){
- assert( pPager->state>=PAGER_EXCLUSIVE );
- return sqlite3OsTruncate(pPager->fd, pPager->pageSize*(i64)nPage);
+static void setSectorSize(Pager *pPager){
+ assert(pPager->fd->pMethods||pPager->tempFile);
+ if( !pPager->tempFile ){
+ /* Sector size doesn't matter for temporary files. Also, the file
+ ** may not have been opened yet, in whcih case the OsSectorSize()
+ ** call will segfault.
+ */
+ pPager->sectorSize = sqlite3OsSectorSize(pPager->fd);
+ }
+ if( pPager->sectorSize<pPager->pageSize ){
+ pPager->sectorSize = pPager->pageSize;
+ }
}
/*
@@ -1257,7 +1727,8 @@ static int pager_truncate(Pager *pPager, int nPage){
** If an I/O or malloc() error occurs, the journal-file is not deleted
** and an error code is returned.
*/
-static int pager_playback(Pager *pPager){
+static int pager_playback(Pager *pPager, int isHot){
+ sqlite3_vfs *pVfs = pPager->pVfs;
i64 szJ; /* Size of the journal file in bytes */
u32 nRec; /* Number of Records in the journal */
int i; /* Loop counter */
@@ -1270,7 +1741,7 @@ static int pager_playback(Pager *pPager){
*/
assert( pPager->journalOpen );
rc = sqlite3OsFileSize(pPager->jfd, &szJ);
- if( rc!=SQLITE_OK ){
+ if( rc!=SQLITE_OK || szJ==0 ){
goto end_playback;
}
@@ -1279,16 +1750,18 @@ 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);
+ zMaster = pPager->pTmpSpace;
+ rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
assert( rc!=SQLITE_DONE );
- if( rc!=SQLITE_OK || (zMaster && !sqlite3OsFileExists(zMaster)) ){
- sqliteFree(zMaster);
+ if( rc!=SQLITE_OK
+ || (zMaster[0] && !sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS))
+ ){
zMaster = 0;
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
goto end_playback;
}
- sqlite3OsSeek(pPager->jfd, 0);
pPager->journalOff = 0;
+ zMaster = 0;
/* This loop terminates either when the readJournalHdr() call returns
** SQLITE_DONE or an IO error occurs. */
@@ -1317,23 +1790,33 @@ static int pager_playback(Pager *pPager){
nRec = (szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager);
}
+ /* If nRec is 0 and this rollback is of a transaction created by this
+ ** process and if this is the final header in the journal, then it means
+ ** that this part of the journal was being filled but has not yet been
+ ** synced to disk. Compute the number of pages based on the remaining
+ ** size of the file.
+ **
+ ** The third term of the test was added to fix ticket #2565.
+ */
+ if( nRec==0 && !isHot &&
+ pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){
+ nRec = (szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager);
+ }
+
/* If this is the first header read from the journal, truncate the
- ** database file back to it's original size.
+ ** database file back to its original size.
*/
- if( pPager->state>=PAGER_EXCLUSIVE &&
- pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){
- assert( pPager->origDbSize==0 || pPager->origDbSize==mxPg );
+ if( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){
rc = pager_truncate(pPager, mxPg);
if( rc!=SQLITE_OK ){
goto end_playback;
}
- pPager->dbSize = mxPg;
}
/* 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, pPager->journalOff, 1);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
@@ -1350,23 +1833,24 @@ static int pager_playback(Pager *pPager){
end_playback:
if( rc==SQLITE_OK ){
- rc = pager_unwritelock(pPager);
+ zMaster = pPager->pTmpSpace;
+ rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
}
- if( zMaster ){
- /* If there was a master journal and this routine will return true,
+ if( rc==SQLITE_OK ){
+ rc = pager_end_transaction(pPager);
+ }
+ if( rc==SQLITE_OK && zMaster[0] ){
+ /* If there was a master journal and this routine will return success,
** see if it is possible to delete the master journal.
*/
- if( rc==SQLITE_OK ){
- rc = pager_delmaster(zMaster);
- }
- sqliteFree(zMaster);
+ rc = pager_delmaster(pPager, zMaster);
}
/* The Pager.sectorSize variable may have been updated while rolling
- ** back a journal created by a process with a different PAGER_SECTOR_SIZE
+ ** back a journal created by a process with a different sector size
** value. Reset it to the correct value for this process.
*/
- pPager->sectorSize = PAGER_SECTOR_SIZE;
+ setSectorSize(pPager);
return rc;
}
@@ -1401,8 +1885,9 @@ static int pager_stmt_playback(Pager *pPager){
}
#endif
- /* Set hdrOff to be the offset to the first journal header written
- ** this statement transaction, or the end of the file if no journal
+ /* Set hdrOff to be the offset just after the end of the last journal
+ ** page written before the first journal-header for this statement
+ ** transaction was written, or the end of the file if no journal
** header was written.
*/
hdrOff = pPager->stmtHdrOff;
@@ -1413,15 +1898,12 @@ static int pager_stmt_playback(Pager *pPager){
/* Truncate the database back to its original size.
*/
- if( pPager->state>=PAGER_EXCLUSIVE ){
- rc = pager_truncate(pPager, pPager->stmtSize);
- }
- pPager->dbSize = pPager->stmtSize;
+ rc = pager_truncate(pPager, pPager->stmtSize);
+ assert( pPager->state>=PAGER_SHARED );
/* Figure out how many records are in the statement journal.
*/
assert( pPager->stmtInUse && pPager->journalOpen );
- sqlite3OsSeek(pPager->stfd, 0);
nRec = pPager->stmtNRec;
/* Copy original pages out of the statement journal and back into the
@@ -1429,8 +1911,9 @@ static int pager_stmt_playback(Pager *pPager){
** each record since power-failure recovery is not important to statement
** journals.
*/
- for(i=nRec-1; i>=0; i--){
- rc = pager_playback_one_page(pPager, pPager->stfd, 0);
+ for(i=0; i<nRec; i++){
+ i64 offset = i*(4+pPager->pageSize);
+ rc = pager_playback_one_page(pPager, pPager->stfd, offset, 0);
assert( rc!=SQLITE_DONE );
if( rc!=SQLITE_OK ) goto end_stmt_playback;
}
@@ -1443,15 +1926,10 @@ 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);
- if( rc!=SQLITE_OK ){
- goto end_stmt_playback;
- }
pPager->journalOff = pPager->stmtJSize;
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);
+ while( pPager->journalOff < hdrOff ){
+ rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1);
assert( rc!=SQLITE_DONE );
if( rc!=SQLITE_OK ) goto end_stmt_playback;
}
@@ -1468,7 +1946,7 @@ static int pager_stmt_playback(Pager *pPager){
nJRec = (szJ - pPager->journalOff) / (pPager->pageSize+8);
}
for(i=nJRec-1; i>=0 && pPager->journalOff < szJ; i--){
- rc = pager_playback_one_page(pPager, pPager->jfd, 1);
+ rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1);
assert( rc!=SQLITE_DONE );
if( rc!=SQLITE_OK ) goto end_stmt_playback;
}
@@ -1487,7 +1965,7 @@ end_stmt_playback:
/*
** Change the maximum number of in-memory pages that are allowed.
*/
-void sqlite3pager_set_cachesize(Pager *pPager, int mxPage){
+void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
if( mxPage>10 ){
pPager->mxPage = mxPage;
}else{
@@ -1522,10 +2000,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, int full_fsync){
+void sqlite3PagerSetSafetyLevel(Pager *pPager, int level, int full_fsync){
pPager->noSync = level==1 || pPager->tempFile;
pPager->fullSync = level==3 && !pPager->tempFile;
- pPager->full_fsync = full_fsync;
+ pPager->sync_flags = (full_fsync?SQLITE_SYNC_FULL:SQLITE_SYNC_NORMAL);
if( pPager->noSync ) pPager->needSync = 0;
}
#endif
@@ -1540,33 +2018,37 @@ int sqlite3_opentemp_count = 0;
#endif
/*
-** Open a temporary file. Write the name of the file into zFile
-** (zFile must be at least SQLITE_TEMPNAME_SIZE bytes long.) Write
-** the file descriptor into *fd. Return SQLITE_OK on success or some
-** other error code if we fail.
+** Open a temporary file.
**
-** The OS will automatically delete the temporary file when it is
-** closed.
+** Write the file descriptor into *fd. Return SQLITE_OK on success or some
+** other error code if we fail. The OS will automatically delete the temporary
+** file when it is closed.
*/
-static int sqlite3pager_opentemp(char *zFile, OsFile **pFd){
- int cnt = 8;
+static int sqlite3PagerOpentemp(
+ sqlite3_vfs *pVfs, /* The virtual file system layer */
+ sqlite3_file *pFile, /* Write the file descriptor here */
+ char *zFilename, /* Name of the file. Might be NULL */
+ int vfsFlags /* Flags passed through to the VFS */
+){
int rc;
+ assert( zFilename!=0 );
+
#ifdef SQLITE_TEST
sqlite3_opentemp_count++; /* Used for testing and analysis only */
#endif
- do{
- cnt--;
- sqlite3OsTempFileName(zFile);
- rc = sqlite3OsOpenExclusive(zFile, pFd, 1);
- }while( cnt>0 && rc!=SQLITE_OK && rc!=SQLITE_NOMEM );
+
+ vfsFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
+ SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE;
+ rc = sqlite3OsOpen(pVfs, zFilename, pFile, vfsFlags, 0);
+ assert( rc!=SQLITE_OK || pFile->pMethods );
return rc;
}
/*
** Create a new page cache and put a pointer to the page cache in *ppPager.
** The file to be cached need not exist. The file is not locked until
-** the first call to sqlite3pager_get() and is only held open until the
-** last page is released using sqlite3pager_unref().
+** the first call to sqlite3PagerGet() and is only held open until the
+** last page is released using sqlite3PagerUnref().
**
** If zFilename is NULL then a randomly-named temporary file is created
** and used as the file to be cached. The file will be deleted
@@ -1576,16 +2058,16 @@ static int sqlite3pager_opentemp(char *zFile, OsFile **pFd){
** It is never written to disk. This can be used to implement an
** in-memory database.
*/
-int sqlite3pager_open(
+int sqlite3PagerOpen(
+ sqlite3_vfs *pVfs, /* The virtual file system to use */
Pager **ppPager, /* Return the Pager structure here */
const char *zFilename, /* Name of the database file to open */
int nExtra, /* Extra bytes append to each in-memory page */
- int flags /* flags controlling this file */
+ int flags, /* flags controlling this file */
+ int vfsFlags /* flags passed through to sqlite3_vfs.xOpen() */
){
+ u8 *pPtr;
Pager *pPager = 0;
- char *zFullPathname = 0;
- int nameLen; /* Compiler is wrong. This is always initialized before use */
- OsFile *fd;
int rc = SQLITE_OK;
int i;
int tempFile = 0;
@@ -1593,88 +2075,142 @@ int sqlite3pager_open(
int readOnly = 0;
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
+ int journalFileSize = sqlite3JournalSize(pVfs);
+ int nDefaultPage = SQLITE_DEFAULT_PAGE_SIZE;
+ char *zPathname;
+ int nPathname;
- /* 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.
- */
+ /* The default return is a NULL pointer */
*ppPager = 0;
- if( sqlite3MallocFailed() ){
+
+ /* Compute the full pathname */
+ nPathname = pVfs->mxPathname+1;
+ zPathname = sqlite3_malloc(nPathname);
+ if( zPathname==0 ){
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("");
+ zPathname[0] = 0;
}else
#endif
{
- zFullPathname = sqlite3OsFullPathname(zFilename);
- if( zFullPathname ){
- rc = sqlite3OsOpenReadWrite(zFullPathname, &fd, &readOnly);
- }
+ rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
}
}else{
- rc = sqlite3pager_opentemp(zTemp, &fd);
- zFilename = zTemp;
- zFullPathname = sqlite3OsFullPathname(zFilename);
- if( rc==SQLITE_OK ){
- tempFile = 1;
+ rc = sqlite3OsGetTempname(pVfs, nPathname, zPathname);
+ }
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(zPathname);
+ return rc;
+ }
+ nPathname = strlen(zPathname);
+
+ /* Allocate memory for the pager structure */
+ pPager = sqlite3MallocZero(
+ sizeof(*pPager) + /* Pager structure */
+ journalFileSize + /* The journal file structure */
+ pVfs->szOsFile * 2 + /* The db and stmt journal files */
+ 4*nPathname + 40 /* zFilename, zDirectory, zJournal, zStmtJrnl */
+ );
+ if( !pPager ){
+ sqlite3_free(zPathname);
+ return SQLITE_NOMEM;
+ }
+ pPtr = (u8 *)&pPager[1];
+ pPager->vfsFlags = vfsFlags;
+ pPager->fd = (sqlite3_file*)&pPtr[pVfs->szOsFile*0];
+ pPager->stfd = (sqlite3_file*)&pPtr[pVfs->szOsFile*1];
+ pPager->jfd = (sqlite3_file*)&pPtr[pVfs->szOsFile*2];
+ pPager->zFilename = (char*)&pPtr[pVfs->szOsFile*2+journalFileSize];
+ pPager->zDirectory = &pPager->zFilename[nPathname+1];
+ pPager->zJournal = &pPager->zDirectory[nPathname+1];
+ pPager->zStmtJrnl = &pPager->zJournal[nPathname+10];
+ pPager->pVfs = pVfs;
+ memcpy(pPager->zFilename, zPathname, nPathname+1);
+ sqlite3_free(zPathname);
+
+ /* Open the pager file.
+ */
+ if( zFilename && zFilename[0] && !memDb ){
+ if( nPathname>(pVfs->mxPathname - sizeof("-journal")) ){
+ rc = SQLITE_CANTOPEN;
+ }else{
+ int fout = 0;
+ rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd,
+ pPager->vfsFlags, &fout);
+ readOnly = (fout&SQLITE_OPEN_READONLY);
+
+ /* If the file was successfully opened for read/write access,
+ ** choose a default page size in case we have to create the
+ ** database file. The default page size is the maximum of:
+ **
+ ** + SQLITE_DEFAULT_PAGE_SIZE,
+ ** + The value returned by sqlite3OsSectorSize()
+ ** + The largest page size that can be written atomically.
+ */
+ if( rc==SQLITE_OK && !readOnly ){
+ int iSectorSize = sqlite3OsSectorSize(pPager->fd);
+ if( nDefaultPage<iSectorSize ){
+ nDefaultPage = iSectorSize;
+ }
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ {
+ int iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
+ int ii;
+ assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
+ assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
+ assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536);
+ for(ii=nDefaultPage; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){
+ if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ) nDefaultPage = ii;
+ }
+ }
+#endif
+ if( nDefaultPage>SQLITE_MAX_DEFAULT_PAGE_SIZE ){
+ nDefaultPage = SQLITE_MAX_DEFAULT_PAGE_SIZE;
+ }
+ }
}
+ }else if( !memDb ){
+ /* If a temporary file is requested, it is not opened immediately.
+ ** In this case we accept the default page size and delay actually
+ ** opening the file until the first call to OsWrite().
+ */
+ tempFile = 1;
+ pPager->state = PAGER_EXCLUSIVE;
}
- /* 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 );
+ if( pPager && rc==SQLITE_OK ){
+ pPager->pTmpSpace = (char *)sqlite3_malloc(nDefaultPage);
}
- /* 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
+ /* If an error occured in either of the blocks above.
+ ** 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);
- sqliteFree(pPager);
+ if( !pPager || !pPager->pTmpSpace ){
+ sqlite3OsClose(pPager->fd);
+ sqlite3_free(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);
+ PAGERTRACE3("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename);
+ IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename))
- for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){}
+ /* Fill in Pager.zDirectory[] */
+ memcpy(pPager->zDirectory, pPager->zFilename, nPathname+1);
+ for(i=strlen(pPager->zDirectory); 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;
+
+ /* Fill in Pager.zJournal[] and Pager.zStmtJrnl[] */
+ memcpy(pPager->zJournal, pPager->zFilename, nPathname);
+ memcpy(&pPager->zJournal[nPathname], "-journal", 9);
+ memcpy(pPager->zStmtJrnl, pPager->zFilename, nPathname);
+ memcpy(&pPager->zStmtJrnl[nPathname], "-stmtjrnl", 10);
+
/* pPager->journalOpen = 0; */
pPager->useJournal = useJournal && !memDb;
pPager->noReadlock = noReadlock && readOnly;
@@ -1682,32 +2218,52 @@ int sqlite3pager_open(
/* pPager->stmtInUse = 0; */
/* pPager->nRef = 0; */
pPager->dbSize = memDb-1;
- pPager->pageSize = SQLITE_DEFAULT_PAGE_SIZE;
+ pPager->pageSize = nDefaultPage;
/* pPager->stmtSize = 0; */
/* pPager->stmtJSize = 0; */
/* pPager->nPage = 0; */
- /* pPager->nMaxPage = 0; */
pPager->mxPage = 100;
- assert( PAGER_UNLOCK==0 );
+ pPager->mxPgno = SQLITE_MAX_PAGE_COUNT;
/* pPager->state = PAGER_UNLOCK; */
+ assert( pPager->state == (tempFile ? PAGER_EXCLUSIVE : PAGER_UNLOCK) );
/* pPager->errMask = 0; */
pPager->tempFile = tempFile;
+ assert( tempFile==PAGER_LOCKINGMODE_NORMAL
+ || tempFile==PAGER_LOCKINGMODE_EXCLUSIVE );
+ assert( PAGER_LOCKINGMODE_EXCLUSIVE==1 );
+ pPager->exclusiveMode = tempFile;
pPager->memDb = memDb;
pPager->readOnly = readOnly;
/* pPager->needSync = 0; */
pPager->noSync = pPager->tempFile || !useJournal;
pPager->fullSync = (pPager->noSync?0:1);
+ pPager->sync_flags = SQLITE_SYNC_NORMAL;
/* pPager->pFirst = 0; */
/* pPager->pFirstSynced = 0; */
/* pPager->pLast = 0; */
pPager->nExtra = FORCE_ALIGNMENT(nExtra);
- pPager->sectorSize = PAGER_SECTOR_SIZE;
+ assert(pPager->fd->pMethods||memDb||tempFile);
+ if( !memDb ){
+ setSectorSize(pPager);
+ }
/* pPager->pBusyHandler = 0; */
/* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
*ppPager = pPager;
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
- pPager->pNext = pTsd->pPager;
- pTsd->pPager = pPager;
+ pPager->iInUseMM = 0;
+ pPager->iInUseDB = 0;
+ if( !memDb ){
+ sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2);
+ sqlite3_mutex_enter(mutex);
+ pPager->pNext = sqlite3PagerList;
+ if( sqlite3PagerList ){
+ assert( sqlite3PagerList->pPrev==0 );
+ sqlite3PagerList->pPrev = pPager;
+ }
+ pPager->pPrev = 0;
+ sqlite3PagerList = pPager;
+ sqlite3_mutex_leave(mutex);
+ }
#endif
return SQLITE_OK;
}
@@ -1715,7 +2271,7 @@ int sqlite3pager_open(
/*
** Set the busy handler function.
*/
-void sqlite3pager_set_busyhandler(Pager *pPager, BusyHandler *pBusyHandler){
+void sqlite3PagerSetBusyhandler(Pager *pPager, BusyHandler *pBusyHandler){
pPager->pBusyHandler = pBusyHandler;
}
@@ -1724,10 +2280,10 @@ void sqlite3pager_set_busyhandler(Pager *pPager, BusyHandler *pBusyHandler){
** when the reference count on each page reaches zero. The destructor can
** be used to clean up information in the extra segment appended to each page.
**
-** The destructor is not called as a result sqlite3pager_close().
-** Destructors are only called by sqlite3pager_unref().
+** The destructor is not called as a result sqlite3PagerClose().
+** Destructors are only called by sqlite3PagerUnref().
*/
-void sqlite3pager_set_destructor(Pager *pPager, void (*xDesc)(void*,int)){
+void sqlite3PagerSetDestructor(Pager *pPager, void (*xDesc)(DbPage*,int)){
pPager->xDestructor = xDesc;
}
@@ -1738,21 +2294,64 @@ void sqlite3pager_set_destructor(Pager *pPager, void (*xDesc)(void*,int)){
** an opportunity to restore the EXTRA section to agree with the restored
** page data.
*/
-void sqlite3pager_set_reiniter(Pager *pPager, void (*xReinit)(void*,int)){
+void sqlite3PagerSetReiniter(Pager *pPager, void (*xReinit)(DbPage*,int)){
pPager->xReiniter = xReinit;
}
/*
-** Set the page size. Return the new size. If the suggest new page
-** size is inappropriate, then an alternative page size is selected
-** and returned.
+** Set the page size to *pPageSize. If the suggest new page size is
+** inappropriate, then an alternative page size is set to that
+** value before returning.
*/
-int sqlite3pager_set_pagesize(Pager *pPager, int pageSize){
- assert( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE );
- if( !pPager->memDb ){
- pPager->pageSize = pageSize;
+int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize){
+ int rc = SQLITE_OK;
+ u16 pageSize = *pPageSize;
+ assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) );
+ if( pageSize && pageSize!=pPager->pageSize
+ && !pPager->memDb && pPager->nRef==0
+ ){
+ char *pNew = (char *)sqlite3_malloc(pageSize);
+ if( !pNew ){
+ rc = SQLITE_NOMEM;
+ }else{
+ pagerEnter(pPager);
+ pager_reset(pPager);
+ pPager->pageSize = pageSize;
+ setSectorSize(pPager);
+ sqlite3_free(pPager->pTmpSpace);
+ pPager->pTmpSpace = pNew;
+ pagerLeave(pPager);
+ }
}
- return pPager->pageSize;
+ *pPageSize = pPager->pageSize;
+ return rc;
+}
+
+/*
+** Return a pointer to the "temporary page" buffer held internally
+** by the pager. This is a buffer that is big enough to hold the
+** entire content of a database page. This buffer is used internally
+** during rollback and will be overwritten whenever a rollback
+** occurs. But other modules are free to use it too, as long as
+** no rollbacks are happening.
+*/
+void *sqlite3PagerTempSpace(Pager *pPager){
+ return pPager->pTmpSpace;
+}
+
+/*
+** Attempt to set the maximum database page count if mxPage is positive.
+** Make no changes if mxPage is zero or negative. And never reduce the
+** maximum page count below the current size of the database.
+**
+** Regardless of mxPage, return the current maximum page count.
+*/
+int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
+ if( mxPage>0 ){
+ pPager->mxPgno = mxPage;
+ }
+ sqlite3PagerPagecount(pPager);
+ return pPager->mxPgno;
}
/*
@@ -1767,9 +2366,6 @@ int sqlite3pager_set_pagesize(Pager *pPager, int pageSize){
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;
@@ -1778,7 +2374,6 @@ 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
@@ -1793,14 +2388,18 @@ void enable_simulated_io_errors(void){
** 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){
+int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){
+ int rc = SQLITE_OK;
memset(pDest, 0, N);
- if( MEMDB==0 ){
- disable_simulated_io_errors();
- sqlite3OsSeek(pPager->fd, 0);
- sqlite3OsRead(pPager->fd, pDest, N);
- enable_simulated_io_errors();
+ assert(MEMDB||pPager->fd->pMethods||pPager->tempFile);
+ if( pPager->fd->pMethods ){
+ IOTRACE(("DBHDR %p 0 %d\n", pPager, N))
+ rc = sqlite3OsRead(pPager->fd, pDest, N, 0);
+ if( rc==SQLITE_IOERR_SHORT_READ ){
+ rc = SQLITE_OK;
+ }
}
+ return rc;
}
/*
@@ -1812,14 +2411,22 @@ void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
** PENDING_BYTE is byte 4096 (the first byte of page 5) and the size of the
** file is 4096 bytes, 5 is returned instead of 4.
*/
-int sqlite3pager_pagecount(Pager *pPager){
- i64 n;
+int sqlite3PagerPagecount(Pager *pPager){
+ i64 n = 0;
+ int rc;
assert( pPager!=0 );
+ if( pPager->errCode ){
+ return 0;
+ }
if( pPager->dbSize>=0 ){
n = pPager->dbSize;
} else {
- if( sqlite3OsFileSize(pPager->fd, &n)!=SQLITE_OK ){
- pager_error(pPager, SQLITE_IOERR);
+ assert(pPager->fd->pMethods||pPager->tempFile);
+ if( (pPager->fd->pMethods)
+ && (rc = sqlite3OsFileSize(pPager->fd, &n))!=SQLITE_OK ){
+ pPager->nRef++;
+ pager_error(pPager, rc);
+ pPager->nRef--;
return 0;
}
if( n>0 && n<pPager->pageSize ){
@@ -1834,6 +2441,9 @@ int sqlite3pager_pagecount(Pager *pPager){
if( n==(PENDING_BYTE/pPager->pageSize) ){
n++;
}
+ if( n>pPager->mxPgno ){
+ pPager->mxPgno = n;
+ }
return n;
}
@@ -1843,8 +2453,8 @@ int sqlite3pager_pagecount(Pager *pPager){
** Clear a PgHistory block
*/
static void clearHistory(PgHistory *pHist){
- sqliteFree(pHist->pOrig);
- sqliteFree(pHist->pStmt);
+ sqlite3_free(pHist->pOrig);
+ sqlite3_free(pHist->pStmt);
pHist->pOrig = 0;
pHist->pStmt = 0;
}
@@ -1858,9 +2468,9 @@ static void clearHistory(PgHistory *pHist){
static int syncJournal(Pager*);
/*
-** Unlink pPg from it's hash chain. Also set the page number to 0 to indicate
+** Unlink pPg from its 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
-** sqlite3pager_movepage() routine can leave a page in the
+** sqlite3PagerMovepage() routine can leave a page in the
** pNextFree/pPrevFree list that is not a part of any hash-chain.
*/
static void unlinkHashChain(Pager *pPager, PgHdr *pPg){
@@ -1892,39 +2502,26 @@ static void unlinkHashChain(Pager *pPager, PgHdr *pPg){
static void unlinkPage(PgHdr *pPg){
Pager *pPager = pPg->pPager;
- /* Keep the pFirstSynced pointer pointing at the first synchronized page */
- if( pPg==pPager->pFirstSynced ){
- PgHdr *p = pPg->pNextFree;
- while( p && p->needSync ){ p = p->pNextFree; }
- pPager->pFirstSynced = p;
- }
-
- /* Unlink from the freelist */
- if( pPg->pPrevFree ){
- pPg->pPrevFree->pNextFree = pPg->pNextFree;
- }else{
- assert( pPager->pFirst==pPg );
- pPager->pFirst = pPg->pNextFree;
- }
- if( pPg->pNextFree ){
- pPg->pNextFree->pPrevFree = pPg->pPrevFree;
- }else{
- assert( pPager->pLast==pPg );
- pPager->pLast = pPg->pPrevFree;
- }
- pPg->pNextFree = pPg->pPrevFree = 0;
+ /* Unlink from free page list */
+ lruListRemove(pPg);
/* Unlink from the pgno hash table */
unlinkHashChain(pPager, pPg);
}
-#ifndef SQLITE_OMIT_MEMORYDB
/*
-** This routine is used to truncate an in-memory database. Delete
-** all pages whose pgno is larger than pPager->dbSize and is unreferenced.
+** This routine is used to truncate the cache when a database
+** is truncated. Drop from the cache all pages whose pgno is
+** larger than pPager->dbSize and is unreferenced.
+**
** Referenced pages larger than pPager->dbSize are zeroed.
+**
+** Actually, at the point this routine is called, it would be
+** an error to have a referenced page. But rather than delete
+** that page and guarantee a subsequent segfault, it seems better
+** to zero it and hope that we error out sanely.
*/
-static void memoryTruncate(Pager *pPager){
+static void pager_truncate_cache(Pager *pPager){
PgHdr *pPg;
PgHdr **ppPg;
int dbSize = pPager->dbSize;
@@ -1938,16 +2535,15 @@ static void memoryTruncate(Pager *pPager){
ppPg = &pPg->pNextAll;
}else{
*ppPg = pPg->pNextAll;
+ IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno));
+ PAGER_INCR(sqlite3_pager_pgfree_count);
unlinkPage(pPg);
makeClean(pPg);
- sqliteFree(pPg);
+ sqlite3_free(pPg);
pPager->nPage--;
}
}
}
-#else
-#define memoryTruncate(p)
-#endif
/*
** Try to obtain a lock on a file. Invoke the busy callback if the lock
@@ -1959,9 +2555,15 @@ static void memoryTruncate(Pager *pPager){
*/
static int pager_wait_on_lock(Pager *pPager, int locktype){
int rc;
+
+ /* The OS lock values must be the same as the Pager lock values */
assert( PAGER_SHARED==SHARED_LOCK );
assert( PAGER_RESERVED==RESERVED_LOCK );
assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK );
+
+ /* If the file is currently unlocked then the size must be unknown */
+ assert( pPager->state>=PAGER_SHARED || pPager->dbSize<0 || MEMDB );
+
if( pPager->state>=locktype ){
rc = SQLITE_OK;
}else{
@@ -1970,6 +2572,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
}while( rc==SQLITE_BUSY && sqlite3InvokeBusyHandler(pPager->pBusyHandler) );
if( rc==SQLITE_OK ){
pPager->state = locktype;
+ IOTRACE(("LOCK %p %d\n", pPager, locktype))
}
}
return rc;
@@ -1978,9 +2581,10 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
/*
** Truncate the file to the number of pages specified.
*/
-int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
+int sqlite3PagerTruncate(Pager *pPager, Pgno nPage){
int rc;
- sqlite3pager_pagecount(pPager);
+ assert( pPager->state>=PAGER_SHARED || MEMDB );
+ sqlite3PagerPagecount(pPager);
if( pPager->errCode ){
rc = pPager->errCode;
return rc;
@@ -1990,24 +2594,25 @@ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
}
if( MEMDB ){
pPager->dbSize = nPage;
- memoryTruncate(pPager);
+ pager_truncate_cache(pPager);
return SQLITE_OK;
}
+ pagerEnter(pPager);
rc = syncJournal(pPager);
+ pagerLeave(pPager);
if( rc!=SQLITE_OK ){
return rc;
}
/* Get an exclusive lock on the database before truncating. */
+ pagerEnter(pPager);
rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
+ pagerLeave(pPager);
if( rc!=SQLITE_OK ){
return rc;
}
rc = pager_truncate(pPager, nPage);
- if( rc==SQLITE_OK ){
- pPager->dbSize = nPage;
- }
return rc;
}
@@ -2025,99 +2630,60 @@ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
** 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;
+int sqlite3PagerClose(Pager *pPager){
#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:
- case PAGER_EXCLUSIVE: {
- /* We ignore any IO errors that occur during the rollback
- ** operation. So disable IO error simulation so that testing
- ** works more easily.
- */
- disable_simulated_io_errors();
- sqlite3pager_rollback(pPager);
- enable_simulated_io_errors();
- if( !MEMDB ){
- sqlite3OsUnlock(pPager->fd, NO_LOCK);
- }
- assert( pPager->errCode || pPager->journalOpen==0 );
- break;
- }
- case PAGER_SHARED: {
- if( !MEMDB ){
- sqlite3OsUnlock(pPager->fd, NO_LOCK);
- }
- break;
+ if( !MEMDB ){
+ sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2);
+ sqlite3_mutex_enter(mutex);
+ if( pPager->pPrev ){
+ pPager->pPrev->pNext = pPager->pNext;
+ }else{
+ sqlite3PagerList = pPager->pNext;
}
- default: {
- /* Do nothing */
- break;
+ if( pPager->pNext ){
+ pPager->pNext->pPrev = pPager->pPrev;
}
+ sqlite3_mutex_leave(mutex);
}
- for(pPg=pPager->pAll; pPg; pPg=pNext){
-#ifndef NDEBUG
- if( MEMDB ){
- PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- assert( !pPg->alwaysRollback );
- assert( !pHist->pOrig );
- assert( !pHist->pStmt );
- }
#endif
- pNext = pPg->pNextAll;
- sqliteFree(pPg);
- }
- TRACE2("CLOSE %d\n", PAGERID(pPager));
+
+ disable_simulated_io_errors();
+ pPager->errCode = 0;
+ pPager->exclusiveMode = 0;
+ pager_reset(pPager);
+ pagerUnlockAndRollback(pPager);
+ enable_simulated_io_errors();
+ PAGERTRACE2("CLOSE %d\n", PAGERID(pPager));
+ IOTRACE(("CLOSE %p\n", pPager))
assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
if( pPager->journalOpen ){
- sqlite3OsClose(&pPager->jfd);
+ sqlite3OsClose(pPager->jfd);
}
- sqliteFree(pPager->aInJournal);
+ sqlite3_free(pPager->aInJournal);
if( pPager->stmtOpen ){
- sqlite3OsClose(&pPager->stfd);
+ sqlite3OsClose(pPager->stfd);
}
- sqlite3OsClose(&pPager->fd);
+ sqlite3OsClose(pPager->fd);
/* Temp files are automatically deleted by the OS
** if( pPager->tempFile ){
** sqlite3OsDelete(pPager->zFilename);
** }
*/
-#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);
+ sqlite3_free(pPager->aHash);
+ sqlite3_free(pPager->pTmpSpace);
+ sqlite3_free(pPager);
return SQLITE_OK;
}
+#if !defined(NDEBUG) || defined(SQLITE_TEST)
/*
** Return the page number for the given page data.
*/
-Pgno sqlite3pager_pagenumber(void *pData){
- PgHdr *p = DATA_TO_PGHDR(pData);
+Pgno sqlite3PagerPagenumber(DbPage *p){
return p->pgno;
}
+#endif
/*
** The page_ref() function increments the reference count for a page.
@@ -2131,25 +2697,10 @@ Pgno sqlite3pager_pagenumber(void *pData){
static void _page_ref(PgHdr *pPg){
if( pPg->nRef==0 ){
/* The page is currently on the freelist. Remove it. */
- if( pPg==pPg->pPager->pFirstSynced ){
- PgHdr *p = pPg->pNextFree;
- while( p && p->needSync ){ p = p->pNextFree; }
- pPg->pPager->pFirstSynced = p;
- }
- if( pPg->pPrevFree ){
- pPg->pPrevFree->pNextFree = pPg->pNextFree;
- }else{
- pPg->pPager->pFirst = pPg->pNextFree;
- }
- if( pPg->pNextFree ){
- pPg->pNextFree->pPrevFree = pPg->pPrevFree;
- }else{
- pPg->pPager->pLast = pPg->pPrevFree;
- }
+ lruListRemove(pPg);
pPg->pPager->nRef++;
}
pPg->nRef++;
- REFINFO(pPg);
}
#ifdef SQLITE_DEBUG
static void page_ref(PgHdr *pPg){
@@ -2157,7 +2708,6 @@ static void _page_ref(PgHdr *pPg){
_page_ref(pPg);
}else{
pPg->nRef++;
- REFINFO(pPg);
}
}
#else
@@ -2168,9 +2718,10 @@ static void _page_ref(PgHdr *pPg){
** Increment the reference count for a page. The input pointer is
** a reference to the page data.
*/
-int sqlite3pager_ref(void *pData){
- PgHdr *pPg = DATA_TO_PGHDR(pData);
+int sqlite3PagerRef(DbPage *pPg){
+ pagerEnter(pPg->pPager);
page_ref(pPg);
+ pagerLeave(pPg->pPager);
return SQLITE_OK;
}
@@ -2189,7 +2740,12 @@ int sqlite3pager_ref(void *pData){
** is synced, then the nRec field is updated, then a second sync occurs.
**
** For temporary databases, we do not care if we are able to rollback
-** after a power failure, so sync occurs.
+** after a power failure, so no sync occurs.
+**
+** If the IOCAP_SEQUENTIAL flag is set for the persistent media on which
+** the database is stored, then OsSync() is never called on the journal
+** file. In this case all that is required is to update the nRec field in
+** the journal header.
**
** This routine clears the needSync field of every page current held in
** memory.
@@ -2198,12 +2754,15 @@ static int syncJournal(Pager *pPager){
PgHdr *pPg;
int rc = SQLITE_OK;
+
/* Sync the journal before modifying the main database
** (assuming there is a journal and it needs to be synced.)
*/
if( pPager->needSync ){
if( !pPager->tempFile ){
+ int iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
assert( pPager->journalOpen );
+
/* assert( !pPager->noSync ); // noSync might be set if synchronous
** was turned off after the transaction was started. Ticket #615 */
#ifndef NDEBUG
@@ -2217,29 +2776,39 @@ static int syncJournal(Pager *pPager){
assert( pPager->journalOff==jSz );
}
#endif
- {
+ if( 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){
/* Write the nRec value into the journal file header. If in
** full-synchronous mode, sync the journal first. This ensures that
** all data has really hit the disk before nRec is updated to mark
- ** it as a candidate for rollback.
+ ** it as a candidate for rollback.
+ **
+ ** This is not required if the persistent media supports the
+ ** SAFE_APPEND property. Because in this case it is not possible
+ ** for garbage data to be appended to the file, the nRec field
+ ** is populated with 0xFFFFFFFF when the journal header is written
+ ** and never needs to be updated.
*/
- if( pPager->fullSync ){
- TRACE2("SYNC journal of %d\n", PAGERID(pPager));
- rc = sqlite3OsSync(pPager->jfd, 0);
+ i64 jrnlOff;
+ if( pPager->fullSync && 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){
+ PAGERTRACE2("SYNC journal of %d\n", PAGERID(pPager));
+ IOTRACE(("JSYNC %p\n", pPager))
+ rc = sqlite3OsSync(pPager->jfd, pPager->sync_flags);
if( rc!=0 ) return rc;
}
- rc = sqlite3OsSeek(pPager->jfd,
- pPager->journalHdr + sizeof(aJournalMagic));
- if( rc ) return rc;
- rc = write32bits(pPager->jfd, pPager->nRec);
- if( rc ) return rc;
- rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff);
+ jrnlOff = pPager->journalHdr + sizeof(aJournalMagic);
+ IOTRACE(("JHDR %p %lld %d\n", pPager, jrnlOff, 4));
+ rc = write32bits(pPager->jfd, jrnlOff, pPager->nRec);
if( rc ) return rc;
}
- TRACE2("SYNC journal of %d\n", PAGERID(pPager));
- rc = sqlite3OsSync(pPager->jfd, pPager->full_fsync);
- if( rc!=0 ) return rc;
+ if( 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){
+ PAGERTRACE2("SYNC journal of %d\n", PAGERID(pPager));
+ IOTRACE(("JSYNC %p\n", pPager))
+ rc = sqlite3OsSync(pPager->jfd, pPager->sync_flags|
+ (pPager->sync_flags==SQLITE_SYNC_FULL?SQLITE_SYNC_DATAONLY:0)
+ );
+ if( rc!=0 ) return rc;
+ }
pPager->journalStarted = 1;
}
pPager->needSync = 0;
@@ -2249,7 +2818,7 @@ static int syncJournal(Pager *pPager){
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
pPg->needSync = 0;
}
- pPager->pFirstSynced = pPager->pFirst;
+ lruListSetFirstSynced(pPager);
}
#ifndef NDEBUG
@@ -2261,7 +2830,7 @@ static int syncJournal(Pager *pPager){
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
assert( pPg->needSync==0 );
}
- assert( pPager->pFirstSynced==pPager->pFirst );
+ assert( pPager->lru.pFirstSynced==pPager->lru.pFirst );
}
#endif
@@ -2301,9 +2870,16 @@ static PgHdr *merge_pagelist(PgHdr *pA, PgHdr *pB){
** connected by pDirty pointers. The pPrevDirty pointers are
** corrupted by this sort.
*/
-#define N_SORT_BUCKET 25
+#define N_SORT_BUCKET_ALLOC 25
+#define N_SORT_BUCKET 25
+#ifdef SQLITE_TEST
+ int sqlite3_pager_n_sort_bucket = 0;
+ #undef N_SORT_BUCKET
+ #define N_SORT_BUCKET \
+ (sqlite3_pager_n_sort_bucket?sqlite3_pager_n_sort_bucket:N_SORT_BUCKET_ALLOC)
+#endif
static PgHdr *sort_pagelist(PgHdr *pIn){
- PgHdr *a[N_SORT_BUCKET], *p;
+ PgHdr *a[N_SORT_BUCKET_ALLOC], *p;
int i;
memset(a, 0, sizeof(a));
while( pIn ){
@@ -2320,6 +2896,11 @@ static PgHdr *sort_pagelist(PgHdr *pIn){
}
}
if( i==N_SORT_BUCKET-1 ){
+ /* Coverage: To get here, there need to be 2^(N_SORT_BUCKET)
+ ** elements in the input list. This is possible, but impractical.
+ ** Testing this line is the point of global variable
+ ** sqlite3_pager_n_sort_bucket.
+ */
a[i] = merge_pagelist(a[i], p);
}
}
@@ -2337,6 +2918,7 @@ static PgHdr *sort_pagelist(PgHdr *pIn){
*/
static int pager_write_pagelist(PgHdr *pList){
Pager *pPager;
+ PgHdr *p;
int rc;
if( pList==0 ) return SQLITE_OK;
@@ -2364,28 +2946,44 @@ static int pager_write_pagelist(PgHdr *pList){
}
pList = sort_pagelist(pList);
+ for(p=pList; p; p=p->pDirty){
+ assert( p->dirty );
+ p->dirty = 0;
+ }
while( pList ){
- assert( pList->dirty );
- rc = sqlite3OsSeek(pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
- if( rc ) return rc;
+
+ /* If the file has not yet been opened, open it now. */
+ if( !pPager->fd->pMethods ){
+ assert(pPager->tempFile);
+ rc = sqlite3PagerOpentemp(pPager->pVfs, pPager->fd, pPager->zFilename,
+ pPager->vfsFlags);
+ 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
+ ** than Pager.dbSize, this means sqlite3PagerTruncate() was called to
** make the file smaller (presumably by auto-vacuum code). Do not write
** any such pages to the file.
*/
if( pList->pgno<=pPager->dbSize ){
+ i64 offset = (pList->pgno-1)*(i64)pPager->pageSize;
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, pData, pPager->pageSize);
- TEST_INCR(pPager->nWrite);
+ PAGERTRACE4("STORE %d page %d hash(%08x)\n",
+ PAGERID(pPager), pList->pgno, pager_pagehash(pList));
+ IOTRACE(("PGOUT %p %d\n", pPager, pList->pgno));
+ rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
+ PAGER_INCR(sqlite3_pager_writedb_count);
+ PAGER_INCR(pPager->nWrite);
+ if( pList->pgno==1 ){
+ memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers));
+ }
}
#ifndef NDEBUG
else{
- TRACE3("NOSTORE %d page %d\n", PAGERID(pPager), pList->pgno);
+ PAGERTRACE3("NOSTORE %d page %d\n", PAGERID(pPager), pList->pgno);
}
#endif
if( rc ) return rc;
- pList->dirty = 0;
#ifdef SQLITE_CHECK_PAGES
pList->pageHash = pager_pagehash(pList);
#endif
@@ -2412,11 +3010,17 @@ static PgHdr *pager_get_all_dirty_pages(Pager *pPager){
** database with the same name. Just delete the journal.
*/
static int hasHotJournal(Pager *pPager){
+ sqlite3_vfs *pVfs = pPager->pVfs;
if( !pPager->useJournal ) return 0;
- if( !sqlite3OsFileExists(pPager->zJournal) ) return 0;
- if( sqlite3OsCheckReservedLock(pPager->fd) ) return 0;
- if( sqlite3pager_pagecount(pPager)==0 ){
- sqlite3OsDelete(pPager->zJournal);
+ if( !pPager->fd->pMethods ) return 0;
+ if( !sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS) ){
+ return 0;
+ }
+ if( sqlite3OsCheckReservedLock(pPager->fd) ){
+ return 0;
+ }
+ if( sqlite3PagerPagecount(pPager)==0 ){
+ sqlite3OsDelete(pVfs, pPager->zJournal, 0);
return 0;
}else{
return 1;
@@ -2429,26 +3033,33 @@ static int hasHotJournal(Pager *pPager){
** 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){
+static int pager_recycle(Pager *pPager, PgHdr **ppPg){
PgHdr *pPg;
*ppPg = 0;
+ /* It is illegal to call this function unless the pager object
+ ** pointed to by pPager has at least one free page (page with nRef==0).
+ */
+ assert(!MEMDB);
+ assert(pPager->lru.pFirst);
+
/* 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;
+ pPg = pPager->lru.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){
+ if( pPg==0 && pPager->lru.pFirst){
+ int iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
int rc = syncJournal(pPager);
if( rc!=0 ){
return rc;
}
- if( pPager->fullSync ){
+ if( pPager->fullSync && 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){
/* 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
@@ -2457,15 +3068,13 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
*/
pPager->nRec = 0;
assert( pPager->journalOff > 0 );
+ assert( pPager->doNotSync==0 );
rc = writeJournalHdr(pPager);
if( rc!=0 ){
return rc;
}
}
- pPg = pPager->pFirst;
- }
- if( pPg==0 ){
- return SQLITE_OK;
+ pPg = pPager->lru.pFirst;
}
assert( pPg->nRef==0 );
@@ -2479,6 +3088,7 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
pPg->dirty = 1;
pPg->pDirty = 0;
rc = pager_write_pagelist( pPg );
+ pPg->dirty = 0;
if( rc!=SQLITE_OK ){
return rc;
}
@@ -2487,107 +3097,444 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
/* 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.
+ ** sqlite3PagerDontRollback() 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 ){
+ IOTRACE(("ALWAYS_ROLLBACK %p\n", pPager))
pPager->alwaysRollback = 1;
}
/* Unlink the old page from the free list and the hash table
*/
unlinkPage(pPg);
- TEST_INCR(pPager->nOvfl);
+ assert( pPg->pgno==0 );
*ppPg = pPg;
return SQLITE_OK;
}
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/*
** 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.
+** by the current thread may be sqlite3_free()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
+** been released, the function returns. 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;
+int sqlite3PagerReleaseMemory(int nReq){
+ int nReleased = 0; /* Bytes of memory released so far */
+ sqlite3_mutex *mutex; /* The MEM2 mutex */
+ Pager *pPager; /* For looping over pagers */
+ BusyHandler *savedBusy; /* Saved copy of the busy handler */
+ int rc = SQLITE_OK;
- /* 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.
+ /* Acquire the memory-management mutex
*/
- if( sqlite3OsInMutex(0) ){
- return 0;
+ mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2);
+ sqlite3_mutex_enter(mutex);
+
+ /* Signal all database connections that memory management wants
+ ** to have access to the pagers.
+ */
+ for(pPager=sqlite3PagerList; pPager; pPager=pPager->pNext){
+ pPager->iInUseMM = 1;
+ }
+
+ while( rc==SQLITE_OK && (nReq<0 || nReleased<nReq) ){
+ PgHdr *pPg;
+ PgHdr *pRecycled;
+
+ /* Try to find a page to recycle that does not require a sync(). If
+ ** this is not possible, find one that does require a sync().
+ */
+ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU));
+ pPg = sqlite3LruPageList.pFirstSynced;
+ while( pPg && (pPg->needSync || pPg->pPager->iInUseDB) ){
+ pPg = pPg->gfree.pNext;
+ }
+ if( !pPg ){
+ pPg = sqlite3LruPageList.pFirst;
+ while( pPg && pPg->pPager->iInUseDB ){
+ pPg = pPg->gfree.pNext;
+ }
+ }
+ sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU));
+
+ /* If pPg==0, then the block above has failed to find a page to
+ ** recycle. In this case return early - no further memory will
+ ** be released.
+ */
+ if( !pPg ) break;
+
+ pPager = pPg->pPager;
+ assert(!pPg->needSync || pPg==pPager->lru.pFirst);
+ assert(pPg->needSync || pPg==pPager->lru.pFirstSynced);
+
+ savedBusy = pPager->pBusyHandler;
+ pPager->pBusyHandler = 0;
+ rc = pager_recycle(pPager, &pRecycled);
+ pPager->pBusyHandler = savedBusy;
+ assert(pRecycled==pPg || rc!=SQLITE_OK);
+ if( rc==SQLITE_OK ){
+ /* 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 );
+ if( pPg==pPager->pAll ){
+ pPager->pAll = pPg->pNextAll;
+ }else{
+ for( pTmp=pPager->pAll; pTmp->pNextAll!=pPg; pTmp=pTmp->pNextAll ){}
+ pTmp->pNextAll = pPg->pNextAll;
+ }
+ nReleased += (
+ sizeof(*pPg) + pPager->pageSize
+ + sizeof(u32) + pPager->nExtra
+ + MEMDB*sizeof(PgHistory)
+ );
+ IOTRACE(("PGFREE %p %d *\n", pPager, pPg->pgno));
+ PAGER_INCR(sqlite3_pager_pgfree_count);
+ sqlite3_free(pPg);
+ pPager->nPage--;
+ }else{
+ /* 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&0xff)==SQLITE_IOERR ||
+ rc==SQLITE_FULL ||
+ rc==SQLITE_BUSY
+ );
+ assert( pPager->state>=PAGER_RESERVED );
+ pager_error(pPager, rc);
+ }
}
- /* 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.
+ /* Clear the memory management flags and release the mutex
*/
- for(i=0; i<=1; i++){
+ for(pPager=sqlite3PagerList; pPager; pPager=pPager->pNext){
+ pPager->iInUseMM = 0;
+ }
+ sqlite3_mutex_leave(mutex);
- /* 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;
+ /* Return the number of bytes released
+ */
+ return nReleased;
+}
+#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
+
+/*
+** Read the content of page pPg out of the database file.
+*/
+static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){
+ int rc;
+ i64 offset;
+ assert( MEMDB==0 );
+ assert(pPager->fd->pMethods||pPager->tempFile);
+ if( !pPager->fd->pMethods ){
+ return SQLITE_IOERR_SHORT_READ;
+ }
+ offset = (pgno-1)*(i64)pPager->pageSize;
+ rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize, offset);
+ PAGER_INCR(sqlite3_pager_readdb_count);
+ PAGER_INCR(pPager->nRead);
+ IOTRACE(("PGIN %p %d\n", pPager, pgno));
+ if( pgno==1 ){
+ memcpy(&pPager->dbFileVers, &((u8*)PGHDR_TO_DATA(pPg))[24],
+ sizeof(pPager->dbFileVers));
+ }
+ CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
+ PAGERTRACE4("FETCH %d page %d hash(%08x)\n",
+ PAGERID(pPager), pPg->pgno, pager_pagehash(pPg));
+ return 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).
+
+/*
+** This function is called to obtain the shared lock required before
+** data may be read from the pager cache. If the shared lock has already
+** been obtained, this function is a no-op.
+**
+** Immediately after obtaining the shared lock (if required), this function
+** checks for a hot-journal file. If one is found, an emergency rollback
+** is performed immediately.
+*/
+static int pagerSharedLock(Pager *pPager){
+ int rc = SQLITE_OK;
+ int isHot = 0;
+
+ /* If this database is opened for exclusive access, has no outstanding
+ ** page references and is in an error-state, now is the chance to clear
+ ** the error. Discard the contents of the pager-cache and treat any
+ ** open journal file as a hot-journal.
+ */
+ if( !MEMDB && pPager->exclusiveMode && pPager->nRef==0 && pPager->errCode ){
+ if( pPager->journalOpen ){
+ isHot = 1;
+ }
+ pager_reset(pPager);
+ pPager->errCode = SQLITE_OK;
+ }
+
+ /* If the pager is still in an error state, do not proceed. The error
+ ** state will be cleared at some point in the future when all page
+ ** references are dropped and the cache can be discarded.
+ */
+ if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
+ return pPager->errCode;
+ }
+
+ if( pPager->state==PAGER_UNLOCK || isHot ){
+ sqlite3_vfs *pVfs = pPager->pVfs;
+ if( !MEMDB ){
+ assert( pPager->nRef==0 );
+ if( !pPager->noReadlock ){
+ rc = pager_wait_on_lock(pPager, SHARED_LOCK);
+ if( rc!=SQLITE_OK ){
+ return pager_error(pPager, rc);
+ }
+ assert( pPager->state>=SHARED_LOCK );
+ }
+
+ /* If a journal file exists, and there is no RESERVED lock on the
+ ** database file, then it either needs to be played back or deleted.
*/
- 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.
+ if( hasHotJournal(pPager) || isHot ){
+ /* 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
+ ** database file, detect the RESERVED lock, and conclude that the
+ ** database is safe to read while this process is still rolling it
+ ** back.
+ **
+ ** Because the intermediate RESERVED lock is not requested, the
+ ** second process will get to this point in the code and fail to
+ ** obtain its own EXCLUSIVE lock on the database file.
+ */
+ if( pPager->state<EXCLUSIVE_LOCK ){
+ rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
+ if( rc!=SQLITE_OK ){
+ pager_unlock(pPager);
+ return pager_error(pPager, rc);
+ }
+ pPager->state = PAGER_EXCLUSIVE;
+ }
+
+ /* Open the journal for reading only. Return SQLITE_BUSY if
+ ** we are unable to open the journal file.
+ **
+ ** The journal file does not need to be locked itself. The
+ ** journal file is never open unless the main database file holds
+ ** a write lock, so there is never any chance of two or more
+ ** processes opening the journal at the same time.
**
- ** Todo: Check the Pager.pStmt list to make sure this is Ok. It
- ** probably is though.
+ ** Open the journal for read/write access. This is because in
+ ** exclusive-access mode the file descriptor will be kept open and
+ ** possibly used for a transaction later on. On some systems, the
+ ** OsTruncate() call used in exclusive-access mode also requires
+ ** a read/write file handle.
*/
- 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;
+ if( !isHot ){
+ rc = SQLITE_BUSY;
+ if( sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS) ){
+ int fout = 0;
+ int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
+ assert( !pPager->tempFile );
+ rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout);
+ assert( rc!=SQLITE_OK || pPager->jfd->pMethods );
+ if( fout&SQLITE_OPEN_READONLY ){
+ rc = SQLITE_BUSY;
+ sqlite3OsClose(pPager->jfd);
+ }
+ }
+ }
+ if( rc!=SQLITE_OK ){
+ pager_unlock(pPager);
+ return ((rc==SQLITE_NOMEM||rc==SQLITE_IOERR_NOMEM)?rc:SQLITE_BUSY);
+ }
+ pPager->journalOpen = 1;
+ pPager->journalStarted = 0;
+ pPager->journalOff = 0;
+ pPager->setMaster = 0;
+ pPager->journalHdr = 0;
+
+ /* Playback and delete the journal. Drop the database write
+ ** lock and reacquire the read lock.
+ */
+ rc = pager_playback(pPager, 1);
+ if( rc!=SQLITE_OK ){
+ return pager_error(pPager, rc);
}
- nReleased += sqliteAllocSize(pPg);
- sqliteFree(pPg);
+ assert(pPager->state==PAGER_SHARED ||
+ (pPager->exclusiveMode && pPager->state>PAGER_SHARED)
+ );
}
- 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.
+ if( pPager->pAll ){
+ /* The shared-lock has just been acquired on the database file
+ ** and there are already pages in the cache (from a previous
+ ** read or write transaction). Check to see if the database
+ ** has been modified. If the database has changed, flush the
+ ** cache.
+ **
+ ** Database changes is detected by looking at 15 bytes beginning
+ ** at offset 24 into the file. The first 4 of these 16 bytes are
+ ** a 32-bit counter that is incremented with each change. The
+ ** other bytes change randomly with each file change when
+ ** a codec is in use.
+ **
+ ** There is a vanishingly small chance that a change will not be
+ ** detected. The chance of an undetected change is so small that
+ ** it can be neglected.
*/
- assert( rc==SQLITE_IOERR || rc==SQLITE_FULL );
- assert( p->state>=PAGER_RESERVED );
- pager_error(p, rc);
+ char dbFileVers[sizeof(pPager->dbFileVers)];
+ sqlite3PagerPagecount(pPager);
+
+ if( pPager->errCode ){
+ return pPager->errCode;
+ }
+
+ if( pPager->dbSize>0 ){
+ IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
+ rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ }else{
+ memset(dbFileVers, 0, sizeof(dbFileVers));
+ }
+
+ if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){
+ pager_reset(pPager);
+ }
}
}
+ assert( pPager->exclusiveMode || pPager->state<=PAGER_SHARED );
+ if( pPager->state==PAGER_UNLOCK ){
+ pPager->state = PAGER_SHARED;
+ }
}
- return nReleased;
+ return rc;
+}
+
+/*
+** Allocate a PgHdr object. Either create a new one or reuse
+** an existing one that is not otherwise in use.
+**
+** A new PgHdr structure is created if any of the following are
+** true:
+**
+** (1) We have not exceeded our maximum allocated cache size
+** as set by the "PRAGMA cache_size" command.
+**
+** (2) There are no unused PgHdr objects available at this time.
+**
+** (3) This is an in-memory database.
+**
+** (4) There are no PgHdr objects that do not require a journal
+** file sync and a sync of the journal file is currently
+** prohibited.
+**
+** Otherwise, reuse an existing PgHdr. In other words, reuse an
+** existing PgHdr if all of the following are true:
+**
+** (1) We have reached or exceeded the maximum cache size
+** allowed by "PRAGMA cache_size".
+**
+** (2) There is a PgHdr available with PgHdr->nRef==0
+**
+** (3) We are not in an in-memory database
+**
+** (4) Either there is an available PgHdr that does not need
+** to be synced to disk or else disk syncing is currently
+** allowed.
+*/
+static int pagerAllocatePage(Pager *pPager, PgHdr **ppPg){
+ int rc = SQLITE_OK;
+ PgHdr *pPg;
+ int nByteHdr;
+
+ /* Create a new PgHdr if any of the four conditions defined
+ ** above are met: */
+ if( pPager->nPage<pPager->mxPage
+ || pPager->lru.pFirst==0
+ || MEMDB
+ || (pPager->lru.pFirstSynced==0 && pPager->doNotSync)
+ ){
+ if( pPager->nPage>=pPager->nHash ){
+ pager_resize_hash_table(pPager,
+ pPager->nHash<256 ? 256 : pPager->nHash*2);
+ if( pPager->nHash==0 ){
+ rc = SQLITE_NOMEM;
+ goto pager_allocate_out;
+ }
+ }
+ pagerLeave(pPager);
+ nByteHdr = sizeof(*pPg) + sizeof(u32) + pPager->nExtra
+ + MEMDB*sizeof(PgHistory);
+ pPg = sqlite3_malloc( nByteHdr + pPager->pageSize );
+ pagerEnter(pPager);
+ if( pPg==0 ){
+ rc = SQLITE_NOMEM;
+ goto pager_allocate_out;
+ }
+ memset(pPg, 0, nByteHdr);
+ pPg->pData = (void*)(nByteHdr + (char*)pPg);
+ pPg->pPager = pPager;
+ pPg->pNextAll = pPager->pAll;
+ pPager->pAll = pPg;
+ pPager->nPage++;
+ }else{
+ /* Recycle an existing page with a zero ref-count. */
+ rc = pager_recycle(pPager, &pPg);
+ if( rc==SQLITE_BUSY ){
+ rc = SQLITE_IOERR_BLOCKED;
+ }
+ if( rc!=SQLITE_OK ){
+ goto pager_allocate_out;
+ }
+ assert( pPager->state>=SHARED_LOCK );
+ assert(pPg);
+ }
+ *ppPg = pPg;
+
+pager_allocate_out:
+ return rc;
+}
+
+/*
+** Make sure we have the content for a page. If the page was
+** previously acquired with noContent==1, then the content was
+** just initialized to zeros instead of being read from disk.
+** But now we need the real data off of disk. So make sure we
+** have it. Read it in if we do not have it already.
+*/
+static int pager_get_content(PgHdr *pPg){
+ if( pPg->needRead ){
+ int rc = readDbPage(pPg->pPager, pPg, pPg->pgno);
+ if( rc==SQLITE_OK ){
+ pPg->needRead = 0;
+ }else{
+ return rc;
+ }
+ }
+ return SQLITE_OK;
}
-#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
/*
** Acquire a page.
@@ -2595,7 +3542,7 @@ int sqlite3pager_release_memory(int nReq){
** A read lock on the disk file is obtained when the first page is acquired.
** This read lock is dropped when the last page is released.
**
-** A _get works for any page number greater than 0. If the database
+** This routine works for any page number greater than 0. If the database
** file is smaller than the requested page, then no actual disk
** read occurs and the memory image of the page is initialized to
** all zeros. The extra data appended to a page is always initialized
@@ -2604,18 +3551,34 @@ int sqlite3pager_release_memory(int nReq){
** The acquisition might fail for several reasons. In all cases,
** an appropriate error code is returned and *ppPage is set to NULL.
**
-** See also sqlite3pager_lookup(). Both this routine and _lookup() attempt
+** See also sqlite3PagerLookup(). Both this routine and Lookup() attempt
** to find a page in the in-memory cache first. If the page is not already
-** in memory, this routine goes to disk to read it in whereas _lookup()
+** in memory, this routine goes to disk to read it in whereas Lookup()
** just returns 0. This routine acquires a read-lock the first time it
** has to go to disk, and could also playback an old journal if necessary.
-** Since _lookup() never goes to disk, it never has to deal with locks
+** Since Lookup() never goes to disk, it never has to deal with locks
** or journal files.
+**
+** If noContent is false, the page contents are actually read from disk.
+** If noContent is true, it means that we do not care about the contents
+** of the page at this time, so do not do a disk read. Just fill in the
+** page content with zeros. But mark the fact that we have not read the
+** content by setting the PgHdr.needRead flag. Later on, if
+** sqlite3PagerWrite() is called on this page or if this routine is
+** called again with noContent==0, that means that the content is needed
+** and the disk read should occur at that point.
*/
-int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
+static int pagerAcquire(
+ Pager *pPager, /* The pager open on the database file */
+ Pgno pgno, /* Page number to fetch */
+ DbPage **ppPage, /* Write a pointer to the page here */
+ int noContent /* Do not bother reading content from disk if true */
+){
PgHdr *pPg;
int rc;
+ assert( pPager->state==PAGER_UNLOCK || pPager->nRef>0 || pgno==1 );
+
/* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
** number greater than this, or zero, is requested.
*/
@@ -2627,121 +3590,34 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
*/
assert( pPager!=0 );
*ppPage = 0;
- if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
- return pPager->errCode;
- }
/* If this is the first page accessed, then get a SHARED lock
- ** on the database file.
+ ** on the database file. pagerSharedLock() is a no-op if
+ ** a database lock is already held.
*/
- if( pPager->nRef==0 && !MEMDB ){
- if( !pPager->noReadlock ){
- rc = pager_wait_on_lock(pPager, SHARED_LOCK);
- if( rc!=SQLITE_OK ){
- return pager_error(pPager, rc);
- }
- }
-
- /* If a journal file exists, and there is no RESERVED lock on the
- ** database file, then it either needs to be played back or deleted.
- */
- if( hasHotJournal(pPager) ){
- /* 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
- ** database file, detect the RESERVED lock, and conclude that the
- ** database is safe to read while this process is still rolling it
- ** back.
- **
- ** Because the intermediate RESERVED lock is not requested, the
- ** 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);
- if( rc!=SQLITE_OK ){
- sqlite3OsUnlock(pPager->fd, NO_LOCK);
- pPager->state = PAGER_UNLOCK;
- return pager_error(pPager, rc);
- }
- pPager->state = PAGER_EXCLUSIVE;
-
- /* Open the journal for reading only. Return SQLITE_BUSY if
- ** we are unable to open the journal file.
- **
- ** The journal file does not need to be locked itself. The
- ** journal file is never open unless the main database file holds
- ** a write lock, so there is never any chance of two or more
- ** processes opening the journal at the same time.
- */
- rc = sqlite3OsOpenReadOnly(pPager->zJournal, &pPager->jfd);
- if( rc!=SQLITE_OK ){
- sqlite3OsUnlock(pPager->fd, NO_LOCK);
- pPager->state = PAGER_UNLOCK;
- return SQLITE_BUSY;
- }
- pPager->journalOpen = 1;
- pPager->journalStarted = 0;
- pPager->journalOff = 0;
- pPager->setMaster = 0;
- pPager->journalHdr = 0;
-
- /* Playback and delete the journal. Drop the database write
- ** lock and reacquire the read lock.
- */
- rc = pager_playback(pPager);
- if( rc!=SQLITE_OK ){
- return pager_error(pPager, rc);
- }
- }
- pPg = 0;
- }else{
- /* Search for page in cache */
- pPg = pager_lookup(pPager, pgno);
- if( MEMDB && pPager->state==PAGER_UNLOCK ){
- pPager->state = PAGER_SHARED;
- }
+ rc = pagerSharedLock(pPager);
+ if( rc!=SQLITE_OK ){
+ return rc;
}
+ assert( pPager->state!=PAGER_UNLOCK );
+
+ pPg = pager_lookup(pPager, pgno);
if( pPg==0 ){
/* The requested page is not in the page cache. */
+ int nMax;
int h;
- 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 ){
- return SQLITE_NOMEM;
- }
- memset(pPg, 0, sizeof(*pPg));
- if( MEMDB ){
- memset(PGHDR_TO_HIST(pPg, pPager), 0, sizeof(PgHistory));
- }
- pPg->pPager = pPager;
- pPg->pNextAll = pPager->pAll;
- pPager->pAll = pPg;
- pPager->nPage++;
- if( pPager->nPage>pPager->nMaxPage ){
- assert( pPager->nMaxPage==(pPager->nPage-1) );
- pPager->nMaxPage++;
- }
- }else{
- rc = pager_recycle(pPager, 1, &pPg);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- assert(pPg) ;
+ PAGER_INCR(pPager->nMiss);
+ rc = pagerAllocatePage(pPager, &pPg);
+ if( rc!=SQLITE_OK ){
+ return rc;
}
+
pPg->pgno = pgno;
+ assert( !MEMDB || pgno>pPager->stmtSize );
if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){
+#if 0
sqlite3CheckMemory(pPager->aInJournal, pgno/8);
+#endif
assert( pPager->journalOpen );
pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0;
pPg->needSync = 0;
@@ -2749,56 +3625,40 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
pPg->inJournal = 0;
pPg->needSync = 0;
}
- if( pPager->aInStmt && (int)pgno<=pPager->stmtSize
- && (pPager->aInStmt[pgno/8] & (1<<(pgno&7)))!=0 ){
- page_add_to_stmt_list(pPg);
- }else{
- page_remove_from_stmt_list(pPg);
- }
+
makeClean(pPg);
pPg->nRef = 1;
- REFINFO(pPg);
pPager->nRef++;
if( pPager->nExtra>0 ){
memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
}
+ nMax = sqlite3PagerPagecount(pPager);
if( pPager->errCode ){
- sqlite3pager_unref(PGHDR_TO_DATA(pPg));
rc = pPager->errCode;
+ sqlite3PagerUnref(pPg);
return rc;
}
/* 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 ){
+ if( nMax<(int)pgno || MEMDB || (noContent && !pPager->alwaysRollback) ){
+ if( pgno>pPager->mxPgno ){
+ sqlite3PagerUnref(pPg);
+ return SQLITE_FULL;
+ }
memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
+ pPg->needRead = noContent && !pPager->alwaysRollback;
+ IOTRACE(("ZERO %p %d\n", pPager, pgno));
}else{
- assert( MEMDB==0 );
- rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize);
- if( rc==SQLITE_OK ){
- rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg),
- pPager->pageSize);
- }
- TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
- CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
- if( rc!=SQLITE_OK ){
- i64 fileSize;
- 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);
+ rc = readDbPage(pPager, pPg, pgno);
+ if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
+ pPg->pgno = 0;
+ sqlite3PagerUnref(pPg);
+ return rc;
}
+ pPg->needRead = 0;
}
/* Link the page into the page hash table */
@@ -2816,36 +3676,60 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
#endif
}else{
/* The requested page is in the page cache. */
- TEST_INCR(pPager->nHit);
+ assert(pPager->nRef>0 || pgno==1);
+ PAGER_INCR(pPager->nHit);
+ if( !noContent ){
+ rc = pager_get_content(pPg);
+ if( rc ){
+ return rc;
+ }
+ }
page_ref(pPg);
}
- *ppPage = PGHDR_TO_DATA(pPg);
+ *ppPage = pPg;
return SQLITE_OK;
}
+int sqlite3PagerAcquire(
+ Pager *pPager, /* The pager open on the database file */
+ Pgno pgno, /* Page number to fetch */
+ DbPage **ppPage, /* Write a pointer to the page here */
+ int noContent /* Do not bother reading content from disk if true */
+){
+ int rc;
+ pagerEnter(pPager);
+ rc = pagerAcquire(pPager, pgno, ppPage, noContent);
+ pagerLeave(pPager);
+ return rc;
+}
+
/*
** Acquire a page if it is already in the in-memory cache. Do
** not read the page from disk. Return a pointer to the page,
** or 0 if the page is not in cache.
**
-** See also sqlite3pager_get(). The difference between this routine
-** and sqlite3pager_get() is that _get() will go to the disk and read
+** See also sqlite3PagerGet(). The difference between this routine
+** and sqlite3PagerGet() is that _get() will go to the disk and read
** in the page if the page is not already in cache. This routine
** returns NULL if the page is not in cache or if a disk I/O error
** has ever happened.
*/
-void *sqlite3pager_lookup(Pager *pPager, Pgno pgno){
- PgHdr *pPg;
+DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
+ PgHdr *pPg = 0;
assert( pPager!=0 );
assert( pgno!=0 );
- if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
- return 0;
+
+ pagerEnter(pPager);
+ if( pPager->state==PAGER_UNLOCK ){
+ assert( !pPager->pAll || pPager->exclusiveMode );
+ }else if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
+ /* Do nothing */
+ }else if( (pPg = pager_lookup(pPager, pgno))!=0 ){
+ page_ref(pPg);
}
- pPg = pager_lookup(pPager, pgno);
- if( pPg==0 ) return 0;
- page_ref(pPg);
- return PGHDR_TO_DATA(pPg);
+ pagerLeave(pPager);
+ return pPg;
}
/*
@@ -2856,15 +3740,14 @@ void *sqlite3pager_lookup(Pager *pPager, Pgno pgno){
** are released, a rollback occurs and the lock on the database is
** removed.
*/
-int sqlite3pager_unref(void *pData){
- PgHdr *pPg;
+int sqlite3PagerUnref(DbPage *pPg){
+ Pager *pPager = pPg->pPager;
/* Decrement the reference count for this page
*/
- pPg = DATA_TO_PGHDR(pData);
assert( pPg->nRef>0 );
+ pagerEnter(pPg->pPager);
pPg->nRef--;
- REFINFO(pPg);
CHECK_PAGE(pPg);
@@ -2872,21 +3755,10 @@ int sqlite3pager_unref(void *pData){
** destructor and add the page to the freelist.
*/
if( pPg->nRef==0 ){
- Pager *pPager;
- pPager = pPg->pPager;
- pPg->pNextFree = 0;
- pPg->pPrevFree = pPager->pLast;
- pPager->pLast = pPg;
- if( pPg->pPrevFree ){
- pPg->pPrevFree->pNextFree = pPg;
- }else{
- pPager->pFirst = pPg;
- }
- if( pPg->needSync==0 && pPager->pFirstSynced==0 ){
- pPager->pFirstSynced = pPg;
- }
+
+ lruListAdd(pPg);
if( pPager->xDestructor ){
- pPager->xDestructor(pData, pPager->pageSize);
+ pPager->xDestructor(pPg, pPager->pageSize);
}
/* When all pages reach the freelist, drop the read lock from
@@ -2894,10 +3766,11 @@ int sqlite3pager_unref(void *pData){
*/
pPager->nRef--;
assert( pPager->nRef>=0 );
- if( pPager->nRef==0 && !MEMDB ){
- pager_reset(pPager);
+ if( pPager->nRef==0 && (!pPager->exclusiveMode || pPager->journalOff>0) ){
+ pagerUnlockAndRollback(pPager);
}
}
+ pagerLeave(pPager);
return SQLITE_OK;
}
@@ -2909,29 +3782,46 @@ int sqlite3pager_unref(void *pData){
** write lock if anything goes wrong.
*/
static int pager_open_journal(Pager *pPager){
+ sqlite3_vfs *pVfs = pPager->pVfs;
+ int flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_CREATE);
+
int rc;
assert( !MEMDB );
assert( pPager->state>=PAGER_RESERVED );
assert( pPager->journalOpen==0 );
assert( pPager->useJournal );
assert( pPager->aInJournal==0 );
- sqlite3pager_pagecount(pPager);
- pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 );
+ sqlite3PagerPagecount(pPager);
+ pagerLeave(pPager);
+ pPager->aInJournal = sqlite3MallocZero( pPager->dbSize/8 + 1 );
+ pagerEnter(pPager);
if( pPager->aInJournal==0 ){
rc = SQLITE_NOMEM;
goto failed_to_open_journal;
}
- rc = sqlite3OsOpenExclusive(pPager->zJournal, &pPager->jfd,
- pPager->tempFile);
+
+ if( pPager->tempFile ){
+ flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
+ }else{
+ flags |= (SQLITE_OPEN_MAIN_JOURNAL);
+ }
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ rc = sqlite3JournalOpen(
+ pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager)
+ );
+#else
+ rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0);
+#endif
+ assert( rc!=SQLITE_OK || pPager->jfd->pMethods );
pPager->journalOff = 0;
pPager->setMaster = 0;
pPager->journalHdr = 0;
if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_NOMEM ){
+ sqlite3OsDelete(pVfs, pPager->zJournal, 0);
+ }
goto failed_to_open_journal;
}
- 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;
@@ -2946,10 +3836,10 @@ static int pager_open_journal(Pager *pPager){
rc = writeJournalHdr(pPager);
if( pPager->stmtAutoopen && rc==SQLITE_OK ){
- rc = sqlite3pager_stmt_begin(pPager);
+ rc = sqlite3PagerStmtBegin(pPager);
}
- if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
- rc = pager_unwritelock(pPager);
+ if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM && rc!=SQLITE_IOERR_NOMEM ){
+ rc = pager_end_transaction(pPager);
if( rc==SQLITE_OK ){
rc = SQLITE_FULL;
}
@@ -2957,19 +3847,8 @@ static int pager_open_journal(Pager *pPager){
return rc;
failed_to_open_journal:
- sqliteFree(pPager->aInJournal);
+ sqlite3_free(pPager->aInJournal);
pPager->aInJournal = 0;
- 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;
}
@@ -2977,10 +3856,10 @@ failed_to_open_journal:
** Acquire a write-lock on the database. The lock is removed when
** the any of the following happen:
**
-** * sqlite3pager_commit() is called.
-** * sqlite3pager_rollback() is called.
-** * sqlite3pager_close() is called.
-** * sqlite3pager_unref() is called to on every outstanding page.
+** * sqlite3PagerCommitPhaseTwo() is called.
+** * sqlite3PagerRollback() is called.
+** * sqlite3PagerClose() is called.
+** * sqlite3PagerUnref() is called to on every outstanding page.
**
** The first parameter to this routine is a pointer to any open page of the
** database file. Nothing changes about the page - it is used merely to
@@ -3000,10 +3879,10 @@ failed_to_open_journal:
** immediately instead of waiting until we try to flush the cache. The
** exFlag is ignored if a transaction is already active.
*/
-int sqlite3pager_begin(void *pData, int exFlag){
- PgHdr *pPg = DATA_TO_PGHDR(pData);
+int sqlite3PagerBegin(DbPage *pPg, int exFlag){
Pager *pPager = pPg->pPager;
int rc = SQLITE_OK;
+ pagerEnter(pPager);
assert( pPg->nRef>0 );
assert( pPager->state!=PAGER_UNLOCK );
if( pPager->state==PAGER_SHARED ){
@@ -3020,15 +3899,37 @@ int sqlite3pager_begin(void *pData, int exFlag){
}
}
if( rc!=SQLITE_OK ){
+ pagerLeave(pPager);
return rc;
}
pPager->dirtyCache = 0;
- TRACE2("TRANSACTION %d\n", PAGERID(pPager));
+ PAGERTRACE2("TRANSACTION %d\n", PAGERID(pPager));
if( pPager->useJournal && !pPager->tempFile ){
rc = pager_open_journal(pPager);
}
}
+ }else if( pPager->journalOpen && pPager->journalOff==0 ){
+ /* This happens when the pager was in exclusive-access mode last
+ ** time a (read or write) transaction was successfully concluded
+ ** by this connection. Instead of deleting the journal file it was
+ ** kept open and truncated to 0 bytes.
+ */
+ assert( pPager->nRec==0 );
+ assert( pPager->origDbSize==0 );
+ assert( pPager->aInJournal==0 );
+ sqlite3PagerPagecount(pPager);
+ pagerLeave(pPager);
+ pPager->aInJournal = sqlite3MallocZero( pPager->dbSize/8 + 1 );
+ pagerEnter(pPager);
+ if( !pPager->aInJournal ){
+ rc = SQLITE_NOMEM;
+ }else{
+ pPager->origDbSize = pPager->dbSize;
+ rc = writeJournalHdr(pPager);
+ }
}
+ assert( !pPager->journalOpen || pPager->journalOff>0 || rc!=SQLITE_OK );
+ pagerLeave(pPager);
return rc;
}
@@ -3057,11 +3958,14 @@ static void makeClean(PgHdr *pPg){
if( pPg->dirty ){
pPg->dirty = 0;
if( pPg->pDirty ){
+ assert( pPg->pDirty->pPrevDirty==pPg );
pPg->pDirty->pPrevDirty = pPg->pPrevDirty;
}
if( pPg->pPrevDirty ){
+ assert( pPg->pPrevDirty->pDirty==pPg );
pPg->pPrevDirty->pDirty = pPg->pDirty;
}else{
+ assert( pPg->pPager->pDirty==pPg );
pPg->pPager->pDirty = pPg->pDirty;
}
}
@@ -3082,11 +3986,11 @@ static void makeClean(PgHdr *pPg){
** If the journal file could not be written because the disk is full,
** then this routine returns SQLITE_FULL and does an immediate rollback.
** All subsequent write attempts also return SQLITE_FULL until there
-** is a call to sqlite3pager_commit() or sqlite3pager_rollback() to
+** is a call to sqlite3PagerCommit() or sqlite3PagerRollback() to
** reset.
*/
-int sqlite3pager_write(void *pData){
- PgHdr *pPg = DATA_TO_PGHDR(pData);
+static int pager_write(PgHdr *pPg){
+ void *pData = PGHDR_TO_DATA(pPg);
Pager *pPager = pPg->pPager;
int rc = SQLITE_OK;
@@ -3103,11 +4007,24 @@ int sqlite3pager_write(void *pData){
CHECK_PAGE(pPg);
+ /* If this page was previously acquired with noContent==1, that means
+ ** we didn't really read in the content of the page. This can happen
+ ** (for example) when the page is being moved to the freelist. But
+ ** now we are (perhaps) moving the page off of the freelist for
+ ** reuse and we need to know its original content so that content
+ ** can be stored in the rollback journal. So do the read at this
+ ** time.
+ */
+ rc = pager_get_content(pPg);
+ if( rc ){
+ return rc;
+ }
+
/* Mark the page as dirty. If the page has already been written
** to the journal then we can return right away.
*/
makeDirty(pPg);
- if( pPg->inJournal && (pPg->inStmt || pPager->stmtInUse==0) ){
+ if( pPg->inJournal && (pageInStatement(pPg) || pPager->stmtInUse==0) ){
pPager->dirtyCache = 1;
}else{
@@ -3119,7 +4036,7 @@ int sqlite3pager_write(void *pData){
** create it if it does not.
*/
assert( pPager->state!=PAGER_UNLOCK );
- rc = sqlite3pager_begin(pData, 0);
+ rc = sqlite3PagerBegin(pPg, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -3137,37 +4054,42 @@ int sqlite3pager_write(void *pData){
*/
if( !pPg->inJournal && (pPager->useJournal || MEMDB) ){
if( (int)pPg->pgno <= pPager->origDbSize ){
- int szPg;
if( MEMDB ){
PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- TRACE3("JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
+ PAGERTRACE3("JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
assert( pHist->pOrig==0 );
- pHist->pOrig = sqliteMallocRaw( pPager->pageSize );
- if( pHist->pOrig ){
- memcpy(pHist->pOrig, PGHDR_TO_DATA(pPg), pPager->pageSize);
+ pHist->pOrig = sqlite3_malloc( pPager->pageSize );
+ if( !pHist->pOrig ){
+ return SQLITE_NOMEM;
}
+ memcpy(pHist->pOrig, PGHDR_TO_DATA(pPg), pPager->pageSize);
}else{
- u32 cksum, saved;
- char *pData2, *pEnd;
+ u32 cksum;
+ char *pData2;
+
/* 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) );
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;
- 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);
- *(u32*)pEnd = saved;
-
- /* An error has occured writing to the journal file. The
+ rc = write32bits(pPager->jfd, pPager->journalOff, pPg->pgno);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize,
+ pPager->journalOff + 4);
+ pPager->journalOff += pPager->pageSize+4;
+ }
+ if( rc==SQLITE_OK ){
+ rc = write32bits(pPager->jfd, pPager->journalOff, cksum);
+ pPager->journalOff += 4;
+ }
+ IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno,
+ pPager->journalOff, pPager->pageSize));
+ PAGER_INCR(sqlite3_pager_writej_count);
+ PAGERTRACE5("JOURNAL %d page %d needSync=%d hash(%08x)\n",
+ PAGERID(pPager), pPg->pgno, pPg->needSync, pager_pagehash(pPg));
+
+ /* An error has occured writing to the journal file. The
** transaction will be rolled back by the layer above.
*/
if( rc!=SQLITE_OK ){
@@ -3180,12 +4102,11 @@ int sqlite3pager_write(void *pData){
pPg->needSync = !pPager->noSync;
if( pPager->stmtInUse ){
pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
- page_add_to_stmt_list(pPg);
}
}
}else{
pPg->needSync = !pPager->journalStarted && !pPager->noSync;
- TRACE4("APPEND %d page %d needSync=%d\n",
+ PAGERTRACE4("APPEND %d page %d needSync=%d\n",
PAGERID(pPager), pPg->pgno, pPg->needSync);
}
if( pPg->needSync ){
@@ -3199,21 +4120,28 @@ int sqlite3pager_write(void *pData){
** the statement journal format differs from the standard journal format
** in that it omits the checksums and the header.
*/
- if( pPager->stmtInUse && !pPg->inStmt && (int)pPg->pgno<=pPager->stmtSize ){
+ if( pPager->stmtInUse
+ && !pageInStatement(pPg)
+ && (int)pPg->pgno<=pPager->stmtSize
+ ){
assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
if( MEMDB ){
PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
assert( pHist->pStmt==0 );
- pHist->pStmt = sqliteMallocRaw( pPager->pageSize );
+ pHist->pStmt = sqlite3_malloc( pPager->pageSize );
if( pHist->pStmt ){
memcpy(pHist->pStmt, PGHDR_TO_DATA(pPg), pPager->pageSize);
}
- TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
+ PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
+ page_add_to_stmt_list(pPg);
}else{
- 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);
+ i64 offset = pPager->stmtNRec*(4+pPager->pageSize);
+ char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7);
+ rc = write32bits(pPager->stfd, offset, pPg->pgno);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize, offset+4);
+ }
+ PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -3221,12 +4149,12 @@ int sqlite3pager_write(void *pData){
assert( pPager->aInStmt!=0 );
pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
}
- page_add_to_stmt_list(pPg);
}
}
/* Update the database size and return.
*/
+ assert( pPager->state>=PAGER_SHARED );
if( pPager->dbSize<(int)pPg->pgno ){
pPager->dbSize = pPg->pgno;
if( !MEMDB && pPager->dbSize==PENDING_BYTE/pPager->pageSize ){
@@ -3237,13 +4165,107 @@ int sqlite3pager_write(void *pData){
}
/*
+** This function is used to mark a data-page as writable. It uses
+** pager_write() to open a journal file (if it is not already open)
+** and write the page *pData to the journal.
+**
+** The difference between this function and pager_write() is that this
+** function also deals with the special case where 2 or more pages
+** fit on a single disk sector. In this case all co-resident pages
+** must have been written to the journal file before returning.
+*/
+int sqlite3PagerWrite(DbPage *pDbPage){
+ int rc = SQLITE_OK;
+
+ PgHdr *pPg = pDbPage;
+ Pager *pPager = pPg->pPager;
+ Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
+
+ pagerEnter(pPager);
+ if( !MEMDB && nPagePerSector>1 ){
+ Pgno nPageCount; /* Total number of pages in database file */
+ Pgno pg1; /* First page of the sector pPg is located on. */
+ int nPage; /* Number of pages starting at pg1 to journal */
+ int ii;
+ int needSync = 0;
+
+ /* Set the doNotSync flag to 1. This is because we cannot allow a journal
+ ** header to be written between the pages journaled by this function.
+ */
+ assert( pPager->doNotSync==0 );
+ pPager->doNotSync = 1;
+
+ /* This trick assumes that both the page-size and sector-size are
+ ** an integer power of 2. It sets variable pg1 to the identifier
+ ** of the first page of the sector pPg is located on.
+ */
+ pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1;
+
+ nPageCount = sqlite3PagerPagecount(pPager);
+ if( pPg->pgno>nPageCount ){
+ nPage = (pPg->pgno - pg1)+1;
+ }else if( (pg1+nPagePerSector-1)>nPageCount ){
+ nPage = nPageCount+1-pg1;
+ }else{
+ nPage = nPagePerSector;
+ }
+ assert(nPage>0);
+ assert(pg1<=pPg->pgno);
+ assert((pg1+nPage)>pPg->pgno);
+
+ for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
+ Pgno pg = pg1+ii;
+ PgHdr *pPage;
+ if( !pPager->aInJournal || pg==pPg->pgno ||
+ pg>pPager->origDbSize || !(pPager->aInJournal[pg/8]&(1<<(pg&7)))
+ ) {
+ if( pg!=PAGER_MJ_PGNO(pPager) ){
+ rc = sqlite3PagerGet(pPager, pg, &pPage);
+ if( rc==SQLITE_OK ){
+ rc = pager_write(pPage);
+ if( pPage->needSync ){
+ needSync = 1;
+ }
+ sqlite3PagerUnref(pPage);
+ }
+ }
+ }else if( (pPage = pager_lookup(pPager, pg)) ){
+ if( pPage->needSync ){
+ needSync = 1;
+ }
+ }
+ }
+
+ /* If the PgHdr.needSync flag is set for any of the nPage pages
+ ** starting at pg1, then it needs to be set for all of them. Because
+ ** writing to any of these nPage pages may damage the others, the
+ ** journal file must contain sync()ed copies of all of them
+ ** before any of them can be written out to the database file.
+ */
+ if( needSync ){
+ for(ii=0; ii<nPage && needSync; ii++){
+ PgHdr *pPage = pager_lookup(pPager, pg1+ii);
+ if( pPage ) pPage->needSync = 1;
+ }
+ assert(pPager->needSync);
+ }
+
+ assert( pPager->doNotSync==1 );
+ pPager->doNotSync = 0;
+ }else{
+ rc = pager_write(pDbPage);
+ }
+ pagerLeave(pPager);
+ return rc;
+}
+
+/*
** Return TRUE if the page given in the argument was previously passed
-** to sqlite3pager_write(). In other words, return TRUE if it is ok
+** to sqlite3PagerWrite(). 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);
+int sqlite3PagerIswriteable(DbPage *pPg){
return pPg->dirty;
}
#endif
@@ -3253,25 +4275,27 @@ int sqlite3pager_iswriteable(void *pData){
** Replace the content of a single page with the information in the third
** argument.
*/
-int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void *pData){
- void *pPage;
+int sqlite3PagerOverwrite(Pager *pPager, Pgno pgno, void *pData){
+ PgHdr *pPg;
int rc;
- rc = sqlite3pager_get(pPager, pgno, &pPage);
+ pagerEnter(pPager);
+ rc = sqlite3PagerGet(pPager, pgno, &pPg);
if( rc==SQLITE_OK ){
- rc = sqlite3pager_write(pPage);
+ rc = sqlite3PagerWrite(pPg);
if( rc==SQLITE_OK ){
- memcpy(pPage, pData, pPager->pageSize);
+ memcpy(sqlite3PagerGetData(pPg), pData, pPager->pageSize);
}
- sqlite3pager_unref(pPage);
+ sqlite3PagerUnref(pPg);
}
+ pagerLeave(pPager);
return rc;
}
#endif
/*
** A call to this routine tells the pager that it is not necessary to
-** write the information on page "pgno" back to the disk, even though
+** write the information on page pPg back to the disk, even though
** that page might be marked as dirty.
**
** The overlying software layer calls this routine when all of the data
@@ -3279,29 +4303,29 @@ int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void *pData){
** that it does not get written to disk.
**
** Tests show that this optimization, together with the
-** sqlite3pager_dont_rollback() below, more than double the speed
+** sqlite3PagerDontRollback() below, more than double the speed
** of large INSERT operations and quadruple the speed of large DELETEs.
**
** When this routine is called, set the alwaysRollback flag to true.
-** Subsequent calls to sqlite3pager_dont_rollback() for the same page
+** Subsequent calls to sqlite3PagerDontRollback() for the same page
** will thereafter be ignored. This is necessary to avoid a problem
** where a page with data is added to the freelist during one part of
** a transaction then removed from the freelist during a later part
** of the same transaction and reused for some other purpose. When it
** is first added to the freelist, this routine is called. When reused,
-** the dont_rollback() routine is called. But because the page contains
-** critical data, we still need to be sure it gets rolled back in spite
-** of the dont_rollback() call.
+** the sqlite3PagerDontRollback() routine is called. But because the
+** page contains critical data, we still need to be sure it gets
+** rolled back in spite of the sqlite3PagerDontRollback() call.
*/
-void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){
- PgHdr *pPg;
+void sqlite3PagerDontWrite(DbPage *pDbPage){
+ PgHdr *pPg = pDbPage;
+ Pager *pPager = pPg->pPager;
if( MEMDB ) return;
-
- pPg = pager_lookup(pPager, pgno);
- assert( pPg!=0 ); /* We never call _dont_write unless the page is in mem */
+ pagerEnter(pPager);
pPg->alwaysRollback = 1;
if( pPg->dirty && !pPager->stmtInUse ){
+ assert( pPager->state>=PAGER_SHARED );
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.
@@ -3312,13 +4336,15 @@ void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){
** corruption during the next transaction.
*/
}else{
- TRACE3("DONT_WRITE page %d of %d\n", pgno, PAGERID(pPager));
+ PAGERTRACE3("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager));
+ IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno))
makeClean(pPg);
#ifdef SQLITE_CHECK_PAGES
pPg->pageHash = pager_pagehash(pPg);
#endif
}
}
+ pagerLeave(pPager);
}
/*
@@ -3326,29 +4352,243 @@ void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){
** it is not necessary to restore the data on the given page. This
** means that the pager does not have to record the given page in the
** rollback journal.
+**
+** If we have not yet actually read the content of this page (if
+** the PgHdr.needRead flag is set) then this routine acts as a promise
+** that we will never need to read the page content in the future.
+** so the needRead flag can be cleared at this point.
+**
+** This routine is only called from a single place in the sqlite btree
+** code (when a leaf is removed from the free-list). This allows the
+** following assumptions to be made about pPg:
+**
+** 1. PagerDontWrite() has been called on the page, OR
+** PagerWrite() has not yet been called on the page.
+**
+** 2. The page existed when the transaction was started.
+**
+** Details: DontRollback() (this routine) is only called when a leaf is
+** removed from the free list. DontWrite() is called whenever a page
+** becomes a free-list leaf.
*/
-void sqlite3pager_dont_rollback(void *pData){
- PgHdr *pPg = DATA_TO_PGHDR(pData);
+void sqlite3PagerDontRollback(DbPage *pPg){
Pager *pPager = pPg->pPager;
- if( pPager->state!=PAGER_EXCLUSIVE || pPager->journalOpen==0 ) return;
- if( pPg->alwaysRollback || pPager->alwaysRollback || MEMDB ) return;
- if( !pPg->inJournal && (int)pPg->pgno <= pPager->origDbSize ){
- assert( pPager->aInJournal!=0 );
- pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
- pPg->inJournal = 1;
- if( pPager->stmtInUse ){
- pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
- page_add_to_stmt_list(pPg);
- }
- TRACE3("DONT_ROLLBACK page %d of %d\n", pPg->pgno, PAGERID(pPager));
- }
- if( pPager->stmtInUse && !pPg->inStmt && (int)pPg->pgno<=pPager->stmtSize ){
- assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
- assert( pPager->aInStmt!=0 );
+ pagerEnter(pPager);
+ assert( pPager->state>=PAGER_RESERVED );
+
+ /* If the journal file is not open, or DontWrite() has been called on
+ ** this page (DontWrite() sets the alwaysRollback flag), then this
+ ** function is a no-op.
+ */
+ if( pPager->journalOpen==0 || pPg->alwaysRollback || pPager->alwaysRollback ){
+ pagerLeave(pPager);
+ return;
+ }
+ assert( !MEMDB ); /* For a memdb, pPager->journalOpen is always 0 */
+
+ /* Check that PagerWrite() has not yet been called on this page, and
+ ** that the page existed when the transaction started.
+ */
+ assert( !pPg->inJournal && (int)pPg->pgno <= pPager->origDbSize );
+
+ assert( pPager->aInJournal!=0 );
+ pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
+ pPg->inJournal = 1;
+ pPg->needRead = 0;
+ if( pPager->stmtInUse ){
+ assert( pPager->stmtSize <= pPager->origDbSize );
pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
- page_add_to_stmt_list(pPg);
}
+ PAGERTRACE3("DONT_ROLLBACK page %d of %d\n", pPg->pgno, PAGERID(pPager));
+ IOTRACE(("GARBAGE %p %d\n", pPager, pPg->pgno))
+ pagerLeave(pPager);
+}
+
+
+/*
+** This routine is called to increment the database file change-counter,
+** stored at byte 24 of the pager file.
+*/
+static int pager_incr_changecounter(Pager *pPager, int isDirect){
+ PgHdr *pPgHdr;
+ u32 change_counter;
+ int rc = SQLITE_OK;
+
+ if( !pPager->changeCountDone ){
+ /* Open page 1 of the file for writing. */
+ rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
+ if( rc!=SQLITE_OK ) return rc;
+
+ if( !isDirect ){
+ rc = sqlite3PagerWrite(pPgHdr);
+ if( rc!=SQLITE_OK ){
+ sqlite3PagerUnref(pPgHdr);
+ return rc;
+ }
+ }
+
+ /* Increment the value just read and write it back to byte 24. */
+ change_counter = sqlite3Get4byte((u8*)pPager->dbFileVers);
+ change_counter++;
+ put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);
+
+ if( isDirect && pPager->fd->pMethods ){
+ const void *zBuf = PGHDR_TO_DATA(pPgHdr);
+ rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
+ }
+
+ /* Release the page reference. */
+ sqlite3PagerUnref(pPgHdr);
+ pPager->changeCountDone = 1;
+ }
+ return rc;
+}
+
+/*
+** Sync the database file for the pager pPager. zMaster points to the name
+** of a master journal file that should be written into the individual
+** journal file. zMaster may be NULL, which is interpreted as no master
+** journal (a single database transaction).
+**
+** This routine ensures that the journal is synced, all dirty pages written
+** to the database file and the database file synced. The only thing that
+** remains to commit the transaction is to delete the journal file (or
+** master journal file if specified).
+**
+** Note that if zMaster==NULL, this does not overwrite a previous value
+** passed to an sqlite3PagerCommitPhaseOne() call.
+**
+** If parameter nTrunc is non-zero, then the pager file is truncated to
+** nTrunc pages (this is used by auto-vacuum databases).
+*/
+int sqlite3PagerCommitPhaseOne(Pager *pPager, const char *zMaster, Pgno nTrunc){
+ int rc = SQLITE_OK;
+
+ PAGERTRACE4("DATABASE SYNC: File=%s zMaster=%s nTrunc=%d\n",
+ pPager->zFilename, zMaster, nTrunc);
+ pagerEnter(pPager);
+
+ /* If this is an in-memory db, or no pages have been written to, or this
+ ** function has already been called, it is a no-op.
+ */
+ if( pPager->state!=PAGER_SYNCED && !MEMDB && pPager->dirtyCache ){
+ PgHdr *pPg;
+
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ /* The atomic-write optimization can be used if all of the
+ ** following are true:
+ **
+ ** + The file-system supports the atomic-write property for
+ ** blocks of size page-size, and
+ ** + This commit is not part of a multi-file transaction, and
+ ** + Exactly one page has been modified and store in the journal file.
+ **
+ ** If the optimization can be used, then the journal file will never
+ ** be created for this transaction.
+ */
+ int useAtomicWrite = (
+ !zMaster &&
+ pPager->journalOff==jrnlBufferSize(pPager) &&
+ nTrunc==0 &&
+ (0==pPager->pDirty || 0==pPager->pDirty->pDirty)
+ );
+ if( useAtomicWrite ){
+ /* Update the nRec field in the journal file. */
+ int offset = pPager->journalHdr + sizeof(aJournalMagic);
+ assert(pPager->nRec==1);
+ rc = write32bits(pPager->jfd, offset, pPager->nRec);
+
+ /* Update the db file change counter. The following call will modify
+ ** the in-memory representation of page 1 to include the updated
+ ** change counter and then write page 1 directly to the database
+ ** file. Because of the atomic-write property of the host file-system,
+ ** this is safe.
+ */
+ if( rc==SQLITE_OK ){
+ rc = pager_incr_changecounter(pPager, 1);
+ }
+ }else{
+ rc = sqlite3JournalCreate(pPager->jfd);
+ }
+
+ if( !useAtomicWrite && rc==SQLITE_OK )
+#endif
+
+ /* If a master journal file name has already been written to the
+ ** journal file, then no sync is required. This happens when it is
+ ** written, then the process fails to upgrade from a RESERVED to an
+ ** EXCLUSIVE lock. The next time the process tries to commit the
+ ** transaction the m-j name will have already been written.
+ */
+ if( !pPager->setMaster ){
+ assert( pPager->journalOpen );
+ rc = pager_incr_changecounter(pPager, 0);
+ if( rc!=SQLITE_OK ) goto sync_exit;
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( nTrunc!=0 ){
+ /* If this transaction has made the database smaller, then all pages
+ ** being discarded by the truncation must be written to the journal
+ ** file.
+ */
+ Pgno i;
+ int iSkip = PAGER_MJ_PGNO(pPager);
+ for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){
+ if( !(pPager->aInJournal[i/8] & (1<<(i&7))) && i!=iSkip ){
+ rc = sqlite3PagerGet(pPager, i, &pPg);
+ if( rc!=SQLITE_OK ) goto sync_exit;
+ rc = sqlite3PagerWrite(pPg);
+ sqlite3PagerUnref(pPg);
+ if( rc!=SQLITE_OK ) goto sync_exit;
+ }
+ }
+ }
+#endif
+ rc = writeMasterJournal(pPager, zMaster);
+ if( rc!=SQLITE_OK ) goto sync_exit;
+ rc = syncJournal(pPager);
+ }
+ if( rc!=SQLITE_OK ) goto sync_exit;
+
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( nTrunc!=0 ){
+ rc = sqlite3PagerTruncate(pPager, nTrunc);
+ if( rc!=SQLITE_OK ) goto sync_exit;
+ }
+#endif
+
+ /* Write all dirty pages to the database file */
+ pPg = pager_get_all_dirty_pages(pPager);
+ rc = pager_write_pagelist(pPg);
+ if( rc!=SQLITE_OK ){
+ while( pPg && !pPg->dirty ){ pPg = pPg->pDirty; }
+ pPager->pDirty = pPg;
+ goto sync_exit;
+ }
+ pPager->pDirty = 0;
+
+ /* Sync the database file. */
+ if( !pPager->noSync ){
+ rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
+ }
+ IOTRACE(("DBSYNC %p\n", pPager))
+
+ pPager->state = PAGER_SYNCED;
+ }else if( MEMDB && nTrunc!=0 ){
+ rc = sqlite3PagerTruncate(pPager, nTrunc);
+ }
+
+sync_exit:
+ if( rc==SQLITE_IOERR_BLOCKED ){
+ /* pager_incr_changecounter() may attempt to obtain an exclusive
+ * lock to spill the cache and return IOERR_BLOCKED. But since
+ * there is no chance the cache is inconsistent, it is
+ * better to return SQLITE_BUSY.
+ */
+ rc = SQLITE_BUSY;
+ }
+ pagerLeave(pPager);
+ return rc;
}
@@ -3359,7 +4599,7 @@ void sqlite3pager_dont_rollback(void *pData){
** and an error code is returned. If the commit worked, SQLITE_OK
** is returned.
*/
-int sqlite3pager_commit(Pager *pPager){
+int sqlite3PagerCommitPhaseTwo(Pager *pPager){
int rc;
PgHdr *pPg;
@@ -3369,16 +4609,18 @@ int sqlite3pager_commit(Pager *pPager){
if( pPager->state<PAGER_RESERVED ){
return SQLITE_ERROR;
}
- TRACE2("COMMIT %d\n", PAGERID(pPager));
+ pagerEnter(pPager);
+ PAGERTRACE2("COMMIT %d\n", PAGERID(pPager));
if( MEMDB ){
pPg = pager_get_all_dirty_pages(pPager);
while( pPg ){
- clearHistory(PGHDR_TO_HIST(pPg, pPager));
+ PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
+ clearHistory(pHist);
pPg->dirty = 0;
pPg->inJournal = 0;
- pPg->inStmt = 0;
+ pHist->inStmt = 0;
pPg->needSync = 0;
- pPg->pPrevStmt = pPg->pNextStmt = 0;
+ pHist->pPrevStmt = pHist->pNextStmt = 0;
pPg = pPg->pDirty;
}
pPager->pDirty = 0;
@@ -3392,22 +4634,14 @@ int sqlite3pager_commit(Pager *pPager){
#endif
pPager->pStmt = 0;
pPager->state = PAGER_SHARED;
+ pagerLeave(pPager);
return SQLITE_OK;
}
- if( pPager->dirtyCache==0 ){
- /* Exit early (without doing the time-consuming sqlite3OsSync() calls)
- ** if there have been no changes to the database file. */
- assert( pPager->needSync==0 );
- rc = pager_unwritelock(pPager);
- pPager->dbSize = -1;
- return rc;
- }
- assert( pPager->journalOpen );
- rc = sqlite3pager_sync(pPager, 0, 0);
- if( rc==SQLITE_OK ){
- rc = pager_unwritelock(pPager);
- pPager->dbSize = -1;
- }
+ assert( pPager->journalOpen || !pPager->dirtyCache );
+ assert( pPager->state==PAGER_SYNCED || !pPager->dirtyCache );
+ rc = pager_end_transaction(pPager);
+ rc = pager_error(pPager, rc);
+ pagerLeave(pPager);
return rc;
}
@@ -3417,15 +4651,15 @@ int sqlite3pager_commit(Pager *pPager){
** The journal is deleted.
**
** This routine cannot fail unless some other process is not following
-** the correct locking protocol (SQLITE_PROTOCOL) or unless some other
+** the correct locking protocol or unless some other
** process is writing trash into the journal file (SQLITE_CORRUPT) or
** unless a prior malloc() failed (SQLITE_NOMEM). Appropriate error
** codes are returned for all these occasions. Otherwise,
** SQLITE_OK is returned.
*/
-int sqlite3pager_rollback(Pager *pPager){
+int sqlite3PagerRollback(Pager *pPager){
int rc;
- TRACE2("ROLLBACK %d\n", PAGERID(pPager));
+ PAGERTRACE2("ROLLBACK %d\n", PAGERID(pPager));
if( MEMDB ){
PgHdr *p;
for(p=pPager->pAll; p; p=p->pNextAll){
@@ -3440,71 +4674,76 @@ int sqlite3pager_rollback(Pager *pPager){
pHist = PGHDR_TO_HIST(p, pPager);
if( pHist->pOrig ){
memcpy(PGHDR_TO_DATA(p), pHist->pOrig, pPager->pageSize);
- TRACE3("ROLLBACK-PAGE %d of %d\n", p->pgno, PAGERID(pPager));
+ PAGERTRACE3("ROLLBACK-PAGE %d of %d\n", p->pgno, PAGERID(pPager));
}else{
- TRACE3("PAGE %d is clean on %d\n", p->pgno, PAGERID(pPager));
+ PAGERTRACE3("PAGE %d is clean on %d\n", p->pgno, PAGERID(pPager));
}
clearHistory(pHist);
p->dirty = 0;
p->inJournal = 0;
- p->inStmt = 0;
- p->pPrevStmt = p->pNextStmt = 0;
+ pHist->inStmt = 0;
+ pHist->pPrevStmt = pHist->pNextStmt = 0;
if( pPager->xReiniter ){
- pPager->xReiniter(PGHDR_TO_DATA(p), pPager->pageSize);
+ pPager->xReiniter(p, pPager->pageSize);
}
}
pPager->pDirty = 0;
pPager->pStmt = 0;
pPager->dbSize = pPager->origDbSize;
- memoryTruncate(pPager);
+ pager_truncate_cache(pPager);
pPager->stmtInUse = 0;
pPager->state = PAGER_SHARED;
return SQLITE_OK;
}
+ pagerEnter(pPager);
if( !pPager->dirtyCache || !pPager->journalOpen ){
- rc = pager_unwritelock(pPager);
- pPager->dbSize = -1;
+ rc = pager_end_transaction(pPager);
+ pagerLeave(pPager);
return rc;
}
if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
if( pPager->state>=PAGER_EXCLUSIVE ){
- pager_playback(pPager);
+ pager_playback(pPager, 0);
}
+ pagerLeave(pPager);
return pPager->errCode;
}
if( pPager->state==PAGER_RESERVED ){
int rc2;
- rc = pager_reload_cache(pPager);
- rc2 = pager_unwritelock(pPager);
+ rc = pager_playback(pPager, 0);
+ rc2 = pager_end_transaction(pPager);
if( rc==SQLITE_OK ){
rc = rc2;
}
}else{
- rc = pager_playback(pPager);
+ rc = pager_playback(pPager, 0);
}
+ /* pager_reset(pPager); */
pPager->dbSize = -1;
/* 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);
+ rc = pager_error(pPager, rc);
+ pagerLeave(pPager);
+ return rc;
}
/*
** Return TRUE if the database file is opened read-only. Return FALSE
** if the database is (in theory) writable.
*/
-int sqlite3pager_isreadonly(Pager *pPager){
+int sqlite3PagerIsreadonly(Pager *pPager){
return pPager->readOnly;
}
/*
** Return the number of references to the pager.
*/
-int sqlite3pager_refcount(Pager *pPager){
+int sqlite3PagerRefcount(Pager *pPager){
return pPager->nRef;
}
@@ -3512,7 +4751,7 @@ int sqlite3pager_refcount(Pager *pPager){
/*
** This routine is used for testing and analysis only.
*/
-int *sqlite3pager_stats(Pager *pPager){
+int *sqlite3PagerStats(Pager *pPager){
static int a[11];
a[0] = pPager->nRef;
a[1] = pPager->nPage;
@@ -3522,7 +4761,7 @@ int *sqlite3pager_stats(Pager *pPager){
a[5] = pPager->errCode;
a[6] = pPager->nHit;
a[7] = pPager->nMiss;
- a[8] = pPager->nOvfl;
+ a[8] = 0; /* Used to be pPager->nOvfl */
a[9] = pPager->nRead;
a[10] = pPager->nWrite;
return a;
@@ -3536,12 +4775,12 @@ int *sqlite3pager_stats(Pager *pPager){
** open. A new statement journal is created that can be used to rollback
** changes of a single SQL command within a larger transaction.
*/
-int sqlite3pager_stmt_begin(Pager *pPager){
+static int pagerStmtBegin(Pager *pPager){
int rc;
- char zTemp[SQLITE_TEMPNAME_SIZE];
assert( !pPager->stmtInUse );
+ assert( pPager->state>=PAGER_SHARED );
assert( pPager->dbSize>=0 );
- TRACE2("STMT-BEGIN %d\n", PAGERID(pPager));
+ PAGERTRACE2("STMT-BEGIN %d\n", PAGERID(pPager));
if( MEMDB ){
pPager->stmtInUse = 1;
pPager->stmtSize = pPager->dbSize;
@@ -3552,7 +4791,10 @@ int sqlite3pager_stmt_begin(Pager *pPager){
return SQLITE_OK;
}
assert( pPager->journalOpen );
- pPager->aInStmt = sqliteMalloc( pPager->dbSize/8 + 1 );
+ pagerLeave(pPager);
+ assert( pPager->aInStmt==0 );
+ pPager->aInStmt = sqlite3MallocZero( pPager->dbSize/8 + 1 );
+ pagerEnter(pPager);
if( pPager->aInStmt==0 ){
/* sqlite3OsLock(pPager->fd, SHARED_LOCK); */
return SQLITE_NOMEM;
@@ -3567,8 +4809,11 @@ int sqlite3pager_stmt_begin(Pager *pPager){
pPager->stmtHdrOff = 0;
pPager->stmtCksum = pPager->cksumInit;
if( !pPager->stmtOpen ){
- rc = sqlite3pager_opentemp(zTemp, &pPager->stfd);
- if( rc ) goto stmt_begin_failed;
+ rc = sqlite3PagerOpentemp(pPager->pVfs, pPager->stfd, pPager->zStmtJrnl,
+ SQLITE_OPEN_SUBJOURNAL);
+ if( rc ){
+ goto stmt_begin_failed;
+ }
pPager->stmtOpen = 1;
pPager->stmtNRec = 0;
}
@@ -3577,33 +4822,39 @@ int sqlite3pager_stmt_begin(Pager *pPager){
stmt_begin_failed:
if( pPager->aInStmt ){
- sqliteFree(pPager->aInStmt);
+ sqlite3_free(pPager->aInStmt);
pPager->aInStmt = 0;
}
return rc;
}
+int sqlite3PagerStmtBegin(Pager *pPager){
+ int rc;
+ pagerEnter(pPager);
+ rc = pagerStmtBegin(pPager);
+ pagerLeave(pPager);
+ return rc;
+}
/*
** Commit a statement.
*/
-int sqlite3pager_stmt_commit(Pager *pPager){
+int sqlite3PagerStmtCommit(Pager *pPager){
+ pagerEnter(pPager);
if( pPager->stmtInUse ){
PgHdr *pPg, *pNext;
- TRACE2("STMT-COMMIT %d\n", PAGERID(pPager));
+ PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager));
if( !MEMDB ){
- sqlite3OsSeek(pPager->stfd, 0);
/* sqlite3OsTruncate(pPager->stfd, 0); */
- sqliteFree( pPager->aInStmt );
+ sqlite3_free( pPager->aInStmt );
pPager->aInStmt = 0;
- }
- for(pPg=pPager->pStmt; pPg; pPg=pNext){
- pNext = pPg->pNextStmt;
- assert( pPg->inStmt );
- pPg->inStmt = 0;
- pPg->pPrevStmt = pPg->pNextStmt = 0;
- if( MEMDB ){
+ }else{
+ for(pPg=pPager->pStmt; pPg; pPg=pNext){
PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- sqliteFree(pHist->pStmt);
+ pNext = pHist->pNextStmt;
+ assert( pHist->inStmt );
+ pHist->inStmt = 0;
+ pHist->pPrevStmt = pHist->pNextStmt = 0;
+ sqlite3_free(pHist->pStmt);
pHist->pStmt = 0;
}
}
@@ -3612,58 +4863,78 @@ int sqlite3pager_stmt_commit(Pager *pPager){
pPager->pStmt = 0;
}
pPager->stmtAutoopen = 0;
+ pagerLeave(pPager);
return SQLITE_OK;
}
/*
** Rollback a statement.
*/
-int sqlite3pager_stmt_rollback(Pager *pPager){
+int sqlite3PagerStmtRollback(Pager *pPager){
int rc;
+ pagerEnter(pPager);
if( pPager->stmtInUse ){
- TRACE2("STMT-ROLLBACK %d\n", PAGERID(pPager));
+ PAGERTRACE2("STMT-ROLLBACK %d\n", PAGERID(pPager));
if( MEMDB ){
PgHdr *pPg;
- for(pPg=pPager->pStmt; pPg; pPg=pPg->pNextStmt){
- PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
+ PgHistory *pHist;
+ for(pPg=pPager->pStmt; pPg; pPg=pHist->pNextStmt){
+ pHist = PGHDR_TO_HIST(pPg, pPager);
if( pHist->pStmt ){
memcpy(PGHDR_TO_DATA(pPg), pHist->pStmt, pPager->pageSize);
- sqliteFree(pHist->pStmt);
+ sqlite3_free(pHist->pStmt);
pHist->pStmt = 0;
}
}
pPager->dbSize = pPager->stmtSize;
- memoryTruncate(pPager);
+ pager_truncate_cache(pPager);
rc = SQLITE_OK;
}else{
rc = pager_stmt_playback(pPager);
}
- sqlite3pager_stmt_commit(pPager);
+ sqlite3PagerStmtCommit(pPager);
}else{
rc = SQLITE_OK;
}
pPager->stmtAutoopen = 0;
+ pagerLeave(pPager);
return rc;
}
/*
** Return the full pathname of the database file.
*/
-const char *sqlite3pager_filename(Pager *pPager){
+const char *sqlite3PagerFilename(Pager *pPager){
return pPager->zFilename;
}
/*
+** Return the VFS structure for the pager.
+*/
+const sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
+ return pPager->pVfs;
+}
+
+/*
+** Return the file handle for the database file associated
+** with the pager. This might return NULL if the file has
+** not yet been opened.
+*/
+sqlite3_file *sqlite3PagerFile(Pager *pPager){
+ return pPager->fd;
+}
+
+/*
** Return the directory of the database file.
*/
-const char *sqlite3pager_dirname(Pager *pPager){
+const char *sqlite3PagerDirname(Pager *pPager){
return pPager->zDirectory;
}
/*
** Return the full pathname of the journal file.
*/
-const char *sqlite3pager_journalname(Pager *pPager){
+const char *sqlite3PagerJournalname(Pager *pPager){
return pPager->zJournal;
}
@@ -3671,14 +4942,15 @@ const char *sqlite3pager_journalname(Pager *pPager){
** Return true if fsync() calls are disabled for this pager. Return FALSE
** if fsync()s are executed normally.
*/
-int sqlite3pager_nosync(Pager *pPager){
+int sqlite3PagerNosync(Pager *pPager){
return pPager->noSync;
}
+#ifdef SQLITE_HAS_CODEC
/*
** Set the codec for this pager
*/
-void sqlite3pager_set_codec(
+void sqlite3PagerSetCodec(
Pager *pPager,
void *(*xCodec)(void*,void*,Pgno,int),
void *pCodecArg
@@ -3686,138 +4958,19 @@ void sqlite3pager_set_codec(
pPager->xCodec = xCodec;
pPager->pCodecArg = pCodecArg;
}
-
-/*
-** This routine is called to increment the database file change-counter,
-** stored at byte 24 of the pager file.
-*/
-static int pager_incr_changecounter(Pager *pPager){
- void *pPage;
- PgHdr *pPgHdr;
- u32 change_counter;
- int rc;
-
- /* Open page 1 of the file for writing. */
- rc = sqlite3pager_get(pPager, 1, &pPage);
- if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3pager_write(pPage);
- if( rc!=SQLITE_OK ) return rc;
-
- /* Read the current value at byte 24. */
- pPgHdr = DATA_TO_PGHDR(pPage);
- change_counter = retrieve32bits(pPgHdr, 24);
-
- /* Increment the value just read and write it back to byte 24. */
- change_counter++;
- put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);
-
- /* Release the page reference. */
- sqlite3pager_unref(pPage);
- return SQLITE_OK;
-}
-
-/*
-** Sync the database file for the pager pPager. zMaster points to the name
-** of a master journal file that should be written into the individual
-** journal file. zMaster may be NULL, which is interpreted as no master
-** journal (a single database transaction).
-**
-** This routine ensures that the journal is synced, all dirty pages written
-** to the database file and the database file synced. The only thing that
-** remains to commit the transaction is to delete the journal file (or
-** master journal file if specified).
-**
-** Note that if zMaster==NULL, this does not overwrite a previous value
-** passed to an sqlite3pager_sync() call.
-**
-** If parameter nTrunc is non-zero, then the pager file is truncated to
-** nTrunc pages (this is used by auto-vacuum databases).
-*/
-int sqlite3pager_sync(Pager *pPager, const char *zMaster, Pgno nTrunc){
- int rc = SQLITE_OK;
-
- TRACE4("DATABASE SYNC: File=%s zMaster=%s nTrunc=%d\n",
- pPager->zFilename, zMaster, nTrunc);
-
- /* If this is an in-memory db, or no pages have been written to, or this
- ** function has already been called, it is a no-op.
- */
- if( pPager->state!=PAGER_SYNCED && !MEMDB && pPager->dirtyCache ){
- PgHdr *pPg;
- assert( pPager->journalOpen );
-
- /* If a master journal file name has already been written to the
- ** journal file, then no sync is required. This happens when it is
- ** written, then the process fails to upgrade from a RESERVED to an
- ** EXCLUSIVE lock. The next time the process tries to commit the
- ** transaction the m-j name will have already been written.
- */
- if( !pPager->setMaster ){
- rc = pager_incr_changecounter(pPager);
- if( rc!=SQLITE_OK ) goto sync_exit;
-#ifndef SQLITE_OMIT_AUTOVACUUM
- if( nTrunc!=0 ){
- /* If this transaction has made the database smaller, then all pages
- ** being discarded by the truncation must be written to the journal
- ** file.
- */
- Pgno i;
- void *pPage;
- int iSkip = PAGER_MJ_PGNO(pPager);
- for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){
- if( !(pPager->aInJournal[i/8] & (1<<(i&7))) && i!=iSkip ){
- rc = sqlite3pager_get(pPager, i, &pPage);
- if( rc!=SQLITE_OK ) goto sync_exit;
- rc = sqlite3pager_write(pPage);
- sqlite3pager_unref(pPage);
- if( rc!=SQLITE_OK ) goto sync_exit;
- }
- }
- }
-#endif
- rc = writeMasterJournal(pPager, zMaster);
- if( rc!=SQLITE_OK ) goto sync_exit;
- rc = syncJournal(pPager);
- if( rc!=SQLITE_OK ) goto sync_exit;
- }
-
-#ifndef SQLITE_OMIT_AUTOVACUUM
- if( nTrunc!=0 ){
- rc = sqlite3pager_truncate(pPager, nTrunc);
- if( rc!=SQLITE_OK ) goto sync_exit;
- }
#endif
- /* Write all dirty pages to the database file */
- pPg = pager_get_all_dirty_pages(pPager);
- rc = pager_write_pagelist(pPg);
- if( rc!=SQLITE_OK ) goto sync_exit;
-
- /* Sync the database file. */
- if( !pPager->noSync ){
- rc = sqlite3OsSync(pPager->fd, 0);
- }
-
- pPager->state = PAGER_SYNCED;
- }else if( MEMDB && nTrunc!=0 ){
- rc = sqlite3pager_truncate(pPager, nTrunc);
- }
-
-sync_exit:
- return rc;
-}
-
#ifndef SQLITE_OMIT_AUTOVACUUM
/*
-** Move the page identified by pData to location pgno in the file.
+** Move the page pPg to location pgno in the file.
**
-** There must be no references to the current page pgno. If current page
-** pgno is not already in the rollback journal, it is not written there by
-** by this routine. The same applies to the page pData refers to on entry to
-** this routine.
+** There must be no references to the page previously located at
+** pgno (which we call pPgOld) though that page is allowed to be
+** in cache. If the page previous located at pgno is not already
+** in the rollback journal, it is not put there by by this routine.
**
-** References to the page refered to by pData remain valid. Updating any
-** meta-data associated with page pData (i.e. data stored in the nExtra bytes
+** References to the page pPg remain valid. Updating any
+** meta-data associated with pPg (i.e. data stored in the nExtra bytes
** allocated along with the page) is the responsibility of the caller.
**
** A transaction must be active when this routine is called. It used to be
@@ -3825,43 +4978,49 @@ sync_exit:
** has been removed (CREATE INDEX needs to move a page when a statement
** transaction is active).
*/
-int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
- PgHdr *pPg = DATA_TO_PGHDR(pData);
- PgHdr *pPgOld;
+int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno){
+ PgHdr *pPgOld; /* The page being overwritten. */
int h;
Pgno needSyncPgno = 0;
+ pagerEnter(pPager);
assert( pPg->nRef>0 );
- TRACE5("MOVE %d page %d (needSync=%d) moves to %d\n",
+ PAGERTRACE5("MOVE %d page %d (needSync=%d) moves to %d\n",
PAGERID(pPager), pPg->pgno, pPg->needSync, pgno);
+ IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno))
+ pager_get_content(pPg);
if( pPg->needSync ){
needSyncPgno = pPg->pgno;
- assert( pPg->inJournal );
+ assert( pPg->inJournal || (int)pgno>pPager->origDbSize );
assert( pPg->dirty );
assert( pPager->needSync );
}
- /* Unlink pPg from it's hash-chain */
+ /* Unlink pPg from its hash-chain */
unlinkHashChain(pPager, pPg);
/* If the cache contains a page with page-number pgno, remove it
- ** from it's hash chain. Also, if the PgHdr.needSync was set for
+ ** from its hash chain. Also, if the PgHdr.needSync was set for
** page pgno before the 'move' operation, it needs to be retained
** for the page moved there.
*/
+ pPg->needSync = 0;
pPgOld = pager_lookup(pPager, pgno);
if( pPgOld ){
assert( pPgOld->nRef==0 );
unlinkHashChain(pPager, pPgOld);
makeClean(pPgOld);
- if( pPgOld->needSync ){
- assert( pPgOld->inJournal );
- pPg->inJournal = 1;
- pPg->needSync = 1;
- assert( pPager->needSync );
- }
+ pPg->needSync = pPgOld->needSync;
+ }else{
+ pPg->needSync = 0;
+ }
+ if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){
+ pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0;
+ }else{
+ pPg->inJournal = 0;
+ assert( pPg->needSync==0 || (int)pgno>pPager->origDbSize );
}
/* Change the page number for pPg and insert it into the new hash-chain. */
@@ -3886,41 +5045,82 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
** Pager.aInJournal bit has been set. This needs to be remedied by loading
** the page into the pager-cache and setting the PgHdr.needSync flag.
**
- ** The sqlite3pager_get() call may cause the journal to sync. So make
+ ** If the attempt to load the page into the page-cache fails, (due
+ ** to a malloc() or IO failure), clear the bit in the aInJournal[]
+ ** array. Otherwise, if the page is loaded and written again in
+ ** this transaction, it may be written to the database file before
+ ** it is synced into the journal file. This way, it may end up in
+ ** the journal file twice, but that is not a problem.
+ **
+ ** The sqlite3PagerGet() call may cause the journal to sync. So make
** sure the Pager.needSync flag is set too.
*/
int rc;
- void *pNeedSync;
+ PgHdr *pPgHdr;
assert( pPager->needSync );
- rc = sqlite3pager_get(pPager, needSyncPgno, &pNeedSync);
- if( rc!=SQLITE_OK ) return rc;
+ rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr);
+ if( rc!=SQLITE_OK ){
+ if( pPager->aInJournal && (int)needSyncPgno<=pPager->origDbSize ){
+ pPager->aInJournal[needSyncPgno/8] &= ~(1<<(needSyncPgno&7));
+ }
+ pagerLeave(pPager);
+ return rc;
+ }
pPager->needSync = 1;
- DATA_TO_PGHDR(pNeedSync)->needSync = 1;
- DATA_TO_PGHDR(pNeedSync)->inJournal = 1;
- makeDirty(DATA_TO_PGHDR(pNeedSync));
- sqlite3pager_unref(pNeedSync);
+ pPgHdr->needSync = 1;
+ pPgHdr->inJournal = 1;
+ makeDirty(pPgHdr);
+ sqlite3PagerUnref(pPgHdr);
}
+ pagerLeave(pPager);
return SQLITE_OK;
}
#endif
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/*
-** Return the current state of the file lock for the given pager.
-** The return value is one of NO_LOCK, SHARED_LOCK, RESERVED_LOCK,
-** PENDING_LOCK, or EXCLUSIVE_LOCK.
+** Return a pointer to the data for the specified page.
*/
-int sqlite3pager_lockstate(Pager *pPager){
- return sqlite3OsLockState(pPager->fd);
+void *sqlite3PagerGetData(DbPage *pPg){
+ return PGHDR_TO_DATA(pPg);
}
-#endif
-#ifdef SQLITE_DEBUG
+/*
+** Return a pointer to the Pager.nExtra bytes of "extra" space
+** allocated along with the specified page.
+*/
+void *sqlite3PagerGetExtra(DbPage *pPg){
+ Pager *pPager = pPg->pPager;
+ return (pPager?PGHDR_TO_EXTRA(pPg, pPager):0);
+}
+
+/*
+** Get/set the locking-mode for this pager. Parameter eMode must be one
+** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or
+** PAGER_LOCKINGMODE_EXCLUSIVE. If the parameter is not _QUERY, then
+** the locking-mode is set to the value specified.
+**
+** The returned value is either PAGER_LOCKINGMODE_NORMAL or
+** PAGER_LOCKINGMODE_EXCLUSIVE, indicating the current (possibly updated)
+** locking-mode.
+*/
+int sqlite3PagerLockingMode(Pager *pPager, int eMode){
+ assert( eMode==PAGER_LOCKINGMODE_QUERY
+ || eMode==PAGER_LOCKINGMODE_NORMAL
+ || eMode==PAGER_LOCKINGMODE_EXCLUSIVE );
+ assert( PAGER_LOCKINGMODE_QUERY<0 );
+ assert( PAGER_LOCKINGMODE_NORMAL>=0 && PAGER_LOCKINGMODE_EXCLUSIVE>=0 );
+ if( eMode>=0 && !pPager->tempFile ){
+ pPager->exclusiveMode = eMode;
+ }
+ return (int)pPager->exclusiveMode;
+}
+
+#ifdef SQLITE_TEST
/*
** Print a listing of all referenced pages and their ref count.
*/
-void sqlite3pager_refdump(Pager *pPager){
+void sqlite3PagerRefdump(Pager *pPager){
PgHdr *pPg;
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
if( pPg->nRef<=0 ) continue;
diff --git a/ext/pdo_sqlite/sqlite/src/pager.h b/ext/pdo_sqlite/sqlite/src/pager.h
index 555e52a031..40c36b5b95 100644
--- a/ext/pdo_sqlite/sqlite/src/pager.h
+++ b/ext/pdo_sqlite/sqlite/src/pager.h
@@ -20,32 +20,6 @@
#define _PAGER_H_
/*
-** The default size of a database page.
-*/
-#ifndef SQLITE_DEFAULT_PAGE_SIZE
-# define SQLITE_DEFAULT_PAGE_SIZE 1024
-#endif
-
-/* Maximum page size. The upper bound on this value is 32768. This a limit
-** imposed by necessity of storing the value in a 2-byte unsigned integer
-** and the fact that the page size must be a power of 2.
-**
-** This value is used to initialize certain arrays on the stack at
-** various places in the code. On embedded machines where stack space
-** is limited and the flexibility of having large pages is not needed,
-** it makes good sense to reduce the maximum page size to something more
-** reasonable, like 1024.
-*/
-#ifndef SQLITE_MAX_PAGE_SIZE
-# define SQLITE_MAX_PAGE_SIZE 32768
-#endif
-
-/*
-** Maximum number of pages in one database.
-*/
-#define SQLITE_MAX_PAGE 1073741823
-
-/*
** The type used to represent a page number. The first page in a file
** is called page 1. 0 is used to represent "not a page".
*/
@@ -57,67 +31,95 @@ typedef unsigned int Pgno;
typedef struct Pager Pager;
/*
-** Allowed values for the flags parameter to sqlite3pager_open().
+** Handle type for pages.
+*/
+typedef struct PgHdr DbPage;
+
+/*
+** Allowed values for the flags parameter to sqlite3PagerOpen().
**
** NOTE: This values must match the corresponding BTREE_ values in btree.h.
*/
#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
#define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */
+/*
+** Valid values for the second argument to sqlite3PagerLockingMode().
+*/
+#define PAGER_LOCKINGMODE_QUERY -1
+#define PAGER_LOCKINGMODE_NORMAL 0
+#define PAGER_LOCKINGMODE_EXCLUSIVE 1
/*
** See source code comments for a detailed description of the following
** routines:
*/
-int sqlite3pager_open(Pager **ppPager, const char *zFilename,
- int nExtra, int flags);
-void sqlite3pager_set_busyhandler(Pager*, BusyHandler *pBusyHandler);
-void sqlite3pager_set_destructor(Pager*, void(*)(void*,int));
-void sqlite3pager_set_reiniter(Pager*, void(*)(void*,int));
-int sqlite3pager_set_pagesize(Pager*, int);
-void sqlite3pager_read_fileheader(Pager*, int, unsigned char*);
-void sqlite3pager_set_cachesize(Pager*, int);
-int sqlite3pager_close(Pager *pPager);
-int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage);
-void *sqlite3pager_lookup(Pager *pPager, Pgno pgno);
-int sqlite3pager_ref(void*);
-int sqlite3pager_unref(void*);
-Pgno sqlite3pager_pagenumber(void*);
-int sqlite3pager_write(void*);
-int sqlite3pager_iswriteable(void*);
-int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void*);
-int sqlite3pager_pagecount(Pager*);
-int sqlite3pager_truncate(Pager*,Pgno);
-int sqlite3pager_begin(void*, int exFlag);
-int sqlite3pager_commit(Pager*);
-int sqlite3pager_sync(Pager*,const char *zMaster, Pgno);
-int sqlite3pager_rollback(Pager*);
-int sqlite3pager_isreadonly(Pager*);
-int sqlite3pager_stmt_begin(Pager*);
-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,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*);
-int sqlite3pager_movepage(Pager*,void*,Pgno);
-int sqlite3pager_reset(Pager*);
-int sqlite3pager_release_memory(int);
+int sqlite3PagerOpen(sqlite3_vfs *, Pager **ppPager, const char*, int,int,int);
+void sqlite3PagerSetBusyhandler(Pager*, BusyHandler *pBusyHandler);
+void sqlite3PagerSetDestructor(Pager*, void(*)(DbPage*,int));
+void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*,int));
+int sqlite3PagerSetPagesize(Pager*, u16*);
+int sqlite3PagerMaxPageCount(Pager*, int);
+int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
+void sqlite3PagerSetCachesize(Pager*, int);
+int sqlite3PagerClose(Pager *pPager);
+int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
+#define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0)
+DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
+int sqlite3PagerRef(DbPage*);
+int sqlite3PagerUnref(DbPage*);
+int sqlite3PagerWrite(DbPage*);
+int sqlite3PagerOverwrite(Pager *pPager, Pgno pgno, void*);
+int sqlite3PagerPagecount(Pager*);
+int sqlite3PagerTruncate(Pager*,Pgno);
+int sqlite3PagerBegin(DbPage*, int exFlag);
+int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, Pgno);
+int sqlite3PagerCommitPhaseTwo(Pager*);
+int sqlite3PagerRollback(Pager*);
+int sqlite3PagerIsreadonly(Pager*);
+int sqlite3PagerStmtBegin(Pager*);
+int sqlite3PagerStmtCommit(Pager*);
+int sqlite3PagerStmtRollback(Pager*);
+void sqlite3PagerDontRollback(DbPage*);
+void sqlite3PagerDontWrite(DbPage*);
+int sqlite3PagerRefcount(Pager*);
+void sqlite3PagerSetSafetyLevel(Pager*,int,int);
+const char *sqlite3PagerFilename(Pager*);
+const sqlite3_vfs *sqlite3PagerVfs(Pager*);
+sqlite3_file *sqlite3PagerFile(Pager*);
+const char *sqlite3PagerDirname(Pager*);
+const char *sqlite3PagerJournalname(Pager*);
+int sqlite3PagerNosync(Pager*);
+int sqlite3PagerMovepage(Pager*,DbPage*,Pgno);
+void *sqlite3PagerGetData(DbPage *);
+void *sqlite3PagerGetExtra(DbPage *);
+int sqlite3PagerLockingMode(Pager *, int);
+void *sqlite3PagerTempSpace(Pager*);
+
+#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO)
+ int sqlite3PagerReleaseMemory(int);
+#endif
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
-int sqlite3pager_lockstate(Pager*);
+#ifdef SQLITE_HAS_CODEC
+ void sqlite3PagerSetCodec(Pager*,void*(*)(void*,void*,Pgno,int),void*);
+#endif
+
+#if !defined(NDEBUG) || defined(SQLITE_TEST)
+ Pgno sqlite3PagerPagenumber(DbPage*);
+ int sqlite3PagerIswriteable(DbPage*);
+#endif
+
+#ifdef SQLITE_TEST
+ int *sqlite3PagerStats(Pager*);
+ void sqlite3PagerRefdump(Pager*);
#endif
#ifdef SQLITE_TEST
-void sqlite3pager_refdump(Pager*);
-int pager3_refinfo_enable;
+void disable_simulated_io_errors(void);
+void enable_simulated_io_errors(void);
+#else
+# define disable_simulated_io_errors()
+# define enable_simulated_io_errors()
#endif
#endif /* _PAGER_H_ */
diff --git a/ext/pdo_sqlite/sqlite/src/parse.c b/ext/pdo_sqlite/sqlite/src/parse.c
index 801bb7ca1a..e7948c7218 100644
--- a/ext/pdo_sqlite/sqlite/src/parse.c
+++ b/ext/pdo_sqlite/sqlite/src/parse.c
@@ -4,10 +4,9 @@
/* First off, code is include which follows the "include" declaration
** in the input file. */
#include <stdio.h>
-#line 56 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 51 "ext/pdo_sqlite/sqlite/src/parse.y"
#include "sqliteInt.h"
-#include "parse.h"
/*
** An instance of this structure holds information about the
@@ -43,7 +42,7 @@ struct TrigEvent { int a; IdList * b; };
*/
struct AttachKey { int type; Token key; };
-#line 48 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 47 "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.
*/
@@ -82,7 +81,8 @@ struct AttachKey { int type; Token key; };
** This is typically a union of many types, one of
** which is sqlite3ParserTOKENTYPE. The entry in the union
** for base tokens is called "yy0".
-** YYSTACKDEPTH is the maximum depth of the parser's stack.
+** YYSTACKDEPTH is the maximum depth of the parser's stack. If
+** zero the stack is dynamically sized using realloc()
** sqlite3ParserARG_SDECL A static variable declaration for the %extra_argument
** sqlite3ParserARG_PDECL A parameter declaration for the %extra_argument
** sqlite3ParserARG_STORE Code to store %extra_argument into yypParser
@@ -95,7 +95,7 @@ struct AttachKey { int type; Token key; };
#define YYCODETYPE unsigned char
#define YYNOCODE 248
#define YYACTIONTYPE unsigned short int
-#define YYWILDCARD 60
+#define YYWILDCARD 59
#define sqlite3ParserTOKENTYPE Token
typedef union {
sqlite3ParserTOKENTYPE yy0;
@@ -108,21 +108,19 @@ typedef union {
TriggerStep* yy243;
struct TrigEvent yy370;
SrcList* yy373;
- Expr * yy386;
struct {int value; int mask;} yy405;
Token yy410;
IdList* yy432;
- int yy495;
} YYMINORTYPE;
+#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
+#endif
#define sqlite3ParserARG_SDECL Parse *pParse;
#define sqlite3ParserARG_PDECL ,Parse *pParse
#define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse
#define sqlite3ParserARG_STORE yypParser->pParse = pParse
-#define YYNSTATE 581
-#define YYNRULE 309
-#define YYERRORSYMBOL 139
-#define YYERRSYMDT yy495
+#define YYNSTATE 588
+#define YYNRULE 312
#define YYFALLBACK 1
#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
@@ -176,409 +174,416 @@ typedef union {
** yy_default[] Default action for each state.
*/
static const YYACTIONTYPE yy_action[] = {
- /* 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,
+ /* 0 */ 292, 901, 124, 587, 409, 172, 2, 418, 61, 61,
+ /* 10 */ 61, 61, 519, 63, 63, 63, 63, 64, 64, 65,
+ /* 20 */ 65, 65, 66, 210, 447, 212, 425, 431, 68, 63,
+ /* 30 */ 63, 63, 63, 64, 64, 65, 65, 65, 66, 210,
+ /* 40 */ 391, 388, 396, 451, 60, 59, 297, 435, 436, 432,
+ /* 50 */ 432, 62, 62, 61, 61, 61, 61, 263, 63, 63,
+ /* 60 */ 63, 63, 64, 64, 65, 65, 65, 66, 210, 292,
+ /* 70 */ 493, 494, 418, 489, 208, 82, 67, 420, 69, 154,
+ /* 80 */ 63, 63, 63, 63, 64, 64, 65, 65, 65, 66,
+ /* 90 */ 210, 67, 462, 69, 154, 425, 431, 573, 264, 58,
+ /* 100 */ 64, 64, 65, 65, 65, 66, 210, 397, 398, 422,
+ /* 110 */ 422, 422, 292, 60, 59, 297, 435, 436, 432, 432,
+ /* 120 */ 62, 62, 61, 61, 61, 61, 317, 63, 63, 63,
+ /* 130 */ 63, 64, 64, 65, 65, 65, 66, 210, 425, 431,
+ /* 140 */ 94, 65, 65, 65, 66, 210, 396, 210, 414, 34,
+ /* 150 */ 56, 298, 442, 443, 410, 488, 60, 59, 297, 435,
+ /* 160 */ 436, 432, 432, 62, 62, 61, 61, 61, 61, 490,
+ /* 170 */ 63, 63, 63, 63, 64, 64, 65, 65, 65, 66,
+ /* 180 */ 210, 292, 257, 524, 295, 571, 113, 408, 522, 451,
+ /* 190 */ 331, 317, 407, 20, 418, 340, 519, 396, 532, 531,
+ /* 200 */ 505, 447, 212, 570, 569, 208, 530, 425, 431, 149,
+ /* 210 */ 150, 397, 398, 414, 41, 211, 151, 533, 372, 489,
+ /* 220 */ 261, 568, 259, 420, 292, 60, 59, 297, 435, 436,
+ /* 230 */ 432, 432, 62, 62, 61, 61, 61, 61, 317, 63,
+ /* 240 */ 63, 63, 63, 64, 64, 65, 65, 65, 66, 210,
+ /* 250 */ 425, 431, 447, 333, 215, 422, 422, 422, 363, 418,
+ /* 260 */ 414, 41, 397, 398, 366, 567, 211, 292, 60, 59,
+ /* 270 */ 297, 435, 436, 432, 432, 62, 62, 61, 61, 61,
+ /* 280 */ 61, 396, 63, 63, 63, 63, 64, 64, 65, 65,
+ /* 290 */ 65, 66, 210, 425, 431, 491, 300, 524, 474, 66,
+ /* 300 */ 210, 214, 474, 229, 411, 286, 534, 20, 449, 523,
+ /* 310 */ 168, 60, 59, 297, 435, 436, 432, 432, 62, 62,
+ /* 320 */ 61, 61, 61, 61, 474, 63, 63, 63, 63, 64,
+ /* 330 */ 64, 65, 65, 65, 66, 210, 209, 480, 317, 77,
+ /* 340 */ 292, 239, 300, 55, 484, 230, 397, 398, 181, 547,
+ /* 350 */ 494, 345, 348, 349, 67, 152, 69, 154, 339, 524,
+ /* 360 */ 414, 35, 350, 241, 221, 370, 425, 431, 578, 20,
+ /* 370 */ 164, 118, 243, 343, 248, 344, 176, 322, 442, 443,
+ /* 380 */ 414, 3, 80, 252, 60, 59, 297, 435, 436, 432,
+ /* 390 */ 432, 62, 62, 61, 61, 61, 61, 174, 63, 63,
+ /* 400 */ 63, 63, 64, 64, 65, 65, 65, 66, 210, 292,
+ /* 410 */ 221, 550, 236, 487, 510, 353, 317, 118, 243, 343,
+ /* 420 */ 248, 344, 176, 181, 317, 525, 345, 348, 349, 252,
+ /* 430 */ 223, 415, 155, 464, 511, 425, 431, 350, 414, 34,
+ /* 440 */ 465, 211, 177, 175, 160, 237, 414, 34, 338, 549,
+ /* 450 */ 449, 323, 168, 60, 59, 297, 435, 436, 432, 432,
+ /* 460 */ 62, 62, 61, 61, 61, 61, 415, 63, 63, 63,
+ /* 470 */ 63, 64, 64, 65, 65, 65, 66, 210, 292, 542,
+ /* 480 */ 335, 517, 504, 541, 456, 571, 302, 19, 331, 144,
+ /* 490 */ 317, 390, 317, 330, 2, 362, 457, 294, 483, 373,
+ /* 500 */ 269, 268, 252, 570, 425, 431, 588, 391, 388, 458,
+ /* 510 */ 208, 495, 414, 49, 414, 49, 303, 585, 892, 159,
+ /* 520 */ 892, 496, 60, 59, 297, 435, 436, 432, 432, 62,
+ /* 530 */ 62, 61, 61, 61, 61, 201, 63, 63, 63, 63,
+ /* 540 */ 64, 64, 65, 65, 65, 66, 210, 292, 317, 181,
+ /* 550 */ 439, 255, 345, 348, 349, 370, 153, 582, 308, 251,
+ /* 560 */ 309, 452, 76, 350, 78, 382, 211, 426, 427, 415,
+ /* 570 */ 414, 27, 319, 425, 431, 440, 1, 22, 585, 891,
+ /* 580 */ 396, 891, 544, 478, 320, 263, 438, 438, 429, 430,
+ /* 590 */ 415, 60, 59, 297, 435, 436, 432, 432, 62, 62,
+ /* 600 */ 61, 61, 61, 61, 328, 63, 63, 63, 63, 64,
+ /* 610 */ 64, 65, 65, 65, 66, 210, 292, 428, 582, 374,
+ /* 620 */ 224, 93, 517, 9, 336, 396, 557, 396, 456, 67,
+ /* 630 */ 396, 69, 154, 399, 400, 401, 320, 238, 438, 438,
+ /* 640 */ 457, 318, 425, 431, 299, 397, 398, 320, 433, 438,
+ /* 650 */ 438, 581, 291, 458, 225, 327, 5, 222, 546, 292,
+ /* 660 */ 60, 59, 297, 435, 436, 432, 432, 62, 62, 61,
+ /* 670 */ 61, 61, 61, 395, 63, 63, 63, 63, 64, 64,
+ /* 680 */ 65, 65, 65, 66, 210, 425, 431, 482, 313, 392,
+ /* 690 */ 397, 398, 397, 398, 207, 397, 398, 824, 273, 517,
+ /* 700 */ 251, 200, 292, 60, 59, 297, 435, 436, 432, 432,
+ /* 710 */ 62, 62, 61, 61, 61, 61, 470, 63, 63, 63,
+ /* 720 */ 63, 64, 64, 65, 65, 65, 66, 210, 425, 431,
+ /* 730 */ 171, 160, 263, 263, 304, 415, 276, 119, 274, 263,
+ /* 740 */ 517, 517, 263, 517, 192, 292, 60, 70, 297, 435,
+ /* 750 */ 436, 432, 432, 62, 62, 61, 61, 61, 61, 379,
/* 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,
+ /* 770 */ 210, 425, 431, 384, 559, 305, 306, 251, 415, 320,
+ /* 780 */ 560, 438, 438, 561, 540, 360, 540, 387, 292, 196,
+ /* 790 */ 59, 297, 435, 436, 432, 432, 62, 62, 61, 61,
+ /* 800 */ 61, 61, 371, 63, 63, 63, 63, 64, 64, 65,
+ /* 810 */ 65, 65, 66, 210, 425, 431, 396, 275, 251, 251,
+ /* 820 */ 172, 250, 418, 415, 386, 367, 178, 179, 180, 469,
+ /* 830 */ 311, 123, 156, 128, 297, 435, 436, 432, 432, 62,
+ /* 840 */ 62, 61, 61, 61, 61, 317, 63, 63, 63, 63,
+ /* 850 */ 64, 64, 65, 65, 65, 66, 210, 72, 324, 177,
+ /* 860 */ 4, 317, 263, 317, 296, 263, 415, 414, 28, 317,
+ /* 870 */ 263, 317, 321, 72, 324, 317, 4, 421, 445, 445,
+ /* 880 */ 296, 397, 398, 414, 23, 414, 32, 418, 321, 326,
+ /* 890 */ 329, 414, 53, 414, 52, 317, 158, 414, 98, 451,
+ /* 900 */ 317, 194, 317, 277, 317, 326, 378, 471, 502, 317,
+ /* 910 */ 478, 279, 478, 165, 294, 451, 317, 414, 96, 75,
+ /* 920 */ 74, 469, 414, 101, 414, 102, 414, 112, 73, 315,
+ /* 930 */ 316, 414, 114, 420, 448, 75, 74, 481, 414, 16,
+ /* 940 */ 381, 317, 183, 467, 73, 315, 316, 72, 324, 420,
+ /* 950 */ 4, 208, 317, 186, 296, 317, 499, 500, 476, 208,
+ /* 960 */ 173, 341, 321, 414, 99, 422, 422, 422, 423, 424,
+ /* 970 */ 11, 361, 380, 307, 414, 33, 415, 414, 97, 326,
+ /* 980 */ 460, 422, 422, 422, 423, 424, 11, 415, 413, 451,
+ /* 990 */ 413, 162, 412, 317, 412, 468, 226, 227, 228, 104,
+ /* 1000 */ 84, 473, 317, 509, 508, 317, 622, 477, 317, 75,
+ /* 1010 */ 74, 249, 205, 21, 281, 414, 24, 418, 73, 315,
+ /* 1020 */ 316, 282, 317, 420, 414, 54, 507, 414, 115, 317,
+ /* 1030 */ 414, 116, 506, 203, 147, 549, 244, 512, 526, 202,
+ /* 1040 */ 317, 513, 204, 317, 414, 117, 317, 245, 317, 18,
+ /* 1050 */ 317, 414, 25, 317, 256, 422, 422, 422, 423, 424,
+ /* 1060 */ 11, 258, 414, 36, 260, 414, 37, 317, 414, 26,
+ /* 1070 */ 414, 38, 414, 39, 262, 414, 40, 317, 514, 317,
+ /* 1080 */ 128, 317, 418, 317, 189, 377, 278, 268, 267, 414,
+ /* 1090 */ 42, 293, 317, 254, 317, 128, 208, 365, 8, 414,
+ /* 1100 */ 43, 414, 44, 414, 29, 414, 30, 352, 368, 128,
+ /* 1110 */ 317, 545, 317, 128, 414, 45, 414, 46, 317, 583,
+ /* 1120 */ 383, 553, 317, 173, 554, 317, 91, 317, 564, 369,
+ /* 1130 */ 91, 357, 414, 47, 414, 48, 580, 270, 290, 271,
+ /* 1140 */ 414, 31, 272, 556, 414, 10, 566, 414, 50, 414,
+ /* 1150 */ 51, 280, 283, 284, 577, 146, 463, 405, 584, 231,
+ /* 1160 */ 325, 419, 444, 466, 446, 246, 505, 552, 563, 515,
+ /* 1170 */ 516, 520, 163, 518, 394, 347, 7, 402, 403, 404,
+ /* 1180 */ 314, 84, 232, 334, 332, 83, 79, 416, 170, 57,
+ /* 1190 */ 213, 461, 125, 85, 337, 342, 492, 301, 233, 498,
+ /* 1200 */ 497, 105, 502, 219, 354, 247, 521, 234, 501, 235,
+ /* 1210 */ 287, 417, 503, 218, 527, 528, 529, 358, 240, 535,
+ /* 1220 */ 475, 242, 288, 479, 356, 184, 185, 121, 187, 132,
+ /* 1230 */ 188, 548, 537, 88, 190, 193, 364, 142, 375, 376,
+ /* 1240 */ 555, 133, 220, 562, 134, 310, 135, 138, 136, 574,
+ /* 1250 */ 575, 141, 576, 265, 579, 100, 538, 217, 393, 92,
+ /* 1260 */ 103, 95, 406, 623, 624, 166, 434, 167, 437, 71,
+ /* 1270 */ 453, 441, 450, 17, 143, 157, 169, 6, 111, 13,
+ /* 1280 */ 454, 455, 459, 472, 126, 81, 12, 127, 161, 485,
+ /* 1290 */ 486, 216, 86, 122, 106, 182, 253, 346, 312, 107,
+ /* 1300 */ 120, 87, 351, 108, 245, 355, 145, 536, 359, 129,
+ /* 1310 */ 173, 266, 191, 109, 289, 551, 130, 539, 195, 543,
+ /* 1320 */ 131, 14, 197, 199, 198, 558, 137, 139, 140, 110,
+ /* 1330 */ 15, 285, 572, 206, 389, 565, 385, 148, 586, 902,
+ /* 1340 */ 902, 902, 902, 902, 902, 89, 90,
};
static const YYCODETYPE yy_lookahead[] = {
- /* 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,
+ /* 0 */ 16, 139, 140, 141, 168, 21, 144, 23, 69, 70,
+ /* 10 */ 71, 72, 176, 74, 75, 76, 77, 78, 79, 80,
+ /* 20 */ 81, 82, 83, 84, 78, 79, 42, 43, 73, 74,
+ /* 30 */ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ /* 40 */ 1, 2, 23, 58, 60, 61, 62, 63, 64, 65,
+ /* 50 */ 66, 67, 68, 69, 70, 71, 72, 147, 74, 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,
+ /* 70 */ 185, 186, 88, 88, 110, 22, 217, 92, 219, 220,
+ /* 80 */ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ /* 90 */ 84, 217, 218, 219, 220, 42, 43, 238, 188, 46,
+ /* 100 */ 78, 79, 80, 81, 82, 83, 84, 88, 89, 124,
+ /* 110 */ 125, 126, 16, 60, 61, 62, 63, 64, 65, 66,
+ /* 120 */ 67, 68, 69, 70, 71, 72, 147, 74, 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,
+ /* 140 */ 44, 80, 81, 82, 83, 84, 23, 84, 169, 170,
+ /* 150 */ 19, 164, 165, 166, 23, 169, 60, 61, 62, 63,
+ /* 160 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 169,
+ /* 170 */ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ /* 180 */ 84, 16, 14, 147, 150, 147, 21, 167, 168, 58,
+ /* 190 */ 211, 147, 156, 157, 23, 216, 176, 23, 181, 176,
+ /* 200 */ 177, 78, 79, 165, 166, 110, 183, 42, 43, 78,
+ /* 210 */ 79, 88, 89, 169, 170, 228, 180, 181, 123, 88,
+ /* 220 */ 52, 98, 54, 92, 16, 60, 61, 62, 63, 64,
+ /* 230 */ 65, 66, 67, 68, 69, 70, 71, 72, 147, 74,
/* 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,
+ /* 250 */ 42, 43, 78, 209, 210, 124, 125, 126, 224, 88,
+ /* 260 */ 169, 170, 88, 89, 230, 227, 228, 16, 60, 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,
+ /* 280 */ 72, 23, 74, 75, 76, 77, 78, 79, 80, 81,
+ /* 290 */ 82, 83, 84, 42, 43, 160, 16, 147, 161, 83,
+ /* 300 */ 84, 210, 161, 153, 169, 158, 156, 157, 161, 162,
+ /* 310 */ 163, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+ /* 320 */ 69, 70, 71, 72, 161, 74, 75, 76, 77, 78,
+ /* 330 */ 79, 80, 81, 82, 83, 84, 192, 200, 147, 131,
+ /* 340 */ 16, 200, 16, 199, 20, 190, 88, 89, 90, 185,
+ /* 350 */ 186, 93, 94, 95, 217, 22, 219, 220, 147, 147,
+ /* 360 */ 169, 170, 104, 200, 84, 147, 42, 43, 156, 157,
+ /* 370 */ 90, 91, 92, 93, 94, 95, 96, 164, 165, 166,
+ /* 380 */ 169, 170, 131, 103, 60, 61, 62, 63, 64, 65,
+ /* 390 */ 66, 67, 68, 69, 70, 71, 72, 155, 74, 75,
+ /* 400 */ 76, 77, 78, 79, 80, 81, 82, 83, 84, 16,
+ /* 410 */ 84, 11, 221, 20, 30, 16, 147, 91, 92, 93,
+ /* 420 */ 94, 95, 96, 90, 147, 181, 93, 94, 95, 103,
+ /* 430 */ 212, 189, 155, 27, 50, 42, 43, 104, 169, 170,
+ /* 440 */ 34, 228, 43, 201, 202, 147, 169, 170, 206, 49,
+ /* 450 */ 161, 162, 163, 60, 61, 62, 63, 64, 65, 66,
+ /* 460 */ 67, 68, 69, 70, 71, 72, 189, 74, 75, 76,
+ /* 470 */ 77, 78, 79, 80, 81, 82, 83, 84, 16, 25,
+ /* 480 */ 211, 147, 20, 29, 12, 147, 102, 19, 211, 21,
+ /* 490 */ 147, 141, 147, 216, 144, 41, 24, 98, 20, 99,
+ /* 500 */ 100, 101, 103, 165, 42, 43, 0, 1, 2, 37,
+ /* 510 */ 110, 39, 169, 170, 169, 170, 182, 19, 20, 147,
+ /* 520 */ 22, 49, 60, 61, 62, 63, 64, 65, 66, 67,
+ /* 530 */ 68, 69, 70, 71, 72, 155, 74, 75, 76, 77,
+ /* 540 */ 78, 79, 80, 81, 82, 83, 84, 16, 147, 90,
+ /* 550 */ 20, 20, 93, 94, 95, 147, 155, 59, 215, 225,
+ /* 560 */ 215, 20, 130, 104, 132, 227, 228, 42, 43, 189,
+ /* 570 */ 169, 170, 16, 42, 43, 20, 19, 22, 19, 20,
+ /* 580 */ 23, 22, 18, 147, 106, 147, 108, 109, 63, 64,
+ /* 590 */ 189, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+ /* 600 */ 69, 70, 71, 72, 186, 74, 75, 76, 77, 78,
+ /* 610 */ 79, 80, 81, 82, 83, 84, 16, 92, 59, 55,
+ /* 620 */ 212, 21, 147, 19, 147, 23, 188, 23, 12, 217,
+ /* 630 */ 23, 219, 220, 7, 8, 9, 106, 147, 108, 109,
+ /* 640 */ 24, 147, 42, 43, 208, 88, 89, 106, 92, 108,
+ /* 650 */ 109, 244, 245, 37, 145, 39, 191, 182, 94, 16,
+ /* 660 */ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ /* 670 */ 70, 71, 72, 147, 74, 75, 76, 77, 78, 79,
+ /* 680 */ 80, 81, 82, 83, 84, 42, 43, 80, 142, 143,
+ /* 690 */ 88, 89, 88, 89, 148, 88, 89, 133, 14, 147,
+ /* 700 */ 225, 155, 16, 60, 61, 62, 63, 64, 65, 66,
+ /* 710 */ 67, 68, 69, 70, 71, 72, 114, 74, 75, 76,
+ /* 720 */ 77, 78, 79, 80, 81, 82, 83, 84, 42, 43,
+ /* 730 */ 201, 202, 147, 147, 182, 189, 52, 147, 54, 147,
+ /* 740 */ 147, 147, 147, 147, 155, 16, 60, 61, 62, 63,
+ /* 750 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 213,
+ /* 760 */ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ /* 770 */ 84, 42, 43, 188, 188, 182, 182, 225, 189, 106,
+ /* 780 */ 188, 108, 109, 188, 99, 100, 101, 241, 16, 155,
+ /* 790 */ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+ /* 800 */ 71, 72, 213, 74, 75, 76, 77, 78, 79, 80,
+ /* 810 */ 81, 82, 83, 84, 42, 43, 23, 133, 225, 225,
+ /* 820 */ 21, 225, 23, 189, 239, 236, 99, 100, 101, 22,
+ /* 830 */ 242, 243, 155, 22, 62, 63, 64, 65, 66, 67,
+ /* 840 */ 68, 69, 70, 71, 72, 147, 74, 75, 76, 77,
+ /* 850 */ 78, 79, 80, 81, 82, 83, 84, 16, 17, 43,
+ /* 860 */ 19, 147, 147, 147, 23, 147, 189, 169, 170, 147,
+ /* 870 */ 147, 147, 31, 16, 17, 147, 19, 147, 124, 125,
+ /* 880 */ 23, 88, 89, 169, 170, 169, 170, 88, 31, 48,
+ /* 890 */ 147, 169, 170, 169, 170, 147, 89, 169, 170, 58,
+ /* 900 */ 147, 22, 147, 188, 147, 48, 188, 114, 97, 147,
+ /* 910 */ 147, 188, 147, 19, 98, 58, 147, 169, 170, 78,
+ /* 920 */ 79, 114, 169, 170, 169, 170, 169, 170, 87, 88,
+ /* 930 */ 89, 169, 170, 92, 161, 78, 79, 80, 169, 170,
+ /* 940 */ 91, 147, 155, 22, 87, 88, 89, 16, 17, 92,
+ /* 950 */ 19, 110, 147, 155, 23, 147, 7, 8, 20, 110,
+ /* 960 */ 22, 80, 31, 169, 170, 124, 125, 126, 127, 128,
+ /* 970 */ 129, 208, 123, 208, 169, 170, 189, 169, 170, 48,
+ /* 980 */ 147, 124, 125, 126, 127, 128, 129, 189, 107, 58,
+ /* 990 */ 107, 5, 111, 147, 111, 203, 10, 11, 12, 13,
+ /* 1000 */ 121, 147, 147, 91, 92, 147, 112, 147, 147, 78,
+ /* 1010 */ 79, 147, 26, 19, 28, 169, 170, 23, 87, 88,
+ /* 1020 */ 89, 35, 147, 92, 169, 170, 178, 169, 170, 147,
+ /* 1030 */ 169, 170, 147, 47, 113, 49, 92, 178, 147, 53,
+ /* 1040 */ 147, 178, 56, 147, 169, 170, 147, 103, 147, 19,
+ /* 1050 */ 147, 169, 170, 147, 147, 124, 125, 126, 127, 128,
+ /* 1060 */ 129, 147, 169, 170, 147, 169, 170, 147, 169, 170,
+ /* 1070 */ 169, 170, 169, 170, 147, 169, 170, 147, 20, 147,
+ /* 1080 */ 22, 147, 88, 147, 232, 99, 100, 101, 147, 169,
+ /* 1090 */ 170, 105, 147, 20, 147, 22, 110, 147, 68, 169,
+ /* 1100 */ 170, 169, 170, 169, 170, 169, 170, 20, 147, 22,
+ /* 1110 */ 147, 20, 147, 22, 169, 170, 169, 170, 147, 20,
+ /* 1120 */ 134, 20, 147, 22, 20, 147, 22, 147, 20, 147,
+ /* 1130 */ 22, 233, 169, 170, 169, 170, 20, 147, 22, 147,
+ /* 1140 */ 169, 170, 147, 147, 169, 170, 147, 169, 170, 169,
+ /* 1150 */ 170, 147, 147, 147, 147, 191, 172, 149, 59, 193,
+ /* 1160 */ 223, 161, 229, 172, 229, 172, 177, 194, 194, 172,
+ /* 1170 */ 161, 161, 6, 172, 146, 173, 22, 146, 146, 146,
+ /* 1180 */ 154, 121, 194, 118, 116, 119, 130, 189, 112, 120,
+ /* 1190 */ 222, 152, 152, 98, 115, 98, 171, 40, 195, 179,
+ /* 1200 */ 171, 19, 97, 84, 15, 171, 179, 196, 173, 197,
+ /* 1210 */ 174, 198, 171, 226, 171, 171, 171, 38, 204, 152,
+ /* 1220 */ 205, 204, 174, 205, 152, 151, 151, 60, 151, 19,
+ /* 1230 */ 152, 184, 152, 130, 151, 184, 152, 214, 152, 15,
+ /* 1240 */ 194, 187, 226, 194, 187, 152, 187, 184, 187, 33,
+ /* 1250 */ 152, 214, 152, 234, 137, 159, 235, 175, 1, 237,
+ /* 1260 */ 175, 237, 20, 112, 112, 112, 92, 112, 107, 19,
+ /* 1270 */ 11, 20, 20, 231, 19, 19, 22, 117, 240, 117,
+ /* 1280 */ 20, 20, 20, 114, 19, 22, 22, 20, 112, 20,
+ /* 1290 */ 20, 44, 19, 243, 19, 96, 20, 44, 246, 19,
+ /* 1300 */ 32, 19, 44, 19, 103, 16, 21, 17, 36, 98,
+ /* 1310 */ 22, 133, 98, 19, 5, 1, 45, 51, 122, 45,
+ /* 1320 */ 102, 19, 113, 115, 14, 17, 113, 102, 122, 14,
+ /* 1330 */ 19, 136, 20, 135, 3, 123, 57, 19, 4, 247,
+ /* 1340 */ 247, 247, 247, 247, 247, 68, 68,
};
-#define YY_SHIFT_USE_DFLT (-106)
-#define YY_SHIFT_MAX 382
+#define YY_SHIFT_USE_DFLT (-62)
+#define YY_SHIFT_MAX 389
static const short yy_shift_ofst[] = {
- /* 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,
+ /* 0 */ 39, 841, 986, -16, 841, 931, 931, 258, 123, -36,
+ /* 10 */ 96, 931, 931, 931, 931, 931, -45, 400, 174, 19,
+ /* 20 */ 171, -54, -54, 53, 165, 208, 251, 324, 393, 462,
+ /* 30 */ 531, 600, 643, 686, 643, 643, 643, 643, 643, 643,
+ /* 40 */ 643, 643, 643, 643, 643, 643, 643, 643, 643, 643,
+ /* 50 */ 643, 643, 729, 772, 772, 857, 931, 931, 931, 931,
+ /* 60 */ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ /* 70 */ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ /* 80 */ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ /* 90 */ 931, 931, 931, 931, 931, 931, -61, -61, 6, 6,
+ /* 100 */ 280, 22, 61, 399, 564, 19, 19, 19, 19, 19,
+ /* 110 */ 19, 19, 216, 171, 63, -62, -62, -62, 131, 326,
+ /* 120 */ 472, 472, 498, 559, 506, 799, 19, 799, 19, 19,
+ /* 130 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ /* 140 */ 19, 849, 95, -36, -36, -36, -62, -62, -62, -15,
+ /* 150 */ -15, 333, 459, 478, 557, 530, 541, 616, 602, 793,
+ /* 160 */ 604, 607, 626, 19, 19, 881, 19, 19, 994, 19,
+ /* 170 */ 19, 807, 19, 19, 673, 807, 19, 19, 384, 384,
+ /* 180 */ 384, 19, 19, 673, 19, 19, 673, 19, 454, 685,
+ /* 190 */ 19, 19, 673, 19, 19, 19, 673, 19, 19, 19,
+ /* 200 */ 673, 673, 19, 19, 19, 19, 19, 468, 883, 921,
+ /* 210 */ 171, 754, 754, 432, 406, 406, 406, 816, 406, 171,
+ /* 220 */ 406, 171, 811, 879, 879, 1166, 1166, 1166, 1166, 1154,
+ /* 230 */ -36, 1060, 1065, 1066, 1068, 1069, 1056, 1076, 1076, 1095,
+ /* 240 */ 1079, 1095, 1079, 1097, 1097, 1157, 1097, 1105, 1097, 1182,
+ /* 250 */ 1119, 1119, 1157, 1097, 1097, 1097, 1182, 1189, 1076, 1189,
+ /* 260 */ 1076, 1189, 1076, 1076, 1179, 1103, 1189, 1076, 1167, 1167,
+ /* 270 */ 1210, 1060, 1076, 1224, 1224, 1224, 1224, 1060, 1167, 1210,
+ /* 280 */ 1076, 1216, 1216, 1076, 1076, 1117, -62, -62, -62, -62,
+ /* 290 */ -62, -62, 525, 684, 727, 168, 894, 556, 555, 938,
+ /* 300 */ 944, 949, 912, 1058, 1073, 1087, 1091, 1101, 1104, 1108,
+ /* 310 */ 1030, 1116, 1099, 1257, 1242, 1151, 1152, 1153, 1155, 1174,
+ /* 320 */ 1161, 1250, 1251, 1252, 1255, 1259, 1256, 1260, 1254, 1261,
+ /* 330 */ 1262, 1263, 1160, 1264, 1162, 1263, 1169, 1265, 1267, 1176,
+ /* 340 */ 1269, 1270, 1268, 1247, 1273, 1253, 1275, 1276, 1280, 1282,
+ /* 350 */ 1258, 1284, 1199, 1201, 1289, 1290, 1285, 1211, 1272, 1266,
+ /* 360 */ 1271, 1288, 1274, 1178, 1214, 1294, 1309, 1314, 1218, 1277,
+ /* 370 */ 1278, 1196, 1302, 1209, 1310, 1208, 1308, 1213, 1225, 1206,
+ /* 380 */ 1311, 1212, 1312, 1315, 1279, 1198, 1195, 1318, 1331, 1334,
};
-#define YY_REDUCE_USE_DFLT (-218)
-#define YY_REDUCE_MAX 286
+#define YY_REDUCE_USE_DFLT (-165)
+#define YY_REDUCE_MAX 291
static const short yy_reduce_ofst[] = {
- /* 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,
+ /* 0 */ -138, 277, 546, 137, 401, -21, 44, 36, 38, 242,
+ /* 10 */ -141, 191, 91, 269, 343, 345, -126, 589, 338, 150,
+ /* 20 */ 147, -13, 213, 412, 412, 412, 412, 412, 412, 412,
+ /* 30 */ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ /* 40 */ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ /* 50 */ 412, 412, 412, 412, 412, 211, 698, 714, 716, 722,
+ /* 60 */ 724, 728, 748, 753, 755, 757, 762, 769, 794, 805,
+ /* 70 */ 808, 846, 855, 858, 861, 875, 882, 893, 896, 899,
+ /* 80 */ 901, 903, 906, 920, 930, 932, 934, 936, 945, 947,
+ /* 90 */ 963, 965, 971, 975, 978, 980, 412, 412, 412, 412,
+ /* 100 */ 20, 412, 412, 23, 34, 334, 475, 552, 593, 594,
+ /* 110 */ 585, 212, 412, 289, 412, 412, 412, 412, 135, -164,
+ /* 120 */ -115, 164, 407, 407, 350, 141, 436, 163, 596, -90,
+ /* 130 */ 763, 218, 765, 438, 586, 592, 595, 715, 718, 408,
+ /* 140 */ 723, 380, 634, 677, 787, 798, 144, 529, 588, -14,
+ /* 150 */ 0, 17, 244, 155, 298, 155, 155, 418, 372, 477,
+ /* 160 */ 490, 494, 509, 526, 590, 465, 494, 730, 773, 743,
+ /* 170 */ 833, 792, 854, 860, 155, 792, 864, 885, 848, 859,
+ /* 180 */ 863, 891, 907, 155, 914, 917, 155, 927, 852, 898,
+ /* 190 */ 941, 950, 155, 961, 982, 990, 155, 992, 995, 996,
+ /* 200 */ 155, 155, 999, 1004, 1005, 1006, 1007, 1008, 964, 966,
+ /* 210 */ 1000, 933, 935, 937, 984, 991, 993, 989, 997, 1009,
+ /* 220 */ 1001, 1010, 1002, 973, 974, 1028, 1031, 1032, 1033, 1026,
+ /* 230 */ 998, 988, 1003, 1011, 1012, 1013, 968, 1039, 1040, 1014,
+ /* 240 */ 1015, 1017, 1018, 1025, 1029, 1020, 1034, 1035, 1041, 1036,
+ /* 250 */ 987, 1016, 1027, 1043, 1044, 1045, 1048, 1074, 1067, 1075,
+ /* 260 */ 1072, 1077, 1078, 1080, 1019, 1021, 1083, 1084, 1047, 1051,
+ /* 270 */ 1023, 1046, 1086, 1054, 1057, 1059, 1061, 1049, 1063, 1037,
+ /* 280 */ 1093, 1022, 1024, 1098, 1100, 1038, 1096, 1082, 1085, 1042,
+ /* 290 */ 1050, 1052,
};
static const YYACTIONTYPE yy_default[] = {
- /* 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,
+ /* 0 */ 594, 819, 900, 709, 900, 819, 900, 900, 846, 713,
+ /* 10 */ 875, 817, 900, 900, 900, 900, 791, 900, 846, 900,
+ /* 20 */ 625, 846, 846, 742, 900, 900, 900, 900, 900, 900,
+ /* 30 */ 900, 900, 743, 900, 821, 816, 812, 814, 813, 820,
+ /* 40 */ 744, 733, 740, 747, 725, 859, 749, 750, 756, 757,
+ /* 50 */ 876, 874, 779, 778, 797, 900, 900, 900, 900, 900,
+ /* 60 */ 900, 900, 900, 900, 900, 900, 900, 900, 900, 900,
+ /* 70 */ 900, 900, 900, 900, 900, 900, 900, 900, 900, 900,
+ /* 80 */ 900, 900, 900, 900, 900, 900, 900, 900, 900, 900,
+ /* 90 */ 900, 900, 900, 900, 900, 900, 781, 803, 780, 790,
+ /* 100 */ 618, 782, 783, 678, 613, 900, 900, 900, 900, 900,
+ /* 110 */ 900, 900, 784, 900, 785, 798, 799, 800, 900, 900,
+ /* 120 */ 900, 900, 900, 900, 594, 709, 900, 709, 900, 900,
+ /* 130 */ 900, 900, 900, 900, 900, 900, 900, 900, 900, 900,
+ /* 140 */ 900, 900, 900, 900, 900, 900, 703, 713, 893, 900,
+ /* 150 */ 900, 669, 900, 900, 900, 900, 900, 900, 900, 900,
+ /* 160 */ 900, 900, 601, 599, 900, 701, 900, 900, 627, 900,
+ /* 170 */ 900, 711, 900, 900, 716, 717, 900, 900, 900, 900,
+ /* 180 */ 900, 900, 900, 615, 900, 900, 690, 900, 852, 900,
+ /* 190 */ 900, 900, 866, 900, 900, 900, 864, 900, 900, 900,
+ /* 200 */ 692, 752, 833, 900, 879, 881, 900, 900, 701, 710,
+ /* 210 */ 900, 900, 900, 815, 736, 736, 736, 648, 736, 900,
+ /* 220 */ 736, 900, 651, 746, 746, 598, 598, 598, 598, 668,
+ /* 230 */ 900, 746, 737, 739, 729, 741, 900, 718, 718, 726,
+ /* 240 */ 728, 726, 728, 680, 680, 665, 680, 651, 680, 825,
+ /* 250 */ 830, 830, 665, 680, 680, 680, 825, 610, 718, 610,
+ /* 260 */ 718, 610, 718, 718, 856, 858, 610, 718, 682, 682,
+ /* 270 */ 758, 746, 718, 689, 689, 689, 689, 746, 682, 758,
+ /* 280 */ 718, 878, 878, 718, 718, 886, 635, 653, 653, 861,
+ /* 290 */ 893, 898, 900, 900, 900, 900, 765, 900, 900, 900,
+ /* 300 */ 900, 900, 900, 900, 900, 900, 900, 900, 900, 900,
+ /* 310 */ 839, 900, 900, 900, 900, 770, 766, 900, 767, 900,
+ /* 320 */ 695, 900, 900, 900, 900, 900, 900, 900, 900, 900,
+ /* 330 */ 900, 818, 900, 730, 900, 738, 900, 900, 900, 900,
+ /* 340 */ 900, 900, 900, 900, 900, 900, 900, 900, 900, 900,
+ /* 350 */ 900, 900, 900, 900, 900, 900, 900, 900, 900, 900,
+ /* 360 */ 854, 855, 900, 900, 900, 900, 900, 900, 900, 900,
+ /* 370 */ 900, 900, 900, 900, 900, 900, 900, 900, 900, 900,
+ /* 380 */ 900, 900, 900, 900, 885, 900, 900, 888, 595, 900,
+ /* 390 */ 589, 592, 591, 593, 597, 600, 622, 623, 624, 602,
+ /* 400 */ 603, 604, 605, 606, 607, 608, 614, 616, 634, 636,
+ /* 410 */ 620, 638, 699, 700, 762, 693, 694, 698, 621, 773,
+ /* 420 */ 764, 768, 769, 771, 772, 786, 787, 789, 795, 802,
+ /* 430 */ 805, 788, 793, 794, 796, 801, 804, 696, 697, 808,
+ /* 440 */ 628, 629, 632, 633, 842, 844, 843, 845, 631, 630,
+ /* 450 */ 774, 777, 810, 811, 867, 868, 869, 870, 871, 806,
+ /* 460 */ 719, 809, 792, 731, 734, 735, 732, 702, 712, 721,
+ /* 470 */ 722, 723, 724, 707, 708, 714, 727, 760, 761, 715,
+ /* 480 */ 704, 705, 706, 807, 763, 775, 776, 639, 640, 770,
+ /* 490 */ 641, 642, 643, 681, 684, 685, 686, 644, 663, 666,
+ /* 500 */ 667, 645, 652, 646, 647, 654, 655, 656, 659, 660,
+ /* 510 */ 661, 662, 657, 658, 826, 827, 831, 829, 828, 649,
+ /* 520 */ 650, 664, 637, 626, 619, 670, 673, 674, 675, 676,
+ /* 530 */ 677, 679, 671, 672, 617, 609, 611, 720, 848, 857,
+ /* 540 */ 853, 849, 850, 851, 612, 822, 823, 683, 754, 755,
+ /* 550 */ 847, 860, 862, 759, 863, 865, 890, 687, 688, 691,
+ /* 560 */ 832, 872, 745, 748, 751, 753, 834, 835, 836, 837,
+ /* 570 */ 840, 841, 838, 873, 877, 880, 882, 883, 884, 887,
+ /* 580 */ 889, 894, 895, 896, 899, 897, 596, 590,
};
#define YY_SZ_ACTTAB (int)(sizeof(yy_action)/sizeof(yy_action[0]))
@@ -646,7 +651,6 @@ static const YYCODETYPE yyFallback[] = {
23, /* REPLACE => ID */
23, /* RESTRICT => ID */
23, /* ROW => ID */
- 23, /* STATEMENT => ID */
23, /* TRIGGER => ID */
23, /* VACUUM => ID */
23, /* VIEW => ID */
@@ -679,6 +683,7 @@ static const YYCODETYPE yyFallback[] = {
0, /* SLASH => nothing */
0, /* REM => nothing */
0, /* CONCAT => nothing */
+ 0, /* COLLATE => nothing */
0, /* UMINUS => nothing */
0, /* UPLUS => nothing */
0, /* BITNOT => nothing */
@@ -691,7 +696,6 @@ static const YYCODETYPE yyFallback[] = {
0, /* UNIQUE => nothing */
0, /* CHECK => nothing */
0, /* REFERENCES => nothing */
- 0, /* COLLATE => nothing */
0, /* AUTOINCR => nothing */
0, /* ON => nothing */
0, /* DELETE => nothing */
@@ -763,7 +767,12 @@ struct yyParser {
int yyidx; /* Index of top element in stack */
int yyerrcnt; /* Shifts left before out of the error */
sqlite3ParserARG_SDECL /* A place to hold %extra_argument */
+#if YYSTACKDEPTH<=0
+ int yystksz; /* Current side of the stack */
+ yyStackEntry *yystack; /* The parser's stack */
+#else
yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
+#endif
};
typedef struct yyParser yyParser;
@@ -816,50 +825,50 @@ static const char *const yyTokenName[] = {
"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",
+ "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",
+ "COLLATE", "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",
+ "REFERENCES", "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", "nexprlist",
+ "setlist", "insert_cmd", "inscollist_opt", "itemlist",
+ "exprlist", "likeop", "escape", "between_op",
+ "in_op", "case_operand", "case_exprlist", "case_else",
+ "uniqueflag", "idxitem", "collate", "nmnum",
"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",
@@ -922,11 +931,11 @@ static const char *const yyRuleName[] = {
/* 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",
+ /* 50 */ "ccons ::= DEFAULT term",
+ /* 51 */ "ccons ::= DEFAULT LP expr RP",
+ /* 52 */ "ccons ::= DEFAULT PLUS term",
+ /* 53 */ "ccons ::= DEFAULT MINUS term",
+ /* 54 */ "ccons ::= DEFAULT id",
/* 55 */ "ccons ::= NULL onconf",
/* 56 */ "ccons ::= NOT NULL onconf",
/* 57 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
@@ -934,7 +943,7 @@ static const char *const yyRuleName[] = {
/* 59 */ "ccons ::= CHECK LP expr RP",
/* 60 */ "ccons ::= REFERENCES nm idxlist_opt refargs",
/* 61 */ "ccons ::= defer_subclause",
- /* 62 */ "ccons ::= COLLATE id",
+ /* 62 */ "ccons ::= COLLATE ids",
/* 63 */ "autoinc ::=",
/* 64 */ "autoinc ::= AUTOINCR",
/* 65 */ "refargs ::=",
@@ -974,7 +983,7 @@ static const char *const yyRuleName[] = {
/* 99 */ "cmd ::= DROP TABLE ifexists fullname",
/* 100 */ "ifexists ::= IF EXISTS",
/* 101 */ "ifexists ::=",
- /* 102 */ "cmd ::= CREATE temp VIEW nm dbnm AS select",
+ /* 102 */ "cmd ::= CREATE temp VIEW ifnotexists nm dbnm AS select",
/* 103 */ "cmd ::= DROP VIEW ifexists fullname",
/* 104 */ "cmd ::= select",
/* 105 */ "select ::= oneselect",
@@ -1015,49 +1024,49 @@ static const char *const yyRuleName[] = {
/* 140 */ "using_opt ::=",
/* 141 */ "orderby_opt ::=",
/* 142 */ "orderby_opt ::= ORDER BY sortlist",
- /* 143 */ "sortlist ::= sortlist COMMA sortitem collate sortorder",
- /* 144 */ "sortlist ::= sortitem collate sortorder",
+ /* 143 */ "sortlist ::= sortlist COMMA sortitem sortorder",
+ /* 144 */ "sortlist ::= sortitem 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 */ "expr ::= REGISTER",
- /* 185 */ "expr ::= VARIABLE",
+ /* 149 */ "groupby_opt ::=",
+ /* 150 */ "groupby_opt ::= GROUP BY nexprlist",
+ /* 151 */ "having_opt ::=",
+ /* 152 */ "having_opt ::= HAVING expr",
+ /* 153 */ "limit_opt ::=",
+ /* 154 */ "limit_opt ::= LIMIT expr",
+ /* 155 */ "limit_opt ::= LIMIT expr OFFSET expr",
+ /* 156 */ "limit_opt ::= LIMIT expr COMMA expr",
+ /* 157 */ "cmd ::= DELETE FROM fullname where_opt",
+ /* 158 */ "where_opt ::=",
+ /* 159 */ "where_opt ::= WHERE expr",
+ /* 160 */ "cmd ::= UPDATE orconf fullname SET setlist where_opt",
+ /* 161 */ "setlist ::= setlist COMMA nm EQ expr",
+ /* 162 */ "setlist ::= nm EQ expr",
+ /* 163 */ "cmd ::= insert_cmd INTO fullname inscollist_opt VALUES LP itemlist RP",
+ /* 164 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select",
+ /* 165 */ "cmd ::= insert_cmd INTO fullname inscollist_opt DEFAULT VALUES",
+ /* 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|FLOAT|BLOB",
+ /* 182 */ "term ::= STRING",
+ /* 183 */ "expr ::= REGISTER",
+ /* 184 */ "expr ::= VARIABLE",
+ /* 185 */ "expr ::= expr COLLATE ids",
/* 186 */ "expr ::= CAST LP expr AS typetoken RP",
/* 187 */ "expr ::= ID LP distinct exprlist RP",
/* 188 */ "expr ::= ID LP STAR RP",
@@ -1081,124 +1090,135 @@ static const char *const yyRuleName[] = {
/* 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",
+ /* 209 */ "expr ::= NOT expr",
+ /* 210 */ "expr ::= BITNOT expr",
+ /* 211 */ "expr ::= MINUS expr",
+ /* 212 */ "expr ::= PLUS expr",
+ /* 213 */ "between_op ::= BETWEEN",
+ /* 214 */ "between_op ::= NOT BETWEEN",
+ /* 215 */ "expr ::= expr between_op expr AND expr",
+ /* 216 */ "in_op ::= IN",
+ /* 217 */ "in_op ::= NOT IN",
+ /* 218 */ "expr ::= expr in_op LP exprlist RP",
+ /* 219 */ "expr ::= LP select RP",
+ /* 220 */ "expr ::= expr in_op LP select RP",
+ /* 221 */ "expr ::= expr in_op nm dbnm",
+ /* 222 */ "expr ::= EXISTS LP select RP",
+ /* 223 */ "expr ::= CASE case_operand case_exprlist case_else END",
+ /* 224 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
+ /* 225 */ "case_exprlist ::= WHEN expr THEN expr",
+ /* 226 */ "case_else ::= ELSE expr",
+ /* 227 */ "case_else ::=",
+ /* 228 */ "case_operand ::= expr",
+ /* 229 */ "case_operand ::=",
+ /* 230 */ "exprlist ::= nexprlist",
+ /* 231 */ "exprlist ::=",
+ /* 232 */ "nexprlist ::= nexprlist COMMA expr",
+ /* 233 */ "nexprlist ::= expr",
+ /* 234 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP",
+ /* 235 */ "uniqueflag ::= UNIQUE",
+ /* 236 */ "uniqueflag ::=",
+ /* 237 */ "idxlist_opt ::=",
+ /* 238 */ "idxlist_opt ::= LP idxlist RP",
+ /* 239 */ "idxlist ::= idxlist COMMA idxitem collate sortorder",
+ /* 240 */ "idxlist ::= idxitem collate sortorder",
+ /* 241 */ "idxitem ::= nm",
+ /* 242 */ "collate ::=",
+ /* 243 */ "collate ::= COLLATE ids",
+ /* 244 */ "cmd ::= DROP INDEX ifexists fullname",
+ /* 245 */ "cmd ::= VACUUM",
+ /* 246 */ "cmd ::= VACUUM nm",
+ /* 247 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
+ /* 248 */ "cmd ::= PRAGMA nm dbnm EQ ON",
+ /* 249 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
+ /* 250 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
+ /* 251 */ "cmd ::= PRAGMA nm dbnm",
+ /* 252 */ "nmnum ::= plus_num",
+ /* 253 */ "nmnum ::= nm",
+ /* 254 */ "plus_num ::= plus_opt number",
+ /* 255 */ "minus_num ::= MINUS number",
+ /* 256 */ "number ::= INTEGER|FLOAT",
+ /* 257 */ "plus_opt ::= PLUS",
+ /* 258 */ "plus_opt ::=",
+ /* 259 */ "cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END",
+ /* 260 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
+ /* 261 */ "trigger_time ::= BEFORE",
+ /* 262 */ "trigger_time ::= AFTER",
+ /* 263 */ "trigger_time ::= INSTEAD OF",
+ /* 264 */ "trigger_time ::=",
+ /* 265 */ "trigger_event ::= DELETE|INSERT",
+ /* 266 */ "trigger_event ::= UPDATE",
+ /* 267 */ "trigger_event ::= UPDATE OF inscollist",
+ /* 268 */ "foreach_clause ::=",
+ /* 269 */ "foreach_clause ::= FOR EACH ROW",
+ /* 270 */ "when_clause ::=",
+ /* 271 */ "when_clause ::= WHEN expr",
+ /* 272 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
+ /* 273 */ "trigger_cmd_list ::=",
+ /* 274 */ "trigger_cmd ::= UPDATE orconf nm SET setlist where_opt",
+ /* 275 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt VALUES LP itemlist RP",
+ /* 276 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt select",
+ /* 277 */ "trigger_cmd ::= DELETE FROM nm where_opt",
+ /* 278 */ "trigger_cmd ::= select",
+ /* 279 */ "expr ::= RAISE LP IGNORE RP",
+ /* 280 */ "expr ::= RAISE LP raisetype COMMA nm RP",
+ /* 281 */ "raisetype ::= ROLLBACK",
+ /* 282 */ "raisetype ::= ABORT",
+ /* 283 */ "raisetype ::= FAIL",
+ /* 284 */ "cmd ::= DROP TRIGGER ifexists fullname",
+ /* 285 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
+ /* 286 */ "cmd ::= DETACH database_kw_opt expr",
+ /* 287 */ "key_opt ::=",
+ /* 288 */ "key_opt ::= KEY expr",
+ /* 289 */ "database_kw_opt ::= DATABASE",
+ /* 290 */ "database_kw_opt ::=",
+ /* 291 */ "cmd ::= REINDEX",
+ /* 292 */ "cmd ::= REINDEX nm dbnm",
+ /* 293 */ "cmd ::= ANALYZE",
+ /* 294 */ "cmd ::= ANALYZE nm dbnm",
+ /* 295 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
+ /* 296 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column",
+ /* 297 */ "add_column_fullname ::= fullname",
+ /* 298 */ "kwcolumn_opt ::=",
+ /* 299 */ "kwcolumn_opt ::= COLUMNKW",
+ /* 300 */ "cmd ::= create_vtab",
+ /* 301 */ "cmd ::= create_vtab LP vtabarglist RP",
+ /* 302 */ "create_vtab ::= CREATE VIRTUAL TABLE nm dbnm USING nm",
+ /* 303 */ "vtabarglist ::= vtabarg",
+ /* 304 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
+ /* 305 */ "vtabarg ::=",
+ /* 306 */ "vtabarg ::= vtabarg vtabargtoken",
+ /* 307 */ "vtabargtoken ::= ANY",
+ /* 308 */ "vtabargtoken ::= lp anylist RP",
+ /* 309 */ "lp ::= LP",
+ /* 310 */ "anylist ::=",
+ /* 311 */ "anylist ::= anylist ANY",
};
#endif /* NDEBUG */
+
+#if YYSTACKDEPTH<=0
/*
-** This function returns the symbolic name associated with a token
-** value.
+** Try to increase the size of the parser stack.
*/
-const char *sqlite3ParserTokenName(int tokenType){
+static void yyGrowStack(yyParser *p){
+ int newSize;
+ yyStackEntry *pNew;
+
+ newSize = p->yystksz*2 + 100;
+ pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
+ if( pNew ){
+ p->yystack = pNew;
+ p->yystksz = newSize;
#ifndef NDEBUG
- if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
- return yyTokenName[tokenType];
- }else{
- return "Unknown";
- }
-#else
- return "";
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack grows to %d entries!\n",
+ yyTracePrompt, p->yystksz);
+ }
#endif
+ }
}
+#endif
/*
** This function allocates a new parser.
@@ -1217,6 +1237,9 @@ void *sqlite3ParserAlloc(void *(*mallocProc)(size_t)){
pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
if( pParser ){
pParser->yyidx = -1;
+#if YYSTACKDEPTH<=0
+ yyGrowStack(pParser);
+#endif
}
return pParser;
}
@@ -1238,81 +1261,69 @@ 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 156:
- case 190:
- case 207:
-#line 374 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 155: /* select */
+ case 189: /* oneselect */
+ case 206: /* seltablist_paren */
+#line 369 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3SelectDelete((yypminor->yy219));}
-#line 1248 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1271 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 170:
- case 171:
- case 195:
- case 197:
- case 205:
- case 211:
- case 219:
- case 222:
- case 224:
- case 225:
- case 235:
-#line 631 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 169: /* term */
+ case 170: /* expr */
+ case 194: /* where_opt */
+ case 196: /* having_opt */
+ case 204: /* on_opt */
+ case 210: /* sortitem */
+ case 218: /* escape */
+ case 221: /* case_operand */
+ case 223: /* case_else */
+ case 235: /* when_clause */
+ case 238: /* key_opt */
+#line 629 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3ExprDelete((yypminor->yy172));}
-#line 1263 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1286 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 175:
- case 183:
- case 193:
- case 196:
- case 198:
- case 200:
- case 210:
- case 213:
- case 214:
- case 217:
- case 223:
-#line 865 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 174: /* idxlist_opt */
+ case 182: /* idxlist */
+ case 192: /* selcollist */
+ case 195: /* groupby_opt */
+ case 197: /* orderby_opt */
+ case 199: /* sclp */
+ case 209: /* sortlist */
+ case 211: /* nexprlist */
+ case 212: /* setlist */
+ case 215: /* itemlist */
+ case 216: /* exprlist */
+ case 222: /* case_exprlist */
+#line 887 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3ExprListDelete((yypminor->yy174));}
-#line 1278 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1302 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 189:
- case 194:
- case 202:
- case 203:
-#line 502 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 188: /* fullname */
+ case 193: /* from */
+ case 201: /* seltablist */
+ case 202: /* stl_prefix */
+#line 486 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3SrcListDelete((yypminor->yy373));}
-#line 1286 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1310 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 199:
-#line 563 "ext/pdo_sqlite/sqlite/src/parse.y"
-{
- sqlite3ExprDelete((yypminor->yy234).pLimit);
- sqlite3ExprDelete((yypminor->yy234).pOffset);
-}
-#line 1294 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 206:
- case 209:
- case 216:
-#line 519 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 205: /* using_opt */
+ case 208: /* inscollist */
+ case 214: /* inscollist_opt */
+#line 503 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3IdListDelete((yypminor->yy432));}
-#line 1301 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1317 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 231:
- case 236:
-#line 959 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 231: /* trigger_cmd_list */
+ case 236: /* trigger_cmd */
+#line 990 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3DeleteTriggerStep((yypminor->yy243));}
-#line 1307 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1323 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 233:
-#line 943 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 233: /* trigger_event */
+#line 976 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3IdListDelete((yypminor->yy370).b);}
-#line 1312 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 238:
-#line 1027 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3ExprDelete((yypminor->yy386));}
-#line 1317 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1328 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
default: break; /* If no destructor action specified: do nothing */
}
@@ -1363,6 +1374,9 @@ void sqlite3ParserFree(
yyParser *pParser = (yyParser*)p;
if( pParser==0 ) return;
while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
+#if YYSTACKDEPTH<=0
+ free(pParser->yystack);
+#endif
(*freeProc)((void*)pParser);
}
@@ -1384,9 +1398,7 @@ static int yy_find_shift_action(
if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
return yy_default[stateno];
}
- if( iLookAhead==YYNOCODE ){
- return YY_NO_ACTION;
- }
+ assert( iLookAhead!=YYNOCODE );
i += iLookAhead;
if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
if( iLookAhead>0 ){
@@ -1437,21 +1449,36 @@ static int yy_find_reduce_action(
YYCODETYPE iLookAhead /* The look-ahead token */
){
int i;
- /* int stateno = pParser->yystack[pParser->yyidx].stateno; */
-
- if( stateno>YY_REDUCE_MAX ||
- (i = yy_reduce_ofst[stateno])==YY_REDUCE_USE_DFLT ){
- return yy_default[stateno];
- }
- if( iLookAhead==YYNOCODE ){
- return YY_NO_ACTION;
- }
+ assert( stateno<=YY_REDUCE_MAX );
+ i = yy_reduce_ofst[stateno];
+ assert( i!=YY_REDUCE_USE_DFLT );
+ assert( iLookAhead!=YYNOCODE );
i += iLookAhead;
- if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
- return yy_default[stateno];
- }else{
- return yy_action[i];
- }
+ assert( i>=0 && i<YY_SZ_ACTTAB );
+ assert( yy_lookahead[i]==iLookAhead );
+ return yy_action[i];
+}
+
+/*
+** The following routine is called if the stack overflows.
+*/
+static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
+ sqlite3ParserARG_FETCH;
+ yypParser->yyidx--;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will execute if the parser
+ ** stack every overflows */
+#line 39 "ext/pdo_sqlite/sqlite/src/parse.y"
+
+ sqlite3ErrorMsg(pParse, "parser stack overflow");
+ pParse->parseError = 1;
+#line 1483 "ext/pdo_sqlite/sqlite/src/parse.c"
+ sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
}
/*
@@ -1465,25 +1492,20 @@ static void yy_shift(
){
yyStackEntry *yytos;
yypParser->yyidx++;
+#if YYSTACKDEPTH>0
if( yypParser->yyidx>=YYSTACKDEPTH ){
- sqlite3ParserARG_FETCH;
- yypParser->yyidx--;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
- }
-#endif
- while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
- /* Here code is inserted which will execute if the parser
- ** stack every overflows */
-#line 44 "ext/pdo_sqlite/sqlite/src/parse.y"
-
- sqlite3ErrorMsg(pParse, "parser stack overflow");
- pParse->parseError = 1;
-#line 1486 "ext/pdo_sqlite/sqlite/src/parse.c"
- sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
- return;
+ yyStackOverflow(yypParser, yypMinor);
+ return;
}
+#else
+ if( yypParser->yyidx>=yypParser->yystksz ){
+ yyGrowStack(yypParser);
+ if( yypParser->yyidx>=yypParser->yystksz ){
+ yyStackOverflow(yypParser, yypMinor);
+ return;
+ }
+ }
+#endif
yytos = &yypParser->yystack[yypParser->yyidx];
yytos->stateno = yyNewState;
yytos->major = yyMajor;
@@ -1507,263 +1529,267 @@ 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[] = {
+ { 139, 1 },
+ { 140, 2 },
{ 140, 1 },
- { 141, 2 },
- { 141, 1 },
- { 143, 1 },
{ 142, 1 },
- { 142, 3 },
- { 145, 0 },
- { 145, 1 },
- { 145, 3 },
+ { 141, 1 },
+ { 141, 3 },
+ { 144, 0 },
+ { 144, 1 },
{ 144, 3 },
- { 147, 0 },
- { 147, 1 },
- { 147, 2 },
+ { 143, 3 },
{ 146, 0 },
{ 146, 1 },
- { 146, 1 },
- { 146, 1 },
- { 144, 2 },
- { 144, 2 },
- { 144, 2 },
- { 144, 2 },
- { 149, 6 },
- { 152, 0 },
- { 152, 3 },
- { 151, 1 },
+ { 146, 2 },
+ { 145, 0 },
+ { 145, 1 },
+ { 145, 1 },
+ { 145, 1 },
+ { 143, 2 },
+ { 143, 2 },
+ { 143, 2 },
+ { 143, 2 },
+ { 148, 6 },
{ 151, 0 },
- { 150, 4 },
- { 150, 2 },
- { 154, 3 },
- { 154, 1 },
- { 157, 3 },
- { 158, 1 },
+ { 151, 3 },
+ { 150, 1 },
+ { 150, 0 },
+ { 149, 4 },
+ { 149, 2 },
+ { 153, 3 },
+ { 153, 1 },
+ { 156, 3 },
+ { 157, 1 },
+ { 160, 1 },
{ 161, 1 },
+ { 147, 1 },
+ { 147, 1 },
+ { 147, 1 },
+ { 158, 0 },
+ { 158, 1 },
{ 162, 1 },
- { 148, 1 },
- { 148, 1 },
- { 148, 1 },
- { 159, 0 },
- { 159, 1 },
+ { 162, 4 },
+ { 162, 6 },
{ 163, 1 },
- { 163, 4 },
- { 163, 6 },
+ { 163, 2 },
{ 164, 1 },
- { 164, 2 },
- { 165, 1 },
- { 165, 1 },
- { 160, 2 },
- { 160, 0 },
- { 168, 3 },
- { 168, 1 },
+ { 164, 1 },
+ { 159, 2 },
+ { 159, 0 },
+ { 167, 3 },
+ { 167, 1 },
{ 168, 2 },
{ 168, 4 },
{ 168, 3 },
{ 168, 3 },
{ 168, 2 },
- { 169, 2 },
- { 169, 3 },
- { 169, 5 },
- { 169, 2 },
- { 169, 4 },
- { 169, 4 },
- { 169, 1 },
- { 169, 2 },
- { 174, 0 },
- { 174, 1 },
- { 176, 0 },
- { 176, 2 },
+ { 168, 2 },
+ { 168, 3 },
+ { 168, 5 },
+ { 168, 2 },
+ { 168, 4 },
+ { 168, 4 },
+ { 168, 1 },
+ { 168, 2 },
+ { 173, 0 },
+ { 173, 1 },
+ { 175, 0 },
+ { 175, 2 },
+ { 177, 2 },
+ { 177, 3 },
+ { 177, 3 },
+ { 177, 3 },
+ { 178, 2 },
{ 178, 2 },
- { 178, 3 },
- { 178, 3 },
- { 178, 3 },
+ { 178, 1 },
+ { 178, 1 },
+ { 176, 3 },
+ { 176, 2 },
+ { 179, 0 },
{ 179, 2 },
{ 179, 2 },
- { 179, 1 },
- { 179, 1 },
- { 177, 3 },
- { 177, 2 },
- { 180, 0 },
- { 180, 2 },
+ { 154, 0 },
+ { 154, 2 },
+ { 180, 3 },
{ 180, 2 },
- { 155, 0 },
- { 155, 2 },
- { 181, 3 },
+ { 180, 1 },
{ 181, 2 },
- { 181, 1 },
- { 182, 2 },
- { 182, 7 },
- { 182, 5 },
- { 182, 5 },
- { 182, 10 },
+ { 181, 7 },
+ { 181, 5 },
+ { 181, 5 },
+ { 181, 10 },
+ { 183, 0 },
+ { 183, 1 },
+ { 171, 0 },
+ { 171, 3 },
{ 184, 0 },
- { 184, 1 },
- { 172, 0 },
- { 172, 3 },
- { 185, 0 },
- { 185, 2 },
- { 186, 1 },
- { 186, 1 },
- { 186, 1 },
- { 144, 4 },
- { 188, 2 },
- { 188, 0 },
- { 144, 7 },
- { 144, 4 },
- { 144, 1 },
- { 156, 1 },
- { 156, 3 },
+ { 184, 2 },
+ { 185, 1 },
+ { 185, 1 },
+ { 185, 1 },
+ { 143, 4 },
+ { 187, 2 },
+ { 187, 0 },
+ { 143, 8 },
+ { 143, 4 },
+ { 143, 1 },
+ { 155, 1 },
+ { 155, 3 },
+ { 190, 1 },
+ { 190, 2 },
+ { 190, 1 },
+ { 189, 9 },
{ 191, 1 },
- { 191, 2 },
{ 191, 1 },
- { 190, 9 },
- { 192, 1 },
- { 192, 1 },
- { 192, 0 },
+ { 191, 0 },
+ { 199, 2 },
+ { 199, 0 },
+ { 192, 3 },
+ { 192, 2 },
+ { 192, 4 },
{ 200, 2 },
+ { 200, 1 },
{ 200, 0 },
- { 193, 3 },
+ { 193, 0 },
{ 193, 2 },
- { 193, 4 },
- { 201, 2 },
- { 201, 1 },
- { 201, 0 },
- { 194, 0 },
- { 194, 2 },
+ { 202, 2 },
+ { 202, 0 },
+ { 201, 6 },
+ { 201, 7 },
+ { 206, 1 },
+ { 206, 1 },
+ { 152, 0 },
+ { 152, 2 },
+ { 188, 2 },
+ { 203, 1 },
{ 203, 2 },
- { 203, 0 },
- { 202, 6 },
- { 202, 7 },
- { 207, 1 },
- { 207, 1 },
- { 153, 0 },
- { 153, 2 },
- { 189, 2 },
- { 204, 1 },
+ { 203, 3 },
+ { 203, 4 },
{ 204, 2 },
- { 204, 3 },
- { 204, 4 },
- { 205, 2 },
+ { 204, 0 },
+ { 205, 4 },
{ 205, 0 },
- { 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 },
- { 199, 4 },
- { 199, 4 },
- { 144, 4 },
+ { 197, 3 },
+ { 209, 4 },
+ { 209, 2 },
+ { 210, 1 },
+ { 172, 1 },
+ { 172, 1 },
+ { 172, 0 },
{ 195, 0 },
- { 195, 2 },
- { 144, 6 },
- { 214, 5 },
- { 214, 3 },
- { 144, 8 },
- { 144, 5 },
- { 215, 2 },
+ { 195, 3 },
+ { 196, 0 },
+ { 196, 2 },
+ { 198, 0 },
+ { 198, 2 },
+ { 198, 4 },
+ { 198, 4 },
+ { 143, 4 },
+ { 194, 0 },
+ { 194, 2 },
+ { 143, 6 },
+ { 212, 5 },
+ { 212, 3 },
+ { 143, 8 },
+ { 143, 5 },
+ { 143, 6 },
+ { 213, 2 },
+ { 213, 1 },
+ { 215, 3 },
{ 215, 1 },
- { 217, 3 },
- { 217, 1 },
- { 216, 0 },
- { 216, 3 },
- { 209, 3 },
- { 209, 1 },
- { 171, 1 },
- { 171, 3 },
+ { 214, 0 },
+ { 214, 3 },
+ { 208, 3 },
+ { 208, 1 },
{ 170, 1 },
- { 171, 1 },
- { 171, 1 },
- { 171, 3 },
- { 171, 5 },
+ { 170, 3 },
+ { 169, 1 },
{ 170, 1 },
{ 170, 1 },
- { 171, 1 },
- { 171, 1 },
- { 171, 6 },
- { 171, 5 },
- { 171, 4 },
+ { 170, 3 },
+ { 170, 5 },
+ { 169, 1 },
+ { 169, 1 },
{ 170, 1 },
- { 171, 3 },
- { 171, 3 },
- { 171, 3 },
- { 171, 3 },
- { 171, 3 },
- { 171, 3 },
- { 171, 3 },
- { 171, 3 },
- { 218, 1 },
- { 218, 2 },
- { 218, 1 },
+ { 170, 1 },
+ { 170, 3 },
+ { 170, 6 },
+ { 170, 5 },
+ { 170, 4 },
+ { 169, 1 },
+ { 170, 3 },
+ { 170, 3 },
+ { 170, 3 },
+ { 170, 3 },
+ { 170, 3 },
+ { 170, 3 },
+ { 170, 3 },
+ { 170, 3 },
+ { 217, 1 },
+ { 217, 2 },
+ { 217, 1 },
+ { 217, 2 },
{ 218, 2 },
+ { 218, 0 },
+ { 170, 4 },
+ { 170, 2 },
+ { 170, 3 },
+ { 170, 3 },
+ { 170, 4 },
+ { 170, 2 },
+ { 170, 2 },
+ { 170, 2 },
+ { 170, 2 },
+ { 219, 1 },
{ 219, 2 },
- { 219, 0 },
- { 171, 4 },
- { 171, 2 },
- { 171, 3 },
- { 171, 3 },
- { 171, 4 },
- { 171, 2 },
- { 171, 2 },
- { 171, 2 },
+ { 170, 5 },
{ 220, 1 },
{ 220, 2 },
- { 171, 5 },
+ { 170, 5 },
+ { 170, 3 },
+ { 170, 5 },
+ { 170, 4 },
+ { 170, 4 },
+ { 170, 5 },
+ { 222, 5 },
+ { 222, 4 },
+ { 223, 2 },
+ { 223, 0 },
{ 221, 1 },
- { 221, 2 },
- { 171, 5 },
- { 171, 3 },
- { 171, 5 },
- { 171, 4 },
- { 171, 4 },
- { 171, 5 },
- { 223, 5 },
- { 223, 4 },
- { 224, 2 },
+ { 221, 0 },
+ { 216, 1 },
+ { 216, 0 },
+ { 211, 3 },
+ { 211, 1 },
+ { 143, 11 },
+ { 224, 1 },
{ 224, 0 },
- { 222, 1 },
- { 222, 0 },
- { 213, 3 },
- { 213, 1 },
+ { 174, 0 },
+ { 174, 3 },
+ { 182, 5 },
+ { 182, 3 },
{ 225, 1 },
- { 225, 0 },
- { 144, 11 },
- { 226, 1 },
{ 226, 0 },
- { 175, 0 },
- { 175, 3 },
- { 183, 5 },
- { 183, 3 },
+ { 226, 2 },
+ { 143, 4 },
+ { 143, 1 },
+ { 143, 2 },
+ { 143, 5 },
+ { 143, 5 },
+ { 143, 5 },
+ { 143, 6 },
+ { 143, 3 },
{ 227, 1 },
- { 144, 4 },
- { 144, 1 },
- { 144, 2 },
- { 144, 5 },
- { 144, 5 },
- { 144, 5 },
- { 144, 5 },
- { 144, 6 },
- { 144, 3 },
+ { 227, 1 },
+ { 165, 2 },
{ 166, 2 },
- { 167, 2 },
{ 229, 1 },
{ 228, 1 },
{ 228, 0 },
- { 144, 5 },
- { 230, 10 },
+ { 143, 5 },
+ { 230, 11 },
{ 232, 1 },
{ 232, 1 },
{ 232, 2 },
@@ -1773,7 +1799,6 @@ static const struct {
{ 233, 3 },
{ 234, 0 },
{ 234, 3 },
- { 234, 3 },
{ 235, 0 },
{ 235, 2 },
{ 231, 3 },
@@ -1783,29 +1808,29 @@ static const struct {
{ 236, 5 },
{ 236, 4 },
{ 236, 1 },
- { 171, 4 },
- { 171, 6 },
- { 187, 1 },
- { 187, 1 },
- { 187, 1 },
- { 144, 3 },
- { 144, 6 },
+ { 170, 4 },
+ { 170, 6 },
+ { 186, 1 },
+ { 186, 1 },
+ { 186, 1 },
+ { 143, 4 },
+ { 143, 6 },
+ { 143, 3 },
{ 238, 0 },
{ 238, 2 },
{ 237, 1 },
{ 237, 0 },
- { 144, 3 },
- { 144, 1 },
- { 144, 3 },
- { 144, 1 },
- { 144, 3 },
- { 144, 6 },
- { 144, 6 },
+ { 143, 1 },
+ { 143, 3 },
+ { 143, 1 },
+ { 143, 3 },
+ { 143, 6 },
+ { 143, 6 },
{ 239, 1 },
{ 240, 0 },
{ 240, 1 },
- { 144, 1 },
- { 144, 4 },
+ { 143, 1 },
+ { 143, 4 },
{ 241, 7 },
{ 242, 1 },
{ 242, 3 },
@@ -1843,7 +1868,6 @@ static void yy_reduce(
}
#endif /* NDEBUG */
-#ifndef NDEBUG
/* Silence complaints from purify about yygotominor being uninitialized
** in some cases when it is copied into the stack after the following
** switch. yygotominor is uninitialized when a rule reduces that does
@@ -1851,9 +1875,15 @@ static void yy_reduce(
** value of the nonterminal uninitialized is utterly harmless as long
** as the value is never used. So really the only thing this code
** accomplishes is to quieten purify.
+ **
+ ** 2007-01-16: The wireshark project (www.wireshark.org) reports that
+ ** without this code, their parser segfaults. I'm not sure what there
+ ** parser is doing to make this happen. This is the second bug report
+ ** from wireshark this week. Clearly they are stressing Lemon in ways
+ ** that it has not been previously stressed... (SQLite ticket #2172)
*/
memset(&yygotominor, 0, sizeof(yygotominor));
-#endif
+
switch( yyruleno ){
/* Beginning here are the reduction cases. A typical example
@@ -1864,1143 +1894,1186 @@ static void yy_reduce(
** #line <lineno> <thisfile>
** break;
*/
- case 3:
-#line 100 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 0: /* input ::= cmdlist */
+ case 1: /* cmdlist ::= cmdlist ecmd */
+ case 2: /* cmdlist ::= ecmd */
+ case 4: /* ecmd ::= SEMI */
+ case 5: /* ecmd ::= explain cmdx SEMI */
+ case 10: /* trans_opt ::= */
+ case 11: /* trans_opt ::= TRANSACTION */
+ case 12: /* trans_opt ::= TRANSACTION nm */
+ case 20: /* cmd ::= create_table create_table_args */
+ case 28: /* columnlist ::= columnlist COMMA column */
+ case 29: /* columnlist ::= column */
+ case 37: /* type ::= */
+ case 44: /* signed ::= plus_num */
+ case 45: /* signed ::= minus_num */
+ case 46: /* carglist ::= carglist carg */
+ case 47: /* carglist ::= */
+ case 48: /* carg ::= CONSTRAINT nm ccons */
+ case 49: /* carg ::= ccons */
+ case 55: /* ccons ::= NULL onconf */
+ case 82: /* conslist ::= conslist COMMA tcons */
+ case 83: /* conslist ::= conslist tcons */
+ case 84: /* conslist ::= tcons */
+ case 85: /* tcons ::= CONSTRAINT nm */
+ case 257: /* plus_opt ::= PLUS */
+ case 258: /* plus_opt ::= */
+ case 268: /* foreach_clause ::= */
+ case 269: /* foreach_clause ::= FOR EACH ROW */
+ case 289: /* database_kw_opt ::= DATABASE */
+ case 290: /* database_kw_opt ::= */
+ case 298: /* kwcolumn_opt ::= */
+ case 299: /* kwcolumn_opt ::= COLUMNKW */
+ case 303: /* vtabarglist ::= vtabarg */
+ case 304: /* vtabarglist ::= vtabarglist COMMA vtabarg */
+ case 306: /* vtabarg ::= vtabarg vtabargtoken */
+ case 310: /* anylist ::= */
+#line 91 "ext/pdo_sqlite/sqlite/src/parse.y"
+{
+}
+#line 1938 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 3: /* cmdx ::= cmd */
+#line 94 "ext/pdo_sqlite/sqlite/src/parse.y"
{ sqlite3FinishCoding(pParse); }
-#line 1873 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1943 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 6:
-#line 103 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 6: /* explain ::= */
+#line 97 "ext/pdo_sqlite/sqlite/src/parse.y"
{ sqlite3BeginParse(pParse, 0); }
-#line 1878 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1948 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 7:
-#line 105 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 7: /* explain ::= EXPLAIN */
+#line 99 "ext/pdo_sqlite/sqlite/src/parse.y"
{ sqlite3BeginParse(pParse, 1); }
-#line 1883 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1953 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 8:
-#line 106 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 8: /* explain ::= EXPLAIN QUERY PLAN */
+#line 100 "ext/pdo_sqlite/sqlite/src/parse.y"
{ sqlite3BeginParse(pParse, 2); }
-#line 1888 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1958 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 9:
-#line 112 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 9: /* cmd ::= BEGIN transtype trans_opt */
+#line 106 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy46);}
-#line 1893 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1963 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 13:
-#line 117 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 13: /* transtype ::= */
+#line 111 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = TK_DEFERRED;}
-#line 1898 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 14:
- case 15:
- case 16:
- case 107:
- case 109:
-#line 118 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 1968 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 14: /* transtype ::= DEFERRED */
+ case 15: /* transtype ::= IMMEDIATE */
+ case 16: /* transtype ::= EXCLUSIVE */
+ case 107: /* multiselect_op ::= UNION */
+ case 109: /* multiselect_op ::= EXCEPT|INTERSECT */
+#line 112 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = yymsp[0].major;}
-#line 1907 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1977 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 17:
- case 18:
-#line 121 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 17: /* cmd ::= COMMIT trans_opt */
+ case 18: /* cmd ::= END trans_opt */
+#line 115 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3CommitTransaction(pParse);}
-#line 1913 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1983 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 19:
-#line 123 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 19: /* cmd ::= ROLLBACK trans_opt */
+#line 117 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3RollbackTransaction(pParse);}
-#line 1918 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1988 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 21:
-#line 128 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 21: /* create_table ::= CREATE temp TABLE ifnotexists nm dbnm */
+#line 122 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3StartTable(pParse,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410,yymsp[-4].minor.yy46,0,0,yymsp[-2].minor.yy46);
}
-#line 1925 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 22:
- case 25:
- case 63:
- case 77:
- case 79:
- case 90:
- case 101:
- case 112:
- case 113:
- case 212:
- case 215:
-#line 132 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 1995 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 22: /* ifnotexists ::= */
+ case 25: /* temp ::= */
+ case 63: /* autoinc ::= */
+ case 77: /* init_deferred_pred_opt ::= */
+ case 79: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
+ case 90: /* defer_subclause_opt ::= */
+ case 101: /* ifexists ::= */
+ case 112: /* distinct ::= ALL */
+ case 113: /* distinct ::= */
+ case 213: /* between_op ::= BETWEEN */
+ case 216: /* in_op ::= IN */
+#line 126 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = 0;}
-#line 1940 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 23:
- case 24:
- case 64:
- case 78:
- case 100:
- case 111:
- case 213:
- case 216:
-#line 133 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 2010 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 23: /* ifnotexists ::= IF NOT EXISTS */
+ case 24: /* temp ::= TEMP */
+ case 64: /* autoinc ::= AUTOINCR */
+ case 78: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
+ case 100: /* ifexists ::= IF EXISTS */
+ case 111: /* distinct ::= DISTINCT */
+ case 214: /* between_op ::= NOT BETWEEN */
+ case 217: /* in_op ::= NOT IN */
+#line 127 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = 1;}
-#line 1952 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2022 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 26:
-#line 139 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 26: /* create_table_args ::= LP columnlist conslist_opt RP */
+#line 133 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3EndTable(pParse,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy0,0);
}
-#line 1959 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2029 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 27:
-#line 142 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 27: /* create_table_args ::= AS select */
+#line 136 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3EndTable(pParse,0,0,yymsp[0].minor.yy219);
sqlite3SelectDelete(yymsp[0].minor.yy219);
}
-#line 1967 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2037 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 30:
-#line 154 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 30: /* column ::= columnid type carglist */
+#line 148 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy410.z = yymsp[-2].minor.yy410.z;
yygotominor.yy410.n = (pParse->sLastToken.z-yymsp[-2].minor.yy410.z) + pParse->sLastToken.n;
}
-#line 1975 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2045 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 31:
-#line 158 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 31: /* columnid ::= nm */
+#line 152 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3AddColumn(pParse,&yymsp[0].minor.yy410);
yygotominor.yy410 = yymsp[0].minor.yy410;
}
-#line 1983 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2053 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 32:
- case 33:
- case 34:
- case 35:
- case 36:
- case 252:
-#line 168 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 32: /* id ::= ID */
+ case 33: /* ids ::= ID|STRING */
+ case 34: /* nm ::= ID */
+ case 35: /* nm ::= STRING */
+ case 36: /* nm ::= JOIN_KW */
+ case 256: /* number ::= INTEGER|FLOAT */
+#line 162 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy410 = yymsp[0].minor.yy0;}
-#line 1993 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2063 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 38:
-#line 228 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 38: /* type ::= typetoken */
+#line 223 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy410);}
-#line 1998 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 39:
- case 42:
- case 119:
- case 120:
- case 131:
- case 150:
- case 240:
- case 250:
- case 251:
-#line 229 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 2068 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 39: /* typetoken ::= typename */
+ case 42: /* typename ::= ids */
+ case 119: /* as ::= AS nm */
+ case 120: /* as ::= ids */
+ case 131: /* dbnm ::= DOT nm */
+ case 241: /* idxitem ::= nm */
+ case 243: /* collate ::= COLLATE ids */
+ case 252: /* nmnum ::= plus_num */
+ case 253: /* nmnum ::= nm */
+ case 254: /* plus_num ::= plus_opt number */
+ case 255: /* minus_num ::= MINUS number */
+#line 224 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy410 = yymsp[0].minor.yy410;}
-#line 2011 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2083 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 40:
-#line 230 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 40: /* typetoken ::= typename LP signed RP */
+#line 225 "ext/pdo_sqlite/sqlite/src/parse.y"
{
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 2019 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2091 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 41:
-#line 234 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 41: /* typetoken ::= typename LP signed COMMA signed RP */
+#line 229 "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 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2099 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 43:
-#line 240 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 43: /* typename ::= typename ids */
+#line 235 "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 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 44:
-#line 242 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy46 = atoi((char*)yymsp[0].minor.yy410.z); }
-#line 2037 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 45:
-#line 243 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy46 = -atoi((char*)yymsp[0].minor.yy410.z); }
-#line 2042 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2104 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 50:
- case 52:
-#line 252 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 50: /* ccons ::= DEFAULT term */
+ case 52: /* ccons ::= DEFAULT PLUS term */
+#line 246 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy172);}
-#line 2048 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2110 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 51:
-#line 253 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 51: /* ccons ::= DEFAULT LP expr RP */
+#line 247 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy172);}
-#line 2053 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2115 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 53:
-#line 255 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 53: /* ccons ::= DEFAULT MINUS term */
+#line 249 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- Expr *p = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy172, 0, 0);
+ Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy172, 0, 0);
sqlite3AddDefaultValue(pParse,p);
}
-#line 2061 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2123 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 54:
-#line 259 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 54: /* ccons ::= DEFAULT id */
+#line 253 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- Expr *p = sqlite3Expr(TK_STRING, 0, 0, &yymsp[0].minor.yy410);
+ Expr *p = sqlite3PExpr(pParse, TK_STRING, 0, 0, &yymsp[0].minor.yy410);
sqlite3AddDefaultValue(pParse,p);
}
-#line 2069 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2131 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 56:
-#line 268 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 56: /* ccons ::= NOT NULL onconf */
+#line 262 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddNotNull(pParse, yymsp[0].minor.yy46);}
-#line 2074 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2136 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 57:
-#line 270 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 57: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
+#line 264 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy46,yymsp[0].minor.yy46,yymsp[-2].minor.yy46);}
-#line 2079 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2141 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 58:
-#line 271 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 58: /* ccons ::= UNIQUE onconf */
+#line 265 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy46,0,0,0,0);}
-#line 2084 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2146 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 59:
-#line 272 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 59: /* ccons ::= CHECK LP expr RP */
+#line 266 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy172);}
-#line 2089 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2151 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 60:
-#line 274 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 60: /* ccons ::= REFERENCES nm idxlist_opt refargs */
+#line 268 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy410,yymsp[-1].minor.yy174,yymsp[0].minor.yy46);}
-#line 2094 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2156 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 61:
-#line 275 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 61: /* ccons ::= defer_subclause */
+#line 269 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy46);}
-#line 2099 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2161 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 62:
-#line 276 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3AddCollateType(pParse, (char*)yymsp[0].minor.yy410.z, yymsp[0].minor.yy410.n);}
-#line 2104 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 62: /* ccons ::= COLLATE ids */
+#line 270 "ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3AddCollateType(pParse, &yymsp[0].minor.yy410);}
+#line 2166 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 65:
-#line 289 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 65: /* refargs ::= */
+#line 283 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = OE_Restrict * 0x010101; }
-#line 2109 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2171 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 66:
-#line 290 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 66: /* refargs ::= refargs refarg */
+#line 284 "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 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2176 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 67:
-#line 292 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 67: /* refarg ::= MATCH nm */
+#line 286 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy405.value = 0; yygotominor.yy405.mask = 0x000000; }
-#line 2119 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2181 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 68:
-#line 293 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 68: /* refarg ::= ON DELETE refact */
+#line 287 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy405.value = yymsp[0].minor.yy46; yygotominor.yy405.mask = 0x0000ff; }
-#line 2124 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2186 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 69:
-#line 294 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 69: /* refarg ::= ON UPDATE refact */
+#line 288 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy405.value = yymsp[0].minor.yy46<<8; yygotominor.yy405.mask = 0x00ff00; }
-#line 2129 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2191 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 70:
-#line 295 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 70: /* refarg ::= ON INSERT refact */
+#line 289 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy405.value = yymsp[0].minor.yy46<<16; yygotominor.yy405.mask = 0xff0000; }
-#line 2134 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2196 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 71:
-#line 297 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 71: /* refact ::= SET NULL */
+#line 291 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = OE_SetNull; }
-#line 2139 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2201 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 72:
-#line 298 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 72: /* refact ::= SET DEFAULT */
+#line 292 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = OE_SetDflt; }
-#line 2144 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2206 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 73:
-#line 299 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 73: /* refact ::= CASCADE */
+#line 293 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = OE_Cascade; }
-#line 2149 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2211 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 74:
-#line 300 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 74: /* refact ::= RESTRICT */
+#line 294 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = OE_Restrict; }
-#line 2154 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 75:
- case 76:
- case 91:
- case 93:
- case 95:
- case 96:
- case 167:
-#line 302 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 2216 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 75: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
+ case 76: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
+ case 91: /* defer_subclause_opt ::= defer_subclause */
+ case 93: /* onconf ::= ON CONFLICT resolvetype */
+ case 95: /* orconf ::= OR resolvetype */
+ case 96: /* resolvetype ::= raisetype */
+ case 166: /* insert_cmd ::= INSERT orconf */
+#line 296 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = yymsp[0].minor.yy46;}
-#line 2165 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2227 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 80:
-#line 312 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 80: /* conslist_opt ::= */
+#line 306 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy410.n = 0; yygotominor.yy410.z = 0;}
-#line 2170 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2232 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 81:
-#line 313 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 81: /* conslist_opt ::= COMMA conslist */
+#line 307 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy410 = yymsp[-1].minor.yy0;}
-#line 2175 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2237 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 86:
-#line 319 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 86: /* tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf */
+#line 313 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy174,yymsp[0].minor.yy46,yymsp[-2].minor.yy46,0);}
-#line 2180 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2242 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 87:
-#line 321 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 87: /* tcons ::= UNIQUE LP idxlist RP onconf */
+#line 315 "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 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2247 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 88:
-#line 322 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 88: /* tcons ::= CHECK LP expr RP onconf */
+#line 316 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy172);}
-#line 2190 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2252 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 89:
-#line 324 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 89: /* tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt */
+#line 318 "ext/pdo_sqlite/sqlite/src/parse.y"
{
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 2198 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2260 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 92:
- case 94:
-#line 338 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 92: /* onconf ::= */
+ case 94: /* orconf ::= */
+#line 332 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = OE_Default;}
-#line 2204 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2266 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 97:
-#line 343 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 97: /* resolvetype ::= IGNORE */
+#line 337 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = OE_Ignore;}
-#line 2209 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2271 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 98:
- case 168:
-#line 344 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 98: /* resolvetype ::= REPLACE */
+ case 167: /* insert_cmd ::= REPLACE */
+#line 338 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = OE_Replace;}
-#line 2215 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2277 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 99:
-#line 348 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 99: /* cmd ::= DROP TABLE ifexists fullname */
+#line 342 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3DropTable(pParse, yymsp[0].minor.yy373, 0, yymsp[-1].minor.yy46);
}
-#line 2222 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2284 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 102:
-#line 358 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 102: /* cmd ::= CREATE temp VIEW ifnotexists nm dbnm AS select */
+#line 352 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3CreateView(pParse, &yymsp[-6].minor.yy0, &yymsp[-3].minor.yy410, &yymsp[-2].minor.yy410, yymsp[0].minor.yy219, yymsp[-5].minor.yy46);
+ sqlite3CreateView(pParse, &yymsp[-7].minor.yy0, &yymsp[-3].minor.yy410, &yymsp[-2].minor.yy410, yymsp[0].minor.yy219, yymsp[-6].minor.yy46, yymsp[-4].minor.yy46);
}
-#line 2229 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2291 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 103:
-#line 361 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 103: /* cmd ::= DROP VIEW ifexists fullname */
+#line 355 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3DropTable(pParse, yymsp[0].minor.yy373, 1, yymsp[-1].minor.yy46);
}
-#line 2236 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2298 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 104:
-#line 368 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 104: /* cmd ::= select */
+#line 362 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3Select(pParse, yymsp[0].minor.yy219, SRT_Callback, 0, 0, 0, 0, 0);
+ SelectDest dest = {SRT_Callback, 0, 0};
+ sqlite3Select(pParse, yymsp[0].minor.yy219, &dest, 0, 0, 0, 0);
sqlite3SelectDelete(yymsp[0].minor.yy219);
}
-#line 2244 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2307 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 105:
- case 128:
-#line 378 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 105: /* select ::= oneselect */
+ case 128: /* seltablist_paren ::= select */
+#line 373 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy219 = yymsp[0].minor.yy219;}
-#line 2250 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2313 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 106:
-#line 380 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 106: /* select ::= select multiselect_op oneselect */
+#line 375 "ext/pdo_sqlite/sqlite/src/parse.y"
{
if( yymsp[0].minor.yy219 ){
yymsp[0].minor.yy219->op = yymsp[-1].minor.yy46;
yymsp[0].minor.yy219->pPrior = yymsp[-2].minor.yy219;
+ }else{
+ sqlite3SelectDelete(yymsp[-2].minor.yy219);
}
yygotominor.yy219 = yymsp[0].minor.yy219;
}
-#line 2261 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2326 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 108:
-#line 389 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 108: /* multiselect_op ::= UNION ALL */
+#line 386 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = TK_ALL;}
-#line 2266 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2331 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 110:
-#line 393 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 110: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
+#line 390 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- 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);
+ yygotominor.yy219 = sqlite3SelectNew(pParse,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 2273 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2338 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 114:
- case 237:
-#line 414 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 114: /* sclp ::= selcollist COMMA */
+ case 238: /* idxlist_opt ::= LP idxlist RP */
+#line 411 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy174 = yymsp[-1].minor.yy174;}
-#line 2279 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 115:
- case 141:
- case 151:
- case 236:
-#line 415 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 2344 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 115: /* sclp ::= */
+ case 141: /* orderby_opt ::= */
+ case 149: /* groupby_opt ::= */
+ case 231: /* exprlist ::= */
+ case 237: /* idxlist_opt ::= */
+#line 412 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy174 = 0;}
-#line 2287 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2353 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 116:
-#line 416 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 116: /* selcollist ::= sclp expr as */
+#line 413 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-2].minor.yy174,yymsp[-1].minor.yy172,yymsp[0].minor.yy410.n?&yymsp[0].minor.yy410:0);
+ yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy174,yymsp[-1].minor.yy172,yymsp[0].minor.yy410.n?&yymsp[0].minor.yy410:0);
}
-#line 2294 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2360 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 117:
-#line 419 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 117: /* selcollist ::= sclp STAR */
+#line 416 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-1].minor.yy174, sqlite3Expr(TK_ALL, 0, 0, 0), 0);
+ Expr *p = sqlite3PExpr(pParse, TK_ALL, 0, 0, 0);
+ yygotominor.yy174 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy174, p, 0);
}
-#line 2301 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2368 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 118:
-#line 422 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 118: /* selcollist ::= sclp nm DOT STAR */
+#line 420 "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.yy410);
- yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-3].minor.yy174, sqlite3Expr(TK_DOT, pLeft, pRight, 0), 0);
+ Expr *pRight = sqlite3PExpr(pParse, TK_ALL, 0, 0, 0);
+ Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy410);
+ Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
+ yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy174, pDot, 0);
}
-#line 2310 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2378 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 121:
-#line 434 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 121: /* as ::= */
+#line 433 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy410.n = 0;}
-#line 2315 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2383 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 122:
-#line 446 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy373 = sqliteMalloc(sizeof(*yygotominor.yy373));}
-#line 2320 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 122: /* from ::= */
+#line 445 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy373 = sqlite3DbMallocZero(pParse->db, sizeof(*yygotominor.yy373));}
+#line 2388 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 123:
-#line 447 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy373 = yymsp[0].minor.yy373;}
-#line 2325 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 123: /* from ::= FROM seltablist */
+#line 446 "ext/pdo_sqlite/sqlite/src/parse.y"
+{
+ yygotominor.yy373 = yymsp[0].minor.yy373;
+ sqlite3SrcListShiftJoinType(yygotominor.yy373);
+}
+#line 2396 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 124:
-#line 452 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 124: /* stl_prefix ::= seltablist joinop */
+#line 454 "ext/pdo_sqlite/sqlite/src/parse.y"
{
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 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2404 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 125:
-#line 456 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 125: /* stl_prefix ::= */
+#line 458 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy373 = 0;}
-#line 2338 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2409 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 126:
-#line 457 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 126: /* seltablist ::= stl_prefix nm dbnm as on_opt using_opt */
+#line 459 "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.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); }
- }
+ yygotominor.yy373 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy373,&yymsp[-4].minor.yy410,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,0,yymsp[-1].minor.yy172,yymsp[0].minor.yy432);
}
-#line 2354 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2416 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 127:
-#line 471 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 127: /* seltablist ::= stl_prefix LP seltablist_paren RP as on_opt using_opt */
+#line 464 "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.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); }
- }
+ yygotominor.yy373 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy373,0,0,&yymsp[-2].minor.yy410,yymsp[-4].minor.yy219,yymsp[-1].minor.yy172,yymsp[0].minor.yy432);
}
-#line 2371 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2423 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 129:
-#line 492 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 129: /* seltablist_paren ::= seltablist */
+#line 475 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy219 = sqlite3SelectNew(0,yymsp[0].minor.yy373,0,0,0,0,0,0,0);
+ sqlite3SrcListShiftJoinType(yymsp[0].minor.yy373);
+ yygotominor.yy219 = sqlite3SelectNew(pParse,0,yymsp[0].minor.yy373,0,0,0,0,0,0,0);
}
-#line 2378 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2431 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 130:
-#line 498 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 130: /* dbnm ::= */
+#line 482 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy410.z=0; yygotominor.yy410.n=0;}
-#line 2383 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2436 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 132:
-#line 503 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy373 = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410);}
-#line 2388 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 132: /* fullname ::= nm dbnm */
+#line 487 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy373 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410);}
+#line 2441 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 133:
-#line 507 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 133: /* joinop ::= COMMA|JOIN */
+#line 491 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = JT_INNER; }
-#line 2393 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2446 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 134:
-#line 508 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 134: /* joinop ::= JOIN_KW JOIN */
+#line 492 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
-#line 2398 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2451 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 135:
-#line 509 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 135: /* joinop ::= JOIN_KW nm JOIN */
+#line 493 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy410,0); }
-#line 2403 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2456 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 136:
-#line 511 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 136: /* joinop ::= JOIN_KW nm nm JOIN */
+#line 495 "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 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 137:
- case 145:
- case 154:
- case 161:
- case 175:
- case 202:
- case 225:
- case 227:
- case 231:
-#line 515 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 2461 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 137: /* on_opt ::= ON expr */
+ case 145: /* sortitem ::= expr */
+ case 152: /* having_opt ::= HAVING expr */
+ case 159: /* where_opt ::= WHERE expr */
+ case 174: /* expr ::= term */
+ case 202: /* escape ::= ESCAPE expr */
+ case 226: /* case_else ::= ELSE expr */
+ case 228: /* case_operand ::= expr */
+#line 499 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy172 = yymsp[0].minor.yy172;}
-#line 2421 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 138:
- case 153:
- case 160:
- case 203:
- case 226:
- case 228:
- case 232:
-#line 516 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 2473 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 138: /* on_opt ::= */
+ case 151: /* having_opt ::= */
+ case 158: /* where_opt ::= */
+ case 203: /* escape ::= */
+ case 227: /* case_else ::= */
+ case 229: /* case_operand ::= */
+#line 500 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy172 = 0;}
-#line 2432 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2483 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 139:
- case 172:
-#line 520 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 139: /* using_opt ::= USING LP inscollist RP */
+ case 171: /* inscollist_opt ::= LP inscollist RP */
+#line 504 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy432 = yymsp[-1].minor.yy432;}
-#line 2438 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2489 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 140:
- case 171:
-#line 521 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 140: /* using_opt ::= */
+ case 170: /* inscollist_opt ::= */
+#line 505 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy432 = 0;}
-#line 2444 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2495 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 142:
- case 152:
-#line 532 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 142: /* orderby_opt ::= ORDER BY sortlist */
+ case 150: /* groupby_opt ::= GROUP BY nexprlist */
+ case 230: /* exprlist ::= nexprlist */
+#line 516 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy174 = yymsp[0].minor.yy174;}
-#line 2450 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2502 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 143:
-#line 533 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 143: /* sortlist ::= sortlist COMMA sortitem sortorder */
+#line 517 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-4].minor.yy174,yymsp[-2].minor.yy172,yymsp[-1].minor.yy410.n>0?&yymsp[-1].minor.yy410:0);
+ yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy174,yymsp[-1].minor.yy172,0);
if( yygotominor.yy174 ) yygotominor.yy174->a[yygotominor.yy174->nExpr-1].sortOrder = yymsp[0].minor.yy46;
}
-#line 2458 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2510 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 144:
-#line 537 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 144: /* sortlist ::= sortitem sortorder */
+#line 521 "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);
+ yygotominor.yy174 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy172,0);
if( yygotominor.yy174 && yygotominor.yy174->a ) yygotominor.yy174->a[0].sortOrder = yymsp[0].minor.yy46;
}
-#line 2466 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2518 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 146:
- case 148:
-#line 546 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 146: /* sortorder ::= ASC */
+ case 148: /* sortorder ::= */
+#line 529 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = SQLITE_SO_ASC;}
-#line 2472 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2524 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 147:
-#line 547 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 147: /* sortorder ::= DESC */
+#line 530 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = SQLITE_SO_DESC;}
-#line 2477 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2529 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 149:
-#line 549 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy410.z = 0; yygotominor.yy410.n = 0;}
-#line 2482 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 155:
-#line 567 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 153: /* limit_opt ::= */
+#line 556 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy234.pLimit = 0; yygotominor.yy234.pOffset = 0;}
-#line 2487 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2534 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 156:
-#line 568 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 154: /* limit_opt ::= LIMIT expr */
+#line 557 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy234.pLimit = yymsp[0].minor.yy172; yygotominor.yy234.pOffset = 0;}
-#line 2492 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2539 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 157:
-#line 570 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 155: /* limit_opt ::= LIMIT expr OFFSET expr */
+#line 559 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy234.pLimit = yymsp[-2].minor.yy172; yygotominor.yy234.pOffset = yymsp[0].minor.yy172;}
-#line 2497 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2544 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 158:
-#line 572 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 156: /* limit_opt ::= LIMIT expr COMMA expr */
+#line 561 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy234.pOffset = yymsp[-2].minor.yy172; yygotominor.yy234.pLimit = yymsp[0].minor.yy172;}
-#line 2502 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2549 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 159:
-#line 576 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 157: /* cmd ::= DELETE FROM fullname where_opt */
+#line 565 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3DeleteFrom(pParse,yymsp[-1].minor.yy373,yymsp[0].minor.yy172);}
-#line 2507 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2554 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 162:
-#line 587 "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 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 160: /* cmd ::= UPDATE orconf fullname SET setlist where_opt */
+#line 575 "ext/pdo_sqlite/sqlite/src/parse.y"
+{
+ sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy174,SQLITE_MAX_COLUMN,"set list");
+ sqlite3Update(pParse,yymsp[-3].minor.yy373,yymsp[-1].minor.yy174,yymsp[0].minor.yy172,yymsp[-4].minor.yy46);
+}
+#line 2562 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 163:
-#line 593 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-4].minor.yy174,yymsp[0].minor.yy172,&yymsp[-2].minor.yy410);}
-#line 2517 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 161: /* setlist ::= setlist COMMA nm EQ expr */
+#line 584 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy174,yymsp[0].minor.yy172,&yymsp[-2].minor.yy410);}
+#line 2567 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 164:
-#line 594 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy174 = sqlite3ExprListAppend(0,yymsp[0].minor.yy172,&yymsp[-2].minor.yy410);}
-#line 2522 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 162: /* setlist ::= nm EQ expr */
+#line 586 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy174 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy172,&yymsp[-2].minor.yy410);}
+#line 2572 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 165:
-#line 600 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 163: /* cmd ::= insert_cmd INTO fullname inscollist_opt VALUES LP itemlist RP */
+#line 592 "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 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2577 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 166:
-#line 602 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 164: /* cmd ::= insert_cmd INTO fullname inscollist_opt select */
+#line 594 "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 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 169:
- case 229:
-#line 612 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-2].minor.yy174,yymsp[0].minor.yy172,0);}
-#line 2538 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 170:
- case 230:
-#line 613 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy174 = sqlite3ExprListAppend(0,yymsp[0].minor.yy172,0);}
-#line 2544 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 173:
-#line 622 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy432 = sqlite3IdListAppend(yymsp[-2].minor.yy432,&yymsp[0].minor.yy410);}
-#line 2549 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2582 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 165: /* cmd ::= insert_cmd INTO fullname inscollist_opt DEFAULT VALUES */
+#line 596 "ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Insert(pParse, yymsp[-3].minor.yy373, 0, 0, yymsp[-2].minor.yy432, yymsp[-5].minor.yy46);}
+#line 2587 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 168: /* itemlist ::= itemlist COMMA expr */
+ case 232: /* nexprlist ::= nexprlist COMMA expr */
+#line 607 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy174,yymsp[0].minor.yy172,0);}
+#line 2593 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 169: /* itemlist ::= expr */
+ case 233: /* nexprlist ::= expr */
+#line 609 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy174 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy172,0);}
+#line 2599 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 172: /* inscollist ::= inscollist COMMA nm */
+#line 619 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy432 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy432,&yymsp[0].minor.yy410);}
+#line 2604 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 173: /* inscollist ::= nm */
+#line 621 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy432 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy410);}
+#line 2609 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 175: /* expr ::= LP expr RP */
+#line 632 "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 2614 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 174:
-#line 623 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy432 = sqlite3IdListAppend(0,&yymsp[0].minor.yy410);}
-#line 2554 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 176: /* term ::= NULL */
+ case 181: /* term ::= INTEGER|FLOAT|BLOB */
+ case 182: /* term ::= STRING */
+#line 633 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy172 = sqlite3PExpr(pParse, yymsp[0].major, 0, 0, &yymsp[0].minor.yy0);}
+#line 2621 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 176:
+ case 177: /* expr ::= ID */
+ case 178: /* expr ::= JOIN_KW */
#line 634 "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 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 177:
- case 182:
- case 183:
-#line 635 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy172 = sqlite3Expr(yymsp[0].major, 0, 0, &yymsp[0].minor.yy0);}
-#line 2566 "ext/pdo_sqlite/sqlite/src/parse.c"
+{yygotominor.yy172 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0);}
+#line 2627 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 178:
- case 179:
+ case 179: /* expr ::= nm DOT nm */
#line 636 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy172 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy0);}
-#line 2572 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 180:
-#line 638 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- 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);
+ Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy410);
+ Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy410);
+ yygotominor.yy172 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
}
-#line 2581 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2636 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 181:
-#line 643 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 180: /* expr ::= nm DOT nm DOT nm */
+#line 641 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- 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.yy172 = sqlite3Expr(TK_DOT, temp1, temp4, 0);
+ Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-4].minor.yy410);
+ Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy410);
+ Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy410);
+ Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0);
+ yygotominor.yy172 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
}
-#line 2592 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2647 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 184:
-#line 652 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 183: /* expr ::= REGISTER */
+#line 650 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy172 = sqlite3RegisterExpr(pParse, &yymsp[0].minor.yy0);}
-#line 2597 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2652 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 185:
-#line 653 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 184: /* expr ::= VARIABLE */
+#line 651 "ext/pdo_sqlite/sqlite/src/parse.y"
{
Token *pToken = &yymsp[0].minor.yy0;
- Expr *pExpr = yygotominor.yy172 = sqlite3Expr(TK_VARIABLE, 0, 0, pToken);
+ Expr *pExpr = yygotominor.yy172 = sqlite3PExpr(pParse, TK_VARIABLE, 0, 0, pToken);
sqlite3ExprAssignVarNumber(pParse, pExpr);
}
-#line 2606 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2661 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 186:
-#line 659 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 185: /* expr ::= expr COLLATE ids */
+#line 656 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy172 = sqlite3Expr(TK_CAST, yymsp[-3].minor.yy172, 0, &yymsp[-1].minor.yy410);
+ yygotominor.yy172 = sqlite3ExprSetColl(pParse, yymsp[-2].minor.yy172, &yymsp[0].minor.yy410);
+}
+#line 2668 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 186: /* expr ::= CAST LP expr AS typetoken RP */
+#line 660 "ext/pdo_sqlite/sqlite/src/parse.y"
+{
+ yygotominor.yy172 = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy172, 0, &yymsp[-1].minor.yy410);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);
}
-#line 2614 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2676 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 187:
-#line 664 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 187: /* expr ::= ID LP distinct exprlist RP */
+#line 665 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy172 = sqlite3ExprFunction(yymsp[-1].minor.yy174, &yymsp[-4].minor.yy0);
+ if( yymsp[-1].minor.yy174 && yymsp[-1].minor.yy174->nExpr>SQLITE_MAX_FUNCTION_ARG ){
+ sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0);
+ }
+ yygotominor.yy172 = sqlite3ExprFunction(pParse, 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 2625 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2690 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 188:
-#line 671 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 188: /* expr ::= ID LP STAR RP */
+#line 675 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy172 = sqlite3ExprFunction(0, &yymsp[-3].minor.yy0);
+ yygotominor.yy172 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
}
-#line 2633 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2698 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 189:
-#line 675 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 189: /* term ::= CTIME_KW */
+#line 679 "ext/pdo_sqlite/sqlite/src/parse.y"
{
/* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are
** treated as functions that return constants */
- yygotominor.yy172 = sqlite3ExprFunction(0,&yymsp[0].minor.yy0);
- if( yygotominor.yy172 ) yygotominor.yy172->op = TK_CONST_FUNC;
-}
-#line 2643 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 190:
- case 191:
- case 192:
- case 193:
- case 194:
- case 195:
- case 196:
- case 197:
-#line 681 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy172 = sqlite3Expr(yymsp[-1].major, yymsp[-2].minor.yy172, yymsp[0].minor.yy172, 0);}
-#line 2655 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 198:
- case 200:
-#line 691 "ext/pdo_sqlite/sqlite/src/parse.y"
+ yygotominor.yy172 = sqlite3ExprFunction(pParse, 0,&yymsp[0].minor.yy0);
+ if( yygotominor.yy172 ){
+ yygotominor.yy172->op = TK_CONST_FUNC;
+ yygotominor.yy172->span = yymsp[0].minor.yy0;
+ }
+}
+#line 2711 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 190: /* expr ::= expr AND expr */
+ case 191: /* expr ::= expr OR expr */
+ case 192: /* expr ::= expr LT|GT|GE|LE expr */
+ case 193: /* expr ::= expr EQ|NE expr */
+ case 194: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
+ case 195: /* expr ::= expr PLUS|MINUS expr */
+ case 196: /* expr ::= expr STAR|SLASH|REM expr */
+ case 197: /* expr ::= expr CONCAT expr */
+#line 688 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy172 = sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy172,yymsp[0].minor.yy172,0);}
+#line 2723 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 198: /* likeop ::= LIKE_KW */
+ case 200: /* likeop ::= MATCH */
+#line 700 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy72.eOperator = yymsp[0].minor.yy0; yygotominor.yy72.not = 0;}
-#line 2661 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2729 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 199:
- case 201:
-#line 692 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 199: /* likeop ::= NOT LIKE_KW */
+ case 201: /* likeop ::= NOT MATCH */
+#line 701 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy72.eOperator = yymsp[0].minor.yy0; yygotominor.yy72.not = 1;}
-#line 2667 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2735 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 204:
-#line 699 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 204: /* expr ::= expr likeop expr escape */
+#line 708 "ext/pdo_sqlite/sqlite/src/parse.y"
{
ExprList *pList;
- pList = sqlite3ExprListAppend(0, yymsp[-1].minor.yy172, 0);
- pList = sqlite3ExprListAppend(pList, yymsp[-3].minor.yy172, 0);
+ pList = sqlite3ExprListAppend(pParse,0, yymsp[-1].minor.yy172, 0);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[-3].minor.yy172, 0);
if( yymsp[0].minor.yy172 ){
- pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy172, 0);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy172, 0);
}
- yygotominor.yy172 = sqlite3ExprFunction(pList, &yymsp[-2].minor.yy72.eOperator);
- if( yymsp[-2].minor.yy72.not ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0);
+ yygotominor.yy172 = sqlite3ExprFunction(pParse, pList, &yymsp[-2].minor.yy72.eOperator);
+ if( yymsp[-2].minor.yy72.not ) yygotominor.yy172 = sqlite3PExpr(pParse, 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 2683 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2751 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 205:
-#line 712 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 205: /* expr ::= expr ISNULL|NOTNULL */
+#line 721 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy172 = sqlite3Expr(yymsp[0].major, yymsp[-1].minor.yy172, 0, 0);
+ yygotominor.yy172 = sqlite3PExpr(pParse, yymsp[0].major, yymsp[-1].minor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2691 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2759 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 206:
-#line 716 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 206: /* expr ::= expr IS NULL */
+#line 725 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy172 = sqlite3Expr(TK_ISNULL, yymsp[-2].minor.yy172, 0, 0);
+ yygotominor.yy172 = sqlite3PExpr(pParse, TK_ISNULL, yymsp[-2].minor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2699 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2767 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 207:
-#line 720 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 207: /* expr ::= expr NOT NULL */
+#line 729 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy172 = sqlite3Expr(TK_NOTNULL, yymsp[-2].minor.yy172, 0, 0);
+ yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOTNULL, yymsp[-2].minor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2707 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2775 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 208:
-#line 724 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 208: /* expr ::= expr IS NOT NULL */
+#line 733 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy172 = sqlite3Expr(TK_NOTNULL, yymsp[-3].minor.yy172, 0, 0);
+ yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOTNULL, yymsp[-3].minor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-3].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2715 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2783 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 209:
-#line 728 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 209: /* expr ::= NOT expr */
+ case 210: /* expr ::= BITNOT expr */
+#line 737 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy172 = sqlite3Expr(yymsp[-1].major, yymsp[0].minor.yy172, 0, 0);
+ yygotominor.yy172 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span);
}
-#line 2723 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2792 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 210:
-#line 732 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 211: /* expr ::= MINUS expr */
+#line 745 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy172 = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy172, 0, 0);
+ yygotominor.yy172 = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span);
}
-#line 2731 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2800 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 211:
-#line 736 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 212: /* expr ::= PLUS expr */
+#line 749 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy172 = sqlite3Expr(TK_UPLUS, yymsp[0].minor.yy172, 0, 0);
+ yygotominor.yy172 = sqlite3PExpr(pParse, TK_UPLUS, yymsp[0].minor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span);
}
-#line 2739 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2808 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 214:
-#line 743 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 215: /* expr ::= expr between_op expr AND expr */
+#line 756 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- 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);
+ ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy172, 0);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy172, 0);
+ yygotominor.yy172 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy172, 0, 0);
if( yygotominor.yy172 ){
yygotominor.yy172->pList = pList;
}else{
sqlite3ExprListDelete(pList);
}
- if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0);
+ if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy172->span,&yymsp[0].minor.yy172->span);
}
-#line 2755 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2824 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 217:
-#line 759 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 218: /* expr ::= expr in_op LP exprlist RP */
+#line 772 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy172 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy172, 0, 0);
+ yygotominor.yy172 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy172, 0, 0);
if( yygotominor.yy172 ){
yygotominor.yy172->pList = yymsp[-1].minor.yy174;
+ sqlite3ExprSetHeight(yygotominor.yy172);
}else{
sqlite3ExprListDelete(yymsp[-1].minor.yy174);
}
- if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0);
+ if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2769 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2839 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 218:
-#line 769 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 219: /* expr ::= LP select RP */
+#line 783 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy172 = sqlite3Expr(TK_SELECT, 0, 0, 0);
+ yygotominor.yy172 = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
if( yygotominor.yy172 ){
yygotominor.yy172->pSelect = yymsp[-1].minor.yy219;
+ sqlite3ExprSetHeight(yygotominor.yy172);
}else{
sqlite3SelectDelete(yymsp[-1].minor.yy219);
}
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
}
-#line 2782 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2853 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 219:
-#line 778 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 220: /* expr ::= expr in_op LP select RP */
+#line 793 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy172 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy172, 0, 0);
+ yygotominor.yy172 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy172, 0, 0);
if( yygotominor.yy172 ){
yygotominor.yy172->pSelect = yymsp[-1].minor.yy219;
+ sqlite3ExprSetHeight(yygotominor.yy172);
}else{
sqlite3SelectDelete(yymsp[-1].minor.yy219);
}
- if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0);
+ if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2796 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2868 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 220:
-#line 788 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 221: /* expr ::= expr in_op nm dbnm */
+#line 804 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- SrcList *pSrc = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410);
- yygotominor.yy172 = sqlite3Expr(TK_IN, yymsp[-3].minor.yy172, 0, 0);
+ SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410);
+ yygotominor.yy172 = sqlite3PExpr(pParse, TK_IN, yymsp[-3].minor.yy172, 0, 0);
if( yygotominor.yy172 ){
- yygotominor.yy172->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0);
+ yygotominor.yy172->pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
+ sqlite3ExprSetHeight(yygotominor.yy172);
}else{
sqlite3SrcListDelete(pSrc);
}
- if( yymsp[-2].minor.yy46 ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0);
+ if( yymsp[-2].minor.yy46 ) yygotominor.yy172 = sqlite3PExpr(pParse, 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 2811 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2884 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 221:
-#line 799 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 222: /* expr ::= EXISTS LP select RP */
+#line 816 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- Expr *p = yygotominor.yy172 = sqlite3Expr(TK_EXISTS, 0, 0, 0);
+ Expr *p = yygotominor.yy172 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
if( p ){
p->pSelect = yymsp[-1].minor.yy219;
sqlite3ExprSpan(p,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
+ sqlite3ExprSetHeight(yygotominor.yy172);
}else{
sqlite3SelectDelete(yymsp[-1].minor.yy219);
}
}
-#line 2824 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2898 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 222:
-#line 811 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 223: /* expr ::= CASE case_operand case_exprlist case_else END */
+#line 829 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy172 = sqlite3Expr(TK_CASE, yymsp[-3].minor.yy172, yymsp[-1].minor.yy172, 0);
+ yygotominor.yy172 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy172, yymsp[-1].minor.yy172, 0);
if( yygotominor.yy172 ){
yygotominor.yy172->pList = yymsp[-2].minor.yy174;
+ sqlite3ExprSetHeight(yygotominor.yy172);
}else{
sqlite3ExprListDelete(yymsp[-2].minor.yy174);
}
sqlite3ExprSpan(yygotominor.yy172, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0);
}
-#line 2837 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2912 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 223:
-#line 822 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 224: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
+#line 841 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-4].minor.yy174, yymsp[-2].minor.yy172, 0);
- yygotominor.yy174 = sqlite3ExprListAppend(yygotominor.yy174, yymsp[0].minor.yy172, 0);
+ yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy174, yymsp[-2].minor.yy172, 0);
+ yygotominor.yy174 = sqlite3ExprListAppend(pParse,yygotominor.yy174, yymsp[0].minor.yy172, 0);
}
-#line 2845 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2920 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 224:
-#line 826 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 225: /* case_exprlist ::= WHEN expr THEN expr */
+#line 845 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy174 = sqlite3ExprListAppend(0, yymsp[-2].minor.yy172, 0);
- yygotominor.yy174 = sqlite3ExprListAppend(yygotominor.yy174, yymsp[0].minor.yy172, 0);
+ yygotominor.yy174 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy172, 0);
+ yygotominor.yy174 = sqlite3ExprListAppend(pParse,yygotominor.yy174, yymsp[0].minor.yy172, 0);
}
-#line 2853 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2928 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 233:
-#line 853 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 234: /* cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP */
+#line 874 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- 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,
+ sqlite3CreateIndex(pParse, &yymsp[-6].minor.yy410, &yymsp[-5].minor.yy410,
+ sqlite3SrcListAppend(pParse->db,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 2861 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2937 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 234:
- case 279:
-#line 859 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 235: /* uniqueflag ::= UNIQUE */
+ case 282: /* raisetype ::= ABORT */
+#line 881 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = OE_Abort;}
-#line 2867 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2943 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 235:
-#line 860 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 236: /* uniqueflag ::= */
+#line 882 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = OE_None;}
-#line 2872 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2948 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 238:
-#line 870 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 239: /* idxlist ::= idxlist COMMA idxitem collate sortorder */
+#line 892 "ext/pdo_sqlite/sqlite/src/parse.y"
{
Expr *p = 0;
if( yymsp[-1].minor.yy410.n>0 ){
- p = sqlite3Expr(TK_COLUMN, 0, 0, 0);
- if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)yymsp[-1].minor.yy410.z, yymsp[-1].minor.yy410.n);
+ p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
+ sqlite3ExprSetColl(pParse, p, &yymsp[-1].minor.yy410);
}
- yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-4].minor.yy174, p, &yymsp[-2].minor.yy410);
+ yygotominor.yy174 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy174, p, &yymsp[-2].minor.yy410);
+ sqlite3ExprListCheckLength(pParse, yygotominor.yy174, SQLITE_MAX_COLUMN, "index");
if( yygotominor.yy174 ) yygotominor.yy174->a[yygotominor.yy174->nExpr-1].sortOrder = yymsp[0].minor.yy46;
}
-#line 2885 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2962 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 239:
-#line 879 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 240: /* idxlist ::= idxitem collate sortorder */
+#line 902 "ext/pdo_sqlite/sqlite/src/parse.y"
{
Expr *p = 0;
if( yymsp[-1].minor.yy410.n>0 ){
- p = sqlite3Expr(TK_COLUMN, 0, 0, 0);
- if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)yymsp[-1].minor.yy410.z, yymsp[-1].minor.yy410.n);
+ p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
+ sqlite3ExprSetColl(pParse, p, &yymsp[-1].minor.yy410);
}
- yygotominor.yy174 = sqlite3ExprListAppend(0, p, &yymsp[-2].minor.yy410);
+ yygotominor.yy174 = sqlite3ExprListAppend(pParse,0, p, &yymsp[-2].minor.yy410);
+ sqlite3ExprListCheckLength(pParse, yygotominor.yy174, SQLITE_MAX_COLUMN, "index");
if( yygotominor.yy174 ) yygotominor.yy174->a[yygotominor.yy174->nExpr-1].sortOrder = yymsp[0].minor.yy46;
}
-#line 2898 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2976 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 242: /* collate ::= */
+#line 915 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy410.z = 0; yygotominor.yy410.n = 0;}
+#line 2981 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 241:
-#line 893 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 244: /* cmd ::= DROP INDEX ifexists fullname */
+#line 921 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3DropIndex(pParse, yymsp[0].minor.yy373, yymsp[-1].minor.yy46);}
-#line 2903 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2986 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 242:
- case 243:
-#line 897 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 245: /* cmd ::= VACUUM */
+ case 246: /* cmd ::= VACUUM nm */
+#line 927 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3Vacuum(pParse);}
-#line 2909 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2992 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 244:
- case 246:
-#line 903 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 247: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
+#line 935 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,&yymsp[0].minor.yy410,0);}
-#line 2915 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2997 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 245:
-#line 904 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 248: /* cmd ::= PRAGMA nm dbnm EQ ON */
+#line 936 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,&yymsp[0].minor.yy0,0);}
-#line 2920 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3002 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 247:
-#line 906 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 249: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
+#line 937 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3Pragma(pParse,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,&yymsp[0].minor.yy410,1);
}
-#line 2927 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3009 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 248:
-#line 909 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 250: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
+#line 940 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy410,&yymsp[-3].minor.yy410,&yymsp[-1].minor.yy410,0);}
-#line 2932 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3014 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 249:
-#line 910 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 251: /* cmd ::= PRAGMA nm dbnm */
+#line 941 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3Pragma(pParse,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410,0,0);}
-#line 2937 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3019 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 255:
-#line 922 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 259: /* cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END */
+#line 955 "ext/pdo_sqlite/sqlite/src/parse.y"
{
Token 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 2947 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3029 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 256:
-#line 931 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 260: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+#line 964 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- 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);
+ 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[0].minor.yy172, yymsp[-10].minor.yy46, yymsp[-8].minor.yy46);
yygotominor.yy410 = (yymsp[-6].minor.yy410.n==0?yymsp[-7].minor.yy410:yymsp[-6].minor.yy410);
}
-#line 2955 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3037 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 257:
- case 260:
-#line 937 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 261: /* trigger_time ::= BEFORE */
+ case 264: /* trigger_time ::= */
+#line 970 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = TK_BEFORE; }
-#line 2961 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3043 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 258:
-#line 938 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 262: /* trigger_time ::= AFTER */
+#line 971 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = TK_AFTER; }
-#line 2966 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3048 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 259:
-#line 939 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 263: /* trigger_time ::= INSTEAD OF */
+#line 972 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = TK_INSTEAD;}
-#line 2971 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3053 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 261:
- case 262:
-#line 944 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 265: /* trigger_event ::= DELETE|INSERT */
+ case 266: /* trigger_event ::= UPDATE */
+#line 977 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy370.a = yymsp[0].major; yygotominor.yy370.b = 0;}
-#line 2977 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3059 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 263:
-#line 946 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 267: /* trigger_event ::= UPDATE OF inscollist */
+#line 979 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy370.a = TK_UPDATE; yygotominor.yy370.b = yymsp[0].minor.yy432;}
-#line 2982 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3064 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 264:
- case 265:
-#line 949 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy46 = TK_ROW; }
-#line 2988 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 266:
-#line 951 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy46 = TK_STATEMENT; }
-#line 2993 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 267:
-#line 955 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 270: /* when_clause ::= */
+ case 287: /* key_opt ::= */
+#line 986 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy172 = 0; }
-#line 2998 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3070 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 268:
-#line 956 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 271: /* when_clause ::= WHEN expr */
+ case 288: /* key_opt ::= KEY expr */
+#line 987 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy172 = yymsp[0].minor.yy172; }
-#line 3003 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3076 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 269:
-#line 960 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 272: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+#line 991 "ext/pdo_sqlite/sqlite/src/parse.y"
{
if( yymsp[-2].minor.yy243 ){
yymsp[-2].minor.yy243->pLast->pNext = yymsp[-1].minor.yy243;
@@ -3010,171 +3083,161 @@ static void yy_reduce(
yymsp[-2].minor.yy243->pLast = yymsp[-1].minor.yy243;
yygotominor.yy243 = yymsp[-2].minor.yy243;
}
-#line 3016 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3089 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 270:
-#line 969 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 273: /* trigger_cmd_list ::= */
+#line 1000 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy243 = 0; }
-#line 3021 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3094 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 271:
-#line 975 "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 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 274: /* trigger_cmd ::= UPDATE orconf nm SET setlist where_opt */
+#line 1006 "ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy243 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-3].minor.yy410, yymsp[-1].minor.yy174, yymsp[0].minor.yy172, yymsp[-4].minor.yy46); }
+#line 3099 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 272:
-#line 980 "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 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 275: /* trigger_cmd ::= insert_cmd INTO nm inscollist_opt VALUES LP itemlist RP */
+#line 1011 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy243 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-5].minor.yy410, yymsp[-4].minor.yy432, yymsp[-1].minor.yy174, 0, yymsp[-7].minor.yy46);}
+#line 3104 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 273:
-#line 983 "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 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 276: /* trigger_cmd ::= insert_cmd INTO nm inscollist_opt select */
+#line 1014 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy243 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy410, yymsp[-1].minor.yy432, 0, yymsp[0].minor.yy219, yymsp[-4].minor.yy46);}
+#line 3109 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 274:
-#line 987 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy243 = sqlite3TriggerDeleteStep(&yymsp[-1].minor.yy410, yymsp[0].minor.yy172);}
-#line 3041 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 277: /* trigger_cmd ::= DELETE FROM nm where_opt */
+#line 1018 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy243 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-1].minor.yy410, yymsp[0].minor.yy172);}
+#line 3114 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 275:
-#line 990 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy243 = sqlite3TriggerSelectStep(yymsp[0].minor.yy219); }
-#line 3046 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 278: /* trigger_cmd ::= select */
+#line 1021 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy243 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy219); }
+#line 3119 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 276:
-#line 993 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 279: /* expr ::= RAISE LP IGNORE RP */
+#line 1024 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy172 = sqlite3Expr(TK_RAISE, 0, 0, 0);
+ yygotominor.yy172 = sqlite3PExpr(pParse, 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 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3130 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 277:
-#line 1000 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 280: /* expr ::= RAISE LP raisetype COMMA nm RP */
+#line 1031 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy172 = sqlite3Expr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy410);
+ yygotominor.yy172 = sqlite3PExpr(pParse, 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 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3141 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 278:
-#line 1010 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 281: /* raisetype ::= ROLLBACK */
+#line 1041 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = OE_Rollback;}
-#line 3073 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3146 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 280:
-#line 1012 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 283: /* raisetype ::= FAIL */
+#line 1043 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = OE_Fail;}
-#line 3078 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3151 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 281:
-#line 1017 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 284: /* cmd ::= DROP TRIGGER ifexists fullname */
+#line 1048 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3DropTrigger(pParse,yymsp[0].minor.yy373);
+ sqlite3DropTrigger(pParse,yymsp[0].minor.yy373,yymsp[-1].minor.yy46);
}
-#line 3085 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3158 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 282:
-#line 1023 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 285: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+#line 1055 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3Attach(pParse, yymsp[-3].minor.yy172, yymsp[-1].minor.yy172, yymsp[0].minor.yy386);
+ sqlite3Attach(pParse, yymsp[-3].minor.yy172, yymsp[-1].minor.yy172, yymsp[0].minor.yy172);
}
-#line 3092 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 283:
-#line 1028 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy386 = 0; }
-#line 3097 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3165 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 284:
-#line 1029 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy386 = yymsp[0].minor.yy172; }
-#line 3102 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 287:
-#line 1035 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 286: /* cmd ::= DETACH database_kw_opt expr */
+#line 1058 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3Detach(pParse, yymsp[0].minor.yy172);
}
-#line 3109 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3172 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 288:
-#line 1041 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 291: /* cmd ::= REINDEX */
+#line 1073 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3Reindex(pParse, 0, 0);}
-#line 3114 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3177 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 289:
-#line 1042 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 292: /* cmd ::= REINDEX nm dbnm */
+#line 1074 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3Reindex(pParse, &yymsp[-1].minor.yy410, &yymsp[0].minor.yy410);}
-#line 3119 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3182 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 290:
-#line 1047 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 293: /* cmd ::= ANALYZE */
+#line 1079 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3Analyze(pParse, 0, 0);}
-#line 3124 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3187 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 291:
-#line 1048 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 294: /* cmd ::= ANALYZE nm dbnm */
+#line 1080 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3Analyze(pParse, &yymsp[-1].minor.yy410, &yymsp[0].minor.yy410);}
-#line 3129 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3192 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 292:
-#line 1053 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 295: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
+#line 1085 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy373,&yymsp[0].minor.yy410);
}
-#line 3136 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3199 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 293:
-#line 1056 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 296: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column */
+#line 1088 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy410);
}
-#line 3143 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3206 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 294:
-#line 1059 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 297: /* add_column_fullname ::= fullname */
+#line 1091 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy373);
}
-#line 3150 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3213 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 297:
-#line 1068 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 300: /* cmd ::= create_vtab */
+#line 1100 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3VtabFinishParse(pParse,0);}
-#line 3155 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3218 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 298:
-#line 1069 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 301: /* cmd ::= create_vtab LP vtabarglist RP */
+#line 1101 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
-#line 3160 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3223 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 299:
-#line 1070 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 302: /* create_vtab ::= CREATE VIRTUAL TABLE nm dbnm USING nm */
+#line 1102 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy410, &yymsp[-2].minor.yy410, &yymsp[0].minor.yy410);
}
-#line 3167 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3230 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 302:
-#line 1075 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 305: /* vtabarg ::= */
+#line 1107 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3VtabArgInit(pParse);}
-#line 3172 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3235 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 304:
- case 305:
- case 306:
- case 308:
-#line 1077 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 307: /* vtabargtoken ::= ANY */
+ case 308: /* vtabargtoken ::= lp anylist RP */
+ case 309: /* lp ::= LP */
+ case 311: /* anylist ::= anylist ANY */
+#line 1109 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
-#line 3180 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3243 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
};
yygoto = yyRuleInfo[yyruleno].lhs;
@@ -3198,7 +3261,8 @@ static void yy_reduce(
{
yy_shift(yypParser,yyact,yygoto,&yygotominor);
}
- }else if( yyact == YYNSTATE + YYNRULE + 1 ){
+ }else{
+ assert( yyact == YYNSTATE + YYNRULE + 1 );
yy_accept(yypParser);
}
}
@@ -3233,15 +3297,10 @@ static void yy_syntax_error(
#define TOKEN (yyminor.yy0)
#line 34 "ext/pdo_sqlite/sqlite/src/parse.y"
- if( !pParse->parseError ){
- if( TOKEN.z[0] ){
- sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
- }else{
- sqlite3ErrorMsg(pParse, "incomplete SQL statement");
- }
- pParse->parseError = 1;
- }
-#line 3248 "ext/pdo_sqlite/sqlite/src/parse.c"
+ assert( TOKEN.z[0] ); /* The tokenizer always gives us a token */
+ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
+ pParse->parseError = 1;
+#line 3307 "ext/pdo_sqlite/sqlite/src/parse.c"
sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
@@ -3291,13 +3350,21 @@ void sqlite3Parser(
YYMINORTYPE yyminorunion;
int yyact; /* The parser action. */
int yyendofinput; /* True if we are at the end of input */
+#ifdef YYERRORSYMBOL
int yyerrorhit = 0; /* True if yymajor has invoked an error */
+#endif
yyParser *yypParser; /* The parser */
/* (re)initialize the parser, if necessary */
yypParser = (yyParser*)yyp;
if( yypParser->yyidx<0 ){
- /* if( yymajor==0 ) return; // not sure why this was here... */
+#if YYSTACKDEPTH<=0
+ if( yypParser->yystksz <=0 ){
+ memset(&yyminorunion, 0, sizeof(yyminorunion));
+ yyStackOverflow(yypParser, &yyminorunion);
+ return;
+ }
+#endif
yypParser->yyidx = 0;
yypParser->yyerrcnt = -1;
yypParser->yystack[0].stateno = 0;
@@ -3316,17 +3383,17 @@ void sqlite3Parser(
do{
yyact = yy_find_shift_action(yypParser,yymajor);
if( yyact<YYNSTATE ){
+ assert( !yyendofinput ); /* Impossible to shift the $ token */
yy_shift(yypParser,yyact,yymajor,&yyminorunion);
yypParser->yyerrcnt--;
- if( yyendofinput && yypParser->yyidx>=0 ){
- yymajor = 0;
- }else{
- yymajor = YYNOCODE;
- }
+ yymajor = YYNOCODE;
}else if( yyact < YYNSTATE + YYNRULE ){
yy_reduce(yypParser,yyact-YYNSTATE);
- }else if( yyact == YY_ERROR_ACTION ){
+ }else{
+ assert( yyact == YY_ERROR_ACTION );
+#ifdef YYERRORSYMBOL
int yymx;
+#endif
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
@@ -3407,9 +3474,6 @@ void sqlite3Parser(
}
yymajor = YYNOCODE;
#endif
- }else{
- yy_accept(yypParser);
- yymajor = YYNOCODE;
}
}while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
return;
diff --git a/ext/pdo_sqlite/sqlite/src/parse.h b/ext/pdo_sqlite/sqlite/src/parse.h
index 65c9a5ce90..ed848ec5c4 100644
--- a/ext/pdo_sqlite/sqlite/src/parse.h
+++ b/ext/pdo_sqlite/sqlite/src/parse.h
@@ -49,39 +49,39 @@
#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_TRIGGER 52
+#define TK_VACUUM 53
+#define TK_VIEW 54
+#define TK_VIRTUAL 55
+#define TK_REINDEX 56
+#define TK_RENAME 57
+#define TK_CTIME_KW 58
+#define TK_ANY 59
+#define TK_OR 60
+#define TK_AND 61
+#define TK_IS 62
+#define TK_BETWEEN 63
+#define TK_IN 64
+#define TK_ISNULL 65
+#define TK_NOTNULL 66
+#define TK_NE 67
+#define TK_EQ 68
+#define TK_GT 69
+#define TK_LE 70
+#define TK_LT 71
+#define TK_GE 72
+#define TK_ESCAPE 73
+#define TK_BITAND 74
+#define TK_BITOR 75
+#define TK_LSHIFT 76
+#define TK_RSHIFT 77
+#define TK_PLUS 78
+#define TK_MINUS 79
+#define TK_STAR 80
+#define TK_SLASH 81
+#define TK_REM 82
+#define TK_CONCAT 83
+#define TK_COLLATE 84
#define TK_UMINUS 85
#define TK_UPLUS 86
#define TK_BITNOT 87
@@ -94,60 +94,59 @@
#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
+#define TK_AUTOINCR 97
+#define TK_ON 98
+#define TK_DELETE 99
+#define TK_UPDATE 100
+#define TK_INSERT 101
+#define TK_SET 102
+#define TK_DEFERRABLE 103
+#define TK_FOREIGN 104
+#define TK_DROP 105
+#define TK_UNION 106
+#define TK_ALL 107
+#define TK_EXCEPT 108
+#define TK_INTERSECT 109
+#define TK_SELECT 110
+#define TK_DISTINCT 111
+#define TK_DOT 112
+#define TK_FROM 113
+#define TK_JOIN 114
+#define TK_USING 115
+#define TK_ORDER 116
+#define TK_BY 117
+#define TK_GROUP 118
+#define TK_HAVING 119
+#define TK_LIMIT 120
+#define TK_WHERE 121
+#define TK_INTO 122
+#define TK_VALUES 123
+#define TK_INTEGER 124
+#define TK_FLOAT 125
+#define TK_BLOB 126
+#define TK_REGISTER 127
+#define TK_VARIABLE 128
+#define TK_CASE 129
+#define TK_WHEN 130
+#define TK_THEN 131
+#define TK_ELSE 132
+#define TK_INDEX 133
+#define TK_ALTER 134
+#define TK_TO 135
+#define TK_ADD 136
+#define TK_COLUMNKW 137
+#define TK_TO_TEXT 138
+#define TK_TO_BLOB 139
+#define TK_TO_NUMERIC 140
+#define TK_TO_INT 141
+#define TK_TO_REAL 142
+#define TK_END_OF_FILE 143
+#define TK_ILLEGAL 144
+#define TK_SPACE 145
+#define TK_UNCLOSED_STRING 146
+#define TK_COMMENT 147
+#define TK_FUNCTION 148
+#define TK_COLUMN 149
+#define TK_AGG_FUNCTION 150
+#define TK_AGG_COLUMN 151
+#define TK_CONST_FUNC 152
diff --git a/ext/pdo_sqlite/sqlite/src/parse.y b/ext/pdo_sqlite/sqlite/src/parse.y
index 301eb9b8e5..1e77d75694 100644
--- a/ext/pdo_sqlite/sqlite/src/parse.y
+++ b/ext/pdo_sqlite/sqlite/src/parse.y
@@ -32,14 +32,9 @@
// This code runs whenever there is a syntax error
//
%syntax_error {
- if( !pParse->parseError ){
- if( TOKEN.z[0] ){
- sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
- }else{
- sqlite3ErrorMsg(pParse, "incomplete SQL statement");
- }
- pParse->parseError = 1;
- }
+ assert( TOKEN.z[0] ); /* The tokenizer always gives us a token */
+ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
+ pParse->parseError = 1;
}
%stack_overflow {
sqlite3ErrorMsg(pParse, "parser stack overflow");
@@ -55,7 +50,6 @@
//
%include {
#include "sqliteInt.h"
-#include "parse.h"
/*
** An instance of this structure holds information about the
@@ -104,7 +98,7 @@ explain ::= . { sqlite3BeginParse(pParse, 0); }
%ifndef SQLITE_OMIT_EXPLAIN
explain ::= EXPLAIN. { sqlite3BeginParse(pParse, 1); }
explain ::= EXPLAIN QUERY PLAN. { sqlite3BeginParse(pParse, 2); }
-%endif
+%endif SQLITE_OMIT_EXPLAIN
///////////////////// Begin and end transactions. ////////////////////////////
//
@@ -134,7 +128,7 @@ ifnotexists(A) ::= IF NOT EXISTS. {A = 1;}
%type temp {int}
%ifndef SQLITE_OMIT_TEMPDB
temp(A) ::= TEMP. {A = 1;}
-%endif
+%endif SQLITE_OMIT_TEMPDB
temp(A) ::= . {A = 0;}
create_table_args ::= LP columnlist conslist_opt(X) RP(Y). {
sqlite3EndTable(pParse,&X,&Y,0);
@@ -174,12 +168,12 @@ id(A) ::= ID(X). {A = X;}
%fallback ID
ABORT AFTER ANALYZE ASC ATTACH BEFORE BEGIN CASCADE CAST CONFLICT
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
+ IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH PLAN
+ QUERY KEY OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW
TEMP TRIGGER VACUUM VIEW VIRTUAL
%ifdef SQLITE_OMIT_COMPOUND_SELECT
EXCEPT INTERSECT UNION
-%endif
+%endif SQLITE_OMIT_COMPOUND_SELECT
REINDEX RENAME CTIME_KW IF
.
%wildcard ANY.
@@ -205,6 +199,7 @@ id(A) ::= ID(X). {A = X;}
%left PLUS MINUS.
%left STAR SLASH REM.
%left CONCAT.
+%left COLLATE.
%right UMINUS UPLUS BITNOT.
// And "ids" is an identifer-or-string.
@@ -238,9 +233,8 @@ typetoken(A) ::= typename(X) LP signed COMMA signed RP(Y). {
%type typename {Token}
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((char*)X.z); }
-signed(A) ::= minus_num(X). { A = -atoi((char*)X.z); }
+signed ::= plus_num.
+signed ::= minus_num.
// "carglist" is a list of additional constraints that come after the
// column name and column type in a CREATE TABLE statement.
@@ -249,15 +243,15 @@ carglist ::= carglist carg.
carglist ::= .
carg ::= CONSTRAINT nm ccons.
carg ::= ccons.
-carg ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,X);}
-carg ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,X);}
-carg ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,X);}
-carg ::= DEFAULT MINUS term(X). {
- Expr *p = sqlite3Expr(TK_UMINUS, X, 0, 0);
+ccons ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,X);}
+ccons ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,X);}
+ccons ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,X);}
+ccons ::= DEFAULT MINUS term(X). {
+ Expr *p = sqlite3PExpr(pParse, TK_UMINUS, X, 0, 0);
sqlite3AddDefaultValue(pParse,p);
}
-carg ::= DEFAULT id(X). {
- Expr *p = sqlite3Expr(TK_STRING, 0, 0, &X);
+ccons ::= DEFAULT id(X). {
+ Expr *p = sqlite3PExpr(pParse, TK_STRING, 0, 0, &X);
sqlite3AddDefaultValue(pParse,p);
}
@@ -273,7 +267,7 @@ 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, (char*)C.z, C.n);}
+ccons ::= COLLATE ids(C). {sqlite3AddCollateType(pParse, &C);}
// The optional AUTOINCREMENT keyword
%type autoinc {int}
@@ -355,18 +349,19 @@ ifexists(A) ::= . {A = 0;}
///////////////////// The CREATE VIEW statement /////////////////////////////
//
%ifndef SQLITE_OMIT_VIEW
-cmd ::= CREATE(X) temp(T) VIEW nm(Y) dbnm(Z) AS select(S). {
- sqlite3CreateView(pParse, &X, &Y, &Z, S, T);
+cmd ::= CREATE(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) AS select(S). {
+ sqlite3CreateView(pParse, &X, &Y, &Z, S, T, E);
}
cmd ::= DROP VIEW ifexists(E) fullname(X). {
sqlite3DropTable(pParse, X, 1, E);
}
-%endif // SQLITE_OMIT_VIEW
+%endif SQLITE_OMIT_VIEW
//////////////////////// The SELECT statement /////////////////////////////////
//
cmd ::= select(X). {
- sqlite3Select(pParse, X, SRT_Callback, 0, 0, 0, 0, 0);
+ SelectDest dest = {SRT_Callback, 0, 0};
+ sqlite3Select(pParse, X, &dest, 0, 0, 0, 0);
sqlite3SelectDelete(X);
}
@@ -381,6 +376,8 @@ select(A) ::= select(X) multiselect_op(Y) oneselect(Z). {
if( Z ){
Z->op = Y;
Z->pPrior = X;
+ }else{
+ sqlite3SelectDelete(X);
}
A = Z;
}
@@ -388,10 +385,10 @@ select(A) ::= select(X) multiselect_op(Y) oneselect(Z). {
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
+%endif SQLITE_OMIT_COMPOUND_SELECT
oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
- A = sqlite3SelectNew(W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset);
+ A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset);
}
// The "distinct" nonterminal is true (1) if the DISTINCT keyword is
@@ -414,15 +411,17 @@ distinct(A) ::= . {A = 0;}
sclp(A) ::= selcollist(X) COMMA. {A = X;}
sclp(A) ::= . {A = 0;}
selcollist(A) ::= sclp(P) expr(X) as(Y). {
- A = sqlite3ExprListAppend(P,X,Y.n?&Y:0);
+ A = sqlite3ExprListAppend(pParse,P,X,Y.n?&Y:0);
}
selcollist(A) ::= sclp(P) STAR. {
- A = sqlite3ExprListAppend(P, sqlite3Expr(TK_ALL, 0, 0, 0), 0);
+ Expr *p = sqlite3PExpr(pParse, TK_ALL, 0, 0, 0);
+ A = sqlite3ExprListAppend(pParse, P, p, 0);
}
selcollist(A) ::= sclp(P) nm(X) DOT STAR. {
- Expr *pRight = sqlite3Expr(TK_ALL, 0, 0, 0);
- Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, &X);
- A = sqlite3ExprListAppend(P, sqlite3Expr(TK_DOT, pLeft, pRight, 0), 0);
+ Expr *pRight = sqlite3PExpr(pParse, TK_ALL, 0, 0, 0);
+ Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
+ Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
+ A = sqlite3ExprListAppend(pParse,P, pDot, 0);
}
// An option "AS <id>" phrase that can follow one of the expressions that
@@ -443,8 +442,11 @@ as(X) ::= . {X.n = 0;}
// A complete FROM clause.
//
-from(A) ::= . {A = sqliteMalloc(sizeof(*A));}
-from(A) ::= FROM seltablist(X). {A = X;}
+from(A) ::= . {A = sqlite3DbMallocZero(pParse->db, sizeof(*A));}
+from(A) ::= FROM seltablist(X). {
+ A = X;
+ sqlite3SrcListShiftJoinType(A);
+}
// "seltablist" is a "Select Table List" - the content of the FROM clause
// in a SELECT statement. "stl_prefix" is a prefix of this list.
@@ -455,31 +457,12 @@ stl_prefix(A) ::= seltablist(X) joinop(Y). {
}
stl_prefix(A) ::= . {A = 0;}
seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
- A = sqlite3SrcListAppend(X,&Y,&D);
- if( Z.n ) sqlite3SrcListAddAlias(A,&Z);
- if( N ){
- if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; }
- else { sqlite3ExprDelete(N); }
- }
- if( U ){
- if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; }
- else { sqlite3IdListDelete(U); }
- }
+ A = sqlite3SrcListAppendFromTerm(pParse,X,&Y,&D,&Z,0,N,U);
}
%ifndef SQLITE_OMIT_SUBQUERY
seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP
as(Z) on_opt(N) using_opt(U). {
- A = sqlite3SrcListAppend(X,0,0);
- 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; }
- else { sqlite3ExprDelete(N); }
- }
- if( U ){
- if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; }
- else { sqlite3IdListDelete(U); }
- }
+ A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,S,N,U);
}
// A seltablist_paren nonterminal represents anything in a FROM that
@@ -490,9 +473,10 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
%destructor seltablist_paren {sqlite3SelectDelete($$);}
seltablist_paren(A) ::= select(S). {A = S;}
seltablist_paren(A) ::= seltablist(F). {
- A = sqlite3SelectNew(0,F,0,0,0,0,0,0,0);
+ sqlite3SrcListShiftJoinType(F);
+ A = sqlite3SelectNew(pParse,0,F,0,0,0,0,0,0,0);
}
-%endif // SQLITE_OMIT_SUBQUERY
+%endif SQLITE_OMIT_SUBQUERY
%type dbnm {Token}
dbnm(A) ::= . {A.z=0; A.n=0;}
@@ -500,7 +484,7 @@ dbnm(A) ::= DOT nm(X). {A = X;}
%type fullname {SrcList*}
%destructor fullname {sqlite3SrcListDelete($$);}
-fullname(A) ::= nm(X) dbnm(Y). {A = sqlite3SrcListAppend(0,&X,&Y);}
+fullname(A) ::= nm(X) dbnm(Y). {A = sqlite3SrcListAppend(pParse->db,0,&X,&Y);}
%type joinop {int}
%type joinop2 {int}
@@ -530,29 +514,26 @@ using_opt(U) ::= . {U = 0;}
orderby_opt(A) ::= . {A = 0;}
orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;}
-sortlist(A) ::= sortlist(X) COMMA sortitem(Y) collate(C) sortorder(Z). {
- A = sqlite3ExprListAppend(X,Y,C.n>0?&C:0);
+sortlist(A) ::= sortlist(X) COMMA sortitem(Y) sortorder(Z). {
+ A = sqlite3ExprListAppend(pParse,X,Y,0);
if( A ) A->a[A->nExpr-1].sortOrder = Z;
}
-sortlist(A) ::= sortitem(Y) collate(C) sortorder(Z). {
- A = sqlite3ExprListAppend(0,Y,C.n>0?&C:0);
+sortlist(A) ::= sortitem(Y) sortorder(Z). {
+ A = sqlite3ExprListAppend(pParse,0,Y,0);
if( A && A->a ) A->a[0].sortOrder = Z;
}
sortitem(A) ::= expr(X). {A = X;}
%type sortorder {int}
-%type collate {Token}
sortorder(A) ::= ASC. {A = SQLITE_SO_ASC;}
sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;}
sortorder(A) ::= . {A = SQLITE_SO_ASC;}
-collate(C) ::= . {C.z = 0; C.n = 0;}
-collate(C) ::= COLLATE id(X). {C = X;}
%type groupby_opt {ExprList*}
%destructor groupby_opt {sqlite3ExprListDelete($$);}
groupby_opt(A) ::= . {A = 0;}
-groupby_opt(A) ::= GROUP BY exprlist(X). {A = X;}
+groupby_opt(A) ::= GROUP BY nexprlist(X). {A = X;}
%type having_opt {Expr*}
%destructor having_opt {sqlite3ExprDelete($$);}
@@ -560,10 +541,18 @@ having_opt(A) ::= . {A = 0;}
having_opt(A) ::= HAVING expr(X). {A = X;}
%type limit_opt {struct LimitVal}
-%destructor limit_opt {
- sqlite3ExprDelete($$.pLimit);
- sqlite3ExprDelete($$.pOffset);
-}
+
+// The destructor for limit_opt will never fire in the current grammar.
+// The limit_opt non-terminal only occurs at the end of a single production
+// rule for SELECT statements. As soon as the rule that create the
+// limit_opt non-terminal reduces, the SELECT statement rule will also
+// reduce. So there is never a limit_opt non-terminal on the stack
+// except as a transient. So there is never anything to destroy.
+//
+//%destructor limit_opt {
+// sqlite3ExprDelete($$.pLimit);
+// sqlite3ExprDelete($$.pOffset);
+//}
limit_opt(A) ::= . {A.pLimit = 0; A.pOffset = 0;}
limit_opt(A) ::= LIMIT expr(X). {A.pLimit = X; A.pOffset = 0;}
limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y).
@@ -583,15 +572,18 @@ where_opt(A) ::= WHERE expr(X). {A = X;}
////////////////////////// The UPDATE command ////////////////////////////////
//
-cmd ::= UPDATE orconf(R) fullname(X) SET setlist(Y) where_opt(Z).
- {sqlite3Update(pParse,X,Y,Z,R);}
+cmd ::= UPDATE orconf(R) fullname(X) SET setlist(Y) where_opt(Z). {
+ sqlite3ExprListCheckLength(pParse,Y,SQLITE_MAX_COLUMN,"set list");
+ sqlite3Update(pParse,X,Y,Z,R);
+}
%type setlist {ExprList*}
%destructor setlist {sqlite3ExprListDelete($$);}
setlist(A) ::= setlist(Z) COMMA nm(X) EQ expr(Y).
- {A = sqlite3ExprListAppend(Z,Y,&X);}
-setlist(A) ::= nm(X) EQ expr(Y). {A = sqlite3ExprListAppend(0,Y,&X);}
+ {A = sqlite3ExprListAppend(pParse,Z,Y,&X);}
+setlist(A) ::= nm(X) EQ expr(Y).
+ {A = sqlite3ExprListAppend(pParse,0,Y,&X);}
////////////////////////// The INSERT command /////////////////////////////////
//
@@ -600,6 +592,8 @@ cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F)
{sqlite3Insert(pParse, X, Y, 0, F, R);}
cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) select(S).
{sqlite3Insert(pParse, X, 0, S, F, R);}
+cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) DEFAULT VALUES.
+ {sqlite3Insert(pParse, X, 0, 0, F, R);}
%type insert_cmd {int}
insert_cmd(A) ::= INSERT orconf(R). {A = R;}
@@ -609,8 +603,10 @@ insert_cmd(A) ::= REPLACE. {A = OE_Replace;}
%type itemlist {ExprList*}
%destructor itemlist {sqlite3ExprListDelete($$);}
-itemlist(A) ::= itemlist(X) COMMA expr(Y). {A = sqlite3ExprListAppend(X,Y,0);}
-itemlist(A) ::= expr(X). {A = sqlite3ExprListAppend(0,X,0);}
+itemlist(A) ::= itemlist(X) COMMA expr(Y).
+ {A = sqlite3ExprListAppend(pParse,X,Y,0);}
+itemlist(A) ::= expr(X).
+ {A = sqlite3ExprListAppend(pParse,0,X,0);}
%type inscollist_opt {IdList*}
%destructor inscollist_opt {sqlite3IdListDelete($$);}
@@ -619,8 +615,10 @@ itemlist(A) ::= expr(X). {A = sqlite3ExprListAppend(0,X,0);}
inscollist_opt(A) ::= . {A = 0;}
inscollist_opt(A) ::= LP inscollist(X) RP. {A = X;}
-inscollist(A) ::= inscollist(X) COMMA nm(Y). {A = sqlite3IdListAppend(X,&Y);}
-inscollist(A) ::= nm(Y). {A = sqlite3IdListAppend(0,&Y);}
+inscollist(A) ::= inscollist(X) COMMA nm(Y).
+ {A = sqlite3IdListAppend(pParse->db,X,&Y);}
+inscollist(A) ::= nm(Y).
+ {A = sqlite3IdListAppend(pParse->db,0,&Y);}
/////////////////////////// Expression Processing /////////////////////////////
//
@@ -632,61 +630,72 @@ inscollist(A) ::= nm(Y). {A = sqlite3IdListAppend(0,&Y);}
expr(A) ::= term(X). {A = X;}
expr(A) ::= LP(B) expr(X) RP(E). {A = X; sqlite3ExprSpan(A,&B,&E); }
-term(A) ::= NULL(X). {A = sqlite3Expr(@X, 0, 0, &X);}
-expr(A) ::= ID(X). {A = sqlite3Expr(TK_ID, 0, 0, &X);}
-expr(A) ::= JOIN_KW(X). {A = sqlite3Expr(TK_ID, 0, 0, &X);}
+term(A) ::= NULL(X). {A = sqlite3PExpr(pParse, @X, 0, 0, &X);}
+expr(A) ::= ID(X). {A = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);}
+expr(A) ::= JOIN_KW(X). {A = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);}
expr(A) ::= nm(X) DOT nm(Y). {
- Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &X);
- Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &Y);
- A = sqlite3Expr(TK_DOT, temp1, temp2, 0);
+ Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
+ Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
+ A = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
}
expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
- Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &X);
- Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &Y);
- Expr *temp3 = sqlite3Expr(TK_ID, 0, 0, &Z);
- Expr *temp4 = sqlite3Expr(TK_DOT, temp2, temp3, 0);
- A = sqlite3Expr(TK_DOT, temp1, temp4, 0);
-}
-term(A) ::= INTEGER|FLOAT|BLOB(X). {A = sqlite3Expr(@X, 0, 0, &X);}
-term(A) ::= STRING(X). {A = sqlite3Expr(@X, 0, 0, &X);}
+ Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
+ Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
+ Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Z);
+ Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0);
+ A = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
+}
+term(A) ::= INTEGER|FLOAT|BLOB(X). {A = sqlite3PExpr(pParse, @X, 0, 0, &X);}
+term(A) ::= STRING(X). {A = sqlite3PExpr(pParse, @X, 0, 0, &X);}
expr(A) ::= REGISTER(X). {A = sqlite3RegisterExpr(pParse, &X);}
expr(A) ::= VARIABLE(X). {
Token *pToken = &X;
- Expr *pExpr = A = sqlite3Expr(TK_VARIABLE, 0, 0, pToken);
+ Expr *pExpr = A = sqlite3PExpr(pParse, TK_VARIABLE, 0, 0, pToken);
sqlite3ExprAssignVarNumber(pParse, pExpr);
}
+expr(A) ::= expr(E) COLLATE ids(C). {
+ A = sqlite3ExprSetColl(pParse, E, &C);
+}
%ifndef SQLITE_OMIT_CAST
expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
- A = sqlite3Expr(TK_CAST, E, 0, &T);
+ A = sqlite3PExpr(pParse, TK_CAST, E, 0, &T);
sqlite3ExprSpan(A,&X,&Y);
}
-%endif // SQLITE_OMIT_CAST
+%endif SQLITE_OMIT_CAST
expr(A) ::= ID(X) LP distinct(D) exprlist(Y) RP(E). {
- A = sqlite3ExprFunction(Y, &X);
+ if( Y && Y->nExpr>SQLITE_MAX_FUNCTION_ARG ){
+ sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X);
+ }
+ A = sqlite3ExprFunction(pParse, Y, &X);
sqlite3ExprSpan(A,&X,&E);
if( D && A ){
A->flags |= EP_Distinct;
}
}
expr(A) ::= ID(X) LP STAR RP(E). {
- A = sqlite3ExprFunction(0, &X);
+ A = sqlite3ExprFunction(pParse, 0, &X);
sqlite3ExprSpan(A,&X,&E);
}
term(A) ::= CTIME_KW(OP). {
/* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are
** treated as functions that return constants */
- A = sqlite3ExprFunction(0,&OP);
- if( A ) A->op = TK_CONST_FUNC;
+ A = sqlite3ExprFunction(pParse, 0,&OP);
+ if( A ){
+ A->op = TK_CONST_FUNC;
+ A->span = OP;
+ }
}
-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) AND(OP) expr(Y). {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
+expr(A) ::= expr(X) OR(OP) expr(Y). {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
+expr(A) ::= expr(X) LT|GT|GE|LE(OP) expr(Y).
+ {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
+expr(A) ::= expr(X) EQ|NE(OP) expr(Y). {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
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);}
+ {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
+expr(A) ::= expr(X) PLUS|MINUS(OP) expr(Y).{A = sqlite3PExpr(pParse,@OP,X,Y,0);}
+expr(A) ::= expr(X) STAR|SLASH|REM(OP) expr(Y).
+ {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
+expr(A) ::= expr(X) CONCAT(OP) expr(Y). {A = sqlite3PExpr(pParse,@OP,X,Y,0);}
%type likeop {struct LikeOp}
likeop(A) ::= LIKE_KW(X). {A.eOperator = X; A.not = 0;}
likeop(A) ::= NOT LIKE_KW(X). {A.eOperator = X; A.not = 1;}
@@ -698,58 +707,62 @@ 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;
- pList = sqlite3ExprListAppend(0, Y, 0);
- pList = sqlite3ExprListAppend(pList, X, 0);
+ pList = sqlite3ExprListAppend(pParse,0, Y, 0);
+ pList = sqlite3ExprListAppend(pParse,pList, X, 0);
if( E ){
- pList = sqlite3ExprListAppend(pList, E, 0);
+ pList = sqlite3ExprListAppend(pParse,pList, E, 0);
}
- A = sqlite3ExprFunction(pList, &OP.eOperator);
- if( OP.not ) A = sqlite3Expr(TK_NOT, A, 0, 0);
+ A = sqlite3ExprFunction(pParse, pList, &OP.eOperator);
+ if( OP.not ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
sqlite3ExprSpan(A, &X->span, &Y->span);
if( A ) A->flags |= EP_InfixFunc;
}
expr(A) ::= expr(X) ISNULL|NOTNULL(E). {
- A = sqlite3Expr(@E, X, 0, 0);
+ A = sqlite3PExpr(pParse, @E, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) IS NULL(E). {
- A = sqlite3Expr(TK_ISNULL, X, 0, 0);
+ A = sqlite3PExpr(pParse, TK_ISNULL, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) NOT NULL(E). {
- A = sqlite3Expr(TK_NOTNULL, X, 0, 0);
+ A = sqlite3PExpr(pParse, TK_NOTNULL, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) IS NOT NULL(E). {
- A = sqlite3Expr(TK_NOTNULL, X, 0, 0);
+ A = sqlite3PExpr(pParse, TK_NOTNULL, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
-expr(A) ::= NOT|BITNOT(B) expr(X). {
- A = sqlite3Expr(@B, X, 0, 0);
+expr(A) ::= NOT(B) expr(X). {
+ A = sqlite3PExpr(pParse, @B, X, 0, 0);
+ sqlite3ExprSpan(A,&B,&X->span);
+}
+expr(A) ::= BITNOT(B) expr(X). {
+ A = sqlite3PExpr(pParse, @B, X, 0, 0);
sqlite3ExprSpan(A,&B,&X->span);
}
expr(A) ::= MINUS(B) expr(X). [UMINUS] {
- A = sqlite3Expr(TK_UMINUS, X, 0, 0);
+ A = sqlite3PExpr(pParse, TK_UMINUS, X, 0, 0);
sqlite3ExprSpan(A,&B,&X->span);
}
expr(A) ::= PLUS(B) expr(X). [UPLUS] {
- A = sqlite3Expr(TK_UPLUS, X, 0, 0);
+ A = sqlite3PExpr(pParse, TK_UPLUS, X, 0, 0);
sqlite3ExprSpan(A,&B,&X->span);
}
%type between_op {int}
between_op(A) ::= BETWEEN. {A = 0;}
between_op(A) ::= NOT BETWEEN. {A = 1;}
expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
- ExprList *pList = sqlite3ExprListAppend(0, X, 0);
- pList = sqlite3ExprListAppend(pList, Y, 0);
- A = sqlite3Expr(TK_BETWEEN, W, 0, 0);
+ ExprList *pList = sqlite3ExprListAppend(pParse,0, X, 0);
+ pList = sqlite3ExprListAppend(pParse,pList, Y, 0);
+ A = sqlite3PExpr(pParse, TK_BETWEEN, W, 0, 0);
if( A ){
A->pList = pList;
}else{
sqlite3ExprListDelete(pList);
}
- if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
+ if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&W->span,&Y->span);
}
%ifndef SQLITE_OMIT_SUBQUERY
@@ -757,61 +770,67 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
in_op(A) ::= IN. {A = 0;}
in_op(A) ::= NOT IN. {A = 1;}
expr(A) ::= expr(X) in_op(N) LP exprlist(Y) RP(E). [IN] {
- A = sqlite3Expr(TK_IN, X, 0, 0);
+ A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
if( A ){
A->pList = Y;
+ sqlite3ExprSetHeight(A);
}else{
sqlite3ExprListDelete(Y);
}
- if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
+ if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= LP(B) select(X) RP(E). {
- A = sqlite3Expr(TK_SELECT, 0, 0, 0);
+ A = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
if( A ){
A->pSelect = X;
+ sqlite3ExprSetHeight(A);
}else{
sqlite3SelectDelete(X);
}
sqlite3ExprSpan(A,&B,&E);
}
expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] {
- A = sqlite3Expr(TK_IN, X, 0, 0);
+ A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
if( A ){
A->pSelect = Y;
+ sqlite3ExprSetHeight(A);
}else{
sqlite3SelectDelete(Y);
}
- if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
+ if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] {
- SrcList *pSrc = sqlite3SrcListAppend(0,&Y,&Z);
- A = sqlite3Expr(TK_IN, X, 0, 0);
+ SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&Y,&Z);
+ A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
if( A ){
- A->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0);
+ A->pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
+ sqlite3ExprSetHeight(A);
}else{
sqlite3SrcListDelete(pSrc);
}
- if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
+ if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,Z.z?&Z:&Y);
}
expr(A) ::= EXISTS(B) LP select(Y) RP(E). {
- Expr *p = A = sqlite3Expr(TK_EXISTS, 0, 0, 0);
+ Expr *p = A = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
if( p ){
p->pSelect = Y;
sqlite3ExprSpan(p,&B,&E);
+ sqlite3ExprSetHeight(A);
}else{
sqlite3SelectDelete(Y);
}
}
-%endif // SQLITE_OMIT_SUBQUERY
+%endif SQLITE_OMIT_SUBQUERY
/* CASE expressions */
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
- A = sqlite3Expr(TK_CASE, X, Z, 0);
+ A = sqlite3PExpr(pParse, TK_CASE, X, Z, 0);
if( A ){
A->pList = Y;
+ sqlite3ExprSetHeight(A);
}else{
sqlite3ExprListDelete(Y);
}
@@ -820,12 +839,12 @@ expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
%type case_exprlist {ExprList*}
%destructor case_exprlist {sqlite3ExprListDelete($$);}
case_exprlist(A) ::= case_exprlist(X) WHEN expr(Y) THEN expr(Z). {
- A = sqlite3ExprListAppend(X, Y, 0);
- A = sqlite3ExprListAppend(A, Z, 0);
+ A = sqlite3ExprListAppend(pParse,X, Y, 0);
+ A = sqlite3ExprListAppend(pParse,A, Z, 0);
}
case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). {
- A = sqlite3ExprListAppend(0, Y, 0);
- A = sqlite3ExprListAppend(A, Z, 0);
+ A = sqlite3ExprListAppend(pParse,0, Y, 0);
+ A = sqlite3ExprListAppend(pParse,A, Z, 0);
}
%type case_else {Expr*}
%destructor case_else {sqlite3ExprDelete($$);}
@@ -838,20 +857,23 @@ case_operand(A) ::= . {A = 0;}
%type exprlist {ExprList*}
%destructor exprlist {sqlite3ExprListDelete($$);}
-%type expritem {Expr*}
-%destructor expritem {sqlite3ExprDelete($$);}
+%type nexprlist {ExprList*}
+%destructor nexprlist {sqlite3ExprListDelete($$);}
+
+exprlist(A) ::= nexprlist(X). {A = X;}
+exprlist(A) ::= . {A = 0;}
+nexprlist(A) ::= nexprlist(X) COMMA expr(Y).
+ {A = sqlite3ExprListAppend(pParse,X,Y,0);}
+nexprlist(A) ::= expr(Y).
+ {A = sqlite3ExprListAppend(pParse,0,Y,0);}
-exprlist(A) ::= exprlist(X) COMMA expritem(Y).
- {A = sqlite3ExprListAppend(X,Y,0);}
-exprlist(A) ::= expritem(X). {A = sqlite3ExprListAppend(0,X,0);}
-expritem(A) ::= expr(X). {A = X;}
-expritem(A) ::= . {A = 0;}
///////////////////////////// The CREATE INDEX command ///////////////////////
//
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,
+ sqlite3CreateIndex(pParse, &X, &D,
+ sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U,
&S, &E, SQLITE_SO_ASC, NE);
}
@@ -870,23 +892,29 @@ idxlist_opt(A) ::= LP idxlist(X) RP. {A = X;}
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, (char*)C.z, C.n);
+ p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
+ sqlite3ExprSetColl(pParse, p, &C);
}
- A = sqlite3ExprListAppend(X, p, &Y);
+ A = sqlite3ExprListAppend(pParse,X, p, &Y);
+ sqlite3ExprListCheckLength(pParse, A, SQLITE_MAX_COLUMN, "index");
if( A ) A->a[A->nExpr-1].sortOrder = Z;
}
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, (char*)C.z, C.n);
+ p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
+ sqlite3ExprSetColl(pParse, p, &C);
}
- A = sqlite3ExprListAppend(0, p, &Y);
+ A = sqlite3ExprListAppend(pParse,0, p, &Y);
+ sqlite3ExprListCheckLength(pParse, A, SQLITE_MAX_COLUMN, "index");
if( A ) A->a[A->nExpr-1].sortOrder = Z;
}
idxitem(A) ::= nm(X). {A = X;}
+%type collate {Token}
+collate(C) ::= . {C.z = 0; C.n = 0;}
+collate(C) ::= COLLATE ids(X). {C = X;}
+
///////////////////////////// The DROP INDEX command /////////////////////////
//
@@ -894,21 +922,26 @@ cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);}
///////////////////////////// The VACUUM command /////////////////////////////
//
+%ifndef SQLITE_OMIT_VACUUM
+%ifndef SQLITE_OMIT_ATTACH
cmd ::= VACUUM. {sqlite3Vacuum(pParse);}
cmd ::= VACUUM nm. {sqlite3Vacuum(pParse);}
+%endif SQLITE_OMIT_ATTACH
+%endif SQLITE_OMIT_VACUUM
///////////////////////////// The PRAGMA command /////////////////////////////
//
%ifndef SQLITE_OMIT_PRAGMA
-cmd ::= PRAGMA nm(X) dbnm(Z) EQ nm(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
+cmd ::= PRAGMA nm(X) dbnm(Z) EQ nmnum(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ ON(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
-cmd ::= PRAGMA nm(X) dbnm(Z) EQ plus_num(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y). {
sqlite3Pragma(pParse,&X,&Z,&Y,1);
}
-cmd ::= PRAGMA nm(X) dbnm(Z) LP nm(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
+cmd ::= PRAGMA nm(X) dbnm(Z) LP nmnum(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);}
-%endif // SQLITE_OMIT_PRAGMA
+nmnum(A) ::= plus_num(X). {A = X;}
+nmnum(A) ::= nm(X). {A = X;}
+%endif SQLITE_OMIT_PRAGMA
plus_num(A) ::= plus_opt number(X). {A = X;}
minus_num(A) ::= MINUS number(X). {A = X;}
number(A) ::= INTEGER|FLOAT(X). {A = X;}
@@ -926,14 +959,14 @@ cmd ::= CREATE trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). {
sqlite3FinishTrigger(pParse, S, &all);
}
-trigger_decl(A) ::= temp(T) TRIGGER nm(B) dbnm(Z) trigger_time(C)
- trigger_event(D)
- ON fullname(E) foreach_clause(F) when_clause(G). {
- sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, F, G, T);
+trigger_decl(A) ::= temp(T) TRIGGER ifnotexists(NOERR) nm(B) dbnm(Z)
+ trigger_time(C) trigger_event(D)
+ ON fullname(E) foreach_clause when_clause(G). {
+ sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, G, T, NOERR);
A = (Z.n==0?B:Z);
}
-%type trigger_time {int}
+%type trigger_time {int}
trigger_time(A) ::= BEFORE. { A = TK_BEFORE; }
trigger_time(A) ::= AFTER. { A = TK_AFTER; }
trigger_time(A) ::= INSTEAD OF. { A = TK_INSTEAD;}
@@ -945,10 +978,8 @@ 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;}
-%type foreach_clause {int}
-foreach_clause(A) ::= . { A = TK_ROW; }
-foreach_clause(A) ::= FOR EACH ROW. { A = TK_ROW; }
-foreach_clause(A) ::= FOR EACH STATEMENT. { A = TK_STATEMENT; }
+foreach_clause ::= .
+foreach_clause ::= FOR EACH ROW.
%type when_clause {Expr*}
%destructor when_clause {sqlite3ExprDelete($$);}
@@ -972,39 +1003,39 @@ trigger_cmd_list(A) ::= . { A = 0; }
%destructor trigger_cmd {sqlite3DeleteTriggerStep($$);}
// UPDATE
trigger_cmd(A) ::= UPDATE orconf(R) nm(X) SET setlist(Y) where_opt(Z).
- { A = sqlite3TriggerUpdateStep(&X, Y, Z, R); }
+ { A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R); }
// INSERT
trigger_cmd(A) ::= insert_cmd(R) INTO nm(X) inscollist_opt(F)
VALUES LP itemlist(Y) RP.
- {A = sqlite3TriggerInsertStep(&X, F, Y, 0, R);}
+ {A = sqlite3TriggerInsertStep(pParse->db, &X, F, Y, 0, R);}
trigger_cmd(A) ::= insert_cmd(R) INTO nm(X) inscollist_opt(F) select(S).
- {A = sqlite3TriggerInsertStep(&X, F, 0, S, R);}
+ {A = sqlite3TriggerInsertStep(pParse->db, &X, F, 0, S, R);}
// DELETE
trigger_cmd(A) ::= DELETE FROM nm(X) where_opt(Y).
- {A = sqlite3TriggerDeleteStep(&X, Y);}
+ {A = sqlite3TriggerDeleteStep(pParse->db, &X, Y);}
// SELECT
-trigger_cmd(A) ::= select(X). {A = sqlite3TriggerSelectStep(X); }
+trigger_cmd(A) ::= select(X). {A = sqlite3TriggerSelectStep(pParse->db, X); }
// The special RAISE expression that may occur in trigger programs
expr(A) ::= RAISE(X) LP IGNORE RP(Y). {
- A = sqlite3Expr(TK_RAISE, 0, 0, 0);
+ A = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
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 = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &Z);
if( A ) {
A->iColumn = T;
sqlite3ExprSpan(A, &X, &Y);
}
}
-%endif // !SQLITE_OMIT_TRIGGER
+%endif !SQLITE_OMIT_TRIGGER
%type raisetype {int}
raisetype(A) ::= ROLLBACK. {A = OE_Rollback;}
@@ -1014,33 +1045,34 @@ raisetype(A) ::= FAIL. {A = OE_Fail;}
//////////////////////// DROP TRIGGER statement //////////////////////////////
%ifndef SQLITE_OMIT_TRIGGER
-cmd ::= DROP TRIGGER fullname(X). {
- sqlite3DropTrigger(pParse,X);
+cmd ::= DROP TRIGGER ifexists(NOERR) fullname(X). {
+ sqlite3DropTrigger(pParse,X,NOERR);
}
-%endif // !SQLITE_OMIT_TRIGGER
+%endif !SQLITE_OMIT_TRIGGER
//////////////////////// ATTACH DATABASE file AS name /////////////////////////
+%ifndef SQLITE_OMIT_ATTACH
cmd ::= ATTACH database_kw_opt expr(F) AS expr(D) key_opt(K). {
sqlite3Attach(pParse, F, D, K);
}
-%type key_opt {Expr *}
+cmd ::= DETACH database_kw_opt expr(D). {
+ sqlite3Detach(pParse, D);
+}
+
+%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 expr(D). {
- sqlite3Detach(pParse, D);
-}
+%endif SQLITE_OMIT_ATTACH
////////////////////////// REINDEX collation //////////////////////////////////
%ifndef SQLITE_OMIT_REINDEX
cmd ::= REINDEX. {sqlite3Reindex(pParse, 0, 0);}
cmd ::= REINDEX nm(X) dbnm(Y). {sqlite3Reindex(pParse, &X, &Y);}
-%endif
+%endif SQLITE_OMIT_REINDEX
/////////////////////////////////// ANALYZE ///////////////////////////////////
%ifndef SQLITE_OMIT_ANALYZE
@@ -1061,7 +1093,7 @@ add_column_fullname ::= fullname(X). {
}
kwcolumn_opt ::= .
kwcolumn_opt ::= COLUMNKW.
-%endif
+%endif SQLITE_OMIT_ALTERTABLE
//////////////////////// CREATE VIRTUAL TABLE ... /////////////////////////////
%ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -1079,4 +1111,4 @@ vtabargtoken ::= lp anylist RP(X). {sqlite3VtabArgExtend(pParse,&X);}
lp ::= LP(X). {sqlite3VtabArgExtend(pParse,&X);}
anylist ::= .
anylist ::= anylist ANY(X). {sqlite3VtabArgExtend(pParse,&X);}
-%endif
+%endif SQLITE_OMIT_VIRTUALTABLE
diff --git a/ext/pdo_sqlite/sqlite/src/pragma.c b/ext/pdo_sqlite/sqlite/src/pragma.c
index fbcc1adc01..40eaff36d0 100644
--- a/ext/pdo_sqlite/sqlite/src/pragma.c
+++ b/ext/pdo_sqlite/sqlite/src/pragma.c
@@ -14,18 +14,12 @@
** $Id$
*/
#include "sqliteInt.h"
-#include "os.h"
#include <ctype.h>
/* Ignore this whole file if pragmas are disabled
*/
#if !defined(SQLITE_OMIT_PRAGMA) && !defined(SQLITE_OMIT_PARSER)
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
-# include "pager.h"
-# include "btree.h"
-#endif
-
/*
** Interpret the given string as a safety level. Return 0 for OFF,
** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or
@@ -62,6 +56,34 @@ static int getBoolean(const char *z){
return getSafetyLevel(z)&1;
}
+/*
+** Interpret the given string as a locking mode value.
+*/
+static int getLockingMode(const char *z){
+ if( z ){
+ if( 0==sqlite3StrICmp(z, "exclusive") ) return PAGER_LOCKINGMODE_EXCLUSIVE;
+ if( 0==sqlite3StrICmp(z, "normal") ) return PAGER_LOCKINGMODE_NORMAL;
+ }
+ return PAGER_LOCKINGMODE_QUERY;
+}
+
+#ifndef SQLITE_OMIT_AUTOVACUUM
+/*
+** Interpret the given string as an auto-vacuum mode value.
+**
+** The following strings, "none", "full" and "incremental" are
+** acceptable, as are their numeric equivalents: 0, 1 and 2 respectively.
+*/
+static int getAutoVacuum(const char *z){
+ int i;
+ if( 0==sqlite3StrICmp(z, "none") ) return BTREE_AUTOVACUUM_NONE;
+ if( 0==sqlite3StrICmp(z, "full") ) return BTREE_AUTOVACUUM_FULL;
+ if( 0==sqlite3StrICmp(z, "incremental") ) return BTREE_AUTOVACUUM_INCR;
+ i = atoi(z);
+ return ((i>=0&&i<=2)?i:0);
+}
+#endif /* ifndef SQLITE_OMIT_AUTOVACUUM */
+
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** Interpret the given string as a temp db location. Return 1 for file
@@ -89,7 +111,7 @@ static int getTempStore(const char *z){
static int invalidateTempStorage(Parse *pParse){
sqlite3 *db = pParse->db;
if( db->aDb[1].pBt!=0 ){
- if( db->flags & SQLITE_InTrans ){
+ if( !db->autoCommit ){
sqlite3ErrorMsg(pParse, "temporary storage cannot be changed "
"from within a transaction");
return SQLITE_ERROR;
@@ -125,12 +147,13 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){
*/
static void returnSingleInt(Parse *pParse, const char *zLabel, int value){
Vdbe *v = sqlite3GetVdbe(pParse);
- sqlite3VdbeAddOp(v, OP_Integer, value, 0);
+ int mem = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Integer, value, mem);
if( pParse->explain==0 ){
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, P4_STATIC);
}
- sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, mem, 1);
}
#ifndef SQLITE_OMIT_FLAG_PRAGMAS
@@ -144,20 +167,22 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
const char *zName; /* Name of the pragma */
int mask; /* Mask for the db->flags value */
} aPragma[] = {
- { "vdbe_trace", SQLITE_VdbeTrace },
- { "sql_trace", SQLITE_SqlTrace },
- { "vdbe_listing", SQLITE_VdbeListing },
{ "full_column_names", SQLITE_FullColNames },
{ "short_column_names", SQLITE_ShortColNames },
{ "count_changes", SQLITE_CountRows },
{ "empty_result_callbacks", SQLITE_NullCallback },
{ "legacy_file_format", SQLITE_LegacyFileFmt },
{ "fullfsync", SQLITE_FullFSync },
+#ifdef SQLITE_DEBUG
+ { "sql_trace", SQLITE_SqlTrace },
+ { "vdbe_listing", SQLITE_VdbeListing },
+ { "vdbe_trace", SQLITE_VdbeTrace },
+#endif
#ifndef SQLITE_OMIT_CHECK
{ "ignore_check_constraints", SQLITE_IgnoreChecks },
#endif
/* The following is VERY experimental */
- { "writable_schema", SQLITE_WriteSchema },
+ { "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode },
{ "omit_readlock", SQLITE_NoReadlock },
/* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
@@ -180,8 +205,15 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
}else{
db->flags &= ~p->mask;
}
+
+ /* Many of the flag-pragmas modify the code generated by the SQL
+ ** compiler (eg. count_changes). So add an opcode to expire all
+ ** compiled SQL statements after modifying a pragma value.
+ */
+ sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
}
}
+
return 1;
}
}
@@ -218,8 +250,9 @@ void sqlite3Pragma(
int iDb; /* Database index for <database> */
sqlite3 *db = pParse->db;
Db *pDb;
- Vdbe *v = sqlite3GetVdbe(pParse);
+ Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(db);
if( v==0 ) return;
+ pParse->nMem = 2;
/* Interpret the [database.] part of the pragma statement. iDb is the
** index of the database this pragma is being applied to in db.aDb[]. */
@@ -234,12 +267,12 @@ void sqlite3Pragma(
return;
}
- zLeft = sqlite3NameFromToken(pId);
+ zLeft = sqlite3NameFromToken(db, pId);
if( !zLeft ) return;
if( minusFlag ){
- zRight = sqlite3MPrintf("-%T", pValue);
+ zRight = sqlite3MPrintf(db, "-%T", pValue);
}else{
- zRight = sqlite3NameFromToken(pValue);
+ zRight = sqlite3NameFromToken(db, pValue);
}
zDb = ((iDb>0)?pDb->zName:0);
@@ -266,32 +299,34 @@ void sqlite3Pragma(
*/
if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){
static const VdbeOpList getCacheSize[] = {
- { OP_ReadCookie, 0, 2, 0}, /* 0 */
- { OP_AbsValue, 0, 0, 0},
- { OP_Dup, 0, 0, 0},
- { OP_Integer, 0, 0, 0},
- { OP_Ne, 0, 6, 0},
- { OP_Integer, 0, 0, 0}, /* 5 */
- { OP_Callback, 1, 0, 0},
+ { OP_ReadCookie, 0, 1, 2}, /* 0 */
+ { OP_IfPos, 1, 6, 0},
+ { OP_Integer, 0, 2, 0},
+ { OP_Subtract, 1, 2, 1},
+ { OP_IfPos, 1, 6, 0},
+ { OP_Integer, 0, 1, 0}, /* 5 */
+ { OP_ResultRow, 1, 1, 0},
};
int addr;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
+ sqlite3VdbeUsesBtree(v, iDb);
if( !zRight ){
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", P4_STATIC);
+ pParse->nMem += 2;
addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
sqlite3VdbeChangeP1(v, addr, iDb);
- sqlite3VdbeChangeP1(v, addr+5, MAX_PAGES);
+ sqlite3VdbeChangeP1(v, addr+5, SQLITE_DEFAULT_CACHE_SIZE);
}else{
int size = atoi(zRight);
if( size<0 ) size = -size;
sqlite3BeginWriteOperation(pParse, 0, iDb);
- sqlite3VdbeAddOp(v, OP_Integer, size, 0);
- sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 2);
- addr = sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
- sqlite3VdbeAddOp(v, OP_Ge, 0, addr+3);
- sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
- sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 2);
+ sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
+ sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, 2, 2);
+ addr = sqlite3VdbeAddOp2(v, OP_IfPos, 2, 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, -size, 1);
+ sqlite3VdbeJumpHere(v, addr);
+ sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, 2, 1);
pDb->pSchema->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
}
@@ -312,9 +347,82 @@ void sqlite3Pragma(
int size = pBt ? sqlite3BtreeGetPageSize(pBt) : 0;
returnSingleInt(pParse, "page_size", size);
}else{
- sqlite3BtreeSetPageSize(pBt, atoi(zRight), -1);
+ /* Malloc may fail when setting the page-size, as there is an internal
+ ** buffer that the pager module resizes using sqlite3_realloc().
+ */
+ if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, atoi(zRight), -1) ){
+ db->mallocFailed = 1;
+ }
}
}else
+
+ /*
+ ** PRAGMA [database.]max_page_count
+ ** PRAGMA [database.]max_page_count=N
+ **
+ ** The first form reports the current setting for the
+ ** maximum number of pages in the database file. The
+ ** second form attempts to change this setting. Both
+ ** forms return the current setting.
+ */
+ if( sqlite3StrICmp(zLeft,"max_page_count")==0 ){
+ Btree *pBt = pDb->pBt;
+ int newMax = 0;
+ if( zRight ){
+ newMax = atoi(zRight);
+ }
+ if( pBt ){
+ newMax = sqlite3BtreeMaxPageCount(pBt, newMax);
+ }
+ returnSingleInt(pParse, "max_page_count", newMax);
+ }else
+
+ /*
+ ** PRAGMA [database.]locking_mode
+ ** PRAGMA [database.]locking_mode = (normal|exclusive)
+ */
+ if( sqlite3StrICmp(zLeft,"locking_mode")==0 ){
+ const char *zRet = "normal";
+ int eMode = getLockingMode(zRight);
+
+ if( pId2->n==0 && eMode==PAGER_LOCKINGMODE_QUERY ){
+ /* Simple "PRAGMA locking_mode;" statement. This is a query for
+ ** the current default locking mode (which may be different to
+ ** the locking-mode of the main database).
+ */
+ eMode = db->dfltLockMode;
+ }else{
+ Pager *pPager;
+ if( pId2->n==0 ){
+ /* This indicates that no database name was specified as part
+ ** of the PRAGMA command. In this case the locking-mode must be
+ ** set on all attached databases, as well as the main db file.
+ **
+ ** Also, the sqlite3.dfltLockMode variable is set so that
+ ** any subsequently attached databases also use the specified
+ ** locking mode.
+ */
+ int ii;
+ assert(pDb==&db->aDb[0]);
+ for(ii=2; ii<db->nDb; ii++){
+ pPager = sqlite3BtreePager(db->aDb[ii].pBt);
+ sqlite3PagerLockingMode(pPager, eMode);
+ }
+ db->dfltLockMode = eMode;
+ }
+ pPager = sqlite3BtreePager(pDb->pBt);
+ eMode = sqlite3PagerLockingMode(pPager, eMode);
+ }
+
+ assert(eMode==PAGER_LOCKINGMODE_NORMAL||eMode==PAGER_LOCKINGMODE_EXCLUSIVE);
+ if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){
+ zRet = "exclusive";
+ }
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "locking_mode", P4_STATIC);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, zRet, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
+ }else
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
/*
@@ -326,16 +434,75 @@ void sqlite3Pragma(
#ifndef SQLITE_OMIT_AUTOVACUUM
if( sqlite3StrICmp(zLeft,"auto_vacuum")==0 ){
Btree *pBt = pDb->pBt;
+ if( sqlite3ReadSchema(pParse) ){
+ goto pragma_out;
+ }
if( !zRight ){
int auto_vacuum =
pBt ? sqlite3BtreeGetAutoVacuum(pBt) : SQLITE_DEFAULT_AUTOVACUUM;
returnSingleInt(pParse, "auto_vacuum", auto_vacuum);
}else{
- sqlite3BtreeSetAutoVacuum(pBt, getBoolean(zRight));
+ int eAuto = getAutoVacuum(zRight);
+ db->nextAutovac = eAuto;
+ if( eAuto>=0 ){
+ /* Call SetAutoVacuum() to set initialize the internal auto and
+ ** incr-vacuum flags. This is required in case this connection
+ ** creates the database file. It is important that it is created
+ ** as an auto-vacuum capable db.
+ */
+ int rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto);
+ if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){
+ /* When setting the auto_vacuum mode to either "full" or
+ ** "incremental", write the value of meta[6] in the database
+ ** file. Before writing to meta[6], check that meta[3] indicates
+ ** that this really is an auto-vacuum capable database.
+ */
+ static const VdbeOpList setMeta6[] = {
+ { OP_Transaction, 0, 1, 0}, /* 0 */
+ { OP_ReadCookie, 0, 1, 3}, /* 1 */
+ { OP_If, 1, 0, 0}, /* 2 */
+ { OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */
+ { OP_Integer, 0, 1, 0}, /* 4 */
+ { OP_SetCookie, 0, 6, 1}, /* 5 */
+ };
+ int iAddr;
+ iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6);
+ sqlite3VdbeChangeP1(v, iAddr, iDb);
+ sqlite3VdbeChangeP1(v, iAddr+1, iDb);
+ sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4);
+ sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1);
+ sqlite3VdbeChangeP1(v, iAddr+5, iDb);
+ sqlite3VdbeUsesBtree(v, iDb);
+ }
+ }
}
}else
#endif
+ /*
+ ** PRAGMA [database.]incremental_vacuum(N)
+ **
+ ** Do N steps of incremental vacuuming on a database.
+ */
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( sqlite3StrICmp(zLeft,"incremental_vacuum")==0 ){
+ int iLimit, addr;
+ if( sqlite3ReadSchema(pParse) ){
+ goto pragma_out;
+ }
+ if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){
+ iLimit = 0x7fffffff;
+ }
+ sqlite3BeginWriteOperation(pParse, 0, iDb);
+ sqlite3VdbeAddOp2(v, OP_Integer, iLimit, 1);
+ addr = sqlite3VdbeAddOp1(v, OP_IncrVacuum, iDb);
+ sqlite3VdbeAddOp1(v, OP_ResultRow, 1);
+ sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
+ sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr);
+ sqlite3VdbeJumpHere(v, addr);
+ }else
+#endif
+
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** PRAGMA [database.]cache_size
@@ -397,12 +564,14 @@ void sqlite3Pragma(
if( sqlite3_temp_directory ){
sqlite3VdbeSetNumCols(v, 1);
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);
+ "temp_store_directory", P4_STATIC);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, sqlite3_temp_directory, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
}else{
- if( zRight[0] && !sqlite3OsIsDirWritable(zRight) ){
+ if( zRight[0]
+ && !sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE)
+ ){
sqlite3ErrorMsg(pParse, "not a writable directory");
goto pragma_out;
}
@@ -412,7 +581,7 @@ void sqlite3Pragma(
){
invalidateTempStorage(pParse);
}
- sqliteFree(sqlite3_temp_directory);
+ sqlite3_free(sqlite3_temp_directory);
if( zRight[0] ){
sqlite3_temp_directory = zRight;
zRight = 0;
@@ -472,24 +641,35 @@ void sqlite3Pragma(
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
int i;
+ int nHidden = 0;
Column *pCol;
sqlite3VdbeSetNumCols(v, 6);
- 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);
+ pParse->nMem = 6;
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", P4_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", P4_STATIC);
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", P4_STATIC);
+ sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", P4_STATIC);
+ sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", P4_STATIC);
sqlite3ViewGetColumnNames(pParse, pTab);
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
- sqlite3VdbeAddOp(v, OP_Integer, i, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pCol->zName, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0,
+ const Token *pDflt;
+ if( IsHiddenColumn(pCol) ){
+ nHidden++;
+ continue;
+ }
+ sqlite3VdbeAddOp2(v, OP_Integer, i-nHidden, 1);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pCol->zName, 0);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 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);
+ sqlite3VdbeAddOp2(v, OP_Integer, pCol->notNull, 4);
+ if( pCol->pDflt && (pDflt = &pCol->pDflt->span)->z ){
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pDflt->z, pDflt->n);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
+ }
+ sqlite3VdbeAddOp2(v, OP_Integer, pCol->isPrimKey, 6);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
}
}
}else
@@ -503,16 +683,17 @@ void sqlite3Pragma(
int i;
pTab = pIdx->pTable;
sqlite3VdbeSetNumCols(v, 3);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", P3_STATIC);
- sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", P3_STATIC);
+ pParse->nMem = 3;
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", P4_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", P4_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", P4_STATIC);
for(i=0; i<pIdx->nColumn; i++){
int cnum = pIdx->aiColumn[i];
- sqlite3VdbeAddOp(v, OP_Integer, i, 0);
- sqlite3VdbeAddOp(v, OP_Integer, cnum, 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
+ sqlite3VdbeAddOp2(v, OP_Integer, cnum, 2);
assert( pTab->nCol>cnum );
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[cnum].zName, 0);
- sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
}
}
}else
@@ -528,14 +709,15 @@ void sqlite3Pragma(
if( pIdx ){
int i = 0;
sqlite3VdbeSetNumCols(v, 3);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
- sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", P3_STATIC);
+ pParse->nMem = 3;
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P4_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", P4_STATIC);
while(pIdx){
- sqlite3VdbeAddOp(v, OP_Integer, i, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0);
- sqlite3VdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
- sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
++i;
pIdx = pIdx->pNext;
}
@@ -547,17 +729,18 @@ void sqlite3Pragma(
int i;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 3);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
- sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", P3_STATIC);
+ pParse->nMem = 3;
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P4_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", P4_STATIC);
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt==0 ) continue;
assert( db->aDb[i].zName!=0 );
- sqlite3VdbeAddOp(v, OP_Integer, i, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0,
+ sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, db->aDb[i].zName, 0);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
sqlite3BtreeGetFilename(db->aDb[i].pBt), 0);
- sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
}
}else
@@ -565,13 +748,14 @@ void sqlite3Pragma(
int i = 0;
HashElem *p;
sqlite3VdbeSetNumCols(v, 2);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
+ pParse->nMem = 2;
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P4_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC);
for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){
CollSeq *pColl = (CollSeq *)sqliteHashData(p);
- sqlite3VdbeAddOp(v, OP_Integer, i++, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pColl->zName, 0);
- sqlite3VdbeAddOp(v, OP_Callback, 2, 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, i++, 1);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pColl->zName, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
}
}else
#endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */
@@ -588,22 +772,23 @@ void sqlite3Pragma(
if( pFK ){
int i = 0;
sqlite3VdbeSetNumCols(v, 5);
- 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);
+ pParse->nMem = 5;
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", P4_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", P4_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", P4_STATIC);
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", P4_STATIC);
+ sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", P4_STATIC);
while(pFK){
int j;
for(j=0; j<pFK->nCol; j++){
char *zCol = pFK->aCol[j].zCol;
- sqlite3VdbeAddOp(v, OP_Integer, i, 0);
- sqlite3VdbeAddOp(v, OP_Integer, j, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pFK->zTo, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0,
- pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
- sqlite3VdbeOp3(v, zCol ? OP_String8 : OP_Null, 0, 0, zCol, 0);
- sqlite3VdbeAddOp(v, OP_Callback, 5, 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
+ sqlite3VdbeAddOp2(v, OP_Integer, j, 2);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pFK->zTo, 0);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
+ pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
+ sqlite3VdbeAddOp4(v, zCol ? OP_String8 : OP_Null, 0, 5, 0, zCol, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
}
++i;
pFK = pFK->pNextFrom;
@@ -615,7 +800,6 @@ void sqlite3Pragma(
#ifndef NDEBUG
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
- extern void sqlite3ParserTrace(FILE*, char *);
if( zRight ){
if( getBoolean(zRight) ){
sqlite3ParserTrace(stderr, "parser: ");
@@ -635,27 +819,48 @@ void sqlite3Pragma(
}
}else
+#ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX
+# define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100
+#endif
+
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
- if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
- int i, j, addr;
+ /* Pragma "quick_check" is an experimental reduced version of
+ ** integrity_check designed to detect most database corruption
+ ** without most of the overhead of a full integrity-check.
+ */
+ if( sqlite3StrICmp(zLeft, "integrity_check")==0
+ || sqlite3StrICmp(zLeft, "quick_check")==0
+ ){
+ int i, j, addr, mxErr;
/* Code that appears at the end of the integrity check. If no error
** messages have been generated, output OK. Otherwise output the
** error message
*/
static const VdbeOpList endCode[] = {
- { OP_MemLoad, 0, 0, 0},
- { OP_Integer, 0, 0, 0},
- { OP_Ne, 0, 0, 0}, /* 2 */
- { OP_String8, 0, 0, "ok"},
- { OP_Callback, 1, 0, 0},
+ { OP_AddImm, 1, 0, 0}, /* 0 */
+ { OP_IfNeg, 1, 0, 0}, /* 1 */
+ { OP_String8, 0, 3, 0}, /* 2 */
+ { OP_ResultRow, 3, 1, 0},
};
+ int isQuick = (zLeft[0]=='q');
+
/* Initialize the VDBE program */
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
+ pParse->nMem = 6;
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P3_STATIC);
- sqlite3VdbeAddOp(v, OP_MemInt, 0, 0); /* Initialize error count to 0 */
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P4_STATIC);
+
+ /* Set the maximum error count */
+ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
+ if( zRight ){
+ mxErr = atoi(zRight);
+ if( mxErr<=0 ){
+ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
+ }
+ }
+ sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1); /* reg[1] holds errors left */
/* Do an integrity check on each database file */
for(i=0; i<db->nDb; i++){
@@ -666,93 +871,115 @@ void sqlite3Pragma(
if( OMIT_TEMPDB && i==1 ) continue;
sqlite3CodeVerifySchema(pParse, i);
+ addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Halt if out of errors */
+ sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
+ sqlite3VdbeJumpHere(v, addr);
/* Do an integrity check of the B-Tree
+ **
+ ** Begin by filling registers 2, 3, ... with the root pages numbers
+ ** for all tables and indices in the database.
*/
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);
+ sqlite3VdbeAddOp2(v, OP_Integer, pTab->tnum, 2+cnt);
cnt++;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- sqlite3VdbeAddOp(v, OP_Integer, pIdx->tnum, 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, pIdx->tnum, 2+cnt);
cnt++;
}
}
- assert( cnt>0 );
- 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+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);
+ if( cnt==0 ) continue;
+
+ /* Make sure sufficient number of registers have been allocated */
+ if( pParse->nMem < cnt+3 ){
+ pParse->nMem = cnt+3;
+ }
+
+ /* Do the b-tree integrity checks */
+ sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
+ sqlite3VdbeChangeP5(v, i);
+ addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
+ sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
+ P4_DYNAMIC);
+ sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 2);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
+ sqlite3VdbeJumpHere(v, addr);
/* Make sure all the indices are constructed correctly.
*/
- sqlite3CodeVerifySchema(pParse, i);
- for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
+ for(x=sqliteHashFirst(pTbls); x && !isQuick; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
int loopTop;
if( pTab->pIndex==0 ) continue;
+ addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Stop if out of errors */
+ sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
+ sqlite3VdbeJumpHere(v, addr);
sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
- sqlite3VdbeAddOp(v, OP_MemInt, 0, 1);
- loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
- sqlite3VdbeAddOp(v, OP_MemIncr, 1, 1);
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, 2); /* reg(2) will count entries */
+ loopTop = sqlite3VdbeAddOp2(v, OP_Rewind, 1, 0);
+ sqlite3VdbeAddOp2(v, OP_AddImm, 2, 1); /* increment entry count */
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int jmp2;
static const VdbeOpList idxErr[] = {
- { OP_MemIncr, 1, 0, 0},
- { OP_String8, 0, 0, "rowid "},
- { OP_Rowid, 1, 0, 0},
- { OP_String8, 0, 0, " missing from index "},
- { OP_String8, 0, 0, 0}, /* 4 */
- { OP_Concat, 2, 0, 0},
- { OP_Callback, 1, 0, 0},
+ { OP_AddImm, 1, -1, 0},
+ { OP_String8, 0, 3, 0}, /* 1 */
+ { OP_Rowid, 1, 4, 0},
+ { OP_String8, 0, 5, 0}, /* 3 */
+ { OP_String8, 0, 6, 0}, /* 4 */
+ { OP_Concat, 4, 3, 3},
+ { OP_Concat, 5, 3, 3},
+ { OP_Concat, 6, 3, 3},
+ { OP_ResultRow, 3, 1, 0},
};
- sqlite3GenerateIndexKey(v, pIdx, 1);
- jmp2 = sqlite3VdbeAddOp(v, OP_Found, j+2, 0);
+ sqlite3GenerateIndexKey(pParse, pIdx, 1, 3);
+ jmp2 = sqlite3VdbeAddOp3(v, OP_Found, j+2, 0, 3);
addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
- sqlite3VdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
+ sqlite3VdbeChangeP4(v, addr+1, "rowid ", P4_STATIC);
+ sqlite3VdbeChangeP4(v, addr+3, " missing from index ", P4_STATIC);
+ sqlite3VdbeChangeP4(v, addr+4, pIdx->zName, P4_STATIC);
sqlite3VdbeJumpHere(v, jmp2);
}
- sqlite3VdbeAddOp(v, OP_Next, 1, loopTop+1);
+ sqlite3VdbeAddOp2(v, OP_Next, 1, loopTop+1);
sqlite3VdbeJumpHere(v, loopTop);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
static const VdbeOpList cntIdx[] = {
- { OP_MemInt, 0, 2, 0},
+ { OP_Integer, 0, 3, 0},
{ OP_Rewind, 0, 0, 0}, /* 1 */
- { OP_MemIncr, 1, 2, 0},
+ { OP_AddImm, 3, 1, 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, 1, 0, 0},
- { OP_String8, 0, 0, "wrong # of entries in index "},
- { OP_String8, 0, 0, 0}, /* 9 */
- { OP_Concat, 0, 0, 0},
- { OP_Callback, 1, 0, 0},
+ { OP_Eq, 2, 0, 3}, /* 4 */
+ { OP_AddImm, 1, -1, 0},
+ { OP_String8, 0, 2, 0}, /* 6 */
+ { OP_String8, 0, 3, 0}, /* 7 */
+ { OP_Concat, 3, 2, 2},
+ { OP_ResultRow, 2, 1, 0},
};
if( pIdx->tnum==0 ) continue;
+ addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);
+ sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
+ sqlite3VdbeJumpHere(v, addr);
addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
sqlite3VdbeChangeP1(v, addr+1, j+2);
sqlite3VdbeChangeP2(v, addr+1, addr+4);
sqlite3VdbeChangeP1(v, addr+3, j+2);
sqlite3VdbeChangeP2(v, addr+3, addr+2);
- sqlite3VdbeJumpHere(v, addr+6);
- sqlite3VdbeChangeP3(v, addr+9, pIdx->zName, P3_STATIC);
+ sqlite3VdbeJumpHere(v, addr+4);
+ sqlite3VdbeChangeP4(v, addr+6,
+ "wrong # of entries in index ", P4_STATIC);
+ sqlite3VdbeChangeP4(v, addr+7, pIdx->zName, P4_STATIC);
}
}
}
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
- sqlite3VdbeJumpHere(v, addr+2);
+ sqlite3VdbeChangeP2(v, addr, -mxErr);
+ sqlite3VdbeJumpHere(v, addr+1);
+ sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC);
}else
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -761,7 +988,7 @@ void sqlite3Pragma(
** PRAGMA encoding
** PRAGMA encoding = "utf-8"|"utf-16"|"utf-16le"|"utf-16be"
**
- ** In it's first form, this pragma returns the encoding of the main
+ ** In its first form, this pragma returns the encoding of the main
** database. If the database is not initialized, it is initialized now.
**
** The second form of this pragma is a no-op if the main database file
@@ -798,15 +1025,15 @@ void sqlite3Pragma(
if( !zRight ){ /* "PRAGMA encoding" */
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "encoding", P3_STATIC);
- sqlite3VdbeAddOp(v, OP_String8, 0, 0);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "encoding", P4_STATIC);
+ sqlite3VdbeAddOp2(v, OP_String8, 0, 1);
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
if( pEnc->enc==ENC(pParse->db) ){
- sqlite3VdbeChangeP3(v, -1, pEnc->zName, P3_STATIC);
+ sqlite3VdbeChangeP4(v, -1, pEnc->zName, P4_STATIC);
break;
}
}
- sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}else{ /* "PRAGMA encoding = XXX" */
/* Only change the value of sqlite.enc if the database handle is not
** initialized. If the main database exists, the new sqlite.enc value
@@ -857,22 +1084,33 @@ void sqlite3Pragma(
** The user-version is not used internally by SQLite. It may be used by
** applications for any purpose.
*/
- if( sqlite3StrICmp(zLeft, "schema_version")==0 ||
- sqlite3StrICmp(zLeft, "user_version")==0 ){
+ if( sqlite3StrICmp(zLeft, "schema_version")==0
+ || sqlite3StrICmp(zLeft, "user_version")==0
+ || sqlite3StrICmp(zLeft, "freelist_count")==0
+ ){
int iCookie; /* Cookie index. 0 for schema-cookie, 6 for user-cookie. */
- if( zLeft[0]=='s' || zLeft[0]=='S' ){
- iCookie = 0;
- }else{
- iCookie = 5;
+ sqlite3VdbeUsesBtree(v, iDb);
+ switch( zLeft[0] ){
+ case 's': case 'S':
+ iCookie = 0;
+ break;
+ case 'f': case 'F':
+ iCookie = 1;
+ iDb = (-1*(iDb+1));
+ assert(iDb<=0);
+ break;
+ default:
+ iCookie = 5;
+ break;
}
- if( zRight ){
+ if( zRight && iDb>=0 ){
/* Write the specified cookie value */
static const VdbeOpList setCookie[] = {
{ OP_Transaction, 0, 1, 0}, /* 0 */
- { OP_Integer, 0, 0, 0}, /* 1 */
- { OP_SetCookie, 0, 0, 0}, /* 2 */
+ { OP_Integer, 0, 1, 0}, /* 1 */
+ { OP_SetCookie, 0, 0, 1}, /* 2 */
};
int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie);
sqlite3VdbeChangeP1(v, addr, iDb);
@@ -882,15 +1120,16 @@ void sqlite3Pragma(
}else{
/* Read the specified cookie value */
static const VdbeOpList readCookie[] = {
- { OP_ReadCookie, 0, 0, 0}, /* 0 */
- { OP_Callback, 1, 0, 0}
+ { OP_ReadCookie, 0, 1, 0}, /* 0 */
+ { OP_ResultRow, 1, 1, 0}
};
int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie);
sqlite3VdbeChangeP1(v, addr, iDb);
- sqlite3VdbeChangeP2(v, addr, iCookie);
+ sqlite3VdbeChangeP3(v, addr, iCookie);
sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, P4_TRANSIENT);
}
- }
+ }else
#endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
@@ -904,22 +1143,25 @@ void sqlite3Pragma(
int i;
Vdbe *v = sqlite3GetVdbe(pParse);
sqlite3VdbeSetNumCols(v, 2);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", P3_STATIC);
- sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", P3_STATIC);
+ pParse->nMem = 2;
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", P4_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", P4_STATIC);
for(i=0; i<db->nDb; i++){
Btree *pBt;
Pager *pPager;
+ const char *zState = "unknown";
+ int j;
if( db->aDb[i].zName==0 ) continue;
- sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, P3_STATIC);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, db->aDb[i].zName, P4_STATIC);
pBt = db->aDb[i].pBt;
if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
- sqlite3VdbeOp3(v, OP_String8, 0, 0, "closed", P3_STATIC);
- }else{
- int j = sqlite3pager_lockstate(pPager);
- sqlite3VdbeOp3(v, OP_String8, 0, 0,
- (j>=0 && j<=4) ? azLockName[j] : "unknown", P3_STATIC);
+ zState = "closed";
+ }else if( sqlite3_file_control(db, i ? db->aDb[i].zName : 0,
+ SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
+ zState = azLockName[j];
}
- sqlite3VdbeAddOp(v, OP_Callback, 2, 0);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, zState, P4_STATIC);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
}
}else
#endif
@@ -940,6 +1182,22 @@ void sqlite3Pragma(
sqlite3_key(db, zRight, strlen(zRight));
}else
#endif
+#if SQLITE_HAS_CODEC || defined(SQLITE_ENABLE_CEROD)
+ if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){
+#if SQLITE_HAS_CODEC
+ if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
+ extern void sqlite3_activate_see(const char*);
+ sqlite3_activate_see(&zRight[4]);
+ }
+#endif
+#ifdef SQLITE_ENABLE_CEROD
+ if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){
+ extern void sqlite3_activate_cerod(const char*);
+ sqlite3_activate_cerod(&zRight[6]);
+ }
+#endif
+ }
+#endif
{}
@@ -948,7 +1206,7 @@ void sqlite3Pragma(
** the VDBE implementing the pragma to expire. Most (all?) pragmas
** are only valid for a single execution.
*/
- sqlite3VdbeAddOp(v, OP_Expire, 1, 0);
+ sqlite3VdbeAddOp2(v, OP_Expire, 1, 0);
/*
** Reset the safety level, in case the fullfsync flag or synchronous
@@ -962,8 +1220,8 @@ void sqlite3Pragma(
#endif
}
pragma_out:
- sqliteFree(zLeft);
- sqliteFree(zRight);
+ sqlite3_free(zLeft);
+ sqlite3_free(zRight);
}
#endif /* SQLITE_OMIT_PRAGMA || SQLITE_OMIT_PARSER */
diff --git a/ext/pdo_sqlite/sqlite/src/prepare.c b/ext/pdo_sqlite/sqlite/src/prepare.c
index 0eae259889..cf488d4562 100644
--- a/ext/pdo_sqlite/sqlite/src/prepare.c
+++ b/ext/pdo_sqlite/sqlite/src/prepare.c
@@ -16,7 +16,6 @@
** $Id$
*/
#include "sqliteInt.h"
-#include "os.h"
#include <ctype.h>
/*
@@ -24,7 +23,7 @@
** that the database is corrupt.
*/
static void corruptSchema(InitData *pData, const char *zExtra){
- if( !sqlite3MallocFailed() ){
+ if( !pData->db->mallocFailed ){
sqlite3SetString(pData->pzErrMsg, "malformed database schema",
zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0);
}
@@ -41,28 +40,27 @@ static void corruptSchema(InitData *pData, const char *zExtra){
** argv[0] = name of thing being created
** 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.
**
*/
int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
InitData *pData = (InitData*)pInit;
sqlite3 *db = pData->db;
- int iDb;
+ int iDb = pData->iDb;
+ assert( sqlite3_mutex_held(db->mutex) );
pData->rc = SQLITE_OK;
- if( sqlite3MallocFailed() ){
+ DbClearProperty(db, iDb, DB_Empty);
+ if( db->mallocFailed ){
corruptSchema(pData, 0);
return SQLITE_NOMEM;
}
- assert( argc==4 );
+ assert( argc==3 );
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
- if( argv[1]==0 || argv[3]==0 ){
+ if( argv[1]==0 ){
corruptSchema(pData, 0);
return 1;
}
- iDb = atoi(argv[3]);
assert( iDb>=0 && iDb<db->nDb );
if( argv[2] && argv[2][0] ){
/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
@@ -81,13 +79,15 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
if( SQLITE_OK!=rc ){
pData->rc = rc;
if( rc==SQLITE_NOMEM ){
- sqlite3FailedMalloc();
+ db->mallocFailed = 1;
}else if( rc!=SQLITE_INTERRUPT ){
corruptSchema(pData, zErr);
}
sqlite3_free(zErr);
return 1;
}
+ }else if( argv[0]==0 ){
+ corruptSchema(pData, 0);
}else{
/* If the SQL column is blank it means this is an index that
** was created to be the PRIMARY KEY or to fulfill a UNIQUE
@@ -125,8 +125,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
int size;
Table *pTab;
Db *pDb;
- char const *azArg[5];
- char zDbNum[30];
+ char const *azArg[4];
int meta[10];
InitData initData;
char const *zMasterSchema;
@@ -160,6 +159,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pSchema );
+ assert( sqlite3_mutex_held(db->mutex) );
+ assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
/* zMasterSchema and zInitScript are set to point at the master schema
** and initialisation script appropriate for the database being
@@ -173,25 +174,24 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
zMasterName = SCHEMA_TABLE(iDb);
/* Construct the schema tables. */
- sqlite3SafetyOff(db);
azArg[0] = zMasterName;
azArg[1] = "1";
azArg[2] = zMasterSchema;
- sprintf(zDbNum, "%d", iDb);
- azArg[3] = zDbNum;
- azArg[4] = 0;
+ azArg[3] = 0;
initData.db = db;
+ initData.iDb = iDb;
initData.pzErrMsg = pzErrMsg;
- rc = sqlite3InitCallback(&initData, 4, (char **)azArg, 0);
+ (void)sqlite3SafetyOff(db);
+ rc = sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
+ (void)sqlite3SafetyOn(db);
if( rc ){
- sqlite3SafetyOn(db);
- return initData.rc;
+ rc = initData.rc;
+ goto error_out;
}
pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName);
if( pTab ){
pTab->readOnly = 1;
}
- sqlite3SafetyOn(db);
/* Create a cursor to hold the database open
*/
@@ -202,10 +202,12 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
}
return SQLITE_OK;
}
+ sqlite3BtreeEnter(pDb->pBt);
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;
+ sqlite3BtreeLeave(pDb->pBt);
+ goto error_out;
}
/* Get the database meta information.
@@ -217,7 +219,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
** meta[3] Use freelist if 0. Autovacuum if greater than zero.
** 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[6] Incremental-vacuum flag.
** meta[7]
** meta[8]
** meta[9]
@@ -233,7 +235,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
if( rc ){
sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
sqlite3BtreeCloseCursor(curMain);
- return rc;
+ sqlite3BtreeLeave(pDb->pBt);
+ goto error_out;
}
}else{
memset(meta, 0, sizeof(meta));
@@ -256,6 +259,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
sqlite3BtreeCloseCursor(curMain);
sqlite3SetString(pzErrMsg, "attached databases must use the same"
" text encoding as main database", (char*)0);
+ sqlite3BtreeLeave(pDb->pBt);
return SQLITE_ERROR;
}
}
@@ -265,7 +269,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
pDb->pSchema->enc = ENC(db);
size = meta[2];
- if( size==0 ){ size = MAX_PAGES; }
+ if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; }
+ if( size<0 ) size = -size;
pDb->pSchema->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
@@ -282,9 +287,18 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){
sqlite3BtreeCloseCursor(curMain);
sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0);
+ sqlite3BtreeLeave(pDb->pBt);
return SQLITE_ERROR;
}
+ /* Ticket #2804: When we open a database in the newer file format,
+ ** clear the legacy_file_format pragma flag so that a VACUUM will
+ ** not downgrade the database and thus invalidate any descending
+ ** indices that the user might have created.
+ */
+ if( iDb==0 && meta[1]>=4 ){
+ db->flags &= ~SQLITE_LegacyFileFmt;
+ }
/* Read the schema information out of the schema tables
*/
@@ -294,14 +308,24 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
rc = SQLITE_OK;
}else{
char *zSql;
- zSql = sqlite3MPrintf(
- "SELECT name, rootpage, sql, '%s' FROM '%q'.%s",
- zDbNum, db->aDb[iDb].zName, zMasterName);
- sqlite3SafetyOff(db);
- rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
+ zSql = sqlite3MPrintf(db,
+ "SELECT name, rootpage, sql FROM '%q'.%s",
+ db->aDb[iDb].zName, zMasterName);
+ (void)sqlite3SafetyOff(db);
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ {
+ int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
+ xAuth = db->xAuth;
+ db->xAuth = 0;
+#endif
+ rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ db->xAuth = xAuth;
+ }
+#endif
if( rc==SQLITE_ABORT ) rc = initData.rc;
- sqlite3SafetyOn(db);
- sqliteFree(zSql);
+ (void)sqlite3SafetyOn(db);
+ sqlite3_free(zSql);
#ifndef SQLITE_OMIT_ANALYZE
if( rc==SQLITE_OK ){
sqlite3AnalysisLoad(db, iDb);
@@ -309,15 +333,28 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
#endif
sqlite3BtreeCloseCursor(curMain);
}
- if( sqlite3MallocFailed() ){
+ if( db->mallocFailed ){
/* sqlite3SetString(pzErrMsg, "out of memory", (char*)0); */
rc = SQLITE_NOMEM;
sqlite3ResetInternalSchema(db, 0);
}
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){
+ /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider
+ ** the schema loaded, even if errors occured. In this situation the
+ ** current sqlite3_prepare() operation will fail, but the following one
+ ** will attempt to compile the supplied statement against whatever subset
+ ** of the schema was loaded before the error occured. The primary
+ ** purpose of this is to allow access to the sqlite_master table
+ ** even when its contents have been corrupted.
+ */
DbSetProperty(db, iDb, DB_SchemaLoaded);
- }else{
- sqlite3ResetInternalSchema(db, iDb);
+ rc = SQLITE_OK;
+ }
+ sqlite3BtreeLeave(pDb->pBt);
+
+error_out:
+ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
+ db->mallocFailed = 1;
}
return rc;
}
@@ -334,8 +371,9 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
*/
int sqlite3Init(sqlite3 *db, char **pzErrMsg){
int i, rc;
- int called_initone = 0;
+ int commit_internal = !(db->flags&SQLITE_InternChanges);
+ assert( sqlite3_mutex_held(db->mutex) );
if( db->init.busy ) return SQLITE_OK;
rc = SQLITE_OK;
db->init.busy = 1;
@@ -345,7 +383,6 @@ 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
@@ -358,12 +395,11 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
if( rc ){
sqlite3ResetInternalSchema(db, 1);
}
- called_initone = 1;
}
#endif
db->init.busy = 0;
- if( rc==SQLITE_OK && called_initone ){
+ if( rc==SQLITE_OK && commit_internal ){
sqlite3CommitInternalChanges(db);
}
@@ -377,6 +413,7 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
int sqlite3ReadSchema(Parse *pParse){
int rc = SQLITE_OK;
sqlite3 *db = pParse->db;
+ assert( sqlite3_mutex_held(db->mutex) );
if( !db->init.busy ){
rc = sqlite3Init(db, &pParse->zErrMsg);
}
@@ -399,6 +436,7 @@ static int schemaIsValid(sqlite3 *db){
int cookie;
int allOk = 1;
+ assert( sqlite3_mutex_held(db->mutex) );
for(iDb=0; allOk && iDb<db->nDb; iDb++){
Btree *pBt;
pBt = db->aDb[iDb].pBt;
@@ -411,6 +449,9 @@ static int schemaIsValid(sqlite3 *db){
}
sqlite3BtreeCloseCursor(curTemp);
}
+ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
+ db->mallocFailed = 1;
+ }
}
return allOk;
}
@@ -435,6 +476,7 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
** more likely to cause a segfault than -1 (of course there are assert()
** statements too, but it never hurts to play the odds).
*/
+ assert( sqlite3_mutex_held(db->mutex) );
if( pSchema ){
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pSchema==pSchema ){
@@ -449,52 +491,64 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
/*
** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
*/
-int sqlite3_prepare(
+int sqlite3Prepare(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
+ int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
- const char** pzTail /* OUT: End of parsed string */
+ const char **pzTail /* OUT: End of parsed string */
){
Parse sParse;
char *zErrMsg = 0;
int rc = SQLITE_OK;
int i;
- /* Assert that malloc() has not failed */
- assert( !sqlite3MallocFailed() );
-
assert( ppStmt );
*ppStmt = 0;
if( sqlite3SafetyOn(db) ){
return SQLITE_MISUSE;
}
+ assert( !db->mallocFailed );
+ assert( sqlite3_mutex_held(db->mutex) );
/* 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;
+ if( pBt ){
+ int rc;
+ rc = sqlite3BtreeSchemaLocked(pBt);
+ if( rc ){
+ const char *zDb = db->aDb[i].zName;
+ sqlite3Error(db, SQLITE_LOCKED, "database schema is locked: %s", zDb);
+ (void)sqlite3SafetyOff(db);
+ return SQLITE_LOCKED;
+ }
}
}
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
if( nBytes>=0 && zSql[nBytes]!=0 ){
- char *zSqlCopy = sqlite3StrNDup(zSql, nBytes);
- sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
- sParse.zTail += zSql - zSqlCopy;
- sqliteFree(zSqlCopy);
+ char *zSqlCopy;
+ if( SQLITE_MAX_SQL_LENGTH>0 && nBytes>SQLITE_MAX_SQL_LENGTH ){
+ sqlite3Error(db, SQLITE_TOOBIG, "statement too long");
+ (void)sqlite3SafetyOff(db);
+ return SQLITE_TOOBIG;
+ }
+ zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
+ if( zSqlCopy ){
+ sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
+ sqlite3_free(zSqlCopy);
+ }
+ sParse.zTail = &zSql[nBytes];
}else{
sqlite3RunParser(&sParse, zSql, &zErrMsg);
}
- if( sqlite3MallocFailed() ){
+ if( db->mallocFailed ){
sParse.rc = SQLITE_NOMEM;
}
if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
@@ -504,59 +558,151 @@ int sqlite3_prepare(
if( sParse.rc==SQLITE_SCHEMA ){
sqlite3ResetInternalSchema(db, 0);
}
- if( sqlite3MallocFailed() ){
+ if( db->mallocFailed ){
sParse.rc = SQLITE_NOMEM;
}
- if( pzTail ) *pzTail = sParse.zTail;
+ if( pzTail ){
+ *pzTail = sParse.zTail;
+ }
rc = sParse.rc;
#ifndef SQLITE_OMIT_EXPLAIN
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
if( sParse.explain==2 ){
sqlite3VdbeSetNumCols(sParse.pVdbe, 3);
- sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "order", P3_STATIC);
- sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "from", P3_STATIC);
- sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "detail", P3_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "order", P4_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "from", P4_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "detail", P4_STATIC);
}else{
- sqlite3VdbeSetNumCols(sParse.pVdbe, 5);
- 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);
+ sqlite3VdbeSetNumCols(sParse.pVdbe, 8);
+ sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "addr", P4_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "opcode", P4_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "p1", P4_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 3, COLNAME_NAME, "p2", P4_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 4, COLNAME_NAME, "p3", P4_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 5, COLNAME_NAME, "p4", P4_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 6, COLNAME_NAME, "p5", P4_STATIC);
+ sqlite3VdbeSetColName(sParse.pVdbe, 7, COLNAME_NAME, "comment",P4_STATIC);
}
- }
+ }
#endif
if( sqlite3SafetyOff(db) ){
rc = SQLITE_MISUSE;
}
- if( rc==SQLITE_OK ){
- *ppStmt = (sqlite3_stmt*)sParse.pVdbe;
- }else if( sParse.pVdbe ){
+
+ if( saveSqlFlag ){
+ sqlite3VdbeSetSql(sParse.pVdbe, zSql, sParse.zTail - zSql);
+ }
+ if( rc!=SQLITE_OK || db->mallocFailed ){
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
+ assert(!(*ppStmt));
+ }else{
+ *ppStmt = (sqlite3_stmt*)sParse.pVdbe;
}
if( zErrMsg ){
sqlite3Error(db, rc, "%s", zErrMsg);
- sqliteFree(zErrMsg);
+ sqlite3_free(zErrMsg);
}else{
sqlite3Error(db, rc, 0);
}
rc = sqlite3ApiExit(db, rc);
- sqlite3ReleaseThreadData();
+ assert( (rc&db->errMask)==rc );
return rc;
}
+static int sqlite3LockAndPrepare(
+ sqlite3 *db, /* Database handle. */
+ const char *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const char **pzTail /* OUT: End of parsed string */
+){
+ int rc;
+ if( !sqlite3SafetyCheckOk(db) ){
+ return SQLITE_MISUSE;
+ }
+ sqlite3_mutex_enter(db->mutex);
+ sqlite3BtreeEnterAll(db);
+ rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, ppStmt, pzTail);
+ sqlite3BtreeLeaveAll(db);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
+}
+
+/*
+** Rerun the compilation of a statement after a schema change.
+** Return true if the statement was recompiled successfully.
+** Return false if there is an error of some kind.
+*/
+int sqlite3Reprepare(Vdbe *p){
+ int rc;
+ sqlite3_stmt *pNew;
+ const char *zSql;
+ sqlite3 *db;
+
+ assert( sqlite3_mutex_held(sqlite3VdbeDb(p)->mutex) );
+ zSql = sqlite3_sql((sqlite3_stmt *)p);
+ assert( zSql!=0 ); /* Reprepare only called for prepare_v2() statements */
+ db = sqlite3VdbeDb(p);
+ assert( sqlite3_mutex_held(db->mutex) );
+ rc = sqlite3LockAndPrepare(db, zSql, -1, 0, &pNew, 0);
+ if( rc ){
+ if( rc==SQLITE_NOMEM ){
+ db->mallocFailed = 1;
+ }
+ assert( pNew==0 );
+ return 0;
+ }else{
+ assert( pNew!=0 );
+ }
+ sqlite3VdbeSwap((Vdbe*)pNew, p);
+ sqlite3_transfer_bindings(pNew, (sqlite3_stmt*)p);
+ sqlite3VdbeResetStepResult((Vdbe*)pNew);
+ sqlite3VdbeFinalize((Vdbe*)pNew);
+ return 1;
+}
+
+
+/*
+** Two versions of the official API. Legacy and new use. In the legacy
+** version, the original SQL text is not saved in the prepared statement
+** and so if a schema change occurs, SQLITE_SCHEMA is returned by
+** sqlite3_step(). In the new version, the original SQL text is retained
+** and the statement is automatically recompiled if an schema change
+** occurs.
+*/
+int sqlite3_prepare(
+ sqlite3 *db, /* Database handle. */
+ const char *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const char **pzTail /* OUT: End of parsed string */
+){
+ return sqlite3LockAndPrepare(db,zSql,nBytes,0,ppStmt,pzTail);
+}
+int sqlite3_prepare_v2(
+ sqlite3 *db, /* Database handle. */
+ const char *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const char **pzTail /* OUT: End of parsed string */
+){
+ return sqlite3LockAndPrepare(db,zSql,nBytes,1,ppStmt,pzTail);
+}
+
#ifndef SQLITE_OMIT_UTF16
/*
** Compile the UTF-16 encoded SQL statement zSql into a statement handle.
*/
-int sqlite3_prepare16(
+static int sqlite3Prepare16(
sqlite3 *db, /* Database handle. */
const void *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
+ int saveSqlFlag, /* True to save SQL text into the sqlite3_stmt */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const void **pzTail /* OUT: End of parsed string */
){
@@ -568,12 +714,13 @@ int sqlite3_prepare16(
const char *zTail8 = 0;
int rc = SQLITE_OK;
- if( sqlite3SafetyCheck(db) ){
+ if( !sqlite3SafetyCheckOk(db) ){
return SQLITE_MISUSE;
}
- zSql8 = sqlite3utf16to8(zSql, nBytes);
+ sqlite3_mutex_enter(db->mutex);
+ zSql8 = sqlite3Utf16to8(db, zSql, nBytes);
if( zSql8 ){
- rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8);
+ rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, ppStmt, &zTail8);
}
if( zTail8 && pzTail ){
@@ -582,10 +729,40 @@ int sqlite3_prepare16(
** characters between zSql8 and zTail8, and then returning a pointer
** the same number of characters into the UTF-16 string.
*/
- int chars_parsed = sqlite3utf8CharLen(zSql8, zTail8-zSql8);
- *pzTail = (u8 *)zSql + sqlite3utf16ByteLen(zSql, chars_parsed);
+ int chars_parsed = sqlite3Utf8CharLen(zSql8, zTail8-zSql8);
+ *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed);
}
- sqliteFree(zSql8);
- return sqlite3ApiExit(db, rc);
+ sqlite3_free(zSql8);
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
}
+
+/*
+** Two versions of the official API. Legacy and new use. In the legacy
+** version, the original SQL text is not saved in the prepared statement
+** and so if a schema change occurs, SQLITE_SCHEMA is returned by
+** sqlite3_step(). In the new version, the original SQL text is retained
+** and the statement is automatically recompiled if an schema change
+** occurs.
+*/
+int sqlite3_prepare16(
+ sqlite3 *db, /* Database handle. */
+ const void *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const void **pzTail /* OUT: End of parsed string */
+){
+ return sqlite3Prepare16(db,zSql,nBytes,0,ppStmt,pzTail);
+}
+int sqlite3_prepare16_v2(
+ sqlite3 *db, /* Database handle. */
+ const void *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const void **pzTail /* OUT: End of parsed string */
+){
+ return sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail);
+}
+
#endif /* SQLITE_OMIT_UTF16 */
diff --git a/ext/pdo_sqlite/sqlite/src/printf.c b/ext/pdo_sqlite/sqlite/src/printf.c
index b4c37fb61d..eafe842a1c 100644
--- a/ext/pdo_sqlite/sqlite/src/printf.c
+++ b/ext/pdo_sqlite/sqlite/src/printf.c
@@ -73,6 +73,8 @@
#define etTOKEN 13 /* a pointer to a Token structure */
#define etSRCLIST 14 /* a pointer to a SrcList */
#define etPOINTER 15 /* The %p conversion */
+#define etSQLESCAPE3 16 /* %w -> Strings with '\"' doubled */
+#define etORDINAL 17 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
/*
@@ -111,9 +113,10 @@ static const et_info fmtinfo[] = {
{ 'd', 10, 1, etRADIX, 0, 0 },
{ 's', 0, 4, etSTRING, 0, 0 },
{ 'g', 0, 1, etGENERIC, 30, 0 },
- { 'z', 0, 6, etDYNSTRING, 0, 0 },
+ { 'z', 0, 4, etDYNSTRING, 0, 0 },
{ 'q', 0, 4, etSQLESCAPE, 0, 0 },
{ 'Q', 0, 4, etSQLESCAPE2, 0, 0 },
+ { 'w', 0, 4, etSQLESCAPE3, 0, 0 },
{ 'c', 0, 0, etCHARX, 0, 0 },
{ 'o', 8, 0, etRADIX, 0, 2 },
{ 'u', 10, 0, etRADIX, 0, 0 },
@@ -131,6 +134,7 @@ static const et_info fmtinfo[] = {
{ 'p', 16, 0, etPOINTER, 0, 1 },
{ 'T', 0, 2, etTOKEN, 0, 0 },
{ 'S', 0, 2, etSRCLIST, 0, 0 },
+ { 'r', 10, 3, etORDINAL, 0, 0 },
};
#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
@@ -165,6 +169,20 @@ static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
#endif /* SQLITE_OMIT_FLOATING_POINT */
/*
+** Append N space characters to the given string buffer.
+*/
+static void appendSpace(StrAccum *pAccum, int N){
+ static const char zSpaces[] = " ";
+ while( N>=sizeof(zSpaces)-1 ){
+ sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1);
+ N -= sizeof(zSpaces)-1;
+ }
+ if( N>0 ){
+ sqlite3StrAccumAppend(pAccum, zSpaces, N);
+ }
+}
+
+/*
** On machines with a small stack size, you can redefine the
** SQLITE_PRINT_BUF_SIZE to be less than 350. But beware - for
** smaller values some %f conversions may go into an infinite loop.
@@ -201,9 +219,8 @@ static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
** seems to make a big difference in determining how fast this beast
** will run.
*/
-static int vxprintf(
- void (*func)(void*,const char*,int), /* Consumer of text */
- void *arg, /* First argument to the consumer */
+static void vxprintf(
+ StrAccum *pAccum, /* Accumulate results here */
int useExtended, /* Allow extended %-conversions */
const char *fmt, /* Format string */
va_list ap /* arguments */
@@ -213,7 +230,6 @@ static int vxprintf(
int precision; /* Precision of the current field */
int length; /* Length of the field */
int idx; /* A general purpose loop counter */
- int count; /* Total number of characters output */
int width; /* Width of the current field */
etByte flag_leftjustify; /* True if "-" flag is present */
etByte flag_plussign; /* True if "+" flag is present */
@@ -232,9 +248,6 @@ static int vxprintf(
etByte errorflag = 0; /* True if an error is encountered */
etByte xtype; /* Conversion paradigm */
char *zExtra; /* Extra memory used for etTCLESCAPE conversions */
- static const char spaces[] =
- " ";
-#define etSPACESIZE (sizeof(spaces)-1)
#ifndef SQLITE_OMIT_FLOATING_POINT
int exp, e2; /* exponent of real numbers */
double rounder; /* Used for rounding floating point values */
@@ -244,8 +257,7 @@ static int vxprintf(
int nsd; /* Number of significant digits returned */
#endif
- func(arg,"",0);
- count = length = 0;
+ length = 0;
bufpt = 0;
for(; (c=(*fmt))!=0; ++fmt){
if( c!='%' ){
@@ -253,14 +265,12 @@ static int vxprintf(
bufpt = (char *)fmt;
amt = 1;
while( (c=(*++fmt))!='%' && c!=0 ) amt++;
- (*func)(arg,bufpt,amt);
- count += amt;
+ sqlite3StrAccumAppend(pAccum, bufpt, amt);
if( c==0 ) break;
}
if( (c=(*++fmt))==0 ){
errorflag = 1;
- (*func)(arg,"%",1);
- count++;
+ sqlite3StrAccumAppend(pAccum, "%", 1);
break;
}
/* Find out what flags are present */
@@ -334,14 +344,14 @@ static int vxprintf(
if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
xtype = infop->type;
}else{
- return -1;
+ return;
}
break;
}
}
zExtra = 0;
if( infop==0 ){
- return -1;
+ return;
}
@@ -376,6 +386,7 @@ static int vxprintf(
flag_longlong = sizeof(char*)==sizeof(i64);
flag_long = sizeof(char*)==sizeof(long int);
/* Fall through into the next case */
+ case etORDINAL:
case etRADIX:
if( infop->flags & FLAG_SIGNED ){
i64 v;
@@ -402,6 +413,16 @@ static int vxprintf(
precision = width-(prefix!=0);
}
bufpt = &buf[etBUFSIZE-1];
+ if( xtype==etORDINAL ){
+ static const char zOrd[] = "thstndrd";
+ int x = longvalue % 10;
+ if( x>=4 || (longvalue/10)%10==1 ){
+ x = 0;
+ }
+ buf[etBUFSIZE-3] = zOrd[x*2];
+ buf[etBUFSIZE-2] = zOrd[x*2+1];
+ bufpt -= 2;
+ }
{
register const char *cset; /* Use registers for speed */
register int base;
@@ -453,6 +474,11 @@ static int vxprintf(
if( xtype==etFLOAT ) realvalue += rounder;
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
exp = 0;
+ if( sqlite3_isnan(realvalue) ){
+ bufpt = "NaN";
+ length = 3;
+ break;
+ }
if( realvalue>0.0 ){
while( realvalue>=1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; }
while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
@@ -460,8 +486,14 @@ static int vxprintf(
while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
if( exp>350 || exp<-350 ){
- bufpt = "NaN";
- length = 3;
+ if( prefix=='-' ){
+ bufpt = "-Inf";
+ }else if( prefix=='+' ){
+ bufpt = "+Inf";
+ }else{
+ bufpt = "Inf";
+ }
+ length = strlen(bufpt);
break;
}
}
@@ -568,7 +600,7 @@ static int vxprintf(
#endif
break;
case etSIZE:
- *(va_arg(ap,int*)) = count;
+ *(va_arg(ap,int*)) = pAccum->nChar;
length = width = 0;
break;
case etPERCENT:
@@ -599,30 +631,32 @@ static int vxprintf(
if( precision>=0 && precision<length ) length = precision;
break;
case etSQLESCAPE:
- case etSQLESCAPE2: {
+ case etSQLESCAPE2:
+ case etSQLESCAPE3: {
int i, j, n, ch, isnull;
int needQuote;
+ char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */
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++;
+ if( ch==q ) n++;
}
needQuote = !isnull && xtype==etSQLESCAPE2;
n += i + 1 + needQuote*2;
if( n>etBUFSIZE ){
- bufpt = zExtra = sqliteMalloc( n );
- if( bufpt==0 ) return -1;
+ bufpt = zExtra = sqlite3_malloc( n );
+ if( bufpt==0 ) return;
}else{
bufpt = buf;
}
j = 0;
- if( needQuote ) bufpt[j++] = '\'';
+ if( needQuote ) bufpt[j++] = q;
for(i=0; (ch=escarg[i])!=0; i++){
bufpt[j++] = ch;
- if( ch=='\'' ) bufpt[j++] = ch;
+ if( ch==q ) bufpt[j++] = ch;
}
- if( needQuote ) bufpt[j++] = '\'';
+ if( needQuote ) bufpt[j++] = q;
bufpt[j] = 0;
length = j;
/* The precision is ignored on %q and %Q */
@@ -632,7 +666,7 @@ static int vxprintf(
case etTOKEN: {
Token *pToken = va_arg(ap, Token*);
if( pToken && pToken->z ){
- (*func)(arg, (char*)pToken->z, pToken->n);
+ sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n);
}
length = width = 0;
break;
@@ -643,10 +677,10 @@ static int vxprintf(
struct SrcList_item *pItem = &pSrc->a[k];
assert( k>=0 && k<pSrc->nSrc );
if( pItem->zDatabase && pItem->zDatabase[0] ){
- (*func)(arg, pItem->zDatabase, strlen(pItem->zDatabase));
- (*func)(arg, ".", 1);
+ sqlite3StrAccumAppend(pAccum, pItem->zDatabase, -1);
+ sqlite3StrAccumAppend(pAccum, ".", 1);
}
- (*func)(arg, pItem->zName, strlen(pItem->zName));
+ sqlite3StrAccumAppend(pAccum, pItem->zName, -1);
length = width = 0;
break;
}
@@ -660,147 +694,140 @@ static int vxprintf(
register int nspace;
nspace = width-length;
if( nspace>0 ){
- count += nspace;
- while( nspace>=etSPACESIZE ){
- (*func)(arg,spaces,etSPACESIZE);
- nspace -= etSPACESIZE;
- }
- if( nspace>0 ) (*func)(arg,spaces,nspace);
+ appendSpace(pAccum, nspace);
}
}
if( length>0 ){
- (*func)(arg,bufpt,length);
- count += length;
+ sqlite3StrAccumAppend(pAccum, bufpt, length);
}
if( flag_leftjustify ){
register int nspace;
nspace = width-length;
if( nspace>0 ){
- count += nspace;
- while( nspace>=etSPACESIZE ){
- (*func)(arg,spaces,etSPACESIZE);
- nspace -= etSPACESIZE;
- }
- if( nspace>0 ) (*func)(arg,spaces,nspace);
+ appendSpace(pAccum, nspace);
}
}
if( zExtra ){
- sqliteFree(zExtra);
+ sqlite3_free(zExtra);
}
}/* End for loop over the format string */
- return errorflag ? -1 : count;
} /* End of function */
-
-/* This structure is used to store state information about the
-** write to memory that is currently in progress.
-*/
-struct sgMprintf {
- char *zBase; /* A base allocation */
- char *zText; /* The string collected so far */
- int nChar; /* Length of the string so far */
- int nTotal; /* Output size if unconstrained */
- int nAlloc; /* Amount of space allocated in zText */
- void *(*xRealloc)(void*,int); /* Function used to realloc memory */
-};
-
-/*
-** This function implements the callback from vxprintf.
-**
-** This routine add nNewChar characters of text in zNewText to
-** the sgMprintf structure pointed to by "arg".
+/*
+** Append N bytes of text from z to the StrAccum object.
*/
-static void mout(void *arg, const char *zNewText, int nNewChar){
- struct sgMprintf *pM = (struct sgMprintf*)arg;
- pM->nTotal += nNewChar;
- if( pM->nChar + nNewChar + 1 > pM->nAlloc ){
- if( pM->xRealloc==0 ){
- nNewChar = pM->nAlloc - pM->nChar - 1;
+void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
+ if( p->tooBig | p->mallocFailed ){
+ return;
+ }
+ if( N<0 ){
+ N = strlen(z);
+ }
+ if( N==0 ){
+ return;
+ }
+ if( p->nChar+N >= p->nAlloc ){
+ char *zNew;
+ if( !p->useMalloc ){
+ p->tooBig = 1;
+ N = p->nAlloc - p->nChar - 1;
+ if( N<=0 ){
+ return;
+ }
}else{
- pM->nAlloc = pM->nChar + nNewChar*2 + 1;
- if( pM->zText==pM->zBase ){
- pM->zText = pM->xRealloc(0, pM->nAlloc);
- if( pM->zText && pM->nChar ){
- memcpy(pM->zText, pM->zBase, pM->nChar);
+ p->nAlloc += p->nAlloc + N + 1;
+ if( p->nAlloc > SQLITE_MAX_LENGTH ){
+ p->nAlloc = SQLITE_MAX_LENGTH;
+ if( p->nChar+N >= p->nAlloc ){
+ sqlite3StrAccumReset(p);
+ p->tooBig = 1;
+ return;
}
+ }
+ zNew = sqlite3_malloc( p->nAlloc );
+ if( zNew ){
+ memcpy(zNew, p->zText, p->nChar);
+ sqlite3StrAccumReset(p);
+ p->zText = zNew;
}else{
- char *zNew;
- zNew = pM->xRealloc(pM->zText, pM->nAlloc);
- if( zNew ){
- pM->zText = zNew;
- }
+ p->mallocFailed = 1;
+ sqlite3StrAccumReset(p);
+ return;
}
}
}
- if( pM->zText ){
- if( nNewChar>0 ){
- memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
- pM->nChar += nNewChar;
- }
- pM->zText[pM->nChar] = 0;
- }
+ memcpy(&p->zText[p->nChar], z, N);
+ p->nChar += N;
}
/*
-** This routine is a wrapper around xprintf() that invokes mout() as
-** the consumer.
+** Finish off a string by making sure it is zero-terminated.
+** Return a pointer to the resulting string. Return a NULL
+** pointer if any kind of error was encountered.
*/
-static char *base_vprintf(
- void *(*xRealloc)(void*,int), /* Routine to realloc memory. May be NULL */
- int useInternal, /* Use internal %-conversions if true */
- char *zInitBuf, /* Initially write here, before mallocing */
- int nInitBuf, /* Size of zInitBuf[] */
- const char *zFormat, /* format string */
- va_list ap /* arguments */
-){
- struct sgMprintf sM;
- sM.zBase = sM.zText = zInitBuf;
- sM.nChar = sM.nTotal = 0;
- sM.nAlloc = nInitBuf;
- sM.xRealloc = xRealloc;
- vxprintf(mout, &sM, useInternal, zFormat, ap);
- if( xRealloc ){
- if( sM.zText==sM.zBase ){
- sM.zText = xRealloc(0, sM.nChar+1);
- if( sM.zText ){
- memcpy(sM.zText, sM.zBase, sM.nChar+1);
- }
- }else if( sM.nAlloc>sM.nChar+10 ){
- char *zNew = xRealloc(sM.zText, sM.nChar+1);
- if( zNew ){
- sM.zText = zNew;
+char *sqlite3StrAccumFinish(StrAccum *p){
+ if( p->zText ){
+ p->zText[p->nChar] = 0;
+ if( p->useMalloc && p->zText==p->zBase ){
+ p->zText = sqlite3_malloc( p->nChar+1 );
+ if( p->zText ){
+ memcpy(p->zText, p->zBase, p->nChar+1);
+ }else{
+ p->mallocFailed = 1;
}
}
}
- return sM.zText;
+ return p->zText;
}
/*
-** Realloc that is a real function, not a macro.
+** Reset an StrAccum string. Reclaim all malloced memory.
*/
-static void *printf_realloc(void *old, int size){
- return sqliteRealloc(old,size);
+void sqlite3StrAccumReset(StrAccum *p){
+ if( p->zText!=p->zBase ){
+ sqlite3_free(p->zText);
+ p->zText = 0;
+ }
+}
+
+/*
+** Initialize a string accumulator
+*/
+static void sqlite3StrAccumInit(StrAccum *p, char *zBase, int n){
+ p->zText = p->zBase = zBase;
+ p->nChar = 0;
+ p->nAlloc = n;
+ p->useMalloc = 1;
+ p->tooBig = 0;
+ p->mallocFailed = 0;
}
/*
** Print into memory obtained from sqliteMalloc(). Use the internal
** %-conversion extensions.
*/
-char *sqlite3VMPrintf(const char *zFormat, va_list ap){
+char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){
+ char *z;
char zBase[SQLITE_PRINT_BUF_SIZE];
- return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
+ StrAccum acc;
+ sqlite3StrAccumInit(&acc, zBase, sizeof(zBase));
+ vxprintf(&acc, 1, zFormat, ap);
+ z = sqlite3StrAccumFinish(&acc);
+ if( acc.mallocFailed && db ){
+ db->mallocFailed = 1;
+ }
+ return z;
}
/*
** Print into memory obtained from sqliteMalloc(). Use the internal
** %-conversion extensions.
*/
-char *sqlite3MPrintf(const char *zFormat, ...){
+char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){
va_list ap;
char *z;
- char zBase[SQLITE_PRINT_BUF_SIZE];
va_start(ap, zFormat);
- z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
+ z = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap);
return z;
}
@@ -810,8 +837,13 @@ char *sqlite3MPrintf(const char *zFormat, ...){
** %-conversion extensions.
*/
char *sqlite3_vmprintf(const char *zFormat, va_list ap){
+ char *z;
char zBase[SQLITE_PRINT_BUF_SIZE];
- return base_vprintf(sqlite3_realloc, 0, zBase, sizeof(zBase), zFormat, ap);
+ StrAccum acc;
+ sqlite3StrAccumInit(&acc, zBase, sizeof(zBase));
+ vxprintf(&acc, 0, zFormat, ap);
+ z = sqlite3StrAccumFinish(&acc);
+ return z;
}
/*
@@ -821,9 +853,8 @@ char *sqlite3_vmprintf(const char *zFormat, va_list ap){
char *sqlite3_mprintf(const char *zFormat, ...){
va_list ap;
char *z;
- char zBase[SQLITE_PRINT_BUF_SIZE];
va_start(ap, zFormat);
- z = base_vprintf(sqlite3_realloc, 0, zBase, sizeof(zBase), zFormat, ap);
+ z = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
return z;
}
@@ -837,27 +868,37 @@ char *sqlite3_mprintf(const char *zFormat, ...){
char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
char *z;
va_list ap;
+ StrAccum acc;
+ if( n<=0 ){
+ return zBuf;
+ }
+ sqlite3StrAccumInit(&acc, zBuf, n);
+ acc.useMalloc = 0;
va_start(ap,zFormat);
- z = base_vprintf(0, 0, zBuf, n, zFormat, ap);
+ vxprintf(&acc, 0, zFormat, ap);
va_end(ap);
+ z = sqlite3StrAccumFinish(&acc);
return z;
}
-#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
+#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) || defined(SQLITE_MEMDEBUG)
/*
** A version of printf() that understands %lld. Used for debugging.
** The printf() built into some versions of windows does not understand %lld
** and segfaults if you give it a long long int.
*/
void sqlite3DebugPrintf(const char *zFormat, ...){
- extern int getpid(void);
va_list ap;
+ StrAccum acc;
char zBuf[500];
- va_start(ap, zFormat);
- base_vprintf(0, 0, zBuf, sizeof(zBuf), zFormat, ap);
+ sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf));
+ acc.useMalloc = 0;
+ va_start(ap,zFormat);
+ vxprintf(&acc, 0, zFormat, ap);
va_end(ap);
- fprintf(stdout,"%d: %s", getpid(), zBuf);
+ sqlite3StrAccumFinish(&acc);
+ fprintf(stdout,"%s", zBuf);
fflush(stdout);
}
#endif
diff --git a/ext/pdo_sqlite/sqlite/src/random.c b/ext/pdo_sqlite/sqlite/src/random.c
index 51d5d72e77..466da32de5 100644
--- a/ext/pdo_sqlite/sqlite/src/random.c
+++ b/ext/pdo_sqlite/sqlite/src/random.c
@@ -18,9 +18,17 @@
** $Id$
*/
#include "sqliteInt.h"
-#include "os.h"
+/* All threads share a single random number generator.
+** This structure is the current state of the generator.
+*/
+static struct sqlite3PrngType {
+ unsigned char isInit; /* True if initialized */
+ unsigned char i, j; /* State variables */
+ unsigned char s[256]; /* State variables */
+} sqlite3Prng;
+
/*
** Get a single 8-bit random value from the RC4 PRNG. The Mutex
** must be held while executing this routine.
@@ -37,17 +45,9 @@
** (Later): Actually, OP_NewRowid does not depend on a good source of
** randomness any more. But we will leave this code in all the same.
*/
-static int randomByte(){
+static int randomByte(void){
unsigned char t;
- /* All threads share a single random number generator.
- ** This structure is the current state of the generator.
- */
- static struct {
- unsigned char isInit; /* True if initialized */
- unsigned char i, j; /* State variables */
- unsigned char s[256]; /* State variables */
- } prng;
/* Initialize the state of the random number generator once,
** the first time this routine is called. The seed value does
@@ -58,33 +58,33 @@ static int randomByte(){
** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random
** number generator) not as an encryption device.
*/
- if( !prng.isInit ){
+ if( !sqlite3Prng.isInit ){
int i;
char k[256];
- prng.j = 0;
- prng.i = 0;
- sqlite3OsRandomSeed(k);
+ sqlite3Prng.j = 0;
+ sqlite3Prng.i = 0;
+ sqlite3OsRandomness(sqlite3_vfs_find(0), 256, k);
for(i=0; i<256; i++){
- prng.s[i] = i;
+ sqlite3Prng.s[i] = i;
}
for(i=0; i<256; i++){
- prng.j += prng.s[i] + k[i];
- t = prng.s[prng.j];
- prng.s[prng.j] = prng.s[i];
- prng.s[i] = t;
+ sqlite3Prng.j += sqlite3Prng.s[i] + k[i];
+ t = sqlite3Prng.s[sqlite3Prng.j];
+ sqlite3Prng.s[sqlite3Prng.j] = sqlite3Prng.s[i];
+ sqlite3Prng.s[i] = t;
}
- prng.isInit = 1;
+ sqlite3Prng.isInit = 1;
}
/* Generate and return single random byte
*/
- prng.i++;
- t = prng.s[prng.i];
- prng.j += t;
- prng.s[prng.i] = prng.s[prng.j];
- prng.s[prng.j] = t;
- t += prng.s[prng.i];
- return prng.s[t];
+ sqlite3Prng.i++;
+ t = sqlite3Prng.s[sqlite3Prng.i];
+ sqlite3Prng.j += t;
+ sqlite3Prng.s[sqlite3Prng.i] = sqlite3Prng.s[sqlite3Prng.j];
+ sqlite3Prng.s[sqlite3Prng.j] = t;
+ t += sqlite3Prng.s[sqlite3Prng.i];
+ return sqlite3Prng.s[t];
}
/*
@@ -92,9 +92,30 @@ static int randomByte(){
*/
void sqlite3Randomness(int N, void *pBuf){
unsigned char *zBuf = pBuf;
- sqlite3OsEnterMutex();
+ static sqlite3_mutex *mutex = 0;
+ if( mutex==0 ){
+ mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG);
+ }
+ sqlite3_mutex_enter(mutex);
while( N-- ){
*(zBuf++) = randomByte();
}
- sqlite3OsLeaveMutex();
+ sqlite3_mutex_leave(mutex);
+}
+
+#ifdef SQLITE_TEST
+/*
+** For testing purposes, we sometimes want to preserve the state of
+** PRNG and restore the PRNG to its saved state at a later time.
+*/
+static struct sqlite3PrngType sqlite3SavedPrng;
+void sqlite3SavePrngState(void){
+ memcpy(&sqlite3SavedPrng, &sqlite3Prng, sizeof(sqlite3Prng));
+}
+void sqlite3RestorePrngState(void){
+ memcpy(&sqlite3Prng, &sqlite3SavedPrng, sizeof(sqlite3Prng));
+}
+void sqlite3ResetPrngState(void){
+ sqlite3Prng.isInit = 0;
}
+#endif /* SQLITE_TEST */
diff --git a/ext/pdo_sqlite/sqlite/src/select.c b/ext/pdo_sqlite/sqlite/src/select.c
index 57b415bf58..b3b9291fe0 100644
--- a/ext/pdo_sqlite/sqlite/src/select.c
+++ b/ext/pdo_sqlite/sqlite/src/select.c
@@ -16,6 +16,7 @@
*/
#include "sqliteInt.h"
+
/*
** Delete all the content of a Select structure but do not deallocate
** the select structure itself.
@@ -33,10 +34,22 @@ static void clearSelect(Select *p){
}
/*
+** Initialize a SelectDest structure.
+*/
+void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){
+ pDest->eDest = eDest;
+ pDest->iParm = iParm;
+ pDest->affinity = 0;
+ pDest->iMem = 0;
+}
+
+
+/*
** Allocate a new Select structure and return a pointer to that
** structure.
*/
Select *sqlite3SelectNew(
+ Parse *pParse, /* Parsing context */
ExprList *pEList, /* which columns to include in the result */
SrcList *pSrc, /* the FROM clause -- which tables to scan */
Expr *pWhere, /* the WHERE clause */
@@ -49,14 +62,15 @@ Select *sqlite3SelectNew(
){
Select *pNew;
Select standin;
- pNew = sqliteMalloc( sizeof(*pNew) );
+ sqlite3 *db = pParse->db;
+ pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
assert( !pOffset || pLimit ); /* Can't have OFFSET without LIMIT. */
if( pNew==0 ){
pNew = &standin;
memset(pNew, 0, sizeof(*pNew));
}
if( pEList==0 ){
- pEList = sqlite3ExprListAppend(0, sqlite3Expr(TK_ALL,0,0,0), 0);
+ pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ALL,0,0,0), 0);
}
pNew->pEList = pEList;
pNew->pSrc = pSrc;
@@ -66,6 +80,7 @@ Select *sqlite3SelectNew(
pNew->pOrderBy = pOrderBy;
pNew->isDistinct = isDistinct;
pNew->op = TK_SELECT;
+ assert( pOffset==0 || pLimit!=0 );
pNew->pLimit = pLimit;
pNew->pOffset = pOffset;
pNew->iLimit = -1;
@@ -86,7 +101,7 @@ Select *sqlite3SelectNew(
void sqlite3SelectDelete(Select *p){
if( p ){
clearSelect(p);
- sqliteFree(p);
+ sqlite3_free(p);
}
}
@@ -183,12 +198,28 @@ static void setToken(Token *p, const char *z){
}
/*
+** Set the token to the double-quoted and escaped version of the string pointed
+** to by z. For example;
+**
+** {a"bc} -> {"a""bc"}
+*/
+static void setQuotedToken(Parse *pParse, Token *p, const char *z){
+ p->z = (u8 *)sqlite3MPrintf(0, "\"%w\"", z);
+ p->dyn = 1;
+ if( p->z ){
+ p->n = strlen((char *)p->z);
+ }else{
+ pParse->db->mallocFailed = 1;
+ }
+}
+
+/*
** Create an expression node for an identifier with the name of zName
*/
-Expr *sqlite3CreateIdExpr(const char *zName){
+Expr *sqlite3CreateIdExpr(Parse *pParse, const char *zName){
Token dummy;
setToken(&dummy, zName);
- return sqlite3Expr(TK_ID, 0, 0, &dummy);
+ return sqlite3PExpr(pParse, TK_ID, 0, 0, &dummy);
}
@@ -197,6 +228,7 @@ Expr *sqlite3CreateIdExpr(const char *zName){
** zCol column to be equal in the two tables pTab1 and pTab2.
*/
static void addWhereTerm(
+ Parse *pParse, /* Parsing context */
const char *zCol, /* Name of the column */
const Table *pTab1, /* First table */
const char *zAlias1, /* Alias for first table. May be NULL */
@@ -209,27 +241,24 @@ static void addWhereTerm(
Expr *pE2a, *pE2b, *pE2c;
Expr *pE;
- pE1a = sqlite3CreateIdExpr(zCol);
- pE2a = sqlite3CreateIdExpr(zCol);
+ pE1a = sqlite3CreateIdExpr(pParse, zCol);
+ pE2a = sqlite3CreateIdExpr(pParse, zCol);
if( zAlias1==0 ){
zAlias1 = pTab1->zName;
}
- pE1b = sqlite3CreateIdExpr(zAlias1);
+ pE1b = sqlite3CreateIdExpr(pParse, zAlias1);
if( zAlias2==0 ){
zAlias2 = pTab2->zName;
}
- pE2b = sqlite3CreateIdExpr(zAlias2);
- pE1c = sqlite3ExprOrFree(TK_DOT, pE1b, pE1a, 0);
- pE2c = sqlite3ExprOrFree(TK_DOT, pE2b, pE2a, 0);
- pE = sqlite3ExprOrFree(TK_EQ, pE1c, pE2c, 0);
+ pE2b = sqlite3CreateIdExpr(pParse, zAlias2);
+ pE1c = sqlite3PExpr(pParse, TK_DOT, pE1b, pE1a, 0);
+ pE2c = sqlite3PExpr(pParse, TK_DOT, pE2b, pE2a, 0);
+ pE = sqlite3PExpr(pParse, TK_EQ, pE1c, pE2c, 0);
if( pE ){
ExprSetProperty(pE, EP_FromJoin);
pE->iRightJoinTable = iRightJoinTable;
}
- pE = sqlite3ExprAnd(*ppExpr, pE);
- if( pE ){
- *ppExpr = pE;
- }
+ *ppExpr = sqlite3ExprAnd(pParse->db,*ppExpr, pE);
}
/*
@@ -299,8 +328,8 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
/* When the NATURAL keyword is present, add WHERE clause terms for
** every column that the two tables have in common.
*/
- if( pLeft->jointype & JT_NATURAL ){
- if( pLeft->pOn || pLeft->pUsing ){
+ if( pRight->jointype & JT_NATURAL ){
+ if( pRight->pOn || pRight->pUsing ){
sqlite3ErrorMsg(pParse, "a NATURAL join may not have "
"an ON or USING clause", 0);
return 1;
@@ -308,7 +337,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
for(j=0; j<pLeftTab->nCol; j++){
char *zName = pLeftTab->aCol[j].zName;
if( columnIndex(pRightTab, zName)>=0 ){
- addWhereTerm(zName, pLeftTab, pLeft->zAlias,
+ addWhereTerm(pParse, zName, pLeftTab, pLeft->zAlias,
pRightTab, pRight->zAlias,
pRight->iCursor, &p->pWhere);
@@ -318,7 +347,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
/* Disallow both ON and USING clauses in the same join
*/
- if( pLeft->pOn && pLeft->pUsing ){
+ if( pRight->pOn && pRight->pUsing ){
sqlite3ErrorMsg(pParse, "cannot have both ON and USING "
"clauses in the same join");
return 1;
@@ -327,10 +356,10 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
/* Add the ON clause to the end of the WHERE clause, connected by
** an AND operator.
*/
- if( pLeft->pOn ){
- setJoinExpr(pLeft->pOn, pRight->iCursor);
- p->pWhere = sqlite3ExprAnd(p->pWhere, pLeft->pOn);
- pLeft->pOn = 0;
+ if( pRight->pOn ){
+ setJoinExpr(pRight->pOn, pRight->iCursor);
+ p->pWhere = sqlite3ExprAnd(pParse->db, p->pWhere, pRight->pOn);
+ pRight->pOn = 0;
}
/* Create extra terms on the WHERE clause for each column named
@@ -340,8 +369,8 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
** Report an error if any column mentioned in the USING clause is
** not contained in both tables to be joined.
*/
- if( pLeft->pUsing ){
- IdList *pList = pLeft->pUsing;
+ if( pRight->pUsing ){
+ IdList *pList = pRight->pUsing;
for(j=0; j<pList->nId; j++){
char *zName = pList->a[j].zName;
if( columnIndex(pLeftTab, zName)<0 || columnIndex(pRightTab, zName)<0 ){
@@ -349,7 +378,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
"not present in both tables", zName);
return 1;
}
- addWhereTerm(zName, pLeftTab, pLeft->zAlias,
+ addWhereTerm(pParse, zName, pLeftTab, pLeft->zAlias,
pRightTab, pRight->zAlias,
pRight->iCursor, &p->pWhere);
}
@@ -365,22 +394,34 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
static void pushOntoSorter(
Parse *pParse, /* Parser context */
ExprList *pOrderBy, /* The ORDER BY clause */
- Select *pSelect /* The whole SELECT statement */
+ Select *pSelect, /* The whole SELECT statement */
+ int regData /* Register holding data to be sorted */
){
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);
+ int nExpr = pOrderBy->nExpr;
+ int regBase = sqlite3GetTempRange(pParse, nExpr+2);
+ int regRecord = sqlite3GetTempReg(pParse);
+ sqlite3ExprCodeExprList(pParse, pOrderBy, regBase);
+ sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr);
+ sqlite3VdbeAddOp2(v, OP_Move, regData, regBase+nExpr+1);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, pOrderBy->iECursor, regRecord);
+ sqlite3ReleaseTempReg(pParse, regRecord);
+ sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
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);
+ int iLimit;
+ if( pSelect->pOffset ){
+ iLimit = pSelect->iOffset+1;
+ }else{
+ iLimit = pSelect->iLimit;
+ }
+ addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, iLimit);
+ sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1);
+ addr2 = sqlite3VdbeAddOp0(v, OP_Goto);
sqlite3VdbeJumpHere(v, addr1);
- sqlite3VdbeAddOp(v, OP_Last, pOrderBy->iECursor, 0);
- sqlite3VdbeAddOp(v, OP_Delete, pOrderBy->iECursor, 0);
+ sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor);
+ sqlite3VdbeAddOp1(v, OP_Delete, pOrderBy->iECursor);
sqlite3VdbeJumpHere(v, addr2);
pSelect->iLimit = -1;
}
@@ -392,25 +433,21 @@ static void pushOntoSorter(
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 nPop /* Number of times to pop stack when jumping */
+ int iContinue /* Jump here to skip the current record */
){
if( p->iOffset>=0 && iContinue!=0 ){
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"));
+ sqlite3VdbeAddOp2(v, OP_AddImm, p->iOffset, -1);
+ addr = sqlite3VdbeAddOp1(v, OP_IfNeg, p->iOffset);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue);
+ VdbeComment((v, "skip OFFSET records"));
sqlite3VdbeJumpHere(v, addr);
}
}
/*
-** Add code that will check to make sure the top N elements of the
-** stack are distinct. iTab is a sorting index that holds previously
+** Add code that will check to make sure the N registers starting at iMem
+** form a distinct entry. iTab is a sorting index that holds previously
** seen combinations of the N values. A new entry is made in iTab
** if the current N values are new.
**
@@ -418,19 +455,43 @@ static void codeOffset(
** stack if the top N elements are not distinct.
*/
static void codeDistinct(
- Vdbe *v, /* Generate code into this VM */
+ Parse *pParse, /* Parsing and code generating context */
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 N, /* Number of elements */
+ int iMem /* First element */
){
- sqlite3VdbeAddOp(v, OP_MakeRecord, -N, 0);
- sqlite3VdbeAddOp(v, OP_Distinct, iTab, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Pop, N+1, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, addrRepeat);
- VdbeComment((v, "# skip indistinct records"));
- sqlite3VdbeAddOp(v, OP_IdxInsert, iTab, 0);
+ Vdbe *v;
+ int r1;
+
+ v = pParse->pVdbe;
+ r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1);
+ sqlite3VdbeAddOp3(v, OP_Found, iTab, addrRepeat, r1);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1);
+ sqlite3ReleaseTempReg(pParse, r1);
}
+/*
+** Generate an error message when a SELECT is used within a subexpression
+** (example: "a IN (SELECT * FROM table)") but it has more than 1 result
+** column. We do this in a subroutine because the error occurs in multiple
+** places.
+*/
+static int checkForMultiColumnSelectError(
+ Parse *pParse, /* Parse context. */
+ SelectDest *pDest, /* Destination of SELECT results */
+ int nExpr /* Number of result columns returned by SELECT */
+){
+ int eDest = pDest->eDest;
+ if( nExpr>1 && (eDest==SRT_Mem || eDest==SRT_Set) ){
+ sqlite3ErrorMsg(pParse, "only a single result allowed for "
+ "a SELECT that is part of an expression");
+ return 1;
+ }else{
+ return 0;
+ }
+}
/*
** This routine generates the code for the inside of the inner loop
@@ -441,7 +502,7 @@ static void codeDistinct(
** then data is pulled from srcTab and pEList is used only to get the
** datatypes for each column.
*/
-static int selectInnerLoop(
+static void selectInnerLoop(
Parse *pParse, /* The parser context */
Select *p, /* The complete select statement being coded */
ExprList *pEList, /* List of values being extracted */
@@ -449,8 +510,7 @@ static int selectInnerLoop(
int nColumn, /* Number of columns in the source table */
ExprList *pOrderBy, /* If not NULL, sort results using this key */
int distinct, /* If >=0, make sure results are distinct */
- int eDest, /* How to dispose of the results */
- int iParm, /* An argument to the disposal method */
+ SelectDest *pDest, /* How to dispose of the results */
int iContinue, /* Jump here to continue with next row */
int iBreak, /* Jump here to break out of the inner loop */
char *aff /* affinity string if eDest is SRT_Union */
@@ -458,8 +518,13 @@ static int selectInnerLoop(
Vdbe *v = pParse->pVdbe;
int i;
int hasDistinct; /* True if the DISTINCT keyword is present */
+ int regResult; /* Start of memory holding result set */
+ int eDest = pDest->eDest; /* How to dispose of results */
+ int iParm = pDest->iParm; /* First argument to disposal method */
+ int nResultCol; /* Number of result columns */
+ int nToFree; /* Number of result columns to release */
- if( v==0 ) return 0;
+ if( v==0 ) return;
assert( pEList!=0 );
/* If there was a LIMIT clause on the SELECT statement, then do the check
@@ -467,19 +532,36 @@ static int selectInnerLoop(
*/
hasDistinct = distinct>=0 && pEList->nExpr>0;
if( pOrderBy==0 && !hasDistinct ){
- codeOffset(v, p, iContinue, 0);
+ codeOffset(v, p, iContinue);
}
/* Pull the requested columns.
*/
if( nColumn>0 ){
+ nResultCol = nColumn;
+ }else{
+ nResultCol = pEList->nExpr;
+ }
+ if( pDest->iMem>0 ){
+ regResult = pDest->iMem;
+ nToFree = 0;
+ }else{
+ pDest->iMem = regResult = sqlite3GetTempRange(pParse, nResultCol);
+ nToFree = nResultCol;
+ }
+ if( nColumn>0 ){
for(i=0; i<nColumn; i++){
- sqlite3VdbeAddOp(v, OP_Column, srcTab, i);
+ sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i);
+ }
+ }else if( eDest!=SRT_Exists ){
+ /* If the destination is an EXISTS(...) expression, the actual
+ ** values returned by the SELECT are not required.
+ */
+ for(i=0; i<nResultCol; i++){
+ sqlite3ExprCode(pParse, pEList->a[i].pExpr, regResult+i);
}
- }else{
- nColumn = pEList->nExpr;
- sqlite3ExprCodeExprList(pParse, pEList);
}
+ nColumn = nResultCol;
/* If the DISTINCT keyword was present on the SELECT statement
** and this row has been seen before, then do not make this row
@@ -488,23 +570,30 @@ static int selectInnerLoop(
if( hasDistinct ){
assert( pEList!=0 );
assert( pEList->nExpr==nColumn );
- codeDistinct(v, distinct, iContinue, nColumn);
+ codeDistinct(pParse, distinct, iContinue, nColumn, regResult);
if( pOrderBy==0 ){
- codeOffset(v, p, iContinue, nColumn);
+ codeOffset(v, p, iContinue);
}
}
+ if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){
+ return;
+ }
+
switch( eDest ){
/* In this mode, write each query result to the key of the temporary
** table iParm.
*/
#ifndef SQLITE_OMIT_COMPOUND_SELECT
case SRT_Union: {
- sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
+ int r1;
+ r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nColumn, r1);
if( aff ){
- sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC);
+ sqlite3VdbeChangeP4(v, -1, aff, P4_STATIC);
}
- sqlite3VdbeAddOp(v, OP_IdxInsert, iParm, 0);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
+ sqlite3ReleaseTempReg(pParse, r1);
break;
}
@@ -513,11 +602,12 @@ static int selectInnerLoop(
** the temporary table iParm.
*/
case SRT_Except: {
- int addr;
- 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);
+ int r1;
+ r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nColumn, r1);
+ sqlite3VdbeChangeP4(v, -1, aff, P4_STATIC);
+ sqlite3VdbeAddOp2(v, OP_IdxDelete, iParm, r1);
+ sqlite3ReleaseTempReg(pParse, r1);
break;
}
#endif
@@ -526,14 +616,18 @@ static int selectInnerLoop(
*/
case SRT_Table:
case SRT_EphemTab: {
- sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
+ int r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nColumn, r1);
if( pOrderBy ){
- pushOntoSorter(pParse, pOrderBy, p);
+ pushOntoSorter(pParse, pOrderBy, p, r1);
}else{
- sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0);
- sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
- sqlite3VdbeAddOp(v, OP_Insert, iParm, 0);
+ int r2 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
+ sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2);
+ sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
+ sqlite3ReleaseTempReg(pParse, r2);
}
+ sqlite3ReleaseTempReg(pParse, r1);
break;
}
@@ -543,24 +637,22 @@ static int selectInnerLoop(
** item into the set table with bogus data.
*/
case SRT_Set: {
- int addr1 = sqlite3VdbeCurrentAddr(v);
int addr2;
assert( nColumn==1 );
- sqlite3VdbeAddOp(v, OP_NotNull, -1, addr1+3);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
+ addr2 = sqlite3VdbeAddOp1(v, OP_IsNull, regResult);
+ p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affinity);
if( pOrderBy ){
/* At first glance you would think we could optimize out the
** 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, pOrderBy, p);
+ pushOntoSorter(pParse, pOrderBy, p, regResult);
}else{
- 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);
+ int r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, 1, r1, &p->affinity, 1);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
+ sqlite3ReleaseTempReg(pParse, r1);
}
sqlite3VdbeJumpHere(v, addr2);
break;
@@ -569,8 +661,7 @@ static int selectInnerLoop(
/* 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);
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, iParm);
/* The LIMIT clause will terminate the loop for us */
break;
}
@@ -582,9 +673,9 @@ static int selectInnerLoop(
case SRT_Mem: {
assert( nColumn==1 );
if( pOrderBy ){
- pushOntoSorter(pParse, pOrderBy, p);
+ pushOntoSorter(pParse, pOrderBy, p, regResult);
}else{
- sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1);
+ sqlite3VdbeAddOp2(v, OP_Move, regResult, iParm);
/* The LIMIT clause will jump out of the loop for us */
}
break;
@@ -598,12 +689,15 @@ static int selectInnerLoop(
case SRT_Subroutine:
case SRT_Callback: {
if( pOrderBy ){
- sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
- pushOntoSorter(pParse, pOrderBy, p);
+ int r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nColumn, r1);
+ pushOntoSorter(pParse, pOrderBy, p, r1);
+ sqlite3ReleaseTempReg(pParse, r1);
}else if( eDest==SRT_Subroutine ){
- sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm);
+ nToFree = 0; /* Preserve registers. Subroutine will need them. */
+ sqlite3VdbeAddOp2(v, OP_Gosub, 0, iParm);
}else{
- sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nColumn);
}
break;
}
@@ -616,7 +710,6 @@ static int selectInnerLoop(
*/
default: {
assert( eDest==SRT_Discard );
- sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0);
break;
}
#endif
@@ -625,10 +718,10 @@ static int selectInnerLoop(
/* 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);
+ sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1);
+ sqlite3VdbeAddOp2(v, OP_IfZero, p->iLimit, iBreak);
}
- return 0;
+ sqlite3ReleaseTempRange(pParse, regResult, nToFree);
}
/*
@@ -643,8 +736,8 @@ static int selectInnerLoop(
**
** Space to hold the KeyInfo structure is obtain from malloc. The calling
** function is responsible for seeing that this structure is eventually
-** freed. Add the KeyInfo structure to the P3 field of an opcode using
-** P3_KEYINFO_HANDOFF is the usual way of dealing with this.
+** freed. Add the KeyInfo structure to the P4 field of an opcode using
+** P4_KEYINFO_HANDOFF is the usual way of dealing with this.
*/
static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){
sqlite3 *db = pParse->db;
@@ -654,7 +747,7 @@ static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){
int i;
nExpr = pList->nExpr;
- pInfo = sqliteMalloc( sizeof(*pInfo) + nExpr*(sizeof(CollSeq*)+1) );
+ pInfo = sqlite3DbMallocZero(db, sizeof(*pInfo) + nExpr*(sizeof(CollSeq*)+1) );
if( pInfo ){
pInfo->aSortOrder = (u8*)&pInfo->aColl[nExpr];
pInfo->nField = nExpr;
@@ -680,53 +773,57 @@ static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){
** routine generates the code needed to do that.
*/
static void generateSortTail(
- Parse *pParse, /* Parsing context */
- Select *p, /* The SELECT statement */
- Vdbe *v, /* Generate code into this VDBE */
- int nColumn, /* Number of columns of data */
- int eDest, /* Write the sorted results here */
- int iParm /* Optional parameter associated with eDest */
+ Parse *pParse, /* Parsing context */
+ Select *p, /* The SELECT statement */
+ Vdbe *v, /* Generate code into this VDBE */
+ int nColumn, /* Number of columns of data */
+ SelectDest *pDest /* Write the sorted results here */
){
int brk = sqlite3VdbeMakeLabel(v);
int cont = sqlite3VdbeMakeLabel(v);
int addr;
int iTab;
- int pseudoTab;
+ int pseudoTab = 0;
ExprList *pOrderBy = p->pOrderBy;
+ int eDest = pDest->eDest;
+ int iParm = pDest->iParm;
+
+ int regRow;
+ int regRowid;
+
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);
- 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);
+ sqlite3VdbeAddOp2(v, OP_OpenPseudo, pseudoTab, 0);
+ sqlite3VdbeAddOp2(v, OP_SetNumColumns, pseudoTab, nColumn);
+ }
+ addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, brk);
+ codeOffset(v, p, cont);
+ regRow = sqlite3GetTempReg(pParse);
+ regRowid = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr + 1, regRow);
switch( eDest ){
case SRT_Table:
case SRT_EphemTab: {
- sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0);
- sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
- sqlite3VdbeAddOp(v, OP_Insert, iParm, 0);
+ sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid);
+ sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, regRowid);
+ sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
case SRT_Set: {
+ int j1;
assert( nColumn==1 );
- 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, "c", P3_STATIC);
- sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0);
+ j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regRow);
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRow, &p->affinity, 1);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRow);
+ sqlite3VdbeJumpHere(v, j1);
break;
}
case SRT_Mem: {
assert( nColumn==1 );
- sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1);
+ sqlite3VdbeAddOp2(v, OP_Move, regRow, iParm);
/* The LIMIT clause will terminate the loop for us */
break;
}
@@ -734,14 +831,15 @@ static void generateSortTail(
case SRT_Callback:
case SRT_Subroutine: {
int i;
- sqlite3VdbeAddOp(v, OP_Insert, pseudoTab, 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, regRowid);
+ sqlite3VdbeAddOp3(v, OP_Insert, pseudoTab, regRow, regRowid);
for(i=0; i<nColumn; i++){
- sqlite3VdbeAddOp(v, OP_Column, pseudoTab, i);
+ sqlite3VdbeAddOp3(v, OP_Column, pseudoTab, i, pDest->iMem+i);
}
if( eDest==SRT_Callback ){
- sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iMem, nColumn);
}else{
- sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm);
+ sqlite3VdbeAddOp2(v, OP_Gosub, 0, iParm);
}
break;
}
@@ -750,21 +848,23 @@ static void generateSortTail(
break;
}
}
+ sqlite3ReleaseTempReg(pParse, regRow);
+ sqlite3ReleaseTempReg(pParse, regRowid);
/* 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);
+ sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1);
+ sqlite3VdbeAddOp2(v, OP_IfZero, p->iLimit, brk);
}
/* The bottom of the loop
*/
sqlite3VdbeResolveLabel(v, cont);
- sqlite3VdbeAddOp(v, OP_Next, iTab, addr);
+ sqlite3VdbeAddOp2(v, OP_Next, iTab, addr);
sqlite3VdbeResolveLabel(v, brk);
if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
- sqlite3VdbeAddOp(v, OP_Close, pseudoTab, 0);
+ sqlite3VdbeAddOp2(v, OP_Close, pseudoTab, 0);
}
}
@@ -801,12 +901,6 @@ static const char *columnType(
int j;
if( pExpr==0 || pNC->pSrcList==0 ) return 0;
- /* The TK_AS operator can only occur in ORDER BY, GROUP BY, HAVING,
- ** and LIMIT clauses. But pExpr originates in the result set of a
- ** SELECT. So pExpr can never contain an AS operator.
- */
- assert( pExpr->op!=TK_AS );
-
switch( pExpr->op ){
case TK_AGG_COLUMN:
case TK_COLUMN: {
@@ -929,14 +1023,14 @@ static void generateColumnTypes(
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
+ /* The vdbe must make its 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, 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);
+ sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, P4_TRANSIENT);
+ sqlite3VdbeSetColName(v, i, COLNAME_DATABASE, zOrigDb, P4_TRANSIENT);
+ sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, P4_TRANSIENT);
+ sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, P4_TRANSIENT);
}
}
@@ -963,7 +1057,7 @@ static void generateColumnNames(
#endif
assert( v!=0 );
- if( pParse->colNamesSet || v==0 || sqlite3MallocFailed() ) return;
+ if( pParse->colNamesSet || v==0 || db->mallocFailed ) return;
pParse->colNamesSet = 1;
fullNames = (db->flags & SQLITE_FullColNames)!=0;
shortNames = (db->flags & SQLITE_ShortColNames)!=0;
@@ -1000,7 +1094,7 @@ static void generateColumnNames(
zTab = pTabList->a[j].zAlias;
if( fullNames || zTab==0 ) zTab = pTab->zName;
sqlite3SetString(&zName, zTab, ".", zCol, (char*)0);
- sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, P3_DYNAMIC);
+ sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, P4_DYNAMIC);
}else{
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, strlen(zCol));
}
@@ -1010,7 +1104,7 @@ static void generateColumnNames(
}else{
char zName[30];
assert( p->op!=TK_COLUMN || pTabList==0 );
- sprintf(zName, "column%d", i+1);
+ sqlite3_snprintf(sizeof(zName), zName, "column%d", i+1);
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, 0);
}
}
@@ -1047,6 +1141,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
int i, j;
ExprList *pEList;
Column *aCol, *pCol;
+ sqlite3 *db = pParse->db;
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
if( prepSelectStmt(pParse, pSelect) ){
@@ -1055,21 +1150,21 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
if( sqlite3SelectResolve(pParse, pSelect, 0) ){
return 0;
}
- pTab = sqliteMalloc( sizeof(Table) );
+ pTab = sqlite3DbMallocZero(db, sizeof(Table) );
if( pTab==0 ){
return 0;
}
pTab->nRef = 1;
- pTab->zName = zTabName ? sqliteStrDup(zTabName) : 0;
+ pTab->zName = zTabName ? sqlite3DbStrDup(db, zTabName) : 0;
pEList = pSelect->pEList;
pTab->nCol = pEList->nExpr;
assert( pTab->nCol>0 );
- pTab->aCol = aCol = sqliteMalloc( sizeof(pTab->aCol[0])*pTab->nCol );
+ pTab->aCol = aCol = sqlite3DbMallocZero(db, sizeof(pTab->aCol[0])*pTab->nCol);
for(i=0, pCol=aCol; i<pTab->nCol; i++, pCol++){
Expr *p, *pR;
char *zType;
char *zName;
- char *zBasename;
+ int nName;
CollSeq *pColl;
int cnt;
NameContext sNC;
@@ -1080,39 +1175,38 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
assert( p->pRight==0 || p->pRight->token.z==0 || p->pRight->token.z[0]!=0 );
if( (zName = pEList->a[i].zName)!=0 ){
/* If the column contains an "AS <name>" phrase, use <name> as the name */
- zName = sqliteStrDup(zName);
+ zName = sqlite3DbStrDup(db, zName);
}else if( p->op==TK_DOT
&& (pR=p->pRight)!=0 && pR->token.z && pR->token.z[0] ){
/* For columns of the from A.B use B as the name */
- zName = sqlite3MPrintf("%T", &pR->token);
+ zName = sqlite3MPrintf(db, "%T", &pR->token);
}else if( p->span.z && p->span.z[0] ){
/* Use the original text of the column expression as its name */
- zName = sqlite3MPrintf("%T", &p->span);
+ zName = sqlite3MPrintf(db, "%T", &p->span);
}else{
/* If all else fails, make up a name */
- zName = sqlite3MPrintf("column%d", i+1);
+ zName = sqlite3MPrintf(db, "column%d", i+1);
}
- sqlite3Dequote(zName);
- if( sqlite3MallocFailed() ){
- sqliteFree(zName);
- sqlite3DeleteTable(0, pTab);
+ if( !zName || db->mallocFailed ){
+ db->mallocFailed = 1;
+ sqlite3_free(zName);
+ sqlite3DeleteTable(pTab);
return 0;
}
+ sqlite3Dequote(zName);
/* Make sure the column name is unique. If the name is not unique,
** append a integer to the name so that it becomes unique.
*/
- zBasename = zName;
+ nName = strlen(zName);
for(j=cnt=0; j<i; j++){
if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
- zName = sqlite3MPrintf("%s:%d", zBasename, ++cnt);
+ zName[nName] = 0;
+ zName = sqlite3MPrintf(db, "%z:%d", zName, ++cnt);
j = -1;
if( zName==0 ) break;
}
}
- if( zBasename!=zName ){
- sqliteFree(zBasename);
- }
pCol->zName = zName;
/* Get the typename, type affinity, and collating sequence for the
@@ -1120,12 +1214,12 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
*/
memset(&sNC, 0, sizeof(sNC));
sNC.pSrcList = pSelect->pSrc;
- zType = sqliteStrDup(columnType(&sNC, p, 0, 0, 0));
+ zType = sqlite3DbStrDup(db, columnType(&sNC, p, 0, 0, 0));
pCol->zType = zType;
pCol->affinity = sqlite3ExprAffinity(p);
pColl = sqlite3ExprCollSeq(pParse, p);
if( pColl ){
- pCol->zColl = sqliteStrDup(pColl->zName);
+ pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
}
}
pTab->iPKey = -1;
@@ -1163,8 +1257,9 @@ static int prepSelectStmt(Parse *pParse, Select *p){
SrcList *pTabList;
ExprList *pEList;
struct SrcList_item *pFrom;
+ sqlite3 *db = pParse->db;
- if( p==0 || p->pSrc==0 || sqlite3MallocFailed() ){
+ if( p==0 || p->pSrc==0 || db->mallocFailed ){
return 1;
}
pTabList = p->pSrc;
@@ -1193,7 +1288,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){
assert( pFrom->pSelect!=0 );
if( pFrom->zAlias==0 ){
pFrom->zAlias =
- sqlite3MPrintf("sqlite_subquery_%p_", (void*)pFrom->pSelect);
+ sqlite3MPrintf(db, "sqlite_subquery_%p_", (void*)pFrom->pSelect);
}
assert( pFrom->pTab==0 );
pFrom->pTab = pTab =
@@ -1211,7 +1306,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){
/* An ordinary table or view name in the FROM clause */
assert( pFrom->pTab==0 );
pFrom->pTab = pTab =
- sqlite3LocateTable(pParse,pFrom->zName,pFrom->zDatabase);
+ sqlite3LocateTable(pParse,0,pFrom->zName,pFrom->zDatabase);
if( pTab==0 ){
return 1;
}
@@ -1228,7 +1323,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){
** in the inner view.
*/
if( pFrom->pSelect==0 ){
- pFrom->pSelect = sqlite3SelectDup(pTab->pSelect);
+ pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect);
}
}
#endif
@@ -1274,7 +1369,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){
(pE->op!=TK_DOT || pE->pRight==0 || pE->pRight->op!=TK_ALL) ){
/* This particular expression does not need to be expanded.
*/
- pNew = sqlite3ExprListAppend(pNew, a[k].pExpr, 0);
+ pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr, 0);
if( pNew ){
pNew->a[pNew->nExpr-1].zName = a[k].zName;
}else{
@@ -1288,7 +1383,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){
int tableSeen = 0; /* Set to 1 when TABLE matches */
char *zTName; /* text of name of TABLE */
if( pE->op==TK_DOT && pE->pLeft ){
- zTName = sqlite3NameFromToken(&pE->pLeft->token);
+ zTName = sqlite3NameFromToken(db, &pE->pLeft->token);
}else{
zTName = 0;
}
@@ -1307,29 +1402,39 @@ static int prepSelectStmt(Parse *pParse, Select *p){
Expr *pExpr, *pRight;
char *zName = pTab->aCol[j].zName;
+ /* If a column is marked as 'hidden' (currently only possible
+ ** for virtual tables), do not include it in the expanded
+ ** result-set list.
+ */
+ if( IsHiddenColumn(&pTab->aCol[j]) ){
+ assert(IsVirtual(pTab));
+ continue;
+ }
+
if( i>0 ){
struct SrcList_item *pLeft = &pTabList->a[i-1];
- if( (pLeft->jointype & JT_NATURAL)!=0 &&
+ if( (pLeft[1].jointype & JT_NATURAL)!=0 &&
columnIndex(pLeft->pTab, zName)>=0 ){
/* In a NATURAL join, omit the join columns from the
** table on the right */
continue;
}
- if( sqlite3IdListIndex(pLeft->pUsing, zName)>=0 ){
+ if( sqlite3IdListIndex(pLeft[1].pUsing, zName)>=0 ){
/* In a join with a USING clause, omit columns in the
** using clause from the table on the right. */
continue;
}
}
- pRight = sqlite3Expr(TK_ID, 0, 0, 0);
+ pRight = sqlite3PExpr(pParse, TK_ID, 0, 0, 0);
if( pRight==0 ) break;
- setToken(&pRight->token, zName);
+ setQuotedToken(pParse, &pRight->token, zName);
if( zTabName && (longNames || pTabList->nSrc>1) ){
- Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, 0);
- pExpr = sqlite3Expr(TK_DOT, pLeft, pRight, 0);
+ Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, 0);
+ pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
if( pExpr==0 ) break;
- setToken(&pLeft->token, zTabName);
- setToken(&pExpr->span, sqlite3MPrintf("%s.%s", zTabName, zName));
+ setQuotedToken(pParse, &pLeft->token, zTabName);
+ setToken(&pExpr->span,
+ sqlite3MPrintf(db, "%s.%s", zTabName, zName));
pExpr->span.dyn = 1;
pExpr->token.z = 0;
pExpr->token.n = 0;
@@ -1337,11 +1442,12 @@ static int prepSelectStmt(Parse *pParse, Select *p){
}else{
pExpr = pRight;
pExpr->span = pExpr->token;
+ pExpr->span.dyn = 0;
}
if( longNames ){
- pNew = sqlite3ExprListAppend(pNew, pExpr, &pExpr->span);
+ pNew = sqlite3ExprListAppend(pParse, pNew, pExpr, &pExpr->span);
}else{
- pNew = sqlite3ExprListAppend(pNew, pExpr, &pRight->token);
+ pNew = sqlite3ExprListAppend(pParse, pNew, pExpr, &pRight->token);
}
}
}
@@ -1353,100 +1459,268 @@ static int prepSelectStmt(Parse *pParse, Select *p){
}
rc = 1;
}
- sqliteFree(zTName);
+ sqlite3_free(zTName);
}
}
sqlite3ExprListDelete(pEList);
p->pEList = pNew;
}
+ if( p->pEList && p->pEList->nExpr>SQLITE_MAX_COLUMN ){
+ sqlite3ErrorMsg(pParse, "too many columns in result set");
+ rc = SQLITE_ERROR;
+ }
+ if( db->mallocFailed ){
+ rc = SQLITE_NOMEM;
+ }
return rc;
}
-#ifndef SQLITE_OMIT_COMPOUND_SELECT
/*
-** This routine associates entries in an ORDER BY expression list with
-** columns in a result. For each ORDER BY expression, the opcode of
-** the top-level node is changed to TK_COLUMN and the iColumn value of
-** the top-level node is filled in with column number and the iTable
-** value of the top-level node is filled with iTable parameter.
+** pE is a pointer to an expression which is a single term in
+** ORDER BY or GROUP BY clause.
**
-** If there are prior SELECT clauses, they are processed first. A match
-** in an earlier SELECT takes precedence over a later SELECT.
+** If pE evaluates to an integer constant i, then return i.
+** This is an indication to the caller that it should sort
+** by the i-th column of the result set.
**
-** Any entry that does not match is flagged as an error. The number
-** of errors is returned.
+** If pE is a well-formed expression and the SELECT statement
+** is not compound, then return 0. This indicates to the
+** caller that it should sort by the value of the ORDER BY
+** expression.
+**
+** If the SELECT is compound, then attempt to match pE against
+** result set columns in the left-most SELECT statement. Return
+** the index i of the matching column, as an indication to the
+** caller that it should sort by the i-th column. If there is
+** no match, return -1 and leave an error message in pParse.
*/
-static int matchOrderbyToColumn(
- Parse *pParse, /* A place to leave error messages */
- Select *pSelect, /* Match to result columns of this SELECT */
- ExprList *pOrderBy, /* The ORDER BY values to match against columns */
- int iTable, /* Insert this value in iTable */
- int mustComplete /* If TRUE all ORDER BYs must match */
+static int matchOrderByTermToExprList(
+ Parse *pParse, /* Parsing context for error messages */
+ Select *pSelect, /* The SELECT statement with the ORDER BY clause */
+ Expr *pE, /* The specific ORDER BY term */
+ int idx, /* When ORDER BY term is this */
+ int isCompound, /* True if this is a compound SELECT */
+ u8 *pHasAgg /* True if expression contains aggregate functions */
){
- int nErr = 0;
- int i, j;
- ExprList *pEList;
+ int i; /* Loop counter */
+ ExprList *pEList; /* The columns of the result set */
+ NameContext nc; /* Name context for resolving pE */
+
- if( pSelect==0 || pOrderBy==0 ) return 1;
- if( mustComplete ){
- for(i=0; i<pOrderBy->nExpr; i++){ pOrderBy->a[i].done = 0; }
+ /* If the term is an integer constant, return the value of that
+ ** constant */
+ pEList = pSelect->pEList;
+ if( sqlite3ExprIsInteger(pE, &i) ){
+ if( i<=0 ){
+ /* If i is too small, make it too big. That way the calling
+ ** function still sees a value that is out of range, but does
+ ** not confuse the column number with 0 or -1 result code.
+ */
+ i = pEList->nExpr+1;
+ }
+ return i;
}
- if( prepSelectStmt(pParse, pSelect) ){
- return 1;
+
+ /* If the term is a simple identifier that try to match that identifier
+ ** against a column name in the result set.
+ */
+ if( pE->op==TK_ID || (pE->op==TK_STRING && pE->token.z[0]!='\'') ){
+ sqlite3 *db = pParse->db;
+ char *zCol = sqlite3NameFromToken(db, &pE->token);
+ if( zCol==0 ){
+ return -1;
+ }
+ for(i=0; i<pEList->nExpr; i++){
+ char *zAs = pEList->a[i].zName;
+ if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
+ sqlite3_free(zCol);
+ return i+1;
+ }
+ }
+ sqlite3_free(zCol);
}
- if( pSelect->pPrior ){
- if( matchOrderbyToColumn(pParse, pSelect->pPrior, pOrderBy, iTable, 0) ){
- return 1;
+
+ /* Resolve all names in the ORDER BY term expression
+ */
+ memset(&nc, 0, sizeof(nc));
+ nc.pParse = pParse;
+ nc.pSrcList = pSelect->pSrc;
+ nc.pEList = pEList;
+ nc.allowAgg = 1;
+ nc.nErr = 0;
+ if( sqlite3ExprResolveNames(&nc, pE) ){
+ if( isCompound ){
+ sqlite3ErrorClear(pParse);
+ return 0;
+ }else{
+ return -1;
+ }
+ }
+ if( nc.hasAgg && pHasAgg ){
+ *pHasAgg = 1;
+ }
+
+ /* For a compound SELECT, we need to try to match the ORDER BY
+ ** expression against an expression in the result set
+ */
+ if( isCompound ){
+ for(i=0; i<pEList->nExpr; i++){
+ if( sqlite3ExprCompare(pEList->a[i].pExpr, pE) ){
+ return i+1;
+ }
}
}
+ return 0;
+}
+
+
+/*
+** Analyze and ORDER BY or GROUP BY clause in a simple SELECT statement.
+** Return the number of errors seen.
+**
+** Every term of the ORDER BY or GROUP BY clause needs to be an
+** expression. If any expression is an integer constant, then
+** that expression is replaced by the corresponding
+** expression from the result set.
+*/
+static int processOrderGroupBy(
+ Parse *pParse, /* Parsing context. Leave error messages here */
+ Select *pSelect, /* The SELECT statement containing the clause */
+ ExprList *pOrderBy, /* The ORDER BY or GROUP BY clause to be processed */
+ int isOrder, /* 1 for ORDER BY. 0 for GROUP BY */
+ u8 *pHasAgg /* Set to TRUE if any term contains an aggregate */
+){
+ int i;
+ sqlite3 *db = pParse->db;
+ ExprList *pEList;
+
+ if( pOrderBy==0 || pParse->db->mallocFailed ) return 0;
+ if( pOrderBy->nExpr>SQLITE_MAX_COLUMN ){
+ const char *zType = isOrder ? "ORDER" : "GROUP";
+ sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType);
+ return 1;
+ }
pEList = pSelect->pEList;
+ if( pEList==0 ){
+ return 0;
+ }
for(i=0; i<pOrderBy->nExpr; i++){
+ int iCol;
Expr *pE = pOrderBy->a[i].pExpr;
- int iCol = -1;
- if( pOrderBy->a[i].done ) continue;
- if( sqlite3ExprIsInteger(pE, &iCol) ){
- if( iCol<=0 || iCol>pEList->nExpr ){
- sqlite3ErrorMsg(pParse,
- "ORDER BY position %d should be between 1 and %d",
- iCol, pEList->nExpr);
- nErr++;
- break;
+ iCol = matchOrderByTermToExprList(pParse, pSelect, pE, i+1, 0, pHasAgg);
+ if( iCol<0 ){
+ return 1;
+ }
+ if( iCol>pEList->nExpr ){
+ const char *zType = isOrder ? "ORDER" : "GROUP";
+ sqlite3ErrorMsg(pParse,
+ "%r %s BY term out of range - should be "
+ "between 1 and %d", i+1, zType, pEList->nExpr);
+ return 1;
+ }
+ if( iCol>0 ){
+ CollSeq *pColl = pE->pColl;
+ int flags = pE->flags & EP_ExpCollate;
+ sqlite3ExprDelete(pE);
+ pE = sqlite3ExprDup(db, pEList->a[iCol-1].pExpr);
+ pOrderBy->a[i].pExpr = pE;
+ if( pE && pColl && flags ){
+ pE->pColl = pColl;
+ pE->flags |= flags;
}
- if( !mustComplete ) continue;
- iCol--;
- }
- for(j=0; iCol<0 && j<pEList->nExpr; j++){
- if( pEList->a[j].zName && (pE->op==TK_ID || pE->op==TK_STRING) ){
- char *zName, *zLabel;
- zName = pEList->a[j].zName;
- zLabel = sqlite3NameFromToken(&pE->token);
- assert( zLabel!=0 );
- if( sqlite3StrICmp(zName, zLabel)==0 ){
- iCol = j;
- }
- sqliteFree(zLabel);
+ }
+ }
+ return 0;
+}
+
+/*
+** Analyze and ORDER BY or GROUP BY clause in a SELECT statement. Return
+** the number of errors seen.
+**
+** The processing depends on whether the SELECT is simple or compound.
+** For a simple SELECT statement, evry term of the ORDER BY or GROUP BY
+** clause needs to be an expression. If any expression is an integer
+** constant, then that expression is replaced by the corresponding
+** expression from the result set.
+**
+** For compound SELECT statements, every expression needs to be of
+** type TK_COLUMN with a iTable value as given in the 4th parameter.
+** If any expression is an integer, that becomes the column number.
+** Otherwise, match the expression against result set columns from
+** the left-most SELECT.
+*/
+static int processCompoundOrderBy(
+ Parse *pParse, /* Parsing context. Leave error messages here */
+ Select *pSelect, /* The SELECT statement containing the ORDER BY */
+ int iTable /* Output table for compound SELECT statements */
+){
+ int i;
+ ExprList *pOrderBy;
+ ExprList *pEList;
+ sqlite3 *db;
+ int moreToDo = 1;
+
+ pOrderBy = pSelect->pOrderBy;
+ if( pOrderBy==0 ) return 0;
+ if( pOrderBy->nExpr>SQLITE_MAX_COLUMN ){
+ sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause");
+ return 1;
+ }
+ db = pParse->db;
+ for(i=0; i<pOrderBy->nExpr; i++){
+ pOrderBy->a[i].done = 0;
+ }
+ while( pSelect->pPrior ){
+ pSelect = pSelect->pPrior;
+ }
+ while( pSelect && moreToDo ){
+ moreToDo = 0;
+ for(i=0; i<pOrderBy->nExpr; i++){
+ int iCol = -1;
+ Expr *pE, *pDup;
+ if( pOrderBy->a[i].done ) continue;
+ pE = pOrderBy->a[i].pExpr;
+ pDup = sqlite3ExprDup(db, pE);
+ if( !db->mallocFailed ){
+ assert(pDup);
+ iCol = matchOrderByTermToExprList(pParse, pSelect, pDup, i+1, 1, 0);
}
- if( iCol<0 && sqlite3ExprCompare(pE, pEList->a[j].pExpr) ){
- iCol = j;
+ sqlite3ExprDelete(pDup);
+ if( iCol<0 ){
+ return 1;
+ }
+ pEList = pSelect->pEList;
+ if( pEList==0 ){
+ return 1;
+ }
+ if( iCol>pEList->nExpr ){
+ sqlite3ErrorMsg(pParse,
+ "%r ORDER BY term out of range - should be "
+ "between 1 and %d", i+1, pEList->nExpr);
+ return 1;
+ }
+ if( iCol>0 ){
+ pE->op = TK_COLUMN;
+ pE->iTable = iTable;
+ pE->iAgg = -1;
+ pE->iColumn = iCol-1;
+ pE->pTab = 0;
+ pOrderBy->a[i].done = 1;
+ }else{
+ moreToDo = 1;
}
}
- if( iCol>=0 ){
- pE->op = TK_COLUMN;
- pE->iColumn = iCol;
- pE->iTable = iTable;
- pE->iAgg = -1;
- pOrderBy->a[i].done = 1;
- }
- if( iCol<0 && mustComplete ){
- sqlite3ErrorMsg(pParse,
- "ORDER BY term number %d does not match any result column", i+1);
- nErr++;
- break;
+ pSelect = pSelect->pNext;
+ }
+ for(i=0; i<pOrderBy->nExpr; i++){
+ if( pOrderBy->a[i].done==0 ){
+ sqlite3ErrorMsg(pParse, "%r ORDER BY term does not match any "
+ "column in the result set", i+1);
+ return 1;
}
}
- return nErr;
+ return 0;
}
-#endif /* #ifndef SQLITE_OMIT_COMPOUND_SELECT */
/*
** Get a VDBE for the given parser context. Create a new one if necessary.
@@ -1456,6 +1730,11 @@ Vdbe *sqlite3GetVdbe(Parse *pParse){
Vdbe *v = pParse->pVdbe;
if( v==0 ){
v = pParse->pVdbe = sqlite3VdbeCreate(pParse->db);
+#ifndef SQLITE_OMIT_TRACE
+ if( v ){
+ sqlite3VdbeAddOp0(v, OP_Trace);
+ }
+#endif
}
return v;
}
@@ -1483,7 +1762,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
Vdbe *v = 0;
int iLimit = 0;
int iOffset;
- int addr1, addr2;
+ int addr1;
/*
** "LIMIT -1" always shows all rows. There is some
@@ -1492,42 +1771,35 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
** no rows.
*/
if( p->pLimit ){
- p->iLimit = iLimit = pParse->nMem;
- pParse->nMem += 2;
+ p->iLimit = iLimit = ++pParse->nMem;
v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
- sqlite3ExprCode(pParse, p->pLimit);
- sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, iLimit, 0);
- VdbeComment((v, "# LIMIT counter"));
- sqlite3VdbeAddOp(v, OP_IfMemZero, iLimit, iBreak);
+ sqlite3ExprCode(pParse, p->pLimit, iLimit);
+ sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit);
+ VdbeComment((v, "LIMIT counter"));
+ sqlite3VdbeAddOp2(v, OP_IfZero, iLimit, iBreak);
}
if( p->pOffset ){
- p->iOffset = iOffset = pParse->nMem++;
+ p->iOffset = iOffset = ++pParse->nMem;
+ if( p->pLimit ){
+ pParse->nMem++; /* Allocate an extra register for limit+offset */
+ }
v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
- sqlite3ExprCode(pParse, p->pOffset);
- sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, iOffset, p->pLimit==0);
- VdbeComment((v, "# OFFSET counter"));
- addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iOffset, 0);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
+ sqlite3ExprCode(pParse, p->pOffset, iOffset);
+ sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset);
+ VdbeComment((v, "OFFSET counter"));
+ addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iOffset);
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, iOffset);
sqlite3VdbeJumpHere(v, addr1);
if( p->pLimit ){
- sqlite3VdbeAddOp(v, OP_Add, 0, 0);
+ sqlite3VdbeAddOp3(v, OP_Add, iLimit, iOffset, iOffset+1);
+ VdbeComment((v, "LIMIT+OFFSET"));
+ addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iLimit);
+ sqlite3VdbeAddOp2(v, OP_Integer, -1, iOffset+1);
+ sqlite3VdbeJumpHere(v, addr1);
}
}
- 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);
- }
}
/*
@@ -1538,7 +1810,7 @@ static void createSortingIndex(Parse *pParse, Select *p, ExprList *pOrderBy){
int addr;
assert( pOrderBy->iECursor==0 );
pOrderBy->iECursor = pParse->nTab++;
- addr = sqlite3VdbeAddOp(pParse->pVdbe, OP_OpenEphemeral,
+ addr = sqlite3VdbeAddOp2(pParse->pVdbe, OP_OpenEphemeral,
pOrderBy->iECursor, pOrderBy->nExpr+1);
assert( p->addrOpenEphm[2] == -1 );
p->addrOpenEphm[2] = addr;
@@ -1602,8 +1874,7 @@ static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){
static int multiSelect(
Parse *pParse, /* Parsing context */
Select *p, /* The right-most of SELECTs to be coded */
- int eDest, /* \___ Store query results as specified */
- int iParm, /* / by these two parameters. */
+ SelectDest *pDest, /* What to do with query results */
char *aff /* If eDest is SRT_Union, the affinity string */
){
int rc = SQLITE_OK; /* Success code from a subroutine */
@@ -1613,6 +1884,9 @@ static int multiSelect(
ExprList *pOrderBy; /* The ORDER BY clause on p */
int aSetP2[2]; /* Set P2 value of these op to number of columns */
int nSetP2 = 0; /* Number of slots in aSetP2[] used */
+ SelectDest dest; /* Alternative data destination */
+
+ dest = *pDest;
/* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only
** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT.
@@ -1647,11 +1921,11 @@ static int multiSelect(
/* Create the destination temporary table if necessary
*/
- if( eDest==SRT_EphemTab ){
+ if( dest.eDest==SRT_EphemTab ){
assert( p->pEList );
assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) );
- aSetP2[nSetP2++] = sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, 0);
- eDest = SRT_Table;
+ aSetP2[nSetP2++] = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iParm, 0);
+ dest.eDest = SRT_Table;
}
/* Generate code for the left and right SELECT statements.
@@ -1664,7 +1938,7 @@ static int multiSelect(
assert( !pPrior->pLimit );
pPrior->pLimit = p->pLimit;
pPrior->pOffset = p->pOffset;
- rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff);
+ rc = sqlite3Select(pParse, pPrior, &dest, 0, 0, 0, aff);
p->pLimit = 0;
p->pOffset = 0;
if( rc ){
@@ -1674,10 +1948,10 @@ static int multiSelect(
p->iLimit = pPrior->iLimit;
p->iOffset = pPrior->iOffset;
if( p->iLimit>=0 ){
- addr = sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, 0);
- VdbeComment((v, "# Jump ahead if LIMIT reached"));
+ addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit);
+ VdbeComment((v, "Jump ahead if LIMIT reached"));
}
- rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff);
+ rc = sqlite3Select(pParse, p, &dest, 0, 0, 0, aff);
p->pPrior = pPrior;
if( rc ){
goto multi_select_end;
@@ -1696,23 +1970,24 @@ static int multiSelect(
int priorOp; /* The SRT_ operation to apply to prior selects */
Expr *pLimit, *pOffset; /* Saved values of p->nLimit and p->nOffset */
int addr;
+ SelectDest uniondest;
priorOp = p->op==TK_ALL ? SRT_Table : SRT_Union;
- if( eDest==priorOp && pOrderBy==0 && !p->pLimit && !p->pOffset ){
+ if( dest.eDest==priorOp && pOrderBy==0 && !p->pLimit && !p->pOffset ){
/* We can reuse a temporary table generated by a SELECT to our
** right.
*/
- unionTab = iParm;
+ unionTab = dest.iParm;
}else{
/* We will need to create our own temporary table to hold the
** intermediate results.
*/
unionTab = pParse->nTab++;
- if( pOrderBy && matchOrderbyToColumn(pParse, p, pOrderBy, unionTab,1) ){
+ if( processCompoundOrderBy(pParse, p, unionTab) ){
rc = 1;
goto multi_select_end;
}
- addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, unionTab, 0);
+ addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0);
if( priorOp==SRT_Table ){
assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) );
aSetP2[nSetP2++] = addr;
@@ -1728,7 +2003,8 @@ static int multiSelect(
/* Code the SELECT statements to our left
*/
assert( !pPrior->pOrderBy );
- rc = sqlite3Select(pParse, pPrior, priorOp, unionTab, 0, 0, 0, aff);
+ sqlite3SelectDestInit(&uniondest, priorOp, unionTab);
+ rc = sqlite3Select(pParse, pPrior, &uniondest, 0, 0, 0, aff);
if( rc ){
goto multi_select_end;
}
@@ -1747,7 +2023,11 @@ static int multiSelect(
p->pLimit = 0;
pOffset = p->pOffset;
p->pOffset = 0;
- rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0, aff);
+ uniondest.eDest = op;
+ rc = sqlite3Select(pParse, p, &uniondest, 0, 0, 0, aff);
+ /* Query flattening in sqlite3Select() might refill p->pOrderBy.
+ ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */
+ sqlite3ExprListDelete(p->pOrderBy);
p->pPrior = pPrior;
p->pOrderBy = pOrderBy;
sqlite3ExprDelete(p->pLimit);
@@ -1763,10 +2043,10 @@ static int multiSelect(
/* Convert the data in the temporary table into whatever form
** it is that we currently need.
*/
- if( eDest!=priorOp || unionTab!=iParm ){
+ if( dest.eDest!=priorOp || unionTab!=dest.iParm ){
int iCont, iBreak, iStart;
assert( p->pEList );
- if( eDest==SRT_Callback ){
+ if( dest.eDest==SRT_Callback ){
Select *pFirst = p;
while( pFirst->pPrior ) pFirst = pFirst->pPrior;
generateColumnNames(pParse, 0, pFirst->pEList);
@@ -1774,19 +2054,14 @@ static int multiSelect(
iBreak = sqlite3VdbeMakeLabel(v);
iCont = sqlite3VdbeMakeLabel(v);
computeLimitRegisters(pParse, p, iBreak);
- sqlite3VdbeAddOp(v, OP_Rewind, unionTab, iBreak);
+ sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak);
iStart = sqlite3VdbeCurrentAddr(v);
- rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,
- pOrderBy, -1, eDest, iParm,
- iCont, iBreak, 0);
- if( rc ){
- rc = 1;
- goto multi_select_end;
- }
+ selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,
+ pOrderBy, -1, &dest, iCont, iBreak, 0);
sqlite3VdbeResolveLabel(v, iCont);
- sqlite3VdbeAddOp(v, OP_Next, unionTab, iStart);
+ sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart);
sqlite3VdbeResolveLabel(v, iBreak);
- sqlite3VdbeAddOp(v, OP_Close, unionTab, 0);
+ sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0);
}
break;
}
@@ -1795,6 +2070,8 @@ static int multiSelect(
int iCont, iBreak, iStart;
Expr *pLimit, *pOffset;
int addr;
+ SelectDest intersectdest;
+ int r1;
/* INTERSECT is different from the others since it requires
** two temporary tables. Hence it has its own case. Begin
@@ -1802,13 +2079,13 @@ static int multiSelect(
*/
tab1 = pParse->nTab++;
tab2 = pParse->nTab++;
- if( pOrderBy && matchOrderbyToColumn(pParse,p,pOrderBy,tab1,1) ){
+ if( processCompoundOrderBy(pParse, p, tab1) ){
rc = 1;
goto multi_select_end;
}
createSortingIndex(pParse, p, pOrderBy);
- addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, tab1, 0);
+ addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0);
assert( p->addrOpenEphm[0] == -1 );
p->addrOpenEphm[0] = addr;
p->pRightmost->usesEphm = 1;
@@ -1816,14 +2093,15 @@ static int multiSelect(
/* Code the SELECTs to our left into temporary table "tab1".
*/
- rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0, aff);
+ sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1);
+ rc = sqlite3Select(pParse, pPrior, &intersectdest, 0, 0, 0, aff);
if( rc ){
goto multi_select_end;
}
/* Code the current SELECT into temporary table "tab2"
*/
- addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, tab2, 0);
+ addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0);
assert( p->addrOpenEphm[1] == -1 );
p->addrOpenEphm[1] = addr;
p->pPrior = 0;
@@ -1831,7 +2109,8 @@ static int multiSelect(
p->pLimit = 0;
pOffset = p->pOffset;
p->pOffset = 0;
- rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0, aff);
+ intersectdest.iParm = tab2;
+ rc = sqlite3Select(pParse, p, &intersectdest, 0, 0, 0, aff);
p->pPrior = pPrior;
sqlite3ExprDelete(p->pLimit);
p->pLimit = pLimit;
@@ -1844,7 +2123,7 @@ static int multiSelect(
** tables.
*/
assert( p->pEList );
- if( eDest==SRT_Callback ){
+ if( dest.eDest==SRT_Callback ){
Select *pFirst = p;
while( pFirst->pPrior ) pFirst = pFirst->pPrior;
generateColumnNames(pParse, 0, pFirst->pEList);
@@ -1852,21 +2131,18 @@ static int multiSelect(
iBreak = sqlite3VdbeMakeLabel(v);
iCont = sqlite3VdbeMakeLabel(v);
computeLimitRegisters(pParse, p, iBreak);
- sqlite3VdbeAddOp(v, OP_Rewind, tab1, iBreak);
- iStart = sqlite3VdbeAddOp(v, OP_RowKey, tab1, 0);
- sqlite3VdbeAddOp(v, OP_NotFound, tab2, iCont);
- rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
- pOrderBy, -1, eDest, iParm,
- iCont, iBreak, 0);
- if( rc ){
- rc = 1;
- goto multi_select_end;
- }
+ sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak);
+ r1 = sqlite3GetTempReg(pParse);
+ iStart = sqlite3VdbeAddOp2(v, OP_RowKey, tab1, r1);
+ sqlite3VdbeAddOp3(v, OP_NotFound, tab2, iCont, r1);
+ sqlite3ReleaseTempReg(pParse, r1);
+ selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
+ pOrderBy, -1, &dest, iCont, iBreak, 0);
sqlite3VdbeResolveLabel(v, iCont);
- sqlite3VdbeAddOp(v, OP_Next, tab1, iStart);
+ sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart);
sqlite3VdbeResolveLabel(v, iBreak);
- sqlite3VdbeAddOp(v, OP_Close, tab2, 0);
- sqlite3VdbeAddOp(v, OP_Close, tab1, 0);
+ sqlite3VdbeAddOp2(v, OP_Close, tab2, 0);
+ sqlite3VdbeAddOp2(v, OP_Close, tab1, 0);
break;
}
}
@@ -1904,12 +2180,13 @@ static int multiSelect(
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;
+ CollSeq **apColl; /* For looping through pKeyInfo->aColl[] */
+ CollSeq **aCopy; /* A copy of pKeyInfo->aColl[] */
assert( p->pRightmost==p );
nKeyCol = nCol + (pOrderBy ? pOrderBy->nExpr : 0);
- pKeyInfo = sqliteMalloc(sizeof(*pKeyInfo)+nKeyCol*(sizeof(CollSeq*) + 1));
+ pKeyInfo = sqlite3DbMallocZero(pParse->db,
+ sizeof(*pKeyInfo)+nKeyCol*(sizeof(CollSeq*) + 1));
if( !pKeyInfo ){
rc = SQLITE_NOMEM;
goto multi_select_end;
@@ -1935,7 +2212,8 @@ static int multiSelect(
break;
}
sqlite3VdbeChangeP2(v, addr, nCol);
- sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO);
+ sqlite3VdbeChangeP4(v, addr, (char*)pKeyInfo, P4_KEYINFO);
+ pLoop->addrOpenEphm[i] = -1;
}
}
@@ -1945,16 +2223,29 @@ static int multiSelect(
int addr;
u8 *pSortOrder;
+ /* Reuse the same pKeyInfo for the ORDER BY as was used above for
+ ** the compound select statements. Except we have to change out the
+ ** pKeyInfo->aColl[] values. Some of the aColl[] values will be
+ ** reused when constructing the pKeyInfo for the ORDER BY, so make
+ ** a copy. Sufficient space to hold both the nCol entries for
+ ** the compound select and the nOrderbyExpr entries for the ORDER BY
+ ** was allocated above. But we need to move the compound select
+ ** entries out of the way before constructing the ORDER BY entries.
+ ** Move the compound select entries into aCopy[] where they can be
+ ** accessed and reused when constructing the ORDER BY entries.
+ ** Because nCol might be greater than or less than nOrderByExpr
+ ** we have to use memmove() when doing the copy.
+ */
aCopy = &pKeyInfo->aColl[nOrderByExpr];
pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nCol];
- memcpy(aCopy, pKeyInfo->aColl, nCol*sizeof(CollSeq*));
+ memmove(aCopy, pKeyInfo->aColl, nCol*sizeof(CollSeq*));
+
apColl = pKeyInfo->aColl;
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 );
- if( zName ){
- *apColl = sqlite3LocateCollSeq(pParse, zName, -1);
+ if( (pExpr->flags & EP_ExpCollate) ){
+ assert( pExpr->pColl!=0 );
+ *apColl = pExpr->pColl;
}else{
*apColl = aCopy[pExpr->iColumn];
}
@@ -1963,22 +2254,27 @@ static int multiSelect(
assert( p->pRightmost==p );
assert( p->addrOpenEphm[2]>=0 );
addr = p->addrOpenEphm[2];
- sqlite3VdbeChangeP2(v, addr, p->pEList->nExpr+2);
+ sqlite3VdbeChangeP2(v, addr, p->pOrderBy->nExpr+2);
pKeyInfo->nField = nOrderByExpr;
- sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
+ sqlite3VdbeChangeP4(v, addr, (char*)pKeyInfo, P4_KEYINFO_HANDOFF);
pKeyInfo = 0;
- generateSortTail(pParse, p, v, p->pEList->nExpr, eDest, iParm);
+ generateSortTail(pParse, p, v, p->pEList->nExpr, &dest);
}
- sqliteFree(pKeyInfo);
+ sqlite3_free(pKeyInfo);
}
multi_select_end:
+ pDest->iMem = dest.iMem;
return rc;
}
#endif /* SQLITE_OMIT_COMPOUND_SELECT */
#ifndef SQLITE_OMIT_VIEW
+/* Forward Declarations */
+static void substExprList(sqlite3*, ExprList*, int, ExprList*);
+static void substSelect(sqlite3*, Select *, int, ExprList *);
+
/*
** Scan through the expression pExpr. Replace every reference to
** a column in table number iTable with a copy of the iColumn-th
@@ -1992,9 +2288,12 @@ multi_select_end:
** changes to pExpr so that it refers directly to the source table
** of the subquery rather the result set of the subquery.
*/
-static void substExprList(ExprList*,int,ExprList*); /* Forward Decl */
-static void substSelect(Select *, int, ExprList *); /* Forward Decl */
-static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){
+static void substExpr(
+ sqlite3 *db, /* Report malloc errors to this connection */
+ Expr *pExpr, /* Expr in which substitution occurs */
+ int iTable, /* Table to be substituted */
+ ExprList *pEList /* Substitute expressions */
+){
if( pExpr==0 ) return;
if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
if( pExpr->iColumn<0 ){
@@ -2007,41 +2306,52 @@ static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){
assert( pNew!=0 );
pExpr->op = pNew->op;
assert( pExpr->pLeft==0 );
- pExpr->pLeft = sqlite3ExprDup(pNew->pLeft);
+ pExpr->pLeft = sqlite3ExprDup(db, pNew->pLeft);
assert( pExpr->pRight==0 );
- pExpr->pRight = sqlite3ExprDup(pNew->pRight);
+ pExpr->pRight = sqlite3ExprDup(db, pNew->pRight);
assert( pExpr->pList==0 );
- pExpr->pList = sqlite3ExprListDup(pNew->pList);
+ pExpr->pList = sqlite3ExprListDup(db, pNew->pList);
pExpr->iTable = pNew->iTable;
pExpr->pTab = pNew->pTab;
pExpr->iColumn = pNew->iColumn;
pExpr->iAgg = pNew->iAgg;
- sqlite3TokenCopy(&pExpr->token, &pNew->token);
- sqlite3TokenCopy(&pExpr->span, &pNew->span);
- pExpr->pSelect = sqlite3SelectDup(pNew->pSelect);
+ sqlite3TokenCopy(db, &pExpr->token, &pNew->token);
+ sqlite3TokenCopy(db, &pExpr->span, &pNew->span);
+ pExpr->pSelect = sqlite3SelectDup(db, pNew->pSelect);
pExpr->flags = pNew->flags;
}
}else{
- substExpr(pExpr->pLeft, iTable, pEList);
- substExpr(pExpr->pRight, iTable, pEList);
- substSelect(pExpr->pSelect, iTable, pEList);
- substExprList(pExpr->pList, iTable, pEList);
+ substExpr(db, pExpr->pLeft, iTable, pEList);
+ substExpr(db, pExpr->pRight, iTable, pEList);
+ substSelect(db, pExpr->pSelect, iTable, pEList);
+ substExprList(db, pExpr->pList, iTable, pEList);
}
}
-static void substExprList(ExprList *pList, int iTable, ExprList *pEList){
+static void substExprList(
+ sqlite3 *db, /* Report malloc errors here */
+ ExprList *pList, /* List to scan and in which to make substitutes */
+ int iTable, /* Table to be substituted */
+ ExprList *pEList /* Substitute values */
+){
int i;
if( pList==0 ) return;
for(i=0; i<pList->nExpr; i++){
- substExpr(pList->a[i].pExpr, iTable, pEList);
+ substExpr(db, pList->a[i].pExpr, iTable, pEList);
}
}
-static void substSelect(Select *p, int iTable, ExprList *pEList){
+static void substSelect(
+ sqlite3 *db, /* Report malloc errors here */
+ Select *p, /* SELECT statement in which to make substitutions */
+ int iTable, /* Table to be replaced */
+ ExprList *pEList /* Substitute values */
+){
if( !p ) return;
- substExprList(p->pEList, iTable, pEList);
- substExprList(p->pGroupBy, iTable, pEList);
- substExprList(p->pOrderBy, iTable, pEList);
- substExpr(p->pHaving, iTable, pEList);
- substExpr(p->pWhere, iTable, pEList);
+ substExprList(db, p->pEList, iTable, pEList);
+ substExprList(db, p->pGroupBy, iTable, pEList);
+ substExprList(db, p->pOrderBy, iTable, pEList);
+ substExpr(db, p->pHaving, iTable, pEList);
+ substExpr(db, p->pWhere, iTable, pEList);
+ substSelect(db, p->pPrior, iTable, pEList);
}
#endif /* !defined(SQLITE_OMIT_VIEW) */
@@ -2109,6 +2419,10 @@ static void substSelect(Select *p, int iTable, ExprList *pEList){
**
** (14) The subquery does not use OFFSET
**
+** (15) The outer query is not part of a compound select or the
+** subquery does not have both an ORDER BY and a LIMIT clause.
+** (See ticket #2339)
+**
** 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.
@@ -2120,6 +2434,7 @@ static void substSelect(Select *p, int iTable, ExprList *pEList){
** the subquery before this routine runs.
*/
static int flattenSubquery(
+ sqlite3 *db, /* Database connection */
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 */
@@ -2153,6 +2468,9 @@ static int flattenSubquery(
** and (14). */
if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */
if( pSub->pOffset ) return 0; /* Restriction (14) */
+ if( p->pRightmost && pSub->pLimit && pSub->pOrderBy ){
+ return 0; /* Restriction (15) */
+ }
if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */
if( (pSub->isDistinct || pSub->pLimit)
&& (pSrc->nSrc>1 || isAgg) ){ /* Restrictions (4)(5)(8)(9) */
@@ -2175,7 +2493,7 @@ static int flattenSubquery(
**
** which is not at all the same thing.
*/
- if( pSubSrc->nSrc>1 && iFrom>0 && (pSrc->a[iFrom-1].jointype & JT_OUTER)!=0 ){
+ if( pSubSrc->nSrc>1 && (pSubitem->jointype & JT_OUTER)!=0 ){
return 0;
}
@@ -2192,8 +2510,7 @@ static int flattenSubquery(
** But the t2.x>0 test will always fail on a NULL row of t2, which
** effectively converts the OUTER JOIN into an INNER JOIN.
*/
- if( iFrom>0 && (pSrc->a[iFrom-1].jointype & JT_OUTER)!=0
- && pSub->pWhere!=0 ){
+ if( (pSubitem->jointype & JT_OUTER)!=0 && pSub->pWhere!=0 ){
return 0;
}
@@ -2214,14 +2531,22 @@ static int flattenSubquery(
int nSubSrc = pSubSrc->nSrc;
int jointype = pSubitem->jointype;
- sqlite3DeleteTable(0, pSubitem->pTab);
- sqliteFree(pSubitem->zDatabase);
- sqliteFree(pSubitem->zName);
- sqliteFree(pSubitem->zAlias);
+ sqlite3DeleteTable(pSubitem->pTab);
+ sqlite3_free(pSubitem->zDatabase);
+ sqlite3_free(pSubitem->zName);
+ sqlite3_free(pSubitem->zAlias);
+ pSubitem->pTab = 0;
+ pSubitem->zDatabase = 0;
+ pSubitem->zName = 0;
+ pSubitem->zAlias = 0;
if( nSubSrc>1 ){
int extra = nSubSrc - 1;
for(i=1; i<nSubSrc; i++){
- pSrc = sqlite3SrcListAppend(pSrc, 0, 0);
+ pSrc = sqlite3SrcListAppend(db, pSrc, 0, 0);
+ if( pSrc==0 ){
+ p->pSrc = 0;
+ return 1;
+ }
}
p->pSrc = pSrc;
for(i=pSrc->nSrc-1; i-extra>=iFrom; i--){
@@ -2232,7 +2557,7 @@ static int flattenSubquery(
pSrc->a[i+iFrom] = pSubSrc->a[i];
memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
}
- pSrc->a[iFrom+nSubSrc-1].jointype = jointype;
+ pSrc->a[iFrom].jointype = jointype;
}
/* Now begin substituting subquery result set expressions for
@@ -2251,23 +2576,24 @@ static int flattenSubquery(
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((char*)pExpr->span.z, pExpr->span.n);
+ pList->a[i].zName =
+ sqlite3DbStrNDup(db, (char*)pExpr->span.z, pExpr->span.n);
}
}
- substExprList(p->pEList, iParent, pSub->pEList);
+ substExprList(db, p->pEList, iParent, pSub->pEList);
if( isAgg ){
- substExprList(p->pGroupBy, iParent, pSub->pEList);
- substExpr(p->pHaving, iParent, pSub->pEList);
+ substExprList(db, p->pGroupBy, iParent, pSub->pEList);
+ substExpr(db, p->pHaving, iParent, pSub->pEList);
}
if( pSub->pOrderBy ){
assert( p->pOrderBy==0 );
p->pOrderBy = pSub->pOrderBy;
pSub->pOrderBy = 0;
}else if( p->pOrderBy ){
- substExprList(p->pOrderBy, iParent, pSub->pEList);
+ substExprList(db, p->pOrderBy, iParent, pSub->pEList);
}
if( pSub->pWhere ){
- pWhere = sqlite3ExprDup(pSub->pWhere);
+ pWhere = sqlite3ExprDup(db, pSub->pWhere);
}else{
pWhere = 0;
}
@@ -2275,13 +2601,14 @@ static int flattenSubquery(
assert( p->pHaving==0 );
p->pHaving = p->pWhere;
p->pWhere = pWhere;
- substExpr(p->pHaving, iParent, pSub->pEList);
- p->pHaving = sqlite3ExprAnd(p->pHaving, sqlite3ExprDup(pSub->pHaving));
+ substExpr(db, p->pHaving, iParent, pSub->pEList);
+ p->pHaving = sqlite3ExprAnd(db, p->pHaving,
+ sqlite3ExprDup(db, pSub->pHaving));
assert( p->pGroupBy==0 );
- p->pGroupBy = sqlite3ExprListDup(pSub->pGroupBy);
+ p->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy);
}else{
- substExpr(p->pWhere, iParent, pSub->pEList);
- p->pWhere = sqlite3ExprAnd(p->pWhere, pWhere);
+ substExpr(db, p->pWhere, iParent, pSub->pEList);
+ p->pWhere = sqlite3ExprAnd(db, p->pWhere, pWhere);
}
/* The flattened query is distinct if either the inner or the
@@ -2309,189 +2636,32 @@ static int flattenSubquery(
#endif /* SQLITE_OMIT_VIEW */
/*
-** Analyze the SELECT statement passed in as an argument to see if it
-** is a simple min() or max() query. If it is and this query can be
-** satisfied using a single seek to the beginning or end of an index,
-** then generate the code for this SELECT and return 1. If this is not a
-** simple min() or max() query, then return 0;
-**
-** A simply min() or max() query looks like this:
+** Analyze the SELECT statement passed as an argument to see if it
+** is a min() or max() query. Return ORDERBY_MIN or ORDERBY_MAX if
+** it is, or 0 otherwise. At present, a query is considered to be
+** a min()/max() query if:
**
-** SELECT min(a) FROM table;
-** SELECT max(a) FROM table;
+** 1. There is a single object in the FROM clause.
**
-** The query may have only a single table in its FROM argument. There
-** can be no GROUP BY or HAVING or WHERE clauses. The result set must
-** be the min() or max() of a single column of the table. The column
-** in the min() or max() function must be indexed.
-**
-** The parameters to this routine are the same as for sqlite3Select().
-** See the header comment on that routine for additional information.
+** 2. There is a single expression in the result set, and it is
+** either min(x) or max(x), where x is a column reference.
*/
-static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
+static int minMaxQuery(Parse *pParse, Select *p){
Expr *pExpr;
- int iCol;
- Table *pTab;
- Index *pIdx;
- int base;
- Vdbe *v;
- int seekOp;
- 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.
- */
- if( p->pGroupBy || p->pHaving || p->pWhere ) return 0;
- pSrc = p->pSrc;
- if( pSrc->nSrc!=1 ) return 0;
- pEList = p->pEList;
- if( pEList->nExpr!=1 ) return 0;
+ ExprList *pEList = p->pEList;
+
+ if( pEList->nExpr!=1 ) return ORDERBY_NORMAL;
pExpr = pEList->a[0].pExpr;
- if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
- pList = pExpr->pList;
- if( pList==0 || pList->nExpr!=1 ) return 0;
- if( pExpr->token.n!=3 ) return 0;
+ pEList = pExpr->pList;
+ if( pExpr->op!=TK_AGG_FUNCTION || pEList==0 || pEList->nExpr!=1 ) return 0;
+ if( pEList->a[0].pExpr->op!=TK_AGG_COLUMN ) return ORDERBY_NORMAL;
+ if( pExpr->token.n!=3 ) return ORDERBY_NORMAL;
if( sqlite3StrNICmp((char*)pExpr->token.z,"min",3)==0 ){
- seekOp = OP_Rewind;
+ return ORDERBY_MIN;
}else if( sqlite3StrNICmp((char*)pExpr->token.z,"max",3)==0 ){
- seekOp = OP_Last;
- }else{
- return 0;
- }
- pExpr = pList->a[0].pExpr;
- if( pExpr->op!=TK_COLUMN ) return 0;
- 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
- ** key column, no index is necessary so set pIdx to NULL. If no
- ** usable index is found, return 0.
- */
- if( iCol<0 ){
- 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 &&
- 0==sqlite3StrICmp(pIdx->azColl[0], pColl->zName) ){
- break;
- }
- }
- if( pIdx==0 ) return 0;
- }
-
- /* Identify column types if we will be using the callback. This
- ** step is skipped if the output is going to a table or a memory cell.
- ** The column names have already been generated in the calling function.
- */
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) return 0;
-
- /* If the output is destined for a temporary table, open that table.
- */
- if( eDest==SRT_EphemTab ){
- sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, 1);
+ return ORDERBY_MAX;
}
-
- /* Generating code to find the min or the max. Basically all we have
- ** to do is find the first or the last entry in the chosen index. If
- ** the min() or max() is on the INTEGER PRIMARY KEY, then find the first
- ** or last entry in the main table.
- */
- 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;
- brk = sqlite3VdbeMakeLabel(v);
- computeLimitRegisters(pParse, p, brk);
- if( pSrc->a[0].pSelect==0 ){
- sqlite3OpenTable(pParse, base, iDb, pTab, OP_OpenRead);
- }
- if( pIdx==0 ){
- sqlite3VdbeAddOp(v, seekOp, base, 0);
- }else{
- /* Even though the cursor used to open the index here is closed
- ** as soon as a single value has been read from it, allocate it
- ** using (pParse->nTab++) to prevent the cursor id from being
- ** reused. This is important for statements of the form
- ** "INSERT INTO x SELECT max() FROM x".
- */
- int iIdx;
- KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
- iIdx = pParse->nTab++;
- 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);
- seekOp = OP_MoveGt;
- }
- sqlite3VdbeAddOp(v, seekOp, iIdx, 0);
- sqlite3VdbeAddOp(v, OP_IdxRowid, iIdx, 0);
- sqlite3VdbeAddOp(v, OP_Close, iIdx, 0);
- sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);
- }
- eList.nExpr = 1;
- memset(&eListItem, 0, sizeof(eListItem));
- eList.a = &eListItem;
- eList.a[0].pExpr = pExpr;
- selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, brk, brk, 0);
- sqlite3VdbeResolveLabel(v, brk);
- sqlite3VdbeAddOp(v, OP_Close, base, 0);
-
- return 1;
-}
-
-/*
-** Analyze and ORDER BY or GROUP BY clause in a SELECT statement. Return
-** the number of errors seen.
-**
-** An ORDER BY or GROUP BY is a list of expressions. If any expression
-** is an integer constant, then that expression is replaced by the
-** corresponding entry in the result set.
-*/
-static int processOrderGroupBy(
- NameContext *pNC, /* Name context of the SELECT statement. */
- ExprList *pOrderBy, /* The ORDER BY or GROUP BY clause to be processed */
- const char *zType /* Either "ORDER" or "GROUP", as appropriate */
-){
- int i;
- ExprList *pEList = pNC->pEList; /* The result set of the SELECT */
- Parse *pParse = pNC->pParse; /* The result set of the SELECT */
- assert( pEList );
-
- if( pOrderBy==0 ) return 0;
- for(i=0; i<pOrderBy->nExpr; i++){
- int iCol;
- Expr *pE = pOrderBy->a[i].pExpr;
- if( sqlite3ExprIsInteger(pE, &iCol) ){
- if( iCol>0 && iCol<=pEList->nExpr ){
- sqlite3ExprDelete(pE);
- pE = pOrderBy->a[i].pExpr = sqlite3ExprDup(pEList->a[iCol-1].pExpr);
- }else{
- sqlite3ErrorMsg(pParse,
- "%s BY column number %d out of range - should be "
- "between 1 and %d", zType, iCol, pEList->nExpr);
- return 1;
- }
- }
- if( sqlite3ExprResolveNames(pNC, pE) ){
- return 1;
- }
- }
- return 0;
+ return ORDERBY_NORMAL;
}
/*
@@ -2584,12 +2754,21 @@ int sqlite3SelectResolve(
*/
sNC.pEList = p->pEList;
if( sqlite3ExprResolveNames(&sNC, p->pWhere) ||
- sqlite3ExprResolveNames(&sNC, p->pHaving) ||
- processOrderGroupBy(&sNC, p->pOrderBy, "ORDER") ||
- processOrderGroupBy(&sNC, pGroupBy, "GROUP")
- ){
+ sqlite3ExprResolveNames(&sNC, p->pHaving) ){
return SQLITE_ERROR;
}
+ if( p->pPrior==0 ){
+ if( processOrderGroupBy(pParse, p, p->pOrderBy, 1, &sNC.hasAgg) ){
+ return SQLITE_ERROR;
+ }
+ }
+ if( processOrderGroupBy(pParse, p, pGroupBy, 0, &sNC.hasAgg) ){
+ return SQLITE_ERROR;
+ }
+
+ if( pParse->db->mallocFailed ){
+ return SQLITE_NOMEM;
+ }
/* Make sure the GROUP BY clause does not contain aggregate functions.
*/
@@ -2605,7 +2784,14 @@ int sqlite3SelectResolve(
}
}
- return SQLITE_OK;
+ /* If this is one SELECT of a compound, be sure to resolve names
+ ** in the other SELECTs.
+ */
+ if( p->pPrior ){
+ return sqlite3SelectResolve(pParse, p->pPrior, pOuterNC);
+ }else{
+ return SQLITE_OK;
+ }
}
/*
@@ -2623,10 +2809,10 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
return;
}
for(i=0; i<pAggInfo->nColumn; i++){
- sqlite3VdbeAddOp(v, OP_MemNull, pAggInfo->aCol[i].iMem, 0);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, pAggInfo->aCol[i].iMem);
}
for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
- sqlite3VdbeAddOp(v, OP_MemNull, pFunc->iMem, 0);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, pFunc->iMem);
if( pFunc->iDistinct>=0 ){
Expr *pE = pFunc->pExpr;
if( pE->pList==0 || pE->pList->nExpr!=1 ){
@@ -2635,8 +2821,8 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
pFunc->iDistinct = -1;
}else{
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->pList);
- sqlite3VdbeOp3(v, OP_OpenEphemeral, pFunc->iDistinct, 0,
- (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
+ sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
+ (char*)pKeyInfo, P4_KEYINFO_HANDOFF);
}
}
}
@@ -2652,8 +2838,8 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
struct AggInfo_func *pF;
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
ExprList *pList = pF->pExpr->pList;
- sqlite3VdbeOp3(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0,
- (void*)pF->pFunc, P3_FUNCDEF);
+ sqlite3VdbeAddOp4(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0, 0,
+ (void*)pF->pFunc, P4_FUNCDEF);
}
}
@@ -2671,17 +2857,20 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
int nArg;
int addrNext = 0;
+ int regAgg;
ExprList *pList = pF->pExpr->pList;
if( pList ){
nArg = pList->nExpr;
- sqlite3ExprCodeExprList(pParse, pList);
+ regAgg = sqlite3GetTempRange(pParse, nArg);
+ sqlite3ExprCodeExprList(pParse, pList, regAgg);
}else{
nArg = 0;
+ regAgg = 0;
}
if( pF->iDistinct>=0 ){
addrNext = sqlite3VdbeMakeLabel(v);
assert( nArg==1 );
- codeDistinct(v, pF->iDistinct, addrNext, 1);
+ codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg);
}
if( pF->pFunc->needCollSeq ){
CollSeq *pColl = 0;
@@ -2694,44 +2883,86 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
if( !pColl ){
pColl = pParse->db->pDfltColl;
}
- sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ);
+ sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
}
- sqlite3VdbeOp3(v, OP_AggStep, pF->iMem, nArg, (void*)pF->pFunc, P3_FUNCDEF);
+ sqlite3VdbeAddOp4(v, OP_AggStep, 0, regAgg, pF->iMem,
+ (void*)pF->pFunc, P4_FUNCDEF);
+ sqlite3VdbeChangeP5(v, nArg);
+ sqlite3ReleaseTempRange(pParse, regAgg, nArg);
if( addrNext ){
sqlite3VdbeResolveLabel(v, addrNext);
}
}
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
- sqlite3ExprCode(pParse, pC->pExpr);
- sqlite3VdbeAddOp(v, OP_MemStore, pC->iMem, 1);
+ sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
}
pAggInfo->directMode = 0;
}
+#ifndef SQLITE_OMIT_TRIGGER
+/*
+** This function is used when a SELECT statement is used to create a
+** temporary table for iterating through when running an INSTEAD OF
+** UPDATE or INSTEAD OF DELETE trigger.
+**
+** If possible, the SELECT statement is modified so that NULL values
+** are stored in the temporary table for all columns for which the
+** corresponding bit in argument mask is not set. If mask takes the
+** special value 0xffffffff, then all columns are populated.
+*/
+void sqlite3SelectMask(Parse *pParse, Select *p, u32 mask){
+ if( p && !p->pPrior && !p->isDistinct && mask!=0xffffffff ){
+ ExprList *pEList;
+ int i;
+ sqlite3SelectResolve(pParse, p, 0);
+ pEList = p->pEList;
+ for(i=0; pEList && i<pEList->nExpr && i<32; i++){
+ if( !(mask&((u32)1<<i)) ){
+ sqlite3ExprDelete(pEList->a[i].pExpr);
+ pEList->a[i].pExpr = sqlite3Expr(pParse->db, TK_NULL, 0, 0, 0);
+ }
+ }
+ }
+}
+#endif
/*
** Generate code for the given SELECT statement.
**
** The results are distributed in various ways depending on the
-** value of eDest and iParm.
+** contents of the SelectDest structure pointed to by argument pDest
+** as follows:
**
-** eDest Value Result
+** pDest->eDest Result
** ------------ -------------------------------------------
** SRT_Callback Invoke the callback for each row of the result.
**
-** SRT_Mem Store first result in memory cell iParm
+** SRT_Mem Store first result in memory cell pDest->iParm
+**
+** SRT_Set Store non-null results as keys of table pDest->iParm.
+** Apply the affinity pDest->affinity before storing them.
**
-** SRT_Set Store results as keys of table iParm.
+** SRT_Union Store results as a key in a temporary table pDest->iParm.
**
-** SRT_Union Store results as a key in a temporary table iParm
+** SRT_Except Remove results from the temporary table pDest->iParm.
**
-** SRT_Except Remove results from the temporary table iParm.
+** SRT_Table Store results in temporary table pDest->iParm
**
-** SRT_Table Store results in temporary table iParm
+** SRT_EphemTab Create an temporary table pDest->iParm and store
+** the result there. The cursor is left open after
+** returning.
**
-** The table above is incomplete. Additional eDist value have be added
-** since this comment was written. See the selectInnerLoop() function for
-** a complete listing of the allowed values of eDest and their meanings.
+** SRT_Subroutine For each row returned, push the results onto the
+** vdbe stack and call the subroutine (via OP_Gosub)
+** at address pDest->iParm.
+**
+** SRT_Exists Store a 1 in memory cell pDest->iParm if the result
+** set is not empty.
+**
+** SRT_Discard Throw the results away.
+**
+** See the selectInnerLoop() function for a canonical listing of the
+** allowed values of eDest and their meanings.
**
** This routine returns the number of errors. If any errors are
** encountered, then an appropriate error message is left in
@@ -2764,8 +2995,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
int sqlite3Select(
Parse *pParse, /* The parser context */
Select *p, /* The SELECT statement being coded. */
- int eDest, /* How to dispose of the results */
- int iParm, /* A parameter used by the eDest disposal method */
+ SelectDest *pDest, /* What to do with the query results */
Select *pParent, /* Another SELECT for which this is a sub-query */
int parentTab, /* Index in pParent->pSrc of this query */
int *pParentAgg, /* True if pParent uses aggregate functions */
@@ -2787,36 +3017,52 @@ int sqlite3Select(
int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */
AggInfo sAggInfo; /* Information used by aggregate queries */
int iEnd; /* Address of the end of the query */
+ sqlite3 *db; /* The database connection */
- if( p==0 || sqlite3MallocFailed() || pParse->nErr ){
+ db = pParse->db;
+ if( p==0 || db->mallocFailed || pParse->nErr ){
return 1;
}
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
memset(&sAggInfo, 0, sizeof(sAggInfo));
+ pOrderBy = p->pOrderBy;
+ if( IgnorableOrderby(pDest) ){
+ p->pOrderBy = 0;
+
+ /* In these cases the DISTINCT operator makes no difference to the
+ ** results, so remove it if it were specified.
+ */
+ assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union ||
+ pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard);
+ p->isDistinct = 0;
+ }
+ if( sqlite3SelectResolve(pParse, p, 0) ){
+ goto select_end;
+ }
+ p->pOrderBy = pOrderBy;
+
#ifndef SQLITE_OMIT_COMPOUND_SELECT
/* If there is are a sequence of queries, do the earlier ones first.
*/
if( p->pPrior ){
if( p->pRightmost==0 ){
- Select *pLoop;
- for(pLoop=p; pLoop; pLoop=pLoop->pPrior){
+ Select *pLoop, *pRight = 0;
+ int cnt = 0;
+ for(pLoop=p; pLoop; pLoop=pLoop->pPrior, cnt++){
pLoop->pRightmost = p;
+ pLoop->pNext = pRight;
+ pRight = pLoop;
+ }
+ if( SQLITE_MAX_COMPOUND_SELECT>0 && cnt>SQLITE_MAX_COMPOUND_SELECT ){
+ sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
+ return 1;
}
}
- return multiSelect(pParse, p, eDest, iParm, aff);
+ return multiSelect(pParse, p, pDest, aff);
}
#endif
- pOrderBy = p->pOrderBy;
- if( IgnorableOrderby(eDest) ){
- p->pOrderBy = 0;
- }
- if( sqlite3SelectResolve(pParse, p, 0) ){
- goto select_end;
- }
- p->pOrderBy = pOrderBy;
-
/* Make local copies of the parameters for this query.
*/
pTabList = p->pSrc;
@@ -2838,16 +3084,14 @@ int sqlite3Select(
** only a single column may be output.
*/
#ifndef SQLITE_OMIT_SUBQUERY
- if( (eDest==SRT_Mem || eDest==SRT_Set) && pEList->nExpr>1 ){
- sqlite3ErrorMsg(pParse, "only a single result allowed for "
- "a SELECT that is part of an expression");
+ if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){
goto select_end;
}
#endif
/* ORDER BY is ignored for some destinations.
*/
- if( IgnorableOrderby(eDest) ){
+ if( IgnorableOrderby(pDest) ){
pOrderBy = 0;
}
@@ -2863,6 +3107,7 @@ int sqlite3Select(
const char *zSavedAuthContext = 0;
int needRestoreContext;
struct SrcList_item *pItem = &pTabList->a[i];
+ SelectDest dest;
if( pItem->pSelect==0 || pItem->isPopulated ) continue;
if( pItem->zName!=0 ){
@@ -2872,14 +3117,30 @@ int sqlite3Select(
}else{
needRestoreContext = 0;
}
- sqlite3Select(pParse, pItem->pSelect, SRT_EphemTab,
- pItem->iCursor, p, i, &isAgg, 0);
+#if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0
+ /* Increment Parse.nHeight by the height of the largest expression
+ ** tree refered to by this, the parent select. The child select
+ ** may contain expression trees of at most
+ ** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit
+ ** more conservative than necessary, but much easier than enforcing
+ ** an exact limit.
+ */
+ pParse->nHeight += sqlite3SelectExprHeight(p);
+#endif
+ sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
+ sqlite3Select(pParse, pItem->pSelect, &dest, p, i, &isAgg, 0);
+ if( db->mallocFailed ){
+ goto select_end;
+ }
+#if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0
+ pParse->nHeight -= sqlite3SelectExprHeight(p);
+#endif
if( needRestoreContext ){
pParse->zAuthContext = zSavedAuthContext;
}
pTabList = p->pSrc;
pWhere = p->pWhere;
- if( !IgnorableOrderby(eDest) ){
+ if( !IgnorableOrderby(pDest) ){
pOrderBy = p->pOrderBy;
}
pGroupBy = p->pGroupBy;
@@ -2891,54 +3152,57 @@ int sqlite3Select(
/* Check for the special case of a min() or max() function by itself
** in the result set.
*/
- if( simpleMinMaxQuery(pParse, p, eDest, iParm) ){
+#if 0
+ if( simpleMinMaxQuery(pParse, p, pDest) ){
rc = 0;
goto select_end;
}
+#endif
/* Check to see if this is a subquery that can be "flattened" into its parent.
** If flattening is a possiblity, do so and return immediately.
*/
#ifndef SQLITE_OMIT_VIEW
if( pParent && pParentAgg &&
- flattenSubquery(pParent, parentTab, *pParentAgg, isAgg) ){
+ flattenSubquery(db, pParent, parentTab, *pParentAgg, isAgg) ){
if( isAgg ) *pParentAgg = 1;
goto select_end;
}
#endif
- /* If there is an ORDER BY clause, resolve any collation sequences
- ** names that have been explicitly specified and create a sorting index.
- **
- ** This sorting index might end up being unused if the data can be
+ /* If possible, rewrite the query to use GROUP BY instead of DISTINCT.
+ ** GROUP BY may use an index, DISTINCT never does.
+ */
+ if( p->isDistinct && !p->isAgg && !p->pGroupBy ){
+ p->pGroupBy = sqlite3ExprListDup(db, p->pEList);
+ pGroupBy = p->pGroupBy;
+ p->isDistinct = 0;
+ isDistinct = 0;
+ }
+
+ /* If there is an ORDER BY clause, then 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_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.
*/
if( pOrderBy ){
- struct ExprList_item *pTerm;
KeyInfo *pKeyInfo;
- for(i=0, pTerm=pOrderBy->a; i<pOrderBy->nExpr; i++, pTerm++){
- if( pTerm->zName ){
- pTerm->pExpr->pColl = sqlite3LocateCollSeq(pParse, pTerm->zName, -1);
- }
- }
- if( pParse->nErr ){
- goto select_end;
- }
pKeyInfo = keyInfoFromExprList(pParse, pOrderBy);
pOrderBy->iECursor = pParse->nTab++;
p->addrOpenEphm[2] = addrSortIndex =
- sqlite3VdbeOp3(v, OP_OpenEphemeral, pOrderBy->iECursor, pOrderBy->nExpr+2, (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
+ sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
+ pOrderBy->iECursor, pOrderBy->nExpr+2, 0,
+ (char*)pKeyInfo, P4_KEYINFO_HANDOFF);
}else{
addrSortIndex = -1;
}
/* If the output is destined for a temporary table, open that table.
*/
- if( eDest==SRT_EphemTab ){
- sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, pEList->nExpr);
+ if( pDest->eDest==SRT_EphemTab ){
+ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iParm, pEList->nExpr);
}
/* Set the limiter.
@@ -2950,10 +3214,11 @@ int sqlite3Select(
*/
if( isDistinct ){
KeyInfo *pKeyInfo;
+ assert( isAgg || pGroupBy );
distinct = pParse->nTab++;
pKeyInfo = keyInfoFromExprList(pParse, p->pEList);
- sqlite3VdbeOp3(v, OP_OpenEphemeral, distinct, 0,
- (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
+ sqlite3VdbeAddOp4(v, OP_OpenEphemeral, distinct, 0, 0,
+ (char*)pKeyInfo, P4_KEYINFO_HANDOFF);
}else{
distinct = -1;
}
@@ -2963,7 +3228,7 @@ int sqlite3Select(
/* This case is for non-aggregate queries
** Begin the database scan
*/
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, 0);
if( pWInfo==0 ) goto select_end;
/* If sorting index that was created by a prior OP_OpenEphemeral
@@ -2977,10 +3242,9 @@ int sqlite3Select(
/* Use the standard inner loop
*/
- if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest,
- iParm, pWInfo->iContinue, pWInfo->iBreak, aff) ){
- goto select_end;
- }
+ assert(!isDistinct);
+ selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, -1, pDest,
+ pWInfo->iContinue, pWInfo->iBreak, aff);
/* End the database scan loop.
*/
@@ -3021,25 +3285,19 @@ int sqlite3Select(
sNC.pAggInfo = &sAggInfo;
sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
sAggInfo.pGroupBy = pGroupBy;
- if( sqlite3ExprAnalyzeAggList(&sNC, pEList) ){
- goto select_end;
- }
- if( sqlite3ExprAnalyzeAggList(&sNC, pOrderBy) ){
- goto select_end;
- }
- if( pHaving && sqlite3ExprAnalyzeAggregates(&sNC, pHaving) ){
- goto select_end;
+ sqlite3ExprAnalyzeAggList(&sNC, pEList);
+ sqlite3ExprAnalyzeAggList(&sNC, pOrderBy);
+ if( pHaving ){
+ sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
}
sAggInfo.nAccumulator = sAggInfo.nColumn;
for(i=0; i<sAggInfo.nFunc; i++){
- if( sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->pList) ){
- goto select_end;
- }
+ sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->pList);
}
- if( sqlite3MallocFailed() ) goto select_end;
+ if( db->mallocFailed ) goto select_end;
/* Processing for aggregates with GROUP BY is very different and
- ** much more complex tha aggregates without a GROUP BY.
+ ** much more complex than aggregates without a GROUP BY.
*/
if( pGroupBy ){
KeyInfo *pKeyInfo; /* Keying information for the group by clause */
@@ -3059,23 +3317,23 @@ int sqlite3Select(
sAggInfo.sortingIdx = pParse->nTab++;
pKeyInfo = keyInfoFromExprList(pParse, pGroupBy);
addrSortingIdx =
- sqlite3VdbeOp3(v, OP_OpenEphemeral, sAggInfo.sortingIdx,
- sAggInfo.nSortingColumn,
- (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
+ sqlite3VdbeAddOp4(v, OP_OpenEphemeral, sAggInfo.sortingIdx,
+ sAggInfo.nSortingColumn, 0,
+ (char*)pKeyInfo, P4_KEYINFO_HANDOFF);
/* Initialize memory locations used by GROUP BY aggregate processing
*/
- iUseFlag = pParse->nMem++;
- iAbortFlag = pParse->nMem++;
- iAMem = pParse->nMem;
+ iUseFlag = ++pParse->nMem;
+ iAbortFlag = ++pParse->nMem;
+ iAMem = pParse->nMem + 1;
pParse->nMem += pGroupBy->nExpr;
- iBMem = pParse->nMem;
+ iBMem = pParse->nMem + 1;
pParse->nMem += pGroupBy->nExpr;
- sqlite3VdbeAddOp(v, OP_MemInt, 0, iAbortFlag);
- VdbeComment((v, "# clear abort flag"));
- sqlite3VdbeAddOp(v, OP_MemInt, 0, iUseFlag);
- VdbeComment((v, "# indicate accumulator empty"));
- sqlite3VdbeAddOp(v, OP_Goto, 0, addrInitializeLoop);
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag);
+ VdbeComment((v, "clear abort flag"));
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
+ VdbeComment((v, "indicate accumulator empty"));
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrInitializeLoop);
/* Generate a subroutine that outputs a single row of the result
** set. This subroutine first looks at the iUseFlag. If iUseFlag
@@ -3085,31 +3343,28 @@ int sqlite3Select(
** order to signal the caller to abort.
*/
addrSetAbort = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeAddOp(v, OP_MemInt, 1, iAbortFlag);
- VdbeComment((v, "# set abort flag"));
- sqlite3VdbeAddOp(v, OP_Return, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, iAbortFlag);
+ VdbeComment((v, "set abort flag"));
+ sqlite3VdbeAddOp2(v, OP_Return, 0, 0);
addrOutputRow = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeAddOp(v, OP_IfMemPos, iUseFlag, addrOutputRow+2);
- VdbeComment((v, "# Groupby result generator entry point"));
- sqlite3VdbeAddOp(v, OP_Return, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2);
+ VdbeComment((v, "Groupby result generator entry point"));
+ sqlite3VdbeAddOp2(v, OP_Return, 0, 0);
finalizeAggFunctions(pParse, &sAggInfo);
if( pHaving ){
- sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, 1);
+ sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
}
- rc = selectInnerLoop(pParse, p, p->pEList, 0, 0, pOrderBy,
- distinct, eDest, iParm,
- addrOutputRow+1, addrSetAbort, aff);
- if( rc ){
- goto select_end;
- }
- sqlite3VdbeAddOp(v, OP_Return, 0, 0);
- VdbeComment((v, "# end groupby result generator"));
+ selectInnerLoop(pParse, p, p->pEList, 0, 0, pOrderBy,
+ distinct, pDest,
+ addrOutputRow+1, addrSetAbort, aff);
+ sqlite3VdbeAddOp2(v, OP_Return, 0, 0);
+ VdbeComment((v, "end groupby result generator"));
/* Generate a subroutine that will reset the group-by accumulator
*/
addrReset = sqlite3VdbeCurrentAddr(v);
resetAccumulator(pParse, &sAggInfo);
- sqlite3VdbeAddOp(v, OP_Return, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_Return, 0, 0);
/* Begin a loop that will extract all source rows in GROUP BY order.
** This might involve two separate loops with an OP_Sort in between, or
@@ -3117,8 +3372,8 @@ int sqlite3Select(
** in the right order to begin with.
*/
sqlite3VdbeResolveLabel(v, addrInitializeLoop);
- sqlite3VdbeAddOp(v, OP_Gosub, 0, addrReset);
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy);
+ sqlite3VdbeAddOp2(v, OP_Gosub, 0, addrReset);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0);
if( pWInfo==0 ) goto select_end;
if( pGroupBy==0 ){
/* The optimizer is able to deliver rows in group by order so
@@ -3133,25 +3388,41 @@ int sqlite3Select(
** then loop over the sorting index in order to get the output
** in sorted order
*/
+ int regBase;
+ int regRecord;
+ int nCol;
+ int nGroupBy;
+
groupBySort = 1;
- sqlite3ExprCodeExprList(pParse, pGroupBy);
- sqlite3VdbeAddOp(v, OP_Sequence, sAggInfo.sortingIdx, 0);
- j = pGroupBy->nExpr+1;
+ nGroupBy = pGroupBy->nExpr;
+ nCol = nGroupBy + 1;
+ j = nGroupBy+1;
+ for(i=0; i<sAggInfo.nColumn; i++){
+ if( sAggInfo.aCol[i].iSorterColumn>=j ){
+ nCol++;
+ j++;
+ }
+ }
+ regBase = sqlite3GetTempRange(pParse, nCol);
+ sqlite3ExprCodeExprList(pParse, pGroupBy, regBase);
+ sqlite3VdbeAddOp2(v, OP_Sequence, sAggInfo.sortingIdx,regBase+nGroupBy);
+ j = nGroupBy+1;
for(i=0; i<sAggInfo.nColumn; i++){
struct AggInfo_col *pCol = &sAggInfo.aCol[i];
- if( pCol->iSorterColumn<j ) continue;
- if( pCol->iColumn<0 ){
- sqlite3VdbeAddOp(v, OP_Rowid, pCol->iTable, 0);
- }else{
- sqlite3VdbeAddOp(v, OP_Column, pCol->iTable, pCol->iColumn);
+ if( pCol->iSorterColumn>=j ){
+ sqlite3ExprCodeGetColumn(v, pCol->pTab, pCol->iColumn, pCol->iTable,
+ j + regBase);
+ j++;
}
- j++;
}
- sqlite3VdbeAddOp(v, OP_MakeRecord, j, 0);
- sqlite3VdbeAddOp(v, OP_IdxInsert, sAggInfo.sortingIdx, 0);
+ regRecord = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, sAggInfo.sortingIdx, regRecord);
+ sqlite3ReleaseTempReg(pParse, regRecord);
+ sqlite3ReleaseTempRange(pParse, regBase, nCol);
sqlite3WhereEnd(pWInfo);
- sqlite3VdbeAddOp(v, OP_Sort, sAggInfo.sortingIdx, addrEnd);
- VdbeComment((v, "# GROUP BY sort"));
+ sqlite3VdbeAddOp2(v, OP_Sort, sAggInfo.sortingIdx, addrEnd);
+ VdbeComment((v, "GROUP BY sort"));
sAggInfo.useSortingIdx = 1;
}
@@ -3163,24 +3434,20 @@ int sqlite3Select(
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
for(j=0; j<pGroupBy->nExpr; j++){
if( groupBySort ){
- sqlite3VdbeAddOp(v, OP_Column, sAggInfo.sortingIdx, j);
+ sqlite3VdbeAddOp3(v, OP_Column, sAggInfo.sortingIdx, j, iBMem+j);
}else{
sAggInfo.directMode = 1;
- sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr);
+ sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
}
- sqlite3VdbeAddOp(v, OP_MemStore, iBMem+j, j<pGroupBy->nExpr-1);
}
for(j=pGroupBy->nExpr-1; j>=0; j--){
- if( j<pGroupBy->nExpr-1 ){
- sqlite3VdbeAddOp(v, OP_MemLoad, iBMem+j, 0);
- }
- sqlite3VdbeAddOp(v, OP_MemLoad, iAMem+j, 0);
if( j==0 ){
- sqlite3VdbeAddOp(v, OP_Eq, 0x200, addrProcessRow);
+ sqlite3VdbeAddOp3(v, OP_Eq, iAMem+j, addrProcessRow, iBMem+j);
}else{
- sqlite3VdbeAddOp(v, OP_Ne, 0x200, addrGroupByChange);
+ sqlite3VdbeAddOp3(v, OP_Ne, iAMem+j, addrGroupByChange, iBMem+j);
}
- sqlite3VdbeChangeP3(v, -1, (void*)pKeyInfo->aColl[j], P3_COLLSEQ);
+ sqlite3VdbeChangeP4(v, -1, (void*)pKeyInfo->aColl[j], P4_COLLSEQ);
+ sqlite3VdbeChangeP5(v, SQLITE_NULLEQUAL);
}
/* Generate code that runs whenever the GROUP BY changes.
@@ -3194,27 +3461,27 @@ int sqlite3Select(
*/
sqlite3VdbeResolveLabel(v, addrGroupByChange);
for(j=0; j<pGroupBy->nExpr; j++){
- sqlite3VdbeAddOp(v, OP_MemMove, iAMem+j, iBMem+j);
+ sqlite3VdbeAddOp2(v, OP_Move, iBMem+j, iAMem+j);
}
- sqlite3VdbeAddOp(v, OP_Gosub, 0, addrOutputRow);
- VdbeComment((v, "# output one row"));
- sqlite3VdbeAddOp(v, OP_IfMemPos, iAbortFlag, addrEnd);
- VdbeComment((v, "# check abort flag"));
- sqlite3VdbeAddOp(v, OP_Gosub, 0, addrReset);
- VdbeComment((v, "# reset accumulator"));
+ sqlite3VdbeAddOp2(v, OP_Gosub, 0, addrOutputRow);
+ VdbeComment((v, "output one row"));
+ sqlite3VdbeAddOp2(v, OP_IfPos, iAbortFlag, addrEnd);
+ VdbeComment((v, "check abort flag"));
+ sqlite3VdbeAddOp2(v, OP_Gosub, 0, addrReset);
+ VdbeComment((v, "reset accumulator"));
/* Update the aggregate accumulators based on the content of
** the current row
*/
sqlite3VdbeResolveLabel(v, addrProcessRow);
updateAccumulator(pParse, &sAggInfo);
- sqlite3VdbeAddOp(v, OP_MemInt, 1, iUseFlag);
- VdbeComment((v, "# indicate data in accumulator"));
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
+ VdbeComment((v, "indicate data in accumulator"));
/* End of the loop
*/
if( groupBySort ){
- sqlite3VdbeAddOp(v, OP_Next, sAggInfo.sortingIdx, addrTopOfLoop);
+ sqlite3VdbeAddOp2(v, OP_Next, sAggInfo.sortingIdx, addrTopOfLoop);
}else{
sqlite3WhereEnd(pWInfo);
sqlite3VdbeChangeToNoop(v, addrSortingIdx, 1);
@@ -3222,27 +3489,74 @@ int sqlite3Select(
/* Output the final row of result
*/
- sqlite3VdbeAddOp(v, OP_Gosub, 0, addrOutputRow);
- VdbeComment((v, "# output final row"));
+ sqlite3VdbeAddOp2(v, OP_Gosub, 0, addrOutputRow);
+ VdbeComment((v, "output final row"));
} /* endif pGroupBy */
else {
+ ExprList *pMinMax = 0;
+ ExprList *pDel = 0;
+ u8 flag;
+
+ /* Check if the query is of one of the following forms:
+ **
+ ** SELECT min(x) FROM ...
+ ** SELECT max(x) FROM ...
+ **
+ ** If it is, then ask the code in where.c to attempt to sort results
+ ** as if there was an "ORDER ON x" or "ORDER ON x DESC" clause.
+ ** If where.c is able to produce results sorted in this order, then
+ ** add vdbe code to break out of the processing loop after the
+ ** first iteration (since the first iteration of the loop is
+ ** guaranteed to operate on the row with the minimum or maximum
+ ** value of x, the only row required).
+ **
+ ** A special flag must be passed to sqlite3WhereBegin() to slightly
+ ** modify behaviour as follows:
+ **
+ ** + If the query is a "SELECT min(x)", then the loop coded by
+ ** where.c should not iterate over any values with a NULL value
+ ** for x.
+ **
+ ** + The optimizer code in where.c (the thing that decides which
+ ** index or indices to use) should place a different priority on
+ ** satisfying the 'ORDER BY' clause than it does in other cases.
+ ** Refer to code and comments in where.c for details.
+ */
+ flag = minMaxQuery(pParse, p);
+ if( flag ){
+ pDel = pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->pList);
+ if( pMinMax && !db->mallocFailed ){
+ pMinMax->a[0].sortOrder = ((flag==ORDERBY_MIN)?0:1);
+ pMinMax->a[0].pExpr->op = TK_COLUMN;
+ }
+ }
+
/* This case runs if the aggregate has no GROUP BY clause. The
** processing is much simpler since there is only a single row
** of output.
*/
resetAccumulator(pParse, &sAggInfo);
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
- if( pWInfo==0 ) goto select_end;
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag);
+ if( pWInfo==0 ){
+ sqlite3ExprListDelete(pDel);
+ goto select_end;
+ }
updateAccumulator(pParse, &sAggInfo);
+ if( !pMinMax && flag ){
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iBreak);
+ VdbeComment((v, "%s() by index", (flag==ORDERBY_MIN?"min":"max")));
+ }
sqlite3WhereEnd(pWInfo);
finalizeAggFunctions(pParse, &sAggInfo);
pOrderBy = 0;
if( pHaving ){
- sqlite3ExprIfFalse(pParse, pHaving, addrEnd, 1);
+ sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
}
selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, -1,
- eDest, iParm, addrEnd, addrEnd, aff);
+ pDest, addrEnd, addrEnd, aff);
+
+ sqlite3ExprListDelete(pDel);
}
sqlite3VdbeResolveLabel(v, addrEnd);
@@ -3252,7 +3566,7 @@ int sqlite3Select(
** and send them to the callback one by one.
*/
if( pOrderBy ){
- generateSortTail(pParse, p, v, pEList->nExpr, eDest, iParm);
+ generateSortTail(pParse, p, v, pEList->nExpr, pDest);
}
#ifndef SQLITE_OMIT_SUBQUERY
@@ -3285,11 +3599,107 @@ 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 ){
+ if( rc==SQLITE_OK && pDest->eDest==SRT_Callback ){
generateColumnNames(pParse, pTabList, pEList);
}
- sqliteFree(sAggInfo.aCol);
- sqliteFree(sAggInfo.aFunc);
+ sqlite3_free(sAggInfo.aCol);
+ sqlite3_free(sAggInfo.aFunc);
return rc;
}
+
+#if defined(SQLITE_DEBUG)
+/*
+*******************************************************************************
+** The following code is used for testing and debugging only. The code
+** that follows does not appear in normal builds.
+**
+** These routines are used to print out the content of all or part of a
+** parse structures such as Select or Expr. Such printouts are useful
+** for helping to understand what is happening inside the code generator
+** during the execution of complex SELECT statements.
+**
+** These routine are not called anywhere from within the normal
+** code base. Then are intended to be called from within the debugger
+** or from temporary "printf" statements inserted for debugging.
+*/
+void sqlite3PrintExpr(Expr *p){
+ if( p->token.z && p->token.n>0 ){
+ sqlite3DebugPrintf("(%.*s", p->token.n, p->token.z);
+ }else{
+ sqlite3DebugPrintf("(%d", p->op);
+ }
+ if( p->pLeft ){
+ sqlite3DebugPrintf(" ");
+ sqlite3PrintExpr(p->pLeft);
+ }
+ if( p->pRight ){
+ sqlite3DebugPrintf(" ");
+ sqlite3PrintExpr(p->pRight);
+ }
+ sqlite3DebugPrintf(")");
+}
+void sqlite3PrintExprList(ExprList *pList){
+ int i;
+ for(i=0; i<pList->nExpr; i++){
+ sqlite3PrintExpr(pList->a[i].pExpr);
+ if( i<pList->nExpr-1 ){
+ sqlite3DebugPrintf(", ");
+ }
+ }
+}
+void sqlite3PrintSelect(Select *p, int indent){
+ sqlite3DebugPrintf("%*sSELECT(%p) ", indent, "", p);
+ sqlite3PrintExprList(p->pEList);
+ sqlite3DebugPrintf("\n");
+ if( p->pSrc ){
+ char *zPrefix;
+ int i;
+ zPrefix = "FROM";
+ for(i=0; i<p->pSrc->nSrc; i++){
+ struct SrcList_item *pItem = &p->pSrc->a[i];
+ sqlite3DebugPrintf("%*s ", indent+6, zPrefix);
+ zPrefix = "";
+ if( pItem->pSelect ){
+ sqlite3DebugPrintf("(\n");
+ sqlite3PrintSelect(pItem->pSelect, indent+10);
+ sqlite3DebugPrintf("%*s)", indent+8, "");
+ }else if( pItem->zName ){
+ sqlite3DebugPrintf("%s", pItem->zName);
+ }
+ if( pItem->pTab ){
+ sqlite3DebugPrintf("(table: %s)", pItem->pTab->zName);
+ }
+ if( pItem->zAlias ){
+ sqlite3DebugPrintf(" AS %s", pItem->zAlias);
+ }
+ if( i<p->pSrc->nSrc-1 ){
+ sqlite3DebugPrintf(",");
+ }
+ sqlite3DebugPrintf("\n");
+ }
+ }
+ if( p->pWhere ){
+ sqlite3DebugPrintf("%*s WHERE ", indent, "");
+ sqlite3PrintExpr(p->pWhere);
+ sqlite3DebugPrintf("\n");
+ }
+ if( p->pGroupBy ){
+ sqlite3DebugPrintf("%*s GROUP BY ", indent, "");
+ sqlite3PrintExprList(p->pGroupBy);
+ sqlite3DebugPrintf("\n");
+ }
+ if( p->pHaving ){
+ sqlite3DebugPrintf("%*s HAVING ", indent, "");
+ sqlite3PrintExpr(p->pHaving);
+ sqlite3DebugPrintf("\n");
+ }
+ if( p->pOrderBy ){
+ sqlite3DebugPrintf("%*s ORDER BY ", indent, "");
+ sqlite3PrintExprList(p->pOrderBy);
+ sqlite3DebugPrintf("\n");
+ }
+}
+/* End of the structure debug printing code
+*****************************************************************************/
+#endif /* defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
diff --git a/ext/pdo_sqlite/sqlite/src/shell.c b/ext/pdo_sqlite/sqlite/src/shell.c
index 6058bc195e..0aa2eb9eb4 100644
--- a/ext/pdo_sqlite/sqlite/src/shell.c
+++ b/ext/pdo_sqlite/sqlite/src/shell.c
@@ -20,23 +20,15 @@
#include <assert.h>
#include "sqlite3.h"
#include <ctype.h>
+#include <stdarg.h>
-#if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__) && !defined(__OS2__)
+#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__)
# include <signal.h>
# include <pwd.h>
# include <unistd.h>
# include <sys/types.h>
#endif
-#ifdef __MACOS__
-# include <console.h>
-# include <signal.h>
-# include <unistd.h>
-# include <extras.h>
-# include <Files.h>
-# include <Folders.h>
-#endif
-
#ifdef __OS2__
# include <unistd.h>
#endif
@@ -52,9 +44,80 @@
# define stifle_history(X)
#endif
+#if defined(_WIN32) || defined(WIN32)
+# include <io.h>
+#else
/* Make sure isatty() has a prototype.
*/
extern int isatty();
+#endif
+
+#if defined(_WIN32_WCE)
+/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
+ * thus we always assume that we have a console. That can be
+ * overridden with the -batch command line option.
+ */
+#define isatty(x) 1
+#endif
+
+#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__)
+#include <sys/time.h>
+#include <sys/resource.h>
+
+/* Saved resource information for the beginning of an operation */
+static struct rusage sBegin;
+
+/* True if the timer is enabled */
+static int enableTimer = 0;
+
+/*
+** Begin timing an operation
+*/
+static void beginTimer(void){
+ if( enableTimer ){
+ getrusage(RUSAGE_SELF, &sBegin);
+ }
+}
+
+/* Return the difference of two time_structs in microseconds */
+static int timeDiff(struct timeval *pStart, struct timeval *pEnd){
+ return (pEnd->tv_usec - pStart->tv_usec) +
+ 1000000*(pEnd->tv_sec - pStart->tv_sec);
+}
+
+/*
+** Print the timing results.
+*/
+static void endTimer(void){
+ if( enableTimer ){
+ struct rusage sEnd;
+ getrusage(RUSAGE_SELF, &sEnd);
+ printf("CPU Time: user %f sys %f\n",
+ 0.000001*timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
+ 0.000001*timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
+ }
+}
+#define BEGIN_TIMER beginTimer()
+#define END_TIMER endTimer()
+#define HAS_TIMER 1
+#else
+#define BEGIN_TIMER
+#define END_TIMER
+#define HAS_TIMER 0
+#endif
+
+
+/*
+** If the following flag is set, then command execution stops
+** at an error if we are not interactive.
+*/
+static int bail_on_error = 0;
+
+/*
+** Threat stdin as an interactive input if the following variable
+** is true. Otherwise, assume stdin is connected to a file or pipe.
+*/
+static int stdin_is_interactive = 1;
/*
** The following is the open SQLite database. We make a pointer
@@ -81,6 +144,32 @@ static char *Argv0;
static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/
static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
+/*
+** Write I/O traces to the following stream.
+*/
+#ifdef SQLITE_ENABLE_IOTRACE
+static FILE *iotrace = 0;
+#endif
+
+/*
+** This routine works like printf in that its first argument is a
+** format string and subsequent arguments are values to be substituted
+** in place of % fields. The result of formatting this string
+** is written to iotrace.
+*/
+#ifdef SQLITE_ENABLE_IOTRACE
+static void iotracePrintf(const char *zFormat, ...){
+ va_list ap;
+ char *z;
+ if( iotrace==0 ) return;
+ va_start(ap, zFormat);
+ z = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+ fprintf(iotrace, "%s", z);
+ sqlite3_free(z);
+}
+#endif
+
/*
** Determines if a string is a number of not.
@@ -180,10 +269,7 @@ static char *local_getline(char *zPrompt, FILE *in){
}
/*
-** Retrieve a single line of input text. "isatty" is true if text
-** is coming from a terminal. In that case, we issue a prompt and
-** attempt to use "readline" for command-line editing. If "isatty"
-** is false, use "local_getline" instead of "readline" and issue no prompt.
+** Retrieve a single line of input text.
**
** zPrior is a string of prior text retrieved. If not the empty
** string, then issue a continuation prompt.
@@ -212,6 +298,7 @@ struct previous_mode_data {
int showHeader;
int colWidth[100];
};
+
/*
** An pointer to an instance of this structure is passed from
** the main program to the callback. This is used to communicate
@@ -223,6 +310,7 @@ struct callback_data {
int cnt; /* Number of records displayed so far */
FILE *out; /* Write results here */
int mode; /* An output mode setting */
+ int writableSchema; /* True if PRAGMA writable_schema=ON */
int showHeader; /* True to show column names in List or Column mode */
char *zDestTable; /* Name of destination table when MODE_Insert */
char separator[20]; /* Separator character for MODE_List */
@@ -235,7 +323,6 @@ struct callback_data {
** .explain ON */
char outfile[FILENAME_MAX]; /* Filename for *out */
const char *zDbFilename; /* name of the database file */
- char *zKey; /* Encryption key */
};
/*
@@ -250,6 +337,7 @@ struct callback_data {
#define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */
#define MODE_Csv 7 /* Quote strings, numbers are plain */
#define MODE_NUM_OF 8 /* The number of modes (not a mode itself) */
+#define MODE_Explain 9 /* Like MODE_Column, but do not truncate data */
static const char *modeDescr[MODE_NUM_OF] = {
"line",
@@ -348,21 +436,62 @@ static void output_html_string(FILE *out, const char *z){
}
/*
+** If a field contains any character identified by a 1 in the following
+** array, then the string must be quoted for CSV.
+*/
+static const char needCsvQuote[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+/*
** Output a single term of CSV. Actually, p->separator is used for
** the separator, which may or may not be a comma. p->nullvalue is
** the null value. Strings are quoted using ANSI-C rules. Numbers
** appear outside of quotes.
*/
static void output_csv(struct callback_data *p, const char *z, int bSep){
+ FILE *out = p->out;
if( z==0 ){
- fprintf(p->out,"%s",p->nullvalue);
- }else if( isNumber(z, 0) ){
- fprintf(p->out,"%s",z);
+ fprintf(out,"%s",p->nullvalue);
}else{
- output_c_string(p->out, z);
+ int i;
+ int nSep = strlen(p->separator);
+ for(i=0; z[i]; i++){
+ if( needCsvQuote[((unsigned char*)z)[i]]
+ || (z[i]==p->separator[0] &&
+ (nSep==1 || memcmp(z, p->separator, nSep)==0)) ){
+ i = 0;
+ break;
+ }
+ }
+ if( i==0 ){
+ putc('"', out);
+ for(i=0; z[i]; i++){
+ if( z[i]=='"' ) putc('"', out);
+ putc(z[i], out);
+ }
+ putc('"', out);
+ }else{
+ fprintf(out, "%s", z);
+ }
}
if( bSep ){
- fprintf(p->out, p->separator);
+ fprintf(p->out, "%s", p->separator);
}
}
@@ -398,14 +527,15 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
}
break;
}
+ case MODE_Explain:
case MODE_Column: {
if( p->cnt++==0 ){
for(i=0; i<nArg; i++){
int w, n;
if( i<ArraySize(p->colWidth) ){
- w = p->colWidth[i];
+ w = p->colWidth[i];
}else{
- w = 0;
+ w = 0;
}
if( w<=0 ){
w = strlen(azCol[i] ? azCol[i] : "");
@@ -442,6 +572,9 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
}else{
w = 10;
}
+ if( p->mode==MODE_Explain && azArg[i] && strlen(azArg[i])>w ){
+ w = strlen(azArg[i]);
+ }
fprintf(p->out,"%-*.*s%s",w,w,
azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
}
@@ -584,7 +717,7 @@ static void set_table_name(struct callback_data *p, const char *zName){
** If the third argument, quote, is not '\0', then it is used as a
** quote character for zAppend.
*/
-static char * appendText(char *zIn, char const *zAppend, char quote){
+static char *appendText(char *zIn, char const *zAppend, char quote){
int len;
int i;
int nAppend = strlen(zAppend);
@@ -625,6 +758,9 @@ static char * appendText(char *zIn, char const *zAppend, char quote){
/*
** Execute a query statement that has a single result column. Print
** that result column on a line by itself with a semicolon terminator.
+**
+** This is used, for example, to show the schema of the database by
+** querying the SQLITE_MASTER table.
*/
static int run_table_dump_query(FILE *out, sqlite3 *db, const char *zSelect){
sqlite3_stmt *pSelect;
@@ -666,6 +802,19 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
fprintf(p->out, "ANALYZE sqlite_master;\n");
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
return 0;
+ }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
+ char *zIns;
+ if( !p->writableSchema ){
+ fprintf(p->out, "PRAGMA writable_schema=ON;\n");
+ p->writableSchema = 1;
+ }
+ zIns = sqlite3_mprintf(
+ "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
+ "VALUES('table','%q','%q',0,'%q');",
+ zTable, zTable, zSql);
+ fprintf(p->out, "%s\n", zIns);
+ sqlite3_free(zIns);
+ return 0;
}else{
fprintf(p->out, "%s;\n", zSql);
}
@@ -699,7 +848,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
zSelect = appendText(zSelect, zText, '"');
rc = sqlite3_step(pTableInfo);
if( rc==SQLITE_ROW ){
- zSelect = appendText(zSelect, ") || ', ' || ", 0);
+ zSelect = appendText(zSelect, ") || ',' || ", 0);
}else{
zSelect = appendText(zSelect, ") ", 0);
}
@@ -718,15 +867,14 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
rc = run_table_dump_query(p->out, p->db, zSelect);
}
if( zSelect ) free(zSelect);
- if( rc!=SQLITE_OK ){
- return 1;
- }
}
return 0;
}
/*
-** Run zQuery. Update dump_callback() as the callback routine.
+** Run zQuery. Use dump_callback() as the callback routine so that
+** the contents of the query are output as SQL statements.
+**
** If we get a SQLITE_CORRUPT error, rerun the query after appending
** "ORDER BY rowid DESC" to the end.
*/
@@ -743,7 +891,7 @@ static int run_schema_dump_query(
if( pzErrMsg ) sqlite3_free(*pzErrMsg);
zQ2 = malloc( len+100 );
if( zQ2==0 ) return rc;
- sprintf(zQ2, "%s ORDER BY rowid DESC", zQuery);
+ sqlite3_snprintf(sizeof(zQ2), zQ2, "%s ORDER BY rowid DESC", zQuery);
rc = sqlite3_exec(p->db, zQ2, dump_callback, p, pzErrMsg);
free(zQ2);
}
@@ -754,6 +902,7 @@ static int run_schema_dump_query(
** Text of a help message
*/
static char zHelp[] =
+ ".bail ON|OFF Stop after hitting an error. Default OFF\n"
".databases List names and files of attached databases\n"
".dump ?TABLE? ... Dump the database in an SQL text format\n"
".echo ON|OFF Turn command echo on or off\n"
@@ -763,6 +912,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"
+#ifdef SQLITE_ENABLE_IOTRACE
+ ".iotrace FILE Enable I/O diagnostic logging to FILE\n"
+#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
".load FILE ?ENTRY? Load an extension library\n"
#endif
@@ -786,11 +938,14 @@ static char zHelp[] =
".show Show the current values for various settings\n"
".tables ?PATTERN? List names of tables matching a LIKE pattern\n"
".timeout MS Try opening locked tables for MS milliseconds\n"
+#if HAS_TIMER
+ ".timer ON|OFF Turn the CPU timer measurement on or off\n"
+#endif
".width NUM NUM ... Set column widths for \"column\" mode\n"
;
/* Forward reference */
-static void process_input(struct callback_data *p, FILE *in);
+static int process_input(struct callback_data *p, FILE *in);
/*
** Make sure the database is open. If it is not, then open it. If
@@ -851,10 +1006,27 @@ static void resolve_backslashes(char *z){
}
/*
+** Interpret zArg as a boolean value. Return either 0 or 1.
+*/
+static int booleanValue(char *zArg){
+ int val = atoi(zArg);
+ int j;
+ for(j=0; zArg[j]; j++){
+ zArg[j] = tolower(zArg[j]);
+ }
+ if( strcmp(zArg,"on")==0 ){
+ val = 1;
+ }else if( strcmp(zArg,"yes")==0 ){
+ val = 1;
+ }
+ return val;
+}
+
+/*
** If an input line begins with "." then invoke this routine to
** process that line.
**
-** Return 1 to exit and 0 to continue.
+** Return 1 on error, 2 to exit, and 0 otherwise.
*/
static int do_meta_command(char *zLine, struct callback_data *p){
int i = 1;
@@ -889,6 +1061,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( nArg==0 ) return rc;
n = strlen(azArg[0]);
c = azArg[0][0];
+ if( c=='b' && n>1 && strncmp(azArg[0], "bail", n)==0 && nArg>1 ){
+ bail_on_error = booleanValue(azArg[1]);
+ }else
+
if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){
struct callback_data data;
char *zErrMsg = 0;
@@ -911,14 +1087,15 @@ static int do_meta_command(char *zLine, struct callback_data *p){
char *zErrMsg = 0;
open_db(p);
fprintf(p->out, "BEGIN TRANSACTION;\n");
+ p->writableSchema = 0;
if( nArg==1 ){
run_schema_dump_query(p,
"SELECT name, type, sql FROM sqlite_master "
"WHERE sql NOT NULL AND type=='table'", 0
);
- run_schema_dump_query(p,
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE sql NOT NULL AND type!='table' AND type!='meta'", 0
+ run_table_dump_query(p->out, p->db,
+ "SELECT sql FROM sqlite_master "
+ "WHERE sql NOT NULL AND type IN ('index','trigger','view')"
);
}else{
int i;
@@ -928,13 +1105,19 @@ static int do_meta_command(char *zLine, struct callback_data *p){
"SELECT name, type, sql FROM sqlite_master "
"WHERE tbl_name LIKE shellstatic() AND type=='table'"
" AND sql NOT NULL", 0);
- run_schema_dump_query(p,
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE tbl_name LIKE shellstatic() AND type!='table'"
- " AND type!='meta' AND sql NOT NULL", 0);
+ run_table_dump_query(p->out, p->db,
+ "SELECT sql FROM sqlite_master "
+ "WHERE sql NOT NULL"
+ " AND type IN ('index','trigger','view')"
+ " AND tbl_name LIKE shellstatic()"
+ );
zShellStatic = 0;
}
}
+ if( p->writableSchema ){
+ fprintf(p->out, "PRAGMA writable_schema=OFF;\n");
+ p->writableSchema = 0;
+ }
if( zErrMsg ){
fprintf(stderr,"Error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
@@ -944,37 +1127,15 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}else
if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){
- int j;
- char *z = azArg[1];
- int val = atoi(azArg[1]);
- for(j=0; z[j]; j++){
- z[j] = tolower((unsigned char)z[j]);
- }
- if( strcmp(z,"on")==0 ){
- val = 1;
- }else if( strcmp(z,"yes")==0 ){
- val = 1;
- }
- p->echoOn = val;
+ p->echoOn = booleanValue(azArg[1]);
}else
if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
- rc = 1;
+ rc = 2;
}else
if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
- int j;
- static char zOne[] = "1";
- char *z = nArg>=2 ? azArg[1] : zOne;
- int val = atoi(z);
- for(j=0; z[j]; j++){
- z[j] = tolower((unsigned char)z[j]);
- }
- if( strcmp(z,"on")==0 ){
- val = 1;
- }else if( strcmp(z,"yes")==0 ){
- val = 1;
- }
+ int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
if(val == 1) {
if(!p->explainPrev.valid) {
p->explainPrev.valid = 1;
@@ -989,14 +1150,17 @@ static int do_meta_command(char *zLine, struct callback_data *p){
** did an .explain followed by a .width, .mode or .header
** command.
*/
- p->mode = MODE_Column;
+ p->mode = MODE_Explain;
p->showHeader = 1;
memset(p->colWidth,0,ArraySize(p->colWidth));
- p->colWidth[0] = 4;
- p->colWidth[1] = 14;
- p->colWidth[2] = 10;
- p->colWidth[3] = 10;
- p->colWidth[4] = 33;
+ p->colWidth[0] = 4; /* addr */
+ p->colWidth[1] = 13; /* opcode */
+ p->colWidth[2] = 4; /* P1 */
+ p->colWidth[3] = 4; /* P2 */
+ p->colWidth[4] = 4; /* P3 */
+ p->colWidth[5] = 13; /* P4 */
+ p->colWidth[6] = 2; /* P5 */
+ p->colWidth[7] = 13; /* Comment */
}else if (p->explainPrev.valid) {
p->explainPrev.valid = 0;
p->mode = p->explainPrev.mode;
@@ -1005,21 +1169,9 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}
}else
- if( c=='h' && (strncmp(azArg[0], "header", n)==0
- ||
+ if( c=='h' && (strncmp(azArg[0], "header", n)==0 ||
strncmp(azArg[0], "headers", n)==0 )&& nArg>1 ){
- int j;
- char *z = azArg[1];
- int val = atoi(azArg[1]);
- for(j=0; z[j]; j++){
- z[j] = tolower((unsigned char)z[j]);
- }
- if( strcmp(z,"on")==0 ){
- val = 1;
- }else if( strcmp(z,"yes")==0 ){
- val = 1;
- }
- p->showHeader = val;
+ p->showHeader = booleanValue(azArg[1]);
}else
if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
@@ -1056,6 +1208,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( rc ){
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
nCol = 0;
+ rc = 1;
}else{
nCol = sqlite3_column_count(pStmt);
}
@@ -1076,7 +1229,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( rc ){
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
sqlite3_finalize(pStmt);
- return 0;
+ return 1;
}
in = fopen(zFile, "rb");
if( in==0 ){
@@ -1122,6 +1275,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( rc!=SQLITE_OK ){
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
zCommit = "ROLLBACK";
+ rc = 1;
break;
}
}
@@ -1155,6 +1309,28 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}
}else
+#ifdef SQLITE_ENABLE_IOTRACE
+ if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
+ extern void (*sqlite3_io_trace)(const char*, ...);
+ if( iotrace && iotrace!=stdout ) fclose(iotrace);
+ iotrace = 0;
+ if( nArg<2 ){
+ sqlite3_io_trace = 0;
+ }else if( strcmp(azArg[1], "-")==0 ){
+ sqlite3_io_trace = iotracePrintf;
+ iotrace = stdout;
+ }else{
+ iotrace = fopen(azArg[1], "w");
+ if( iotrace==0 ){
+ fprintf(stderr, "cannot open \"%s\"\n", azArg[1]);
+ sqlite3_io_trace = 0;
+ }else{
+ sqlite3_io_trace = iotracePrintf;
+ }
+ }
+ }else
+#endif
+
#ifndef SQLITE_OMIT_LOAD_EXTENSION
if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
const char *zFile, *zProc;
@@ -1167,6 +1343,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( rc!=SQLITE_OK ){
fprintf(stderr, "%s\n", zErrMsg);
sqlite3_free(zErrMsg);
+ rc = 1;
}
}else
#endif
@@ -1189,10 +1366,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
p->mode = MODE_Tcl;
}else if( strncmp(azArg[1],"csv",n2)==0 ){
p->mode = MODE_Csv;
- strcpy(p->separator, ",");
+ sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
}else if( strncmp(azArg[1],"tabs",n2)==0 ){
p->mode = MODE_List;
- strcpy(p->separator, "\t");
+ sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
}else if( strncmp(azArg[1],"insert",n2)==0 ){
p->mode = MODE_Insert;
if( nArg>=3 ){
@@ -1201,13 +1378,14 @@ static int do_meta_command(char *zLine, struct callback_data *p){
set_table_name(p, "table");
}
}else {
- fprintf(stderr,"mode should be on of: "
+ fprintf(stderr,"mode should be one of: "
"column csv html insert line list tabs tcl\n");
}
}else
if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
- sprintf(p->nullvalue, "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
+ sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
+ "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
}else
if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
@@ -1216,14 +1394,14 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}
if( strcmp(azArg[1],"stdout")==0 ){
p->out = stdout;
- strcpy(p->outfile,"stdout");
+ sqlite3_snprintf(sizeof(p->outfile), p->outfile, "stdout");
}else{
p->out = fopen(azArg[1], "wb");
if( p->out==0 ){
fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
p->out = stdout;
} else {
- strcpy(p->outfile,azArg[1]);
+ sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]);
}
}
}else
@@ -1238,7 +1416,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}else
if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
- rc = 1;
+ rc = 2;
}else
if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
@@ -1315,7 +1493,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}else
if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
- sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
+ sqlite3_snprintf(sizeof(p->separator), p->separator,
+ "%.*s", (int)sizeof(p->separator)-1, azArg[1]);
}else
if( c=='s' && strncmp(azArg[0], "show", n)==0){
@@ -1390,14 +1569,22 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}
printf("\n");
}
+ }else{
+ rc = 1;
}
sqlite3_free_table(azResult);
}else
- if( c=='t' && n>1 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
+ if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
open_db(p);
sqlite3_busy_timeout(p->db, atoi(azArg[1]));
}else
+
+#if HAS_TIMER
+ if( c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 && nArg>1 ){
+ enableTimer = booleanValue(azArg[1]);
+ }else
+#endif
if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
int j;
@@ -1407,6 +1594,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}
}else
+
{
fprintf(stderr, "unknown command or invalid arguments: "
" \"%s\". Enter \".help\" for help\n", azArg[0]);
@@ -1416,12 +1604,13 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}
/*
-** Return TRUE if the last non-whitespace character in z[] is a semicolon.
-** z[] is N characters long.
+** Return TRUE if a semicolon occurs anywhere in the first N characters
+** of string z[].
*/
-static int _ends_with_semicolon(const char *z, int N){
- while( N>0 && isspace((unsigned char)z[N-1]) ){ N--; }
- return N>0 && z[N-1]==';';
+static int _contains_semicolon(const char *z, int N){
+ int i;
+ for(i=0; i<N; i++){ if( z[i]==';' ) return 1; }
+ return 0;
}
/*
@@ -1469,29 +1658,47 @@ static int _is_command_terminator(const char *zLine){
** is coming from a file or device. A prompt is issued and history
** is saved only if input is interactive. An interrupt signal will
** cause this routine to exit immediately, unless input is interactive.
+**
+** Return the number of errors.
*/
-static void process_input(struct callback_data *p, FILE *in){
- char *zLine;
+static int process_input(struct callback_data *p, FILE *in){
+ char *zLine = 0;
char *zSql = 0;
int nSql = 0;
+ int nSqlPrior = 0;
char *zErrMsg;
int rc;
- while( fflush(p->out), (zLine = one_input_line(zSql, in))!=0 ){
+ int errCnt = 0;
+ int lineno = 0;
+ int startline = 0;
+
+ while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
+ fflush(p->out);
+ free(zLine);
+ zLine = one_input_line(zSql, in);
+ if( zLine==0 ){
+ break; /* We have reached EOF */
+ }
if( seenInterrupt ){
if( in!=0 ) break;
seenInterrupt = 0;
}
+ lineno++;
if( p->echoOn ) printf("%s\n", zLine);
if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
if( zLine && zLine[0]=='.' && nSql==0 ){
- int rc = do_meta_command(zLine, p);
- free(zLine);
- if( rc ) break;
+ rc = do_meta_command(zLine, p);
+ if( rc==2 ){
+ break;
+ }else if( rc ){
+ errCnt++;
+ }
continue;
}
if( _is_command_terminator(zLine) ){
- strcpy(zLine,";");
+ memcpy(zLine,";",2);
}
+ nSqlPrior = nSql;
if( zSql==0 ){
int i;
for(i=0; zLine[i] && isspace((unsigned char)zLine[i]); i++){}
@@ -1502,7 +1709,8 @@ static void process_input(struct callback_data *p, FILE *in){
fprintf(stderr, "out of memory\n");
exit(1);
}
- strcpy(zSql, zLine);
+ memcpy(zSql, zLine, nSql+1);
+ startline = lineno;
}
}else{
int len = strlen(zLine);
@@ -1511,24 +1719,33 @@ static void process_input(struct callback_data *p, FILE *in){
fprintf(stderr,"%s: out of memory!\n", Argv0);
exit(1);
}
- strcpy(&zSql[nSql++], "\n");
- strcpy(&zSql[nSql], zLine);
+ zSql[nSql++] = '\n';
+ memcpy(&zSql[nSql], zLine, len+1);
nSql += len;
}
- free(zLine);
- if( zSql && _ends_with_semicolon(zSql, nSql) && sqlite3_complete(zSql) ){
+ if( zSql && _contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
+ && sqlite3_complete(zSql) ){
p->cnt = 0;
open_db(p);
+ BEGIN_TIMER;
rc = sqlite3_exec(p->db, zSql, callback, p, &zErrMsg);
+ END_TIMER;
if( rc || zErrMsg ){
- /* if( in!=0 && !p->echoOn ) printf("%s\n",zSql); */
+ char zPrefix[100];
+ if( in!=0 || !stdin_is_interactive ){
+ sqlite3_snprintf(sizeof(zPrefix), zPrefix,
+ "SQL error near line %d:", startline);
+ }else{
+ sqlite3_snprintf(sizeof(zPrefix), zPrefix, "SQL error:");
+ }
if( zErrMsg!=0 ){
- printf("SQL error: %s\n", zErrMsg);
+ printf("%s %s\n", zPrefix, zErrMsg);
sqlite3_free(zErrMsg);
zErrMsg = 0;
}else{
- printf("SQL error: %s\n", sqlite3_errmsg(p->db));
+ printf("%s %s\n", zPrefix, sqlite3_errmsg(p->db));
}
+ errCnt++;
}
free(zSql);
zSql = 0;
@@ -1539,6 +1756,8 @@ static void process_input(struct callback_data *p, FILE *in){
if( !_all_whitespace(zSql) ) printf("Incomplete SQL: %s\n", zSql);
free(zSql);
}
+ free(zLine);
+ return errCnt;
}
/*
@@ -1550,7 +1769,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__) && !defined(__OS2__)
+#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(_WIN32_WCE)
struct passwd *pwent;
uid_t uid = getuid();
if( (pwent=getpwuid(uid)) != NULL) {
@@ -1558,27 +1777,45 @@ static char *find_home_dir(void){
}
#endif
-#ifdef __MACOS__
- char home_path[_MAX_PATH+1];
- home_dir = getcwd(home_path, _MAX_PATH);
+#if defined(_WIN32_WCE)
+ /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv()
+ */
+ home_dir = strdup("/");
+#else
+
+#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
+ if (!home_dir) {
+ home_dir = getenv("USERPROFILE");
+ }
#endif
if (!home_dir) {
home_dir = getenv("HOME");
- if (!home_dir) {
- home_dir = getenv("HOMEPATH"); /* Windows? */
- }
}
#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
if (!home_dir) {
- home_dir = "c:";
+ char *zDrive, *zPath;
+ int n;
+ zDrive = getenv("HOMEDRIVE");
+ zPath = getenv("HOMEPATH");
+ if( zDrive && zPath ){
+ n = strlen(zDrive) + strlen(zPath) + 1;
+ home_dir = malloc( n );
+ if( home_dir==0 ) return 0;
+ sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath);
+ return home_dir;
+ }
+ home_dir = "c:\\";
}
#endif
+#endif /* !_WIN32_WCE */
+
if( home_dir ){
- char *z = malloc( strlen(home_dir)+1 );
- if( z ) strcpy(z, home_dir);
+ int n = strlen(home_dir) + 1;
+ char *z = malloc( n );
+ if( z ) memcpy(z, home_dir, n);
home_dir = z;
}
@@ -1597,6 +1834,7 @@ static void process_sqliterc(
const char *sqliterc = sqliterc_override;
char *zBuf = 0;
FILE *in = NULL;
+ int nBuf;
if (sqliterc == NULL) {
home_dir = find_home_dir();
@@ -1604,19 +1842,20 @@ static void process_sqliterc(
fprintf(stderr,"%s: cannot locate your home directory!\n", Argv0);
return;
}
- zBuf = malloc(strlen(home_dir) + 15);
+ nBuf = strlen(home_dir) + 16;
+ zBuf = malloc( nBuf );
if( zBuf==0 ){
fprintf(stderr,"%s: out of memory!\n", Argv0);
exit(1);
}
- sprintf(zBuf,"%s/.sqliterc",home_dir);
+ sqlite3_snprintf(nBuf, zBuf,"%s/.sqliterc",home_dir);
free(home_dir);
sqliterc = (const char*)zBuf;
}
in = fopen(sqliterc,"rb");
if( in ){
- if( isatty(fileno(stdout)) ){
- printf("Loading resources from %s\n",sqliterc);
+ if( stdin_is_interactive ){
+ printf("-- Loading resources from %s\n",sqliterc);
}
process_input(p,in);
fclose(in);
@@ -1632,19 +1871,25 @@ static const char zOptions[] =
" -init filename read/process named file\n"
" -echo print commands before execution\n"
" -[no]header turn headers on or off\n"
+ " -bail stop after hitting an error\n"
+ " -interactive force interactive I/O\n"
+ " -batch force batch I/O\n"
" -column set output mode to 'column'\n"
+ " -csv set output mode to 'csv'\n"
" -html set output mode to HTML\n"
" -line set output mode to 'line'\n"
" -list set output mode to 'list'\n"
" -separator 'x' set output field separator (|)\n"
" -nullvalue 'text' set text string for NULL values\n"
" -version show SQLite version\n"
- " -help show this text, also show dot-commands\n"
;
static void usage(int showDetail){
- fprintf(stderr, "Usage: %s [OPTIONS] FILENAME [SQL]\n", Argv0);
+ fprintf(stderr,
+ "Usage: %s [OPTIONS] FILENAME [SQL]\n"
+ "FILENAME is the name of an SQLite database. A new database is created\n"
+ "if the file does not previously exist.\n", Argv0);
if( showDetail ){
- fprintf(stderr, "Options are:\n%s", zOptions);
+ fprintf(stderr, "OPTIONS include:\n%s", zOptions);
}else{
fprintf(stderr, "Use the -help option for additional information\n");
}
@@ -1657,10 +1902,10 @@ static void usage(int showDetail){
static void main_init(struct callback_data *data) {
memset(data, 0, sizeof(*data));
data->mode = MODE_List;
- strcpy(data->separator,"|");
+ memcpy(data->separator,"|", 2);
data->showHeader = 0;
- strcpy(mainPrompt,"sqlite> ");
- strcpy(continuePrompt," ...> ");
+ sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
+ sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
}
int main(int argc, char **argv){
@@ -1669,13 +1914,11 @@ int main(int argc, char **argv){
const char *zInitFile = 0;
char *zFirstCmd = 0;
int i;
-
-#ifdef __MACOS__
- argc = ccommand(&argv);
-#endif
+ int rc = 0;
Argv0 = argv[0];
main_init(&data);
+ stdin_is_interactive = isatty(0);
/* Make sure we have a valid signal handler early, before anything
** else is done.
@@ -1689,15 +1932,15 @@ int main(int argc, char **argv){
** and the first command to execute.
*/
for(i=1; i<argc-1; i++){
+ char *z;
if( argv[i][0]!='-' ) break;
+ z = argv[i];
+ if( z[0]=='-' && z[1]=='-' ) z++;
if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){
i++;
}else if( strcmp(argv[i],"-init")==0 ){
i++;
zInitFile = argv[i];
- }else if( strcmp(argv[i],"-key")==0 ){
- i++;
- data.zKey = sqlite3_mprintf("%s",argv[i]);
}
}
if( i<argc ){
@@ -1743,7 +1986,8 @@ int main(int argc, char **argv){
*/
for(i=1; i<argc && argv[i][0]=='-'; i++){
char *z = argv[i];
- if( strcmp(z,"-init")==0 || strcmp(z,"-key")==0 ){
+ if( z[1]=='-' ){ z++; }
+ if( strcmp(z,"-init")==0 ){
i++;
}else if( strcmp(z,"-html")==0 ){
data.mode = MODE_Html;
@@ -1753,22 +1997,33 @@ int main(int argc, char **argv){
data.mode = MODE_Line;
}else if( strcmp(z,"-column")==0 ){
data.mode = MODE_Column;
+ }else if( strcmp(z,"-csv")==0 ){
+ data.mode = MODE_Csv;
+ memcpy(data.separator,",",2);
}else if( strcmp(z,"-separator")==0 ){
i++;
- sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[i]);
+ sqlite3_snprintf(sizeof(data.separator), data.separator,
+ "%.*s",(int)sizeof(data.separator)-1,argv[i]);
}else if( strcmp(z,"-nullvalue")==0 ){
i++;
- sprintf(data.nullvalue,"%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
+ sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
+ "%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
}else if( strcmp(z,"-header")==0 ){
data.showHeader = 1;
}else if( strcmp(z,"-noheader")==0 ){
data.showHeader = 0;
}else if( strcmp(z,"-echo")==0 ){
data.echoOn = 1;
+ }else if( strcmp(z,"-bail")==0 ){
+ bail_on_error = 1;
}else if( strcmp(z,"-version")==0 ){
printf("%s\n", sqlite3_libversion());
return 0;
- }else if( strcmp(z,"-help")==0 ){
+ }else if( strcmp(z,"-interactive")==0 ){
+ stdin_is_interactive = 1;
+ }else if( strcmp(z,"-batch")==0 ){
+ stdin_is_interactive = 0;
+ }else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
usage(1);
}else{
fprintf(stderr,"%s: unknown option: %s\n", Argv0, z);
@@ -1795,22 +2050,23 @@ int main(int argc, char **argv){
}else{
/* Run commands received from standard input
*/
- if( isatty(fileno(stdout)) && isatty(fileno(stdin)) ){
+ if( stdin_is_interactive ){
char *zHome;
char *zHistory = 0;
+ int nHistory;
printf(
"SQLite version %s\n"
"Enter \".help\" for instructions\n",
sqlite3_libversion()
);
zHome = find_home_dir();
- if( zHome && (zHistory = malloc(strlen(zHome)+20))!=0 ){
- sprintf(zHistory,"%s/.sqlite_history", zHome);
+ if( zHome && (zHistory = malloc(nHistory = strlen(zHome)+20))!=0 ){
+ sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
}
#if defined(HAVE_READLINE) && HAVE_READLINE==1
if( zHistory ) read_history(zHistory);
#endif
- process_input(&data, 0);
+ rc = process_input(&data, 0);
if( zHistory ){
stifle_history(100);
write_history(zHistory);
@@ -1818,7 +2074,7 @@ int main(int argc, char **argv){
}
free(zHome);
}else{
- process_input(&data, stdin);
+ rc = process_input(&data, stdin);
}
}
set_table_name(&data, 0);
@@ -1827,5 +2083,5 @@ int main(int argc, char **argv){
fprintf(stderr,"error closing database: %s\n", sqlite3_errmsg(db));
}
}
- return 0;
+ return rc;
}
diff --git a/ext/pdo_sqlite/sqlite/src/sqlite.h.in b/ext/pdo_sqlite/sqlite/src/sqlite.h.in
index a1b4759f84..5186b1929f 100644
--- a/ext/pdo_sqlite/sqlite/src/sqlite.h.in
+++ b/ext/pdo_sqlite/sqlite/src/sqlite.h.in
@@ -10,7 +10,25 @@
**
*************************************************************************
** This header file defines the interface that the SQLite library
-** presents to client programs.
+** presents to client programs. If a C-function, structure, datatype,
+** or constant definition does not appear in this file, then it is
+** not a published API of SQLite, is subject to change without
+** notice, and should not be referenced by programs that use SQLite.
+**
+** Some of the definitions that are in this file are marked as
+** "experimental". Experimental interfaces are normally new
+** features recently added to SQLite. We do not anticipate changes
+** to experimental interfaces but reserve to make minor changes if
+** experience from use "in the wild" suggest such changes are prudent.
+**
+** The official C-language API documentation for SQLite is derived
+** from comments in this file. This file is the authoritative source
+** on how SQLite interfaces are suppose to operate.
+**
+** The name of this file under configuration management is "sqlite.h.in".
+** The makefile makes some minor changes to this file (such as inserting
+** the version number) and changes its name to "sqlite3.h" as
+** part of the build process.
**
** @(#) $Id$
*/
@@ -25,58 +43,150 @@
extern "C" {
#endif
+
/*
-** The version of the SQLite library.
+** Add the ability to override 'extern'
*/
-#ifdef SQLITE_VERSION
-# undef SQLITE_VERSION
+#ifndef SQLITE_EXTERN
+# define SQLITE_EXTERN extern
#endif
-#define SQLITE_VERSION "--VERS--"
/*
-** The format of the version string is "X.Y.Z<trailing string>", where
-** X is the major version number, Y is the minor version number and Z
-** is the release number. The trailing string is often "alpha" or "beta".
-** For example "3.1.1beta".
-**
-** The SQLITE_VERSION_NUMBER is an integer with the value
-** (X*100000 + Y*1000 + Z). For example, for version "3.1.1beta",
-** SQLITE_VERSION_NUMBER is set to 3001001. To detect if they are using
-** version 3.1.1 or greater at compile time, programs may use the test
-** (SQLITE_VERSION_NUMBER>=3001001).
+** Make sure these symbols where not defined by some previous header
+** file.
*/
+#ifdef SQLITE_VERSION
+# undef SQLITE_VERSION
+#endif
#ifdef SQLITE_VERSION_NUMBER
# undef SQLITE_VERSION_NUMBER
#endif
+
+/*
+** CAPI3REF: Compile-Time Library Version Numbers {F10010}
+**
+** The SQLITE_VERSION and SQLITE_VERSION_NUMBER #defines in
+** the sqlite3.h file specify the version of SQLite with which
+** that header file is associated.
+**
+** The "version" of SQLite is a strong of the form "X.Y.Z".
+** The phrase "alpha" or "beta" might be appended after the Z.
+** The X value is major version number always 3 in SQLite3.
+** The X value only changes when backwards compatibility is
+** broken and we intend to never break
+** backwards compatibility. The Y value is the minor version
+** number and only changes when
+** there are major feature enhancements that are forwards compatible
+** but not backwards compatible. The Z value is release number
+** and is incremented with
+** each release but resets back to 0 when Y is incremented.
+**
+** See also: [sqlite3_libversion()] and [sqlite3_libversion_number()].
+**
+** INVARIANTS:
+**
+** {F10011} The SQLITE_VERSION #define in the sqlite3.h header file
+** evaluates to a string literal that is the SQLite version
+** with which the header file is associated.
+**
+** {F10014} The SQLITE_VERSION_NUMBER #define resolves to an integer
+** with the value (X*1000000 + Y*1000 + Z) where X, Y, and
+** Z are the major version, minor version, and release number.
+*/
+#define SQLITE_VERSION "--VERS--"
#define SQLITE_VERSION_NUMBER --VERSION-NUMBER--
/*
-** The version string is also compiled into the library so that a program
-** can check to make sure that the lib*.a file and the *.h file are from
-** the same version. The sqlite3_libversion() function returns a pointer
-** to the sqlite3_version variable - useful in DLLs which cannot access
-** global variables.
+** CAPI3REF: Run-Time Library Version Numbers {F10020}
+** KEYWORDS: sqlite3_version
+**
+** These features provide the same information as the [SQLITE_VERSION]
+** and [SQLITE_VERSION_NUMBER] #defines in the header, but are associated
+** with the library instead of the header file. Cautious programmers might
+** include a check in their application to verify that
+** sqlite3_libversion_number() always returns the value
+** [SQLITE_VERSION_NUMBER].
+**
+** The sqlite3_libversion() function returns the same information as is
+** in the sqlite3_version[] string constant. The function is provided
+** for use in DLLs since DLL users usually do not have direct access to string
+** constants within the DLL.
+**
+** INVARIANTS:
+**
+** {F10021} The [sqlite3_libversion_number()] interface returns an integer
+** equal to [SQLITE_VERSION_NUMBER].
+**
+** {F10022} The [sqlite3_version] string constant contains the text of the
+** [SQLITE_VERSION] string.
+**
+** {F10023} The [sqlite3_libversion()] function returns
+** a pointer to the [sqlite3_version] string constant.
*/
-extern const char sqlite3_version[];
+SQLITE_EXTERN const char sqlite3_version[];
const char *sqlite3_libversion(void);
+int sqlite3_libversion_number(void);
/*
-** Return the value of the SQLITE_VERSION_NUMBER macro when the
-** library was compiled.
+** CAPI3REF: Test To See If The Library Is Threadsafe {F10100}
+**
+** SQLite can be compiled with or without mutexes. When
+** the SQLITE_THREADSAFE C preprocessor macro is true, mutexes
+** are enabled and SQLite is threadsafe. When that macro os false,
+** the mutexes are omitted. Without the mutexes, it is not safe
+** to use SQLite from more than one thread.
+**
+** There is a measurable performance penalty for enabling mutexes.
+** So if speed is of utmost importance, it makes sense to disable
+** the mutexes. But for maximum safety, mutexes should be enabled.
+** The default behavior is for mutexes to be enabled.
+**
+** This interface can be used by a program to make sure that the
+** version of SQLite that it is linking against was compiled with
+** the desired setting of the SQLITE_THREADSAFE macro.
+**
+** INVARIANTS:
+**
+** {F10101} The [sqlite3_threadsafe()] function returns nonzero if
+** SQLite was compiled with its mutexes enabled or zero
+** if SQLite was compiled with mutexes disabled.
*/
-int sqlite3_libversion_number(void);
+int sqlite3_threadsafe(void);
/*
-** Each open sqlite database is represented by an instance of the
-** following opaque structure.
+** CAPI3REF: Database Connection Handle {F12000}
+** KEYWORDS: {database connection}
+**
+** Each open SQLite database is represented by pointer to an instance of the
+** opaque structure named "sqlite3". It is useful to think of an sqlite3
+** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and
+** [sqlite3_open_v2()] interfaces are its constructors
+** and [sqlite3_close()] is its destructor. There are many other interfaces
+** (such as [sqlite3_prepare_v2()], [sqlite3_create_function()], and
+** [sqlite3_busy_timeout()] to name but three) that are methods on this
+** object.
*/
typedef struct sqlite3 sqlite3;
/*
-** Some compilers do not support the "long long" datatype. So we have
-** to do a typedef that for 64-bit integers that depends on what compiler
-** is being used.
+** CAPI3REF: 64-Bit Integer Types {F10200}
+** KEYWORDS: sqlite_int64 sqlite_uint64
+**
+** Because there is no cross-platform way to specify 64-bit integer types
+** SQLite includes typedefs for 64-bit signed and unsigned integers.
+**
+** The sqlite3_int64 and sqlite3_uint64 are the preferred type
+** definitions. The sqlite_int64 and sqlite_uint64 types are
+** supported for backwards compatibility only.
+**
+** INVARIANTS:
+**
+** {F10201} The [sqlite_int64] and [sqlite3_int64] types specify a
+** 64-bit signed integer.
+**
+** {F10202} The [sqlite_uint64] and [sqlite3_uint64] types specify
+** a 64-bit unsigned integer.
*/
#ifdef SQLITE_INT64_TYPE
typedef SQLITE_INT64_TYPE sqlite_int64;
@@ -88,88 +198,180 @@ typedef struct sqlite3 sqlite3;
typedef long long int sqlite_int64;
typedef unsigned long long int sqlite_uint64;
#endif
+typedef sqlite_int64 sqlite3_int64;
+typedef sqlite_uint64 sqlite3_uint64;
/*
** 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 double sqlite3_int64
#endif
/*
-** A function to close the database.
+** CAPI3REF: Closing A Database Connection {F12010}
+**
+** This routine is the destructor for the [sqlite3] object.
+**
+** Applications should [sqlite3_finalize | finalize] all
+** [prepared statements] and
+** [sqlite3_blob_close | close] all [sqlite3_blob | BLOBs]
+** associated with the [sqlite3] object prior
+** to attempting to close the [sqlite3] object.
+**
+** <todo>What happens to pending transactions? Are they
+** rolled back, or abandoned?</todo>
**
-** Call this function with a pointer to a structure that was previously
-** returned from sqlite3_open() and the corresponding database will by closed.
+** INVARIANTS:
**
-** All SQL statements prepared using sqlite3_prepare() or
-** sqlite3_prepare16() must be deallocated using sqlite3_finalize() before
-** this routine is called. Otherwise, SQLITE_BUSY is returned and the
-** database connection remains open.
+** {F12011} The [sqlite3_close()] interface destroys an [sqlite3] object
+** allocated by a prior call to [sqlite3_open()],
+** [sqlite3_open16()], or [sqlite3_open_v2()].
+**
+** {F12012} The [sqlite3_close()] function releases all memory used by the
+** connection and closes all open files.
+**
+** {F12013} If the database connection contains
+** [prepared statements] that have not been
+** finalized by [sqlite3_finalize()], then [sqlite3_close()]
+** returns [SQLITE_BUSY] and leaves the connection open.
+**
+** {F12014} Giving sqlite3_close() a NULL pointer is a harmless no-op.
+**
+** LIMITATIONS:
+**
+** {U12015} The parameter to [sqlite3_close()] must be an [sqlite3] object
+** pointer previously obtained from [sqlite3_open()] or the
+** equivalent, or NULL.
+**
+** {U12016} The parameter to [sqlite3_close()] must not have been previously
+** closed.
*/
int sqlite3_close(sqlite3 *);
/*
** The type for a callback function.
+** This is legacy and deprecated. It is included for historical
+** compatibility and is not documented.
*/
typedef int (*sqlite3_callback)(void*,int,char**, char**);
/*
-** A function to executes one or more statements of SQL.
+** CAPI3REF: One-Step Query Execution Interface {F12100}
+**
+** The sqlite3_exec() interface is a convenient way of running
+** one or more SQL statements without a lot of C code. The
+** SQL statements are passed in as the second parameter to
+** sqlite3_exec(). The statements are evaluated one by one
+** until either an error or an interrupt is encountered or
+** until they are all done. The 3rd parameter is an optional
+** callback that is invoked once for each row of any query results
+** produced by the SQL statements. The 5th parameter tells where
+** to write any error messages.
+**
+** The sqlite3_exec() interface is implemented in terms of
+** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()].
+** The sqlite3_exec() routine does nothing that cannot be done
+** by [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()].
+** The sqlite3_exec() is just a convenient wrapper.
+**
+** INVARIANTS:
+**
+** {F12101} The [sqlite3_exec()] interface evaluates zero or more UTF-8
+** encoded, semicolon-separated, SQL statements in the
+** zero-terminated string of its 2nd parameter within the
+** context of the [sqlite3] object given in the 1st parameter.
+**
+** {F12104} The return value of [sqlite3_exec()] is SQLITE_OK if all
+** SQL statements run successfully.
+**
+** {F12105} The return value of [sqlite3_exec()] is an appropriate
+** non-zero error code if any SQL statement fails.
**
-** If one or more of the SQL statements are queries, then
-** the callback function specified by the 3rd parameter is
-** invoked once for each row of the query result. This callback
-** should normally return 0. If the callback returns a non-zero
-** value then the query is aborted, all subsequent SQL statements
-** are skipped and the sqlite3_exec() function returns the SQLITE_ABORT.
+** {F12107} If one or more of the SQL statements handed to [sqlite3_exec()]
+** return results and the 3rd parameter is not NULL, then
+** the callback function specified by the 3rd parameter is
+** invoked once for each row of result.
**
-** The 4th parameter is an arbitrary pointer that is passed
-** to the callback function as its first parameter.
+** {F12110} If the callback returns a non-zero value then [sqlite3_exec()]
+** will aborted the SQL statement it is currently evaluating,
+** skip all subsequent SQL statements, and return [SQLITE_ABORT].
+** <todo>What happens to *errmsg here? Does the result code for
+** sqlite3_errcode() get set?</todo>
**
-** The 2nd parameter to the callback function is the number of
-** columns in the query result. The 3rd parameter to the callback
-** is an array of strings holding the values for each column.
-** The 4th parameter to the callback is an array of strings holding
-** the names of each column.
+** {F12113} The [sqlite3_exec()] routine will pass its 4th parameter through
+** as the 1st parameter of the callback.
**
-** The callback function may be NULL, even for queries. A NULL
-** callback is not an error. It just means that no callback
-** will be invoked.
+** {F12116} The [sqlite3_exec()] routine sets the 2nd parameter of its
+** callback to be the number of columns in the current row of
+** result.
**
-** If an error occurs while parsing or evaluating the SQL (but
-** not while executing the callback) then an appropriate error
-** message is written into memory obtained from malloc() and
-** *errmsg is made to point to that message. The calling function
-** is responsible for freeing the memory that holds the error
-** message. Use sqlite3_free() for this. If errmsg==NULL,
-** then no error message is ever written.
+** {F12119} The [sqlite3_exec()] routine sets the 3rd parameter of its
+** callback to be an array of pointers to strings holding the
+** values for each column in the current result set row as
+** obtained from [sqlite3_column_text()].
**
-** The return value is is SQLITE_OK if there are no errors and
-** some other return code if there is an error. The particular
-** return value depends on the type of error.
+** {F12122} The [sqlite3_exec()] routine sets the 4th parameter of its
+** callback to be an array of pointers to strings holding the
+** names of result columns as obtained from [sqlite3_column_name()].
**
-** If the query could not be executed because a database file is
-** locked or busy, then this function returns SQLITE_BUSY. (This
-** behavior can be modified somewhat using the sqlite3_busy_handler()
-** and sqlite3_busy_timeout() functions below.)
+** {F12125} If the 3rd parameter to [sqlite3_exec()] is NULL then
+** [sqlite3_exec()] never invokes a callback. All query
+** results are silently discarded.
+**
+** {F12128} If an error occurs while parsing or evaluating any of the SQL
+** statements handed to [sqlite3_exec()] then [sqlite3_exec()] will
+** return an [error code] other than [SQLITE_OK].
+**
+** {F12131} If an error occurs while parsing or evaluating any of the SQL
+** handed to [sqlite3_exec()] and if the 5th parameter (errmsg)
+** to [sqlite3_exec()] is not NULL, then an error message is
+** allocated using the equivalent of [sqlite3_mprintf()] and
+** *errmsg is made to point to that message.
+**
+** {F12134} The [sqlite3_exec()] routine does not change the value of
+** *errmsg if errmsg is NULL or if there are no errors.
+**
+** {F12137} The [sqlite3_exec()] function sets the error code and message
+** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()].
+**
+** LIMITATIONS:
+**
+** {U12141} The first parameter to [sqlite3_exec()] must be an valid and open
+** [database connection].
+**
+** {U12142} The database connection must not be closed while
+** [sqlite3_exec()] is running.
+**
+** {U12143} The calling function is should use [sqlite3_free()] to free
+** the memory that *errmsg is left pointing at once the error
+** message is no longer needed.
+**
+** {U12145} The SQL statement text in the 2nd parameter to [sqlite3_exec()]
+** must remain unchanged while [sqlite3_exec()] is running.
*/
int sqlite3_exec(
- sqlite3*, /* An open database */
- const char *sql, /* SQL to be executed */
- sqlite3_callback, /* Callback function */
- void *, /* 1st argument to callback function */
- char **errmsg /* Error msg written here */
+ sqlite3*, /* An open database */
+ const char *sql, /* SQL to be evaluted */
+ int (*callback)(void*,int,char**,char**), /* Callback function */
+ void *, /* 1st argument to callback */
+ char **errmsg /* Error msg written here */
);
/*
-** Return values for sqlite3_exec() and sqlite3_step()
+** CAPI3REF: Result Codes {F10210}
+** KEYWORDS: SQLITE_OK {error code} {error codes}
+**
+** Many SQLite functions return an integer result code from the set shown
+** here in order to indicates success or failure.
+**
+** See also: [SQLITE_IOERR_READ | extended result codes]
*/
#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_INTERNAL 2 /* Internal logic error in SQLite */
#define SQLITE_PERM 3 /* Access permission denied */
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
#define SQLITE_BUSY 5 /* The database file is locked */
@@ -182,11 +384,11 @@ int sqlite3_exec(
#define SQLITE_NOTFOUND 12 /* NOT USED. Table or record not found */
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
-#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
+#define SQLITE_PROTOCOL 15 /* NOT USED. Database lock protocol error */
#define SQLITE_EMPTY 16 /* Database is empty */
#define SQLITE_SCHEMA 17 /* The database schema changed */
-#define SQLITE_TOOBIG 18 /* NOT USED. Too much data for one row */
-#define SQLITE_CONSTRAINT 19 /* Abort due to contraint violation */
+#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
+#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
#define SQLITE_MISMATCH 20 /* Data type mismatch */
#define SQLITE_MISUSE 21 /* Library used incorrectly */
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
@@ -199,181 +401,957 @@ int sqlite3_exec(
/* end-of-error-codes */
/*
-** Each entry in an SQLite table has a unique integer key. (The key is
-** the value of the INTEGER PRIMARY KEY column if there is such a column,
-** otherwise the key is generated at random. The unique key is always
-** available as the ROWID, OID, or _ROWID_ column.) The following routine
-** returns the integer key of the most recent insert in the database.
+** CAPI3REF: Extended Result Codes {F10220}
+** KEYWORDS: {extended error code} {extended error codes}
+** KEYWORDS: {extended result codes}
+**
+** In its default configuration, SQLite API routines return one of 26 integer
+** [SQLITE_OK | result codes]. However, experience has shown that
+** many of these result codes are too course-grained. They do not provide as
+** much information about problems as programmers might like. In an effort to
+** address this, newer versions of SQLite (version 3.3.8 and later) include
+** support for additional result codes that provide more detailed information
+** about errors. The extended result codes are enabled or disabled
+** for each database connection using the [sqlite3_extended_result_codes()]
+** API.
+**
+** Some of the available extended result codes are listed here.
+** One may expect the number of extended result codes will be expand
+** over time. Software that uses extended result codes should expect
+** to see new result codes in future releases of SQLite.
+**
+** The SQLITE_OK result code will never be extended. It will always
+** be exactly zero.
+**
+** INVARIANTS:
+**
+** {F10223} The symbolic name for an extended result code always contains
+** a related primary result code as a prefix.
+**
+** {F10224} Primary result code names contain a single "_" character.
+**
+** {F10225} Extended result code names contain two or more "_" characters.
+**
+** {F10226} The numeric value of an extended result code contains the
+** numeric value of its corresponding primary result code it
+** its least significant 8 bits.
+*/
+#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
+#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
+#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))
+#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8))
+#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8))
+#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8))
+#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8))
+#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8<<8))
+#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8))
+#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8))
+#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8))
+#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12<<8))
+
+/*
+** CAPI3REF: Flags For File Open Operations {F10230}
**
-** This function is similar to the mysql_insert_id() function from MySQL.
+** These bit values are intended for use in then
+** 3rd parameter to the [sqlite3_open_v2()] interface and
+** in the 4th parameter to the xOpen method of the
+** [sqlite3_vfs] object.
*/
-sqlite_int64 sqlite3_last_insert_rowid(sqlite3*);
+#define SQLITE_OPEN_READONLY 0x00000001
+#define SQLITE_OPEN_READWRITE 0x00000002
+#define SQLITE_OPEN_CREATE 0x00000004
+#define SQLITE_OPEN_DELETEONCLOSE 0x00000008
+#define SQLITE_OPEN_EXCLUSIVE 0x00000010
+#define SQLITE_OPEN_MAIN_DB 0x00000100
+#define SQLITE_OPEN_TEMP_DB 0x00000200
+#define SQLITE_OPEN_TRANSIENT_DB 0x00000400
+#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800
+#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000
+#define SQLITE_OPEN_SUBJOURNAL 0x00002000
+#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000
/*
-** This function returns the number of database rows that were changed
-** (or inserted or deleted) by the most recent called sqlite3_exec().
+** CAPI3REF: Device Characteristics {F10240}
+**
+** The xDeviceCapabilities method of the [sqlite3_io_methods]
+** object returns an integer which is a vector of the these
+** bit values expressing I/O characteristics of the mass storage
+** device that holds the file that the [sqlite3_io_methods]
+** refers to.
+**
+** The SQLITE_IOCAP_ATOMIC property means that all writes of
+** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values
+** mean that writes of blocks that are nnn bytes in size and
+** are aligned to an address which is an integer multiple of
+** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means
+** that when data is appended to a file, the data is appended
+** first then the size of the file is extended, never the other
+** way around. The SQLITE_IOCAP_SEQUENTIAL property means that
+** information is written to disk in the same order as calls
+** to xWrite().
+*/
+#define SQLITE_IOCAP_ATOMIC 0x00000001
+#define SQLITE_IOCAP_ATOMIC512 0x00000002
+#define SQLITE_IOCAP_ATOMIC1K 0x00000004
+#define SQLITE_IOCAP_ATOMIC2K 0x00000008
+#define SQLITE_IOCAP_ATOMIC4K 0x00000010
+#define SQLITE_IOCAP_ATOMIC8K 0x00000020
+#define SQLITE_IOCAP_ATOMIC16K 0x00000040
+#define SQLITE_IOCAP_ATOMIC32K 0x00000080
+#define SQLITE_IOCAP_ATOMIC64K 0x00000100
+#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
+#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
+
+/*
+** CAPI3REF: File Locking Levels {F10250}
**
-** All changes are counted, even if they were later undone by a
-** ROLLBACK or ABORT. Except, changes associated with creating and
-** dropping tables are not counted.
+** SQLite uses one of these integer values as the second
+** argument to calls it makes to the xLock() and xUnlock() methods
+** of an [sqlite3_io_methods] object.
+*/
+#define SQLITE_LOCK_NONE 0
+#define SQLITE_LOCK_SHARED 1
+#define SQLITE_LOCK_RESERVED 2
+#define SQLITE_LOCK_PENDING 3
+#define SQLITE_LOCK_EXCLUSIVE 4
+
+/*
+** CAPI3REF: Synchronization Type Flags {F10260}
**
-** If a callback invokes sqlite3_exec() recursively, then the changes
-** in the inner, recursive call are counted together with the changes
-** in the outer call.
+** When SQLite invokes the xSync() method of an
+** [sqlite3_io_methods] object it uses a combination of the
+** these integer values as the second argument.
**
-** SQLite implements the command "DELETE FROM table" without a WHERE clause
-** by dropping and recreating the table. (This is much faster than going
-** through and deleting individual elements form the table.) Because of
-** this optimization, the change count for "DELETE FROM table" will be
-** zero regardless of the number of elements that were originally in the
-** table. To get an accurate count of the number of rows deleted, use
+** When the SQLITE_SYNC_DATAONLY flag is used, it means that the
+** sync operation only needs to flush data to mass storage. Inode
+** information need not be flushed. The SQLITE_SYNC_NORMAL means
+** to use normal fsync() semantics. The SQLITE_SYNC_FULL flag means
+** to use Mac OS-X style fullsync instead of fsync().
+*/
+#define SQLITE_SYNC_NORMAL 0x00002
+#define SQLITE_SYNC_FULL 0x00003
+#define SQLITE_SYNC_DATAONLY 0x00010
+
+
+/*
+** CAPI3REF: OS Interface Open File Handle {F11110}
+**
+** An [sqlite3_file] object represents an open file in the OS
+** interface layer. Individual OS interface implementations will
+** want to subclass this object by appending additional fields
+** for their own use. The pMethods entry is a pointer to an
+** [sqlite3_io_methods] object that defines methods for performing
+** I/O operations on the open file.
+*/
+typedef struct sqlite3_file sqlite3_file;
+struct sqlite3_file {
+ const struct sqlite3_io_methods *pMethods; /* Methods for an open file */
+};
+
+/*
+** CAPI3REF: OS Interface File Virtual Methods Object {F11120}
+**
+** Every file opened by the [sqlite3_vfs] xOpen method contains a pointer to
+** an instance of the this object. This object defines the
+** methods used to perform various operations against the open file.
+**
+** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or
+** [SQLITE_SYNC_FULL]. The first choice is the normal fsync().
+* The second choice is an
+** OS-X style fullsync. The SQLITE_SYNC_DATA flag may be ORed in to
+** indicate that only the data of the file and not its inode needs to be
+** synced.
+**
+** The integer values to xLock() and xUnlock() are one of
+** <ul>
+** <li> [SQLITE_LOCK_NONE],
+** <li> [SQLITE_LOCK_SHARED],
+** <li> [SQLITE_LOCK_RESERVED],
+** <li> [SQLITE_LOCK_PENDING], or
+** <li> [SQLITE_LOCK_EXCLUSIVE].
+** </ul>
+** xLock() increases the lock. xUnlock() decreases the lock.
+** The xCheckReservedLock() method looks
+** to see if any database connection, either in this
+** process or in some other process, is holding an RESERVED,
+** PENDING, or EXCLUSIVE lock on the file. It returns true
+** if such a lock exists and false if not.
+**
+** The xFileControl() method is a generic interface that allows custom
+** VFS implementations to directly control an open file using the
+** [sqlite3_file_control()] interface. The second "op" argument
+** is an integer opcode. The third
+** argument is a generic pointer which is intended to be a pointer
+** to a structure that may contain arguments or space in which to
+** write return values. Potential uses for xFileControl() might be
+** functions to enable blocking locks with timeouts, to change the
+** locking strategy (for example to use dot-file locks), to inquire
+** about the status of a lock, or to break stale locks. The SQLite
+** core reserves opcodes less than 100 for its own use.
+** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available.
+** Applications that define a custom xFileControl method should use opcodes
+** greater than 100 to avoid conflicts.
+**
+** The xSectorSize() method returns the sector size of the
+** device that underlies the file. The sector size is the
+** minimum write that can be performed without disturbing
+** other bytes in the file. The xDeviceCharacteristics()
+** method returns a bit vector describing behaviors of the
+** underlying device:
+**
+** <ul>
+** <li> [SQLITE_IOCAP_ATOMIC]
+** <li> [SQLITE_IOCAP_ATOMIC512]
+** <li> [SQLITE_IOCAP_ATOMIC1K]
+** <li> [SQLITE_IOCAP_ATOMIC2K]
+** <li> [SQLITE_IOCAP_ATOMIC4K]
+** <li> [SQLITE_IOCAP_ATOMIC8K]
+** <li> [SQLITE_IOCAP_ATOMIC16K]
+** <li> [SQLITE_IOCAP_ATOMIC32K]
+** <li> [SQLITE_IOCAP_ATOMIC64K]
+** <li> [SQLITE_IOCAP_SAFE_APPEND]
+** <li> [SQLITE_IOCAP_SEQUENTIAL]
+** </ul>
+**
+** The SQLITE_IOCAP_ATOMIC property means that all writes of
+** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values
+** mean that writes of blocks that are nnn bytes in size and
+** are aligned to an address which is an integer multiple of
+** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means
+** that when data is appended to a file, the data is appended
+** first then the size of the file is extended, never the other
+** way around. The SQLITE_IOCAP_SEQUENTIAL property means that
+** information is written to disk in the same order as calls
+** to xWrite().
+*/
+typedef struct sqlite3_io_methods sqlite3_io_methods;
+struct sqlite3_io_methods {
+ int iVersion;
+ int (*xClose)(sqlite3_file*);
+ int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
+ int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst);
+ int (*xTruncate)(sqlite3_file*, sqlite3_int64 size);
+ int (*xSync)(sqlite3_file*, int flags);
+ int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize);
+ int (*xLock)(sqlite3_file*, int);
+ int (*xUnlock)(sqlite3_file*, int);
+ int (*xCheckReservedLock)(sqlite3_file*);
+ int (*xFileControl)(sqlite3_file*, int op, void *pArg);
+ int (*xSectorSize)(sqlite3_file*);
+ int (*xDeviceCharacteristics)(sqlite3_file*);
+ /* Additional methods may be added in future releases */
+};
+
+/*
+** CAPI3REF: Standard File Control Opcodes {F11310}
+**
+** These integer constants are opcodes for the xFileControl method
+** of the [sqlite3_io_methods] object and to the [sqlite3_file_control()]
+** interface.
+**
+** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This
+** opcode cases the xFileControl method to write the current state of
+** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
+** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
+** into an integer that the pArg argument points to. This capability
+** is used during testing and only needs to be supported when SQLITE_TEST
+** is defined.
+*/
+#define SQLITE_FCNTL_LOCKSTATE 1
+
+/*
+** CAPI3REF: Mutex Handle {F17110}
+**
+** The mutex module within SQLite defines [sqlite3_mutex] to be an
+** abstract type for a mutex object. The SQLite core never looks
+** at the internal representation of an [sqlite3_mutex]. It only
+** deals with pointers to the [sqlite3_mutex] object.
+**
+** Mutexes are created using [sqlite3_mutex_alloc()].
+*/
+typedef struct sqlite3_mutex sqlite3_mutex;
+
+/*
+** CAPI3REF: OS Interface Object {F11140}
+**
+** An instance of this object defines the interface between the
+** SQLite core and the underlying operating system. The "vfs"
+** in the name of the object stands for "virtual file system".
+**
+** The iVersion field is initially 1 but may be larger for future
+** versions of SQLite. Additional fields may be appended to this
+** object when the iVersion value is increased.
+**
+** The szOsFile field is the size of the subclassed [sqlite3_file]
+** structure used by this VFS. mxPathname is the maximum length of
+** a pathname in this VFS.
+**
+** Registered vfs modules are kept on a linked list formed by
+** the pNext pointer. The [sqlite3_vfs_register()]
+** and [sqlite3_vfs_unregister()] interfaces manage this list
+** in a thread-safe way. The [sqlite3_vfs_find()] interface
+** searches the list.
+**
+** The pNext field is the only fields in the sqlite3_vfs
+** structure that SQLite will ever modify. SQLite will only access
+** or modify this field while holding a particular static mutex.
+** The application should never modify anything within the sqlite3_vfs
+** object once the object has been registered.
+**
+** The zName field holds the name of the VFS module. The name must
+** be unique across all VFS modules.
+**
+** {F11141} SQLite will guarantee that the zFilename string passed to
+** xOpen() is a full pathname as generated by xFullPathname() and
+** that the string will be valid and unchanged until xClose() is
+** called. {END} So the [sqlite3_file] can store a pointer to the
+** filename if it needs to remember the filename for some reason.
+**
+** {F11142} The flags argument to xOpen() includes all bits set in
+** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()]
+** or [sqlite3_open16()] is used, then flags includes at least
+** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. {END}
+** If xOpen() opens a file read-only then it sets *pOutFlags to
+** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be
+** set.
+**
+** {F11143} SQLite will also add one of the following flags to the xOpen()
+** call, depending on the object being opened:
+**
+** <ul>
+** <li> [SQLITE_OPEN_MAIN_DB]
+** <li> [SQLITE_OPEN_MAIN_JOURNAL]
+** <li> [SQLITE_OPEN_TEMP_DB]
+** <li> [SQLITE_OPEN_TEMP_JOURNAL]
+** <li> [SQLITE_OPEN_TRANSIENT_DB]
+** <li> [SQLITE_OPEN_SUBJOURNAL]
+** <li> [SQLITE_OPEN_MASTER_JOURNAL]
+** </ul> {END}
+**
+** The file I/O implementation can use the object type flags to
+** changes the way it deals with files. For example, an application
+** that does not care about crash recovery or rollback, might make
+** the open of a journal file a no-op. Writes to this journal are
+** also a no-op. Any attempt to read the journal return SQLITE_IOERR.
+** Or the implementation might recognize the a database file will
+** be doing page-aligned sector reads and writes in a random order
+** and set up its I/O subsystem accordingly.
+**
+** SQLite might also add one of the following flags to the xOpen
+** method:
+**
+** <ul>
+** <li> [SQLITE_OPEN_DELETEONCLOSE]
+** <li> [SQLITE_OPEN_EXCLUSIVE]
+** </ul>
+**
+** {F11145} The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be
+** deleted when it is closed. {F11146} The [SQLITE_OPEN_DELETEONCLOSE]
+** will be set for TEMP databases, journals and for subjournals.
+** {F11147} The [SQLITE_OPEN_EXCLUSIVE] flag means the file should be opened
+** for exclusive access. This flag is set for all files except
+** for the main database file. {END}
+**
+** {F11148} At least szOsFile bytes of memory is allocated by SQLite
+** to hold the [sqlite3_file] structure passed as the third
+** argument to xOpen. {END} The xOpen method does not have to
+** allocate the structure; it should just fill it in.
+**
+** {F11149} The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
+** to test for the existance of a file,
+** or [SQLITE_ACCESS_READWRITE] to test to see
+** if a file is readable and writable, or [SQLITE_ACCESS_READ]
+** to test to see if a file is at least readable. {END} The file can be a
+** directory.
+**
+** {F11150} SQLite will always allocate at least mxPathname+1 byte for
+** the output buffers for xGetTempname and xFullPathname. {F11151} The exact
+** size of the output buffer is also passed as a parameter to both
+** methods. {END} If the output buffer is not large enough, SQLITE_CANTOPEN
+** should be returned. As this is handled as a fatal error by SQLite,
+** vfs implementations should endeavor to prevent this by setting
+** mxPathname to a sufficiently large value.
+**
+** The xRandomness(), xSleep(), and xCurrentTime() interfaces
+** are not strictly a part of the filesystem, but they are
+** included in the VFS structure for completeness.
+** The xRandomness() function attempts to return nBytes bytes
+** of good-quality randomness into zOut. The return value is
+** the actual number of bytes of randomness obtained. The
+** xSleep() method cause the calling thread to sleep for at
+** least the number of microseconds given. The xCurrentTime()
+** method returns a Julian Day Number for the current date and
+** time.
+*/
+typedef struct sqlite3_vfs sqlite3_vfs;
+struct sqlite3_vfs {
+ int iVersion; /* Structure version number */
+ int szOsFile; /* Size of subclassed sqlite3_file */
+ int mxPathname; /* Maximum file pathname length */
+ sqlite3_vfs *pNext; /* Next registered VFS */
+ const char *zName; /* Name of this virtual file system */
+ void *pAppData; /* Pointer to application-specific data */
+ int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*,
+ int flags, int *pOutFlags);
+ int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir);
+ int (*xAccess)(sqlite3_vfs*, const char *zName, int flags);
+ int (*xGetTempname)(sqlite3_vfs*, int nOut, char *zOut);
+ int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut);
+ void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename);
+ void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg);
+ void *(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol);
+ void (*xDlClose)(sqlite3_vfs*, void*);
+ int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut);
+ int (*xSleep)(sqlite3_vfs*, int microseconds);
+ int (*xCurrentTime)(sqlite3_vfs*, double*);
+ /* New fields may be appended in figure versions. The iVersion
+ ** value will increment whenever this happens. */
+};
+
+/*
+** CAPI3REF: Flags for the xAccess VFS method {F11190}
+**
+** {F11191} These integer constants can be used as the third parameter to
+** the xAccess method of an [sqlite3_vfs] object. {END} They determine
+** the kind of what kind of permissions the xAccess method is
+** looking for. {F11192} With SQLITE_ACCESS_EXISTS, the xAccess method
+** simply checks to see if the file exists. {F11193} With
+** SQLITE_ACCESS_READWRITE, the xAccess method checks to see
+** if the file is both readable and writable. {F11194} With
+** SQLITE_ACCESS_READ the xAccess method
+** checks to see if the file is readable.
+*/
+#define SQLITE_ACCESS_EXISTS 0
+#define SQLITE_ACCESS_READWRITE 1
+#define SQLITE_ACCESS_READ 2
+
+/*
+** CAPI3REF: Enable Or Disable Extended Result Codes {F12200}
+**
+** The sqlite3_extended_result_codes() routine enables or disables the
+** [SQLITE_IOERR_READ | extended result codes] feature of SQLite.
+** The extended result codes are disabled by default for historical
+** compatibility.
+**
+** INVARIANTS:
+**
+** {F12201} Each new [database connection] has the
+** [extended result codes] feature
+** disabled by default.
+**
+** {F12202} The [sqlite3_extended_result_codes(D,F)] interface will enable
+** [extended result codes] for the
+** [database connection] D if the F parameter
+** is true, or disable them if F is false.
+*/
+int sqlite3_extended_result_codes(sqlite3*, int onoff);
+
+/*
+** CAPI3REF: Last Insert Rowid {F12220}
+**
+** Each entry in an SQLite table has a unique 64-bit signed
+** integer key called the "rowid". The rowid is always available
+** as an undeclared column named ROWID, OID, or _ROWID_ as long as those
+** names are not also used by explicitly declared columns. If
+** the table has a column of type INTEGER PRIMARY KEY then that column
+** is another an alias for the rowid.
+**
+** This routine returns the rowid of the most recent
+** successful INSERT into the database from the database connection
+** shown in the first argument. If no successful inserts
+** have ever occurred on this database connection, zero is returned.
+**
+** If an INSERT occurs within a trigger, then the rowid of the
+** inserted row is returned by this routine as long as the trigger
+** is running. But once the trigger terminates, the value returned
+** by this routine reverts to the last value inserted before the
+** trigger fired.
+**
+** An INSERT that fails due to a constraint violation is not a
+** successful insert and does not change the value returned by this
+** routine. Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK,
+** and INSERT OR ABORT make no changes to the return value of this
+** routine when their insertion fails. When INSERT OR REPLACE
+** encounters a constraint violation, it does not fail. The
+** INSERT continues to completion after deleting rows that caused
+** the constraint problem so INSERT OR REPLACE will always change
+** the return value of this interface.
+**
+** For the purposes of this routine, an insert is considered to
+** be successful even if it is subsequently rolled back.
+**
+** INVARIANTS:
+**
+** {F12221} The [sqlite3_last_insert_rowid()] function returns the
+** rowid of the most recent successful insert done
+** on the same database connection and within the same
+** trigger context, or zero if there have
+** been no qualifying inserts on that connection.
+**
+** {F12223} The [sqlite3_last_insert_rowid()] function returns
+** same value when called from the same trigger context
+** immediately before and after a ROLLBACK.
+**
+** LIMITATIONS:
+**
+** {U12232} If separate thread does a new insert on the same
+** database connection while the [sqlite3_last_insert_rowid()]
+** function is running and thus changes the last insert rowid,
+** then the value returned by [sqlite3_last_insert_rowid()] is
+** unpredictable and might not equal either the old or the new
+** last insert rowid.
+*/
+sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
+
+/*
+** CAPI3REF: Count The Number Of Rows Modified {F12240}
+**
+** This function returns the number of database rows that were changed
+** or inserted or deleted by the most recently completed SQL statement
+** on the connection specified by the first parameter. Only
+** changes that are directly specified by the INSERT, UPDATE, or
+** DELETE statement are counted. Auxiliary changes caused by
+** triggers are not counted. Use the [sqlite3_total_changes()] function
+** to find the total number of changes including changes caused by triggers.
+**
+** A "row changes" is a change to a single row of a single table
+** caused by an INSERT, DELETE, or UPDATE statement. Rows that
+** are changed as side effects of REPLACE constraint resolution,
+** rollback, ABORT processing, DROP TABLE, or by any other
+** mechanisms do not count as direct row changes.
+**
+** A "trigger context" is a scope of execution that begins and
+** ends with the script of a trigger. Most SQL statements are
+** evaluated outside of any trigger. This is the "top level"
+** trigger context. If a trigger fires from the top level, a
+** new trigger context is entered for the duration of that one
+** trigger. Subtriggers create subcontexts for their duration.
+**
+** Calling [sqlite3_exec()] or [sqlite3_step()] recursively does
+** not create a new trigger context.
+**
+** This function returns the number of direct row changes in the
+** most recent INSERT, UPDATE, or DELETE statement within the same
+** trigger context.
+**
+** So when called from the top level, this function returns the
+** number of changes in the most recent INSERT, UPDATE, or DELETE
+** that also occurred at the top level.
+** Within the body of a trigger, the sqlite3_changes() interface
+** can be called to find the number of
+** changes in the most recently completed INSERT, UPDATE, or DELETE
+** statement within the body of the same trigger.
+** However, the number returned does not include in changes
+** caused by subtriggers since they have their own context.
+**
+** SQLite implements the command "DELETE FROM table" without
+** a WHERE clause by dropping and recreating the table. (This is much
+** faster than going through and deleting individual elements from the
+** table.) Because of this optimization, the deletions in
+** "DELETE FROM table" are not row changes and will not be counted
+** by the sqlite3_changes() or [sqlite3_total_changes()] functions.
+** To get an accurate count of the number of rows deleted, use
** "DELETE FROM table WHERE 1" instead.
+**
+** INVARIANTS:
+**
+** {F12241} The [sqlite3_changes()] function returns the number of
+** row changes caused by the most recent INSERT, UPDATE,
+** or DELETE statement on the same database connection and
+** within the same trigger context, or zero if there have
+** not been any qualifying row changes.
+**
+** LIMITATIONS:
+**
+** {U12252} If a separate thread makes changes on the same database connection
+** while [sqlite3_changes()] is running then the value returned
+** is unpredictable and unmeaningful.
*/
int sqlite3_changes(sqlite3*);
/*
-** This function returns the number of database rows that have been
-** modified by INSERT, UPDATE or DELETE statements since the database handle
-** was opened. This includes UPDATE, INSERT and DELETE statements executed
-** as part of trigger programs. All changes are counted as soon as the
-** statement that makes them is completed (when the statement handle is
-** passed to sqlite3_reset() or sqlite_finalise()).
-**
-** SQLite implements the command "DELETE FROM table" without a WHERE clause
-** by dropping and recreating the table. (This is much faster than going
+** CAPI3REF: Total Number Of Rows Modified {F12260}
+***
+** This function returns the number of row changes caused
+** by INSERT, UPDATE or DELETE statements since the database handle
+** was opened. The count includes all changes from all trigger
+** contexts. But the count does not include changes used to
+** implement REPLACE constraints, do rollbacks or ABORT processing,
+** or DROP table processing.
+** The changes
+** are counted as soon as the statement that makes them is completed
+** (when the statement handle is passed to [sqlite3_reset()] or
+** [sqlite3_finalize()]).
+**
+** SQLite implements the command "DELETE FROM table" without
+** a WHERE clause by dropping and recreating the table. (This is much
+** faster than going
** through and deleting individual elements form the table.) Because of
** this optimization, the change count for "DELETE FROM table" will be
** zero regardless of the number of elements that were originally in the
** table. To get an accurate count of the number of rows deleted, use
** "DELETE FROM table WHERE 1" instead.
+**
+** See also the [sqlite3_changes()] interface.
+**
+** INVARIANTS:
+**
+** {F12261} The [sqlite3_total_changes()] returns the total number
+** of row changes caused by INSERT, UPDATE, and/or DELETE
+** statements on the same [database connection], in any
+** trigger context, since the database connection was
+** created.
+**
+** LIMITATIONS:
+**
+** {U12264} If a separate thread makes changes on the same database connection
+** while [sqlite3_total_changes()] is running then the value
+** returned is unpredictable and unmeaningful.
*/
int sqlite3_total_changes(sqlite3*);
-/* This function causes any pending database operation to abort and
-** return at its earliest opportunity. This routine is typically
+/*
+** CAPI3REF: Interrupt A Long-Running Query {F12270}
+**
+** This function causes any pending database operation to abort and
+** return at its earliest opportunity. This routine is typically
** called in response to a user action such as pressing "Cancel"
** or Ctrl-C where the user wants a long query operation to halt
** immediately.
+**
+** It is safe to call this routine from a thread different from the
+** thread that is currently running the database operation. But it
+** is not safe to call this routine with a database connection that
+** is closed or might close before sqlite3_interrupt() returns.
+**
+** If an SQL is very nearly finished at the time when sqlite3_interrupt()
+** is called, then it might not have an opportunity to be interrupted.
+** It might continue to completion.
+** An SQL operation that is interrupted will return
+** [SQLITE_INTERRUPT]. If the interrupted SQL operation is an
+** INSERT, UPDATE, or DELETE that is inside an explicit transaction,
+** then the entire transaction will be rolled back automatically.
+** A call to sqlite3_interrupt() has no effect on SQL statements
+** that are started after sqlite3_interrupt() returns.
+**
+** INVARIANTS:
+**
+** {F12271} The [sqlite3_interrupt()] interface will force all running
+** SQL statements associated with the same database connection
+** to halt after processing at most one additional row of
+** data.
+**
+** {F12272} Any SQL statement that is interrupted by [sqlite3_interrupt()]
+** will return [SQLITE_INTERRUPT].
+**
+** LIMITATIONS:
+**
+** {U12279} If the database connection closes while [sqlite3_interrupt()]
+** is running then bad things will likely happen.
*/
void sqlite3_interrupt(sqlite3*);
-
-/* These functions return true if the given input string comprises
-** one or more complete SQL statements. For the sqlite3_complete() call,
-** the parameter must be a nul-terminated UTF-8 string. For
-** sqlite3_complete16(), a nul-terminated machine byte order UTF-16 string
-** is required.
+/*
+** CAPI3REF: Determine If An SQL Statement Is Complete {F10510}
+**
+** These routines are useful for command-line input to determine if the
+** currently entered text seems to form complete a SQL statement or
+** if additional input is needed before sending the text into
+** SQLite for parsing. These routines return true if the input string
+** appears to be a complete SQL statement. A statement is judged to be
+** complete if it ends with a semicolon token and is not a fragment of a
+** CREATE TRIGGER statement. Semicolons that are embedded within
+** string literals or quoted identifier names or comments are not
+** independent tokens (they are part of the token in which they are
+** embedded) and thus do not count as a statement terminator.
+**
+** These routines do not parse the SQL and
+** so will not detect syntactically incorrect SQL.
+**
+** INVARIANTS:
**
-** The algorithm is simple. If the last token other than spaces
-** and comments is a semicolon, then return true. otherwise return
-** false.
+** {F10511} The sqlite3_complete() and sqlite3_complete16() functions
+** return true (non-zero) if and only if the last
+** non-whitespace token in their input is a semicolon that
+** is not in between the BEGIN and END of a CREATE TRIGGER
+** statement.
+**
+** LIMITATIONS:
+**
+** {U10512} The input to sqlite3_complete() must be a zero-terminated
+** UTF-8 string.
+**
+** {U10513} The input to sqlite3_complete16() must be a zero-terminated
+** UTF-16 string in native byte order.
*/
int sqlite3_complete(const char *sql);
int sqlite3_complete16(const void *sql);
/*
-** This routine identifies a callback function that is invoked
-** whenever an attempt is made to open a database table that is
-** currently locked by another process or thread. If the busy callback
-** is NULL, then sqlite3_exec() returns SQLITE_BUSY immediately if
-** it finds a locked table. If the busy callback is not NULL, then
-** sqlite3_exec() invokes the callback with three arguments. The
-** second argument is the name of the locked table and the third
-** argument is the number of times the table has been busy. If the
-** busy callback returns 0, then sqlite3_exec() immediately returns
-** SQLITE_BUSY. If the callback returns non-zero, then sqlite3_exec()
-** tries to open the table again and the cycle repeats.
+** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors {F12310}
+**
+** This routine identifies a callback function that might be
+** invoked whenever an attempt is made to open a database table
+** that another thread or process has locked.
+** If the busy callback is NULL, then [SQLITE_BUSY]
+** or [SQLITE_IOERR_BLOCKED]
+** is returned immediately upon encountering the lock.
+** If the busy callback is not NULL, then the
+** callback will be invoked with two arguments. The
+** first argument to the handler is a copy of the void* pointer which
+** is the third argument to this routine. The second argument to
+** the handler is the number of times that the busy handler has
+** been invoked for this locking event. If the
+** busy callback returns 0, then no additional attempts are made to
+** access the database and [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] is returned.
+** If the callback returns non-zero, then another attempt
+** is made to open the database for reading and the cycle repeats.
+**
+** The presence of a busy handler does not guarantee that
+** it will be invoked when there is lock contention.
+** If SQLite determines that invoking the busy handler could result in
+** a deadlock, it will go ahead and return [SQLITE_BUSY] or
+** [SQLITE_IOERR_BLOCKED] instead of invoking the
+** busy handler.
+** Consider a scenario where one process is holding a read lock that
+** it is trying to promote to a reserved lock and
+** a second process is holding a reserved lock that it is trying
+** to promote to an exclusive lock. The first process cannot proceed
+** because it is blocked by the second and the second process cannot
+** proceed because it is blocked by the first. If both processes
+** invoke the busy handlers, neither will make any progress. Therefore,
+** SQLite returns [SQLITE_BUSY] for the first process, hoping that this
+** will induce the first process to release its read lock and allow
+** the second process to proceed.
**
** The default busy callback is NULL.
**
-** Sqlite is re-entrant, so the busy handler may start a new query.
-** (It is not clear why anyone would every want to do this, but it
-** is allowed, in theory.) But the busy handler may not close the
-** database. Closing the database from a busy handler will delete
-** data structures out from under the executing query and will
-** probably result in a coredump.
+** The [SQLITE_BUSY] error is converted to [SQLITE_IOERR_BLOCKED]
+** when SQLite is in the middle of a large transaction where all the
+** changes will not fit into the in-memory cache. SQLite will
+** already hold a RESERVED lock on the database file, but it needs
+** to promote this lock to EXCLUSIVE so that it can spill cache
+** pages into the database file without harm to concurrent
+** readers. If it is unable to promote the lock, then the in-memory
+** cache will be left in an inconsistent state and so the error
+** code is promoted from the relatively benign [SQLITE_BUSY] to
+** the more severe [SQLITE_IOERR_BLOCKED]. This error code promotion
+** forces an automatic rollback of the changes. See the
+** <a href="http://www.sqlite.org/cvstrac/wiki?p=CorruptionFollowingBusyError">
+** CorruptionFollowingBusyError</a> wiki page for a discussion of why
+** this is important.
+**
+** There can only be a single busy handler defined for each database
+** connection. Setting a new busy handler clears any previous one.
+** Note that calling [sqlite3_busy_timeout()] will also set or clear
+** the busy handler.
+**
+** INVARIANTS:
+**
+** {F12311} The [sqlite3_busy_handler()] function replaces the busy handler
+** callback in the database connection identified by the 1st
+** parameter with a new busy handler identified by the 2nd and 3rd
+** parameters.
+**
+** {F12312} The default busy handler for new database connections is NULL.
+**
+** {F12314} When two or more database connection share a common cache,
+** the busy handler for the database connection currently using
+** the cache is invoked when the cache encounters a lock.
+**
+** {F12316} If a busy handler callback returns zero, then the SQLite
+** interface that provoked the locking event will return
+** [SQLITE_BUSY].
+**
+** {F12318} SQLite will invokes the busy handler with two argument which
+** are a copy of the pointer supplied by the 3rd parameter to
+** [sqlite3_busy_handler()] and a count of the number of prior
+** invocations of the busy handler for the same locking event.
+**
+** LIMITATIONS:
+**
+** {U12319} A busy handler should not call close the database connection
+** or prepared statement that invoked the busy handler.
*/
int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
/*
-** This routine sets a busy handler that sleeps for a while when a
+** CAPI3REF: Set A Busy Timeout {F12340}
+**
+** This routine sets a [sqlite3_busy_handler | busy handler]
+** that sleeps for a while when a
** table is locked. The handler will sleep multiple times until
-** at least "ms" milleseconds of sleeping have been done. After
-** "ms" milleseconds of sleeping, the handler returns 0 which
-** causes sqlite3_exec() to return SQLITE_BUSY.
+** at least "ms" milliseconds of sleeping have been done. {F12343} After
+** "ms" milliseconds of sleeping, the handler returns 0 which
+** causes [sqlite3_step()] to return [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED].
**
** Calling this routine with an argument less than or equal to zero
** turns off all busy handlers.
+**
+** There can only be a single busy handler for a particular database
+** connection. If another busy handler was defined
+** (using [sqlite3_busy_handler()]) prior to calling
+** this routine, that other busy handler is cleared.
+**
+** INVARIANTS:
+**
+** {F12341} The [sqlite3_busy_timeout()] function overrides any prior
+** [sqlite3_busy_timeout()] or [sqlite3_busy_handler()] setting
+** on the same database connection.
+**
+** {F12343} If the 2nd parameter to [sqlite3_busy_timeout()] is less than
+** or equal to zero, then the busy handler is cleared so that
+** all subsequent locking events immediately return [SQLITE_BUSY].
+**
+** {F12344} If the 2nd parameter to [sqlite3_busy_timeout()] is a positive
+** number N, then a busy handler is set that repeatedly calls
+** the xSleep() method in the VFS interface until either the
+** lock clears or until the cumulative sleep time reported back
+** by xSleep() exceeds N milliseconds.
*/
int sqlite3_busy_timeout(sqlite3*, int ms);
/*
-** This next routine is really just a wrapper around sqlite3_exec().
-** Instead of invoking a user-supplied callback for each row of the
-** result, this routine remembers each row of the result in memory
-** obtained from malloc(), then returns all of the result after the
-** query has finished.
-**
-** As an example, suppose the query result where this table:
-**
+** CAPI3REF: Convenience Routines For Running Queries {F12370}
+**
+** Definition: A <b>result table</b> is memory data structure created by the
+** [sqlite3_get_table()] interface. A result table records the
+** complete query results from one or more queries.
+**
+** The table conceptually has a number of rows and columns. But
+** these numbers are not part of the result table itself. These
+** numbers are obtained separately. Let N be the number of rows
+** and M be the number of columns.
+**
+** A result table is an array of pointers to zero-terminated
+** UTF-8 strings. There are (N+1)*M elements in the array.
+** The first M pointers point to zero-terminated strings that
+** contain the names of the columns.
+** The remaining entries all point to query results. NULL
+** values are give a NULL pointer. All other values are in
+** their UTF-8 zero-terminated string representation as returned by
+** [sqlite3_column_text()].
+**
+** A result table might consists of one or more memory allocations.
+** It is not safe to pass a result table directly to [sqlite3_free()].
+** A result table should be deallocated using [sqlite3_free_table()].
+**
+** As an example of the result table format, suppose a query result
+** is as follows:
+**
+** <blockquote><pre>
** Name | Age
** -----------------------
** Alice | 43
** Bob | 28
** Cindy | 21
-**
-** If the 3rd argument were &azResult then after the function returns
-** azResult will contain the following data:
-**
-** azResult[0] = "Name";
-** azResult[1] = "Age";
-** azResult[2] = "Alice";
-** azResult[3] = "43";
-** azResult[4] = "Bob";
-** azResult[5] = "28";
-** azResult[6] = "Cindy";
-** azResult[7] = "21";
-**
-** Notice that there is an extra row of data containing the column
-** headers. But the *nrow return value is still 3. *ncolumn is
-** set to 2. In general, the number of values inserted into azResult
-** will be ((*nrow) + 1)*(*ncolumn).
+** </pre></blockquote>
+**
+** There are two column (M==2) and three rows (N==3). Thus the
+** result table has 8 entries. Suppose the result table is stored
+** in an array names azResult. Then azResult holds this content:
+**
+** <blockquote><pre>
+** azResult&#91;0] = "Name";
+** azResult&#91;1] = "Age";
+** azResult&#91;2] = "Alice";
+** azResult&#91;3] = "43";
+** azResult&#91;4] = "Bob";
+** azResult&#91;5] = "28";
+** azResult&#91;6] = "Cindy";
+** azResult&#91;7] = "21";
+** </pre></blockquote>
+**
+** The sqlite3_get_table() function evaluates one or more
+** semicolon-separated SQL statements in the zero-terminated UTF-8
+** string of its 2nd parameter. It returns a result table to the
+** pointer given in its 3rd parameter.
**
** After the calling function has finished using the result, it should
-** pass the result data pointer to sqlite3_free_table() in order to
+** pass the pointer to the result table to sqlite3_free_table() in order to
** release the memory that was malloc-ed. Because of the way the
-** malloc() happens, the calling function must not try to call
-** free() directly. Only sqlite3_free_table() is able to release
-** the memory properly and safely.
-**
-** The return value of this routine is the same as from sqlite3_exec().
+** [sqlite3_malloc()] happens within sqlite3_get_table(), the calling
+** function must not try to call [sqlite3_free()] directly. Only
+** [sqlite3_free_table()] is able to release the memory properly and safely.
+**
+** The sqlite3_get_table() interface is implemented as a wrapper around
+** [sqlite3_exec()]. The sqlite3_get_table() routine does not have access
+** to any internal data structures of SQLite. It uses only the public
+** interface defined here. As a consequence, errors that occur in the
+** wrapper layer outside of the internal [sqlite3_exec()] call are not
+** reflected in subsequent calls to [sqlite3_errcode()] or
+** [sqlite3_errmsg()].
+**
+** INVARIANTS:
+**
+** {F12371} If a [sqlite3_get_table()] fails a memory allocation, then
+** it frees the result table under construction, aborts the
+** query in process, skips any subsequent queries, sets the
+** *resultp output pointer to NULL and returns [SQLITE_NOMEM].
+**
+** {F12373} If the ncolumn parameter to [sqlite3_get_table()] is not NULL
+** then [sqlite3_get_table()] write the number of columns in the
+** result set of the query into *ncolumn if the query is
+** successful (if the function returns SQLITE_OK).
+**
+** {F12374} If the nrow parameter to [sqlite3_get_table()] is not NULL
+** then [sqlite3_get_table()] write the number of rows in the
+** result set of the query into *nrow if the query is
+** successful (if the function returns SQLITE_OK).
+**
+** {F12376} The [sqlite3_get_table()] function sets its *ncolumn value
+** to the number of columns in the result set of the query in the
+** sql parameter, or to zero if the query in sql has an empty
+** result set.
*/
int sqlite3_get_table(
- sqlite3*, /* An open database */
- const char *sql, /* SQL to be executed */
- char ***resultp, /* Result written to a char *[] that this points to */
- int *nrow, /* Number of result rows written here */
- int *ncolumn, /* Number of result columns written here */
- char **errmsg /* Error msg written here */
+ sqlite3*, /* An open database */
+ const char *sql, /* SQL to be evaluated */
+ char ***pResult, /* Results of the query */
+ int *nrow, /* Number of result rows written here */
+ int *ncolumn, /* Number of result columns written here */
+ char **errmsg /* Error msg written here */
);
-
-/*
-** Call this routine to free the memory that sqlite3_get_table() allocated.
-*/
void sqlite3_free_table(char **result);
/*
-** The following routines are variants of the "sprintf()" from the
-** standard C library. The resulting string is written into memory
-** obtained from malloc() so that there is never a possiblity of buffer
-** overflow. These routines also implement some additional formatting
+** CAPI3REF: Formatted String Printing Functions {F17400}
+**
+** These routines are workalikes of the "printf()" family of functions
+** from the standard C library.
+**
+** The sqlite3_mprintf() and sqlite3_vmprintf() routines write their
+** results into memory obtained from [sqlite3_malloc()].
+** The strings returned by these two routines should be
+** released by [sqlite3_free()]. Both routines return a
+** NULL pointer if [sqlite3_malloc()] is unable to allocate enough
+** memory to hold the resulting string.
+**
+** In sqlite3_snprintf() routine is similar to "snprintf()" from
+** the standard C library. The result is written into the
+** buffer supplied as the second parameter whose size is given by
+** the first parameter. Note that the order of the
+** first two parameters is reversed from snprintf(). This is an
+** historical accident that cannot be fixed without breaking
+** backwards compatibility. Note also that sqlite3_snprintf()
+** returns a pointer to its buffer instead of the number of
+** characters actually written into the buffer. We admit that
+** the number of characters written would be a more useful return
+** value but we cannot change the implementation of sqlite3_snprintf()
+** now without breaking compatibility.
+**
+** As long as the buffer size is greater than zero, sqlite3_snprintf()
+** guarantees that the buffer is always zero-terminated. The first
+** parameter "n" is the total size of the buffer, including space for
+** the zero terminator. So the longest string that can be completely
+** written will be n-1 characters.
+**
+** These routines all implement some additional formatting
** options that are useful for constructing SQL statements.
-**
-** The strings returned by these routines should be freed by calling
-** sqlite3_free().
-**
** All of the usual printf formatting options apply. In addition, there
-** is a "%q" option. %q works like %s in that it substitutes a null-terminated
+** is are "%q", "%Q", and "%z" options.
+**
+** The %q option works like %s in that it substitutes a null-terminated
** string from the argument list. But %q also doubles every '\'' character.
** %q is designed for use inside a string literal. By doubling each '\''
** character it escapes that character and allows it to be inserted into
@@ -381,73 +1359,407 @@ void sqlite3_free_table(char **result);
**
** For example, so some string variable contains text as follows:
**
-** char *zText = "It's a happy day!";
+** <blockquote><pre>
+** char *zText = "It's a happy day!";
+** </pre></blockquote>
**
-** We can use this text in an SQL statement as follows:
+** One can use this text in an SQL statement as follows:
**
-** char *z = sqlite3_mprintf("INSERT INTO TABLES('%q')", zText);
-** sqlite3_exec(db, z, callback1, 0, 0);
-** sqlite3_free(z);
+** <blockquote><pre>
+** char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES('%q')", zText);
+** sqlite3_exec(db, zSQL, 0, 0, 0);
+** sqlite3_free(zSQL);
+** </pre></blockquote>
**
** Because the %q format string is used, the '\'' character in zText
** is escaped and the SQL generated is as follows:
**
-** INSERT INTO table1 VALUES('It''s a happy day!')
+** <blockquote><pre>
+** INSERT INTO table1 VALUES('It''s a happy day!')
+** </pre></blockquote>
**
** This is correct. Had we used %s instead of %q, the generated SQL
** would have looked like this:
**
-** INSERT INTO table1 VALUES('It's a happy day!');
+** <blockquote><pre>
+** INSERT INTO table1 VALUES('It's a happy day!');
+** </pre></blockquote>
**
** This second example is an SQL syntax error. As a general rule you
** should always use %q instead of %s when inserting text into a string
** literal.
+**
+** The %Q option works like %q except it also adds single quotes around
+** the outside of the total string. Or if the parameter in the argument
+** list is a NULL pointer, %Q substitutes the text "NULL" (without single
+** quotes) in place of the %Q option. {END} So, for example, one could say:
+**
+** <blockquote><pre>
+** char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText);
+** sqlite3_exec(db, zSQL, 0, 0, 0);
+** sqlite3_free(zSQL);
+** </pre></blockquote>
+**
+** The code above will render a correct SQL statement in the zSQL
+** variable even if the zText variable is a NULL pointer.
+**
+** The "%z" formatting option works exactly like "%s" with the
+** addition that after the string has been read and copied into
+** the result, [sqlite3_free()] is called on the input string. {END}
+**
+** INVARIANTS:
+**
+** {F17403} The [sqlite3_mprintf()] and [sqlite3_vmprintf()] interfaces
+** return either pointers to zero-terminated UTF-8 strings held in
+** memory obtained from [sqlite3_malloc()] or NULL pointers if
+** a call to [sqlite3_malloc()] fails.
+**
+** {F17406} The [sqlite3_snprintf()] interface writes a zero-terminated
+** UTF-8 string into the buffer pointed to by the second parameter
+** provided that the first parameter is greater than zero.
+**
+** {F17407} The [sqlite3_snprintf()] interface does not writes slots of
+** its output buffer (the second parameter) outside the range
+** of 0 through N-1 (where N is the first parameter)
+** regardless of the length of the string
+** requested by the format specification.
+**
*/
char *sqlite3_mprintf(const char*,...);
char *sqlite3_vmprintf(const char*, va_list);
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.
+** CAPI3REF: Memory Allocation Subsystem {F17300}
+**
+** The SQLite core uses these three routines for all of its own
+** internal memory allocation needs. "Core" in the previous sentence
+** does not include operating-system specific VFS implementation. The
+** windows VFS uses native malloc and free for some operations.
+**
+** The sqlite3_malloc() routine returns a pointer to a block
+** of memory at least N bytes in length, where N is the parameter.
+** If sqlite3_malloc() is unable to obtain sufficient free
+** memory, it returns a NULL pointer. If the parameter N to
+** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns
+** a NULL pointer.
+**
+** Calling sqlite3_free() with a pointer previously returned
+** by sqlite3_malloc() or sqlite3_realloc() releases that memory so
+** that it might be reused. The sqlite3_free() routine is
+** a no-op if is called with a NULL pointer. Passing a NULL pointer
+** to sqlite3_free() is harmless. After being freed, memory
+** should neither be read nor written. Even reading previously freed
+** memory might result in a segmentation fault or other severe error.
+** Memory corruption, a segmentation fault, or other severe error
+** might result if sqlite3_free() is called with a non-NULL pointer that
+** was not obtained from sqlite3_malloc() or sqlite3_free().
+**
+** The sqlite3_realloc() interface attempts to resize a
+** prior memory allocation to be at least N bytes, where N is the
+** second parameter. The memory allocation to be resized is the first
+** parameter. If the first parameter to sqlite3_realloc()
+** is a NULL pointer then its behavior is identical to calling
+** sqlite3_malloc(N) where N is the second parameter to sqlite3_realloc().
+** If the second parameter to sqlite3_realloc() is zero or
+** negative then the behavior is exactly the same as calling
+** sqlite3_free(P) where P is the first parameter to sqlite3_realloc().
+** Sqlite3_realloc() returns a pointer to a memory allocation
+** of at least N bytes in size or NULL if sufficient memory is unavailable.
+** If M is the size of the prior allocation, then min(N,M) bytes
+** of the prior allocation are copied into the beginning of buffer returned
+** by sqlite3_realloc() and the prior allocation is freed.
+** If sqlite3_realloc() returns NULL, then the prior allocation
+** is not freed.
+**
+** The memory returned by sqlite3_malloc() and sqlite3_realloc()
+** is always aligned to at least an 8 byte boundary. {END}
+**
+** The default implementation
+** of the memory allocation subsystem uses the malloc(), realloc()
+** and free() provided by the standard C library. {F17382} However, if
+** SQLite is compiled with the following C preprocessor macro
+**
+** <blockquote> SQLITE_MEMORY_SIZE=<i>NNN</i> </blockquote>
+**
+** where <i>NNN</i> is an integer, then SQLite create a static
+** array of at least <i>NNN</i> bytes in size and use that array
+** for all of its dynamic memory allocation needs. {END} Additional
+** memory allocator options may be added in future releases.
+**
+** In SQLite version 3.5.0 and 3.5.1, it was possible to define
+** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in
+** implementation of these routines to be omitted. That capability
+** is no longer provided. Only built-in memory allocators can be
+** used.
+**
+** The windows OS interface layer calls
+** the system malloc() and free() directly when converting
+** filenames between the UTF-8 encoding used by SQLite
+** and whatever filename encoding is used by the particular windows
+** installation. Memory allocation errors are detected, but
+** they are reported back as [SQLITE_CANTOPEN] or
+** [SQLITE_IOERR] rather than [SQLITE_NOMEM].
+**
+** INVARIANTS:
+**
+** {F17303} The [sqlite3_malloc(N)] interface returns either a pointer to
+** newly checked-out block of at least N bytes of memory
+** that is 8-byte aligned,
+** or it returns NULL if it is unable to fulfill the request.
+**
+** {F17304} The [sqlite3_malloc(N)] interface returns a NULL pointer if
+** N is less than or equal to zero.
+**
+** {F17305} The [sqlite3_free(P)] interface releases memory previously
+** returned from [sqlite3_malloc()] or [sqlite3_realloc()],
+** making it available for reuse.
+**
+** {F17306} A call to [sqlite3_free(NULL)] is a harmless no-op.
+**
+** {F17310} A call to [sqlite3_realloc(0,N)] is equivalent to a call
+** to [sqlite3_malloc(N)].
+**
+** {F17312} A call to [sqlite3_realloc(P,0)] is equivalent to a call
+** to [sqlite3_free(P)].
+**
+** {F17315} The SQLite core uses [sqlite3_malloc()], [sqlite3_realloc()],
+** and [sqlite3_free()] for all of its memory allocation and
+** deallocation needs.
+**
+** {F17318} The [sqlite3_realloc(P,N)] interface returns either a pointer
+** to a block of checked-out memory of at least N bytes in size
+** that is 8-byte aligned, or a NULL pointer.
+**
+** {F17321} When [sqlite3_realloc(P,N)] returns a non-NULL pointer, it first
+** copies the first K bytes of content from P into the newly allocated
+** where K is the lessor of N and the size of the buffer P.
+**
+** {F17322} When [sqlite3_realloc(P,N)] returns a non-NULL pointer, it first
+** releases the buffer P.
+**
+** {F17323} When [sqlite3_realloc(P,N)] returns NULL, the buffer P is
+** not modified or released.
+**
+** LIMITATIONS:
+**
+** {U17350} The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()]
+** must be either NULL or else a pointer obtained from a prior
+** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that has
+** not been released.
+**
+** {U17351} The application must not read or write any part of
+** a block of memory after it has been released using
+** [sqlite3_free()] or [sqlite3_realloc()].
+**
*/
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
-** callback is invoked (at compile-time, not at run-time) for each
-** attempt to access a column of a table in the database. The callback
-** returns SQLITE_OK if access is allowed, SQLITE_DENY if the entire
-** SQL statement should be aborted with an error and SQLITE_IGNORE
-** if the column should be treated as a NULL value.
+** CAPI3REF: Memory Allocator Statistics {F17370}
+**
+** SQLite provides these two interfaces for reporting on the status
+** of the [sqlite3_malloc()], [sqlite3_free()], and [sqlite3_realloc()]
+** the memory allocation subsystem included within the SQLite.
+**
+** INVARIANTS:
+**
+** {F17371} The [sqlite3_memory_used()] routine returns the
+** number of bytes of memory currently outstanding
+** (malloced but not freed).
+**
+** {F17373} The [sqlite3_memory_highwater()] routine returns the maximum
+** value of [sqlite3_memory_used()]
+** since the highwater mark was last reset.
+**
+** {F17374} The values returned by [sqlite3_memory_used()] and
+** [sqlite3_memory_highwater()] include any overhead
+** added by SQLite in its implementation of [sqlite3_malloc()],
+** but not overhead added by the any underlying system library
+** routines that [sqlite3_malloc()] may call.
+**
+** {F17375} The memory highwater mark is reset to the current value of
+** [sqlite3_memory_used()] if and only if the parameter to
+** [sqlite3_memory_highwater()] is true. The value returned
+** by [sqlite3_memory_highwater(1)] is the highwater mark
+** prior to the reset.
+*/
+sqlite3_int64 sqlite3_memory_used(void);
+sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
+
+/*
+** CAPI3REF: Compile-Time Authorization Callbacks {F12500}
+**
+** This routine registers a authorizer callback with a particular
+** database connection, supplied in the first argument.
+** The authorizer callback is invoked as SQL statements are being compiled
+** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()],
+** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. At various
+** points during the compilation process, as logic is being created
+** to perform various actions, the authorizer callback is invoked to
+** see if those actions are allowed. The authorizer callback should
+** return SQLITE_OK to allow the action, [SQLITE_IGNORE] to disallow the
+** specific action but allow the SQL statement to continue to be
+** compiled, or [SQLITE_DENY] to cause the entire SQL statement to be
+** rejected with an error. If the authorizer callback returns
+** any value other than [SQLITE_IGNORE], [SQLITE_OK], or [SQLITE_DENY]
+** then [sqlite3_prepare_v2()] or equivalent call that triggered
+** the authorizer will fail with an error message.
+**
+** When the callback returns [SQLITE_OK], that means the operation
+** requested is ok. When the callback returns [SQLITE_DENY], the
+** [sqlite3_prepare_v2()] or equivalent call that triggered the
+** authorizer will fail with an error message explaining that
+** access is denied. If the authorizer code is [SQLITE_READ]
+** and the callback returns [SQLITE_IGNORE] then the prepared
+** statement is constructed to insert a NULL value in place of
+** the table column that would have
+** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE]
+** return can be used to deny an untrusted user access to individual
+** columns of a table.
+**
+** The first parameter to the authorizer callback is a copy of
+** the third parameter to the sqlite3_set_authorizer() interface.
+** The second parameter to the callback is an integer
+** [SQLITE_COPY | action code] that specifies the particular action
+** to be authorized. The third through sixth
+** parameters to the callback are zero-terminated strings that contain
+** additional details about the action to be authorized.
+**
+** An authorizer is used when preparing SQL statements from an untrusted
+** source, to ensure that the SQL statements do not try to access data
+** that they are not allowed to see, or that they do not try to
+** execute malicious statements that damage the database. For
+** example, an application may allow a user to enter arbitrary
+** SQL queries for evaluation by a database. But the application does
+** not want the user to be able to make arbitrary changes to the
+** database. An authorizer could then be put in place while the
+** user-entered SQL is being prepared that disallows everything
+** except SELECT statements.
+**
+** Only a single authorizer can be in place on a database connection
+** at a time. Each call to sqlite3_set_authorizer overrides the
+** previous call. Disable the authorizer by installing a NULL callback.
+** The authorizer is disabled by default.
+**
+** Note that the authorizer callback is invoked only during
+** [sqlite3_prepare()] or its variants. Authorization is not
+** performed during statement evaluation in [sqlite3_step()].
+**
+** INVARIANTS:
+**
+** {F12501} The [sqlite3_set_authorizer(D,...)] interface registers a
+** authorizer callback with database connection D.
+**
+** {F12502} The authorizer callback is invoked as SQL statements are
+** being compiled
+**
+** {F12503} If the authorizer callback returns any value other than
+** [SQLITE_IGNORE], [SQLITE_OK], or [SQLITE_DENY] then
+** the [sqlite3_prepare_v2()] or equivalent call that caused
+** the authorizer callback to run shall fail with an
+** [SQLITE_ERROR] error code and an appropriate error message.
+**
+** {F12504} When the authorizer callback returns [SQLITE_OK], the operation
+** described is coded normally.
+**
+** {F12505} When the authorizer callback returns [SQLITE_DENY], the
+** [sqlite3_prepare_v2()] or equivalent call that caused the
+** authorizer callback to run shall fail
+** with an [SQLITE_ERROR] error code and an error message
+** explaining that access is denied.
+**
+** {F12506} If the authorizer code (the 2nd parameter to the authorizer
+** callback) is [SQLITE_READ] and the authorizer callback returns
+** [SQLITE_IGNORE] then the prepared statement is constructed to
+** insert a NULL value in place of the table column that would have
+** been read if [SQLITE_OK] had been returned.
+**
+** {F12507} If the authorizer code (the 2nd parameter to the authorizer
+** callback) is anything other than [SQLITE_READ], then
+** a return of [SQLITE_IGNORE] has the same effect as [SQLITE_DENY].
+**
+** {F12510} The first parameter to the authorizer callback is a copy of
+** the third parameter to the [sqlite3_set_authorizer()] interface.
+**
+** {F12511} The second parameter to the callback is an integer
+** [SQLITE_COPY | action code] that specifies the particular action
+** to be authorized.
+**
+** {F12512} The third through sixth parameters to the callback are
+** zero-terminated strings that contain
+** additional details about the action to be authorized.
+**
+** {F12520} Each call to [sqlite3_set_authorizer()] overrides the
+** any previously installed authorizer.
+**
+** {F12521} A NULL authorizer means that no authorization
+** callback is invoked.
+**
+** {F12522} The default authorizer is NULL.
*/
int sqlite3_set_authorizer(
sqlite3*,
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
void *pUserData
);
-#endif
/*
-** The second parameter to the access authorization function above will
-** be one of the values below. These values signify what kind of operation
-** is to be authorized. The 3rd and 4th parameters to the authorization
-** function will be parameters or NULL depending on which of the following
-** codes is used as the second parameter. The 5th parameter is the name
-** of the database ("main", "temp", etc.) if applicable. The 6th parameter
+** CAPI3REF: Authorizer Return Codes {F12590}
+**
+** The [sqlite3_set_authorizer | authorizer callback function] must
+** return either [SQLITE_OK] or one of these two constants in order
+** to signal SQLite whether or not the action is permitted. See the
+** [sqlite3_set_authorizer | authorizer documentation] for additional
+** information.
+*/
+#define SQLITE_DENY 1 /* Abort the SQL statement with an error */
+#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
+
+/*
+** CAPI3REF: Authorizer Action Codes {F12550}
+**
+** The [sqlite3_set_authorizer()] interface registers a callback function
+** that is invoked to authorizer certain SQL statement actions. The
+** second parameter to the callback is an integer code that specifies
+** what action is being authorized. These are the integer action codes that
+** the authorizer callback may be passed.
+**
+** These action code values signify what kind of operation is to be
+** authorized. The 3rd and 4th parameters to the authorization
+** callback function will be parameters or NULL depending on which of these
+** codes is used as the second parameter. The 5th parameter to the
+** authorizer callback is the name of the database ("main", "temp",
+** etc.) if applicable. The 6th parameter to the authorizer callback
** is the name of the inner-most trigger or view that is responsible for
** the access attempt or NULL if this access attempt is directly from
-** input SQL code.
+** top-level SQL code.
+**
+** INVARIANTS:
+**
+** {F12551} The second parameter to an
+** [sqlite3_set_authorizer | authorizer callback is always an integer
+** [SQLITE_COPY | authorizer code] that specifies what action
+** is being authorized.
**
-** Arg-3 Arg-4
+** {F12552} The 3rd and 4th parameters to the
+** [sqlite3_set_authorizer | authorization callback function]
+** will be parameters or NULL depending on which
+** [SQLITE_COPY | authorizer code] is used as the second parameter.
+**
+** {F12553} The 5th parameter to the
+** [sqlite3_set_authorizer | authorizer callback] is the name
+** of the database (example: "main", "temp", etc.) if applicable.
+**
+** {F12554} The 6th parameter to the
+** [sqlite3_set_authorizer | authorizer callback] is the name
+** of the inner-most trigger or view that is responsible for
+** the access attempt or NULL if this access attempt is directly from
+** top-level SQL code.
*/
-#define SQLITE_COPY 0 /* Table Name File Name */
+/******************************************* 3rd ************ 4th ***********/
#define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */
#define SQLITE_CREATE_TABLE 2 /* Table Name NULL */
#define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */
@@ -478,88 +1790,255 @@ int sqlite3_set_authorizer(
#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 */
+#define SQLITE_FUNCTION 31 /* Function Name NULL */
+#define SQLITE_COPY 0 /* No longer used */
/*
-** The return value of the authorization function should be one of the
-** following constants:
-*/
-/* #define SQLITE_OK 0 // Allow access (This is actually defined above) */
-#define SQLITE_DENY 1 /* Abort the SQL statement with an error */
-#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
-
-/*
-** Register a function for tracing SQL command evaluation. The function
-** registered by sqlite3_trace() is invoked at the first sqlite3_step()
-** for the evaluation of an SQL statement. The function registered by
-** sqlite3_profile() runs at the end of each SQL statement and includes
-** information on how long that statement ran.
+** CAPI3REF: Tracing And Profiling Functions {F12280}
+**
+** These routines register callback functions that can be used for
+** tracing and profiling the execution of SQL statements.
+**
+** The callback function registered by sqlite3_trace() is invoked at
+** various times when an SQL statement is being run by [sqlite3_step()].
+** The callback returns a UTF-8 rendering of the SQL statement text
+** as the statement first begins executing. Additional callbacks occur
+** as each triggersubprogram is entered. The callbacks for triggers
+** contain a UTF-8 SQL comment that identifies the trigger.
+**
+** The callback function registered by sqlite3_profile() is invoked
+** as each SQL statement finishes. The profile callback contains
+** the original statement text and an estimate of wall-clock time
+** of how long that statement took to run.
**
** The sqlite3_profile() API is currently considered experimental and
-** is subject to change.
+** is subject to change or removal in a future release.
+**
+** The trigger reporting feature of the trace callback is considered
+** experimental and is subject to change or removal in future releases.
+** Future versions of SQLite might also add new trace callback
+** invocations.
+**
+** INVARIANTS:
+**
+** {F12281} The callback function registered by [sqlite3_trace()] is
+** whenever an SQL statement first begins to execute and
+** whenever a trigger subprogram first begins to run.
+**
+** {F12282} Each call to [sqlite3_trace()] overrides the previously
+** registered trace callback.
+**
+** {F12283} A NULL trace callback disables tracing.
+**
+** {F12284} The first argument to the trace callback is a copy of
+** the pointer which was the 3rd argument to [sqlite3_trace()].
+**
+** {F12285} The second argument to the trace callback is a
+** zero-terminated UTF8 string containing the original text
+** of the SQL statement as it was passed into [sqlite3_prepare_v2()]
+** or the equivalent, or an SQL comment indicating the beginning
+** of a trigger subprogram.
+**
+** {F12287} The callback function registered by [sqlite3_profile()] is invoked
+** as each SQL statement finishes.
+**
+** {F12288} The first parameter to the profile callback is a copy of
+** the 3rd parameter to [sqlite3_profile()].
+**
+** {F12289} The second parameter to the profile callback is a
+** zero-terminated UTF-8 string that contains the complete text of
+** the SQL statement as it was processed by [sqlite3_prepare_v2()]
+** or the equivalent.
+**
+** {F12290} The third parameter to the profile callback is an estimate
+** of the number of nanoseconds of wall-clock time required to
+** run the SQL statement from start to finish.
*/
void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
void *sqlite3_profile(sqlite3*,
- void(*xProfile)(void*,const char*,sqlite_uint64), void*);
+ void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
/*
-** This routine configures a callback function - the progress callback - that
-** is invoked periodically during long running calls to sqlite3_exec(),
-** sqlite3_step() and sqlite3_get_table(). An example use for this API is to
-** keep a GUI updated during a large query.
+** CAPI3REF: Query Progress Callbacks {F12910}
**
-** The progress callback is invoked once for every N virtual machine opcodes,
-** where N is the second argument to this function. The progress callback
-** itself is identified by the third argument to this function. The fourth
-** argument to this function is a void pointer passed to the progress callback
-** function each time it is invoked.
+** This routine configures a callback function - the
+** progress callback - that is invoked periodically during long
+** running calls to [sqlite3_exec()], [sqlite3_step()] and
+** [sqlite3_get_table()]. An example use for this
+** interface is to keep a GUI updated during a large query.
**
-** If a call to sqlite3_exec(), sqlite3_step() or sqlite3_get_table() results
-** in less than N opcodes being executed, then the progress callback is not
-** invoked.
-**
-** To remove the progress callback altogether, pass NULL as the third
-** argument to this function.
+** If the progress callback returns non-zero, the opertion is
+** interrupted. This feature can be used to implement a
+** "Cancel" button on a GUI dialog box.
**
-** If the progress callback returns a result other than 0, then the current
-** query is immediately terminated and any database changes rolled back. If the
-** query was part of a larger transaction, then the transaction is not rolled
-** back and remains active. The sqlite3_exec() call returns SQLITE_ABORT.
+** INVARIANTS:
**
-******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
-*/
-void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
-
-/*
-** Register a callback function to be invoked whenever a new transaction
-** is committed. The pArg argument is passed through to the callback.
-** callback. If the callback function returns non-zero, then the commit
-** is converted into a rollback.
+** {F12911} The callback function registered by [sqlite3_progress_handler()]
+** is invoked periodically during long running calls to
+** [sqlite3_step()].
+**
+** {F12912} The progress callback is invoked once for every N virtual
+** machine opcodes, where N is the second argument to
+** the [sqlite3_progress_handler()] call that registered
+** the callback. <todo>What if N is less than 1?</todo>
+**
+** {F12913} The progress callback itself is identified by the third
+** argument to [sqlite3_progress_handler()].
**
-** If another function was previously registered, its pArg value is returned.
-** Otherwise NULL is returned.
+** {F12914} The fourth argument [sqlite3_progress_handler()] is a
+*** void pointer passed to the progress callback
+** function each time it is invoked.
**
-** Registering a NULL function disables the callback.
+** {F12915} If a call to [sqlite3_step()] results in fewer than
+** N opcodes being executed,
+** then the progress callback is never invoked. {END}
+**
+** {F12916} Every call to [sqlite3_progress_handler()]
+** overwrites any previously registere progress handler.
+**
+** {F12917} If the progress handler callback is NULL then no progress
+** handler is invoked.
**
-******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
+** {F12918} If the progress callback returns a result other than 0, then
+** the behavior is a if [sqlite3_interrupt()] had been called.
*/
-void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
+void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
/*
-** Open the sqlite database file "filename". The "filename" is UTF-8
-** encoded for sqlite3_open() and UTF-16 encoded in the native byte order
-** for sqlite3_open16(). An sqlite3* handle is returned in *ppDb, even
-** if an error occurs. If the database is opened (or created) successfully,
-** then SQLITE_OK is returned. Otherwise an error code is returned. The
-** sqlite3_errmsg() or sqlite3_errmsg16() routines can be used to obtain
+** CAPI3REF: Opening A New Database Connection {F12700}
+**
+** These routines open an SQLite database file whose name
+** is given by the filename argument.
+** The filename argument is interpreted as UTF-8
+** for [sqlite3_open()] and [sqlite3_open_v2()] and as UTF-16
+** in the native byte order for [sqlite3_open16()].
+** An [sqlite3*] handle is usually returned in *ppDb, even
+** if an error occurs. The only exception is if SQLite is unable
+** to allocate memory to hold the [sqlite3] object, a NULL will
+** be written into *ppDb instead of a pointer to the [sqlite3] object.
+** If the database is opened (and/or created)
+** successfully, then [SQLITE_OK] is returned. Otherwise an
+** error code is returned. The
+** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain
** an English language description of the error.
**
-** If the database file does not exist, then a new database is created.
-** The encoding for the database is UTF-8 if sqlite3_open() is called and
-** UTF-16 if sqlite3_open16 is used.
-**
-** Whether or not an error occurs when it is opened, resources associated
-** with the sqlite3* handle should be released by passing it to
-** sqlite3_close() when it is no longer required.
+** The default encoding for the database will be UTF-8 if
+** [sqlite3_open()] or [sqlite3_open_v2()] is called and
+** UTF-16 in the native byte order if [sqlite3_open16()] is used.
+**
+** Whether or not an error occurs when it is opened, resources
+** associated with the [sqlite3*] handle should be released by passing it
+** to [sqlite3_close()] when it is no longer required.
+**
+** The [sqlite3_open_v2()] interface works like [sqlite3_open()]
+** except that it acccepts two additional parameters for additional control
+** over the new database connection. The flags parameter can be
+** one of:
+**
+** <ol>
+** <li> [SQLITE_OPEN_READONLY]
+** <li> [SQLITE_OPEN_READWRITE]
+** <li> [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]
+** </ol>
+**
+** The first value opens the database read-only.
+** If the database does not previously exist, an error is returned.
+** The second option opens
+** the database for reading and writing if possible, or reading only if
+** if the file is write protected. In either case the database
+** must already exist or an error is returned. The third option
+** opens the database for reading and writing and creates it if it does
+** not already exist.
+** The third options is behavior that is always used for [sqlite3_open()]
+** and [sqlite3_open16()].
+**
+** If the filename is ":memory:", then an private
+** in-memory database is created for the connection. This in-memory
+** database will vanish when the database connection is closed. Future
+** version of SQLite might make use of additional special filenames
+** that begin with the ":" character. It is recommended that
+** when a database filename really does begin with
+** ":" that you prefix the filename with a pathname like "./" to
+** avoid ambiguity.
+**
+** If the filename is an empty string, then a private temporary
+** on-disk database will be created. This private database will be
+** automatically deleted as soon as the database connection is closed.
+**
+** The fourth parameter to sqlite3_open_v2() is the name of the
+** [sqlite3_vfs] object that defines the operating system
+** interface that the new database connection should use. If the
+** fourth parameter is a NULL pointer then the default [sqlite3_vfs]
+** object is used.
+**
+** <b>Note to windows users:</b> The encoding used for the filename argument
+** of [sqlite3_open()] and [sqlite3_open_v2()] must be UTF-8, not whatever
+** codepage is currently defined. Filenames containing international
+** characters must be converted to UTF-8 prior to passing them into
+** [sqlite3_open()] or [sqlite3_open_v2()].
+**
+** INVARIANTS:
+**
+** {F12701} The [sqlite3_open()], [sqlite3_open16()], and
+** [sqlite3_open_v2()] interfaces create a new
+** [database connection] associated with
+** the database file given in their first parameter.
+**
+** {F12702} The filename argument is interpreted as UTF-8
+** for [sqlite3_open()] and [sqlite3_open_v2()] and as UTF-16
+** in the native byte order for [sqlite3_open16()].
+**
+** {F12703} A successful invocation of [sqlite3_open()], [sqlite3_open16()],
+** or [sqlite3_open_v2()] writes a pointer to a new
+** [database connection] into *ppDb.
+**
+** {F12704} The [sqlite3_open()], [sqlite3_open16()], and
+** [sqlite3_open_v2()] interfaces return [SQLITE_OK] upon success,
+** or an appropriate [error code] on failure.
+**
+** {F12706} The default text encoding for a new database created using
+** [sqlite3_open()] or [sqlite3_open_v2()] will be UTF-8.
+**
+** {F12707} The default text encoding for a new database created using
+** [sqlite3_open16()] will be UTF-16.
+**
+** {F12709} The [sqlite3_open(F,D)] interface is equivalent to
+** [sqlite3_open_v2(F,D,G,0)] where the G parameter is
+** [SQLITE_OPEN_READWRITE]|[SQLITE_OPEN_CREATE].
+**
+** {F12711} If the G parameter to [sqlite3_open_v2(F,D,G,V)] contains the
+** bit value [SQLITE_OPEN_READONLY] then the database is opened
+** for reading only.
+**
+** {F12712} If the G parameter to [sqlite3_open_v2(F,D,G,V)] contains the
+** bit value [SQLITE_OPEN_READWRITE] then the database is opened
+** reading and writing if possible, or for reading only if the
+** file is write protected by the operating system.
+**
+** {F12713} If the G parameter to [sqlite3_open(v2(F,D,G,V)] omits the
+** bit value [SQLITE_OPEN_CREATE] and the database does not
+** previously exist, an error is returned.
+**
+** {F12714} If the G parameter to [sqlite3_open(v2(F,D,G,V)] contains the
+** bit value [SQLITE_OPEN_CREATE] and the database does not
+** previously exist, then an attempt is made to create and
+** initialize the database.
+**
+** {F12717} If the filename argument to [sqlite3_open()], [sqlite3_open16()],
+** or [sqlite3_open_v2()] is ":memory:", then an private,
+** ephemeral, in-memory database is created for the connection.
+** <todo>Is SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE required
+** in sqlite3_open_v2()?</todo>
+**
+** {F12719} If the filename is an empty string, then a private, ephermeral
+** on-disk database will be created.
+** <todo>Is SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE required
+** in sqlite3_open_v2()?</todo>
+**
+** {F12721} The [database connection] created by
+** [sqlite3_open_v2(F,D,G,V)] will use the
+** [sqlite3_vfs] object identified by the V parameter, or
+** the default [sqlite3_vfs] object is V is a NULL pointer.
*/
int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
@@ -569,192 +2048,709 @@ int sqlite3_open16(
const void *filename, /* Database filename (UTF-16) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
+int sqlite3_open_v2(
+ const char *filename, /* Database filename (UTF-8) */
+ sqlite3 **ppDb, /* OUT: SQLite db handle */
+ int flags, /* Flags */
+ const char *zVfs /* Name of VFS module to use */
+);
/*
-** Return the error code for the most recent sqlite3_* API call associated
-** with sqlite3 handle 'db'. SQLITE_OK is returned if the most recent
-** API call was successful.
-**
-** Calls to many sqlite3_* functions set the error code and string returned
-** by sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16()
-** (overwriting the previous values). Note that calls to sqlite3_errcode(),
-** sqlite3_errmsg() and sqlite3_errmsg16() themselves do not affect the
-** results of future invocations.
-**
-** Assuming no other intervening sqlite3_* API calls are made, the error
-** code returned by this function is associated with the same error as
-** the strings returned by sqlite3_errmsg() and sqlite3_errmsg16().
+** CAPI3REF: Error Codes And Messages {F12800}
+**
+** The sqlite3_errcode() interface returns the numeric
+** [SQLITE_OK | result code] or [SQLITE_IOERR_READ | extended result code]
+** for the most recent failed sqlite3_* API call associated
+** with [sqlite3] handle 'db'. If a prior API call failed but the
+** most recent API call succeeded, the return value from sqlite3_errcode()
+** is undefined.
+**
+** The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
+** text that describes the error, as either UTF8 or UTF16 respectively.
+** Memory to hold the error message string is managed internally.
+** The application does not need to worry with freeing the result.
+** However, the error string might be overwritten or deallocated b
+** subsequent calls to other SQLite interface functions.
+**
+** INVARIANTS:
+**
+** {F12801} The [sqlite3_errcode(D)] interface returns the numeric
+** [SQLITE_OK | result code] or
+** [SQLITE_IOERR_READ | extended result code]
+** for the most recent failed interface call associated
+** with [sqlite3] handle D.
+**
+** {U12802} If a prior API call failed but the most recent API call
+** succeeded, the return value from [sqlite3_errcode()],
+** [sqlite3_errmsg()], and [sqlite3_errmsg16()] are undefined.
+**
+** {F12803} The [sqlite3_errmsg(D)] and [sqlite3_errmsg16(D)]
+** interfaces return English-language text that describes
+** the error in the mostly recently failed interface call,
+** encoded as either UTF8 or UTF16 respectively.
+**
+** {U12804} The strings returned by [sqlite3_errmsg()] and [sqlite3_errmsg16()]
+** are only valid until the next SQLite interface call.
+**
+** {F12807} Calls to [sqlite3_errcode()], [sqlite3_errmsg()], and
+** [sqlite3_errmsg16()] themselves do not affect the
+** results of future invocations of these routines.
+**
+** {F12808} Calls to API routines that do not return an error code
+** (example: [sqlite3_data_count()]) do not
+** change the error code or message returned by
+** [sqlite3_errcode()], [sqlite3_errmsg()], or [sqlite3_errmsg16()].
+**
+** {F12809} Interfaces that are not associated with a specific
+** [database connection] (examples:
+** [sqlite3_mprintf()] or [sqlite3_enable_shared_cache()]
+** do not change the values returned by
+** [sqlite3_errcode()], [sqlite3_errmsg()], or [sqlite3_errmsg16()].
*/
int sqlite3_errcode(sqlite3 *db);
-
-/*
-** Return a pointer to a UTF-8 encoded string describing in english the
-** error condition for the most recent sqlite3_* API call. The returned
-** string is always terminated by an 0x00 byte.
-**
-** The string "not an error" is returned when the most recent API call was
-** successful.
-*/
const char *sqlite3_errmsg(sqlite3*);
-
-/*
-** Return a pointer to a UTF-16 native byte order encoded string describing
-** in english the error condition for the most recent sqlite3_* API call.
-** The returned string is always terminated by a pair of 0x00 bytes.
-**
-** The string "not an error" is returned when the most recent API call was
-** successful.
-*/
const void *sqlite3_errmsg16(sqlite3*);
/*
-** An instance of the following opaque structure is used to represent
-** a compiled SQL statment.
+** CAPI3REF: SQL Statement Object {F13000}
+** KEYWORDS: {prepared statement} {prepared statements}
+**
+** An instance of this object represent single SQL statements. This
+** object is variously known as a "prepared statement" or a
+** "compiled SQL statement" or simply as a "statement".
+**
+** The life of a statement object goes something like this:
+**
+** <ol>
+** <li> Create the object using [sqlite3_prepare_v2()] or a related
+** function.
+** <li> Bind values to host parameters using
+** [sqlite3_bind_blob | sqlite3_bind_* interfaces].
+** <li> Run the SQL by calling [sqlite3_step()] one or more times.
+** <li> Reset the statement using [sqlite3_reset()] then go back
+** to step 2. Do this zero or more times.
+** <li> Destroy the object using [sqlite3_finalize()].
+** </ol>
+**
+** Refer to documentation on individual methods above for additional
+** information.
*/
typedef struct sqlite3_stmt sqlite3_stmt;
/*
-** To execute an SQL query, it must first be compiled into a byte-code
-** program using one of the following routines. The only difference between
-** them is that the second argument, specifying the SQL statement to
-** compile, is assumed to be encoded in UTF-8 for the sqlite3_prepare()
-** function and UTF-16 for sqlite3_prepare16().
+** CAPI3REF: Compiling An SQL Statement {F13010}
**
-** The first parameter "db" is an SQLite database handle. The second
-** parameter "zSql" is the statement to be compiled, encoded as either
-** UTF-8 or UTF-16 (see above). If the next parameter, "nBytes", is less
-** than zero, then zSql is read up to the first nul terminator. If
-** "nBytes" is not less than zero, then it is the length of the string zSql
-** in bytes (not characters).
-**
-** *pzTail is made to point to the first byte past the end of the first
-** SQL statement in zSql. This routine only compiles the first statement
-** in zSql, so *pzTail is left pointing to what remains uncompiled.
-**
-** *ppStmt is left pointing to a compiled SQL statement that can be
-** executed using sqlite3_step(). Or if there is an error, *ppStmt may be
-** set to NULL. If the input text contained no SQL (if the input is and
-** empty string or a comment) then *ppStmt is set to NULL.
-**
-** On success, SQLITE_OK is returned. Otherwise an error code is returned.
+** To execute an SQL query, it must first be compiled into a byte-code
+** program using one of these routines.
+**
+** The first argument "db" is an [database connection]
+** obtained from a prior call to [sqlite3_open()], [sqlite3_open_v2()]
+** or [sqlite3_open16()].
+** The second argument "zSql" is the statement to be compiled, encoded
+** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2()
+** interfaces uses UTF-8 and sqlite3_prepare16() and sqlite3_prepare16_v2()
+** use UTF-16. {END}
+**
+** If the nByte argument is less
+** than zero, then zSql is read up to the first zero terminator.
+** If nByte is non-negative, then it is the maximum number of
+** bytes read from zSql. When nByte is non-negative, the
+** zSql string ends at either the first '\000' or '\u0000' character or
+** until the nByte-th byte, whichever comes first. {END}
+**
+** *pzTail is made to point to the first byte past the end of the
+** first SQL statement in zSql. These routines only compiles the first
+** statement in zSql, so *pzTail is left pointing to what remains
+** uncompiled.
+**
+** *ppStmt is left pointing to a compiled [prepared statement] that can be
+** executed using [sqlite3_step()]. Or if there is an error, *ppStmt may be
+** set to NULL. If the input text contains no SQL (if the input
+** is and empty string or a comment) then *ppStmt is set to NULL.
+** {U13018} The calling procedure is responsible for deleting the
+** compiled SQL statement
+** using [sqlite3_finalize()] after it has finished with it.
+**
+** On success, [SQLITE_OK] is returned. Otherwise an
+** [error code] is returned.
+**
+** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are
+** recommended for all new programs. The two older interfaces are retained
+** for backwards compatibility, but their use is discouraged.
+** In the "v2" interfaces, the prepared statement
+** that is returned (the [sqlite3_stmt] object) contains a copy of the
+** original SQL text. {END} This causes the [sqlite3_step()] interface to
+** behave a differently in two ways:
+**
+** <ol>
+** <li>
+** If the database schema changes, instead of returning [SQLITE_SCHEMA] as it
+** always used to do, [sqlite3_step()] will automatically recompile the SQL
+** statement and try to run it again. If the schema has changed in
+** a way that makes the statement no longer valid, [sqlite3_step()] will still
+** return [SQLITE_SCHEMA]. But unlike the legacy behavior,
+** [SQLITE_SCHEMA] is now a fatal error. Calling
+** [sqlite3_prepare_v2()] again will not make the
+** error go away. Note: use [sqlite3_errmsg()] to find the text
+** of the parsing error that results in an [SQLITE_SCHEMA] return. {END}
+** </li>
+**
+** <li>
+** When an error occurs,
+** [sqlite3_step()] will return one of the detailed
+** [error codes] or [extended error codes].
+** The legacy behavior was that [sqlite3_step()] would only return a generic
+** [SQLITE_ERROR] result code and you would have to make a second call to
+** [sqlite3_reset()] in order to find the underlying cause of the problem.
+** With the "v2" prepare interfaces, the underlying reason for the error is
+** returned immediately.
+** </li>
+** </ol>
+**
+** INVARIANTS:
+**
+** {F13011} The [sqlite3_prepare(db,zSql,...)] and
+** [sqlite3_prepare_v2(db,zSql,...)] interfaces interpret the
+** text in their zSql parameter as UTF-8.
+**
+** {F13012} The [sqlite3_prepare16(db,zSql,...)] and
+** [sqlite3_prepare16_v2(db,zSql,...)] interfaces interpret the
+** text in their zSql parameter as UTF-16 in the native byte order.
+**
+** {F13013} If the nByte argument to [sqlite3_prepare_v2(db,zSql,nByte,...)]
+** and its variants is less than zero, then SQL text is
+** read from zSql is read up to the first zero terminator.
+**
+** {F13014} If the nByte argument to [sqlite3_prepare_v2(db,zSql,nByte,...)]
+** and its variants is non-negative, then nBytes bytes
+** SQL text is read from zSql.
+**
+** {F13015} In [sqlite3_prepare_v2(db,zSql,N,P,pzTail)] and its variants
+** if the zSql input text contains more than one SQL statement
+** and pzTail is not NULL, then *pzTail is made to point to the
+** first byte past the end of the first SQL statement in zSql.
+** <todo>What does *pzTail point to if there is one statement?</todo>
+**
+** {F13016} A successful call to [sqlite3_prepare_v2(db,zSql,N,ppStmt,...)]
+** or one of its variants writes into *ppStmt a pointer to a new
+** [prepared statement] or a pointer to NULL
+** if zSql contains nothing other than whitespace or comments.
+**
+** {F13019} The [sqlite3_prepare_v2()] interface and its variants return
+** [SQLITE_OK] or an appropriate [error code] upon failure.
*/
int sqlite3_prepare(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
- int nBytes, /* Length of zSql in bytes. */
+ int nByte, /* Maximum length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
+ const char **pzTail /* OUT: Pointer to unused portion of zSql */
+);
+int sqlite3_prepare_v2(
+ sqlite3 *db, /* Database handle */
+ const char *zSql, /* SQL statement, UTF-8 encoded */
+ int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
int sqlite3_prepare16(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
- int nBytes, /* Length of zSql in bytes. */
+ int nByte, /* Maximum length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
+ const void **pzTail /* OUT: Pointer to unused portion of zSql */
+);
+int sqlite3_prepare16_v2(
+ sqlite3 *db, /* Database handle */
+ const void *zSql, /* SQL statement, UTF-16 encoded */
+ int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const void **pzTail /* OUT: Pointer to unused portion of zSql */
);
/*
-** Pointers to the following two opaque structures are used to communicate
-** with the implementations of user-defined functions.
+** CAPIREF: Retrieving Statement SQL {F13100}
+**
+** This intereface can be used to retrieve a saved copy of the original
+** SQL text used to create a [prepared statement].
+**
+** INVARIANTS:
+**
+** {F13101} If the [prepared statement] passed as
+** the an argument to [sqlite3_sql()] was compiled
+** compiled using either [sqlite3_prepare_v2()] or
+** [sqlite3_prepare16_v2()],
+** then [sqlite3_sql()] function returns a pointer to a
+** zero-terminated string containing a UTF-8 rendering
+** of the original SQL statement.
+**
+** {F13102} If the [prepared statement] passed as
+** the an argument to [sqlite3_sql()] was compiled
+** compiled using either [sqlite3_prepare()] or
+** [sqlite3_prepare16()],
+** then [sqlite3_sql()] function returns a NULL pointer.
+**
+** {F13103} The string returned by [sqlite3_sql(S)] is valid until the
+** [prepared statement] S is deleted using [sqlite3_finalize(S)].
*/
-typedef struct sqlite3_context sqlite3_context;
-typedef struct Mem sqlite3_value;
+const char *sqlite3_sql(sqlite3_stmt *pStmt);
/*
-** In the SQL strings input to sqlite3_prepare() and sqlite3_prepare16(),
-** one or more literals can be replace by parameters "?" or ":AAA" or
-** "$VVV" where AAA is an identifer and VVV is a variable name according
-** to the syntax rules of the TCL programming language.
-** The value of these parameters (also called "host parameter names") can
-** be set using the routines listed below.
+** CAPI3REF: Dynamically Typed Value Object {F15000}
**
-** In every case, the first parameter is a pointer to the sqlite3_stmt
-** structure returned from sqlite3_prepare(). The second parameter is the
-** index of the parameter. The first parameter as an index of 1. For
-** named parameters (":AAA" or "$VVV") you can use
-** sqlite3_bind_parameter_index() to get the correct index value given
-** the parameters name. If the same named parameter occurs more than
-** once, it is assigned the same index each time.
+** SQLite uses the sqlite3_value object to represent all values
+** that are or can be stored in a database table.
+** SQLite uses dynamic typing for the values it stores.
+** Values stored in sqlite3_value objects can be
+** be integers, floating point values, strings, BLOBs, or NULL.
+*/
+typedef struct Mem sqlite3_value;
+
+/*
+** CAPI3REF: SQL Function Context Object {F16001}
**
-** The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and
+** The context in which an SQL function executes is stored in an
+** sqlite3_context object. A pointer to an sqlite3_context
+** object is always first parameter to application-defined SQL functions.
+*/
+typedef struct sqlite3_context sqlite3_context;
+
+/*
+** CAPI3REF: Binding Values To Prepared Statements {F13500}
+**
+** In the SQL strings input to [sqlite3_prepare_v2()] and its
+** variants, literals may be replace by a parameter in one
+** of these forms:
+**
+** <ul>
+** <li> ?
+** <li> ?NNN
+** <li> :VVV
+** <li> @VVV
+** <li> $VVV
+** </ul>
+**
+** In the parameter forms shown above NNN is an integer literal,
+** VVV alpha-numeric parameter name.
+** The values of these parameters (also called "host parameter names"
+** or "SQL parameters")
+** can be set using the sqlite3_bind_*() routines defined here.
+**
+** The first argument to the sqlite3_bind_*() routines always
+** is a pointer to the [sqlite3_stmt] object returned from
+** [sqlite3_prepare_v2()] or its variants. The second
+** argument is the index of the parameter to be set. The
+** first parameter has an index of 1. When the same named
+** parameter is used more than once, second and subsequent
+** occurrences have the same index as the first occurrence.
+** The index for named parameters can be looked up using the
+** [sqlite3_bind_parameter_name()] API if desired. The index
+** for "?NNN" parameters is the value of NNN.
+** The NNN value must be between 1 and the compile-time
+** parameter SQLITE_MAX_VARIABLE_NUMBER (default value: 999).
+**
+** The third argument is the value to bind to the parameter.
+**
+** In those
+** routines that have a fourth argument, its value is the number of bytes
+** in the parameter. To be clear: the value is the number of <u>bytes</u>
+** in the value, not the number of characters. The number
+** of bytes does not include the zero-terminator at the end of strings.
+** If the fourth parameter is negative, the length of the string is
+** number of bytes up to the first zero terminator.
+**
+** The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
-** text after SQLite has finished with it. If the fifth argument is the
-** special value SQLITE_STATIC, then the library assumes that the information
-** is in static, unmanaged space and does not need to be freed. If the
-** fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its
-** own private copy of the data.
-**
-** The sqlite3_bind_* routine must be called before sqlite3_step() after
-** an sqlite3_prepare() or sqlite3_reset(). Unbound parameterss are
-** interpreted as NULL.
+** string after SQLite has finished with it. If the fifth argument is
+** the special value [SQLITE_STATIC], then SQLite assumes that the
+** information is in static, unmanaged space and does not need to be freed.
+** If the fifth argument has the value [SQLITE_TRANSIENT], then
+** SQLite makes its own private copy of the data immediately, before
+** the sqlite3_bind_*() routine returns.
+**
+** The sqlite3_bind_zeroblob() routine binds a BLOB of length N that
+** is filled with zeros. A zeroblob uses a fixed amount of memory
+** (just an integer to hold it size) while it is being processed.
+** Zeroblobs are intended to serve as place-holders for BLOBs whose
+** content is later written using
+** [sqlite3_blob_open | increment BLOB I/O] routines. A negative
+** value for the zeroblob results in a zero-length BLOB.
+**
+** The sqlite3_bind_*() routines must be called after
+** [sqlite3_prepare_v2()] (and its variants) or [sqlite3_reset()] and
+** before [sqlite3_step()].
+** Bindings are not cleared by the [sqlite3_reset()] routine.
+** Unbound parameters are interpreted as NULL.
+**
+** These routines return [SQLITE_OK] on success or an error code if
+** anything goes wrong. [SQLITE_RANGE] is returned if the parameter
+** index is out of range. [SQLITE_NOMEM] is returned if malloc fails.
+** [SQLITE_MISUSE] might be returned if these routines are called on a
+** virtual machine that is the wrong state or which has already been finalized.
+** Detection of misuse is unreliable. Applications should not depend
+** on SQLITE_MISUSE returns. SQLITE_MISUSE is intended to indicate a
+** a logic error in the application. Future versions of SQLite might
+** panic rather than return SQLITE_MISUSE.
+**
+** See also: [sqlite3_bind_parameter_count()],
+** [sqlite3_bind_parameter_name()], and
+** [sqlite3_bind_parameter_index()].
+**
+** INVARIANTS:
+**
+** {F13506} The [sqlite3_prepare | SQL statement compiler] recognizes
+** tokens of the forms "?", "?NNN", "$VVV", ":VVV", and "@VVV"
+** as SQL parameters, where NNN is any sequence of one or more
+** digits and where VVV is any sequence of one or more
+** alphanumeric characters or "::" optionally followed by
+** a string containing no spaces and contained within parentheses.
+**
+** {F13509} The initial value of an SQL parameter is NULL.
+**
+** {F13512} The index of an "?" SQL parameter is one larger than the
+** largest index of SQL parameter to the left, or 1 if
+** the "?" is the leftmost SQL parameter.
+**
+** {F13515} The index of an "?NNN" SQL parameter is the integer NNN.
+**
+** {F13518} The index of an ":VVV", "$VVV", or "@VVV" SQL parameter is
+** the same as the index of leftmost occurances of the same
+** parameter, or one more than the largest index over all
+** parameters to the left if this is the first occurrance
+** of this parameter, or 1 if this is the leftmost parameter.
+**
+** {F13521} The [sqlite3_prepare | SQL statement compiler] fail with
+** an [SQLITE_RANGE] error if the index of an SQL parameter
+** is less than 1 or greater than SQLITE_MAX_VARIABLE_NUMBER.
+**
+** {F13524} Calls to [sqlite3_bind_text | sqlite3_bind(S,N,V,...)]
+** associate the value V with all SQL parameters having an
+** index of N in the [prepared statement] S.
+**
+** {F13527} Calls to [sqlite3_bind_text | sqlite3_bind(S,N,...)]
+** override prior calls with the same values of S and N.
+**
+** {F13530} Bindings established by [sqlite3_bind_text | sqlite3_bind(S,...)]
+** persist across calls to [sqlite3_reset(S)].
+**
+** {F13533} In calls to [sqlite3_bind_blob(S,N,V,L,D)],
+** [sqlite3_bind_text(S,N,V,L,D)], or
+** [sqlite3_bind_text16(S,N,V,L,D)] SQLite binds the first L
+** bytes of the blob or string pointed to by V, when L
+** is non-negative.
+**
+** {F13536} In calls to [sqlite3_bind_text(S,N,V,L,D)] or
+** [sqlite3_bind_text16(S,N,V,L,D)] SQLite binds characters
+** from V through the first zero character when L is negative.
+**
+** {F13539} In calls to [sqlite3_bind_blob(S,N,V,L,D)],
+** [sqlite3_bind_text(S,N,V,L,D)], or
+** [sqlite3_bind_text16(S,N,V,L,D)] when D is the special
+** constant [SQLITE_STATIC], SQLite assumes that the value V
+** is held in static unmanaged space that will not change
+** during the lifetime of the binding.
+**
+** {F13542} In calls to [sqlite3_bind_blob(S,N,V,L,D)],
+** [sqlite3_bind_text(S,N,V,L,D)], or
+** [sqlite3_bind_text16(S,N,V,L,D)] when D is the special
+** constant [SQLITE_TRANSIENT], the routine makes a
+** private copy of V value before it returns.
+**
+** {F13545} In calls to [sqlite3_bind_blob(S,N,V,L,D)],
+** [sqlite3_bind_text(S,N,V,L,D)], or
+** [sqlite3_bind_text16(S,N,V,L,D)] when D is a pointer to
+** a function, SQLite invokes that function to destroy the
+** V value after it has finished using the V value.
+**
+** {F13548} In calls to [sqlite3_bind_zeroblob(S,N,V,L)] the value bound
+** is a blob of L bytes, or a zero-length blob if L is negative.
*/
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
int sqlite3_bind_double(sqlite3_stmt*, int, double);
int sqlite3_bind_int(sqlite3_stmt*, int, int);
-int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite_int64);
+int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
int sqlite3_bind_null(sqlite3_stmt*, int);
int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
+int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
/*
-** Return the number of parameters in a compiled SQL statement. This
-** routine was added to support DBD::SQLite.
+** CAPI3REF: Number Of SQL Parameters {F13600}
+**
+** This routine can be used to find the number of SQL parameters
+** in a prepared statement. SQL parameters are tokens of the
+** form "?", "?NNN", ":AAA", "$AAA", or "@AAA" that serve as
+** place-holders for values that are [sqlite3_bind_blob | bound]
+** to the parameters at a later time.
+**
+** This routine actually returns the index of the largest parameter.
+** For all forms except ?NNN, this will correspond to the number of
+** unique parameters. If parameters of the ?NNN are used, there may
+** be gaps in the list.
+**
+** See also: [sqlite3_bind_blob|sqlite3_bind()],
+** [sqlite3_bind_parameter_name()], and
+** [sqlite3_bind_parameter_index()].
+**
+** INVARIANTS:
+**
+** {F13601} The [sqlite3_bind_parameter_count(S)] interface returns
+** the largest index of all SQL parameters in the
+** [prepared statement] S, or 0 if S
+** contains no SQL parameters.
*/
int sqlite3_bind_parameter_count(sqlite3_stmt*);
/*
-** Return the name of the i-th parameter. Ordinary parameters "?" are
-** nameless and a NULL is returned. For parameters of the form :AAA or
-** $VVV the complete text of the parameter name is returned, including
-** the initial ":" or "$". NULL is returned if the index is out of range.
+** CAPI3REF: Name Of A Host Parameter {F13620}
+**
+** This routine returns a pointer to the name of the n-th
+** SQL parameter in a [prepared statement].
+** SQL parameters of the form ":AAA" or "@AAA" or "$AAA" have a name
+** which is the string ":AAA" or "@AAA" or "$VVV".
+** In other words, the initial ":" or "$" or "@"
+** is included as part of the name.
+** Parameters of the form "?" or "?NNN" have no name.
+**
+** The first host parameter has an index of 1, not 0.
+**
+** If the value n is out of range or if the n-th parameter is
+** nameless, then NULL is returned. The returned string is
+** always in the UTF-8 encoding even if the named parameter was
+** originally specified as UTF-16 in [sqlite3_prepare16()] or
+** [sqlite3_prepare16_v2()].
+**
+** See also: [sqlite3_bind_blob|sqlite3_bind()],
+** [sqlite3_bind_parameter_count()], and
+** [sqlite3_bind_parameter_index()].
+**
+** INVARIANTS:
+**
+** {F13621} The [sqlite3_bind_parameter_name(S,N)] interface returns
+** a UTF-8 rendering of the name of the SQL parameter in
+** [prepared statement] S having index N, or
+** NULL if there is no SQL parameter with index N or if the
+** parameter with index N is an anonymous parameter "?" or
+** a numbered parameter "?NNN".
*/
const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
/*
-** Return the index of a parameter with the given name. The name
-** must match exactly. If no parameter with the given name is found,
-** return 0.
+** CAPI3REF: Index Of A Parameter With A Given Name {F13640}
+**
+** Return the index of an SQL parameter given its name. The
+** index value returned is suitable for use as the second
+** parameter to [sqlite3_bind_blob|sqlite3_bind()]. A zero
+** is returned if no matching parameter is found. The parameter
+** name must be given in UTF-8 even if the original statement
+** was prepared from UTF-16 text using [sqlite3_prepare16_v2()].
+**
+** See also: [sqlite3_bind_blob|sqlite3_bind()],
+** [sqlite3_bind_parameter_count()], and
+** [sqlite3_bind_parameter_index()].
+**
+** INVARIANTS:
+**
+** {F13641} The [sqlite3_bind_parameter_index(S,N)] interface returns
+** the index of SQL parameter in [prepared statement]
+** S whose name matches the UTF-8 string N, or 0 if there is
+** no match.
*/
int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
/*
-** Set all the parameters in the compiled SQL statement to NULL.
+** CAPI3REF: Reset All Bindings On A Prepared Statement {F13660}
+**
+** Contrary to the intuition of many, [sqlite3_reset()] does not
+** reset the [sqlite3_bind_blob | bindings] on a
+** [prepared statement]. Use this routine to
+** reset all host parameters to NULL.
+**
+** INVARIANTS:
+**
+** {F13661} The [sqlite3_clear_bindings(S)] interface resets all
+** SQL parameter bindings in [prepared statement] S
+** back to NULL.
*/
int sqlite3_clear_bindings(sqlite3_stmt*);
/*
-** Return the number of columns in the result set returned by the compiled
-** SQL statement. This routine returns 0 if pStmt is an SQL statement
-** that does not return data (for example an UPDATE).
+** CAPI3REF: Number Of Columns In A Result Set {F13710}
+**
+** Return the number of columns in the result set returned by the
+** [prepared statement]. This routine returns 0
+** if pStmt is an SQL statement that does not return data (for
+** example an UPDATE).
+**
+** INVARIANTS:
+**
+** {F13711} The [sqlite3_column_count(S)] interface returns the number of
+** columns in the result set generated by the
+** [prepared statement] S, or 0 if S does not generate
+** a result set.
*/
int sqlite3_column_count(sqlite3_stmt *pStmt);
/*
-** The first parameter is a compiled SQL statement. This function returns
-** the column heading for the Nth column of that statement, where N is the
-** second function parameter. The string returned is UTF-8 for
-** sqlite3_column_name() and UTF-16 for sqlite3_column_name16().
+** CAPI3REF: Column Names In A Result Set {F13720}
+**
+** These routines return the name assigned to a particular column
+** in the result set of a SELECT statement. The sqlite3_column_name()
+** interface returns a pointer to a zero-terminated UTF8 string
+** and sqlite3_column_name16() returns a pointer to a zero-terminated
+** UTF16 string. The first parameter is the
+** [prepared statement] that implements the SELECT statement.
+** The second parameter is the column number. The left-most column is
+** number 0.
+**
+** The returned string pointer is valid until either the
+** [prepared statement] is destroyed by [sqlite3_finalize()]
+** or until the next call sqlite3_column_name() or sqlite3_column_name16()
+** on the same column.
+**
+** If sqlite3_malloc() fails during the processing of either routine
+** (for example during a conversion from UTF-8 to UTF-16) then a
+** NULL pointer is returned.
+**
+** The name of a result column is the value of the "AS" clause for
+** that column, if there is an AS clause. If there is no AS clause
+** then the name of the column is unspecified and may change from
+** one release of SQLite to the next.
+**
+** INVARIANTS:
+**
+** {F13721} A successful invocation of the [sqlite3_column_name(S,N)]
+** interface returns the name
+** of the Nth column (where 0 is the left-most column) for the
+** result set of [prepared statement] S as a
+** zero-terminated UTF-8 string.
+**
+** {F13723} A successful invocation of the [sqlite3_column_name16(S,N)]
+** interface returns the name
+** of the Nth column (where 0 is the left-most column) for the
+** result set of [prepared statement] S as a
+** zero-terminated UTF-16 string in the native byte order.
+**
+** {F13724} The [sqlite3_column_name()] and [sqlite3_column_name16()]
+** interfaces return a NULL pointer if they are unable to
+** allocate memory memory to hold there normal return strings.
+**
+** {F13725} If the N parameter to [sqlite3_column_name(S,N)] or
+** [sqlite3_column_name16(S,N)] is out of range, then the
+** interfaces returns a NULL pointer.
+**
+** {F13726} The strings returned by [sqlite3_column_name(S,N)] and
+** [sqlite3_column_name16(S,N)] are valid until the next
+** call to either routine with the same S and N parameters
+** or until [sqlite3_finalize(S)] is called.
+**
+** {F13727} When a result column of a [SELECT] statement contains
+** an AS clause, the name of that column is the indentifier
+** to the right of the AS keyword.
*/
-const char *sqlite3_column_name(sqlite3_stmt*,int);
-const void *sqlite3_column_name16(sqlite3_stmt*,int);
+const char *sqlite3_column_name(sqlite3_stmt*, int N);
+const void *sqlite3_column_name16(sqlite3_stmt*, int N);
/*
-** The first parameter to the following calls is a compiled SQL statement.
+** CAPI3REF: Source Of Data In A Query Result {F13740}
+**
+** These routines provide a means to determine what column of what
+** table in which database a result of a SELECT statement comes from.
+** The name of the database or table or column can be returned as
+** either a UTF8 or UTF16 string. The _database_ routines return
+** the database name, the _table_ routines return the table name, and
+** the origin_ routines return the column name.
+** The returned string is valid until
+** the [prepared statement] is destroyed using
+** [sqlite3_finalize()] or until the same information is requested
+** again in a different encoding.
+**
+** The names returned are the original un-aliased names of the
+** database, table, and column.
+**
+** The first argument to the following calls is a [prepared 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.
+** If the Nth column returned by the statement is an expression
+** or subquery and is not a column value, then all of these functions
+** return NULL. These routine might also return NULL if a memory
+** allocation error occurs. Otherwise, they return the
+** name of the attached database, table and column that query result
+** column was extracted 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().
+** As with all other SQLite APIs, those postfixed with "16" return
+** UTF-16 encoded strings, the other functions return UTF-8. {END}
**
** These APIs are only available if the library was compiled with the
** SQLITE_ENABLE_COLUMN_METADATA preprocessor symbol defined.
+**
+** {U13751}
+** If two or more threads call one or more of these routines against the same
+** prepared statement and column at the same time then the results are
+** undefined.
+**
+** INVARIANTS:
+**
+** {F13741} The [sqlite3_column_database_name(S,N)] interface returns either
+** the UTF-8 zero-terminated name of the database from which the
+** Nth result column of [prepared statement] S
+** is extracted, or NULL if the the Nth column of S is a
+** general expression or if unable to allocate memory
+** to store the name.
+**
+** {F13742} The [sqlite3_column_database_name16(S,N)] interface returns either
+** the UTF-16 native byte order
+** zero-terminated name of the database from which the
+** Nth result column of [prepared statement] S
+** is extracted, or NULL if the the Nth column of S is a
+** general expression or if unable to allocate memory
+** to store the name.
+**
+** {F13743} The [sqlite3_column_table_name(S,N)] interface returns either
+** the UTF-8 zero-terminated name of the table from which the
+** Nth result column of [prepared statement] S
+** is extracted, or NULL if the the Nth column of S is a
+** general expression or if unable to allocate memory
+** to store the name.
+**
+** {F13744} The [sqlite3_column_table_name16(S,N)] interface returns either
+** the UTF-16 native byte order
+** zero-terminated name of the table from which the
+** Nth result column of [prepared statement] S
+** is extracted, or NULL if the the Nth column of S is a
+** general expression or if unable to allocate memory
+** to store the name.
+**
+** {F13745} The [sqlite3_column_origin_name(S,N)] interface returns either
+** the UTF-8 zero-terminated name of the table column from which the
+** Nth result column of [prepared statement] S
+** is extracted, or NULL if the the Nth column of S is a
+** general expression or if unable to allocate memory
+** to store the name.
+**
+** {F13746} The [sqlite3_column_origin_name16(S,N)] interface returns either
+** the UTF-16 native byte order
+** zero-terminated name of the table column from which the
+** Nth result column of [prepared statement] S
+** is extracted, or NULL if the the Nth column of S is a
+** general expression or if unable to allocate memory
+** to store the name.
+**
+** {F13748} The return values from
+** [sqlite3_column_database_name|column metadata interfaces]
+** are valid
+** for the lifetime of the [prepared statement]
+** or until the encoding is changed by another metadata
+** interface call for the same prepared statement and column.
+**
+** LIMITATIONS:
+**
+** {U13751} If two or more threads call one or more
+** [sqlite3_column_database_name|column metadata interfaces]
+** the same [prepared statement] and result column
+** at the same time then the results are undefined.
*/
const char *sqlite3_column_database_name(sqlite3_stmt*,int);
const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
@@ -764,12 +2760,16 @@ 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
-** column is returned. If the Nth column of the result set is not at table
-** column, then a NULL pointer is returned. The returned string is always
-** UTF-8 encoded. For example, in the database schema:
+** CAPI3REF: Declared Datatype Of A Query Result {F13760}
+**
+** The first parameter is a [prepared statement].
+** If this statement is a SELECT statement and the Nth column of the
+** returned result set of that SELECT is a table column (not an
+** expression or subquery) then the declared type of the table
+** column is returned. If the Nth column of the result set is an
+** expression or subquery, then a NULL pointer is returned.
+** The returned string is always UTF-8 encoded. {END}
+** For example, in the database schema:
**
** CREATE TABLE t1(c1 VARIANT);
**
@@ -780,89 +2780,184 @@ const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
** Then this routine would return the string "VARIANT" for the second
** result column (i==1), and a NULL pointer for the first result column
** (i==0).
-*/
-const char *sqlite3_column_decltype(sqlite3_stmt *, int i);
-
-/*
-** 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
-** column is returned. If the Nth column of the result set is not at table
-** column, then a NULL pointer is returned. The returned string is always
-** UTF-16 encoded. For example, in the database schema:
-**
-** CREATE TABLE t1(c1 INTEGER);
-**
-** And the following statement compiled:
**
-** 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
-** (i==0).
+** SQLite uses dynamic run-time typing. So just because a column
+** is declared to contain a particular type does not mean that the
+** data stored in that column is of the declared type. SQLite is
+** strongly typed, but the typing is dynamic not static. Type
+** is associated with individual values, not with the containers
+** used to hold those values.
+**
+** INVARIANTS:
+**
+** {F13761} A successful call to [sqlite3_column_decltype(S,N)]
+** returns a zero-terminated UTF-8 string containing the
+** the declared datatype of the table column that appears
+** as the Nth column (numbered from 0) of the result set to the
+** [prepared statement] S.
+**
+** {F13762} A successful call to [sqlite3_column_decltype16(S,N)]
+** returns a zero-terminated UTF-16 native byte order string
+** containing the declared datatype of the table column that appears
+** as the Nth column (numbered from 0) of the result set to the
+** [prepared statement] S.
+**
+** {F13763} If N is less than 0 or N is greater than or equal to
+** the number of columns in [prepared statement] S
+** or if the Nth column of S is an expression or subquery rather
+** than a table column or if a memory allocation failure
+** occurs during encoding conversions, then
+** calls to [sqlite3_column_decltype(S,N)] or
+** [sqlite3_column_decltype16(S,N)] return NULL.
*/
+const char *sqlite3_column_decltype(sqlite3_stmt*,int);
const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
/*
-** After an SQL query has been compiled with a call to either
-** sqlite3_prepare() or sqlite3_prepare16(), then this function must be
-** called one or more times to execute the statement.
-**
-** The return value will be either SQLITE_BUSY, SQLITE_DONE,
-** SQLITE_ROW, SQLITE_ERROR, or SQLITE_MISUSE.
-**
-** SQLITE_BUSY means that the database engine attempted to open
-** a locked database and there is no busy callback registered.
-** Call sqlite3_step() again to retry the open.
-**
-** SQLITE_DONE means that the statement has finished executing
+** CAPI3REF: Evaluate An SQL Statement {F13200}
+**
+** After an [prepared statement] has been prepared with a call
+** to either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or to one of
+** the legacy interfaces [sqlite3_prepare()] or [sqlite3_prepare16()],
+** then this function must be called one or more times to evaluate the
+** statement.
+**
+** The details of the behavior of this sqlite3_step() interface depend
+** on whether the statement was prepared using the newer "v2" interface
+** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy
+** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the
+** new "v2" interface is recommended for new applications but the legacy
+** interface will continue to be supported.
+**
+** In the lagacy interface, the return value will be either [SQLITE_BUSY],
+** [SQLITE_DONE], [SQLITE_ROW], [SQLITE_ERROR], or [SQLITE_MISUSE].
+** With the "v2" interface, any of the other [SQLITE_OK | result code]
+** or [SQLITE_IOERR_READ | extended result code] might be returned as
+** well.
+**
+** [SQLITE_BUSY] means that the database engine was unable to acquire the
+** database locks it needs to do its job. If the statement is a COMMIT
+** or occurs outside of an explicit transaction, then you can retry the
+** statement. If the statement is not a COMMIT and occurs within a
+** explicit transaction then you should rollback the transaction before
+** continuing.
+**
+** [SQLITE_DONE] means that the statement has finished executing
** successfully. sqlite3_step() should not be called again on this virtual
-** machine.
+** machine without first calling [sqlite3_reset()] to reset the virtual
+** machine back to its initial state.
**
** If the SQL statement being executed returns any data, then
-** SQLITE_ROW is returned each time a new row of data is ready
+** [SQLITE_ROW] is returned each time a new row of data is ready
** for processing by the caller. The values may be accessed using
-** the sqlite3_column_*() functions described below. sqlite3_step()
-** is called again to retrieve the next row of data.
+** the [sqlite3_column_int | column access functions].
+** sqlite3_step() is called again to retrieve the next row of data.
**
-** SQLITE_ERROR means that a run-time error (such as a constraint
+** [SQLITE_ERROR] means that a run-time error (such as a constraint
** violation) has occurred. sqlite3_step() should not be called again on
-** the VM. More information may be found by calling sqlite3_errmsg().
-**
-** SQLITE_MISUSE means that the this routine was called inappropriately.
-** Perhaps it was called on a virtual machine that had already been
-** finalized or on one that had previously returned SQLITE_ERROR or
-** SQLITE_DONE. Or it could be the case the the same database connection
-** is being used simulataneously by two or more threads.
+** the VM. More information may be found by calling [sqlite3_errmsg()].
+** With the legacy interface, a more specific error code (example:
+** [SQLITE_INTERRUPT], [SQLITE_SCHEMA], [SQLITE_CORRUPT], and so forth)
+** can be obtained by calling [sqlite3_reset()] on the
+** [prepared statement]. In the "v2" interface,
+** the more specific error code is returned directly by sqlite3_step().
+**
+** [SQLITE_MISUSE] means that the this routine was called inappropriately.
+** Perhaps it was called on a [prepared statement] that has
+** already been [sqlite3_finalize | finalized] or on one that had
+** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could
+** be the case that the same database connection is being used by two or
+** more threads at the same moment in time.
+**
+** <b>Goofy Interface Alert:</b>
+** In the legacy interface,
+** the sqlite3_step() API always returns a generic error code,
+** [SQLITE_ERROR], following any error other than [SQLITE_BUSY]
+** and [SQLITE_MISUSE]. You must call [sqlite3_reset()] or
+** [sqlite3_finalize()] in order to find one of the specific
+** [error codes] that better describes the error.
+** We admit that this is a goofy design. The problem has been fixed
+** with the "v2" interface. If you prepare all of your SQL statements
+** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead
+** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()], then the
+** more specific [error codes] are returned directly
+** by sqlite3_step(). The use of the "v2" interface is recommended.
+**
+** INVARIANTS:
+**
+** {F13202} If [prepared statement] S is ready to be
+** run, then [sqlite3_step(S)] advances that prepared statement
+** until to completion or until it is ready to return another
+** row of the result set or an interrupt or run-time error occurs.
+**
+** {F15304} When a call to [sqlite3_step(S)] causes the
+** [prepared statement] S to run to completion,
+** the function returns [SQLITE_DONE].
+**
+** {F15306} When a call to [sqlite3_step(S)] stops because it is ready
+** to return another row of the result set, it returns
+** [SQLITE_ROW].
+**
+** {F15308} If a call to [sqlite3_step(S)] encounters an
+** [sqlite3_interrupt|interrupt] or a run-time error,
+** it returns an appropraite error code that is not one of
+** [SQLITE_OK], [SQLITE_ROW], or [SQLITE_DONE].
+**
+** {F15310} If an [sqlite3_interrupt|interrupt] or run-time error
+** occurs during a call to [sqlite3_step(S)]
+** for a [prepared statement] S created using
+** legacy interfaces [sqlite3_prepare()] or
+** [sqlite3_prepare16()] then the function returns either
+** [SQLITE_ERROR], [SQLITE_BUSY], or [SQLITE_MISUSE].
*/
int sqlite3_step(sqlite3_stmt*);
/*
+** CAPI3REF: Number of columns in a result set {F13770}
+**
** Return the number of values in the current row of the result set.
**
-** After a call to sqlite3_step() that returns SQLITE_ROW, this routine
-** will return the same value as the sqlite3_column_count() function.
-** After sqlite3_step() has returned an SQLITE_DONE, SQLITE_BUSY or
-** error code, or before sqlite3_step() has been called on a
-** compiled SQL statement, this routine returns zero.
+** INVARIANTS:
+**
+** {F13771} After a call to [sqlite3_step(S)] that returns
+** [SQLITE_ROW], the [sqlite3_data_count(S)] routine
+** will return the same value as the
+** [sqlite3_column_count(S)] function.
+**
+** {F13772} After [sqlite3_step(S)] has returned any value other than
+** [SQLITE_ROW] or before [sqlite3_step(S)] has been
+** called on the [prepared statement] for
+** the first time since it was [sqlite3_prepare|prepared]
+** or [sqlite3_reset|reset], the [sqlite3_data_count(S)]
+** routine returns zero.
*/
int sqlite3_data_count(sqlite3_stmt *pStmt);
/*
-** Values are stored in the database in one of the following fundamental
-** types.
+** CAPI3REF: Fundamental Datatypes {F10265}
+** KEYWORDS: SQLITE_TEXT
+**
+** {F10266}Every value in SQLite has one of five fundamental datatypes:
+**
+** <ul>
+** <li> 64-bit signed integer
+** <li> 64-bit IEEE floating point number
+** <li> string
+** <li> BLOB
+** <li> NULL
+** </ul> {END}
+**
+** These constants are codes for each of those types.
+**
+** Note that the SQLITE_TEXT constant was also used in SQLite version 2
+** for a completely different meaning. Software that links against both
+** SQLite version 2 and SQLite version 3 should use SQLITE3_TEXT not
+** SQLITE_TEXT.
*/
#define SQLITE_INTEGER 1
#define SQLITE_FLOAT 2
-/* #define SQLITE_TEXT 3 // See below */
#define SQLITE_BLOB 4
#define SQLITE_NULL 5
-
-/*
-** SQLite version 2 defines SQLITE_TEXT differently. To allow both
-** version 2 and version 3 to be included, undefine them both if a
-** conflict is seen. Define SQLITE3_TEXT to be the version 3 value.
-*/
#ifdef SQLITE_TEXT
# undef SQLITE_TEXT
#else
@@ -871,175 +2966,447 @@ int sqlite3_data_count(sqlite3_stmt *pStmt);
#define SQLITE3_TEXT 3
/*
-** The next group of routines returns information about the information
-** in a single column of the current result row of a query. In every
-** case the first parameter is a pointer to the SQL statement that is being
-** executed (the sqlite_stmt* that was returned from sqlite3_prepare()) and
+** CAPI3REF: Results Values From A Query {F13800}
+**
+** These routines form the "result set query" interface.
+**
+** These routines return information about
+** a single column of the current result row of a query. In every
+** case the first argument is a pointer to the
+** [prepared statement] that is being
+** evaluated (the [sqlite3_stmt*] that was returned from
+** [sqlite3_prepare_v2()] or one of its variants) and
** the second argument is the index of the column for which information
-** should be returned. iCol is zero-indexed. The left-most column as an
-** index of 0.
+** should be returned. The left-most column of the result set
+** has an index of 0.
**
** If the SQL statement is not currently point to a valid row, or if the
-** the colulmn index is out of range, the result is undefined.
+** the column index is out of range, the result is undefined.
+** These routines may only be called when the most recent call to
+** [sqlite3_step()] has returned [SQLITE_ROW] and neither
+** [sqlite3_reset()] nor [sqlite3_finalize()] has been call subsequently.
+** If any of these routines are called after [sqlite3_reset()] or
+** [sqlite3_finalize()] or after [sqlite3_step()] has returned
+** something other than [SQLITE_ROW], the results are undefined.
+** If [sqlite3_step()] or [sqlite3_reset()] or [sqlite3_finalize()]
+** are called from a different thread while any of these routines
+** are pending, then the results are undefined.
+**
+** The sqlite3_column_type() routine returns
+** [SQLITE_INTEGER | datatype code] for the initial data type
+** of the result column. The returned value is one of [SQLITE_INTEGER],
+** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value
+** returned by sqlite3_column_type() is only meaningful if no type
+** conversions have occurred as described below. After a type conversion,
+** the value returned by sqlite3_column_type() is undefined. Future
+** versions of SQLite may change the behavior of sqlite3_column_type()
+** following a type conversion.
+**
+** If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes()
+** routine returns the number of bytes in that BLOB or string.
+** If the result is a UTF-16 string, then sqlite3_column_bytes() converts
+** the string to UTF-8 and then returns the number of bytes.
+** If the result is a numeric value then sqlite3_column_bytes() uses
+** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns
+** the number of bytes in that string.
+** The value returned does not include the zero terminator at the end
+** of the string. For clarity: the value returned is the number of
+** bytes in the string, not the number of characters.
+**
+** Strings returned by sqlite3_column_text() and sqlite3_column_text16(),
+** even empty strings, are always zero terminated. The return
+** value from sqlite3_column_blob() for a zero-length blob is an arbitrary
+** pointer, possibly even a NULL pointer.
+**
+** The sqlite3_column_bytes16() routine is similar to sqlite3_column_bytes()
+** but leaves the result in UTF-16 in native byte order instead of UTF-8.
+** The zero terminator is not included in this count.
**
** These routines attempt to convert the value where appropriate. For
** example, if the internal representation is FLOAT and a text result
-** is requested, sprintf() is used internally to do the conversion
+** is requested, [sqlite3_snprintf()] is used internally to do the conversion
** automatically. The following table details the conversions that
** are applied:
**
-** Internal Type Requested Type Conversion
-** ------------- -------------- --------------------------
-** NULL INTEGER Result is 0
-** NULL FLOAT Result is 0.0
-** NULL TEXT Result is an empty string
-** NULL BLOB Result is a zero-length BLOB
-** INTEGER FLOAT Convert from integer to float
-** INTEGER TEXT ASCII rendering of the integer
-** INTEGER BLOB Same as for INTEGER->TEXT
-** FLOAT INTEGER Convert from float to integer
-** FLOAT TEXT ASCII rendering of the float
-** FLOAT BLOB Same as FLOAT->TEXT
-** TEXT INTEGER Use atoi()
-** TEXT FLOAT Use atof()
-** TEXT BLOB No change
-** BLOB INTEGER Convert to TEXT then use atoi()
-** BLOB FLOAT Convert to TEXT then use atof()
-** BLOB TEXT Add a \000 terminator if needed
-**
-** The following access routines are provided:
-**
-** _type() Return the datatype of the result. This is one of
-** SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB,
-** or SQLITE_NULL.
-** _blob() Return the value of a BLOB.
-** _bytes() Return the number of bytes in a BLOB value or the number
-** of bytes in a TEXT value represented as UTF-8. The \000
-** terminator is included in the byte count for TEXT values.
-** _bytes16() Return the number of bytes in a BLOB value or the number
-** of bytes in a TEXT value represented as UTF-16. The \u0000
-** terminator is included in the byte count for TEXT values.
-** _double() Return a FLOAT value.
-** _int() Return an INTEGER value in the host computer's native
-** integer representation. This might be either a 32- or 64-bit
-** integer depending on the host.
-** _int64() Return an INTEGER value as a 64-bit signed integer.
-** _text() Return the value as UTF-8 text.
-** _text16() Return the value as UTF-16 text.
+** <blockquote>
+** <table border="1">
+** <tr><th> Internal<br>Type <th> Requested<br>Type <th> Conversion
+**
+** <tr><td> NULL <td> INTEGER <td> Result is 0
+** <tr><td> NULL <td> FLOAT <td> Result is 0.0
+** <tr><td> NULL <td> TEXT <td> Result is NULL pointer
+** <tr><td> NULL <td> BLOB <td> Result is NULL pointer
+** <tr><td> INTEGER <td> FLOAT <td> Convert from integer to float
+** <tr><td> INTEGER <td> TEXT <td> ASCII rendering of the integer
+** <tr><td> INTEGER <td> BLOB <td> Same as for INTEGER->TEXT
+** <tr><td> FLOAT <td> INTEGER <td> Convert from float to integer
+** <tr><td> FLOAT <td> TEXT <td> ASCII rendering of the float
+** <tr><td> FLOAT <td> BLOB <td> Same as FLOAT->TEXT
+** <tr><td> TEXT <td> INTEGER <td> Use atoi()
+** <tr><td> TEXT <td> FLOAT <td> Use atof()
+** <tr><td> TEXT <td> BLOB <td> No change
+** <tr><td> BLOB <td> INTEGER <td> Convert to TEXT then use atoi()
+** <tr><td> BLOB <td> FLOAT <td> Convert to TEXT then use atof()
+** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed
+** </table>
+** </blockquote>
+**
+** The table above makes reference to standard C library functions atoi()
+** and atof(). SQLite does not really use these functions. It has its
+** on equavalent internal routines. The atoi() and atof() names are
+** used in the table for brevity and because they are familiar to most
+** C programmers.
+**
+** Note that when type conversions occur, pointers returned by prior
+** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or
+** sqlite3_column_text16() may be invalidated.
+** Type conversions and pointer invalidations might occur
+** in the following cases:
+**
+** <ul>
+** <li><p> The initial content is a BLOB and sqlite3_column_text()
+** or sqlite3_column_text16() is called. A zero-terminator might
+** need to be added to the string.</p></li>
+**
+** <li><p> The initial content is UTF-8 text and sqlite3_column_bytes16() or
+** sqlite3_column_text16() is called. The content must be converted
+** to UTF-16.</p></li>
+**
+** <li><p> The initial content is UTF-16 text and sqlite3_column_bytes() or
+** sqlite3_column_text() is called. The content must be converted
+** to UTF-8.</p></li>
+** </ul>
+**
+** Conversions between UTF-16be and UTF-16le are always done in place and do
+** not invalidate a prior pointer, though of course the content of the buffer
+** that the prior pointer points to will have been modified. Other kinds
+** of conversion are done in place when it is possible, but sometime it is
+** not possible and in those cases prior pointers are invalidated.
+**
+** The safest and easiest to remember policy is to invoke these routines
+** in one of the following ways:
+**
+** <ul>
+** <li>sqlite3_column_text() followed by sqlite3_column_bytes()</li>
+** <li>sqlite3_column_blob() followed by sqlite3_column_bytes()</li>
+** <li>sqlite3_column_text16() followed by sqlite3_column_bytes16()</li>
+** </ul>
+**
+** In other words, you should call sqlite3_column_text(), sqlite3_column_blob(),
+** or sqlite3_column_text16() first to force the result into the desired
+** format, then invoke sqlite3_column_bytes() or sqlite3_column_bytes16() to
+** find the size of the result. Do not mix call to sqlite3_column_text() or
+** sqlite3_column_blob() with calls to sqlite3_column_bytes16(). And do not
+** mix calls to sqlite3_column_text16() with calls to sqlite3_column_bytes().
+**
+** The pointers returned are valid until a type conversion occurs as
+** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
+** [sqlite3_finalize()] is called. The memory space used to hold strings
+** and blobs is freed automatically. Do <b>not</b> pass the pointers returned
+** [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
+** [sqlite3_free()].
+**
+** If a memory allocation error occurs during the evaluation of any
+** of these routines, a default value is returned. The default value
+** is either the integer 0, the floating point number 0.0, or a NULL
+** pointer. Subsequent calls to [sqlite3_errcode()] will return
+** [SQLITE_NOMEM].
+**
+** INVARIANTS:
+**
+** {F13803} The [sqlite3_column_blob(S,N)] interface converts the
+** Nth column in the current row of the result set for
+** [prepared statement] S into a blob and then returns a
+** pointer to the converted value.
+**
+** {F13806} The [sqlite3_column_bytes(S,N)] interface returns the
+** number of bytes in the blob or string (exclusive of the
+** zero terminator on the string) that was returned by the
+** most recent call to [sqlite3_column_blob(S,N)] or
+** [sqlite3_column_text(S,N)].
+**
+** {F13809} The [sqlite3_column_bytes16(S,N)] interface returns the
+** number of bytes in the string (exclusive of the
+** zero terminator on the string) that was returned by the
+** most recent call to [sqlite3_column_text16(S,N)].
+**
+** {F13812} The [sqlite3_column_double(S,N)] interface converts the
+** Nth column in the current row of the result set for
+** [prepared statement] S into a floating point value and
+** returns a copy of that value.
+**
+** {F13815} The [sqlite3_column_int(S,N)] interface converts the
+** Nth column in the current row of the result set for
+** [prepared statement] S into a 32-bit signed integer and
+** returns a copy of that integer.
+**
+** {F13818} The [sqlite3_column_int64(S,N)] interface converts the
+** Nth column in the current row of the result set for
+** [prepared statement] S into a 64-bit signed integer and
+** returns a copy of that integer.
+**
+** {F13821} The [sqlite3_column_text(S,N)] interface converts the
+** Nth column in the current row of the result set for
+** [prepared statement] S into a zero-terminated UTF-8
+** string and returns a pointer to that string.
+**
+** {F13824} The [sqlite3_column_text16(S,N)] interface converts the
+** Nth column in the current row of the result set for
+** [prepared statement] S into a zero-terminated 2-byte
+** aligned UTF-16 native byte order
+** string and returns a pointer to that string.
+**
+** {F13827} The [sqlite3_column_type(S,N)] interface returns
+** one of [SQLITE_NULL], [SQLITE_INTEGER], [SQLITE_FLOAT],
+** [SQLITE_TEXT], or [SQLITE_BLOB] as appropriate for
+** the Nth column in the current row of the result set for
+** [prepared statement] S.
+**
+** {F13830} The [sqlite3_column_value(S,N)] interface returns a
+** pointer to the [sqlite3_value] object that for the
+** Nth column in the current row of the result set for
+** [prepared statement] S.
*/
const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
double sqlite3_column_double(sqlite3_stmt*, int iCol);
int sqlite3_column_int(sqlite3_stmt*, int iCol);
-sqlite_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
+sqlite3_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
-** SQL statement obtained by a previous call to sqlite3_prepare()
-** or sqlite3_prepare16(). If the statement was executed successfully, or
-** not executed at all, then SQLITE_OK is returned. If execution of the
-** statement failed then an error code is returned.
+** CAPI3REF: Destroy A Prepared Statement Object {F13300}
+**
+** The sqlite3_finalize() function is called to delete a
+** [prepared statement]. If the statement was
+** executed successfully, or not executed at all, then SQLITE_OK is returned.
+** If execution of the statement failed then an
+** [error code] or [extended error code]
+** is returned.
**
** This routine can be called at any point during the execution of the
-** virtual machine. If the virtual machine has not completed execution
-** when this routine is called, that is like encountering an error or
-** an interrupt. (See sqlite3_interrupt().) Incomplete updates may be
-** rolled back and transactions cancelled, depending on the circumstances,
-** and the result code returned will be SQLITE_ABORT.
+** [prepared statement]. If the virtual machine has not
+** completed execution when this routine is called, that is like
+** encountering an error or an interrupt. (See [sqlite3_interrupt()].)
+** Incomplete updates may be rolled back and transactions cancelled,
+** depending on the circumstances, and the
+** [error code] returned will be [SQLITE_ABORT].
+**
+** INVARIANTS:
+**
+** {F11302} The [sqlite3_finalize(S)] interface destroys the
+** [prepared statement] S and releases all
+** memory and file resources held by that object.
+**
+** {F11304} If the most recent call to [sqlite3_step(S)] for the
+** [prepared statement] S returned an error,
+** then [sqlite3_finalize(S)] returns that same error.
*/
int sqlite3_finalize(sqlite3_stmt *pStmt);
/*
-** The sqlite3_reset() function is called to reset a compiled SQL
-** statement obtained by a previous call to sqlite3_prepare() or
-** sqlite3_prepare16() back to it's initial state, ready to be re-executed.
+** CAPI3REF: Reset A Prepared Statement Object {F13330}
+**
+** The sqlite3_reset() function is called to reset a
+** [prepared statement] object.
+** back to its initial state, ready to be re-executed.
** Any SQL statement variables that had values bound to them using
-** the sqlite3_bind_*() API retain their values.
+** the [sqlite3_bind_blob | sqlite3_bind_*() API] retain their values.
+** Use [sqlite3_clear_bindings()] to reset the bindings.
+**
+** {F11332} The [sqlite3_reset(S)] interface resets the [prepared statement] S
+** back to the beginning of its program.
+**
+** {F11334} If the most recent call to [sqlite3_step(S)] for
+** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE],
+** or if [sqlite3_step(S)] has never before been called on S,
+** then [sqlite3_reset(S)] returns [SQLITE_OK].
+**
+** {F11336} If the most recent call to [sqlite3_step(S)] for
+** [prepared statement] S indicated an error, then
+** [sqlite3_reset(S)] returns an appropriate [error code].
+**
+** {F11338} The [sqlite3_reset(S)] interface does not change the values
+** of any [sqlite3_bind_blob|bindings] on [prepared statement] S.
*/
int sqlite3_reset(sqlite3_stmt *pStmt);
/*
-** The following two functions are used to add user functions or aggregates
-** implemented in C to the SQL langauge interpreted by SQLite. The
+** CAPI3REF: Create Or Redefine SQL Functions {F16100}
+** KEYWORDS: {function creation routines}
+**
+** These two functions (collectively known as
+** "function creation routines") are used to add SQL functions or aggregates
+** or to redefine the behavior of existing SQL functions or aggregates. The
** difference only between the two is that the second parameter, the
** name of the (scalar) function or aggregate, is encoded in UTF-8 for
** sqlite3_create_function() and UTF-16 for sqlite3_create_function16().
**
-** The first argument is the database handle that the new function or
-** aggregate is to be added to. If a single program uses more than one
-** database handle internally, then user functions or aggregates must
-** be added individually to each database handle with which they will be
-** used.
-**
-** The third parameter is the number of arguments that the function or
-** aggregate takes. If this parameter is negative, then the function or
+** The first argument is the [database connection] that holds the
+** SQL function or aggregate is to be added or redefined. If a single
+** program uses more than one database handle internally, then SQL
+** functions or aggregates must be added individually to each database
+** handle with which they will be used.
+**
+** The second parameter is the name of the SQL function to be created
+** or redefined.
+** The length of the name is limited to 255 bytes, exclusive of the
+** zero-terminator. Note that the name length limit is in bytes, not
+** characters. Any attempt to create a function with a longer name
+** will result in an SQLITE_ERROR error.
+**
+** The third parameter is the number of arguments that the SQL function or
+** aggregate takes. If this parameter is negative, then the SQL function or
** aggregate may take any number of arguments.
**
-** The fourth parameter is one of SQLITE_UTF* values defined below,
-** indicating the encoding that the function is most likely to handle
-** values in. This does not change the behaviour of the programming
-** interface. However, if two versions of the same function are registered
-** with different encoding values, SQLite invokes the version likely to
-** minimize conversions between text encodings.
+** The fourth parameter, eTextRep, specifies what
+** [SQLITE_UTF8 | text encoding] this SQL function prefers for
+** its parameters. Any SQL function implementation should be able to work
+** work with UTF-8, UTF-16le, or UTF-16be. But some implementations may be
+** more efficient with one encoding than another. It is allowed to
+** invoke sqlite3_create_function() or sqlite3_create_function16() multiple
+** times with the same function but with different values of eTextRep.
+** When multiple implementations of the same function are available, SQLite
+** will pick the one that involves the least amount of data conversion.
+** If there is only a single implementation which does not care what
+** text encoding is used, then the fourth argument should be
+** [SQLITE_ANY].
+**
+** The fifth parameter is an arbitrary pointer. The implementation
+** of the function can gain access to this pointer using
+** [sqlite3_user_data()].
**
** The seventh, eighth and ninth parameters, xFunc, xStep and xFinal, are
-** pointers to user implemented C functions that implement the user
-** function or aggregate. A scalar function requires an implementation of
+** pointers to C-language functions that implement the SQL
+** function or aggregate. A scalar SQL function requires an implementation of
** the xFunc callback only, NULL pointers should be passed as the xStep
-** and xFinal parameters. An aggregate function requires an implementation
-** of xStep and xFinal, but NULL should be passed for xFunc. To delete an
-** existing user function or aggregate, pass NULL for all three function
-** callback. Specifying an inconstent set of callback values, such as an
-** xFunc and an xFinal, or an xStep but no xFinal, SQLITE_ERROR is
-** returned.
+** and xFinal parameters. An aggregate SQL function requires an implementation
+** of xStep and xFinal and NULL should be passed for xFunc. To delete an
+** existing SQL function or aggregate, pass NULL for all three function
+** callback.
+**
+** It is permitted to register multiple implementations of the same
+** functions with the same name but with either differing numbers of
+** arguments or differing perferred text encodings. SQLite will use
+** the implementation most closely matches the way in which the
+** SQL function is used.
+**
+** INVARIANTS:
+**
+** {F16103} The [sqlite3_create_function16()] interface behaves exactly
+** like [sqlite3_create_function()] in every way except that it
+** interprets the zFunctionName argument as
+** zero-terminated UTF-16 native byte order instead of as a
+** zero-terminated UTF-8.
+**
+** {F16106}
*/
int sqlite3_create_function(
- sqlite3 *,
+ sqlite3 *db,
const char *zFunctionName,
int nArg,
int eTextRep,
- void*,
+ void *pApp,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
int sqlite3_create_function16(
- sqlite3*,
+ sqlite3 *db,
const void *zFunctionName,
int nArg,
int eTextRep,
- void*,
+ void *pApp,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
/*
-** 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.
+** CAPI3REF: Text Encodings {F10267}
+**
+** These constant define integer codes that represent the various
+** text encodings supported by SQLite.
+*/
+#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 */
+
+/*
+** CAPI3REF: Obsolete Functions
+**
+** These functions are all now obsolete. In order to maintain
+** backwards compatibility with older code, we continue to support
+** these functions. However, new development projects should avoid
+** the use of these functions. To help encourage people to avoid
+** using these functions, we are not going to tell you want they do.
*/
int sqlite3_aggregate_count(sqlite3_context*);
+int sqlite3_expired(sqlite3_stmt*);
+int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
+int sqlite3_global_recover(void);
+void sqlite3_thread_cleanup(void);
+int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),void*,sqlite3_int64);
/*
-** The next group of routines returns information about parameters to
-** a user-defined function. Function implementations use these routines
-** to access their parameters. These routines are the same as the
-** sqlite3_column_* routines except that these routines take a single
-** sqlite3_value* pointer instead of an sqlite3_stmt* and an integer
-** column number.
+** CAPI3REF: Obtaining SQL Function Parameter Values {F15100}
+**
+** The C-language implementation of SQL functions and aggregates uses
+** this set of interface routines to access the parameter values on
+** the function or aggregate.
+**
+** The xFunc (for scalar functions) or xStep (for aggregates) parameters
+** to [sqlite3_create_function()] and [sqlite3_create_function16()]
+** define callbacks that implement the SQL functions and aggregates.
+** The 4th parameter to these callbacks is an array of pointers to
+** [sqlite3_value] objects. There is one [sqlite3_value] object for
+** each parameter to the SQL function. These routines are used to
+** extract values from the [sqlite3_value] objects.
+**
+** These routines work just like the corresponding
+** [sqlite3_column_blob | sqlite3_column_* routines] except that
+** these routines take a single [sqlite3_value*] pointer instead
+** of an [sqlite3_stmt*] pointer and an integer column number.
+**
+** The sqlite3_value_text16() interface extracts a UTF16 string
+** in the native byte-order of the host machine. The
+** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces
+** extract UTF16 strings as big-endian and little-endian respectively.
+**
+** The sqlite3_value_numeric_type() interface attempts to apply
+** numeric affinity to the value. This means that an attempt is
+** made to convert the value to an integer or floating point. If
+** such a conversion is possible without loss of information (in other
+** words if the value is a string that looks like a number)
+** then the conversion is done. Otherwise no conversion occurs. The
+** [SQLITE_INTEGER | datatype] after conversion is returned.
+**
+** Please pay particular attention to the fact that the pointer that
+** is returned from [sqlite3_value_blob()], [sqlite3_value_text()], or
+** [sqlite3_value_text16()] can be invalidated by a subsequent call to
+** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()],
+** or [sqlite3_value_text16()].
+**
+** These routines must be called from the same thread as
+** the SQL function that supplied the sqlite3_value* parameters.
+** Or, if the sqlite3_value* argument comes from the [sqlite3_column_value()]
+** interface, then these routines should be called from the same thread
+** that ran [sqlite3_column_value()].
+**
*/
const void *sqlite3_value_blob(sqlite3_value*);
int sqlite3_value_bytes(sqlite3_value*);
int sqlite3_value_bytes16(sqlite3_value*);
double sqlite3_value_double(sqlite3_value*);
int sqlite3_value_int(sqlite3_value*);
-sqlite_int64 sqlite3_value_int64(sqlite3_value*);
+sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
const unsigned char *sqlite3_value_text(sqlite3_value*);
const void *sqlite3_value_text16(sqlite3_value*);
const void *sqlite3_value_text16le(sqlite3_value*);
@@ -1048,121 +3415,276 @@ int sqlite3_value_type(sqlite3_value*);
int sqlite3_value_numeric_type(sqlite3_value*);
/*
-** Aggregate functions use the following routine to allocate
-** a structure for storing their state. The first time this routine
-** is called for a particular aggregate, a new structure of size nBytes
-** is allocated, zeroed, and returned. On subsequent calls (for the
-** same aggregate instance) the same buffer is returned. The implementation
+** CAPI3REF: Obtain Aggregate Function Context {F16210}
+**
+** The implementation of aggregate SQL functions use this routine to allocate
+** a structure for storing their state.
+** {F16211} The first time the sqlite3_aggregate_context() routine is
+** is called for a particular aggregate, SQLite allocates nBytes of memory
+** zeros that memory, and returns a pointer to it.
+** {F16212} On second and subsequent calls to sqlite3_aggregate_context()
+** for the same aggregate function index, the same buffer is returned. {END}
+** The implementation
** of the aggregate can use the returned buffer to accumulate data.
**
-** The buffer allocated is freed automatically by SQLite.
+** {F16213} SQLite automatically frees the allocated buffer when the aggregate
+** query concludes. {END}
+**
+** The first parameter should be a copy of the
+** [sqlite3_context | SQL function context] that is the first
+** parameter to the callback routine that implements the aggregate
+** function.
+**
+** This routine must be called from the same thread in which
+** the aggregate SQL function is running.
*/
void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
/*
-** The pUserData parameter to the sqlite3_create_function()
-** routine used to register user functions is available to
-** the implementation of the function using this call.
+** CAPI3REF: User Data For Functions {F16240}
+**
+** {F16241} The sqlite3_user_data() interface returns a copy of
+** the pointer that was the pUserData parameter (the 5th parameter)
+** of the the [sqlite3_create_function()]
+** and [sqlite3_create_function16()] routines that originally
+** registered the application defined function. {END}
+**
+** {U16243} This routine must be called from the same thread in which
+** the application-defined function is running.
*/
void *sqlite3_user_data(sqlite3_context*);
/*
-** The following two functions may be used by scalar user functions to
+** CAPI3REF: Function Auxiliary Data {F16270}
+**
+** The following two functions may be used by scalar SQL functions to
** associate meta-data with argument values. If the same value is passed to
-** multiple invocations of the user-function during query execution, under
+** multiple invocations of the same SQL function during query execution, under
** some circumstances the associated meta-data may be preserved. This may
** be used, for example, to add a regular-expression matching scalar
** function. The compiled version of the regular expression is stored as
** meta-data associated with the SQL value passed as the regular expression
-** pattern.
-**
-** Calling sqlite3_get_auxdata() returns a pointer to the meta data
-** associated with the Nth argument value to the current user function
-** call, where N is the second parameter. If no meta-data has been set for
-** that value, then a NULL pointer is returned.
-**
-** The sqlite3_set_auxdata() is used to associate meta data with a user
-** function argument. The third parameter is a pointer to the meta data
-** to be associated with the Nth user function argument value. The fourth
-** parameter specifies a 'delete function' that will be called on the meta
-** data pointer to release it when it is no longer required. If the delete
-** function pointer is NULL, it is not invoked.
+** pattern. The compiled regular expression can be reused on multiple
+** invocations of the same function so that the original pattern string
+** does not need to be recompiled on each invocation.
+**
+** {F16271}
+** The sqlite3_get_auxdata() interface returns a pointer to the meta-data
+** associated by the sqlite3_set_auxdata() function with the Nth argument
+** value to the application-defined function.
+** {F16272} If no meta-data has been ever been set for the Nth
+** argument of the function, or if the cooresponding function parameter
+** has changed since the meta-data was set, then sqlite3_get_auxdata()
+** returns a NULL pointer.
+**
+** {F16275} The sqlite3_set_auxdata() interface saves the meta-data
+** pointed to by its 3rd parameter as the meta-data for the N-th
+** argument of the application-defined function. {END} Subsequent
+** calls to sqlite3_get_auxdata() might return this data, if it has
+** not been destroyed.
+** {F16277} If it is not NULL, SQLite will invoke the destructor
+** function given by the 4th parameter to sqlite3_set_auxdata() on
+** the meta-data when the corresponding function parameter changes
+** or when the SQL statement completes, whichever comes first. {END}
**
** In practice, meta-data is preserved between function calls for
** expressions that are constant at compile time. This includes literal
** values and SQL variables.
+**
+** These routines must be called from the same thread in which
+** the SQL function is running.
*/
-void *sqlite3_get_auxdata(sqlite3_context*, int);
-void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*));
+void *sqlite3_get_auxdata(sqlite3_context*, int N);
+void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
/*
+** CAPI3REF: Constants Defining Special Destructor Behavior {F10280}
+**
** These are special value for the destructor that is passed in as the
-** final argument to routines like sqlite3_result_blob(). If the destructor
+** final argument to routines like [sqlite3_result_blob()]. If the destructor
** argument is SQLITE_STATIC, it means that the content pointer is constant
** and will never change. It does not need to be destroyed. The
** SQLITE_TRANSIENT value means that the content will likely change in
** the near future and that SQLite should make its own private copy of
** the content before returning.
+**
+** The typedef is necessary to work around problems in certain
+** C++ compilers. See ticket #2191.
*/
-#define SQLITE_STATIC ((void(*)(void *))0)
-#define SQLITE_TRANSIENT ((void(*)(void *))-1)
+typedef void (*sqlite3_destructor_type)(void*);
+#define SQLITE_STATIC ((sqlite3_destructor_type)0)
+#define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1)
/*
-** User-defined functions invoke the following routines in order to
-** set their return value.
+** CAPI3REF: Setting The Result Of An SQL Function {F16400}
+**
+** These routines are used by the xFunc or xFinal callbacks that
+** implement SQL functions and aggregates. See
+** [sqlite3_create_function()] and [sqlite3_create_function16()]
+** for additional information.
+**
+** These functions work very much like the
+** [sqlite3_bind_blob | sqlite3_bind_*] family of functions used
+** to bind values to host parameters in prepared statements.
+** Refer to the
+** [sqlite3_bind_blob | sqlite3_bind_* documentation] for
+** additional information.
+**
+** {F16402} The sqlite3_result_blob() interface sets the result from
+** an application defined function to be the BLOB whose content is pointed
+** to by the second parameter and which is N bytes long where N is the
+** third parameter.
+** {F16403} The sqlite3_result_zeroblob() inerfaces set the result of
+** the application defined function to be a BLOB containing all zero
+** bytes and N bytes in size, where N is the value of the 2nd parameter.
+**
+** {F16407} The sqlite3_result_double() interface sets the result from
+** an application defined function to be a floating point value specified
+** by its 2nd argument.
+**
+** {F16409} The sqlite3_result_error() and sqlite3_result_error16() functions
+** cause the implemented SQL function to throw an exception.
+** {F16411} SQLite uses the string pointed to by the
+** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16()
+** as the text of an error message. {F16412} SQLite interprets the error
+** message string from sqlite3_result_error() as UTF8. {F16413} SQLite
+** interprets the string from sqlite3_result_error16() as UTF16 in native
+** byte order. {F16414} If the third parameter to sqlite3_result_error()
+** or sqlite3_result_error16() is negative then SQLite takes as the error
+** message all text up through the first zero character.
+** {F16415} If the third parameter to sqlite3_result_error() or
+** sqlite3_result_error16() is non-negative then SQLite takes that many
+** bytes (not characters) from the 2nd parameter as the error message.
+** {F16417} The sqlite3_result_error() and sqlite3_result_error16()
+** routines make a copy private copy of the error message text before
+** they return. {END} Hence, the calling function can deallocate or
+** modify the text after they return without harm.
+** The sqlite3_result_error_code() function changes the error code
+** returned by SQLite as a result of an error in a function. By default,
+** the error code is SQLITE_ERROR.
+**
+** {F16421} The sqlite3_result_toobig() interface causes SQLite
+** to throw an error indicating that a string or BLOB is to long
+** to represent. {F16422} The sqlite3_result_nomem() interface
+** causes SQLite to throw an exception indicating that the a
+** memory allocation failed.
+**
+** {F16431} The sqlite3_result_int() interface sets the return value
+** of the application-defined function to be the 32-bit signed integer
+** value given in the 2nd argument.
+** {F16432} The sqlite3_result_int64() interface sets the return value
+** of the application-defined function to be the 64-bit signed integer
+** value given in the 2nd argument.
+**
+** {F16437} The sqlite3_result_null() interface sets the return value
+** of the application-defined function to be NULL.
+**
+** {F16441} The sqlite3_result_text(), sqlite3_result_text16(),
+** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces
+** set the return value of the application-defined function to be
+** a text string which is represented as UTF-8, UTF-16 native byte order,
+** UTF-16 little endian, or UTF-16 big endian, respectively.
+** {F16442} SQLite takes the text result from the application from
+** the 2nd parameter of the sqlite3_result_text* interfaces.
+** {F16444} If the 3rd parameter to the sqlite3_result_text* interfaces
+** is negative, then SQLite takes result text from the 2nd parameter
+** through the first zero character.
+** {F16447} If the 3rd parameter to the sqlite3_result_text* interfaces
+** is non-negative, then as many bytes (not characters) of the text
+** pointed to by the 2nd parameter are taken as the application-defined
+** function result.
+** {F16451} If the 4th parameter to the sqlite3_result_text* interfaces
+** or sqlite3_result_blob is a non-NULL pointer, then SQLite calls that
+** function as the destructor on the text or blob result when it has
+** finished using that result.
+** {F16453} If the 4th parameter to the sqlite3_result_text* interfaces
+** or sqlite3_result_blob is the special constant SQLITE_STATIC, then
+** SQLite assumes that the text or blob result is constant space and
+** does not copy the space or call a destructor when it has
+** finished using that result.
+** {F16454} If the 4th parameter to the sqlite3_result_text* interfaces
+** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT
+** then SQLite makes a copy of the result into space obtained from
+** from [sqlite3_malloc()] before it returns.
+**
+** {F16461} The sqlite3_result_value() interface sets the result of
+** the application-defined function to be a copy the [sqlite3_value]
+** object specified by the 2nd parameter. {F16463} The
+** sqlite3_result_value() interface makes a copy of the [sqlite3_value]
+** so that [sqlite3_value] specified in the parameter may change or
+** be deallocated after sqlite3_result_value() returns without harm.
+**
+** {U16491} These routines are called from within the different thread
+** than the one containing the application-defined function that recieved
+** the [sqlite3_context] pointer, the results are undefined.
*/
void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
void sqlite3_result_double(sqlite3_context*, double);
void sqlite3_result_error(sqlite3_context*, const char*, int);
void sqlite3_result_error16(sqlite3_context*, const void*, int);
+void sqlite3_result_error_toobig(sqlite3_context*);
+void sqlite3_result_error_nomem(sqlite3_context*);
+void sqlite3_result_error_code(sqlite3_context*, int);
void sqlite3_result_int(sqlite3_context*, int);
-void sqlite3_result_int64(sqlite3_context*, sqlite_int64);
+void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
void sqlite3_result_null(sqlite3_context*);
void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
+void sqlite3_result_zeroblob(sqlite3_context*, int n);
/*
-** 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_UTF16_ALIGNED 8 /* sqlite3_create_collation only */
-
-/*
-** These two functions are used to add new collation sequences to the
-** sqlite3 handle specified as the first argument.
+** CAPI3REF: Define New Collating Sequences {F16600}
**
+** {F16601}
+** These functions are used to add new collation sequences to the
+** [sqlite3*] handle specified as the first argument.
+**
+** {F16602}
** The name of the new collation sequence is specified as a UTF-8 string
-** for sqlite3_create_collation() and a UTF-16 string for
-** sqlite3_create_collation16(). In both cases the name is passed as the
-** second function argument.
+** for sqlite3_create_collation() and sqlite3_create_collation_v2()
+** and a UTF-16 string for sqlite3_create_collation16(). {F16603} In all cases
+** the name is passed as the second function argument.
**
-** The third argument must be one of the constants SQLITE_UTF8,
-** SQLITE_UTF16LE or SQLITE_UTF16BE, indicating that the user-supplied
+** {F16604}
+** The third argument may be one of the constants [SQLITE_UTF8],
+** [SQLITE_UTF16LE] or [SQLITE_UTF16BE], indicating that the user-supplied
** routine expects to be passed pointers to strings encoded using UTF-8,
-** UTF-16 little-endian or UTF-16 big-endian respectively.
+** UTF-16 little-endian or UTF-16 big-endian respectively. {F16605} The
+** third argument might also be [SQLITE_UTF16_ALIGNED] to indicate that
+** the routine expects pointers to 16-bit word aligned strings
+** of UTF16 in the native byte order of the host computer.
**
+** {F16607}
** A pointer to the user supplied routine must be passed as the fifth
-** argument. If it is NULL, this is the same as deleting the collation
-** sequence (so that SQLite cannot call it anymore). Each time the user
+** argument. {F16609} If it is NULL, this is the same as deleting the collation
+** sequence (so that SQLite cannot call it anymore).
+** {F16611} Each time the application
** supplied function is invoked, it is passed a copy of the void* passed as
** the fourth argument to sqlite3_create_collation() or
** sqlite3_create_collation16() as its first parameter.
**
-** The remaining arguments to the user-supplied routine are two strings,
-** each represented by a [length, data] pair and encoded in the encoding
+** {F16612}
+** The remaining arguments to the application-supplied routine are two strings,
+** each represented by a (length, data) pair and encoded in the encoding
** that was passed as the third argument when the collation sequence was
-** registered. The user routine should return negative, zero or positive if
+** registered. {END} The application defined collation routine should
+** return negative, zero or positive if
** the first string is less than, equal to, or greater than the second
** string. i.e. (STRING1 - STRING2).
+**
+** {F16615}
+** The sqlite3_create_collation_v2() works like sqlite3_create_collation()
+** excapt that it takes an extra argument which is a destructor for
+** the collation. {F16617} The destructor is called when the collation is
+** destroyed and is passed a copy of the fourth parameter void* pointer
+** of the sqlite3_create_collation_v2().
+** {F16618} Collations are destroyed when
+** they are overridden by later calls to the collation creation functions
+** or when the [sqlite3*] database handle is closed using [sqlite3_close()].
*/
int sqlite3_create_collation(
sqlite3*,
@@ -1171,6 +3693,14 @@ int sqlite3_create_collation(
void*,
int(*xCompare)(void*,int,const void*,int,const void*)
);
+int sqlite3_create_collation_v2(
+ sqlite3*,
+ const char *zName,
+ int eTextRep,
+ void*,
+ int(*xCompare)(void*,int,const void*,int,const void*),
+ void(*xDestroy)(void*)
+);
int sqlite3_create_collation16(
sqlite3*,
const char *zName,
@@ -1180,28 +3710,33 @@ int sqlite3_create_collation16(
);
/*
+** CAPI3REF: Collation Needed Callbacks {F16700}
+**
+** {F16701}
** To avoid having to register all collation sequences before a database
** can be used, a single callback function may be registered with the
** database handle to be called whenever an undefined collation sequence is
** required.
**
+** {F16702}
** If the function is registered using the sqlite3_collation_needed() API,
** then it is passed the names of undefined collation sequences as strings
-** encoded in UTF-8. If sqlite3_collation_needed16() is used, the names
-** are passed as UTF-16 in machine native byte order. A call to either
+** encoded in UTF-8. {F16703} If sqlite3_collation_needed16() is used, the names
+** are passed as UTF-16 in machine native byte order. {F16704} A call to either
** function replaces any existing callback.
**
-** When the user-function is invoked, the first argument passed is a copy
+** {F16705} When the callback is invoked, the first argument passed is a copy
** of the second argument to sqlite3_collation_needed() or
-** sqlite3_collation_needed16(). The second argument is the database
-** handle. The third argument is one of SQLITE_UTF8, SQLITE_UTF16BE or
-** SQLITE_UTF16LE, indicating the most desirable form of the collation
-** sequence function required. The fourth parameter is the name of the
-** required collation sequence.
-**
-** The collation sequence is returned to SQLite by a collation-needed
-** callback using the sqlite3_create_collation() or
-** sqlite3_create_collation16() APIs, described above.
+** sqlite3_collation_needed16(). {F16706} The second argument is the database
+** handle. {F16707} The third argument is one of [SQLITE_UTF8],
+** [SQLITE_UTF16BE], or [SQLITE_UTF16LE], indicating the most
+** desirable form of the collation sequence function required.
+** {F16708} The fourth parameter is the name of the
+** required collation sequence. {END}
+**
+** The callback function should register the desired collation using
+** [sqlite3_create_collation()], [sqlite3_create_collation16()], or
+** [sqlite3_create_collation_v2()].
*/
int sqlite3_collation_needed(
sqlite3*,
@@ -1240,179 +3775,248 @@ int sqlite3_rekey(
);
/*
-** Sleep for a little while. The second parameter is the number of
-** miliseconds to sleep for.
+** CAPI3REF: Suspend Execution For A Short Time {F10530}
+**
+** {F10531} The sqlite3_sleep() function
+** causes the current thread to suspend execution
+** for at least a number of milliseconds specified in its parameter.
**
-** If the operating system does not support sleep requests with
-** milisecond time resolution, then the time will be rounded up to
-** the nearest second. The number of miliseconds of sleep actually
+** {F10532} If the operating system does not support sleep requests with
+** millisecond time resolution, then the time will be rounded up to
+** the nearest second. {F10533} The number of milliseconds of sleep actually
** requested from the operating system is returned.
+**
+** {F10534} SQLite implements this interface by calling the xSleep()
+** method of the default [sqlite3_vfs] object. {END}
*/
int sqlite3_sleep(int);
/*
-** Return TRUE (non-zero) if the statement supplied as an argument needs
-** to be recompiled. A statement needs to be recompiled whenever the
-** execution environment changes in a way that would alter the program
-** that sqlite3_prepare() generates. For example, if new functions or
-** collating sequences are registered or if an authorizer function is
-** added or changed.
+** CAPI3REF: Name Of The Folder Holding Temporary Files {F10310}
**
-*/
-int sqlite3_expired(sqlite3_stmt*);
-
-/*
-** Move all bindings from the first prepared statement over to the second.
-** This routine is useful, for example, if the first prepared statement
-** fails with an SQLITE_SCHEMA error. The same SQL can be prepared into
-** the second prepared statement then all of the bindings transfered over
-** to the second statement before the first statement is finalized.
-*/
-int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
-
-/*
-** If the following global variable is made to point to a
-** string which is the name of a directory, then all temporary files
+** If this global variable is made to point to a string which is
+** the name of a folder (a.ka. directory), then all temporary files
** created by SQLite will be placed in that directory. If this variable
** is NULL pointer, then SQLite does a search for an appropriate temporary
** file directory.
**
-** Once sqlite3_open() has been called, changing this variable will invalidate
-** the current temporary database, if any.
+** It is not safe to modify this variable once a database connection
+** has been opened. It is intended that this variable be set once
+** as part of process initialization and before any SQLite interface
+** routines have been call and remain unchanged thereafter.
*/
-extern char *sqlite3_temp_directory;
+SQLITE_EXTERN char *sqlite3_temp_directory;
/*
-** This function is called to recover from a malloc() failure that occured
-** within the SQLite library. Normally, after a single malloc() fails the
-** library refuses to function (all major calls return SQLITE_NOMEM).
-** This function restores the library state so that it can be used again.
+** CAPI3REF: Test To See If The Database Is In Auto-Commit Mode {F12930}
+**
+** The sqlite3_get_autocommit() interfaces returns non-zero or
+** zero if the given database connection is or is not in autocommit mode,
+** respectively. Autocommit mode is on
+** by default. Autocommit mode is disabled by a [BEGIN] statement.
+** Autocommit mode is reenabled by a [COMMIT] or [ROLLBACK].
+**
+** If certain kinds of errors occur on a statement within a multi-statement
+** transactions (errors including [SQLITE_FULL], [SQLITE_IOERR],
+** [SQLITE_NOMEM], [SQLITE_BUSY], and [SQLITE_INTERRUPT]) then the
+** transaction might be rolled back automatically. The only way to
+** find out if SQLite automatically rolled back the transaction after
+** an error is to use this function.
+**
+** INVARIANTS:
+**
+** {F12931} The [sqlite3_get_autocommit()] interface returns non-zero or
+** zero if the given database connection is or is not in autocommit
+** mode, respectively.
**
-** All existing statements (sqlite3_stmt pointers) must be finalized or
-** reset before this call is made. Otherwise, SQLITE_BUSY is returned.
-** If any in-memory databases are in use, either as a main or TEMP
-** database, SQLITE_ERROR is returned. In either of these cases, the
-** library is not reset and remains unusable.
+** {F12932} Autocommit mode is on by default.
**
-** 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.
+** {F12933} Autocommit mode is disabled by a successful [BEGIN] statement.
**
-** This functionality can be omitted from a build by defining the
-** SQLITE_OMIT_GLOBALRECOVER at compile time.
+** {F12934} Autocommit mode is enabled by a successful [COMMIT] or [ROLLBACK]
+** statement.
+**
+**
+** LIMITATIONS:
+***
+** {U12936} If another thread changes the autocommit status of the database
+** connection while this routine is running, then the return value
+** is undefined.
*/
-int sqlite3_global_recover(void);
+int sqlite3_get_autocommit(sqlite3*);
/*
-** Test to see whether or not the database connection is in autocommit
-** mode. Return TRUE if it is and FALSE if not. Autocommit mode is on
-** by default. Autocommit is disabled by a BEGIN statement and reenabled
-** by the next COMMIT or ROLLBACK.
+** CAPI3REF: Find The Database Handle Of A Prepared Statement {F13120}
+**
+** {F13121} The sqlite3_db_handle interface
+** returns the [sqlite3*] database handle to which a
+** [prepared statement] belongs.
+** {F13122} the database handle returned by sqlite3_db_handle
+** is the same database handle that was
+** the first argument to the [sqlite3_prepare_v2()] or its variants
+** that was used to create the statement in the first place.
*/
-int sqlite3_get_autocommit(sqlite3*);
+sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
+
/*
-** Return the sqlite3* database handle to which the prepared statement given
-** in the argument belongs. This is the same database handle that was
-** the first argument to the sqlite3_prepare() that was used to create
-** the statement in the first place.
+** CAPI3REF: Commit And Rollback Notification Callbacks {F12950}
+**
+** {F12951} The sqlite3_commit_hook() interface registers a callback
+** function to be invoked whenever a transaction is committed.
+** {F12952} Any callback set by a previous call to sqlite3_commit_hook()
+** for the same database connection is overridden.
+** {F12953} The sqlite3_rollback_hook() interface registers a callback
+** function to be invoked whenever a transaction is committed.
+** {F12954} Any callback set by a previous call to sqlite3_commit_hook()
+** for the same database connection is overridden.
+** {F12956} The pArg argument is passed through
+** to the callback. {F12957} If the callback on a commit hook function
+** returns non-zero, then the commit is converted into a rollback.
+**
+** {F12958} If another function was previously registered, its
+** pArg value is returned. Otherwise NULL is returned.
+**
+** {F12959} Registering a NULL function disables the callback.
+**
+** {F12961} 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.
+** {F12962} The rollback callback is not invoked if a transaction is
+** automatically rolled back because the database connection is closed.
+** {F12964} The rollback callback is not invoked if a transaction is
+** rolled back because a commit callback returned non-zero.
+** <todo> Check on this </todo> {END}
+**
+** These are experimental interfaces and are subject to change.
*/
-sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
+void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
+void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
/*
-** Register a callback function with the database connection identified by the
+** CAPI3REF: Data Change Notification Callbacks {F12970}
+**
+** {F12971} The sqlite3_update_hook() interface
+** registers 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
+** {F12972} 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
+** {F12974} The second argument is a pointer to the function to invoke when a
+** row is updated, inserted or deleted.
+** {F12976} The first argument to the callback is
+** a copy of the third argument to sqlite3_update_hook().
+** {F12977} 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.
+** {F12978} 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
+** table name containing the affected row.
+** {F12979} The final callback parameter is
+** the rowid of the row.
+** {F12981} 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
+** {F12983} 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.
+** {F12984} If another function was previously registered, its pArg value
+** is returned. {F12985} Otherwise NULL is returned.
*/
void *sqlite3_update_hook(
sqlite3*,
- void(*)(void *,int ,char const *,char const *,sqlite_int64),
+ void(*)(void *,int ,char const *,char const *,sqlite3_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.
+** CAPI3REF: Enable Or Disable Shared Pager Cache {F10330}
+**
+** {F10331}
+** This routine enables or disables the sharing of the database cache
+** and schema data structures between connections to the same database.
+** {F10332}
+** Sharing is enabled if the argument is true and disabled if the argument
+** is false.
+**
+** {F10333} Cache sharing is enabled and disabled
+** for an entire process. {END} This is a change as of SQLite version 3.5.0.
+** In prior versions of SQLite, sharing was
+** enabled or disabled for each thread separately.
+**
+** {F10334}
+** The cache sharing mode set by this interface effects all subsequent
+** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()].
+** {F10335} Existing database connections continue use the sharing mode
+** that was in effect at the time they were opened. {END}
+**
+** Virtual tables cannot be used with a shared cache. {F10336} When shared
+** cache is enabled, the [sqlite3_create_module()] API used to register
+** virtual tables will always return an error. {END}
+**
+** {F10337} This routine returns [SQLITE_OK] if shared cache was
+** enabled or disabled successfully. {F10338} An [error code]
+** is returned otherwise. {END}
+**
+** {F10339} Shared cache is disabled by default. {END} But this might change in
+** future releases of SQLite. Applications that care about shared
+** cache setting should set it explicitly.
*/
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.
+** CAPI3REF: Attempt To Free Heap Memory {F17340}
+**
+** {F17341} The sqlite3_release_memory() interface attempts to
+** free N bytes of heap memory by deallocating non-essential memory
+** allocations held by the database labrary. {END} Memory used
+** to cache database pages to improve performance is an example of
+** non-essential memory. {F16342} sqlite3_release_memory() returns
+** the number of bytes actually freed, which might be more or less
+** than the amount requested.
*/
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.
+** CAPI3REF: Impose A Limit On Heap Size {F17350}
+**
+** {F16351} The sqlite3_soft_heap_limit() interface
+** places a "soft" limit on the amount of heap memory that may be allocated
+** by SQLite. {F16352} If an internal allocation is requested
+** that would exceed the soft heap limit, [sqlite3_release_memory()] is
+** invoked one or more times to free up some space before the allocation
+** is made. {END}
+**
+** {F16353} 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.
+**
+** {F16354}
+** A negative or zero value for N means that there is no soft heap limit and
+** [sqlite3_release_memory()] will only be called when memory is exhausted.
+** {F16355} The default value for the soft heap limit is zero.
+**
+** SQLite makes a best effort to honor the soft heap limit.
+** {F16356} But if the soft heap limit cannot honored, execution will
+** continue without error or notification. {END} This is why the limit is
+** called a "soft" limit. It is advisory only.
+**
+** Prior to SQLite version 3.5.0, this routine only constrained the memory
+** allocated by a single thread - the same thread in which this routine
+** runs. Beginning with SQLite version 3.5.0, the soft heap limit is
+** applied to all threads. {F16357} The value specified for the soft heap limit
+** is an upper bound on the total memory allocation for all threads. {END} In
+** version 3.5.0 there is no mechanism for limiting the heap usage for
+** individual threads.
*/
void sqlite3_soft_heap_limit(int);
/*
-** This routine makes sure that all thread-local storage has been
-** deallocated for the current thread.
+** CAPI3REF: Extract Metadata About A Column Of A Table {F12850}
**
-** 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
+** This routine
+** returns meta-data about a specific column of a specific database
** table accessible using the connection handle passed as the first function
** argument.
**
@@ -1432,6 +4036,7 @@ void sqlite3_thread_cleanup(void);
** arguments may be NULL, in which case the corresponding element of meta
** information is ommitted.
**
+** <pre>
** Parameter Output Type Description
** -----------------------------------
**
@@ -1440,6 +4045,7 @@ void sqlite3_thread_cleanup(void);
** 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
+** </pre>
**
**
** The memory pointed to by the character pointers returned for the
@@ -1454,11 +4060,13 @@ void sqlite3_thread_cleanup(void);
** explicitly declared IPK column, then the output parameters are set as
** follows:
**
+** <pre>
** data type: "INTEGER"
** collation sequence: "BINARY"
** not null: 0
** primary key: 1
** auto increment: 0
+** </pre>
**
** 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
@@ -1477,26 +4085,31 @@ int sqlite3_table_column_metadata(
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 *pAutoinc /* OUTPUT: True if column 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()
+** CAPI3REF: Load An Extension {F12600}
+**
+** {F12601} The sqlite3_load_extension() interface
+** attempts to load an SQLite extension library contained in the file
+** zFile. {F12602} The entry point is zProc. {F12603} zProc may be 0
+** in which case the name of the entry point defaults
+** to "sqlite3_extension_init".
+**
+** {F12604} The sqlite3_load_extension() interface shall
+** return [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong.
+**
+** {F12605}
+** If an error occurs and pzErrMsg is not 0, then the
+** sqlite3_load_extension() interface shall attempt to fill *pzErrMsg with
+** error message text stored in memory obtained from [sqlite3_malloc()].
+** {END} The calling function should free this memory
+** by calling [sqlite3_free()].
+**
+** {F12606}
+** 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 */
@@ -1506,18 +4119,66 @@ int sqlite3_load_extension(
);
/*
-** 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.
+** CAPI3REF: Enable Or Disable Extension Loading {F12620}
**
-** Call this routine with onoff==1 to turn extension loading on
-** and call it with onoff==0 to turn it back off again.
+** So as not to open security holes in older applications that are
+** unprepared to deal with extension loading, and as a means of disabling
+** extension loading while evaluating user-entered SQL, the following
+** API is provided to turn the [sqlite3_load_extension()] mechanism on and
+** off. {F12622} It is off by default. {END} See ticket #1863.
+**
+** {F12621} Call the sqlite3_enable_load_extension() routine
+** with onoff==1 to turn extension loading on
+** and call it with onoff==0 to turn it back off again. {END}
*/
int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
/*
+** CAPI3REF: Make Arrangements To Automatically Load An Extension {F12640}
+**
+** {F12641} This function
+** registers an extension entry point that is automatically invoked
+** whenever a new database connection is opened using
+** [sqlite3_open()], [sqlite3_open16()], or [sqlite3_open_v2()]. {END}
+**
+** This API can be invoked at program startup in order to register
+** one or more statically linked extensions that will be available
+** to all new database connections.
+**
+** {F12642} Duplicate extensions are detected so calling this routine multiple
+** times with the same extension is harmless.
+**
+** {F12643} This routine stores a pointer to the extension in an array
+** that is obtained from sqlite_malloc(). {END} If you run a memory leak
+** checker on your program and it reports a leak because of this
+** array, then invoke [sqlite3_reset_auto_extension()] prior
+** to shutdown to free the memory.
+**
+** {F12644} Automatic extensions apply across all threads. {END}
+**
+** This interface is experimental and is subject to change or
+** removal in future releases of SQLite.
+*/
+int sqlite3_auto_extension(void *xEntryPoint);
+
+
+/*
+** CAPI3REF: Reset Automatic Extension Loading {F12660}
+**
+** {F12661} This function disables all previously registered
+** automatic extensions. {END} This
+** routine undoes the effect of all prior [sqlite3_auto_extension()]
+** calls.
+**
+** {F12662} This call disabled automatic extensions in all threads. {END}
+**
+** This interface is experimental and is subject to change or
+** removal in future releases of SQLite.
+*/
+void sqlite3_reset_auto_extension(void);
+
+
+/*
****** EXPERIMENTAL - subject to change without notice **************
**
** The interface to the virtual-table mechanism is currently considered
@@ -1544,11 +4205,11 @@ typedef struct sqlite3_module sqlite3_module;
struct sqlite3_module {
int iVersion;
int (*xCreate)(sqlite3*, void *pAux,
- int argc, char **argv,
- sqlite3_vtab **ppVTab);
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVTab, char**);
int (*xConnect)(sqlite3*, void *pAux,
- int argc, char **argv,
- sqlite3_vtab **ppVTab);
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVTab, char**);
int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);
int (*xDisconnect)(sqlite3_vtab *pVTab);
int (*xDestroy)(sqlite3_vtab *pVTab);
@@ -1559,8 +4220,8 @@ struct sqlite3_module {
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 (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid);
+ int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *);
int (*xBegin)(sqlite3_vtab *pVTab);
int (*xSync)(sqlite3_vtab *pVTab);
int (*xCommit)(sqlite3_vtab *pVTab);
@@ -1568,6 +4229,8 @@ struct sqlite3_module {
int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName,
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
void **ppArg);
+
+ int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
};
/*
@@ -1582,14 +4245,15 @@ struct sqlite3_module {
**
** column OP expr
**
-** Where OP is =, <, <=, >, or >=. The particular operator is stored
+** Where OP is =, &lt;, &lt;=, &gt;, or &gt;=.
+** 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
+** and makes other simplifications 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.
@@ -1618,24 +4282,24 @@ struct sqlite3_module {
*/
struct sqlite3_index_info {
/* Inputs */
- const int nConstraint; /* Number of entries in aConstraint */
- const struct sqlite3_index_constraint {
+ int nConstraint; /* Number of entries in aConstraint */
+ 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 {
+ } *aConstraint; /* Table of WHERE clause constraints */
+ int nOrderBy; /* Number of terms in the ORDER BY clause */
+ struct sqlite3_index_orderby {
int iColumn; /* Column number */
unsigned char desc; /* True for DESC. False for ASC. */
- } *const aOrderBy; /* The ORDER BY clause */
+ } *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;
+ } *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 */
@@ -1663,15 +4327,39 @@ int sqlite3_create_module(
);
/*
+** This routine is identical to the sqlite3_create_module() method above,
+** except that it allows a destructor function to be specified. It is
+** even more experimental than the rest of the virtual tables API.
+*/
+int sqlite3_create_module_v2(
+ 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 */
+ void(*xDestroy)(void*) /* Module destructor function */
+);
+
+/*
** 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
+** be tailored 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.
+**
+** Virtual tables methods can set an error message by assigning a
+** string obtained from sqlite3_mprintf() to zErrMsg. The method should
+** take care that any prior string is freed by a call to sqlite3_free()
+** prior to assigning a new string to zErrMsg. After the error message
+** is delivered up to the client application, the string will be automatically
+** freed by sqlite3_free() and the zErrMsg field will be zeroed. Note
+** that sqlite3_mprintf() and sqlite3_free() are used on the zErrMsg field
+** since virtual tables are commonly implemented in loadable extensions which
+** do not have access to sqlite3MPrintf() or sqlite3Free().
*/
struct sqlite3_vtab {
const sqlite3_module *pModule; /* The module for this virtual table */
int nRef; /* Used internally */
+ char *zErrMsg; /* Error message from sqlite3_mprintf() */
/* Virtual table implementations will typically add additional fields */
};
@@ -1697,18 +4385,412 @@ struct sqlite3_vtab_cursor {
int sqlite3_declare_vtab(sqlite3*, const char *zCreateTable);
/*
+** Virtual tables can provide alternative implementations of functions
+** using the xFindFunction method. But global versions of those functions
+** must exist in order to be overloaded.
+**
+** This API makes sure a global version of a function with a particular
+** name and number of parameters exists. If no such function exists
+** before this API is called, a new function is created. The implementation
+** of the new function always causes an exception to be thrown. So
+** the new function is not good for anything by itself. Its only
+** purpose is to be a place-holder function that can be overloaded
+** by virtual tables.
+**
+** This API should be considered part of the virtual table interface,
+** which is experimental and subject to change.
+*/
+int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
+
+/*
** 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
+** When the virtual-table mechanism stabilizes, we will declare the
** interface fixed, support it indefinitely, and remove this comment.
**
****** EXPERIMENTAL - subject to change without notice **************
*/
/*
+** CAPI3REF: A Handle To An Open BLOB {F17800}
+**
+** An instance of the following opaque structure is used to
+** represent an blob-handle. A blob-handle is created by
+** [sqlite3_blob_open()] and destroyed by [sqlite3_blob_close()].
+** The [sqlite3_blob_read()] and [sqlite3_blob_write()] interfaces
+** can be used to read or write small subsections of the blob.
+** The [sqlite3_blob_bytes()] interface returns the size of the
+** blob in bytes.
+*/
+typedef struct sqlite3_blob sqlite3_blob;
+
+/*
+** CAPI3REF: Open A BLOB For Incremental I/O {F17810}
+**
+** {F17811} This interfaces opens a handle to the blob located
+** in row iRow,, column zColumn, table zTable in database zDb;
+** in other words, the same blob that would be selected by:
+**
+** <pre>
+** SELECT zColumn FROM zDb.zTable WHERE rowid = iRow;
+** </pre> {END}
+**
+** {F17812} If the flags parameter is non-zero, the blob is opened for
+** read and write access. If it is zero, the blob is opened for read
+** access. {END}
+**
+** {F17813} On success, [SQLITE_OK] is returned and the new
+** [sqlite3_blob | blob handle] is written to *ppBlob.
+** {F17814} Otherwise an error code is returned and
+** any value written to *ppBlob should not be used by the caller.
+** {F17815} This function sets the database-handle error code and message
+** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()].
+** <todo>We should go through and mark all interfaces that behave this
+** way with a similar statement</todo>
+*/
+int sqlite3_blob_open(
+ sqlite3*,
+ const char *zDb,
+ const char *zTable,
+ const char *zColumn,
+ sqlite3_int64 iRow,
+ int flags,
+ sqlite3_blob **ppBlob
+);
+
+/*
+** CAPI3REF: Close A BLOB Handle {F17830}
+**
+** Close an open [sqlite3_blob | blob handle].
+**
+** {F17831} Closing a BLOB shall cause the current transaction to commit
+** if there are no other BLOBs, no pending prepared statements, and the
+** database connection is in autocommit mode.
+** {F17832} If any writes were made to the BLOB, they might be held in cache
+** until the close operation if they will fit. {END}
+** Closing the BLOB often forces the changes
+** out to disk and so if any I/O errors occur, they will likely occur
+** at the time when the BLOB is closed. {F17833} Any errors that occur during
+** closing are reported as a non-zero return value.
+**
+** {F17839} The BLOB is closed unconditionally. Even if this routine returns
+** an error code, the BLOB is still closed.
+*/
+int sqlite3_blob_close(sqlite3_blob *);
+
+/*
+** CAPI3REF: Return The Size Of An Open BLOB {F17805}
+**
+** {F16806} Return the size in bytes of the blob accessible via the open
+** [sqlite3_blob | blob-handle] passed as an argument.
+*/
+int sqlite3_blob_bytes(sqlite3_blob *);
+
+/*
+** CAPI3REF: Read Data From A BLOB Incrementally {F17850}
+**
+** This function is used to read data from an open
+** [sqlite3_blob | blob-handle] into a caller supplied buffer.
+** {F17851} n bytes of data are copied into buffer
+** z from the open blob, starting at offset iOffset.
+**
+** {F17852} If offset iOffset is less than n bytes from the end of the blob,
+** [SQLITE_ERROR] is returned and no data is read. {F17853} If n is
+** less than zero [SQLITE_ERROR] is returned and no data is read.
+**
+** {F17854} On success, SQLITE_OK is returned. Otherwise, an
+** [error code] or an [extended error code] is returned.
+*/
+int sqlite3_blob_read(sqlite3_blob *, void *z, int n, int iOffset);
+
+/*
+** CAPI3REF: Write Data Into A BLOB Incrementally {F17870}
+**
+** This function is used to write data into an open
+** [sqlite3_blob | blob-handle] from a user supplied buffer.
+** {F17871} n bytes of data are copied from the buffer
+** pointed to by z into the open blob, starting at offset iOffset.
+**
+** {F17872} If the [sqlite3_blob | blob-handle] passed as the first argument
+** was not opened for writing (the flags parameter to [sqlite3_blob_open()]
+*** was zero), this function returns [SQLITE_READONLY].
+**
+** {F17873} This function may only modify the contents of the blob; it is
+** not possible to increase the size of a blob using this API.
+** {F17874} If offset iOffset is less than n bytes from the end of the blob,
+** [SQLITE_ERROR] is returned and no data is written. {F17875} If n is
+** less than zero [SQLITE_ERROR] is returned and no data is written.
+**
+** {F17876} On success, SQLITE_OK is returned. Otherwise, an
+** [error code] or an [extended error code] is returned.
+*/
+int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
+
+/*
+** CAPI3REF: Virtual File System Objects {F11200}
+**
+** A virtual filesystem (VFS) is an [sqlite3_vfs] object
+** that SQLite uses to interact
+** with the underlying operating system. Most builds come with a
+** single default VFS that is appropriate for the host computer.
+** New VFSes can be registered and existing VFSes can be unregistered.
+** The following interfaces are provided.
+**
+** {F11201} The sqlite3_vfs_find() interface returns a pointer to
+** a VFS given its name. {F11202} Names are case sensitive.
+** {F11203} Names are zero-terminated UTF-8 strings.
+** {F11204} If there is no match, a NULL
+** pointer is returned. {F11205} If zVfsName is NULL then the default
+** VFS is returned. {END}
+**
+** {F11210} New VFSes are registered with sqlite3_vfs_register().
+** {F11211} Each new VFS becomes the default VFS if the makeDflt flag is set.
+** {F11212} The same VFS can be registered multiple times without injury.
+** {F11213} To make an existing VFS into the default VFS, register it again
+** with the makeDflt flag set. {U11214} If two different VFSes with the
+** same name are registered, the behavior is undefined. {U11215} If a
+** VFS is registered with a name that is NULL or an empty string,
+** then the behavior is undefined.
+**
+** {F11220} Unregister a VFS with the sqlite3_vfs_unregister() interface.
+** {F11221} If the default VFS is unregistered, another VFS is chosen as
+** the default. The choice for the new VFS is arbitrary.
+*/
+sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
+int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
+int sqlite3_vfs_unregister(sqlite3_vfs*);
+
+/*
+** CAPI3REF: Mutexes {F17000}
+**
+** The SQLite core uses these routines for thread
+** synchronization. Though they are intended for internal
+** use by SQLite, code that links against SQLite is
+** permitted to use any of these routines.
+**
+** The SQLite source code contains multiple implementations
+** of these mutex routines. An appropriate implementation
+** is selected automatically at compile-time. The following
+** implementations are available in the SQLite core:
+**
+** <ul>
+** <li> SQLITE_MUTEX_OS2
+** <li> SQLITE_MUTEX_PTHREAD
+** <li> SQLITE_MUTEX_W32
+** <li> SQLITE_MUTEX_NOOP
+** </ul>
+**
+** The SQLITE_MUTEX_NOOP implementation is a set of routines
+** that does no real locking and is appropriate for use in
+** a single-threaded application. The SQLITE_MUTEX_OS2,
+** SQLITE_MUTEX_PTHREAD, and SQLITE_MUTEX_W32 implementations
+** are appropriate for use on os/2, unix, and windows.
+**
+** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
+** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex
+** implementation is included with the library. The
+** mutex interface routines defined here become external
+** references in the SQLite library for which implementations
+** must be provided by the application. This facility allows an
+** application that links against SQLite to provide its own mutex
+** implementation without having to modify the SQLite core.
+**
+** {F17011} The sqlite3_mutex_alloc() routine allocates a new
+** mutex and returns a pointer to it. {F17012} If it returns NULL
+** that means that a mutex could not be allocated. {F17013} SQLite
+** will unwind its stack and return an error. {F17014} The argument
+** to sqlite3_mutex_alloc() is one of these integer constants:
+**
+** <ul>
+** <li> SQLITE_MUTEX_FAST
+** <li> SQLITE_MUTEX_RECURSIVE
+** <li> SQLITE_MUTEX_STATIC_MASTER
+** <li> SQLITE_MUTEX_STATIC_MEM
+** <li> SQLITE_MUTEX_STATIC_MEM2
+** <li> SQLITE_MUTEX_STATIC_PRNG
+** <li> SQLITE_MUTEX_STATIC_LRU
+** </ul> {END}
+**
+** {F17015} The first two constants cause sqlite3_mutex_alloc() to create
+** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
+** is used but not necessarily so when SQLITE_MUTEX_FAST is used. {END}
+** The mutex implementation does not need to make a distinction
+** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
+** not want to. {F17016} But SQLite will only request a recursive mutex in
+** cases where it really needs one. {END} If a faster non-recursive mutex
+** implementation is available on the host platform, the mutex subsystem
+** might return such a mutex in response to SQLITE_MUTEX_FAST.
+**
+** {F17017} The other allowed parameters to sqlite3_mutex_alloc() each return
+** a pointer to a static preexisting mutex. {END} Four static mutexes are
+** used by the current version of SQLite. Future versions of SQLite
+** may add additional static mutexes. Static mutexes are for internal
+** use by SQLite only. Applications that use SQLite mutexes should
+** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
+** SQLITE_MUTEX_RECURSIVE.
+**
+** {F17018} Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
+** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
+** returns a different mutex on every call. {F17034} But for the static
+** mutex types, the same mutex is returned on every call that has
+** the same type number. {END}
+**
+** {F17019} The sqlite3_mutex_free() routine deallocates a previously
+** allocated dynamic mutex. {F17020} SQLite is careful to deallocate every
+** dynamic mutex that it allocates. {U17021} The dynamic mutexes must not be in
+** use when they are deallocated. {U17022} Attempting to deallocate a static
+** mutex results in undefined behavior. {F17023} SQLite never deallocates
+** a static mutex. {END}
+**
+** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
+** to enter a mutex. {F17024} If another thread is already within the mutex,
+** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
+** SQLITE_BUSY. {F17025} The sqlite3_mutex_try() interface returns SQLITE_OK
+** upon successful entry. {F17026} Mutexes created using
+** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread.
+** {F17027} In such cases the,
+** mutex must be exited an equal number of times before another thread
+** can enter. {U17028} If the same thread tries to enter any other
+** kind of mutex more than once, the behavior is undefined.
+** {F17029} SQLite will never exhibit
+** such behavior in its own use of mutexes. {END}
+**
+** Some systems (ex: windows95) do not the operation implemented by
+** sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() will
+** always return SQLITE_BUSY. {F17030} The SQLite core only ever uses
+** sqlite3_mutex_try() as an optimization so this is acceptable behavior. {END}
+**
+** {F17031} The sqlite3_mutex_leave() routine exits a mutex that was
+** previously entered by the same thread. {U17032} The behavior
+** is undefined if the mutex is not currently entered by the
+** calling thread or is not currently allocated. {F17033} SQLite will
+** never do either. {END}
+**
+** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
+*/
+sqlite3_mutex *sqlite3_mutex_alloc(int);
+void sqlite3_mutex_free(sqlite3_mutex*);
+void sqlite3_mutex_enter(sqlite3_mutex*);
+int sqlite3_mutex_try(sqlite3_mutex*);
+void sqlite3_mutex_leave(sqlite3_mutex*);
+
+/*
+** CAPI3REF: Mutex Verifcation Routines {F17080}
+**
+** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines
+** are intended for use inside assert() statements. {F17081} The SQLite core
+** never uses these routines except inside an assert() and applications
+** are advised to follow the lead of the core. {F17082} The core only
+** provides implementations for these routines when it is compiled
+** with the SQLITE_DEBUG flag. {U17087} External mutex implementations
+** are only required to provide these routines if SQLITE_DEBUG is
+** defined and if NDEBUG is not defined.
+**
+** {F17083} These routines should return true if the mutex in their argument
+** is held or not held, respectively, by the calling thread. {END}
+**
+** {X17084} The implementation is not required to provided versions of these
+** routines that actually work.
+** If the implementation does not provide working
+** versions of these routines, it should at least provide stubs
+** that always return true so that one does not get spurious
+** assertion failures. {END}
+**
+** {F17085} If the argument to sqlite3_mutex_held() is a NULL pointer then
+** the routine should return 1. {END} This seems counter-intuitive since
+** clearly the mutex cannot be held if it does not exist. But the
+** the reason the mutex does not exist is because the build is not
+** using mutexes. And we do not want the assert() containing the
+** call to sqlite3_mutex_held() to fail, so a non-zero return is
+** the appropriate thing to do. {F17086} The sqlite3_mutex_notheld()
+** interface should also return 1 when given a NULL pointer.
+*/
+int sqlite3_mutex_held(sqlite3_mutex*);
+int sqlite3_mutex_notheld(sqlite3_mutex*);
+
+/*
+** CAPI3REF: Mutex Types {F17001}
+**
+** {F17002} The [sqlite3_mutex_alloc()] interface takes a single argument
+** which is one of these integer constants. {END}
+*/
+#define SQLITE_MUTEX_FAST 0
+#define SQLITE_MUTEX_RECURSIVE 1
+#define SQLITE_MUTEX_STATIC_MASTER 2
+#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */
+#define SQLITE_MUTEX_STATIC_MEM2 4 /* sqlite3_release_memory() */
+#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */
+#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
+
+/*
+** CAPI3REF: Low-Level Control Of Database Files {F11300}
+**
+** {F11301} The [sqlite3_file_control()] interface makes a direct call to the
+** xFileControl method for the [sqlite3_io_methods] object associated
+** with a particular database identified by the second argument. {F11302} The
+** name of the database is the name assigned to the database by the
+** <a href="lang_attach.html">ATTACH</a> SQL command that opened the
+** database. {F11303} To control the main database file, use the name "main"
+** or a NULL pointer. {F11304} The third and fourth parameters to this routine
+** are passed directly through to the second and third parameters of
+** the xFileControl method. {F11305} The return value of the xFileControl
+** method becomes the return value of this routine.
+**
+** {F11306} If the second parameter (zDbName) does not match the name of any
+** open database file, then SQLITE_ERROR is returned. {F11307} This error
+** code is not remembered and will not be recalled by [sqlite3_errcode()]
+** or [sqlite3_errmsg()]. {U11308} The underlying xFileControl method might
+** also return SQLITE_ERROR. {U11309} There is no way to distinguish between
+** an incorrect zDbName and an SQLITE_ERROR return from the underlying
+** xFileControl method. {END}
+**
+** See also: [SQLITE_FCNTL_LOCKSTATE]
+*/
+int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
+
+/*
+** CAPI3REF: Testing Interface {F11400}
+**
+** The sqlite3_test_control() interface is used to read out internal
+** state of SQLite and to inject faults into SQLite for testing
+** purposes. The first parameter a operation code that determines
+** the number, meaning, and operation of all subsequent parameters.
+**
+** This interface is not for use by applications. It exists solely
+** for verifying the correct operation of the SQLite library. Depending
+** on how the SQLite library is compiled, this interface might not exist.
+**
+** The details of the operation codes, their meanings, the parameters
+** they take, and what they do are all subject to change without notice.
+** Unlike most of the SQLite API, this function is not guaranteed to
+** operate consistently from one release to the next.
+*/
+int sqlite3_test_control(int op, ...);
+
+/*
+** CAPI3REF: Testing Interface Operation Codes {F11410}
+**
+** These constants are the valid operation code parameters used
+** as the first argument to [sqlite3_test_control()].
+**
+** These parameters and their meansing are subject to change
+** without notice. These values are for testing purposes only.
+** Applications should not use any of these parameters or the
+** [sqlite3_test_control()] interface.
+*/
+#define SQLITE_TESTCTRL_FAULT_CONFIG 1
+#define SQLITE_TESTCTRL_FAULT_FAILURES 2
+#define SQLITE_TESTCTRL_FAULT_BENIGN_FAILURES 3
+#define SQLITE_TESTCTRL_FAULT_PENDING 4
+
+
+
+
+
+/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
*/
diff --git a/ext/pdo_sqlite/sqlite/src/sqlite3ext.h b/ext/pdo_sqlite/sqlite/src/sqlite3ext.h
index 016f31ff05..ba4f9d6e60 100644
--- a/ext/pdo_sqlite/sqlite/src/sqlite3ext.h
+++ b/ext/pdo_sqlite/sqlite/src/sqlite3ext.h
@@ -1,5 +1,5 @@
/*
-** 2007 June 7
+** 2006 June 7
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -19,13 +19,19 @@
*/
#ifndef _SQLITE3EXT_H_
#define _SQLITE3EXT_H_
-#include <sqlite3.h>
+#include "sqlite3.h"
typedef struct sqlite3_api_routines sqlite3_api_routines;
/*
** The following structure hold pointers to all of the SQLite API
** routines.
+**
+** WARNING: In order to maintain backwards compatibility, add new
+** interfaces to the end of this structure only. If you insert new
+** interfaces in the middle of this structure, then older different
+** versions of SQLite will not be able to load each others shared
+** libraries!
*/
struct sqlite3_api_routines {
void * (*aggregate_context)(sqlite3_context*,int nBytes);
@@ -92,7 +98,7 @@ struct sqlite3_api_routines {
void * (*get_auxdata)(sqlite3_context*,int);
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
int (*global_recover)(void);
- void (*interrupt)(sqlite3*);
+ void (*interruptx)(sqlite3*);
sqlite_int64 (*last_insert_rowid)(sqlite3*);
const char * (*libversion)(void);
int (*libversion_number)(void);
@@ -142,7 +148,40 @@ struct sqlite3_api_routines {
const void * (*value_text16be)(sqlite3_value*);
const void * (*value_text16le)(sqlite3_value*);
int (*value_type)(sqlite3_value*);
- char * (*vmprintf)(const char*,va_list);
+ char *(*vmprintf)(const char*,va_list);
+ /* Added ??? */
+ int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
+ /* Added by 3.3.13 */
+ int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
+ int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
+ int (*clear_bindings)(sqlite3_stmt*);
+ /* Added by 3.4.1 */
+ int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,void (*xDestroy)(void *));
+ /* Added by 3.5.0 */
+ int (*bind_zeroblob)(sqlite3_stmt*,int,int);
+ int (*blob_bytes)(sqlite3_blob*);
+ int (*blob_close)(sqlite3_blob*);
+ int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,int,sqlite3_blob**);
+ int (*blob_read)(sqlite3_blob*,void*,int,int);
+ int (*blob_write)(sqlite3_blob*,const void*,int,int);
+ int (*create_collation_v2)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*),void(*)(void*));
+ int (*file_control)(sqlite3*,const char*,int,void*);
+ sqlite3_int64 (*memory_highwater)(int);
+ sqlite3_int64 (*memory_used)(void);
+ sqlite3_mutex *(*mutex_alloc)(int);
+ void (*mutex_enter)(sqlite3_mutex*);
+ void (*mutex_free)(sqlite3_mutex*);
+ void (*mutex_leave)(sqlite3_mutex*);
+ int (*mutex_try)(sqlite3_mutex*);
+ int (*open_v2)(const char*,sqlite3**,int,const char*);
+ int (*release_memory)(int);
+ void (*result_error_nomem)(sqlite3_context*);
+ void (*result_error_toobig)(sqlite3_context*);
+ int (*sleep)(int);
+ void (*soft_heap_limit)(int);
+ sqlite3_vfs *(*vfs_find)(const char*);
+ int (*vfs_register)(sqlite3_vfs*,int);
+ int (*vfs_unregister)(sqlite3_vfs*);
};
/*
@@ -205,6 +244,7 @@ struct sqlite3_api_routines {
#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_create_module_v2 sqlite3_api->create_module_v2
#define sqlite3_data_count sqlite3_api->data_count
#define sqlite3_db_handle sqlite3_api->db_handle
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
@@ -221,7 +261,7 @@ struct sqlite3_api_routines {
#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_interrupt sqlite3_api->interruptx
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
#define sqlite3_libversion sqlite3_api->libversion
#define sqlite3_libversion_number sqlite3_api->libversion_number
@@ -231,6 +271,8 @@ struct sqlite3_api_routines {
#define sqlite3_open16 sqlite3_api->open16
#define sqlite3_prepare sqlite3_api->prepare
#define sqlite3_prepare16 sqlite3_api->prepare16
+#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
+#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_profile sqlite3_api->profile
#define sqlite3_progress_handler sqlite3_api->progress_handler
#define sqlite3_realloc sqlite3_api->realloc
@@ -272,6 +314,34 @@ struct sqlite3_api_routines {
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
+#define sqlite3_overload_function sqlite3_api->overload_function
+#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
+#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
+#define sqlite3_clear_bindings sqlite3_api->clear_bindings
+#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
+#define sqlite3_blob_bytes sqlite3_api->blob_bytes
+#define sqlite3_blob_close sqlite3_api->blob_close
+#define sqlite3_blob_open sqlite3_api->blob_open
+#define sqlite3_blob_read sqlite3_api->blob_read
+#define sqlite3_blob_write sqlite3_api->blob_write
+#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
+#define sqlite3_file_control sqlite3_api->file_control
+#define sqlite3_memory_highwater sqlite3_api->memory_highwater
+#define sqlite3_memory_used sqlite3_api->memory_used
+#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
+#define sqlite3_mutex_enter sqlite3_api->mutex_enter
+#define sqlite3_mutex_free sqlite3_api->mutex_free
+#define sqlite3_mutex_leave sqlite3_api->mutex_leave
+#define sqlite3_mutex_try sqlite3_api->mutex_try
+#define sqlite3_open_v2 sqlite3_api->open_v2
+#define sqlite3_release_memory sqlite3_api->release_memory
+#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
+#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
+#define sqlite3_sleep sqlite3_api->sleep
+#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
+#define sqlite3_vfs_find sqlite3_api->vfs_find
+#define sqlite3_vfs_register sqlite3_api->vfs_register
+#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
#endif /* SQLITE_CORE */
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api;
diff --git a/ext/pdo_sqlite/sqlite/src/sqliteInt.h b/ext/pdo_sqlite/sqlite/src/sqliteInt.h
index 58e21c4f3c..4c9b98acc1 100644
--- a/ext/pdo_sqlite/sqlite/src/sqliteInt.h
+++ b/ext/pdo_sqlite/sqlite/src/sqliteInt.h
@@ -17,28 +17,29 @@
#define _SQLITEINT_H_
/*
-** Extra interface definitions for those who need them
-*/
-#ifdef SQLITE_EXTRA
-# include "sqliteExtra.h"
+** The macro unlikely() is a hint that surrounds a boolean
+** expression that is usually false. Macro likely() surrounds
+** a boolean expression that is usually true. GCC is able to
+** use these hints to generate better code, sometimes.
+*/
+#if defined(__GNUC__) && 0
+# define likely(X) __builtin_expect((X),1)
+# define unlikely(X) __builtin_expect((X),0)
+#else
+# define likely(X) !!(X)
+# define unlikely(X) !!(X)
#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
-** option is set. Thus NDEBUG becomes an opt-in rather than an opt-out
-** feature.
-*/
-#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
-# define NDEBUG 1
-#endif
/*
** These #defines should enable >2GB file support on Posix if the
** underlying operating system supports it. If the OS lacks
** large file support, or if the OS is windows, these should be no-ops.
**
+** Ticket #2739: The _LARGEFILE_SOURCE macro must appear before any
+** system #includes. Hence, this block of code must be the very first
+** code in all source files.
+**
** 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
@@ -57,6 +58,97 @@
# define _LARGEFILE_SOURCE 1
#endif
+
+#include "sqliteLimit.h"
+
+/*
+** For testing purposes, the various size limit constants are really
+** variables that we can modify in the testfixture.
+*/
+#ifdef SQLITE_TEST
+ #undef SQLITE_MAX_LENGTH
+ #undef SQLITE_MAX_COLUMN
+ #undef SQLITE_MAX_SQL_LENGTH
+ #undef SQLITE_MAX_EXPR_DEPTH
+ #undef SQLITE_MAX_COMPOUND_SELECT
+ #undef SQLITE_MAX_VDBE_OP
+ #undef SQLITE_MAX_FUNCTION_ARG
+ #undef SQLITE_MAX_VARIABLE_NUMBER
+ #undef SQLITE_MAX_PAGE_SIZE
+ #undef SQLITE_MAX_PAGE_COUNT
+ #undef SQLITE_MAX_LIKE_PATTERN_LENGTH
+
+ #define SQLITE_MAX_LENGTH sqlite3MAX_LENGTH
+ #define SQLITE_MAX_COLUMN sqlite3MAX_COLUMN
+ #define SQLITE_MAX_SQL_LENGTH sqlite3MAX_SQL_LENGTH
+ #define SQLITE_MAX_EXPR_DEPTH sqlite3MAX_EXPR_DEPTH
+ #define SQLITE_MAX_COMPOUND_SELECT sqlite3MAX_COMPOUND_SELECT
+ #define SQLITE_MAX_VDBE_OP sqlite3MAX_VDBE_OP
+ #define SQLITE_MAX_FUNCTION_ARG sqlite3MAX_FUNCTION_ARG
+ #define SQLITE_MAX_VARIABLE_NUMBER sqlite3MAX_VARIABLE_NUMBER
+ #define SQLITE_MAX_PAGE_SIZE sqlite3MAX_PAGE_SIZE
+ #define SQLITE_MAX_PAGE_COUNT sqlite3MAX_PAGE_COUNT
+ #define SQLITE_MAX_LIKE_PATTERN_LENGTH sqlite3MAX_LIKE_PATTERN_LENGTH
+
+ extern int sqlite3MAX_LENGTH;
+ extern int sqlite3MAX_COLUMN;
+ extern int sqlite3MAX_SQL_LENGTH;
+ extern int sqlite3MAX_EXPR_DEPTH;
+ extern int sqlite3MAX_COMPOUND_SELECT;
+ extern int sqlite3MAX_VDBE_OP;
+ extern int sqlite3MAX_FUNCTION_ARG;
+ extern int sqlite3MAX_VARIABLE_NUMBER;
+ extern int sqlite3MAX_PAGE_SIZE;
+ extern int sqlite3MAX_PAGE_COUNT;
+ extern int sqlite3MAX_LIKE_PATTERN_LENGTH;
+#endif
+
+
+/*
+** The SQLITE_THREADSAFE macro must be defined as either 0 or 1.
+** Older versions of SQLite used an optional THREADSAFE macro.
+** We support that for legacy
+*/
+#if !defined(SQLITE_THREADSAFE)
+#if defined(THREADSAFE)
+# define SQLITE_THREADSAFE THREADSAFE
+#else
+# define SQLITE_THREADSAFE 1
+#endif
+#endif
+
+/*
+** We need to define _XOPEN_SOURCE as follows in order to enable
+** recursive mutexes on most unix systems. But Mac OS X is different.
+** The _XOPEN_SOURCE define causes problems for Mac OS X we are told,
+** so it is omitted there. See ticket #2673.
+**
+** Later we learn that _XOPEN_SOURCE is poorly or incorrectly
+** implemented on some systems. So we avoid defining it at all
+** if it is already defined or if it is unneeded because we are
+** not doing a threadsafe build. Ticket #2681.
+**
+** See also ticket #2741.
+*/
+#if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) && !defined(__APPLE__) && SQLITE_THREADSAFE
+# define _XOPEN_SOURCE 500 /* Needed to enable pthread recursive mutexes */
+#endif
+
+#if defined(SQLITE_TCL) || defined(TCLSH)
+# include <tcl.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
+** option is set. Thus NDEBUG becomes an opt-in rather than an opt-out
+** feature.
+*/
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
+# define NDEBUG 1
+#endif
+
#include "sqlite3.h"
#include "hash.h"
#include "parse.h"
@@ -66,6 +158,8 @@
#include <assert.h>
#include <stddef.h>
+#define sqlite3_isnan(X) ((X)!=(X))
+
/*
** If compiling for a processor that lacks floating point support,
** substitute integer for floating-point
@@ -78,30 +172,13 @@
# endif
# define SQLITE_OMIT_DATETIME_FUNCS 1
# define SQLITE_OMIT_TRACE 1
+# undef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
#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
-** compilation time, the SQLITE_DEFAULT_CACHE_SIZE and
-** SQLITE_DEFAULT_TEMP_CACHE_SIZE macros should be set.
-*/
-#ifdef SQLITE_DEFAULT_CACHE_SIZE
-# define MAX_PAGES SQLITE_DEFAULT_CACHE_SIZE
-#else
-# define MAX_PAGES 2000
-#endif
-#ifdef SQLITE_DEFAULT_TEMP_CACHE_SIZE
-# define TEMP_PAGES SQLITE_DEFAULT_TEMP_CACHE_SIZE
-#else
-# define TEMP_PAGES 500
-#endif
-
-/*
** OMIT_TEMPDB is set to 1 if SQLITE_OMIT_TEMPDB is defined, or 0
** afterward. Having this macro allows us to cause the C compiler
** to omit code used by TEMP tables without messy #ifndef statements.
@@ -127,20 +204,6 @@
#define NULL_DISTINCT_FOR_UNIQUE 1
/*
-** The maximum number of attached databases. This must be at least 2
-** in order to support the main database file (0) and the file used to
-** hold temporary tables (1). And it must be less than 32 because
-** we use a bitmask of databases with a u32 in places (for example
-** the Parse.cookieMask field).
-*/
-#define MAX_ATTACHED 10
-
-/*
-** The maximum value of a ?nnn wildcard that the parser will accept.
-*/
-#define SQLITE_MAX_VARIABLE_NUMBER 999
-
-/*
** 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
@@ -214,9 +277,20 @@ typedef UINT8_TYPE i8; /* 1-byte signed integer */
** Macros to determine whether the machine is big or little endian,
** evaluated at runtime.
*/
+#ifdef SQLITE_AMALGAMATION
+const int sqlite3One;
+#else
extern const int sqlite3one;
-#define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0)
-#define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
+#endif
+#if defined(i386) || defined(__i386__) || defined(_M_IX86)
+# define SQLITE_BIGENDIAN 0
+# define SQLITE_LITTLEENDIAN 1
+# define SQLITE_UTF16NATIVE SQLITE_UTF16LE
+#else
+# define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0)
+# define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
+# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
+#endif
/*
** An instance of the following structure is used to store the busy-handler
@@ -235,74 +309,6 @@ struct BusyHandler {
};
/*
-** Defer sourcing vdbe.h and btree.h until after the "u8" and
-** "BusyHandler typedefs.
-*/
-#include "vdbe.h"
-#include "btree.h"
-#include "pager.h"
-
-#ifdef SQLITE_MEMDEBUG
-/*
-** The following global variables are used for testing and debugging
-** only. They only work if SQLITE_MEMDEBUG is defined.
-*/
-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))
-
-#else
-
-#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
-
-#define sqliteFree(x) sqlite3FreeX(x)
-#define sqliteAllocSize(x) sqlite3AllocSize(x)
-
-
-/*
-** An instance of this structure might be allocated to store information
-** specific to a single thread.
-*/
-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
** is a special table that holds the names and attributes of all
** user tables and indices.
@@ -348,7 +354,7 @@ typedef struct NameContext NameContext;
typedef struct Parse Parse;
typedef struct Select Select;
typedef struct SrcList SrcList;
-typedef struct ThreadData ThreadData;
+typedef struct StrAccum StrAccum;
typedef struct Table Table;
typedef struct TableLock TableLock;
typedef struct Token Token;
@@ -359,6 +365,18 @@ typedef struct WhereInfo WhereInfo;
typedef struct WhereLevel WhereLevel;
/*
+** Defer sourcing vdbe.h and btree.h until after the "u8" and
+** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
+** pointer types (i.e. FuncDef) defined above.
+*/
+#include "btree.h"
+#include "vdbe.h"
+#include "pager.h"
+
+#include "os.h"
+#include "mutex.h"
+
+/*
** Each database file to be accessed by the system is an instance
** of the following structure. There are normally two of these structures
** in the sqlite.aDb[] array. aDb[0] is the main database file and
@@ -377,6 +395,14 @@ struct Db {
/*
** An instance of the following structure stores a database schema.
+**
+** If there are no virtual tables configured in this schema, the
+** Schema.db variable is set to NULL. After the first virtual table
+** has been added, it is set to point to the database connection
+** used to create the connection. Once a virtual table has been
+** added to the Schema structure and the Schema.db variable populated,
+** only that database connection may use the Schema to prepare
+** statements.
*/
struct Schema {
int schema_cookie; /* Database schema version number for this file */
@@ -389,6 +415,9 @@ struct Schema {
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 */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ sqlite3 *db; /* "Owner" connection. See comment above */
+#endif
};
/*
@@ -414,7 +443,6 @@ struct Schema {
#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)
/*
** Each database is an instance of the following structure.
@@ -443,12 +471,17 @@ struct Schema {
** consistently.
*/
struct sqlite3 {
+ sqlite3_vfs *pVfs; /* OS Interface */
int nDb; /* Number of backends currently in use */
Db *aDb; /* All backends */
int flags; /* Miscellanous flags. See below */
+ int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
int errCode; /* Most recent error code (SQLITE_*) */
+ int errMask; /* & result codes with this before returning */
u8 autoCommit; /* The auto-commit flag. */
u8 temp_store; /* 1: file 2: memory 0: default */
+ u8 mallocFailed; /* True if we have seen a malloc failure */
+ signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */
int nTable; /* Number of tables in the database */
CollSeq *pDfltColl; /* The default collating sequence (BINARY) */
i64 lastRowid; /* ROWID of most recent insert (see above) */
@@ -456,13 +489,14 @@ struct sqlite3 {
int magic; /* Magic number for detect library misuse */
int nChange; /* Value returned by sqlite3_changes() */
int nTotalChange; /* Value returned by sqlite3_total_changes() */
+ sqlite3_mutex *mutex; /* Connection mutex */
struct sqlite3InitInfo { /* Information used during initialization */
int iDb; /* When back is being initialized */
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 */
+ 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 */
@@ -509,6 +543,7 @@ struct sqlite3 {
#ifdef SQLITE_SSE
sqlite3_stmt *pFetch; /* Used by SSE to fetch stored statements */
#endif
+ u8 dfltLockMode; /* Default locking-mode for attached dbs */
};
/*
@@ -544,6 +579,10 @@ struct sqlite3 {
#define SQLITE_FullFSync 0x00010000 /* Use full fsync on the backend */
#define SQLITE_LoadExtension 0x00020000 /* Enable load_extension */
+#define SQLITE_RecoveryMode 0x00040000 /* Ignore schema errors */
+#define SQLITE_SharedCache 0x00080000 /* Cache sharing is enabled */
+#define SQLITE_Vtab 0x00100000 /* There exists a virtual table */
+
/*
** Possible values for the sqlite.magic field.
** The numbers are obtained at random and have no special meaning, other
@@ -551,6 +590,7 @@ struct sqlite3 {
*/
#define SQLITE_MAGIC_OPEN 0xa029a697 /* Database is open */
#define SQLITE_MAGIC_CLOSED 0x9f3c2d33 /* Database is closed */
+#define SQLITE_MAGIC_SICK 0x4b771290 /* Error and awaiting close */
#define SQLITE_MAGIC_BUSY 0xf03b7906 /* Database currently in use */
#define SQLITE_MAGIC_ERROR 0xb5357930 /* An SQLITE_MISUSE error occurred */
@@ -582,6 +622,7 @@ struct Module {
const sqlite3_module *pModule; /* Callback pointers */
const char *zName; /* Name passed to create_module() */
void *pAux; /* pAux passed to create_module() */
+ void (*xDestroy)(void *); /* Module destructor function */
};
/*
@@ -603,6 +644,9 @@ struct Column {
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 */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ u8 isHidden; /* True if this column is 'hidden' */
+#endif
};
/*
@@ -627,11 +671,12 @@ struct Column {
** collating sequence may not be read or written.
*/
struct CollSeq {
- char *zName; /* Name of the collating sequence, UTF-8 encoded */
- u8 enc; /* Text encoding handled by xCmp() */
- u8 type; /* One of the SQLITE_COLL_... values below */
- void *pUser; /* First argument to xCmp() */
+ char *zName; /* Name of the collating sequence, UTF-8 encoded */
+ u8 enc; /* Text encoding handled by xCmp() */
+ u8 type; /* One of the SQLITE_COLL_... values below */
+ void *pUser; /* First argument to xCmp() */
int (*xCmp)(void*,int, const void*, int, const void*);
+ void (*xDel)(void*); /* Destructor for pUser */
};
/*
@@ -657,7 +702,7 @@ struct CollSeq {
**
** 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.
+** used as the P4 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.
@@ -671,6 +716,20 @@ struct CollSeq {
#define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC)
/*
+** The SQLITE_AFF_MASK values masks off the significant bits of an
+** affinity value.
+*/
+#define SQLITE_AFF_MASK 0x67
+
+/*
+** Additional bit values that can be ORed with an affinity without
+** changing the affinity.
+*/
+#define SQLITE_JUMPIFNULL 0x08 /* jumps if either operand is NULL */
+#define SQLITE_NULLEQUAL 0x10 /* compare NULLs equal */
+#define SQLITE_STOREP2 0x80 /* Store result in reg[P2] rather than jump */
+
+/*
** Each SQL table is represented in memory by an instance of the
** following structure.
**
@@ -731,7 +790,7 @@ struct Table {
int nModuleArg; /* Number of arguments to the module */
char **azModuleArg; /* Text of all module args. [0] is module name */
#endif
- Schema *pSchema;
+ Schema *pSchema; /* Schema that contains this table */
};
/*
@@ -740,9 +799,11 @@ struct Table {
** table support is omitted from the build.
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
-# define IsVirtual(X) ((X)->isVirtual)
+# define IsVirtual(X) ((X)->isVirtual)
+# define IsHiddenColumn(X) ((X)->isHidden)
#else
-# define IsVirtual(X) 0
+# define IsVirtual(X) 0
+# define IsHiddenColumn(X) 0
#endif
/*
@@ -787,7 +848,7 @@ struct FKey {
};
/*
-** SQLite supports many different ways to resolve a contraint
+** SQLite supports many different ways to resolve a constraint
** error. ROLLBACK processing means that a constraint violation
** causes the operation in process to fail and for the current transaction
** to be rolled back. ABORT processing means the operation in process
@@ -836,8 +897,10 @@ struct FKey {
** were larger.
*/
struct KeyInfo {
+ sqlite3 *db; /* The database connection */
u8 enc; /* Text encoding - one of the TEXT_Utf* values */
u8 incrKey; /* Increase 2nd key by epsilon before comparison */
+ u8 prefixIsEqual; /* Treat a prefix as equal */
int nField; /* Number of entries in aColl[] */
u8 *aSortOrder; /* If defined an aSortOrder[i] is true, sort DESC */
CollSeq *aColl[1]; /* Collating sequence for each term of the key */
@@ -921,6 +984,7 @@ struct AggInfo {
ExprList *pGroupBy; /* The group by clause */
int nSortingColumn; /* Number of columns in the sorting index */
struct AggInfo_col { /* For each column used in source tables */
+ Table *pTab; /* Source table */
int iTable; /* Cursor number of the source table */
int iColumn; /* Column number within the source table */
int iSorterColumn; /* Column number in the sorting index */
@@ -1006,7 +1070,10 @@ 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;
+/* Schema *pSchema; */
+#if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0
+ int nHeight; /* Height of the tree headed by this node */
+#endif
};
/*
@@ -1020,6 +1087,7 @@ struct Expr {
#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 */
+#define EP_ExpCollate 0x100 /* Collating sequence specified explicitly */
/*
** These macros can be used to test, set, or clear bits in the
@@ -1077,8 +1145,12 @@ struct IdList {
/*
** The bitmask datatype defined below is used for various optimizations.
+**
+** Changing this from a 64-bit to a 32-bit type limits the number of
+** tables in a join to 32 instead of 64. But it also reduces the size
+** of the library by 738 bytes on ix86.
*/
-typedef unsigned int Bitmask;
+typedef u64 Bitmask;
/*
** The following structure describes the FROM clause of a SELECT statement.
@@ -1090,6 +1162,11 @@ typedef unsigned int Bitmask;
** is modified by an INSERT, DELETE, or UPDATE statement. In standard SQL,
** such a table must be a simple name: ID. But in SQLite, the table can
** now be identified by a database name, a dot, then the table name: ID.ID.
+**
+** The jointype starts out showing the join type between the current table
+** and the next table on the list. The parser builds the list this way.
+** But sqlite3SrcListShiftJoinType() later shifts the jointypes so that each
+** jointype expresses the join between the table and the previous table.
*/
struct SrcList {
i16 nSrc; /* Number of tables or subqueries in the FROM clause */
@@ -1101,8 +1178,8 @@ struct SrcList {
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 */
+ u8 jointype; /* Type of join between this able and the previous */
+ int iCursor; /* The VDBE cursor number used to access this table */
Expr *pOn; /* The ON clause of a join */
IdList *pUsing; /* The USING clause of a join */
Bitmask colUsed; /* Bit N (1<<N) set if column N or pTab is used */
@@ -1148,12 +1225,16 @@ struct WhereLevel {
int iTabCur; /* The VDBE cursor used to access the table */
int iIdxCur; /* The VDBE cursor used to acesss pIdx */
int brk; /* Jump here to break out of the loop */
+ int nxt; /* Jump here to start the next IN combination */
int cont; /* Jump here to continue with the next loop cycle */
int top; /* First instruction of interior of the loop */
int op, p1, p2; /* Opcode used to terminate the loop */
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 */
+ struct InLoop {
+ int iCur; /* The VDBE cursor used by this IN operator */
+ int topAddr; /* Top of the IN loop */
+ } *aInLoop; /* Information about each nested IN operator */
sqlite3_index_info *pBestIdx; /* Index information for this level */
/* The following field is really not part of the current level. But
@@ -1163,6 +1244,10 @@ struct WhereLevel {
sqlite3_index_info *pIdxInfo; /* Index info for n-th source table */
};
+#define ORDERBY_NORMAL 0
+#define ORDERBY_MIN 1
+#define ORDERBY_MAX 2
+
/*
** The WHERE clause processing routine has two halves. The
** first part does the start of the WHERE loop and the second
@@ -1228,7 +1313,7 @@ struct NameContext {
**
** 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 P4_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_OpenEphm instruction is coded because not
** enough information about the compound query is known at that point.
@@ -1244,12 +1329,14 @@ struct Select {
u8 isAgg; /* True if this is an aggregate query */
u8 usesEphm; /* True if uses an OpenEphemeral opcode */
u8 disallowOrderBy; /* Do not allow an ORDER BY to be attached if TRUE */
+ char affinity; /* MakeRecord with this affinity for SRT_Set */
SrcList *pSrc; /* The FROM clause */
Expr *pWhere; /* The WHERE clause */
ExprList *pGroupBy; /* The GROUP BY clause */
Expr *pHaving; /* The HAVING clause */
ExprList *pOrderBy; /* The ORDER BY clause */
Select *pPrior; /* Prior select in a compound select statement */
+ Select *pNext; /* Next select to the left in a compound */
Select *pRightmost; /* Right-most select in a compound select statement */
Expr *pLimit; /* LIMIT expression. NULL means not used. */
Expr *pOffset; /* OFFSET expression. NULL means not used. */
@@ -1262,18 +1349,30 @@ struct Select {
*/
#define SRT_Union 1 /* Store result as keys in an index */
#define SRT_Except 2 /* Remove result from a UNION index */
-#define SRT_Discard 3 /* Do not save the results anywhere */
+#define SRT_Exists 3 /* Store 1 if the result is not empty */
+#define SRT_Discard 4 /* Do not save the results anywhere */
/* The ORDER BY clause is ignored for all of the above */
-#define IgnorableOrderby(X) (X<=SRT_Discard)
+#define IgnorableOrderby(X) ((X->eDest)<=SRT_Discard)
-#define SRT_Callback 4 /* Invoke a callback with each row of result */
-#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_EphemTab 8 /* Create transient tab and store like SRT_Table */
-#define SRT_Subroutine 9 /* Call a subroutine to handle results */
-#define SRT_Exists 10 /* Store 1 if the result is not empty */
+#define SRT_Callback 5 /* Invoke a callback with each row of result */
+#define SRT_Mem 6 /* Store result in a memory cell */
+#define SRT_Set 7 /* Store non-null results as keys in an index */
+#define SRT_Table 8 /* Store result as data with an automatic rowid */
+#define SRT_EphemTab 9 /* Create transient tab and store like SRT_Table */
+#define SRT_Subroutine 10 /* Call a subroutine to handle results */
+
+/*
+** A structure used to customize the behaviour of sqlite3Select(). See
+** comments above sqlite3Select() for details.
+*/
+typedef struct SelectDest SelectDest;
+struct SelectDest {
+ u8 eDest; /* How to dispose of the results */
+ u8 affinity; /* Affinity used when eDest==SRT_Set */
+ int iParm; /* A parameter used by the eDest disposal method */
+ int iMem; /* Base register where results are written */
+};
/*
** An SQL parser context. A copy of this structure is passed through
@@ -1300,16 +1399,21 @@ 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 */
+ u8 parseError; /* True after a parsing error. Ticket #1794 */
+ u8 nTempReg; /* Number of temporary registers in aTempReg[] */
+ u8 nTempInUse; /* Number of aTempReg[] currently checked out */
+ int aTempReg[8]; /* Holding area for temporary registers */
+ int nRangeReg; /* Size of the temporary register block */
+ int iRangeReg; /* First register in temporary register block */
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 */
+ int ckBase; /* Base register of data during 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 */
+ int cookieValue[SQLITE_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 */
@@ -1318,6 +1422,8 @@ struct Parse {
/* Above is constant between recursions. Below is reset before and after
** each recursion */
+ int regRowid; /* Register holding rowid of CREATE TABLE entry */
+ int regRoot; /* Register holding root page number for new objects */
int nVar; /* Number of '?' variables seen in the SQL so far */
int nVarExpr; /* Number of used slots in apVarExpr[] */
int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */
@@ -1337,6 +1443,9 @@ struct Parse {
u8 declareVtab; /* True if inside sqlite3_declare_vtab() */
Table *pVirtualLock; /* Require virtual table lock on this table */
#endif
+#if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0
+ int nHeight; /* Expression tree height of current sub-select */
+#endif
};
#ifdef SQLITE_OMIT_VIRTUALTABLE
@@ -1360,6 +1469,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 */
+#define OPFLAG_APPEND 8 /* This is likely to be an append */
/*
* Each trigger present in the database schema is stored as an instance of
@@ -1384,7 +1494,6 @@ struct Trigger {
Expr *pWhen; /* The WHEN clause of the expresion (may be NULL) */
IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger,
the <column-list> is stored here */
- 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 */
@@ -1446,11 +1555,11 @@ struct TriggerStep {
Trigger *pTrig; /* The trigger that this step is a part of */
Select *pSelect; /* Valid for SELECT and sometimes
- INSERT steps (when pExprList == 0) */
+ INSERT steps (when pExprList == 0) */
Token target; /* Valid for DELETE, UPDATE, INSERT steps */
Expr *pWhere; /* Valid for DELETE, UPDATE steps */
ExprList *pExprList; /* Valid for UPDATE statements and sometimes
- INSERT steps (when pSelect == 0) */
+ INSERT steps (when pSelect == 0) */
IdList *pIdList; /* Valid for INSERT statements only */
TriggerStep *pNext; /* Next in the link-list */
TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */
@@ -1487,6 +1596,8 @@ struct TriggerStack {
Table *pTab; /* Table that triggers are currently being coded on */
int newIdx; /* Index of vdbe cursor to "new" temp table */
int oldIdx; /* Index of vdbe cursor to "old" temp table */
+ u32 newColMask;
+ u32 oldColMask;
int orconf; /* Current orconf policy */
int ignoreJump; /* where to jump to for a RAISE(IGNORE) */
Trigger *pTrigger; /* The trigger currently being coded */
@@ -1507,21 +1618,39 @@ struct DbFixer {
};
/*
+** An objected used to accumulate the text of a string where we
+** do not necessarily know how big the string will be in the end.
+*/
+struct StrAccum {
+ char *zBase; /* A base allocation. Not from malloc. */
+ char *zText; /* The string collected so far */
+ int nChar; /* Length of the string so far */
+ int nAlloc; /* Amount of space allocated in zText */
+ u8 mallocFailed; /* Becomes true if any memory allocation fails */
+ u8 useMalloc; /* True if zText is enlargable using realloc */
+ u8 tooBig; /* Becomes true if string size exceeds limits */
+};
+
+/*
** A pointer to this structure is used to communicate information
** from sqlite3Init and OP_ParseSchema into the sqlite3InitCallback.
*/
typedef struct {
sqlite3 *db; /* The database being initialized */
+ int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */
char **pzErrMsg; /* Error message stored here */
int rc; /* Result code stored here */
} InitData;
/*
- * This global flag is set for performance testing of triggers. When it is set
- * SQLite will perform the overhead of building new and old trigger references
- * even when no triggers exist
- */
-extern int sqlite3_always_code_trigger_setup;
+** Assuming zIn points to the first byte of a UTF-8 character,
+** advance zIn to point to the first byte of the next UTF-8 character.
+*/
+#define SQLITE_SKIP_UTF8(zIn) { \
+ if( (*(zIn++))>=0xc0 ){ \
+ while( (*zIn & 0xc0)==0x80 ){ zIn++; } \
+ } \
+}
/*
** The SQLITE_CORRUPT_BKPT macro can be either a constant (for production
@@ -1530,10 +1659,12 @@ extern int sqlite3_always_code_trigger_setup;
** corruption is first detected.
*/
#ifdef SQLITE_DEBUG
- extern int sqlite3Corrupt(void);
+ int sqlite3Corrupt(void);
# define SQLITE_CORRUPT_BKPT sqlite3Corrupt()
+# define DEBUGONLY(X) X
#else
# define SQLITE_CORRUPT_BKPT SQLITE_CORRUPT
+# define DEBUGONLY(X)
#endif
/*
@@ -1541,52 +1672,53 @@ extern int sqlite3_always_code_trigger_setup;
*/
int sqlite3StrICmp(const char *, const char *);
int sqlite3StrNICmp(const char *, const char *, int);
-int sqlite3HashNoCase(const char *, int);
int sqlite3IsNumber(const char*, int*, u8);
-int sqlite3Compare(const char *, const char *);
-int sqlite3SortCompare(const char *, const char *);
-void sqlite3RealToSortable(double r, char *);
-
-void *sqlite3Malloc(int,int);
-void *sqlite3MallocRaw(int,int);
-void sqlite3Free(void*);
-void *sqlite3Realloc(void*,int);
+
+void *sqlite3MallocZero(unsigned);
+void *sqlite3DbMallocZero(sqlite3*, unsigned);
+void *sqlite3DbMallocRaw(sqlite3*, unsigned);
char *sqlite3StrDup(const char*);
char *sqlite3StrNDup(const char*, int);
-# define sqlite3CheckMemory(a,b)
-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*);
+char *sqlite3DbStrDup(sqlite3*,const char*);
+char *sqlite3DbStrNDup(sqlite3*,const char*, int);
+void *sqlite3DbReallocOrFree(sqlite3 *, void *, int);
+void *sqlite3DbRealloc(sqlite3 *, void *, int);
+
+char *sqlite3MPrintf(sqlite3*,const char*, ...);
+char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
+#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
+ void sqlite3DebugPrintf(const char*, ...);
+#endif
+#if defined(SQLITE_TEST)
+ void *sqlite3TextToPtr(const char*);
+#endif
void sqlite3SetString(char **, ...);
void sqlite3ErrorMsg(Parse*, const char*, ...);
void sqlite3ErrorClear(Parse*);
void sqlite3Dequote(char*);
-void sqlite3DequoteExpr(Expr*);
+void sqlite3DequoteExpr(sqlite3*, Expr*);
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*);
+int sqlite3GetTempReg(Parse*);
+void sqlite3ReleaseTempReg(Parse*,int);
+int sqlite3GetTempRange(Parse*,int);
+void sqlite3ReleaseTempRange(Parse*,int,int);
+Expr *sqlite3Expr(sqlite3*, int, Expr*, Expr*, const Token*);
+Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*, const Token*);
Expr *sqlite3RegisterExpr(Parse*,Token*);
-Expr *sqlite3ExprAnd(Expr*, Expr*);
+Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*);
void sqlite3ExprSpan(Expr*,Token*,Token*);
-Expr *sqlite3ExprFunction(ExprList*, Token*);
+Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*);
void sqlite3ExprAssignVarNumber(Parse*, Expr*);
void sqlite3ExprDelete(Expr*);
-ExprList *sqlite3ExprListAppend(ExprList*,Expr*,Token*);
+ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*,Token*);
void sqlite3ExprListDelete(ExprList*);
int sqlite3Init(sqlite3*, char**);
int sqlite3InitCallback(void*, int, char**, char**);
void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
void sqlite3ResetInternalSchema(sqlite3*, int);
void sqlite3BeginParse(Parse*,int);
-void sqlite3RollbackInternalChanges(sqlite3*);
void sqlite3CommitInternalChanges(sqlite3*);
Table *sqlite3ResultSetOfSelect(Parse*,char*,Select*);
void sqlite3OpenMasterTable(Parse *, int);
@@ -1597,10 +1729,10 @@ 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 sqlite3AddCollateType(Parse*, Token*);
void sqlite3EndTable(Parse*,Token*,Token*,Select*);
-void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int);
+void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
int sqlite3ViewGetColumnNames(Parse*,Table*);
@@ -1609,55 +1741,53 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int);
#endif
void sqlite3DropTable(Parse*, SrcList*, int, int);
-void sqlite3DeleteTable(sqlite3*, Table*);
+void sqlite3DeleteTable(Table*);
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
-int sqlite3ArrayAllocate(void**,int,int);
-IdList *sqlite3IdListAppend(IdList*, Token*);
+void *sqlite3ArrayAllocate(sqlite3*,void*,int,int,int*,int*,int*);
+IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
int sqlite3IdListIndex(IdList*,const char*);
-SrcList *sqlite3SrcListAppend(SrcList*, Token*, Token*);
-void sqlite3SrcListAddAlias(SrcList*, Token*);
+SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*);
+SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, Token*,
+ Select*, Expr*, IdList*);
+void sqlite3SrcListShiftJoinType(SrcList*);
void sqlite3SrcListAssignCursors(Parse*, SrcList*);
void sqlite3IdListDelete(IdList*);
void sqlite3SrcListDelete(SrcList*);
void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
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);
-Select *sqlite3SelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*,
- int,Expr*,Expr*);
+int sqlite3Select(Parse*, Select*, SelectDest*, Select*, int, int*, char *aff);
+Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
+ Expr*,ExprList*,int,Expr*,Expr*);
void sqlite3SelectDelete(Select*);
-void sqlite3SelectUnbind(Select*);
Table *sqlite3SrcListLookup(Parse*, SrcList*);
int sqlite3IsReadOnly(Parse*, 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**);
+WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8);
void sqlite3WhereEnd(WhereInfo*);
-void sqlite3ExprCode(Parse*, Expr*);
-void sqlite3ExprCodeAndCache(Parse*, Expr*);
-int sqlite3ExprCodeExprList(Parse*, ExprList*);
+void sqlite3ExprCodeGetColumn(Vdbe*, Table*, int, int, int);
+int sqlite3ExprCode(Parse*, Expr*, int);
+int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
+int sqlite3ExprCodeAndCache(Parse*, Expr*, int);
+int sqlite3ExprCodeExprList(Parse*, ExprList*, int);
void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
-void sqlite3NextedParse(Parse*, const char*, ...);
Table *sqlite3FindTable(sqlite3*,const char*, const char*);
-Table *sqlite3LocateTable(Parse*,const char*, const char*);
+Table *sqlite3LocateTable(Parse*,int isView,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*);
int sqlite3RunVacuum(char**, sqlite3*);
-char *sqlite3NameFromToken(Token*);
-int sqlite3ExprCheck(Parse*, Expr*, int, int*);
+char *sqlite3NameFromToken(sqlite3*, Token*);
int sqlite3ExprCompare(Expr*, Expr*);
-int sqliteFuncId(Token*);
int sqlite3ExprResolveNames(NameContext *, Expr *);
-int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
-int sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
+void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
+void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
Vdbe *sqlite3GetVdbe(Parse*);
-Expr *sqlite3CreateIdExpr(const char*);
+Expr *sqlite3CreateIdExpr(Parse *, const char*);
void sqlite3Randomness(int, void*);
void sqlite3RollbackAll(sqlite3*);
void sqlite3CodeVerifySchema(Parse*, int);
@@ -1665,65 +1795,76 @@ void sqlite3BeginTransaction(Parse*, int);
void sqlite3CommitTransaction(Parse*);
void sqlite3RollbackTransaction(Parse*);
int sqlite3ExprIsConstant(Expr*);
+int sqlite3ExprIsConstantNotJoin(Expr*);
int sqlite3ExprIsConstantOrFunction(Expr*);
int sqlite3ExprIsInteger(Expr*, int*);
int sqlite3IsRowid(const char*);
-void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int);
-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);
-void sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
+void sqlite3GenerateRowDelete(Parse*, Table*, int, int, int);
+void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int*);
+int sqlite3GenerateIndexKey(Parse*, Index*, int, int);
+void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
+ int*,int,int,int,int);
+void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*,int,int,int,int);
+int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
void sqlite3BeginWriteOperation(Parse*, int, int);
-Expr *sqlite3ExprDup(Expr*);
-void sqlite3TokenCopy(Token*, Token*);
-ExprList *sqlite3ExprListDup(ExprList*);
-SrcList *sqlite3SrcListDup(SrcList*);
-IdList *sqlite3IdListDup(IdList*);
-Select *sqlite3SelectDup(Select*);
+Expr *sqlite3ExprDup(sqlite3*,Expr*);
+void sqlite3TokenCopy(sqlite3*,Token*, Token*);
+ExprList *sqlite3ExprListDup(sqlite3*,ExprList*);
+SrcList *sqlite3SrcListDup(sqlite3*,SrcList*);
+IdList *sqlite3IdListDup(sqlite3*,IdList*);
+Select *sqlite3SelectDup(sqlite3*,Select*);
FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,int);
void sqlite3RegisterBuiltinFunctions(sqlite3*);
void sqlite3RegisterDateTimeFunctions(sqlite3*);
-int sqlite3SafetyOn(sqlite3*);
-int sqlite3SafetyOff(sqlite3*);
-int sqlite3SafetyCheck(sqlite3*);
-void sqlite3ChangeCookie(sqlite3*, Vdbe*, int);
+#ifdef SQLITE_DEBUG
+ int sqlite3SafetyOn(sqlite3*);
+ int sqlite3SafetyOff(sqlite3*);
+#else
+# define sqlite3SafetyOn(A) 0
+# define sqlite3SafetyOff(A) 0
+#endif
+int sqlite3SafetyCheckOk(sqlite3*);
+int sqlite3SafetyCheckSickOrOk(sqlite3*);
+void sqlite3ChangeCookie(Parse*, int);
#ifndef SQLITE_OMIT_TRIGGER
void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*,
- int,Expr*,int);
+ Expr*,int, int);
void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
- void sqlite3DropTrigger(Parse*, SrcList*);
+ void sqlite3DropTrigger(Parse*, SrcList*, int);
void sqlite3DropTriggerPtr(Parse*, Trigger*);
int sqlite3TriggersExist(Parse*, Table*, int, ExprList*);
int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
- int, int);
+ int, int, u32*, u32*);
void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
void sqlite3DeleteTriggerStep(TriggerStep*);
- TriggerStep *sqlite3TriggerSelectStep(Select*);
- TriggerStep *sqlite3TriggerInsertStep(Token*, IdList*, ExprList*,Select*,int);
- TriggerStep *sqlite3TriggerUpdateStep(Token*, ExprList*, Expr*, int);
- TriggerStep *sqlite3TriggerDeleteStep(Token*, Expr*);
+ TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*);
+ TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*,
+ ExprList*,Select*,int);
+ TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, int);
+ TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*);
void sqlite3DeleteTrigger(Trigger*);
void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
+ void sqlite3SelectMask(Parse *, Select *, u32);
#else
# define sqlite3TriggersExist(A,B,C,D,E,F) 0
# define sqlite3DeleteTrigger(A)
# define sqlite3DropTriggerPtr(A,B)
# define sqlite3UnlinkAndDeleteTrigger(A,B,C)
-# define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I) 0
+# define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I,J,K) 0
+# define sqlite3SelectMask(A, B, C)
#endif
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int);
void sqlite3DeferForeignKey(Parse*, int);
#ifndef SQLITE_OMIT_AUTHORIZATION
- void sqlite3AuthRead(Parse*,Expr*,SrcList*);
+ void sqlite3AuthRead(Parse*,Expr*,Schema*,SrcList*);
int sqlite3AuthCheck(Parse*,int, const char*, const char*, const char*);
void sqlite3AuthContextPush(Parse*, AuthContext*, const char*);
void sqlite3AuthContextPop(AuthContext*);
#else
-# define sqlite3AuthRead(a,b,c)
+# define sqlite3AuthRead(a,b,c,d)
# define sqlite3AuthCheck(a,b,c,d,e) SQLITE_OK
# define sqlite3AuthContextPush(a,b,c)
# define sqlite3AuthContextPop(a) ((void)(a))
@@ -1731,7 +1872,7 @@ void sqlite3DeferForeignKey(Parse*, int);
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 omitJournal, int nCache, int flags, Btree **ppBtree);
int sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
int sqlite3FixSrcList(DbFixer*, SrcList*);
int sqlite3FixSelect(DbFixer*, Select*);
@@ -1741,10 +1882,10 @@ int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
int sqlite3AtoF(const char *z, double*);
char *sqlite3_snprintf(int,char*,const char*,...);
int sqlite3GetInt32(const char *, int*);
-int sqlite3FitsIn64Bits(const char *);
-int sqlite3utf16ByteLen(const void *pData, int nChar);
-int sqlite3utf8CharLen(const char *pData, int nByte);
-int sqlite3ReadUtf8(const unsigned char *);
+int sqlite3FitsIn64Bits(const char *, int);
+int sqlite3Utf16ByteLen(const void *pData, int nChar);
+int sqlite3Utf8CharLen(const char *pData, int nByte);
+int sqlite3Utf8Read(const u8*, const u8*, const u8**);
int sqlite3PutVarint(unsigned char *, u64);
int sqlite3GetVarint(const unsigned char *, u64 *);
int sqlite3GetVarint32(const unsigned char *, u32 *);
@@ -1754,31 +1895,32 @@ void sqlite3TableAffinityStr(Vdbe *, Table *);
char sqlite3CompareAffinity(Expr *pExpr, char aff2);
int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
char sqlite3ExprAffinity(Expr *pExpr);
-int sqlite3atoi64(const char*, i64*);
+int sqlite3Atoi64(const char*, i64*);
void sqlite3Error(sqlite3*, int, const char*,...);
-void *sqlite3HexToBlob(const char *z);
+void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
const char *sqlite3ErrStr(int);
-int sqlite3ReadUniChar(const char *zStr, int *pOffset, u8 *pEnc, int fold);
int sqlite3ReadSchema(Parse *pParse);
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char *,int,int);
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName);
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
+Expr *sqlite3ExprSetColl(Parse *pParse, Expr *, Token *);
int sqlite3CheckCollSeq(Parse *, CollSeq *);
-int sqlite3CheckIndexCollSeq(Parse *, Index *);
int sqlite3CheckObjectName(Parse *, const char *);
void sqlite3VdbeSetChanges(sqlite3 *, int);
-void sqlite3utf16Substr(sqlite3_context *,int,sqlite3_value **);
const void *sqlite3ValueText(sqlite3_value*, u8);
int sqlite3ValueBytes(sqlite3_value*, u8);
-void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*));
+void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
+ void(*)(void*));
void sqlite3ValueFree(sqlite3_value*);
-sqlite3_value *sqlite3ValueNew(void);
-char *sqlite3utf16to8(const void*, int);
-int sqlite3ValueFromExpr(Expr *, u8, u8, sqlite3_value **);
+sqlite3_value *sqlite3ValueNew(sqlite3 *);
+char *sqlite3Utf16to8(sqlite3 *, const void*, int);
+int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **);
void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
+#ifndef SQLITE_AMALGAMATION
extern const unsigned char sqlite3UpperToLower[];
+#endif
void sqlite3RootPageMoved(Db*, int, int);
void sqlite3Reindex(Parse*, Token*, Token*);
void sqlite3AlterFunctions(sqlite3*);
@@ -1791,38 +1933,45 @@ int sqlite3SelectResolve(Parse *, Select *, NameContext *);
void sqlite3ColumnDefault(Vdbe *, Table *, int);
void sqlite3AlterFinishAddColumn(Parse *, Token *);
void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
-const char *sqlite3TestErrorName(int);
CollSeq *sqlite3GetCollSeq(sqlite3*, CollSeq *, const char *, int);
char sqlite3AffinityType(const Token*);
void sqlite3Analyze(Parse*, Token*, Token*);
int sqlite3InvokeBusyHandler(BusyHandler*);
int sqlite3FindDb(sqlite3*, Token*);
-void sqlite3AnalysisLoad(sqlite3*,int iDB);
+int 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 *);
+Schema *sqlite3SchemaGet(sqlite3 *, 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 *);
+void sqlite3StrAccumAppend(StrAccum*,const char*,int);
+char *sqlite3StrAccumFinish(StrAccum*);
+void sqlite3StrAccumReset(StrAccum*);
+void sqlite3SelectDestInit(SelectDest*,int,int);
+
+/*
+** The interface to the LEMON-generated parser
+*/
+void *sqlite3ParserAlloc(void*(*)(size_t));
+void sqlite3ParserFree(void*, void(*)(void*));
+void sqlite3Parser(void*, int, Token, Parse*);
+
#ifndef SQLITE_OMIT_LOAD_EXTENSION
void sqlite3CloseExtensions(sqlite3*);
+ int sqlite3AutoLoadExtensions(sqlite3*);
#else
# define sqlite3CloseExtensions(X)
+# define sqlite3AutoLoadExtensions(X) SQLITE_OK
#endif
#ifndef SQLITE_OMIT_SHARED_CACHE
@@ -1831,22 +1980,8 @@ int sqlite3OpenTempDatabase(Parse *);
#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
+#ifdef SQLITE_TEST
+ int sqlite3Utf8To8(unsigned char*);
#endif
#ifdef SQLITE_OMIT_VIRTUALTABLE
@@ -1860,6 +1995,8 @@ int sqlite3OpenTempDatabase(Parse *);
int sqlite3VtabRollback(sqlite3 *db);
int sqlite3VtabCommit(sqlite3 *db);
#endif
+void sqlite3VtabLock(sqlite3_vtab*);
+void sqlite3VtabUnlock(sqlite3*, sqlite3_vtab*);
void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*);
void sqlite3VtabFinishParse(Parse*, Token*);
void sqlite3VtabArgInit(Parse*);
@@ -1868,10 +2005,85 @@ 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*);
+FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
+void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
+int sqlite3Reprepare(Vdbe*);
+void sqlite3ExprListCheckLength(Parse*, ExprList*, int, const char*);
+CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
+
+
+/*
+** Available fault injectors. Should be numbered beginning with 0.
+*/
+#define SQLITE_FAULTINJECTOR_MALLOC 0
+#define SQLITE_FAULTINJECTOR_COUNT 1
+
+/*
+** The interface to the fault injector subsystem. If the fault injector
+** mechanism is disabled at compile-time then set up macros so that no
+** unnecessary code is generated.
+*/
+#ifndef SQLITE_OMIT_FAULTINJECTOR
+ void sqlite3FaultConfig(int,int,int);
+ int sqlite3FaultFailures(int);
+ int sqlite3FaultBenignFailures(int);
+ int sqlite3FaultPending(int);
+ void sqlite3FaultBenign(int,int);
+ int sqlite3FaultStep(int);
+#else
+# define sqlite3FaultConfig(A,B,C)
+# define sqlite3FaultFailures(A) 0
+# define sqlite3FaultBenignFailures(A) 0
+# define sqlite3FaultPending(A) (-1)
+# define sqlite3FaultBenign(A,B)
+# define sqlite3FaultStep(A) 0
+#endif
+
+
+
+#define IN_INDEX_ROWID 1
+#define IN_INDEX_EPH 2
+#define IN_INDEX_INDEX 3
+int sqlite3FindInIndex(Parse *, Expr *, int);
+
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
+ int sqlite3JournalSize(sqlite3_vfs *);
+ int sqlite3JournalCreate(sqlite3_file *);
+#else
+ #define sqlite3JournalSize(pVfs) ((pVfs)->szOsFile)
+#endif
+
+#if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0
+ void sqlite3ExprSetHeight(Expr *);
+ int sqlite3SelectExprHeight(Select *);
+#else
+ #define sqlite3ExprSetHeight(x)
+#endif
+
+u32 sqlite3Get4byte(const u8*);
+void sqlite3Put4byte(u8*, u32);
#ifdef SQLITE_SSE
#include "sseInt.h"
#endif
+#ifdef SQLITE_DEBUG
+ void sqlite3ParserTrace(FILE*, char *);
+#endif
+
+/*
+** If the SQLITE_ENABLE IOTRACE exists then the global variable
+** sqlite3_io_trace is a pointer to a printf-like routine used to
+** print I/O tracing messages.
+*/
+#ifdef SQLITE_ENABLE_IOTRACE
+# define IOTRACE(A) if( sqlite3_io_trace ){ sqlite3_io_trace A; }
+ void sqlite3VdbeIOTraceSql(Vdbe*);
+#else
+# define IOTRACE(A)
+# define sqlite3VdbeIOTraceSql(X)
+#endif
+SQLITE_EXTERN void (*sqlite3_io_trace)(const char*,...);
+
#endif
diff --git a/ext/pdo_sqlite/sqlite/src/sqliteLimit.h b/ext/pdo_sqlite/sqlite/src/sqliteLimit.h
new file mode 100644
index 0000000000..4652e81b8a
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/sqliteLimit.h
@@ -0,0 +1,179 @@
+/*
+** 2007 May 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 defines various limits of what SQLite can process.
+**
+** @(#) $Id$
+*/
+
+/*
+** The maximum length of a TEXT or BLOB in bytes. This also
+** limits the size of a row in a table or index.
+**
+** The hard limit is the ability of a 32-bit signed integer
+** to count the size: 2^31-1 or 2147483647.
+*/
+#ifndef SQLITE_MAX_LENGTH
+# define SQLITE_MAX_LENGTH 1000000000
+#endif
+
+/*
+** This is the maximum number of
+**
+** * Columns in a table
+** * Columns in an index
+** * Columns in a view
+** * Terms in the SET clause of an UPDATE statement
+** * Terms in the result set of a SELECT statement
+** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement.
+** * Terms in the VALUES clause of an INSERT statement
+**
+** The hard upper limit here is 32676. Most database people will
+** tell you that in a well-normalized database, you usually should
+** not have more than a dozen or so columns in any table. And if
+** that is the case, there is no point in having more than a few
+** dozen values in any of the other situations described above.
+*/
+#ifndef SQLITE_MAX_COLUMN
+# define SQLITE_MAX_COLUMN 2000
+#endif
+
+/*
+** The maximum length of a single SQL statement in bytes.
+** A value of zero means there is no limit.
+*/
+#ifndef SQLITE_MAX_SQL_LENGTH
+# define SQLITE_MAX_SQL_LENGTH 0
+#endif
+
+/*
+** The maximum depth of an expression tree. This is limited to
+** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
+** want to place more severe limits on the complexity of an
+** expression. A value of 0 (the default) means do not enforce
+** any limitation on expression tree depth.
+*/
+#ifndef SQLITE_MAX_EXPR_DEPTH
+# define SQLITE_MAX_EXPR_DEPTH 1000
+#endif
+
+/*
+** The maximum number of terms in a compound SELECT statement.
+** The code generator for compound SELECT statements does one
+** level of recursion for each term. A stack overflow can result
+** if the number of terms is too large. In practice, most SQL
+** never has more than 3 or 4 terms. Use a value of 0 to disable
+** any limit on the number of terms in a compount SELECT.
+*/
+#ifndef SQLITE_MAX_COMPOUND_SELECT
+# define SQLITE_MAX_COMPOUND_SELECT 500
+#endif
+
+/*
+** The maximum number of opcodes in a VDBE program.
+** Not currently enforced.
+*/
+#ifndef SQLITE_MAX_VDBE_OP
+# define SQLITE_MAX_VDBE_OP 25000
+#endif
+
+/*
+** The maximum number of arguments to an SQL function.
+*/
+#ifndef SQLITE_MAX_FUNCTION_ARG
+# define SQLITE_MAX_FUNCTION_ARG 100
+#endif
+
+/*
+** The maximum number of in-memory pages to use for the main database
+** table and for temporary tables. The SQLITE_DEFAULT_CACHE_SIZE
+*/
+#ifndef SQLITE_DEFAULT_CACHE_SIZE
+# define SQLITE_DEFAULT_CACHE_SIZE 2000
+#endif
+#ifndef SQLITE_DEFAULT_TEMP_CACHE_SIZE
+# define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500
+#endif
+
+/*
+** The maximum number of attached databases. This must be at least 2
+** in order to support the main database file (0) and the file used to
+** hold temporary tables (1). And it must be less than 32 because
+** we use a bitmask of databases with a u32 in places (for example
+** the Parse.cookieMask field).
+*/
+#ifndef SQLITE_MAX_ATTACHED
+# define SQLITE_MAX_ATTACHED 10
+#endif
+
+
+/*
+** The maximum value of a ?nnn wildcard that the parser will accept.
+*/
+#ifndef SQLITE_MAX_VARIABLE_NUMBER
+# define SQLITE_MAX_VARIABLE_NUMBER 999
+#endif
+
+/* Maximum page size. The upper bound on this value is 32768. This a limit
+** imposed by the necessity of storing the value in a 2-byte unsigned integer
+** and the fact that the page size must be a power of 2.
+*/
+#ifndef SQLITE_MAX_PAGE_SIZE
+# define SQLITE_MAX_PAGE_SIZE 32768
+#endif
+
+
+/*
+** The default size of a database page.
+*/
+#ifndef SQLITE_DEFAULT_PAGE_SIZE
+# define SQLITE_DEFAULT_PAGE_SIZE 1024
+#endif
+#if SQLITE_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
+# undef SQLITE_DEFAULT_PAGE_SIZE
+# define SQLITE_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
+#endif
+
+/*
+** Ordinarily, if no value is explicitly provided, SQLite creates databases
+** with page size SQLITE_DEFAULT_PAGE_SIZE. However, based on certain
+** device characteristics (sector-size and atomic write() support),
+** SQLite may choose a larger value. This constant is the maximum value
+** SQLite will choose on its own.
+*/
+#ifndef SQLITE_MAX_DEFAULT_PAGE_SIZE
+# define SQLITE_MAX_DEFAULT_PAGE_SIZE 8192
+#endif
+#if SQLITE_MAX_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
+# undef SQLITE_MAX_DEFAULT_PAGE_SIZE
+# define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
+#endif
+
+
+/*
+** Maximum number of pages in one database file.
+**
+** This is really just the default value for the max_page_count pragma.
+** This value can be lowered (or raised) at run-time using that the
+** max_page_count macro.
+*/
+#ifndef SQLITE_MAX_PAGE_COUNT
+# define SQLITE_MAX_PAGE_COUNT 1073741823
+#endif
+
+/*
+** Maximum length (in bytes) of the pattern in a LIKE or GLOB
+** operator.
+*/
+#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
+# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000
+#endif
diff --git a/ext/pdo_sqlite/sqlite/src/table.c b/ext/pdo_sqlite/sqlite/src/table.c
index c4e228361f..88a96ee6fd 100644
--- a/ext/pdo_sqlite/sqlite/src/table.c
+++ b/ext/pdo_sqlite/sqlite/src/table.c
@@ -70,17 +70,15 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
if( p->nRow==0 ){
p->nColumn = nCol;
for(i=0; i<nCol; i++){
- if( colv[i]==0 ){
- z = sqlite3_mprintf("");
- }else{
- z = sqlite3_mprintf("%s", colv[i]);
- }
+ z = sqlite3_mprintf("%s", colv[i]);
+ if( z==0 ) goto malloc_failed;
p->azResult[p->nData++] = z;
}
}else if( p->nColumn!=nCol ){
- sqlite3SetString(&p->zErrMsg,
- "sqlite3_get_table() called with two or more incompatible queries",
- (char*)0);
+ sqlite3_free(p->zErrMsg);
+ p->zErrMsg = sqlite3_mprintf(
+ "sqlite3_get_table() called with two or more incompatible queries"
+ );
p->rc = SQLITE_ERROR;
return 1;
}
@@ -92,9 +90,10 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
if( argv[i]==0 ){
z = 0;
}else{
- z = sqlite3_malloc( strlen(argv[i])+1 );
+ int n = strlen(argv[i])+1;
+ z = sqlite3_malloc( n );
if( z==0 ) goto malloc_failed;
- strcpy(z, argv[i]);
+ memcpy(z, argv[i], n);
}
p->azResult[p->nData++] = z;
}
@@ -127,7 +126,7 @@ int sqlite3_get_table(
){
int rc;
TabResult res;
- if( pazResult==0 ){ return SQLITE_ERROR; }
+
*pazResult = 0;
if( pnColumn ) *pnColumn = 0;
if( pnRow ) *pnRow = 0;
@@ -138,27 +137,28 @@ int sqlite3_get_table(
res.nData = 1;
res.nAlloc = 20;
res.rc = SQLITE_OK;
- res.azResult = sqlite3_malloc( sizeof(char*)*res.nAlloc );
- if( res.azResult==0 ) return SQLITE_NOMEM;
+ res.azResult = sqlite3_malloc(sizeof(char*)*res.nAlloc );
+ if( res.azResult==0 ){
+ db->errCode = SQLITE_NOMEM;
+ 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 ){
+ assert( sizeof(res.azResult[0])>= sizeof(res.nData) );
+ res.azResult[0] = (char*)res.nData;
+ if( (rc&0xff)==SQLITE_ABORT ){
sqlite3_free_table(&res.azResult[1]);
if( res.zErrMsg ){
if( pzErrMsg ){
sqlite3_free(*pzErrMsg);
*pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg);
}
- sqliteFree(res.zErrMsg);
+ sqlite3_free(res.zErrMsg);
}
- db->errCode = res.rc;
+ db->errCode = res.rc; /* Assume 32-bit assignment is atomic */
return res.rc;
}
- sqliteFree(res.zErrMsg);
+ sqlite3_free(res.zErrMsg);
if( rc!=SQLITE_OK ){
sqlite3_free_table(&res.azResult[1]);
return rc;
@@ -168,6 +168,7 @@ int sqlite3_get_table(
azNew = sqlite3_realloc( res.azResult, sizeof(char*)*(res.nData+1) );
if( azNew==0 ){
sqlite3_free_table(&res.azResult[1]);
+ db->errCode = SQLITE_NOMEM;
return SQLITE_NOMEM;
}
res.nAlloc = res.nData+1;
@@ -188,7 +189,7 @@ void sqlite3_free_table(
if( azResult ){
int i, n;
azResult--;
- if( azResult==0 ) return;
+ assert( azResult!=0 );
n = (int)azResult[0];
for(i=1; i<n; i++){ if( azResult[i] ) sqlite3_free(azResult[i]); }
sqlite3_free(azResult);
diff --git a/ext/pdo_sqlite/sqlite/src/tclsqlite.c b/ext/pdo_sqlite/sqlite/src/tclsqlite.c
index 8572b7cf65..5a10614f13 100644
--- a/ext/pdo_sqlite/sqlite/src/tclsqlite.c
+++ b/ext/pdo_sqlite/sqlite/src/tclsqlite.c
@@ -9,19 +9,25 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
-** A TCL Interface to SQLite
+** A TCL Interface to SQLite. Append this file to sqlite3.c and
+** compile the whole thing to build a TCL-enabled version of SQLite.
**
** $Id$
*/
-#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
-
-#include "sqliteInt.h"
-#include "hash.h"
#include "tcl.h"
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
+#include <errno.h>
+
+/*
+** Some additional include files are needed if this file is not
+** appended to the amalgamation.
+*/
+#ifndef SQLITE_AMALGAMATION
+# include "sqliteInt.h"
+# include <stdlib.h>
+# include <string.h>
+# include <assert.h>
+# include <ctype.h>
+#endif
/*
* Windows needs to know which symbols to export. Unix does not.
@@ -79,9 +85,11 @@ struct SqlPreparedStmt {
SqlPreparedStmt *pPrev; /* Previous on the list */
sqlite3_stmt *pStmt; /* The prepared statement */
int nSql; /* chars in zSql[] */
- char zSql[1]; /* Text of the SQL statement */
+ const char *zSql; /* Text of the SQL statement */
};
+typedef struct IncrblobChannel IncrblobChannel;
+
/*
** There is one instance of this structure for each SQLite database
** that has been opened by the SQLite TCL interface.
@@ -107,8 +115,238 @@ struct SqliteDb {
SqlPreparedStmt *stmtLast; /* Last statement in the list */
int maxStmt; /* The next maximum number of stmtList */
int nStmt; /* Number of statements in stmtList */
+ IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */
};
+struct IncrblobChannel {
+ sqlite3_blob *pBlob; /* sqlite3 blob handle */
+ SqliteDb *pDb; /* Associated database connection */
+ int iSeek; /* Current seek offset */
+ Tcl_Channel channel; /* Channel identifier */
+ IncrblobChannel *pNext; /* Linked list of all open incrblob channels */
+ IncrblobChannel *pPrev; /* Linked list of all open incrblob channels */
+};
+
+#ifndef SQLITE_OMIT_INCRBLOB
+/*
+** Close all incrblob channels opened using database connection pDb.
+** This is called when shutting down the database connection.
+*/
+static void closeIncrblobChannels(SqliteDb *pDb){
+ IncrblobChannel *p;
+ IncrblobChannel *pNext;
+
+ for(p=pDb->pIncrblob; p; p=pNext){
+ pNext = p->pNext;
+
+ /* Note: Calling unregister here call Tcl_Close on the incrblob channel,
+ ** which deletes the IncrblobChannel structure at *p. So do not
+ ** call Tcl_Free() here.
+ */
+ Tcl_UnregisterChannel(pDb->interp, p->channel);
+ }
+}
+
+/*
+** Close an incremental blob channel.
+*/
+static int incrblobClose(ClientData instanceData, Tcl_Interp *interp){
+ IncrblobChannel *p = (IncrblobChannel *)instanceData;
+ int rc = sqlite3_blob_close(p->pBlob);
+ sqlite3 *db = p->pDb->db;
+
+ /* Remove the channel from the SqliteDb.pIncrblob list. */
+ if( p->pNext ){
+ p->pNext->pPrev = p->pPrev;
+ }
+ if( p->pPrev ){
+ p->pPrev->pNext = p->pNext;
+ }
+ if( p->pDb->pIncrblob==p ){
+ p->pDb->pIncrblob = p->pNext;
+ }
+
+ /* Free the IncrblobChannel structure */
+ Tcl_Free((char *)p);
+
+ if( rc!=SQLITE_OK ){
+ Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+** Read data from an incremental blob channel.
+*/
+static int incrblobInput(
+ ClientData instanceData,
+ char *buf,
+ int bufSize,
+ int *errorCodePtr
+){
+ IncrblobChannel *p = (IncrblobChannel *)instanceData;
+ int nRead = bufSize; /* Number of bytes to read */
+ int nBlob; /* Total size of the blob */
+ int rc; /* sqlite error code */
+
+ nBlob = sqlite3_blob_bytes(p->pBlob);
+ if( (p->iSeek+nRead)>nBlob ){
+ nRead = nBlob-p->iSeek;
+ }
+ if( nRead<=0 ){
+ return 0;
+ }
+
+ rc = sqlite3_blob_read(p->pBlob, (void *)buf, nRead, p->iSeek);
+ if( rc!=SQLITE_OK ){
+ *errorCodePtr = rc;
+ return -1;
+ }
+
+ p->iSeek += nRead;
+ return nRead;
+}
+
+/*
+** Write data to an incremental blob channel.
+*/
+static int incrblobOutput(
+ ClientData instanceData,
+ CONST char *buf,
+ int toWrite,
+ int *errorCodePtr
+){
+ IncrblobChannel *p = (IncrblobChannel *)instanceData;
+ int nWrite = toWrite; /* Number of bytes to write */
+ int nBlob; /* Total size of the blob */
+ int rc; /* sqlite error code */
+
+ nBlob = sqlite3_blob_bytes(p->pBlob);
+ if( (p->iSeek+nWrite)>nBlob ){
+ *errorCodePtr = EINVAL;
+ return -1;
+ }
+ if( nWrite<=0 ){
+ return 0;
+ }
+
+ rc = sqlite3_blob_write(p->pBlob, (void *)buf, nWrite, p->iSeek);
+ if( rc!=SQLITE_OK ){
+ *errorCodePtr = EIO;
+ return -1;
+ }
+
+ p->iSeek += nWrite;
+ return nWrite;
+}
+
+/*
+** Seek an incremental blob channel.
+*/
+static int incrblobSeek(
+ ClientData instanceData,
+ long offset,
+ int seekMode,
+ int *errorCodePtr
+){
+ IncrblobChannel *p = (IncrblobChannel *)instanceData;
+
+ switch( seekMode ){
+ case SEEK_SET:
+ p->iSeek = offset;
+ break;
+ case SEEK_CUR:
+ p->iSeek += offset;
+ break;
+ case SEEK_END:
+ p->iSeek = sqlite3_blob_bytes(p->pBlob) + offset;
+ break;
+
+ default: assert(!"Bad seekMode");
+ }
+
+ return p->iSeek;
+}
+
+
+static void incrblobWatch(ClientData instanceData, int mode){
+ /* NO-OP */
+}
+static int incrblobHandle(ClientData instanceData, int dir, ClientData *hPtr){
+ return TCL_ERROR;
+}
+
+static Tcl_ChannelType IncrblobChannelType = {
+ "incrblob", /* typeName */
+ TCL_CHANNEL_VERSION_2, /* version */
+ incrblobClose, /* closeProc */
+ incrblobInput, /* inputProc */
+ incrblobOutput, /* outputProc */
+ incrblobSeek, /* seekProc */
+ 0, /* setOptionProc */
+ 0, /* getOptionProc */
+ incrblobWatch, /* watchProc (this is a no-op) */
+ incrblobHandle, /* getHandleProc (always returns error) */
+ 0, /* close2Proc */
+ 0, /* blockModeProc */
+ 0, /* flushProc */
+ 0, /* handlerProc */
+ 0, /* wideSeekProc */
+};
+
+/*
+** Create a new incrblob channel.
+*/
+static int createIncrblobChannel(
+ Tcl_Interp *interp,
+ SqliteDb *pDb,
+ const char *zDb,
+ const char *zTable,
+ const char *zColumn,
+ sqlite_int64 iRow,
+ int isReadonly
+){
+ IncrblobChannel *p;
+ sqlite3 *db = pDb->db;
+ sqlite3_blob *pBlob;
+ int rc;
+ int flags = TCL_READABLE|(isReadonly ? 0 : TCL_WRITABLE);
+
+ /* This variable is used to name the channels: "incrblob_[incr count]" */
+ static int count = 0;
+ char zChannel[64];
+
+ rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRow, !isReadonly, &pBlob);
+ if( rc!=SQLITE_OK ){
+ Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
+ return TCL_ERROR;
+ }
+
+ p = (IncrblobChannel *)Tcl_Alloc(sizeof(IncrblobChannel));
+ p->iSeek = 0;
+ p->pBlob = pBlob;
+
+ sqlite3_snprintf(sizeof(zChannel), zChannel, "incrblob_%d", ++count);
+ p->channel = Tcl_CreateChannel(&IncrblobChannelType, zChannel, p, flags);
+ Tcl_RegisterChannel(interp, p->channel);
+
+ /* Link the new channel into the SqliteDb.pIncrblob list. */
+ p->pNext = pDb->pIncrblob;
+ p->pPrev = 0;
+ if( p->pNext ){
+ p->pNext->pPrev = p;
+ }
+ pDb->pIncrblob = p;
+ p->pDb = pDb;
+
+ Tcl_SetResult(interp, (char *)Tcl_GetChannelName(p->channel), TCL_VOLATILE);
+ return TCL_OK;
+}
+#else /* else clause for "#ifndef SQLITE_OMIT_INCRBLOB" */
+ #define closeIncrblobChannels(pDb)
+#endif
+
/*
** Look at the script prefix in pCmd. We will be executing this script
** after first appending one or more arguments. This routine analyzes
@@ -184,6 +422,7 @@ static void flushStmtCache( SqliteDb *pDb ){
static void DbDeleteCmd(void *db){
SqliteDb *pDb = (SqliteDb*)db;
flushStmtCache(pDb);
+ closeIncrblobChannels(pDb);
sqlite3_close(pDb->db);
while( pDb->pFunc ){
SqlFunc *pFunc = pDb->pFunc;
@@ -232,7 +471,7 @@ static int DbBusyHandler(void *cd, int nTries){
int rc;
char zVal[30];
- sprintf(zVal, "%d", nTries);
+ sqlite3_snprintf(sizeof(zVal), zVal, "%d", nTries);
rc = Tcl_VarEval(pDb->interp, pDb->zBusy, " ", zVal, (char*)0);
if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
return 0;
@@ -481,15 +720,15 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
** has no string representation. */
data = Tcl_GetByteArrayFromObj(pVar, &n);
sqlite3_result_blob(context, data, n, SQLITE_TRANSIENT);
- }else if( (c=='b' && strcmp(zType,"boolean")==0) ||
- (c=='i' && strcmp(zType,"int")==0) ){
+ }else if( c=='b' && strcmp(zType,"boolean")==0 ){
Tcl_GetIntFromObj(0, pVar, &n);
sqlite3_result_int(context, n);
}else if( c=='d' && strcmp(zType,"double")==0 ){
double r;
Tcl_GetDoubleFromObj(0, pVar, &r);
sqlite3_result_double(context, r);
- }else if( c=='w' && strcmp(zType,"wideInt")==0 ){
+ }else if( (c=='w' && strcmp(zType,"wideInt")==0) ||
+ (c=='i' && strcmp(zType,"int")==0) ){
Tcl_WideInt v;
Tcl_GetWideIntFromObj(0, pVar, &v);
sqlite3_result_int64(context, v);
@@ -553,6 +792,7 @@ static int auth_callback(
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;
+ case SQLITE_FUNCTION : zCode="SQLITE_FUNCTION"; break;
default : zCode="????"; break;
}
Tcl_DStringInit(&str);
@@ -646,6 +886,67 @@ static char *local_getline(char *zPrompt, FILE *in){
return zLine;
}
+
+/*
+** Figure out the column names for the data returned by the statement
+** passed as the second argument.
+**
+** If parameter papColName is not NULL, then *papColName is set to point
+** at an array allocated using Tcl_Alloc(). It is the callers responsibility
+** to free this array using Tcl_Free(), and to decrement the reference
+** count of each Tcl_Obj* member of the array.
+**
+** The return value of this function is the number of columns of data
+** returned by pStmt (and hence the size of the *papColName array).
+**
+** If pArray is not NULL, then it contains the name of a Tcl array
+** variable. The "*" member of this array is set to a list containing
+** the names of the columns returned by the statement, in order from
+** left to right. e.g. if the names of the returned columns are a, b and
+** c, it does the equivalent of the tcl command:
+**
+** set ${pArray}(*) {a b c}
+*/
+static int
+computeColumnNames(
+ Tcl_Interp *interp,
+ sqlite3_stmt *pStmt, /* SQL statement */
+ Tcl_Obj ***papColName, /* OUT: Array of column names */
+ Tcl_Obj *pArray /* Name of array variable (may be null) */
+){
+ int nCol;
+
+ /* Compute column names */
+ nCol = sqlite3_column_count(pStmt);
+ if( papColName ){
+ int i;
+ Tcl_Obj **apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol );
+ for(i=0; i<nCol; i++){
+ apColName[i] = dbTextToObj(sqlite3_column_name(pStmt,i));
+ Tcl_IncrRefCount(apColName[i]);
+ }
+
+ /* If results are being stored in an array variable, then create
+ ** the array(*) entry for that array
+ */
+ if( pArray ){
+ Tcl_Obj *pColList = Tcl_NewObj();
+ Tcl_Obj *pStar = Tcl_NewStringObj("*", -1);
+ Tcl_IncrRefCount(pColList);
+ for(i=0; i<nCol; i++){
+ Tcl_ListObjAppendElement(interp, pColList, apColName[i]);
+ }
+ Tcl_IncrRefCount(pStar);
+ Tcl_ObjSetVar2(interp, pArray, pStar, pColList,0);
+ Tcl_DecrRefCount(pColList);
+ Tcl_DecrRefCount(pStar);
+ }
+ *papColName = apColName;
+ }
+
+ return nCol;
+}
+
/*
** The "sqlite" command below creates a new Tcl command for each
** connection it opens to an SQLite database. This routine is invoked
@@ -669,11 +970,12 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
"collation_needed", "commit_hook", "complete",
"copy", "enable_load_extension","errorcode",
"eval", "exists", "function",
- "interrupt", "last_insert_rowid", "nullvalue",
- "onecolumn", "profile", "progress",
- "rekey", "rollback_hook", "timeout",
- "total_changes", "trace", "transaction",
- "update_hook", "version", 0
+ "incrblob", "interrupt", "last_insert_rowid",
+ "nullvalue", "onecolumn", "profile",
+ "progress", "rekey", "rollback_hook",
+ "timeout", "total_changes", "trace",
+ "transaction", "update_hook", "version",
+ 0
};
enum DB_enum {
DB_AUTHORIZER, DB_BUSY, DB_CACHE,
@@ -681,11 +983,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE,
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_ROLLBACK_HOOK, DB_TIMEOUT,
- DB_TOTAL_CHANGES, DB_TRACE, DB_TRANSACTION,
- DB_UPDATE_HOOK, DB_VERSION,
+ DB_INCRBLOB, DB_INTERRUPT, DB_LAST_INSERT_ROWID,
+ DB_NULLVALUE, DB_ONECOLUMN, DB_PROFILE,
+ DB_PROGRESS, 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 */
@@ -738,7 +1040,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
zAuth = Tcl_GetStringFromObj(objv[2], &len);
if( zAuth && len>0 ){
pDb->zAuth = Tcl_Alloc( len + 1 );
- strcpy(pDb->zAuth, zAuth);
+ memcpy(pDb->zAuth, zAuth, len+1);
}else{
pDb->zAuth = 0;
}
@@ -775,7 +1077,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
zBusy = Tcl_GetStringFromObj(objv[2], &len);
if( zBusy && len>0 ){
pDb->zBusy = Tcl_Alloc( len + 1 );
- strcpy(pDb->zBusy, zBusy);
+ memcpy(pDb->zBusy, zBusy, len+1);
}else{
pDb->zBusy = 0;
}
@@ -832,7 +1134,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
}else{
Tcl_AppendResult( interp, "bad option \"",
- Tcl_GetStringFromObj(objv[0],0), "\": must be flush or size", 0);
+ Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size", 0);
return TCL_ERROR;
}
break;
@@ -887,7 +1189,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
pCollate->pNext = pDb->pCollate;
pCollate->zScript = (char*)&pCollate[1];
pDb->pCollate = pCollate;
- strcpy(pCollate->zScript, zScript);
+ memcpy(pCollate->zScript, zScript, nScript+1);
if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8,
pCollate, tclSqlCollate) ){
Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
@@ -940,7 +1242,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
zCommit = Tcl_GetStringFromObj(objv[2], &len);
if( zCommit && len>0 ){
pDb->zCommit = Tcl_Alloc( len + 1 );
- strcpy(pDb->zCommit, zCommit);
+ memcpy(pDb->zCommit, zCommit, len+1);
}else{
pDb->zCommit = 0;
}
@@ -1035,7 +1337,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
nSep = strlen(zSep);
nNull = strlen(zNull);
if( nSep==0 ){
- Tcl_AppendResult(interp, "Error: non-null separator required for copy", 0);
+ Tcl_AppendResult(interp,"Error: non-null separator required for copy",0);
return TCL_ERROR;
}
if(sqlite3StrICmp(zConflict, "rollback") != 0 &&
@@ -1054,7 +1356,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
return TCL_ERROR;
}
nByte = strlen(zSql);
- rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
+ rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc ){
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
@@ -1080,7 +1382,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
zSql[j++] = ')';
zSql[j] = 0;
- rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
+ rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0);
free(zSql);
if( rc ){
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
@@ -1118,9 +1420,10 @@ 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));
+ int nErr = strlen(zFile) + 200;
+ zErr = malloc(nErr);
if( zErr ){
- sprintf(zErr,
+ sqlite3_snprintf(nErr, zErr,
"Error: %s line %d: expected %d columns of data but found %d",
zFile, lineno, nCol, i+1);
Tcl_AppendResult(interp, zErr, 0);
@@ -1158,7 +1461,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
rc = TCL_OK;
}else{
/* failure, append lineno where failed */
- sprintf(zLineNum,"%d",lineno);
+ sqlite3_snprintf(sizeof(zLineNum), zLineNum,"%d",lineno);
Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,0);
rc = TCL_ERROR;
}
@@ -1172,6 +1475,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** default.
*/
case DB_ENABLE_LOAD_EXTENSION: {
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
int onoff;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "BOOLEAN");
@@ -1182,6 +1486,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
sqlite3_enable_load_extension(pDb->db, onoff);
break;
+#else
+ Tcl_AppendResult(interp, "extension loading is turned off at compile-time",
+ 0);
+ return TCL_ERROR;
+#endif
}
/*
@@ -1258,7 +1567,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
while( rc==TCL_OK && zSql[0] ){
int i; /* Loop counter */
int nVar; /* Number of bind parameters in the pStmt */
- int nCol; /* Number of columns in the result set */
+ int nCol = -1; /* Number of columns in the result set */
Tcl_Obj **apColName = 0; /* Array of column names */
int len; /* String length of zSql */
@@ -1266,13 +1575,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** which matches the next sequence of SQL.
*/
pStmt = 0;
- pPreStmt = pDb->stmtList;
len = strlen(zSql);
- if( pPreStmt && sqlite3_expired(pPreStmt->pStmt) ){
- flushStmtCache(pDb);
- pPreStmt = 0;
- }
- for(; pPreStmt; pPreStmt=pPreStmt->pNext){
+ for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){
int n = pPreStmt->nSql;
if( len>=n
&& memcmp(pPreStmt->zSql, zSql, n)==0
@@ -1303,7 +1607,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
/* If no prepared statement was found. Compile the SQL text
*/
if( pStmt==0 ){
- if( SQLITE_OK!=sqlite3_prepare(pDb->db, zSql, -1, &pStmt, &zLeft) ){
+ if( SQLITE_OK!=sqlite3_prepare_v2(pDb->db, zSql, -1, &pStmt, &zLeft) ){
Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
rc = TCL_ERROR;
break;
@@ -1337,29 +1641,31 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
for(i=1; i<=nVar; i++){
const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
- if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':') ){
+ if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':' || zVar[0]=='@') ){
Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0);
if( pVar ){
int n;
u8 *data;
char *zType = pVar->typePtr ? pVar->typePtr->name : "";
char c = zType[0];
- if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){
- /* Only load a BLOB type if the Tcl variable is a bytearray and
- ** has no string representation. */
+ if( zVar[0]=='@' ||
+ (c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0) ){
+ /* Load a BLOB type if the Tcl variable is a bytearray and
+ ** it has no string representation or the host
+ ** parameter name begins with "@". */
data = Tcl_GetByteArrayFromObj(pVar, &n);
sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC);
Tcl_IncrRefCount(pVar);
apParm[nParm++] = pVar;
- }else if( (c=='b' && strcmp(zType,"boolean")==0) ||
- (c=='i' && strcmp(zType,"int")==0) ){
+ }else if( c=='b' && strcmp(zType,"boolean")==0 ){
Tcl_GetIntFromObj(interp, pVar, &n);
sqlite3_bind_int(pStmt, i, n);
}else if( c=='d' && strcmp(zType,"double")==0 ){
double r;
Tcl_GetDoubleFromObj(interp, pVar, &r);
sqlite3_bind_double(pStmt, i, r);
- }else if( c=='w' && strcmp(zType,"wideInt")==0 ){
+ }else if( (c=='w' && strcmp(zType,"wideInt")==0) ||
+ (c=='i' && strcmp(zType,"int")==0) ){
Tcl_WideInt v;
Tcl_GetWideIntFromObj(interp, pVar, &v);
sqlite3_bind_int64(pStmt, i, v);
@@ -1375,35 +1681,20 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
}
- /* Compute column names */
- nCol = sqlite3_column_count(pStmt);
- if( pScript ){
- apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol );
- if( apColName==0 ) break;
- for(i=0; i<nCol; i++){
- apColName[i] = dbTextToObj(sqlite3_column_name(pStmt,i));
- Tcl_IncrRefCount(apColName[i]);
- }
- }
-
- /* If results are being stored in an array variable, then create
- ** the array(*) entry for that array
- */
- if( pArray ){
- Tcl_Obj *pColList = Tcl_NewObj();
- Tcl_Obj *pStar = Tcl_NewStringObj("*", -1);
- Tcl_IncrRefCount(pColList);
- for(i=0; i<nCol; i++){
- Tcl_ListObjAppendElement(interp, pColList, apColName[i]);
- }
- Tcl_ObjSetVar2(interp, pArray, pStar, pColList,0);
- Tcl_DecrRefCount(pColList);
- Tcl_DecrRefCount(pStar);
- }
-
/* Execute the SQL
*/
while( rc==TCL_OK && pStmt && SQLITE_ROW==sqlite3_step(pStmt) ){
+
+ /* Compute column names. This must be done after the first successful
+ ** call to sqlite3_step(), in case the query is recompiled and the
+ ** number or names of the returned columns changes.
+ */
+ assert(!pArray||pScript);
+ if (nCol < 0) {
+ Tcl_Obj ***ap = (pScript?&apColName:0);
+ nCol = computeColumnNames(interp, pStmt, ap, pArray);
+ }
+
for(i=0; i<nCol; i++){
Tcl_Obj *pVal;
@@ -1476,6 +1767,14 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
/* Free the column name objects */
if( pScript ){
+ /* If the query returned no rows, but an array variable was
+ ** specified, call computeColumnNames() now to populate the
+ ** arrayname(*) variable.
+ */
+ if (pArray && nCol < 0) {
+ Tcl_Obj ***ap = (pScript?&apColName:0);
+ nCol = computeColumnNames(interp, pStmt, ap, pArray);
+ }
for(i=0; i<nCol; i++){
Tcl_DecrRefCount(apColName[i]);
}
@@ -1494,15 +1793,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** flush the statement cache and try the statement again.
*/
rc2 = sqlite3_reset(pStmt);
- if( SQLITE_SCHEMA==rc2 ){
- /* After a schema change, flush the cache and try to run the
- ** statement again
- */
- flushStmtCache( pDb );
- sqlite3_finalize(pStmt);
- if( pPreStmt ) Tcl_Free((char*)pPreStmt);
- continue;
- }else if( SQLITE_OK!=rc2 ){
+ if( SQLITE_OK!=rc2 ){
/* If a run-time error occurs, report the error and stop reading
** the SQL
*/
@@ -1522,12 +1813,13 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
*/
if( pPreStmt==0 ){
len = zLeft - zSql;
- pPreStmt = (SqlPreparedStmt*)Tcl_Alloc( sizeof(*pPreStmt) + len );
+ pPreStmt = (SqlPreparedStmt*)Tcl_Alloc( sizeof(*pPreStmt) );
if( pPreStmt==0 ) return TCL_ERROR;
pPreStmt->pStmt = pStmt;
pPreStmt->nSql = len;
- memcpy(pPreStmt->zSql, zSql, len);
- pPreStmt->zSql[len] = 0;
+ pPreStmt->zSql = sqlite3_sql(pStmt);
+ assert( strlen(pPreStmt->zSql)==len );
+ assert( 0==memcmp(pPreStmt->zSql, zSql, len) );
}
/* Add the prepared statement to the beginning of the cache list
@@ -1603,14 +1895,51 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
if( rc!=SQLITE_OK ){
rc = TCL_ERROR;
Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
- }else{
- /* Must flush any cached statements */
- flushStmtCache( pDb );
}
break;
}
/*
+ ** $db incrblob ?-readonly? ?DB? TABLE COLUMN ROWID
+ */
+ case DB_INCRBLOB: {
+#ifdef SQLITE_OMIT_INCRBLOB
+ Tcl_AppendResult(interp, "incrblob not available in this build", 0);
+ return TCL_ERROR;
+#else
+ int isReadonly = 0;
+ const char *zDb = "main";
+ const char *zTable;
+ const char *zColumn;
+ sqlite_int64 iRow;
+
+ /* Check for the -readonly option */
+ if( objc>3 && strcmp(Tcl_GetString(objv[2]), "-readonly")==0 ){
+ isReadonly = 1;
+ }
+
+ if( objc!=(5+isReadonly) && objc!=(6+isReadonly) ){
+ Tcl_WrongNumArgs(interp, 2, objv, "?-readonly? ?DB? TABLE COLUMN ROWID");
+ return TCL_ERROR;
+ }
+
+ if( objc==(6+isReadonly) ){
+ zDb = Tcl_GetString(objv[2]);
+ }
+ zTable = Tcl_GetString(objv[objc-3]);
+ zColumn = Tcl_GetString(objv[objc-2]);
+ rc = Tcl_GetWideIntFromObj(interp, objv[objc-1], &iRow);
+
+ if( rc==TCL_OK ){
+ rc = createIncrblobChannel(
+ interp, pDb, zDb, zTable, zColumn, iRow, isReadonly
+ );
+ }
+#endif
+ break;
+ }
+
+ /*
** $db interrupt
**
** Interrupt the execution of the inner-most SQL interpreter. This
@@ -1689,7 +2018,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
int len;
int N;
if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){
- return TCL_ERROR;
+ return TCL_ERROR;
};
if( pDb->zProgress ){
Tcl_Free(pDb->zProgress);
@@ -1697,7 +2026,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
zProgress = Tcl_GetStringFromObj(objv[3], &len);
if( zProgress && len>0 ){
pDb->zProgress = Tcl_Alloc( len + 1 );
- strcpy(pDb->zProgress, zProgress);
+ memcpy(pDb->zProgress, zProgress, len+1);
}else{
pDb->zProgress = 0;
}
@@ -1739,7 +2068,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
zProfile = Tcl_GetStringFromObj(objv[2], &len);
if( zProfile && len>0 ){
pDb->zProfile = Tcl_Alloc( len + 1 );
- strcpy(pDb->zProfile, zProfile);
+ memcpy(pDb->zProfile, zProfile, len+1);
}else{
pDb->zProfile = 0;
}
@@ -1834,7 +2163,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
zTrace = Tcl_GetStringFromObj(objv[2], &len);
if( zTrace && len>0 ){
pDb->zTrace = Tcl_Alloc( len + 1 );
- strcpy(pDb->zTrace, zTrace);
+ memcpy(pDb->zTrace, zTrace, len+1);
}else{
pDb->zTrace = 0;
}
@@ -1902,7 +2231,9 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
} else {
zEnd = "COMMIT";
}
- (void)sqlite3_exec(pDb->db, zEnd, 0, 0, 0);
+ if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){
+ sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0);
+ }
}
break;
}
@@ -1964,7 +2295,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
/*
-** sqlite3 DBNAME FILENAME ?MODE? ?-key KEY?
+** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN?
+** ?-create BOOLEAN?
**
** This is the main Tcl command. When the "sqlite" Tcl command is
** invoked, this routine runs to process that command.
@@ -1974,25 +2306,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** DBNAME that is used to control that connection. The database
** connection is deleted when the DBNAME command is deleted.
**
-** The second argument is the name of the directory that contains
-** the sqlite database that is to be accessed.
-**
-** For testing purposes, we also support the following:
-**
-** sqlite3 -encoding
-**
-** Return the encoding used by LIKE and GLOB operators. Choices
-** are UTF-8 and iso8859.
-**
-** sqlite3 -version
+** The second argument is the name of the database file.
**
-** Return the version number of the SQLite library.
-**
-** sqlite3 -tcl-uses-utf
-**
-** Return "1" if compiled with a Tcl uses UTF-8. Return "0" if
-** not. Used by tests to make sure the library was compiled
-** correctly.
*/
static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
SqliteDb *p;
@@ -2000,7 +2315,11 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
int nKey = 0;
const char *zArg;
char *zErrMsg;
+ int i;
const char *zFile;
+ const char *zVfs = 0;
+ int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
+ Tcl_DString translatedFilename;
if( objc==2 ){
zArg = Tcl_GetStringFromObj(objv[1], 0);
if( strcmp(zArg,"-version")==0 ){
@@ -2015,28 +2334,42 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
#endif
return TCL_OK;
}
- if( strcmp(zArg,"-tcl-uses-utf")==0 ){
-#ifdef TCL_UTF_MAX
- Tcl_AppendResult(interp,"1",0);
-#else
- Tcl_AppendResult(interp,"0",0);
-#endif
- return TCL_OK;
- }
}
- if( objc==5 || objc==6 ){
- zArg = Tcl_GetStringFromObj(objv[objc-2], 0);
+ for(i=3; i+1<objc; i+=2){
+ zArg = Tcl_GetString(objv[i]);
if( strcmp(zArg,"-key")==0 ){
- pKey = Tcl_GetByteArrayFromObj(objv[objc-1], &nKey);
- objc -= 2;
+ pKey = Tcl_GetByteArrayFromObj(objv[i+1], &nKey);
+ }else if( strcmp(zArg, "-vfs")==0 ){
+ i++;
+ zVfs = Tcl_GetString(objv[i]);
+ }else if( strcmp(zArg, "-readonly")==0 ){
+ int b;
+ if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
+ if( b ){
+ flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
+ flags |= SQLITE_OPEN_READONLY;
+ }else{
+ flags &= ~SQLITE_OPEN_READONLY;
+ flags |= SQLITE_OPEN_READWRITE;
+ }
+ }else if( strcmp(zArg, "-create")==0 ){
+ int b;
+ if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
+ if( b && (flags & SQLITE_OPEN_READONLY)==0 ){
+ flags |= SQLITE_OPEN_CREATE;
+ }else{
+ flags &= ~SQLITE_OPEN_CREATE;
+ }
+ }else{
+ Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0);
+ return TCL_ERROR;
}
}
- if( objc!=3 && objc!=4 ){
+ if( objc<3 || (objc&1)!=1 ){
Tcl_WrongNumArgs(interp, 1, objv,
+ "HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
#ifdef SQLITE_HAS_CODEC
- "HANDLE FILENAME ?-key CODEC-KEY?"
-#else
- "HANDLE FILENAME ?MODE?"
+ " ?-key CODECKEY?"
#endif
);
return TCL_ERROR;
@@ -2049,42 +2382,39 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
memset(p, 0, sizeof(*p));
zFile = Tcl_GetStringFromObj(objv[2], 0);
- sqlite3_open(zFile, &p->db);
+ zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename);
+ sqlite3_open_v2(zFile, &p->db, flags, zVfs);
+ Tcl_DStringFree(&translatedFilename);
if( SQLITE_OK!=sqlite3_errcode(p->db) ){
- zErrMsg = strdup(sqlite3_errmsg(p->db));
+ zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
sqlite3_close(p->db);
p->db = 0;
}
+#ifdef SQLITE_TEST
+ if( p->db ){
+ extern int Md5_Register(sqlite3*);
+ if( Md5_Register(p->db)==SQLITE_NOMEM ){
+ zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
+ sqlite3_close(p->db);
+ p->db = 0;
+ }
+ }
+#endif
#ifdef SQLITE_HAS_CODEC
- sqlite3_key(p->db, pKey, nKey);
+ if( p->db ){
+ sqlite3_key(p->db, pKey, nKey);
+ }
#endif
if( p->db==0 ){
Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
Tcl_Free((char*)p);
- free(zErrMsg);
+ sqlite3_free(zErrMsg);
return TCL_ERROR;
}
p->maxStmt = NUM_PREPARED_STMTS;
+ p->interp = interp;
zArg = Tcl_GetStringFromObj(objv[1], 0);
Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
-
- /* If compiled with SQLITE_TEST turned on, then register the "md5sum"
- ** SQL function.
- */
-#ifdef SQLITE_TEST
- {
- extern void Md5_Register(sqlite3*);
-#ifdef SQLITE_MEMDEBUG
- int mallocfail = sqlite3_iMallocFail;
- sqlite3_iMallocFail = 0;
-#endif
- Md5_Register(p->db);
-#ifdef SQLITE_MEMDEBUG
- sqlite3_iMallocFail = mallocfail;
-#endif
- }
-#endif
- p->interp = interp;
return TCL_OK;
}
@@ -2137,12 +2467,14 @@ EXTERN int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
#ifdef TCLSH
/*****************************************************************************
** The code that follows is used to build standalone TCL interpreters
+** that are statically linked with SQLite.
*/
/*
** If the macro TCLSH is one, then put in code this for the
** "main" routine that will initialize Tcl and take input from
-** standard input.
+** standard input, or if a file is named on the command line
+** the TCL interpreter reads and evaluates that file.
*/
#if TCLSH==1
static char zMainloop[] =
@@ -2187,6 +2519,8 @@ int TCLSH_MAIN(int argc, char **argv){
Sqlite3_Init(interp);
#ifdef SQLITE_TEST
{
+ extern int Md5_Init(Tcl_Interp*);
+ extern int Sqliteconfig_Init(Tcl_Interp*);
extern int Sqlitetest1_Init(Tcl_Interp*);
extern int Sqlitetest2_Init(Tcl_Interp*);
extern int Sqlitetest3_Init(Tcl_Interp*);
@@ -2195,12 +2529,19 @@ int TCLSH_MAIN(int argc, char **argv){
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 Sqlitetest9_Init(Tcl_Interp*);
extern int Sqlitetestasync_Init(Tcl_Interp*);
- extern int Sqlitetesttclvar_Init(Tcl_Interp*);
+ extern int Sqlitetest_autoext_Init(Tcl_Interp*);
+ extern int Sqlitetest_hexio_Init(Tcl_Interp*);
+ extern int Sqlitetest_malloc_Init(Tcl_Interp*);
extern int Sqlitetestschema_Init(Tcl_Interp*);
+ extern int Sqlitetestsse_Init(Tcl_Interp*);
+ extern int Sqlitetesttclvar_Init(Tcl_Interp*);
+ extern int SqlitetestThread_Init(Tcl_Interp*);
+ extern int SqlitetestOnefile_Init();
+ Md5_Init(interp);
+ Sqliteconfig_Init(interp);
Sqlitetest1_Init(interp);
Sqlitetest2_Init(interp);
Sqlitetest3_Init(interp);
@@ -2209,10 +2550,16 @@ int TCLSH_MAIN(int argc, char **argv){
Sqlitetest6_Init(interp);
Sqlitetest7_Init(interp);
Sqlitetest8_Init(interp);
+ Sqlitetest9_Init(interp);
Sqlitetestasync_Init(interp);
- Sqlitetesttclvar_Init(interp);
+ Sqlitetest_autoext_Init(interp);
+ Sqlitetest_hexio_Init(interp);
+ Sqlitetest_malloc_Init(interp);
Sqlitetestschema_Init(interp);
- Md5_Init(interp);
+ Sqlitetesttclvar_Init(interp);
+ SqlitetestThread_Init(interp);
+ SqlitetestOnefile_Init(interp);
+
#ifdef SQLITE_SSE
Sqlitetestsse_Init(interp);
#endif
@@ -2220,6 +2567,9 @@ int TCLSH_MAIN(int argc, char **argv){
#endif
if( argc>=2 || TCLSH==2 ){
int i;
+ char zArgc[32];
+ sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-(3-TCLSH));
+ Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY);
Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
for(i=3-TCLSH; i<argc; i++){
@@ -2239,5 +2589,3 @@ int TCLSH_MAIN(int argc, char **argv){
return 0;
}
#endif /* TCLSH */
-
-#endif /* !defined(NO_TCL) */
diff --git a/ext/pdo_sqlite/sqlite/src/test1.c b/ext/pdo_sqlite/sqlite/src/test1.c
index fd474b2763..886a45dbd7 100644
--- a/ext/pdo_sqlite/sqlite/src/test1.c
+++ b/ext/pdo_sqlite/sqlite/src/test1.c
@@ -17,7 +17,6 @@
*/
#include "sqliteInt.h"
#include "tcl.h"
-#include "os.h"
#include <stdlib.h>
#include <string.h>
@@ -32,6 +31,43 @@ struct SqliteDb {
};
/*
+** Convert text generated by the "%p" conversion format back into
+** a pointer.
+*/
+static int testHexToInt(int h){
+ if( h>='0' && h<='9' ){
+ return h - '0';
+ }else if( h>='a' && h<='f' ){
+ return h - 'a' + 10;
+ }else{
+ assert( h>='A' && h<='F' );
+ return h - 'A' + 10;
+ }
+}
+void *sqlite3TextToPtr(const char *z){
+ void *p;
+ u64 v;
+ u32 v2;
+ if( z[0]=='0' && z[1]=='x' ){
+ z += 2;
+ }
+ v = 0;
+ while( *z ){
+ v = (v<<4) + testHexToInt(*z);
+ z++;
+ }
+ if( sizeof(p)==sizeof(v) ){
+ memcpy(&p, &v, sizeof(p));
+ }else{
+ assert( sizeof(p)==sizeof(v2) );
+ v2 = (u32)v;
+ memcpy(&p, &v2, sizeof(p));
+ }
+ return p;
+}
+
+
+/*
** 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.
@@ -63,9 +99,25 @@ static int get_sqlite_pointer(
return TCL_OK;
}
+/*
+** Decode a pointer to an sqlite3 object.
+*/
+static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
+ struct SqliteDb *p;
+ Tcl_CmdInfo cmdInfo;
+ if( Tcl_GetCommandInfo(interp, zA, &cmdInfo) ){
+ p = (struct SqliteDb*)cmdInfo.objClientData;
+ *ppDb = p->db;
+ }else{
+ *ppDb = (sqlite3*)sqlite3TextToPtr(zA);
+ }
+ return TCL_OK;
+}
+
+
const char *sqlite3TestErrorName(int rc){
const char *zName = 0;
- switch( rc ){
+ switch( rc & 0xff ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
@@ -92,11 +144,12 @@ const char *sqlite3TestErrorName(int rc){
case SQLITE_ROW: zName = "SQLITE_ROW"; break;
case SQLITE_DONE: zName = "SQLITE_DONE"; break;
case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break;
+ case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break;
default: zName = "SQLITE_Unknown"; break;
}
return zName;
}
-#define errorName sqlite3TestErrorName
+#define t1ErrorName sqlite3TestErrorName
/*
** Convert an sqlite3_stmt* into an sqlite3*. This depends on the
@@ -113,7 +166,7 @@ int sqlite3TestErrCode(Tcl_Interp *interp, sqlite3 *db, int rc){
char zBuf[200];
int r2 = sqlite3_errcode(db);
sprintf(zBuf, "error code %s (%d) does not match sqlite3_errcode %s (%d)",
- errorName(rc), rc, errorName(r2), r2);
+ t1ErrorName(rc), rc, t1ErrorName(r2), r2);
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, zBuf, 0);
return 1;
@@ -122,14 +175,6 @@ int sqlite3TestErrCode(Tcl_Interp *interp, sqlite3 *db, int rc){
}
/*
-** Decode a pointer to an sqlite3 object.
-*/
-static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
- *ppDb = (sqlite3*)sqlite3TextToPtr(zA);
- return TCL_OK;
-}
-
-/*
** Decode a pointer to an sqlite3_stmt object.
*/
static int getStmtPointer(
@@ -142,18 +187,6 @@ static int getStmtPointer(
}
/*
-** Decode a pointer to an sqlite3_stmt object.
-*/
-static int getFilePointer(
- Tcl_Interp *interp,
- const char *zArg,
- OsFile **ppFile
-){
- *ppFile = (OsFile*)sqlite3TextToPtr(zArg);
- return TCL_OK;
-}
-
-/*
** Generate a text representation of a pointer that can be understood
** by the getDbPointer and getVmPointer routines above.
**
@@ -190,6 +223,57 @@ static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){
}
/*
+** The I/O tracing callback.
+*/
+static FILE *iotrace_file = 0;
+static void io_trace_callback(const char *zFormat, ...){
+ va_list ap;
+ va_start(ap, zFormat);
+ vfprintf(iotrace_file, zFormat, ap);
+ va_end(ap);
+ fflush(iotrace_file);
+}
+
+/*
+** Usage: io_trace FILENAME
+**
+** Turn I/O tracing on or off. If FILENAME is not an empty string,
+** I/O tracing begins going into FILENAME. If FILENAME is an empty
+** string, I/O tracing is turned off.
+*/
+static int test_io_trace(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ char **argv /* Text of each argument */
+){
+ if( argc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " FILENAME\"", 0);
+ return TCL_ERROR;
+ }
+ if( iotrace_file ){
+ if( iotrace_file!=stdout && iotrace_file!=stderr ){
+ fclose(iotrace_file);
+ }
+ iotrace_file = 0;
+ sqlite3_io_trace = 0;
+ }
+ if( argv[1][0] ){
+ if( strcmp(argv[1],"stdout")==0 ){
+ iotrace_file = stdout;
+ }else if( strcmp(argv[1],"stderr")==0 ){
+ iotrace_file = stderr;
+ }else{
+ iotrace_file = fopen(argv[1], "w");
+ }
+ sqlite3_io_trace = io_trace_callback;
+ }
+ return SQLITE_OK;
+}
+
+
+/*
** Usage: sqlite3_exec_printf DB FORMAT STRING
**
** Invoke the sqlite3_exec_printf() interface using the open database
@@ -228,6 +312,117 @@ static int test_exec_printf(
}
/*
+** Usage: db_enter DB
+** db_leave DB
+**
+** Enter or leave the mutex on a database connection.
+*/
+static int db_enter(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ char **argv /* Text of each argument */
+){
+ sqlite3 *db;
+ if( argc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " DB", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
+ sqlite3_mutex_enter(db->mutex);
+ return TCL_OK;
+}
+static int db_leave(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ char **argv /* Text of each argument */
+){
+ sqlite3 *db;
+ if( argc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " DB", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
+ sqlite3_mutex_leave(db->mutex);
+ return TCL_OK;
+}
+
+/*
+** Usage: sqlite3_exec DB SQL
+**
+** Invoke the sqlite3_exec interface using the open database DB
+*/
+static int test_exec(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ char **argv /* Text of each argument */
+){
+ sqlite3 *db;
+ Tcl_DString str;
+ int rc;
+ char *zErr = 0;
+ char *zSql;
+ int i, j;
+ char zBuf[30];
+ if( argc!=3 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " DB SQL", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
+ Tcl_DStringInit(&str);
+ zSql = sqlite3_mprintf("%s", argv[2]);
+ for(i=j=0; zSql[i];){
+ if( zSql[i]=='%' ){
+ zSql[j++] = (testHexToInt(zSql[i+1])<<4) + testHexToInt(zSql[i+2]);
+ i += 3;
+ }else{
+ zSql[j++] = zSql[i++];
+ }
+ }
+ zSql[j] = 0;
+ rc = sqlite3_exec(db, zSql, exec_printf_cb, &str, &zErr);
+ sqlite3_free(zSql);
+ sprintf(zBuf, "%d", rc);
+ Tcl_AppendElement(interp, zBuf);
+ Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
+ Tcl_DStringFree(&str);
+ if( zErr ) sqlite3_free(zErr);
+ if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
+ return TCL_OK;
+}
+
+/*
+** Usage: sqlite3_exec_nr DB SQL
+**
+** Invoke the sqlite3_exec interface using the open database DB. Discard
+** all results
+*/
+static int test_exec_nr(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ char **argv /* Text of each argument */
+){
+ sqlite3 *db;
+ int rc;
+ char *zErr = 0;
+ if( argc!=3 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " DB SQL", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
+ rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
+ if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
+ return TCL_OK;
+}
+
+/*
** Usage: sqlite3_mprintf_z_test SEPARATOR ARG0 ARG1 ...
**
** Test the %z format of sqliteMPrintf(). Use multiple mprintf() calls to
@@ -243,11 +438,11 @@ static int test_mprintf_z(
char *zResult = 0;
int i;
- for(i=2; i<argc; i++){
- zResult = sqlite3MPrintf("%z%s%s", zResult, argv[1], argv[i]);
+ for(i=2; i<argc && (i==2 || zResult); i++){
+ zResult = sqlite3MPrintf(0, "%z%s%s", zResult, argv[1], argv[i]);
}
Tcl_AppendResult(interp, zResult, 0);
- sqliteFree(zResult);
+ sqlite3_free(zResult);
return TCL_OK;
}
@@ -265,14 +460,41 @@ static int test_mprintf_n(
){
char *zStr;
int n = 0;
- zStr = sqlite3MPrintf("%s%n", argv[1], &n);
- sqliteFree(zStr);
+ zStr = sqlite3MPrintf(0, "%s%n", argv[1], &n);
+ sqlite3_free(zStr);
Tcl_SetObjResult(interp, Tcl_NewIntObj(n));
return TCL_OK;
}
/*
-** Usage: sqlite3_get_table_printf DB FORMAT STRING
+** Usage: sqlite3_snprintf_int SIZE FORMAT INT
+**
+** Test the of sqlite3_snprintf() routine. SIZE is the size of the
+** output buffer in bytes. The maximum size is 100. FORMAT is the
+** format string. INT is a single integer argument. The FORMAT
+** string must require no more than this one integer argument. If
+** You pass in a format string that requires more than one argument,
+** bad things will happen.
+*/
+static int test_snprintf_int(
+ 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[100];
+ int n = atoi(argv[1]);
+ const char *zFormat = argv[2];
+ int a1 = atoi(argv[3]);
+ if( n>sizeof(zStr) ) n = sizeof(zStr);
+ strcpy(zStr, "abcdefghijklmnopqrstuvwxyz");
+ sqlite3_snprintf(n, zStr, zFormat, a1);
+ Tcl_AppendResult(interp, zStr, 0);
+ return TCL_OK;
+}
+
+/*
+** Usage: sqlite3_get_table_printf DB FORMAT STRING ?--no-counts?
**
** Invoke the sqlite3_get_table_printf() interface using the open database
** DB. The SQL is the string FORMAT. The format string should contain
@@ -293,24 +515,35 @@ static int test_get_table_printf(
int i;
char zBuf[30];
char *zSql;
- if( argc!=4 ){
+ int resCount = -1;
+ if( argc==5 ){
+ if( Tcl_GetInt(interp, argv[4], &resCount) ) return TCL_ERROR;
+ }
+ if( argc!=4 && argc!=5 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
- " DB FORMAT STRING", 0);
+ " DB FORMAT STRING ?COUNT?", 0);
return TCL_ERROR;
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
Tcl_DStringInit(&str);
zSql = sqlite3_mprintf(argv[2],argv[3]);
- rc = sqlite3_get_table(db, zSql, &aResult, &nRow, &nCol, &zErr);
+ if( argc==5 ){
+ rc = sqlite3_get_table(db, zSql, &aResult, 0, 0, &zErr);
+ }else{
+ rc = sqlite3_get_table(db, zSql, &aResult, &nRow, &nCol, &zErr);
+ resCount = (nRow+1)*nCol;
+ }
sqlite3_free(zSql);
sprintf(zBuf, "%d", rc);
Tcl_AppendElement(interp, zBuf);
if( rc==SQLITE_OK ){
- sprintf(zBuf, "%d", nRow);
- Tcl_AppendElement(interp, zBuf);
- sprintf(zBuf, "%d", nCol);
- Tcl_AppendElement(interp, zBuf);
- for(i=0; i<(nRow+1)*nCol; i++){
+ if( argc==4 ){
+ sprintf(zBuf, "%d", nRow);
+ Tcl_AppendElement(interp, zBuf);
+ sprintf(zBuf, "%d", nCol);
+ Tcl_AppendElement(interp, zBuf);
+ }
+ for(i=0; i<resCount; i++){
Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL");
}
}else{
@@ -423,7 +656,7 @@ static int sqlite_test_close(
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
rc = sqlite3_close(db);
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_OK;
}
@@ -431,18 +664,53 @@ static int sqlite_test_close(
** Implementation of the x_coalesce() function.
** Return the first argument non-NULL argument.
*/
-static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
+static void t1_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]) ){
+ int n = sqlite3_value_bytes(argv[i]);
sqlite3_result_text(context, (char*)sqlite3_value_text(argv[i]),
- sqlite3_value_bytes(argv[i]), SQLITE_TRANSIENT);
+ n, SQLITE_TRANSIENT);
break;
}
}
}
/*
+** These are test functions. hex8() interprets its argument as
+** UTF8 and returns a hex encoding. hex16le() interprets its argument
+** as UTF16le and returns a hex encoding.
+*/
+static void hex8Func(sqlite3_context *p, int argc, sqlite3_value **argv){
+ const unsigned char *z;
+ int i;
+ char zBuf[200];
+ z = sqlite3_value_text(argv[0]);
+ for(i=0; i<sizeof(zBuf)/2 - 2 && z[i]; i++){
+ sprintf(&zBuf[i*2], "%02x", z[i]&0xff);
+ }
+ zBuf[i*2] = 0;
+ sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT);
+}
+#ifndef SQLITE_OMIT_UTF16
+static void hex16Func(sqlite3_context *p, int argc, sqlite3_value **argv){
+ const unsigned short int *z;
+ int i;
+ char zBuf[400];
+ z = sqlite3_value_text16(argv[0]);
+ for(i=0; i<sizeof(zBuf)/4 - 4 && z[i]; i++){
+ sprintf(&zBuf[i*4], "%04x", z[i]&0xff);
+ }
+ zBuf[i*4] = 0;
+ sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT);
+}
+#endif
+
+/*
** A structure into which to accumulate text.
*/
struct dstr {
@@ -459,9 +727,9 @@ static void dstrAppend(struct dstr *p, const char *z, int divider){
if( p->nUsed + n + 2 > p->nAlloc ){
char *zNew;
p->nAlloc = p->nAlloc*2 + n + 200;
- zNew = sqliteRealloc(p->z, p->nAlloc);
+ zNew = sqlite3_realloc(p->z, p->nAlloc);
if( zNew==0 ){
- sqliteFree(p->z);
+ sqlite3_free(p->z);
memset(p, 0, sizeof(*p));
return;
}
@@ -512,10 +780,125 @@ static void sqlite3ExecFunc(
(char*)sqlite3_value_text(argv[0]),
execFuncCallback, &x, 0);
sqlite3_result_text(context, x.z, x.nUsed, SQLITE_TRANSIENT);
- sqliteFree(x.z);
+ sqlite3_free(x.z);
}
/*
+** Implementation of tkt2213func(), a scalar function that takes exactly
+** one argument. It has two interesting features:
+**
+** * It calls sqlite3_value_text() 3 times on the argument sqlite3_value*.
+** If the three pointers returned are not the same an SQL error is raised.
+**
+** * Otherwise it returns a copy of the text representation of its
+** argument in such a way as the VDBE representation is a Mem* cell
+** with the MEM_Term flag clear.
+**
+** Ticket #2213 can therefore be tested by evaluating the following
+** SQL expression:
+**
+** tkt2213func(tkt2213func('a string'));
+*/
+static void tkt2213Function(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int nText;
+ unsigned char const *zText1;
+ unsigned char const *zText2;
+ unsigned char const *zText3;
+
+ nText = sqlite3_value_bytes(argv[0]);
+ zText1 = sqlite3_value_text(argv[0]);
+ zText2 = sqlite3_value_text(argv[0]);
+ zText3 = sqlite3_value_text(argv[0]);
+
+ if( zText1!=zText2 || zText2!=zText3 ){
+ sqlite3_result_error(context, "tkt2213 is not fixed", -1);
+ }else{
+ char *zCopy = (char *)sqlite3_malloc(nText);
+ memcpy(zCopy, zText1, nText);
+ sqlite3_result_text(context, zCopy, nText, sqlite3_free);
+ }
+}
+
+/*
+** The following SQL function takes 4 arguments. The 2nd and
+** 4th argument must be one of these strings: 'text', 'text16',
+** or 'blob' corresponding to API functions
+**
+** sqlite3_value_text()
+** sqlite3_value_text16()
+** sqlite3_value_blob()
+**
+** The third argument is a string, either 'bytes' or 'bytes16' or 'noop',
+** corresponding to APIs:
+**
+** sqlite3_value_bytes()
+** sqlite3_value_bytes16()
+** noop
+**
+** The APIs designated by the 2nd through 4th arguments are applied
+** to the first argument in order. If the pointers returned by the
+** second and fourth are different, this routine returns 1. Otherwise,
+** this routine returns 0.
+**
+** This function is used to test to see when returned pointers from
+** the _text(), _text16() and _blob() APIs become invalidated.
+*/
+static void ptrChngFunction(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const void *p1, *p2;
+ const char *zCmd;
+ if( argc!=4 ) return;
+ zCmd = (const char*)sqlite3_value_text(argv[1]);
+ if( zCmd==0 ) return;
+ if( strcmp(zCmd,"text")==0 ){
+ p1 = (const void*)sqlite3_value_text(argv[0]);
+#ifndef SQLITE_OMIT_UTF16
+ }else if( strcmp(zCmd, "text16")==0 ){
+ p1 = (const void*)sqlite3_value_text16(argv[0]);
+#endif
+ }else if( strcmp(zCmd, "blob")==0 ){
+ p1 = (const void*)sqlite3_value_blob(argv[0]);
+ }else{
+ return;
+ }
+ zCmd = (const char*)sqlite3_value_text(argv[2]);
+ if( zCmd==0 ) return;
+ if( strcmp(zCmd,"bytes")==0 ){
+ sqlite3_value_bytes(argv[0]);
+#ifndef SQLITE_OMIT_UTF16
+ }else if( strcmp(zCmd, "bytes16")==0 ){
+ sqlite3_value_bytes16(argv[0]);
+#endif
+ }else if( strcmp(zCmd, "noop")==0 ){
+ /* do nothing */
+ }else{
+ return;
+ }
+ zCmd = (const char*)sqlite3_value_text(argv[3]);
+ if( zCmd==0 ) return;
+ if( strcmp(zCmd,"text")==0 ){
+ p2 = (const void*)sqlite3_value_text(argv[0]);
+#ifndef SQLITE_OMIT_UTF16
+ }else if( strcmp(zCmd, "text16")==0 ){
+ p2 = (const void*)sqlite3_value_text16(argv[0]);
+#endif
+ }else if( strcmp(zCmd, "blob")==0 ){
+ p2 = (const void*)sqlite3_value_blob(argv[0]);
+ }else{
+ return;
+ }
+ sqlite3_result_int(context, p1!=p2);
+}
+
+
+/*
** Usage: sqlite_test_create_function DB
**
** Call the sqlite3_create_function API on the given database in order
@@ -547,29 +930,48 @@ static int test_create_function(
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_ANY, 0,
- ifnullFunc, 0, 0);
+ t1_ifnullFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "hex8", 1, SQLITE_ANY, 0,
+ hex8Func, 0, 0);
+ }
+#ifndef SQLITE_OMIT_UTF16
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "hex16", 1, SQLITE_ANY, 0,
+ hex16Func, 0, 0);
+ }
+#endif
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "tkt2213func", 1, SQLITE_ANY, 0,
+ tkt2213Function, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "pointer_change", 4, SQLITE_ANY, 0,
+ ptrChngFunction, 0, 0);
+ }
#ifndef SQLITE_OMIT_UTF16
/* Use the sqlite3_create_function16() API here. Mainly for fun, but also
** because it is not tested anywhere else. */
if( rc==SQLITE_OK ){
sqlite3_value *pVal;
-#ifdef SQLITE_MEMDEBUG
- if( sqlite3_iMallocFail>0 ){
- sqlite3_iMallocFail++;
- }
-#endif
- pVal = sqlite3ValueNew();
+ sqlite3_mutex_enter(db->mutex);
+ pVal = sqlite3ValueNew(db);
sqlite3ValueSetStr(pVal, -1, "x_sqlite_exec", SQLITE_UTF8, SQLITE_STATIC);
- rc = sqlite3_create_function16(db,
+ if( db->mallocFailed ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_create_function16(db,
sqlite3ValueText(pVal, SQLITE_UTF16NATIVE),
1, SQLITE_UTF16, db, sqlite3ExecFunc, 0, 0);
+ }
sqlite3ValueFree(pVal);
+ sqlite3_mutex_leave(db->mutex);
}
#endif
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
- Tcl_SetResult(interp, (char *)errorName(rc), 0);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
return TCL_OK;
}
@@ -584,12 +986,16 @@ static int test_create_function(
** 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 {
+typedef struct t1CountCtx t1CountCtx;
+struct t1CountCtx {
int n;
};
-static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
- CountCtx *p;
+static void t1CountStep(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ t1CountCtx *p;
p = sqlite3_aggregate_context(context, sizeof(*p));
if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0]) ) && p ){
p->n++;
@@ -606,8 +1012,8 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
}
}
}
-static void countFinalize(sqlite3_context *context){
- CountCtx *p;
+static void t1CountFinalize(sqlite3_context *context){
+ t1CountCtx *p;
p = sqlite3_aggregate_context(context, sizeof(*p));
if( p ){
if( p->n==42 ){
@@ -618,12 +1024,24 @@ static void countFinalize(sqlite3_context *context){
}
}
+static void legacyCountStep(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ /* no-op */
+}
+static void legacyCountFinalize(sqlite3_context *context){
+ sqlite3_result_int(context, sqlite3_aggregate_count(context));
+}
+
/*
-** Usage: sqlite_test_create_aggregate DB
+** Usage: sqlite3_create_aggregate DB
**
** Call the sqlite3_create_function API on the given database in order
-** to create a function named "x_count". This function does the same thing
-** as the "md5sum" function.
+** to create a function named "x_count". This function is similar
+** to the built-in count() function, with a few special quirks
+** for testing the sqlite3_result_error() APIs.
**
** 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
@@ -631,6 +1049,10 @@ static void countFinalize(sqlite3_context *context){
**
** This routine was later extended to test the use of sqlite3_result_error()
** within aggregate functions.
+**
+** Later: It is now also extended to register the aggregate function
+** "legacy_count()" with the supplied database handle. This is used
+** to test the deprecated sqlite3_aggregate_count() API.
*/
static int test_create_aggregate(
void *NotUsed,
@@ -647,12 +1069,42 @@ static int test_create_aggregate(
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
rc = sqlite3_create_function(db, "x_count", 0, SQLITE_UTF8, 0, 0,
- countStep,countFinalize);
+ t1CountStep,t1CountFinalize);
if( rc==SQLITE_OK ){
- sqlite3_create_function(db, "x_count", 1, SQLITE_UTF8, 0, 0,
- countStep,countFinalize);
+ rc = sqlite3_create_function(db, "x_count", 1, SQLITE_UTF8, 0, 0,
+ t1CountStep,t1CountFinalize);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "legacy_count", 0, SQLITE_ANY, 0, 0,
+ legacyCountStep, legacyCountFinalize
+ );
}
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
+ return TCL_OK;
+}
+
+
+/*
+** Usage: printf TEXT
+**
+** Send output to printf. Use this rather than puts to merge the output
+** in the correct sequence with debugging printfs inserted into C code.
+** Puts uses a separate buffer and debugging statements will be out of
+** sequence if it is used.
+*/
+static int test_printf(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ char **argv /* Text of each argument */
+){
+ if( argc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " TEXT\"", 0);
+ return TCL_ERROR;
+ }
+ printf("%s\n", argv[1]);
return TCL_OK;
}
@@ -690,8 +1142,8 @@ static int sqlite3_mprintf_int(
** *pValue to that integer and return true. Otherwise return false.
*/
static int sqlite3GetInt64(const char *zNum, i64 *pValue){
- if( sqlite3FitsIn64Bits(zNum) ){
- sqlite3atoi64(zNum, pValue);
+ if( sqlite3FitsIn64Bits(zNum, 0) ){
+ sqlite3Atoi64(zNum, pValue);
return 1;
}
return 0;
@@ -756,6 +1208,40 @@ static int sqlite3_mprintf_str(
}
/*
+** Usage: sqlite3_snprintf_str INTEGER FORMAT INTEGER INTEGER STRING
+**
+** Call mprintf with two integer arguments and one string argument
+*/
+static int sqlite3_snprintf_str(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ char **argv /* Text of each argument */
+){
+ int a[3], i;
+ int n;
+ char *z;
+ if( argc<5 || argc>6 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " INT FORMAT INT INT ?STRING?\"", 0);
+ return TCL_ERROR;
+ }
+ if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
+ if( n<0 ){
+ Tcl_AppendResult(interp, "N must be non-negative", 0);
+ return TCL_ERROR;
+ }
+ for(i=3; i<5; i++){
+ if( Tcl_GetInt(interp, argv[i], &a[i-3]) ) return TCL_ERROR;
+ }
+ z = sqlite3_malloc( n+1 );
+ sqlite3_snprintf(n, z, argv[2], a[0], a[1], argc>4 ? argv[5] : NULL);
+ Tcl_AppendResult(interp, z, 0);
+ sqlite3_free(z);
+ return TCL_OK;
+}
+
+/*
** Usage: sqlite3_mprintf_double FORMAT INTEGER INTEGER DOUBLE
**
** Call mprintf with two integer arguments and one double argument
@@ -874,125 +1360,6 @@ static int sqlite3_mprintf_hexdouble(
}
/*
-** Usage: sqlite_malloc_fail N ?REPEAT-INTERVAL?
-**
-** Rig sqliteMalloc() to fail on the N-th call and every REPEAT-INTERVAL call
-** after that. If REPEAT-INTERVAL is 0 or is omitted, then only a single
-** malloc will fail. If REPEAT-INTERVAL is 1 then all mallocs after the
-** first failure will continue to fail on every call. If REPEAT-INTERVAL is
-** 2 then every other malloc will fail. And so forth.
-**
-** Turn off this mechanism and reset the sqlite3ThreadData()->mallocFailed
-** variable if N==0.
-*/
-#ifdef SQLITE_MEMDEBUG
-static int sqlite_malloc_fail(
- void *NotUsed,
- Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
- int argc, /* Number of arguments */
- char **argv /* Text of each argument */
-){
- int n;
- int rep;
- if( argc!=2 && argc!=3 ){
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
- return TCL_ERROR;
- }
- if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
- if( argc==3 ){
- if( Tcl_GetInt(interp, argv[2], &rep) ) return TCL_ERROR;
- }else{
- rep = 0;
- }
- sqlite3_iMallocFail = n;
- sqlite3_iMallocReset = rep;
- return TCL_OK;
-}
-#endif
-
-/*
-** Usage: sqlite_malloc_stat
-**
-** Return the number of prior calls to sqliteMalloc() and sqliteFree().
-*/
-#ifdef SQLITE_MEMDEBUG
-static int sqlite_malloc_stat(
- void *NotUsed,
- Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
- int argc, /* Number of arguments */
- char **argv /* Text of each argument */
-){
- char zBuf[200];
- 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
**
*/
@@ -1006,6 +1373,7 @@ static int test_enable_shared(
int rc;
int enable;
int ret = 0;
+ extern int sqlite3SharedCacheEnabled;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
@@ -1014,7 +1382,7 @@ static int test_enable_shared(
if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ){
return TCL_ERROR;
}
- ret = sqlite3ThreadDataReadOnly()->useSharedData;
+ ret = sqlite3SharedCacheEnabled;
rc = sqlite3_enable_shared_cache(enable);
if( rc!=SQLITE_OK ){
Tcl_SetResult(interp, (char *)sqlite3ErrStr(rc), TCL_STATIC);
@@ -1025,6 +1393,31 @@ static int test_enable_shared(
}
#endif
+
+
+/*
+** Usage: sqlite3_extended_result_codes DB BOOLEAN
+**
+*/
+static int test_extended_result_codes(
+ 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 enable;
+ sqlite3 *db;
+
+ if( objc!=3 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB BOOLEAN");
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ if( Tcl_GetBooleanFromObj(interp, objv[2], &enable) ) return TCL_ERROR;
+ sqlite3_extended_result_codes(db, enable);
+ return TCL_OK;
+}
+
/*
** Usage: sqlite3_libversion_number
**
@@ -1094,6 +1487,198 @@ static int test_table_column_metadata(
}
#endif
+#ifndef SQLITE_OMIT_INCRBLOB
+
+/*
+** sqlite3_blob_read CHANNEL OFFSET N
+**
+** This command is used to test the sqlite3_blob_read() in ways that
+** the Tcl channel interface does not. The first argument should
+** be the name of a valid channel created by the [incrblob] method
+** of a database handle. This function calls sqlite3_blob_read()
+** to read N bytes from offset OFFSET from the underlying SQLite
+** blob handle.
+**
+** On success, a byte-array object containing the read data is
+** returned. On failure, the interpreter result is set to the
+** text representation of the returned error code (i.e. "SQLITE_NOMEM")
+** and a Tcl exception is thrown.
+*/
+static int test_blob_read(
+ 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_Channel channel;
+ ClientData instanceData;
+ sqlite3_blob *pBlob;
+ int notUsed;
+ int nByte;
+ int iOffset;
+ unsigned char *zBuf;
+ int rc;
+
+ if( objc!=4 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET N");
+ return TCL_ERROR;
+ }
+
+ channel = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), &notUsed);
+ if( !channel
+ || TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset)
+ || TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &nByte)
+ || nByte<0 || iOffset<0
+ ){
+ return TCL_ERROR;
+ }
+
+ instanceData = Tcl_GetChannelInstanceData(channel);
+ pBlob = *((sqlite3_blob **)instanceData);
+
+ zBuf = (unsigned char *)Tcl_Alloc(nByte);
+ rc = sqlite3_blob_read(pBlob, zBuf, nByte, iOffset);
+ if( rc==SQLITE_OK ){
+ Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zBuf, nByte));
+ }else{
+ Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
+ }
+ Tcl_Free((char *)zBuf);
+
+ return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
+}
+
+/*
+** sqlite3_blob_write CHANNEL OFFSET DATA
+**
+** This command is used to test the sqlite3_blob_write() in ways that
+** the Tcl channel interface does not. The first argument should
+** be the name of a valid channel created by the [incrblob] method
+** of a database handle. This function calls sqlite3_blob_write()
+** to write the DATA byte-array to the underlying SQLite blob handle.
+** at offset OFFSET.
+**
+** On success, an empty string is returned. On failure, the interpreter
+** result is set to the text representation of the returned error code
+** (i.e. "SQLITE_NOMEM") and a Tcl exception is thrown.
+*/
+static int test_blob_write(
+ 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_Channel channel;
+ ClientData instanceData;
+ sqlite3_blob *pBlob;
+ int notUsed;
+ int iOffset;
+ int rc;
+
+ unsigned char *zBuf;
+ int nBuf;
+
+ if( objc!=4 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET DATA");
+ return TCL_ERROR;
+ }
+
+ channel = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), &notUsed);
+ if( !channel
+ || TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset)
+ || iOffset<0
+ ){
+ return TCL_ERROR;
+ }
+
+ instanceData = Tcl_GetChannelInstanceData(channel);
+ pBlob = *((sqlite3_blob **)instanceData);
+
+ zBuf = Tcl_GetByteArrayFromObj(objv[3], &nBuf);
+ rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset);
+ if( rc!=SQLITE_OK ){
+ Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
+ }
+
+ return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
+}
+#endif
+
+/*
+** Usage: sqlite3_create_collation_v2 DB-HANDLE NAME CMP-PROC DEL-PROC
+**
+** This Tcl proc is used for testing the experimental
+** sqlite3_create_collation_v2() interface.
+*/
+struct TestCollationX {
+ Tcl_Interp *interp;
+ Tcl_Obj *pCmp;
+ Tcl_Obj *pDel;
+};
+typedef struct TestCollationX TestCollationX;
+static void testCreateCollationDel(void *pCtx){
+ TestCollationX *p = (TestCollationX *)pCtx;
+
+ int rc = Tcl_EvalObjEx(p->interp, p->pDel, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL);
+ if( rc!=TCL_OK ){
+ Tcl_BackgroundError(p->interp);
+ }
+
+ Tcl_DecrRefCount(p->pCmp);
+ Tcl_DecrRefCount(p->pDel);
+ sqlite3_free((void *)p);
+}
+static int testCreateCollationCmp(
+ void *pCtx,
+ int nLeft,
+ const void *zLeft,
+ int nRight,
+ const void *zRight
+){
+ TestCollationX *p = (TestCollationX *)pCtx;
+ Tcl_Obj *pScript = Tcl_DuplicateObj(p->pCmp);
+ int iRes = 0;
+
+ Tcl_IncrRefCount(pScript);
+ Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj((char *)zLeft, nLeft));
+ Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj((char *)zRight,nRight));
+
+ if( TCL_OK!=Tcl_EvalObjEx(p->interp, pScript, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL)
+ || TCL_OK!=Tcl_GetIntFromObj(p->interp, Tcl_GetObjResult(p->interp), &iRes)
+ ){
+ Tcl_BackgroundError(p->interp);
+ }
+ Tcl_DecrRefCount(pScript);
+
+ return iRes;
+}
+static int test_create_collation_v2(
+ 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 */
+){
+ TestCollationX *p;
+ sqlite3 *db;
+
+ if( objc!=5 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB-HANDLE NAME CMP-PROC DEL-PROC");
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+
+ p = (TestCollationX *)sqlite3_malloc(sizeof(TestCollationX));
+ p->pCmp = objv[3];
+ p->pDel = objv[4];
+ p->interp = interp;
+ Tcl_IncrRefCount(p->pCmp);
+ Tcl_IncrRefCount(p->pDel);
+
+ sqlite3_create_collation_v2(db, Tcl_GetString(objv[2]), SQLITE_UTF8,
+ (void *)p, testCreateCollationCmp, testCreateCollationDel
+ );
+ return TCL_OK;
+}
/*
** Usage: sqlite3_load_extension DB-HANDLE FILE ?PROC?
@@ -1289,7 +1874,7 @@ static int test_finalize(
){
sqlite3_stmt *pStmt;
int rc;
- sqlite3 *db;
+ sqlite3 *db = 0;
if( objc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
@@ -1303,7 +1888,7 @@ static int test_finalize(
db = StmtToDb(pStmt);
}
rc = sqlite3_finalize(pStmt);
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
if( db && sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
return TCL_OK;
}
@@ -1334,7 +1919,7 @@ static int test_reset(
if( pStmt && sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ){
return TCL_ERROR;
}
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
/*
if( rc ){
return TCL_ERROR;
@@ -1417,6 +2002,7 @@ static int test_changes(
** the FLAG option of sqlite3_bind is "static"
*/
static char *sqlite_static_bind_value = 0;
+static int sqlite_static_bind_nbyte = 0;
/*
** Usage: sqlite3_bind VM IDX VALUE FLAGS
@@ -1449,6 +2035,9 @@ static int test_bind(
rc = sqlite3_bind_null(pStmt, idx);
}else if( strcmp(argv[4],"static")==0 ){
rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0);
+ }else if( strcmp(argv[4],"static-nbytes")==0 ){
+ rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value,
+ sqlite_static_bind_nbyte, 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 ){
@@ -1528,7 +2117,7 @@ static int test_collate_func(
assert(0);
}
- pVal = sqlite3ValueNew();
+ pVal = sqlite3ValueNew(0);
sqlite3ValueSetStr(pVal, nA, zA, encin, SQLITE_STATIC);
n = sqlite3_value_bytes(pVal);
Tcl_ListObjAppendElement(i,pX,
@@ -1568,17 +2157,23 @@ 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 0
if( sqlite3_iMallocFail>0 ){
sqlite3_iMallocFail++;
}
#endif
- pVal = sqlite3ValueNew();
+ sqlite3_mutex_enter(db->mutex);
+ pVal = sqlite3ValueNew(db);
sqlite3ValueSetStr(pVal, -1, "test_collate", SQLITE_UTF8, SQLITE_STATIC);
- rc = sqlite3_create_collation16(db,
+ if( db->mallocFailed ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_create_collation16(db,
sqlite3ValueText(pVal, SQLITE_UTF16NATIVE), SQLITE_UTF16BE,
(void *)SQLITE_UTF16BE, val?test_collate_func:0);
+ }
sqlite3ValueFree(pVal);
+ sqlite3_mutex_leave(db->mutex);
}
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
@@ -1742,7 +2337,7 @@ static void test_function_utf8(
Tcl_EvalObjEx(interp, pX, 0);
Tcl_DecrRefCount(pX);
sqlite3_result_text(pCtx, Tcl_GetStringResult(interp), -1, SQLITE_TRANSIENT);
- pVal = sqlite3ValueNew();
+ pVal = sqlite3ValueNew(0);
sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp),
SQLITE_UTF8, SQLITE_STATIC);
sqlite3_result_text16be(pCtx, sqlite3_value_text16be(pVal),
@@ -1765,7 +2360,7 @@ static void test_function_utf16le(
Tcl_NewStringObj((char*)sqlite3_value_text(argv[0]), -1));
Tcl_EvalObjEx(interp, pX, 0);
Tcl_DecrRefCount(pX);
- pVal = sqlite3ValueNew();
+ pVal = sqlite3ValueNew(0);
sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp),
SQLITE_UTF8, SQLITE_STATIC);
sqlite3_result_text(pCtx,(char*)sqlite3_value_text(pVal),-1,SQLITE_TRANSIENT);
@@ -1787,9 +2382,13 @@ static void test_function_utf16be(
Tcl_NewStringObj((char*)sqlite3_value_text(argv[0]), -1));
Tcl_EvalObjEx(interp, pX, 0);
Tcl_DecrRefCount(pX);
- pVal = sqlite3ValueNew();
+ pVal = sqlite3ValueNew(0);
sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp),
SQLITE_UTF8, SQLITE_STATIC);
+ sqlite3_result_text16(pCtx, sqlite3_value_text16le(pVal),
+ -1, SQLITE_TRANSIENT);
+ sqlite3_result_text16be(pCtx, sqlite3_value_text16le(pVal),
+ -1, SQLITE_TRANSIENT);
sqlite3_result_text16le(pCtx, sqlite3_value_text16le(pVal),
-1, SQLITE_TRANSIENT);
sqlite3ValueFree(pVal);
@@ -1854,7 +2453,7 @@ static int test_errstr(
zCode = Tcl_GetString(objv[1]);
for(i=0; i<200; i++){
- if( 0==strcmp(errorName(i), zCode) ) break;
+ if( 0==strcmp(t1ErrorName(i), zCode) ) break;
}
Tcl_SetResult(interp, (char *)sqlite3ErrStr(i), 0);
return TCL_OK;
@@ -1883,6 +2482,42 @@ static int test_breakpoint(
}
/*
+** Usage: sqlite3_bind_zeroblob STMT IDX N
+**
+** Test the sqlite3_bind_zeroblob interface. STMT is a prepared statement.
+** IDX is the index of a wildcard in the prepared statement. This command
+** binds a N-byte zero-filled BLOB to the wildcard.
+*/
+static int test_bind_zeroblob(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3_stmt *pStmt;
+ int idx;
+ int n;
+ int rc;
+
+ if( objc!=4 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "STMT IDX N");
+ return TCL_ERROR;
+ }
+
+ if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
+ if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
+ if( Tcl_GetIntFromObj(interp, objv[3], &n) ) return TCL_ERROR;
+
+ rc = sqlite3_bind_zeroblob(pStmt, idx, n);
+ if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
+ if( rc!=SQLITE_OK ){
+ return TCL_ERROR;
+ }
+
+ return TCL_OK;
+}
+
+/*
** Usage: sqlite3_bind_int STMT N VALUE
**
** Test the sqlite3_bind_int interface. STMT is a prepared statement.
@@ -2120,7 +2755,7 @@ static int test_bind_text16(
}
/*
-** Usage: sqlite3_bind_blob STMT N DATA BYTES
+** Usage: sqlite3_bind_blob ?-static? STMT N DATA BYTES
**
** Test the sqlite3_bind_blob interface. STMT is a prepared statement.
** N is the index of a wildcard in the prepared statement. This command
@@ -2137,19 +2772,25 @@ static int test_bind_blob(
int bytes;
char *value;
int rc;
+ sqlite3_destructor_type xDestructor = SQLITE_TRANSIENT;
- if( objc!=5 ){
+ if( objc!=5 && objc!=6 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetStringFromObj(objv[0], 0), " STMT N DATA BYTES", 0);
return TCL_ERROR;
}
+ if( objc==6 ){
+ xDestructor = SQLITE_STATIC;
+ objv++;
+ }
+
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
value = Tcl_GetString(objv[3]);
if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
- rc = sqlite3_bind_blob(pStmt, idx, value, bytes, SQLITE_TRANSIENT);
+ rc = sqlite3_bind_blob(pStmt, idx, value, bytes, xDestructor);
if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
if( rc!=SQLITE_OK ){
return TCL_ERROR;
@@ -2291,6 +2932,8 @@ static int test_errcode(
Tcl_Obj *CONST objv[]
){
sqlite3 *db;
+ int rc;
+ char zBuf[30];
if( objc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
@@ -2298,7 +2941,13 @@ static int test_errcode(
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
- Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0);
+ rc = sqlite3_errcode(db);
+ if( (rc&0xff)==rc ){
+ zBuf[0] = 0;
+ }else{
+ sprintf(zBuf,"+%d", rc>>8);
+ }
+ Tcl_AppendResult(interp, (char *)t1ErrorName(rc), zBuf, 0);
return TCL_OK;
}
@@ -2357,7 +3006,7 @@ static int test_errmsg16(
zErr = sqlite3_errmsg16(db);
if( zErr ){
- bytes = sqlite3utf16ByteLen(zErr, -1);
+ bytes = sqlite3Utf16ByteLen(zErr, -1);
}
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes));
#endif /* SQLITE_OMIT_UTF16 */
@@ -2418,7 +3067,61 @@ static int test_prepare(
}
/*
-** Usage: sqlite3_prepare DB sql bytes tailvar
+** Usage: sqlite3_prepare_v2 DB sql bytes tailvar
+**
+** Compile up to <bytes> bytes of the supplied SQL string <sql> using
+** database handle <DB>. The parameter <tailval> is the name of a global
+** variable that is set to the unused portion of <sql> (if any). A
+** STMT handle is returned.
+*/
+static int test_prepare_v2(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3 *db;
+ const char *zSql;
+ int bytes;
+ const char *zTail = 0;
+ sqlite3_stmt *pStmt = 0;
+ char zBuf[50];
+ int rc;
+
+ if( objc!=5 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ zSql = Tcl_GetString(objv[2]);
+ if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
+
+ rc = sqlite3_prepare_v2(db, zSql, bytes, &pStmt, &zTail);
+ assert(rc==SQLITE_OK || pStmt==0);
+ if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
+ if( zTail ){
+ if( bytes>=0 ){
+ bytes = bytes - (zTail-zSql);
+ }
+ Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
+ }
+ if( rc!=SQLITE_OK ){
+ assert( pStmt==0 );
+ sprintf(zBuf, "(%d) ", rc);
+ Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
+ return TCL_ERROR;
+ }
+
+ if( pStmt ){
+ if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
+ Tcl_AppendResult(interp, zBuf, 0);
+ }
+ return TCL_OK;
+}
+
+/*
+** Usage: sqlite3_prepare16 DB sql bytes tailvar
**
** Compile up to <bytes> bytes of the supplied SQL string <sql> using
** database handle <DB>. The parameter <tailval> is the name of a global
@@ -2476,6 +3179,64 @@ static int test_prepare16(
}
/*
+** Usage: sqlite3_prepare16_v2 DB sql bytes tailvar
+**
+** Compile up to <bytes> bytes of the supplied SQL string <sql> using
+** database handle <DB>. The parameter <tailval> is the name of a global
+** variable that is set to the unused portion of <sql> (if any). A
+** STMT handle is returned.
+*/
+static int test_prepare16_v2(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+#ifndef SQLITE_OMIT_UTF16
+ sqlite3 *db;
+ const void *zSql;
+ const void *zTail = 0;
+ Tcl_Obj *pTail = 0;
+ sqlite3_stmt *pStmt = 0;
+ char zBuf[50];
+ int rc;
+ int bytes; /* The integer specified as arg 3 */
+ int objlen; /* The byte-array length of arg 2 */
+
+ if( objc!=5 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
+ if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
+
+ rc = sqlite3_prepare16_v2(db, zSql, bytes, &pStmt, &zTail);
+ if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
+ if( rc ){
+ return TCL_ERROR;
+ }
+
+ if( zTail ){
+ objlen = objlen - ((u8 *)zTail-(u8 *)zSql);
+ }else{
+ objlen = 0;
+ }
+ pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
+ Tcl_IncrRefCount(pTail);
+ Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
+ Tcl_DecrRefCount(pTail);
+
+ if( pStmt ){
+ if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
+ }
+ Tcl_AppendResult(interp, zBuf, 0);
+#endif /* SQLITE_OMIT_UTF16 */
+ return TCL_OK;
+}
+
+/*
** Usage: sqlite3_open filename ?options-list?
*/
static int test_open(
@@ -2583,7 +3344,7 @@ static int test_step(
rc = sqlite3_step(pStmt);
/* if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; */
- Tcl_SetResult(interp, (char *)errorName(rc), 0);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
return TCL_OK;
}
@@ -2714,8 +3475,8 @@ static int test_column_blob(
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
- pBlob = sqlite3_column_blob(pStmt, col);
len = sqlite3_column_bytes(pStmt, col);
+ pBlob = sqlite3_column_blob(pStmt, col);
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pBlob, len));
return TCL_OK;
}
@@ -2820,7 +3581,7 @@ static int test_global_recover(
return TCL_ERROR;
}
rc = sqlite3_global_recover();
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
#endif
return TCL_OK;
}
@@ -2856,7 +3617,7 @@ static int test_stmt_utf16(
zName16 = xFunc(pStmt, col);
if( zName16 ){
- pRet = Tcl_NewByteArrayObj(zName16, sqlite3utf16ByteLen(zName16, -1)+2);
+ pRet = Tcl_NewByteArrayObj(zName16, sqlite3Utf16ByteLen(zName16, -1)+2);
Tcl_SetObjResult(interp, pRet);
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -2896,6 +3657,7 @@ static int test_stmt_int(
}
#ifndef SQLITE_OMIT_DISKIO
+#if 0
/*
** Usage: sqlite3OsOpenReadWrite <filename>
*/
@@ -2905,7 +3667,7 @@ static int test_sqlite3OsOpenReadWrite(
int objc,
Tcl_Obj *CONST objv[]
){
- OsFile *pFile;
+ sqlite3_file *pFile;
int rc;
int dummy;
char zBuf[100];
@@ -2918,7 +3680,7 @@ static int test_sqlite3OsOpenReadWrite(
rc = sqlite3OsOpenReadWrite(Tcl_GetString(objv[1]), &pFile, &dummy);
if( rc!=SQLITE_OK ){
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_ERROR;
}
sqlite3TestMakePointerStr(interp, zBuf, pFile);
@@ -2935,7 +3697,7 @@ static int test_sqlite3OsClose(
int objc,
Tcl_Obj *CONST objv[]
){
- OsFile *pFile;
+ sqlite3_file *pFile;
int rc;
if( objc!=2 ){
@@ -2949,7 +3711,7 @@ static int test_sqlite3OsClose(
}
rc = sqlite3OsClose(&pFile);
if( rc!=SQLITE_OK ){
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
@@ -2964,7 +3726,7 @@ static int test_sqlite3OsLock(
int objc,
Tcl_Obj *CONST objv[]
){
- OsFile * pFile;
+ sqlite3_file * pFile;
int rc;
if( objc!=3 ){
@@ -2997,7 +3759,7 @@ static int test_sqlite3OsLock(
}
if( rc!=SQLITE_OK ){
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
@@ -3012,7 +3774,7 @@ static int test_sqlite3OsUnlock(
int objc,
Tcl_Obj *CONST objv[]
){
- OsFile * pFile;
+ sqlite3_file * pFile;
int rc;
if( objc!=2 ){
@@ -3026,7 +3788,7 @@ static int test_sqlite3OsUnlock(
}
rc = sqlite3OsUnlock(pFile, NO_LOCK);
if( rc!=SQLITE_OK ){
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
@@ -3046,13 +3808,14 @@ static int test_sqlite3OsTempFileName(
rc = sqlite3OsTempFileName(zFile);
if( rc!=SQLITE_OK ){
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_ERROR;
}
Tcl_AppendResult(interp, zFile, 0);
return TCL_OK;
}
#endif
+#endif
/*
** Usage: sqlite_set_magic DB MAGIC-NUMBER
@@ -3175,7 +3938,7 @@ static int delete_function(
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0, 0, 0, 0);
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_OK;
}
@@ -3201,7 +3964,7 @@ static int delete_collation(
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
rc = sqlite3_create_collation(db, argv[2], SQLITE_UTF8, 0, 0);
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_OK;
}
@@ -3326,377 +4089,275 @@ static int test_soft_heap_limit(
int objc,
Tcl_Obj *CONST objv[]
){
-#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO)
+ static int softHeapLimit = 0;
int amt;
if( objc!=1 && objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "?N?");
return TCL_ERROR;
}
- amt = sqlite3ThreadDataReadOnly()->nSoftHeapLimit;
+ amt = softHeapLimit;
if( objc==2 ){
int N;
if( Tcl_GetIntFromObj(interp, objv[1], &N) ) return TCL_ERROR;
sqlite3_soft_heap_limit(N);
+ softHeapLimit = N;
}
Tcl_SetObjResult(interp, Tcl_NewIntObj(amt));
-#endif
return TCL_OK;
}
/*
-** Usage: sqlite3_clear_tsd_memdebug
+** Usage: sqlite3_thread_cleanup
**
-** Clear all of the MEMDEBUG information out of thread-specific data.
-** This will allow it to be deallocated.
+** Call the sqlite3_thread_cleanup API.
*/
-static int test_clear_tsd_memdebug(
+static int test_thread_cleanup(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
+ sqlite3_thread_cleanup();
return TCL_OK;
}
+
/*
-** Usage: sqlite3_tsd_release
+** Usage: sqlite3_pager_refcounts DB
**
-** Call sqlite3ReleaseThreadData.
+** Return a list of numbers which are the PagerRefcount for all
+** pagers on each database connection.
*/
-static int test_tsd_release(
+static int test_pager_refcounts(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
-#if defined(SQLITE_MEMDEBUG)
- sqlite3ReleaseThreadData();
-#endif
+ sqlite3 *db;
+ int i;
+ int v, *a;
+ Tcl_Obj *pResult;
+
+ if( objc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ pResult = Tcl_NewObj();
+ for(i=0; i<db->nDb; i++){
+ if( db->aDb[i].pBt==0 ){
+ v = -1;
+ }else{
+ sqlite3_mutex_enter(db->mutex);
+ a = sqlite3PagerStats(sqlite3BtreePager(db->aDb[i].pBt));
+ v = a[0];
+ sqlite3_mutex_leave(db->mutex);
+ }
+ Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(v));
+ }
+ Tcl_SetObjResult(interp, pResult);
return TCL_OK;
}
+
/*
-** Usage: sqlite3_thread_cleanup
+** tclcmd: working_64bit_int
**
-** Call the sqlite3_thread_cleanup API.
+** Some TCL builds (ex: cygwin) do not support 64-bit integers. This
+** leads to a number of test failures. The present command checks the
+** TCL build to see whether or not it supports 64-bit integers. It
+** returns TRUE if it does and FALSE if not.
+**
+** This command is used to warn users that their TCL build is defective
+** and that the errors they are seeing in the test scripts might be
+** a result of their defective TCL rather than problems in SQLite.
*/
-static int test_thread_cleanup(
- void * clientData,
- Tcl_Interp *interp,
- int objc,
- Tcl_Obj *CONST objv[]
+static int working_64bit_int(
+ 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_thread_cleanup();
+ Tcl_Obj *pTestObj;
+ int working = 0;
+
+ pTestObj = Tcl_NewWideIntObj(1000000*(i64)1234567890);
+ working = strcmp(Tcl_GetString(pTestObj), "1234567890000000")==0;
+ Tcl_DecrRefCount(pTestObj);
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(working));
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.
+** tclcmd: vfs_unlink_test
+**
+** This TCL command unregisters the primary VFS and then registers
+** it back again. This is used to test the ability to register a
+** VFS when none are previously registered, and the ability to
+** unregister the only available VFS. Ticket #2738
*/
-static void set_options(Tcl_Interp *interp){
-#ifdef SQLITE_32BIT_ROWID
- Tcl_SetVar2(interp, "sqlite_options", "rowid32", "1", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "rowid32", "0", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_CASE_SENSITIVE_LIKE
- Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","1",TCL_GLOBAL_ONLY);
-#else
- 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
- Tcl_SetVar2(interp, "sqlite_options", "altertable", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_ANALYZE
- Tcl_SetVar2(interp, "sqlite_options", "analyze", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "analyze", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_AUTHORIZATION
- Tcl_SetVar2(interp, "sqlite_options", "auth", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "auth", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_AUTOINCREMENT
- Tcl_SetVar2(interp, "sqlite_options", "autoinc", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "autoinc", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_AUTOVACUUM
- Tcl_SetVar2(interp, "sqlite_options", "autovacuum", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "autovacuum", "1", TCL_GLOBAL_ONLY);
-#endif /* SQLITE_OMIT_AUTOVACUUM */
-#if !defined(SQLITE_DEFAULT_AUTOVACUUM) || SQLITE_DEFAULT_AUTOVACUUM==0
- Tcl_SetVar2(interp,"sqlite_options","default_autovacuum","0",TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp,"sqlite_options","default_autovacuum","1",TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION
- Tcl_SetVar2(interp, "sqlite_options", "between_opt", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "between_opt", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_BLOB_LITERAL
- Tcl_SetVar2(interp, "sqlite_options", "bloblit", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "bloblit", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_CAST
- Tcl_SetVar2(interp, "sqlite_options", "cast", "0", TCL_GLOBAL_ONLY);
-#else
- 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
- Tcl_SetVar2(interp, "sqlite_options", "complete", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_COMPOUND_SELECT
- Tcl_SetVar2(interp, "sqlite_options", "compound", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "compound", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_CONFLICT_CLAUSE
- Tcl_SetVar2(interp, "sqlite_options", "conflict", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "conflict", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#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
- Tcl_SetVar2(interp, "sqlite_options", "datetime", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_DISKIO
- Tcl_SetVar2(interp, "sqlite_options", "diskio", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "diskio", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_EXPLAIN
- Tcl_SetVar2(interp, "sqlite_options", "explain", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "explain", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_FLOATING_POINT
- Tcl_SetVar2(interp, "sqlite_options", "floatingpoint", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "floatingpoint", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_FOREIGN_KEY
- Tcl_SetVar2(interp, "sqlite_options", "foreignkey", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "foreignkey", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_GLOBALRECOVER
- Tcl_SetVar2(interp, "sqlite_options", "globalrecover", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "globalrecover", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_INTEGRITY_CHECK
- Tcl_SetVar2(interp, "sqlite_options", "integrityck", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "integrityck", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#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
- Tcl_SetVar2(interp, "sqlite_options", "like_opt", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_MEMORYDB
- Tcl_SetVar2(interp, "sqlite_options", "memorydb", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "memorydb", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_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
- Tcl_SetVar2(interp, "sqlite_options", "or_opt", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_PAGER_PRAGMAS
- Tcl_SetVar2(interp, "sqlite_options", "pager_pragmas", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "pager_pragmas", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_PARSER
- Tcl_SetVar2(interp, "sqlite_options", "parser", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "parser", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#if defined(SQLITE_OMIT_PRAGMA) || defined(SQLITE_OMIT_FLAG_PRAGMAS)
- Tcl_SetVar2(interp, "sqlite_options", "pragma", "0", TCL_GLOBAL_ONLY);
- Tcl_SetVar2(interp, "sqlite_options", "integrityck", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "pragma", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_PROGRESS_CALLBACK
- Tcl_SetVar2(interp, "sqlite_options", "progress", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "progress", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_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
- Tcl_SetVar2(interp, "sqlite_options", "reindex", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
- Tcl_SetVar2(interp, "sqlite_options", "schema_pragmas", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "schema_pragmas", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
- Tcl_SetVar2(interp, "sqlite_options", "schema_version", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "schema_version", "1", TCL_GLOBAL_ONLY);
-#endif
+static int vfs_unlink_test(
+ 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 i;
+ sqlite3_vfs *pMain;
+ sqlite3_vfs *apVfs[20];
+ sqlite3_vfs one, two;
-#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
+ sqlite3_vfs_unregister(0); /* Unregister of NULL is harmless */
+ one.zName = "__one";
+ two.zName = "__two";
-#ifdef SQLITE_OMIT_SUBQUERY
- Tcl_SetVar2(interp, "sqlite_options", "subquery", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "subquery", "1", TCL_GLOBAL_ONLY);
-#endif
-
-#ifdef SQLITE_OMIT_TCL_VARIABLE
- Tcl_SetVar2(interp, "sqlite_options", "tclvar", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "tclvar", "1", TCL_GLOBAL_ONLY);
-#endif
+ /* Calling sqlite3_vfs_register with 2nd argument of 0 does not
+ ** change the default VFS
+ */
+ pMain = sqlite3_vfs_find(0);
+ sqlite3_vfs_register(&one, 0);
+ assert( pMain==0 || pMain==sqlite3_vfs_find(0) );
+ sqlite3_vfs_register(&two, 0);
+ assert( pMain==0 || pMain==sqlite3_vfs_find(0) );
+
+ /* We can find a VFS by its name */
+ assert( sqlite3_vfs_find("__one")==&one );
+ assert( sqlite3_vfs_find("__two")==&two );
+
+ /* Calling sqlite_vfs_register with non-zero second parameter changes the
+ ** default VFS, even if the 1st parameter is an existig VFS that is
+ ** previously registered as the non-default.
+ */
+ sqlite3_vfs_register(&one, 1);
+ assert( sqlite3_vfs_find("__one")==&one );
+ assert( sqlite3_vfs_find("__two")==&two );
+ assert( sqlite3_vfs_find(0)==&one );
+ sqlite3_vfs_register(&two, 1);
+ assert( sqlite3_vfs_find("__one")==&one );
+ assert( sqlite3_vfs_find("__two")==&two );
+ assert( sqlite3_vfs_find(0)==&two );
+ if( pMain ){
+ sqlite3_vfs_register(pMain, 1);
+ assert( sqlite3_vfs_find("__one")==&one );
+ assert( sqlite3_vfs_find("__two")==&two );
+ assert( sqlite3_vfs_find(0)==pMain );
+ }
+
+ /* Unlink the default VFS. Repeat until there are no more VFSes
+ ** registered.
+ */
+ for(i=0; i<sizeof(apVfs)/sizeof(apVfs[0]); i++){
+ apVfs[i] = sqlite3_vfs_find(0);
+ if( apVfs[i] ){
+ assert( apVfs[i]==sqlite3_vfs_find(apVfs[i]->zName) );
+ sqlite3_vfs_unregister(apVfs[i]);
+ assert( 0==sqlite3_vfs_find(apVfs[i]->zName) );
+ }
+ }
+ assert( 0==sqlite3_vfs_find(0) );
-#if defined(THREADSAFE) && THREADSAFE
- Tcl_SetVar2(interp, "sqlite_options", "threadsafe", "1", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "threadsafe", "0", TCL_GLOBAL_ONLY);
-#endif
+ /* Relink all VFSes in reverse order. */
+ for(i=sizeof(apVfs)/sizeof(apVfs[0])-1; i>=0; i--){
+ if( apVfs[i] ){
+ sqlite3_vfs_register(apVfs[i], 1);
+ assert( apVfs[i]==sqlite3_vfs_find(0) );
+ assert( apVfs[i]==sqlite3_vfs_find(apVfs[i]->zName) );
+ }
+ }
-#ifdef SQLITE_OMIT_TRACE
- Tcl_SetVar2(interp, "sqlite_options", "trace", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "trace", "1", TCL_GLOBAL_ONLY);
-#endif
+ /* Unregister out sample VFSes. */
+ sqlite3_vfs_unregister(&one);
+ sqlite3_vfs_unregister(&two);
-#ifdef SQLITE_OMIT_TRIGGER
- Tcl_SetVar2(interp, "sqlite_options", "trigger", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "trigger", "1", TCL_GLOBAL_ONLY);
-#endif
+ /* Unregistering a VFS that is not currently registered is harmless */
+ sqlite3_vfs_unregister(&one);
+ sqlite3_vfs_unregister(&two);
+ assert( sqlite3_vfs_find("__one")==0 );
+ assert( sqlite3_vfs_find("__two")==0 );
-#ifdef SQLITE_OMIT_TEMPDB
- Tcl_SetVar2(interp, "sqlite_options", "tempdb", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "tempdb", "1", TCL_GLOBAL_ONLY);
-#endif
+ /* We should be left with the original default VFS back as the
+ ** original */
+ assert( sqlite3_vfs_find(0)==pMain );
-#ifdef SQLITE_OMIT_UTF16
- Tcl_SetVar2(interp, "sqlite_options", "utf16", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "utf16", "1", TCL_GLOBAL_ONLY);
-#endif
+ return TCL_OK;
+}
-#ifdef SQLITE_OMIT_VACUUM
- Tcl_SetVar2(interp, "sqlite_options", "vacuum", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "vacuum", "1", TCL_GLOBAL_ONLY);
-#endif
+/*
+** tclcmd: file_control_test DB
+**
+** This TCL command runs the sqlite3_file_control interface and
+** verifies correct operation of the same.
+*/
+static int file_control_test(
+ 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 iArg = 0;
+ sqlite3 *db;
+ int rc;
-#ifdef SQLITE_OMIT_VIEW
- Tcl_SetVar2(interp, "sqlite_options", "view", "0", TCL_GLOBAL_ONLY);
-#else
- Tcl_SetVar2(interp, "sqlite_options", "view", "1", TCL_GLOBAL_ONLY);
-#endif
+ if( objc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ rc = sqlite3_file_control(db, 0, 0, &iArg);
+ assert( rc==SQLITE_ERROR );
+ rc = sqlite3_file_control(db, "notadatabase", SQLITE_FCNTL_LOCKSTATE, &iArg);
+ assert( rc==SQLITE_ERROR );
+ rc = sqlite3_file_control(db, "main", -1, &iArg);
+ assert( rc==SQLITE_ERROR );
+ rc = sqlite3_file_control(db, "temp", -1, &iArg);
+ assert( rc==SQLITE_ERROR );
+ return TCL_OK;
+}
-#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
+/*
+** tclcmd: save_prng_state
+*/
+static int save_prng_state(
+ 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 */
+){
+ extern void sqlite3SavePrngState(void);
+ sqlite3SavePrngState();
+ return TCL_OK;
}
+/*
+** tclcmd: restore_prng_state
+*/
+static int restore_prng_state(
+ 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 */
+){
+ extern void sqlite3RestorePrngState(void);
+ sqlite3RestorePrngState();
+ return TCL_OK;
+}
+/*
+** tclcmd: reset_prng_state
+*/
+static int reset_prng_state(
+ 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 */
+){
+ extern void sqlite3ResetPrngState(void);
+ sqlite3ResetPrngState();
+ return TCL_OK;
+}
+
/*
** Register commands with the TCL interpreter.
@@ -3707,31 +4368,36 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
extern int sqlite3_open_file_count;
extern int sqlite3_sort_count;
extern int sqlite3_current_time;
+ extern int sqlite3_max_blobsize;
+ extern int sqlite3BtreeSharedCacheReport(void*,
+ Tcl_Interp*,int,Tcl_Obj*CONST*);
static struct {
char *zName;
Tcl_CmdProc *xProc;
} aCmd[] = {
+ { "db_enter", (Tcl_CmdProc*)db_enter },
+ { "db_leave", (Tcl_CmdProc*)db_leave },
{ "sqlite3_mprintf_int", (Tcl_CmdProc*)sqlite3_mprintf_int },
{ "sqlite3_mprintf_int64", (Tcl_CmdProc*)sqlite3_mprintf_int64 },
{ "sqlite3_mprintf_str", (Tcl_CmdProc*)sqlite3_mprintf_str },
+ { "sqlite3_snprintf_str", (Tcl_CmdProc*)sqlite3_snprintf_str },
{ "sqlite3_mprintf_stronly", (Tcl_CmdProc*)sqlite3_mprintf_stronly},
{ "sqlite3_mprintf_double", (Tcl_CmdProc*)sqlite3_mprintf_double },
{ "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_snprintf_int", (Tcl_CmdProc*)test_snprintf_int },
{ "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid },
{ "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf },
+ { "sqlite3_exec", (Tcl_CmdProc*)test_exec },
+ { "sqlite3_exec_nr", (Tcl_CmdProc*)test_exec_nr },
{ "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf },
{ "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close },
{ "sqlite3_create_function", (Tcl_CmdProc*)test_create_function },
{ "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate },
{ "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func },
{ "sqlite_abort", (Tcl_CmdProc*)sqlite_abort },
-#ifdef SQLITE_MEMDEBUG
- { "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail },
- { "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat },
-#endif
{ "sqlite_bind", (Tcl_CmdProc*)test_bind },
{ "breakpoint", (Tcl_CmdProc*)test_breakpoint },
{ "sqlite3_key", (Tcl_CmdProc*)test_key },
@@ -3743,6 +4409,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_get_autocommit", (Tcl_CmdProc*)get_autocommit },
{ "sqlite3_stack_used", (Tcl_CmdProc*)test_stack_used },
{ "sqlite3_busy_timeout", (Tcl_CmdProc*)test_busy_timeout },
+ { "printf", (Tcl_CmdProc*)test_printf },
+ { "sqlite3_io_trace", (Tcl_CmdProc*)test_io_trace },
};
static struct {
char *zName;
@@ -3751,6 +4419,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
} aObjCmd[] = {
{ "sqlite3_connection_pointer", get_sqlite_pointer, 0 },
{ "sqlite3_bind_int", test_bind_int, 0 },
+ { "sqlite3_bind_zeroblob", test_bind_zeroblob, 0 },
{ "sqlite3_bind_int64", test_bind_int64, 0 },
{ "sqlite3_bind_double", test_bind_double, 0 },
{ "sqlite3_bind_null", test_bind_null ,0 },
@@ -3771,6 +4440,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_prepare", test_prepare ,0 },
{ "sqlite3_prepare16", test_prepare16 ,0 },
+ { "sqlite3_prepare_v2", test_prepare_v2 ,0 },
+ { "sqlite3_prepare16_v2", test_prepare16_v2 ,0 },
{ "sqlite3_finalize", test_finalize ,0 },
{ "sqlite3_reset", test_reset ,0 },
{ "sqlite3_expired", test_expired ,0 },
@@ -3780,12 +4451,16 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "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_pager_refcounts", test_pager_refcounts, 0},
{ "sqlite3_load_extension", test_load_extension, 0},
{ "sqlite3_enable_load_extension", test_enable_load, 0},
+ { "sqlite3_extended_result_codes", test_extended_result_codes, 0},
+
+ { "save_prng_state", save_prng_state, 0 },
+ { "restore_prng_state", restore_prng_state, 0 },
+ { "reset_prng_state", reset_prng_state, 0 },
/* sqlite3_column_*() API */
{ "sqlite3_column_count", test_column_count ,0 },
@@ -3818,10 +4493,15 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{"sqlite3_column_origin_name16", test_stmt_utf16, sqlite3_column_origin_name16},
#endif
#endif
- { "sqlite3_global_recover", test_global_recover, 0 },
+ { "sqlite3_create_collation_v2", test_create_collation_v2, 0 },
+ { "sqlite3_global_recover", test_global_recover, 0 },
+ { "working_64bit_int", working_64bit_int, 0 },
+ { "vfs_unlink_test", vfs_unlink_test, 0 },
+ { "file_control_test", file_control_test, 0 },
/* Functions from os.h */
#ifndef SQLITE_OMIT_DISKIO
+#if 0
{ "sqlite3OsOpenReadWrite",test_sqlite3OsOpenReadWrite, 0 },
{ "sqlite3OsClose", test_sqlite3OsClose, 0 },
{ "sqlite3OsLock", test_sqlite3OsLock, 0 },
@@ -3830,45 +4510,50 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
/* Custom test interfaces */
{ "sqlite3OsUnlock", test_sqlite3OsUnlock, 0 },
#endif
+#endif
#ifndef SQLITE_OMIT_UTF16
{ "add_test_collate", test_collate, 0 },
{ "add_test_collate_needed", test_collate_needed, 0 },
{ "add_test_function", test_function, 0 },
#endif
-#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 },
+ { "sqlite3_shared_cache_report", sqlite3BtreeSharedCacheReport, 0},
#endif
{ "sqlite3_libversion_number", test_libversion_number, 0 },
#ifdef SQLITE_ENABLE_COLUMN_METADATA
{ "sqlite3_table_column_metadata", test_table_column_metadata, 0 },
#endif
+#ifndef SQLITE_OMIT_INCRBLOB
+ { "sqlite3_blob_read", test_blob_read, 0 },
+ { "sqlite3_blob_write", test_blob_write, 0 },
+#endif
};
static int bitmask_size = sizeof(Bitmask)*8;
int i;
- extern int sqlite3_os_trace;
- extern int sqlite3_where_trace;
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 sqlite3_xferopt_count;
+ extern int sqlite3_pager_readdb_count;
+ extern int sqlite3_pager_writedb_count;
+ extern int sqlite3_pager_writej_count;
+ extern int sqlite3_pager_pgfree_count;
+#if OS_UNIX && defined(SQLITE_TEST) && SQLITE_THREADSAFE
extern int threadsOverrideEachOthersLocks;
#endif
#if OS_WIN
extern int sqlite3_os_type;
#endif
#ifdef SQLITE_DEBUG
+ extern int sqlite3_where_trace;
+ extern int sqlite3_os_trace;
extern int sqlite3_vdbe_addop_trace;
#endif
#ifdef SQLITE_TEST
+ extern int sqlite3_enable_in_opt;
extern char sqlite3_query_plan[];
static char *query_plan = sqlite3_query_plan;
#endif
@@ -3884,6 +4569,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
(char*)&sqlite3_search_count, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_sort_count",
(char*)&sqlite3_sort_count, TCL_LINK_INT);
+ Tcl_LinkVar(interp, "sqlite3_max_blobsize",
+ (char*)&sqlite3_max_blobsize, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_like_count",
(char*)&sqlite3_like_count, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_interrupt_count",
@@ -3892,15 +4579,21 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
(char*)&sqlite3_open_file_count, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_current_time",
(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);
+ Tcl_LinkVar(interp, "sqlite3_xferopt_count",
+ (char*)&sqlite3_xferopt_count, TCL_LINK_INT);
+ Tcl_LinkVar(interp, "sqlite3_pager_readdb_count",
+ (char*)&sqlite3_pager_readdb_count, TCL_LINK_INT);
+ Tcl_LinkVar(interp, "sqlite3_pager_writedb_count",
+ (char*)&sqlite3_pager_writedb_count, TCL_LINK_INT);
+ Tcl_LinkVar(interp, "sqlite3_pager_writej_count",
+ (char*)&sqlite3_pager_writej_count, TCL_LINK_INT);
+ Tcl_LinkVar(interp, "sqlite3_pager_pgfree_count",
+ (char*)&sqlite3_pager_pgfree_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
+#if OS_UNIX && defined(SQLITE_TEST) && SQLITE_THREADSAFE
Tcl_LinkVar(interp, "threadsOverrideEachOthersLocks",
(char*)&threadsOverrideEachOthersLocks, TCL_LINK_INT);
#endif
@@ -3908,10 +4601,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
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);
@@ -3925,12 +4614,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
(char*)&sqlite3_vdbe_addop_trace, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_where_trace",
(char*)&sqlite3_where_trace, TCL_LINK_INT);
-#endif
-#ifdef SQLITE_MEMDEBUG
- Tcl_LinkVar(interp, "sqlite_memused",
- (char*)&sqlite3_memUsed, TCL_LINK_INT | TCL_LINK_READ_ONLY);
- Tcl_LinkVar(interp, "sqlite_memmax",
- (char*)&sqlite3_memMax, TCL_LINK_INT | TCL_LINK_READ_ONLY);
+ Tcl_LinkVar(interp, "sqlite_os_trace",
+ (char*)&sqlite3_os_trace, TCL_LINK_INT);
#endif
#ifndef SQLITE_OMIT_DISKIO
Tcl_LinkVar(interp, "sqlite_opentemp_count",
@@ -3938,25 +4623,19 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#endif
Tcl_LinkVar(interp, "sqlite_static_bind_value",
(char*)&sqlite_static_bind_value, TCL_LINK_STRING);
+ Tcl_LinkVar(interp, "sqlite_static_bind_nbyte",
+ (char*)&sqlite_static_bind_nbyte, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_temp_directory",
(char*)&sqlite3_temp_directory, TCL_LINK_STRING);
Tcl_LinkVar(interp, "bitmask_size",
(char*)&bitmask_size, TCL_LINK_INT|TCL_LINK_READ_ONLY);
-#if OS_UNIX
Tcl_LinkVar(interp, "sqlite_sync_count",
(char*)&sqlite3_sync_count, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_fullsync_count",
(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);
+#ifdef SQLITE_TEST
+ Tcl_LinkVar(interp, "sqlite_enable_in_opt",
+ (char*)&sqlite3_enable_in_opt, TCL_LINK_INT);
#endif
- }
return TCL_OK;
}
diff --git a/ext/pdo_sqlite/sqlite/src/test2.c b/ext/pdo_sqlite/sqlite/src/test2.c
index 80e57cd87e..9e76b9ff34 100644
--- a/ext/pdo_sqlite/sqlite/src/test2.c
+++ b/ext/pdo_sqlite/sqlite/src/test2.c
@@ -16,8 +16,6 @@
** $Id$
*/
#include "sqliteInt.h"
-#include "os.h"
-#include "pager.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
@@ -68,6 +66,7 @@ static int pager_open(
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
+ u16 pageSize;
Pager *pPager;
int nPage;
int rc;
@@ -78,13 +77,15 @@ static int pager_open(
return TCL_ERROR;
}
if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR;
- rc = sqlite3pager_open(&pPager, argv[1], 0, 0);
+ rc = sqlite3PagerOpen(sqlite3_vfs_find(0), &pPager, argv[1], 0, 0,
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
- sqlite3pager_set_cachesize(pPager, nPage);
- sqlite3pager_set_pagesize(pPager, test_pagesize);
+ sqlite3PagerSetCachesize(pPager, nPage);
+ pageSize = test_pagesize;
+ sqlite3PagerSetPagesize(pPager, &pageSize);
sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPager);
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
@@ -109,7 +110,7 @@ static int pager_close(
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
- rc = sqlite3pager_close(pPager);
+ rc = sqlite3PagerClose(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -136,7 +137,7 @@ static int pager_rollback(
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
- rc = sqlite3pager_rollback(pPager);
+ rc = sqlite3PagerRollback(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -163,7 +164,12 @@ static int pager_commit(
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
- rc = sqlite3pager_commit(pPager);
+ rc = sqlite3PagerCommitPhaseOne(pPager, 0, 0);
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp, errorName(rc), 0);
+ return TCL_ERROR;
+ }
+ rc = sqlite3PagerCommitPhaseTwo(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -190,7 +196,7 @@ static int pager_stmt_begin(
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
- rc = sqlite3pager_stmt_begin(pPager);
+ rc = sqlite3PagerStmtBegin(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -217,7 +223,7 @@ static int pager_stmt_rollback(
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
- rc = sqlite3pager_stmt_rollback(pPager);
+ rc = sqlite3PagerStmtRollback(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -244,7 +250,7 @@ static int pager_stmt_commit(
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
- rc = sqlite3pager_stmt_commit(pPager);
+ rc = sqlite3PagerStmtCommit(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -271,7 +277,7 @@ static int pager_stats(
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
- a = sqlite3pager_stats(pPager);
+ a = sqlite3PagerStats(pPager);
for(i=0; i<9; i++){
static char *zName[] = {
"ref", "page", "max", "size", "state", "err",
@@ -304,7 +310,7 @@ static int pager_pagecount(
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
- sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",sqlite3pager_pagecount(pPager));
+ sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",sqlite3PagerPagecount(pPager));
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
@@ -322,7 +328,7 @@ static int page_get(
){
Pager *pPager;
char zBuf[100];
- void *pPage;
+ DbPage *pPage;
int pgno;
int rc;
if( argc!=3 ){
@@ -332,7 +338,7 @@ static int page_get(
}
pPager = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
- rc = sqlite3pager_get(pPager, pgno, &pPage);
+ rc = sqlite3PagerGet(pPager, pgno, &pPage);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -356,7 +362,7 @@ static int page_lookup(
){
Pager *pPager;
char zBuf[100];
- void *pPage;
+ DbPage *pPage;
int pgno;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
@@ -365,7 +371,7 @@ static int page_lookup(
}
pPager = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
- pPage = sqlite3pager_lookup(pPager, pgno);
+ pPage = sqlite3PagerLookup(pPager, pgno);
if( pPage ){
sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage);
Tcl_AppendResult(interp, zBuf, 0);
@@ -392,7 +398,7 @@ static int pager_truncate(
}
pPager = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
- rc = sqlite3pager_truncate(pPager, pgno);
+ rc = sqlite3PagerTruncate(pPager, pgno);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -412,15 +418,15 @@ static int page_unref(
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
- void *pPage;
+ DbPage *pPage;
int rc;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" PAGE\"", 0);
return TCL_ERROR;
}
- pPage = sqlite3TextToPtr(argv[1]);
- rc = sqlite3pager_unref(pPage);
+ pPage = (DbPage *)sqlite3TextToPtr(argv[1]);
+ rc = sqlite3PagerUnref(pPage);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -440,14 +446,14 @@ static int page_read(
const char **argv /* Text of each argument */
){
char zBuf[100];
- void *pPage;
+ DbPage *pPage;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" PAGE\"", 0);
return TCL_ERROR;
}
pPage = sqlite3TextToPtr(argv[1]);
- memcpy(zBuf, pPage, sizeof(zBuf));
+ memcpy(zBuf, sqlite3PagerGetData(pPage), sizeof(zBuf));
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
@@ -464,14 +470,14 @@ static int page_number(
const char **argv /* Text of each argument */
){
char zBuf[100];
- void *pPage;
+ DbPage *pPage;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" PAGE\"", 0);
return TCL_ERROR;
}
- pPage = sqlite3TextToPtr(argv[1]);
- sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3pager_pagenumber(pPage));
+ pPage = (DbPage *)sqlite3TextToPtr(argv[1]);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3PagerPagenumber(pPage));
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
@@ -487,21 +493,23 @@ static int page_write(
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
- void *pPage;
+ DbPage *pPage;
+ char *pData;
int rc;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" PAGE DATA\"", 0);
return TCL_ERROR;
}
- pPage = sqlite3TextToPtr(argv[1]);
- rc = sqlite3pager_write(pPage);
+ pPage = (DbPage *)sqlite3TextToPtr(argv[1]);
+ rc = sqlite3PagerWrite(pPage);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
- strncpy((char*)pPage, argv[2], test_pagesize-1);
- ((char*)pPage)[test_pagesize-1] = 0;
+ pData = sqlite3PagerGetData(pPage);
+ strncpy(pData, argv[2], test_pagesize-1);
+ pData[test_pagesize-1] = 0;
return TCL_OK;
}
@@ -521,31 +529,30 @@ static int fake_big_file(
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
+ sqlite3_vfs *pVfs;
+ sqlite3_file *fd = 0;
int rc;
int n;
i64 offset;
- OsFile *fd = 0;
- int readOnly = 0;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" N-MEGABYTES FILE\"", 0);
return TCL_ERROR;
}
if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
- rc = sqlite3OsOpenReadWrite(argv[2], &fd, &readOnly);
+
+ pVfs = sqlite3_vfs_find(0);
+ rc = sqlite3OsOpenMalloc(pVfs, argv[2], &fd,
+ (SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB), 0
+ );
if( rc ){
Tcl_AppendResult(interp, "open failed: ", errorName(rc), 0);
return TCL_ERROR;
}
offset = n;
offset *= 1024*1024;
- rc = sqlite3OsSeek(fd, offset);
- if( rc ){
- Tcl_AppendResult(interp, "seek failed: ", errorName(rc), 0);
- return TCL_ERROR;
- }
- rc = sqlite3OsWrite(fd, "Hello, World!", 14);
- sqlite3OsClose(&fd);
+ rc = sqlite3OsWrite(fd, "Hello, World!", 14, offset);
+ sqlite3OsCloseFree(fd);
if( rc ){
Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0);
return TCL_ERROR;
@@ -558,10 +565,12 @@ static int fake_big_file(
** Register commands with the TCL interpreter.
*/
int Sqlitetest2_Init(Tcl_Interp *interp){
+ extern int sqlite3_io_error_persist;
extern int sqlite3_io_error_pending;
extern int sqlite3_io_error_hit;
extern int sqlite3_diskfull_pending;
extern int sqlite3_diskfull;
+ extern int sqlite3_pager_n_sort_bucket;
static struct {
char *zName;
Tcl_CmdProc *xProc;
@@ -592,6 +601,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_persist",
+ (char*)&sqlite3_io_error_persist, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_io_error_hit",
(char*)&sqlite3_io_error_hit, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_diskfull_pending",
@@ -602,5 +613,7 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
(char*)&sqlite3_pending_byte, TCL_LINK_INT);
Tcl_LinkVar(interp, "pager_pagesize",
(char*)&test_pagesize, TCL_LINK_INT);
+ Tcl_LinkVar(interp, "sqlite_pager_n_sort_bucket",
+ (char*)&sqlite3_pager_n_sort_bucket, TCL_LINK_INT);
return TCL_OK;
}
diff --git a/ext/pdo_sqlite/sqlite/src/test3.c b/ext/pdo_sqlite/sqlite/src/test3.c
index 6557fb4f4d..8f568d7694 100644
--- a/ext/pdo_sqlite/sqlite/src/test3.c
+++ b/ext/pdo_sqlite/sqlite/src/test3.c
@@ -16,8 +16,7 @@
** $Id$
*/
#include "sqliteInt.h"
-#include "pager.h"
-#include "btree.h"
+#include "btreeInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
@@ -49,6 +48,13 @@ static char *errorName(int rc){
}
/*
+** A bogus sqlite3 connection structure for use in the btree
+** tests.
+*/
+static sqlite3 sDb;
+static int nRefSqlite3 = 0;
+
+/*
** Usage: btree_open FILENAME NCACHE FLAGS
**
** Open a new database
@@ -69,7 +75,14 @@ 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], 0, &pBt, flags);
+ nRefSqlite3++;
+ if( nRefSqlite3==1 ){
+ sDb.pVfs = sqlite3_vfs_find(0);
+ sDb.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE);
+ sqlite3_mutex_enter(sDb.mutex);
+ }
+ rc = sqlite3BtreeOpen(argv[1], &sDb, &pBt, flags,
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -104,9 +117,17 @@ static int btree_close(
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
+ nRefSqlite3--;
+ if( nRefSqlite3==0 ){
+ sqlite3_mutex_leave(sDb.mutex);
+ sqlite3_mutex_free(sDb.mutex);
+ sDb.mutex = 0;
+ sDb.pVfs = 0;
+ }
return TCL_OK;
}
+
/*
** Usage: btree_begin_transaction ID
**
@@ -126,7 +147,9 @@ static int btree_begin_transaction(
return TCL_ERROR;
}
pBt = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeBeginTrans(pBt, 1);
+ sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -153,7 +176,9 @@ static int btree_rollback(
return TCL_ERROR;
}
pBt = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeRollback(pBt);
+ sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -180,7 +205,9 @@ static int btree_commit(
return TCL_ERROR;
}
pBt = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeCommit(pBt);
+ sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -207,7 +234,9 @@ static int btree_begin_statement(
return TCL_ERROR;
}
pBt = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeBeginStmt(pBt);
+ sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -234,7 +263,9 @@ static int btree_rollback_statement(
return TCL_ERROR;
}
pBt = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeRollbackStmt(pBt);
+ sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -261,7 +292,9 @@ static int btree_commit_statement(
return TCL_ERROR;
}
pBt = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeCommitStmt(pBt);
+ sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -290,7 +323,9 @@ static int btree_create_table(
}
pBt = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &flags) ) return TCL_ERROR;
+ sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeCreateTable(pBt, &iTable, flags);
+ sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -322,7 +357,9 @@ static int btree_drop_table(
}
pBt = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
+ sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeDropTable(pBt, iTable, &notUsed1);
+ sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -351,7 +388,9 @@ static int btree_clear_table(
}
pBt = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
+ sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeClearTable(pBt, iTable);
+ sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -382,7 +421,9 @@ static int btree_get_meta(
for(i=0; i<SQLITE_N_BTREE_META; i++){
char zBuf[30];
unsigned int v;
+ sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeGetMeta(pBt, i, &v);
+ sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -421,7 +462,9 @@ static int btree_update_meta(
if( Tcl_GetInt(interp, argv[i+2], &aMeta[i]) ) return TCL_ERROR;
}
for(i=1; i<SQLITE_N_BTREE_META; i++){
+ sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeUpdateMeta(pBt, i, aMeta[i]);
+ sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -452,7 +495,9 @@ static int btree_page_dump(
}
pBt = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR;
+ sqlite3BtreeEnter(pBt);
rc = sqlite3BtreePageDump(pBt, iPage, 0);
+ sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -482,7 +527,9 @@ static int btree_tree_dump(
}
pBt = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR;
+ sqlite3BtreeEnter(pBt);
rc = sqlite3BtreePageDump(pBt, iPage, 1);
+ sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -511,7 +558,18 @@ static int btree_pager_stats(
return TCL_ERROR;
}
pBt = sqlite3TextToPtr(argv[1]);
- a = sqlite3pager_stats(sqlite3BtreePager(pBt));
+
+ /* Normally in this file, with a b-tree handle opened using the
+ ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly.
+ ** But this function is sometimes called with a btree handle obtained
+ ** from an open SQLite connection (using [btree_from_db]). In this case
+ ** we need to obtain the mutex for the controlling SQLite handle before
+ ** it is safe to call sqlite3BtreeEnter().
+ */
+ sqlite3_mutex_enter(pBt->db->mutex);
+
+ sqlite3BtreeEnter(pBt);
+ a = sqlite3PagerStats(sqlite3BtreePager(pBt));
for(i=0; i<11; i++){
static char *zName[] = {
"ref", "page", "max", "size", "state", "err",
@@ -522,6 +580,10 @@ static int btree_pager_stats(
sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]);
Tcl_AppendElement(interp, zBuf);
}
+ sqlite3BtreeLeave(pBt);
+
+ /* Release the mutex on the SQLite handle that controls this b-tree */
+ sqlite3_mutex_leave(pBt->db->mutex);
return TCL_OK;
}
@@ -544,8 +606,10 @@ static int btree_pager_ref_dump(
return TCL_ERROR;
}
pBt = sqlite3TextToPtr(argv[1]);
-#ifdef SQLITE_DEBUG
- sqlite3pager_refdump(sqlite3BtreePager(pBt));
+#ifdef SQLITE_TEST
+ sqlite3BtreeEnter(pBt);
+ sqlite3PagerRefdump(sqlite3BtreePager(pBt));
+ sqlite3BtreeLeave(pBt);
#endif
return TCL_OK;
}
@@ -567,6 +631,7 @@ static int btree_integrity_check(
int nRoot;
int *aRoot;
int i;
+ int nErr;
char *zResult;
if( argc<3 ){
@@ -576,19 +641,21 @@ static int btree_integrity_check(
}
pBt = sqlite3TextToPtr(argv[1]);
nRoot = argc-2;
- aRoot = malloc( sizeof(int)*(argc-2) );
+ aRoot = (int*)sqlite3_malloc( sizeof(int)*(argc-2) );
for(i=0; i<argc-2; i++){
if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
}
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
- zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot);
+ sqlite3BtreeEnter(pBt);
+ zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot, 10000, &nErr);
+ sqlite3BtreeLeave(pBt);
#else
zResult = 0;
#endif
- free(aRoot);
+ sqlite3_free((void*)aRoot);
if( zResult ){
Tcl_AppendResult(interp, zResult, 0);
- sqliteFree(zResult);
+ sqlite3_free(zResult);
}
return TCL_OK;
}
@@ -598,7 +665,6 @@ 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 */
@@ -613,10 +679,11 @@ static int btree_cursor_list(
return TCL_ERROR;
}
pBt = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pBt);
sqlite3BtreeCursorList(pBt);
+ sqlite3BtreeLeave(pBt);
return SQLITE_OK;
}
-#endif
/*
** Usage: btree_cursor ID TABLENUM WRITEABLE
@@ -644,7 +711,9 @@ static int btree_cursor(
pBt = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
+ sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, 0, &pCur);
+ sqlite3BtreeLeave(pBt);
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -666,6 +735,7 @@ static int btree_close_cursor(
const char **argv /* Text of each argument */
){
BtCursor *pCur;
+ Btree *pBt;
int rc;
if( argc!=2 ){
@@ -674,7 +744,10 @@ static int btree_close_cursor(
return TCL_ERROR;
}
pCur = sqlite3TextToPtr(argv[1]);
+ pBt = pCur->pBtree;
+ sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeCloseCursor(pCur);
+ sqlite3BtreeLeave(pBt);
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -704,13 +777,18 @@ static int btree_move_to(
return TCL_ERROR;
}
pCur = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pCur->pBtree);
if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
int iKey;
- if( Tcl_GetInt(interp, argv[2], &iKey) ) return TCL_ERROR;
- rc = sqlite3BtreeMoveto(pCur, 0, iKey, &res);
+ if( Tcl_GetInt(interp, argv[2], &iKey) ){
+ sqlite3BtreeLeave(pCur->pBtree);
+ return TCL_ERROR;
+ }
+ rc = sqlite3BtreeMoveto(pCur, 0, iKey, 0, &res);
}else{
- rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), &res);
+ rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), 0, &res);
}
+ sqlite3BtreeLeave(pCur->pBtree);
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -742,7 +820,9 @@ static int btree_delete(
return TCL_ERROR;
}
pCur = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pCur->pBtree);
rc = sqlite3BtreeDelete(pCur);
+ sqlite3BtreeLeave(pCur->pBtree);
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -751,7 +831,7 @@ static int btree_delete(
}
/*
-** Usage: btree_insert ID KEY DATA
+** Usage: btree_insert ID KEY DATA ?NZERO?
**
** Create a new entry with the given key and data. If an entry already
** exists with the same key the old entry is overwritten.
@@ -764,19 +844,29 @@ static int btree_insert(
){
BtCursor *pCur;
int rc;
+ int nZero;
- if( objc!=4 ){
- Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA");
+ if( objc!=4 && objc!=5 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA ?NZERO?");
return TCL_ERROR;
}
pCur = sqlite3TextToPtr(Tcl_GetString(objv[1]));
+ if( objc==5 ){
+ if( Tcl_GetIntFromObj(interp, objv[4], &nZero) ) return TCL_ERROR;
+ }else{
+ nZero = 0;
+ }
+ sqlite3BtreeEnter(pCur->pBtree);
if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
i64 iKey;
int len;
unsigned char *pBuf;
- if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ) return TCL_ERROR;
+ if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ){
+ sqlite3BtreeLeave(pCur->pBtree);
+ return TCL_ERROR;
+ }
pBuf = Tcl_GetByteArrayFromObj(objv[3], &len);
- rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len);
+ rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len, nZero, 0);
}else{
int keylen;
int dlen;
@@ -784,8 +874,9 @@ static int btree_insert(
unsigned char *pDBuf;
pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen);
pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen);
- rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen);
+ rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen, nZero, 0);
}
+ sqlite3BtreeLeave(pCur->pBtree);
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -817,7 +908,9 @@ static int btree_next(
return TCL_ERROR;
}
pCur = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pCur->pBtree);
rc = sqlite3BtreeNext(pCur, &res);
+ sqlite3BtreeLeave(pCur->pBtree);
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -851,7 +944,9 @@ static int btree_prev(
return TCL_ERROR;
}
pCur = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pCur->pBtree);
rc = sqlite3BtreePrevious(pCur, &res);
+ sqlite3BtreeLeave(pCur->pBtree);
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -884,7 +979,9 @@ static int btree_first(
return TCL_ERROR;
}
pCur = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pCur->pBtree);
rc = sqlite3BtreeFirst(pCur, &res);
+ sqlite3BtreeLeave(pCur->pBtree);
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -917,7 +1014,9 @@ static int btree_last(
return TCL_ERROR;
}
pCur = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pCur->pBtree);
rc = sqlite3BtreeLast(pCur, &res);
+ sqlite3BtreeLeave(pCur->pBtree);
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -940,6 +1039,7 @@ static int btree_eof(
const char **argv /* Text of each argument */
){
BtCursor *pCur;
+ int rc;
char zBuf[50];
if( argc!=2 ){
@@ -948,7 +1048,10 @@ static int btree_eof(
return TCL_ERROR;
}
pCur = sqlite3TextToPtr(argv[1]);
- sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", sqlite3BtreeEof(pCur));
+ sqlite3BtreeEnter(pCur->pBtree);
+ rc = sqlite3BtreeEof(pCur);
+ sqlite3BtreeLeave(pCur->pBtree);
+ sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc);
Tcl_AppendResult(interp, zBuf, 0);
return SQLITE_OK;
}
@@ -975,7 +1078,9 @@ static int btree_keysize(
return TCL_ERROR;
}
pCur = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pCur->pBtree);
sqlite3BtreeKeySize(pCur, (i64*)&n);
+ sqlite3BtreeLeave(pCur->pBtree);
sqlite3_snprintf(sizeof(zBuf),zBuf, "%llu", n);
Tcl_AppendResult(interp, zBuf, 0);
return SQLITE_OK;
@@ -1003,22 +1108,25 @@ static int btree_key(
return TCL_ERROR;
}
pCur = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pCur->pBtree);
sqlite3BtreeKeySize(pCur, (i64*)&n);
if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
char zBuf2[60];
sqlite3_snprintf(sizeof(zBuf2),zBuf2, "%llu", n);
Tcl_AppendResult(interp, zBuf2, 0);
}else{
- zBuf = malloc( n+1 );
+ zBuf = sqlite3_malloc( n+1 );
rc = sqlite3BtreeKey(pCur, 0, n, zBuf);
if( rc ){
+ sqlite3BtreeLeave(pCur->pBtree);
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
zBuf[n] = 0;
Tcl_AppendResult(interp, zBuf, 0);
- free(zBuf);
+ sqlite3_free(zBuf);
}
+ sqlite3BtreeLeave(pCur->pBtree);
return SQLITE_OK;
}
@@ -1044,20 +1152,23 @@ static int btree_data(
return TCL_ERROR;
}
pCur = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pCur->pBtree);
if( argc==2 ){
sqlite3BtreeDataSize(pCur, &n);
}else{
n = atoi(argv[2]);
}
- zBuf = malloc( n+1 );
+ zBuf = sqlite3_malloc( n+1 );
rc = sqlite3BtreeData(pCur, 0, n, zBuf);
+ sqlite3BtreeLeave(pCur->pBtree);
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
+ sqlite3_free(zBuf);
return TCL_ERROR;
}
zBuf[n] = 0;
Tcl_AppendResult(interp, zBuf, 0);
- free(zBuf);
+ sqlite3_free(zBuf);
return SQLITE_OK;
}
@@ -1087,6 +1198,7 @@ static int btree_fetch_key(
}
pCur = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
+ sqlite3BtreeEnter(pCur->pBtree);
sqlite3BtreeKeySize(pCur, (i64*)&nKey);
zBuf = sqlite3BtreeKeyFetch(pCur, &amt);
if( zBuf && amt>=n ){
@@ -1096,6 +1208,7 @@ static int btree_fetch_key(
zStatic[nKey] = 0;
Tcl_AppendResult(interp, zStatic, 0);
}
+ sqlite3BtreeLeave(pCur->pBtree);
return TCL_OK;
}
@@ -1125,6 +1238,7 @@ static int btree_fetch_data(
}
pCur = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
+ sqlite3BtreeEnter(pCur->pBtree);
sqlite3BtreeDataSize(pCur, &nData);
zBuf = sqlite3BtreeDataFetch(pCur, &amt);
if( zBuf && amt>=n ){
@@ -1134,6 +1248,7 @@ static int btree_fetch_data(
zStatic[nData] = 0;
Tcl_AppendResult(interp, zStatic, 0);
}
+ sqlite3BtreeLeave(pCur->pBtree);
return TCL_OK;
}
@@ -1159,12 +1274,14 @@ static int btree_payload_size(
return TCL_ERROR;
}
pCur = sqlite3TextToPtr(argv[1]);
+ sqlite3BtreeEnter(pCur->pBtree);
if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
n1 = 0;
}else{
sqlite3BtreeKeySize(pCur, (i64*)&n1);
}
sqlite3BtreeDataSize(pCur, (u32*)&n2);
+ sqlite3BtreeLeave(pCur->pBtree);
sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2));
Tcl_AppendResult(interp, zBuf, 0);
return SQLITE_OK;
@@ -1186,8 +1303,8 @@ static int btree_payload_size(
** aResult[7] = Header size in bytes
** aResult[8] = Local payload size
** aResult[9] = Parent page number
+** aResult[10]= Page number of the first overflow page
*/
-#ifdef SQLITE_DEBUG
static int btree_cursor_info(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
@@ -1198,7 +1315,7 @@ static int btree_cursor_info(
int rc;
int i, j;
int up;
- int aResult[10];
+ int aResult[11];
char zBuf[400];
if( argc!=2 && argc!=3 ){
@@ -1212,9 +1329,11 @@ static int btree_cursor_info(
}else{
up = 0;
}
+ sqlite3BtreeEnter(pCur->pBtree);
rc = sqlite3BtreeCursorInfo(pCur, aResult, up);
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
+ sqlite3BtreeLeave(pCur->pBtree);
return TCL_ERROR;
}
j = 0;
@@ -1222,10 +1341,86 @@ static int btree_cursor_info(
sqlite3_snprintf(40,&zBuf[j]," %d", aResult[i]);
j += strlen(&zBuf[j]);
}
+ sqlite3BtreeLeave(pCur->pBtree);
Tcl_AppendResult(interp, &zBuf[1], 0);
return SQLITE_OK;
}
-#endif
+
+/*
+** Copied from btree.c:
+*/
+static u32 t4Get4byte(unsigned char *p){
+ return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
+}
+
+/*
+** btree_ovfl_info BTREE CURSOR
+**
+** Given a cursor, return the sequence of pages number that form the
+** overflow pages for the data of the entry that the cursor is point
+** to.
+*/
+static int btree_ovfl_info(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ const char **argv /* Text of each argument */
+){
+ Btree *pBt;
+ BtCursor *pCur;
+ Pager *pPager;
+ int rc;
+ int n;
+ int dataSize;
+ u32 pgno;
+ void *pPage;
+ int aResult[11];
+ char zElem[100];
+ Tcl_DString str;
+
+ if( argc!=3 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " BTREE CURSOR", 0);
+ return TCL_ERROR;
+ }
+ pBt = sqlite3TextToPtr(argv[1]);
+ pCur = sqlite3TextToPtr(argv[2]);
+ if( (*(void**)pCur) != (void*)pBt ){
+ Tcl_AppendResult(interp, "Cursor ", argv[2], " does not belong to btree ",
+ argv[1], 0);
+ return TCL_ERROR;
+ }
+ sqlite3BtreeEnter(pBt);
+ pPager = sqlite3BtreePager(pBt);
+ rc = sqlite3BtreeCursorInfo(pCur, aResult, 0);
+ if( rc ){
+ Tcl_AppendResult(interp, errorName(rc), 0);
+ sqlite3BtreeLeave(pBt);
+ return TCL_ERROR;
+ }
+ dataSize = pBt->pBt->usableSize;
+ Tcl_DStringInit(&str);
+ n = aResult[6] - aResult[8];
+ n = (n + dataSize - 1)/dataSize;
+ pgno = (u32)aResult[10];
+ while( pgno && n-- ){
+ DbPage *pDbPage;
+ sprintf(zElem, "%d", pgno);
+ Tcl_DStringAppendElement(&str, zElem);
+ if( sqlite3PagerGet(pPager, pgno, &pDbPage)!=SQLITE_OK ){
+ Tcl_DStringFree(&str);
+ Tcl_AppendResult(interp, "unable to get page ", zElem, 0);
+ sqlite3BtreeLeave(pBt);
+ return TCL_ERROR;
+ }
+ pPage = sqlite3PagerGetData(pDbPage);
+ pgno = t4Get4byte((unsigned char*)pPage);
+ sqlite3PagerUnref(pDbPage);
+ }
+ sqlite3BtreeLeave(pBt);
+ Tcl_DStringResult(interp, &str);
+ return SQLITE_OK;
+}
/*
** The command is provided for the purpose of setting breakpoints.
@@ -1348,10 +1543,11 @@ static int btree_from_db(
Tcl_CmdInfo info;
sqlite3 *db;
Btree *pBt;
+ int iDb = 0;
- if( argc!=2 ){
+ if( argc!=2 && argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
- " DB-HANDLE\"", 0);
+ " DB-HANDLE ?N?\"", 0);
return TCL_ERROR;
}
@@ -1359,10 +1555,14 @@ static int btree_from_db(
Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
return TCL_ERROR;
}
+ if( argc==3 ){
+ iDb = atoi(argv[2]);
+ }
+
db = *((sqlite3 **)info.objClientData);
assert( db );
- pBt = db->aDb[0].pBt;
+ pBt = db->aDb[iDb].pBt;
sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
return TCL_OK;
@@ -1390,7 +1590,13 @@ static int btree_set_cache_size(
}
pBt = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
+
+ sqlite3_mutex_enter(pBt->db->mutex);
+ sqlite3BtreeEnter(pBt);
sqlite3BtreeSetCacheSize(pBt, nCache);
+ sqlite3BtreeLeave(pBt);
+ sqlite3_mutex_leave(pBt->db->mutex);
+
return TCL_OK;
}
@@ -1441,18 +1647,15 @@ 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_ovfl_info", (Tcl_CmdProc*)btree_ovfl_info },
{ "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list },
-#endif
};
int i;
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
}
- Tcl_LinkVar(interp, "pager_refinfo_enable", (char*)&pager3_refinfo_enable,
- TCL_LINK_INT);
Tcl_LinkVar(interp, "btree_trace", (char*)&sqlite3_btree_trace,
TCL_LINK_INT);
diff --git a/ext/pdo_sqlite/sqlite/src/test4.c b/ext/pdo_sqlite/sqlite/src/test4.c
index a7af482993..0aa2d0e0cc 100644
--- a/ext/pdo_sqlite/sqlite/src/test4.c
+++ b/ext/pdo_sqlite/sqlite/src/test4.c
@@ -15,8 +15,7 @@
*/
#include "sqliteInt.h"
#include "tcl.h"
-#include "os.h"
-#if defined(OS_UNIX) && OS_UNIX==1 && defined(THREADSAFE) && THREADSAFE==1
+#if defined(OS_UNIX) && OS_UNIX==1 && SQLITE_THREADSAFE
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
@@ -142,14 +141,14 @@ static int tcl_thread_create(
return TCL_ERROR;
}
threadset[i].busy = 1;
- sqliteFree(threadset[i].zFilename);
- threadset[i].zFilename = sqliteStrDup(argv[2]);
+ sqlite3_free(threadset[i].zFilename);
+ threadset[i].zFilename = sqlite3StrDup(argv[2]);
threadset[i].opnum = 1;
threadset[i].completed = 0;
rc = pthread_create(&x, 0, thread_main, &threadset[i]);
if( rc ){
Tcl_AppendResult(interp, "failed to create the thread", 0);
- sqliteFree(threadset[i].zFilename);
+ sqlite3_free(threadset[i].zFilename);
threadset[i].busy = 0;
return TCL_ERROR;
}
@@ -200,9 +199,9 @@ static void stop_thread(Thread *p){
p->xOp = 0;
p->opnum++;
thread_wait(p);
- sqliteFree(p->zArg);
+ sqlite3_free(p->zArg);
p->zArg = 0;
- sqliteFree(p->zFilename);
+ sqlite3_free(p->zFilename);
p->zFilename = 0;
p->busy = 0;
}
@@ -476,8 +475,8 @@ static int tcl_thread_compile(
}
thread_wait(&threadset[i]);
threadset[i].xOp = do_compile;
- sqliteFree(threadset[i].zArg);
- threadset[i].zArg = sqliteStrDup(argv[2]);
+ sqlite3_free(threadset[i].zArg);
+ threadset[i].zArg = sqlite3StrDup(argv[2]);
threadset[i].opnum++;
return TCL_OK;
}
@@ -571,7 +570,7 @@ static int tcl_thread_finalize(
}
thread_wait(&threadset[i]);
threadset[i].xOp = do_finalize;
- sqliteFree(threadset[i].zArg);
+ sqlite3_free(threadset[i].zArg);
threadset[i].zArg = 0;
threadset[i].opnum++;
return TCL_OK;
diff --git a/ext/pdo_sqlite/sqlite/src/test5.c b/ext/pdo_sqlite/sqlite/src/test5.c
index aaa7979a92..3be7833826 100644
--- a/ext/pdo_sqlite/sqlite/src/test5.c
+++ b/ext/pdo_sqlite/sqlite/src/test5.c
@@ -19,7 +19,6 @@
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
-#include "os.h" /* to get SQLITE_BIGENDIAN */
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
@@ -142,7 +141,7 @@ static int test_translate(
return TCL_ERROR;
}
if( objc==5 ){
- xDel = sqlite3FreeX;
+ xDel = sqlite3_free;
}
enc_from = name_to_enc(interp, objv[2]);
@@ -150,19 +149,19 @@ static int test_translate(
enc_to = name_to_enc(interp, objv[3]);
if( !enc_to ) return TCL_ERROR;
- pVal = sqlite3ValueNew();
+ pVal = sqlite3ValueNew(0);
if( enc_from==SQLITE_UTF8 ){
z = Tcl_GetString(objv[1]);
if( objc==5 ){
- z = sqliteStrDup(z);
+ z = sqlite3StrDup(z);
}
sqlite3ValueSetStr(pVal, -1, z, enc_from, xDel);
}else{
z = (char*)Tcl_GetByteArrayFromObj(objv[1], &len);
if( objc==5 ){
char *zTmp = z;
- z = sqliteMalloc(len);
+ z = sqlite3_malloc(len);
memcpy(z, zTmp, len);
}
sqlite3ValueSetStr(pVal, -1, z, enc_from, xDel);
@@ -180,10 +179,10 @@ static int test_translate(
/*
** Usage: translate_selftest
**
-** Call sqlite3utfSelfTest() to run the internal tests for unicode
+** Call sqlite3UtfSelfTest() to run the internal tests for unicode
** translation. If there is a problem an assert() will fail.
**/
-void sqlite3utfSelfTest();
+void sqlite3UtfSelfTest();
static int test_translate_selftest(
void * clientData,
Tcl_Interp *interp,
@@ -191,7 +190,7 @@ static int test_translate_selftest(
Tcl_Obj *CONST objv[]
){
#ifndef SQLITE_OMIT_UTF16
- sqlite3utfSelfTest();
+ sqlite3UtfSelfTest();
#endif
return SQLITE_OK;
}
diff --git a/ext/pdo_sqlite/sqlite/src/tokenize.c b/ext/pdo_sqlite/sqlite/src/tokenize.c
index 69db09aa4f..2aaa304688 100644
--- a/ext/pdo_sqlite/sqlite/src/tokenize.c
+++ b/ext/pdo_sqlite/sqlite/src/tokenize.c
@@ -18,7 +18,6 @@
** $Id$
*/
#include "sqliteInt.h"
-#include "os.h"
#include <ctype.h>
#include <stdlib.h>
@@ -86,7 +85,7 @@ const unsigned char ebcdicToAscii[] = {
** But the feature is undocumented.
*/
#ifdef SQLITE_ASCII
-const char sqlite3IsIdChar[] = {
+const char sqlite3IsAsciiIdChar[] = {
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */
@@ -95,10 +94,10 @@ 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]))
+#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsAsciiIdChar[c-0x20]))
#endif
#ifdef SQLITE_EBCDIC
-const char sqlite3IsIdChar[] = {
+const char sqlite3IsEbcdicIdChar[] = {
/* 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 */
@@ -113,7 +112,7 @@ const char sqlite3IsIdChar[] = {
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]))
+#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
#endif
@@ -293,7 +292,7 @@ static int getToken(const unsigned char *z, int *tokenType){
}
case '[': {
for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){}
- *tokenType = TK_ID;
+ *tokenType = c==']' ? TK_ID : TK_ILLEGAL;
return i;
}
case '?': {
@@ -345,19 +344,14 @@ static int getToken(const unsigned char *z, int *tokenType){
}
#ifndef SQLITE_OMIT_BLOB_LITERAL
case 'x': case 'X': {
- if( (c=z[1])=='\'' || c=='"' ){
- int delim = c;
+ if( z[1]=='\'' ){
*tokenType = TK_BLOB;
- for(i=2; (c=z[i])!=0; i++){
- if( c==delim ){
- if( i%2 ) *tokenType = TK_ILLEGAL;
- break;
- }
+ for(i=2; (c=z[i])!=0 && c!='\''; i++){
if( !isxdigit(c) ){
*tokenType = TK_ILLEGAL;
- return i;
}
}
+ if( i%2 || !c ) *tokenType = TK_ILLEGAL;
if( c ) i++;
return i;
}
@@ -384,7 +378,7 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
** Run the parser on the given SQL string. The parser structure is
** passed in. An SQLITE_ status code is returned. If an error occurs
** and pzErrMsg!=NULL then an error message might be written into
-** memory obtained from malloc() and *pzErrMsg made to point to that
+** memory obtained from sqlite3_malloc() and *pzErrMsg made to point to that
** error message. Or maybe not.
*/
int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
@@ -394,17 +388,15 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
int tokenType;
int lastTokenParsed = -1;
sqlite3 *db = pParse->db;
- extern void *sqlite3ParserAlloc(void*(*)(int));
- extern void sqlite3ParserFree(void*, void(*)(void*));
- extern int sqlite3Parser(void*, int, Token, Parse*);
if( db->activeVdbeCnt==0 ){
db->u1.isInterrupted = 0;
}
pParse->rc = SQLITE_OK;
i = 0;
- pEngine = sqlite3ParserAlloc((void*(*)(int))sqlite3MallocX);
+ pEngine = sqlite3ParserAlloc((void*(*)(size_t))sqlite3_malloc);
if( pEngine==0 ){
+ db->mallocFailed = 1;
return SQLITE_NOMEM;
}
assert( pParse->sLastToken.dyn==0 );
@@ -415,12 +407,16 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
assert( pParse->nVarExprAlloc==0 );
assert( pParse->apVarExpr==0 );
pParse->zTail = pParse->zSql = zSql;
- while( !sqlite3MallocFailed() && zSql[i]!=0 ){
+ while( !db->mallocFailed && zSql[i]!=0 ){
assert( i>=0 );
pParse->sLastToken.z = (u8*)&zSql[i];
assert( pParse->sLastToken.dyn==0 );
pParse->sLastToken.n = getToken((unsigned char*)&zSql[i],&tokenType);
i += pParse->sLastToken.n;
+ if( SQLITE_MAX_SQL_LENGTH>0 && i>SQLITE_MAX_SQL_LENGTH ){
+ pParse->rc = SQLITE_TOOBIG;
+ break;
+ }
switch( tokenType ){
case TK_SPACE:
case TK_COMMENT: {
@@ -433,8 +429,8 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
}
case TK_ILLEGAL: {
if( pzErrMsg ){
- sqliteFree(*pzErrMsg);
- *pzErrMsg = sqlite3MPrintf("unrecognized token: \"%T\"",
+ sqlite3_free(*pzErrMsg);
+ *pzErrMsg = sqlite3MPrintf(db, "unrecognized token: \"%T\"",
&pParse->sLastToken);
}
nErr++;
@@ -462,8 +458,8 @@ abort_parse:
}
sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
}
- sqlite3ParserFree(pEngine, sqlite3FreeX);
- if( sqlite3MallocFailed() ){
+ sqlite3ParserFree(pEngine, sqlite3_free);
+ if( db->mallocFailed ){
pParse->rc = SQLITE_NOMEM;
}
if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
@@ -473,10 +469,10 @@ abort_parse:
if( pzErrMsg && *pzErrMsg==0 ){
*pzErrMsg = pParse->zErrMsg;
}else{
- sqliteFree(pParse->zErrMsg);
+ sqlite3_free(pParse->zErrMsg);
}
pParse->zErrMsg = 0;
- if( !nErr ) nErr++;
+ nErr++;
}
if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){
sqlite3VdbeDelete(pParse->pVdbe);
@@ -484,7 +480,7 @@ abort_parse:
}
#ifndef SQLITE_OMIT_SHARED_CACHE
if( pParse->nested==0 ){
- sqliteFree(pParse->aTableLock);
+ sqlite3_free(pParse->aTableLock);
pParse->aTableLock = 0;
pParse->nTableLock = 0;
}
@@ -495,11 +491,11 @@ abort_parse:
** 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);
+ sqlite3DeleteTable(pParse->pNewTable);
}
sqlite3DeleteTrigger(pParse->pNewTrigger);
- sqliteFree(pParse->apVarExpr);
+ sqlite3_free(pParse->apVarExpr);
if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){
pParse->rc = SQLITE_ERROR;
}
diff --git a/ext/pdo_sqlite/sqlite/src/trigger.c b/ext/pdo_sqlite/sqlite/src/trigger.c
index 15992df381..70cf6aba53 100644
--- a/ext/pdo_sqlite/sqlite/src/trigger.c
+++ b/ext/pdo_sqlite/sqlite/src/trigger.c
@@ -21,13 +21,13 @@ void sqlite3DeleteTriggerStep(TriggerStep *pTriggerStep){
TriggerStep * pTmp = pTriggerStep;
pTriggerStep = pTriggerStep->pNext;
- if( pTmp->target.dyn ) sqliteFree((char*)pTmp->target.z);
+ if( pTmp->target.dyn ) sqlite3_free((char*)pTmp->target.z);
sqlite3ExprDelete(pTmp->pWhere);
sqlite3ExprListDelete(pTmp->pExprList);
sqlite3SelectDelete(pTmp->pSelect);
sqlite3IdListDelete(pTmp->pIdList);
- sqliteFree(pTmp);
+ sqlite3_free(pTmp);
}
}
@@ -47,9 +47,9 @@ void sqlite3BeginTrigger(
int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
IdList *pColumns, /* column list if this is an UPDATE OF trigger */
SrcList *pTableName,/* The name of the table/view the trigger applies to */
- int foreach, /* One of TK_ROW or TK_STATEMENT */
Expr *pWhen, /* WHEN clause */
- int isTemp /* True if the TEMPORARY keyword is present */
+ int isTemp, /* True if the TEMPORARY keyword is present */
+ int noErr /* Suppress errors if the trigger already exists */
){
Trigger *pTrigger = 0;
Table *pTab;
@@ -83,7 +83,7 @@ void sqlite3BeginTrigger(
** If sqlite3SrcListLookup() returns 0, indicating the table does not
** exist, the error is caught by the block below.
*/
- if( !pTableName || sqlite3MallocFailed() ){
+ if( !pTableName || db->mallocFailed ){
goto trigger_cleanup;
}
pTab = sqlite3SrcListLookup(pParse, pTableName);
@@ -92,7 +92,7 @@ void sqlite3BeginTrigger(
}
/* Ensure the table name matches database name and that the table exists */
- if( sqlite3MallocFailed() ) goto trigger_cleanup;
+ if( db->mallocFailed ) goto trigger_cleanup;
assert( pTableName->nSrc==1 );
if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) &&
sqlite3FixSrcList(&sFix, pTableName) ){
@@ -110,12 +110,14 @@ void sqlite3BeginTrigger(
/* Check that the trigger name is not reserved and that no trigger of the
** specified name exists */
- zName = sqlite3NameFromToken(pName);
+ zName = sqlite3NameFromToken(db, pName);
if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
goto trigger_cleanup;
}
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), zName,strlen(zName)) ){
- sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
+ if( !noErr ){
+ sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
+ }
goto trigger_cleanup;
}
@@ -166,24 +168,23 @@ void sqlite3BeginTrigger(
}
/* Build the Trigger object */
- pTrigger = (Trigger*)sqliteMalloc(sizeof(Trigger));
+ pTrigger = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger));
if( pTrigger==0 ) goto trigger_cleanup;
pTrigger->name = zName;
zName = 0;
- pTrigger->table = sqliteStrDup(pTableName->a[0].zName);
+ pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName);
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);
- pTrigger->pColumns = sqlite3IdListDup(pColumns);
- pTrigger->foreach = foreach;
- sqlite3TokenCopy(&pTrigger->nameToken,pName);
+ pTrigger->pWhen = sqlite3ExprDup(db, pWhen);
+ pTrigger->pColumns = sqlite3IdListDup(db, pColumns);
+ sqlite3TokenCopy(db, &pTrigger->nameToken,pName);
assert( pParse->pNewTrigger==0 );
pParse->pNewTrigger = pTrigger;
trigger_cleanup:
- sqliteFree(zName);
+ sqlite3_free(zName);
sqlite3SrcListDelete(pTableName);
sqlite3IdListDelete(pColumns);
sqlite3ExprDelete(pWhen);
@@ -226,34 +227,23 @@ void sqlite3FinishTrigger(
** build the sqlite_master entry
*/
if( !db->init.busy ){
- static const VdbeOpList insertTrig[] = {
- { OP_NewRowid, 0, 0, 0 },
- { OP_String8, 0, 0, "trigger" },
- { OP_String8, 0, 0, 0 }, /* 2: trigger name */
- { OP_String8, 0, 0, 0 }, /* 3: table name */
- { OP_Integer, 0, 0, 0 },
- { OP_String8, 0, 0, "CREATE TRIGGER "},
- { OP_String8, 0, 0, 0 }, /* 6: SQL */
- { OP_Concat, 0, 0, 0 },
- { OP_MakeRecord, 5, 0, "aaada" },
- { OP_Insert, 0, 0, 0 },
- };
- int addr;
Vdbe *v;
+ char *z;
/* Make an entry in the sqlite_master table */
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto triggerfinish_cleanup;
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, (char*)pAll->z, pAll->n);
- sqlite3ChangeCookie(db, v, iDb);
- sqlite3VdbeAddOp(v, OP_Close, 0, 0);
- sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0,
- sqlite3MPrintf("type='trigger' AND name='%q'", pTrig->name), P3_DYNAMIC);
+ z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
+ sqlite3NestedParse(pParse,
+ "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
+ db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTrig->name,
+ pTrig->table, z);
+ sqlite3_free(z);
+ sqlite3ChangeCookie(pParse, iDb);
+ sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, sqlite3MPrintf(
+ db, "type='trigger' AND name='%q'", pTrig->name), P4_DYNAMIC
+ );
}
if( db->init.busy ){
@@ -263,7 +253,8 @@ void sqlite3FinishTrigger(
pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash,
pTrig->name, strlen(pTrig->name), pTrig);
if( pDel ){
- assert( sqlite3MallocFailed() && pDel==pTrig );
+ assert( pDel==pTrig );
+ db->mallocFailed = 1;
goto triggerfinish_cleanup;
}
n = strlen(pTrig->table) + 1;
@@ -283,35 +274,35 @@ triggerfinish_cleanup:
/*
** Make a copy of all components of the given trigger step. This has
** the effect of copying all Expr.token.z values into memory obtained
-** from sqliteMalloc(). As initially created, the Expr.token.z values
+** from sqlite3_malloc(). As initially created, the Expr.token.z values
** all point to the input string that was fed to the parser. But that
** string is ephemeral - it will go away as soon as the sqlite3_exec()
** call that started the parser exits. This routine makes a persistent
** copy of all the Expr.token.z strings so that the TriggerStep structure
** will be valid even after the sqlite3_exec() call returns.
*/
-static void sqlitePersistTriggerStep(TriggerStep *p){
+static void sqlitePersistTriggerStep(sqlite3 *db, TriggerStep *p){
if( p->target.z ){
- p->target.z = (u8*)sqliteStrNDup((char*)p->target.z, p->target.n);
+ p->target.z = (u8*)sqlite3DbStrNDup(db, (char*)p->target.z, p->target.n);
p->target.dyn = 1;
}
if( p->pSelect ){
- Select *pNew = sqlite3SelectDup(p->pSelect);
+ Select *pNew = sqlite3SelectDup(db, p->pSelect);
sqlite3SelectDelete(p->pSelect);
p->pSelect = pNew;
}
if( p->pWhere ){
- Expr *pNew = sqlite3ExprDup(p->pWhere);
+ Expr *pNew = sqlite3ExprDup(db, p->pWhere);
sqlite3ExprDelete(p->pWhere);
p->pWhere = pNew;
}
if( p->pExprList ){
- ExprList *pNew = sqlite3ExprListDup(p->pExprList);
+ ExprList *pNew = sqlite3ExprListDup(db, p->pExprList);
sqlite3ExprListDelete(p->pExprList);
p->pExprList = pNew;
}
if( p->pIdList ){
- IdList *pNew = sqlite3IdListDup(p->pIdList);
+ IdList *pNew = sqlite3IdListDup(db, p->pIdList);
sqlite3IdListDelete(p->pIdList);
p->pIdList = pNew;
}
@@ -324,8 +315,8 @@ static void sqlitePersistTriggerStep(TriggerStep *p){
** The parser calls this routine when it finds a SELECT statement in
** body of a TRIGGER.
*/
-TriggerStep *sqlite3TriggerSelectStep(Select *pSelect){
- TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
+TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
+ TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
if( pTriggerStep==0 ) {
sqlite3SelectDelete(pSelect);
return 0;
@@ -334,7 +325,7 @@ TriggerStep *sqlite3TriggerSelectStep(Select *pSelect){
pTriggerStep->op = TK_SELECT;
pTriggerStep->pSelect = pSelect;
pTriggerStep->orconf = OE_Default;
- sqlitePersistTriggerStep(pTriggerStep);
+ sqlitePersistTriggerStep(db, pTriggerStep);
return pTriggerStep;
}
@@ -347,17 +338,19 @@ TriggerStep *sqlite3TriggerSelectStep(Select *pSelect){
** body of a trigger.
*/
TriggerStep *sqlite3TriggerInsertStep(
+ sqlite3 *db, /* The database connection */
Token *pTableName, /* Name of the table into which we insert */
IdList *pColumn, /* List of columns in pTableName to insert into */
ExprList *pEList, /* The VALUE clause: a list of values to be inserted */
Select *pSelect, /* A SELECT statement that supplies values */
int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
){
- TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
+ TriggerStep *pTriggerStep;
assert(pEList == 0 || pSelect == 0);
- assert(pEList != 0 || pSelect != 0);
+ assert(pEList != 0 || pSelect != 0 || db->mallocFailed);
+ pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
if( pTriggerStep ){
pTriggerStep->op = TK_INSERT;
pTriggerStep->pSelect = pSelect;
@@ -365,11 +358,11 @@ TriggerStep *sqlite3TriggerInsertStep(
pTriggerStep->pIdList = pColumn;
pTriggerStep->pExprList = pEList;
pTriggerStep->orconf = orconf;
- sqlitePersistTriggerStep(pTriggerStep);
+ sqlitePersistTriggerStep(db, pTriggerStep);
}else{
sqlite3IdListDelete(pColumn);
sqlite3ExprListDelete(pEList);
- sqlite3SelectDup(pSelect);
+ sqlite3SelectDelete(pSelect);
}
return pTriggerStep;
@@ -381,20 +374,25 @@ TriggerStep *sqlite3TriggerInsertStep(
** sees an UPDATE statement inside the body of a CREATE TRIGGER.
*/
TriggerStep *sqlite3TriggerUpdateStep(
+ sqlite3 *db, /* The database connection */
Token *pTableName, /* Name of the table to be updated */
ExprList *pEList, /* The SET clause: list of column and new values */
Expr *pWhere, /* The WHERE clause */
int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
){
- TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
- if( pTriggerStep==0 ) return 0;
+ TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
+ if( pTriggerStep==0 ){
+ sqlite3ExprListDelete(pEList);
+ sqlite3ExprDelete(pWhere);
+ return 0;
+ }
pTriggerStep->op = TK_UPDATE;
pTriggerStep->target = *pTableName;
pTriggerStep->pExprList = pEList;
pTriggerStep->pWhere = pWhere;
pTriggerStep->orconf = orconf;
- sqlitePersistTriggerStep(pTriggerStep);
+ sqlitePersistTriggerStep(db, pTriggerStep);
return pTriggerStep;
}
@@ -404,15 +402,22 @@ TriggerStep *sqlite3TriggerUpdateStep(
** a pointer to that trigger step. The parser calls this routine when it
** sees a DELETE statement inside the body of a CREATE TRIGGER.
*/
-TriggerStep *sqlite3TriggerDeleteStep(Token *pTableName, Expr *pWhere){
- TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
- if( pTriggerStep==0 ) return 0;
+TriggerStep *sqlite3TriggerDeleteStep(
+ sqlite3 *db, /* Database connection */
+ Token *pTableName, /* The table from which rows are deleted */
+ Expr *pWhere /* The WHERE clause */
+){
+ TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
+ if( pTriggerStep==0 ){
+ sqlite3ExprDelete(pWhere);
+ return 0;
+ }
pTriggerStep->op = TK_DELETE;
pTriggerStep->target = *pTableName;
pTriggerStep->pWhere = pWhere;
pTriggerStep->orconf = OE_Default;
- sqlitePersistTriggerStep(pTriggerStep);
+ sqlitePersistTriggerStep(db, pTriggerStep);
return pTriggerStep;
}
@@ -423,12 +428,12 @@ TriggerStep *sqlite3TriggerDeleteStep(Token *pTableName, Expr *pWhere){
void sqlite3DeleteTrigger(Trigger *pTrigger){
if( pTrigger==0 ) return;
sqlite3DeleteTriggerStep(pTrigger->step_list);
- sqliteFree(pTrigger->name);
- sqliteFree(pTrigger->table);
+ sqlite3_free(pTrigger->name);
+ sqlite3_free(pTrigger->table);
sqlite3ExprDelete(pTrigger->pWhen);
sqlite3IdListDelete(pTrigger->pColumns);
- if( pTrigger->nameToken.dyn ) sqliteFree((char*)pTrigger->nameToken.z);
- sqliteFree(pTrigger);
+ if( pTrigger->nameToken.dyn ) sqlite3_free((char*)pTrigger->nameToken.z);
+ sqlite3_free(pTrigger);
}
/*
@@ -439,7 +444,7 @@ void sqlite3DeleteTrigger(Trigger *pTrigger){
** same job as this routine except it takes a pointer to the trigger
** instead of the trigger name.
**/
-void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
+void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
Trigger *pTrigger = 0;
int i;
const char *zDb;
@@ -447,7 +452,7 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
int nName;
sqlite3 *db = pParse->db;
- if( sqlite3MallocFailed() ) goto drop_trigger_cleanup;
+ if( db->mallocFailed ) goto drop_trigger_cleanup;
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto drop_trigger_cleanup;
}
@@ -463,7 +468,9 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
if( pTrigger ) break;
}
if( !pTrigger ){
- sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
+ if( !noErr ){
+ sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
+ }
goto drop_trigger_cleanup;
}
sqlite3DropTriggerPtr(pParse, pTrigger);
@@ -516,12 +523,12 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
int base;
static const VdbeOpList dropTrigger[] = {
{ OP_Rewind, 0, ADDR(9), 0},
- { OP_String8, 0, 0, 0}, /* 1 */
- { OP_Column, 0, 1, 0},
- { OP_Ne, 0, ADDR(8), 0},
- { OP_String8, 0, 0, "trigger"},
- { OP_Column, 0, 0, 0},
- { OP_Ne, 0, ADDR(8), 0},
+ { OP_String8, 0, 1, 0}, /* 1 */
+ { OP_Column, 0, 1, 2},
+ { OP_Ne, 2, ADDR(8), 1},
+ { OP_String8, 0, 1, 0}, /* 4: "trigger" */
+ { OP_Column, 0, 0, 2},
+ { OP_Ne, 2, ADDR(8), 1},
{ OP_Delete, 0, 0, 0},
{ OP_Next, 0, ADDR(1), 0}, /* 8 */
};
@@ -529,10 +536,11 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3OpenMasterTable(pParse, iDb);
base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
- sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0);
- sqlite3ChangeCookie(db, v, iDb);
- sqlite3VdbeAddOp(v, OP_Close, 0, 0);
- sqlite3VdbeOp3(v, OP_DropTrigger, iDb, 0, pTrigger->name, 0);
+ sqlite3VdbeChangeP4(v, base+1, pTrigger->name, 0);
+ sqlite3VdbeChangeP4(v, base+4, "trigger", P4_STATIC);
+ sqlite3ChangeCookie(pParse, iDb);
+ sqlite3VdbeAddOp2(v, OP_Close, 0, 0);
+ sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->name, 0);
}
}
@@ -634,9 +642,9 @@ static SrcList *targetSrcList(
assert( iDb<pParse->db->nDb );
sDb.z = (u8*)pParse->db->aDb[iDb].zName;
sDb.n = strlen((char*)sDb.z);
- pSrc = sqlite3SrcListAppend(0, &sDb, &pStep->target);
+ pSrc = sqlite3SrcListAppend(pParse->db, 0, &sDb, &pStep->target);
} else {
- pSrc = sqlite3SrcListAppend(0, &pStep->target, 0);
+ pSrc = sqlite3SrcListAppend(pParse->db, 0, &pStep->target, 0);
}
return pSrc;
}
@@ -653,51 +661,56 @@ static int codeTriggerProgram(
TriggerStep * pTriggerStep = pStepList;
int orconf;
Vdbe *v = pParse->pVdbe;
+ sqlite3 *db = pParse->db;
assert( pTriggerStep!=0 );
assert( v!=0 );
- sqlite3VdbeAddOp(v, OP_ContextPush, 0, 0);
- VdbeComment((v, "# begin trigger %s", pStepList->pTrig->name));
+ sqlite3VdbeAddOp2(v, OP_ContextPush, 0, 0);
+ VdbeComment((v, "begin trigger %s", pStepList->pTrig->name));
while( pTriggerStep ){
orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
pParse->trigStack->orconf = orconf;
switch( pTriggerStep->op ){
case TK_SELECT: {
- Select * ss = sqlite3SelectDup(pTriggerStep->pSelect);
- assert(ss);
- assert(ss->pSrc);
- sqlite3SelectResolve(pParse, ss, 0);
- sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
- sqlite3SelectDelete(ss);
- break;
+ Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect);
+ if( ss ){
+ SelectDest dest;
+
+ sqlite3SelectDestInit(&dest, SRT_Discard, 0);
+ sqlite3SelectResolve(pParse, ss, 0);
+ sqlite3Select(pParse, ss, &dest, 0, 0, 0, 0);
+ sqlite3SelectDelete(ss);
+ }
+ break;
}
case TK_UPDATE: {
SrcList *pSrc;
pSrc = targetSrcList(pParse, pTriggerStep);
- sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
sqlite3Update(pParse, pSrc,
- sqlite3ExprListDup(pTriggerStep->pExprList),
- sqlite3ExprDup(pTriggerStep->pWhere), orconf);
- sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
+ sqlite3ExprListDup(db, pTriggerStep->pExprList),
+ sqlite3ExprDup(db, pTriggerStep->pWhere), orconf);
+ sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
break;
}
case TK_INSERT: {
SrcList *pSrc;
pSrc = targetSrcList(pParse, pTriggerStep);
- sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
sqlite3Insert(pParse, pSrc,
- sqlite3ExprListDup(pTriggerStep->pExprList),
- sqlite3SelectDup(pTriggerStep->pSelect),
- sqlite3IdListDup(pTriggerStep->pIdList), orconf);
- sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
+ sqlite3ExprListDup(db, pTriggerStep->pExprList),
+ sqlite3SelectDup(db, pTriggerStep->pSelect),
+ sqlite3IdListDup(db, pTriggerStep->pIdList), orconf);
+ sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
break;
}
case TK_DELETE: {
SrcList *pSrc;
- sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
pSrc = targetSrcList(pParse, pTriggerStep);
- sqlite3DeleteFrom(pParse, pSrc, sqlite3ExprDup(pTriggerStep->pWhere));
- sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
+ sqlite3DeleteFrom(pParse, pSrc,
+ sqlite3ExprDup(db, pTriggerStep->pWhere));
+ sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
break;
}
default:
@@ -705,8 +718,8 @@ static int codeTriggerProgram(
}
pTriggerStep = pTriggerStep->pNext;
}
- sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0);
- VdbeComment((v, "# end trigger %s", pStepList->pTrig->name));
+ sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0);
+ VdbeComment((v, "end trigger %s", pStepList->pTrig->name));
return 0;
}
@@ -730,6 +743,13 @@ static int codeTriggerProgram(
** a row containing values to be substituted for old.* expressions in the
** trigger program(s).
**
+** If they are not NULL, the piOldColMask and piNewColMask output variables
+** are set to values that describe the columns used by the trigger program
+** in the OLD.* and NEW.* tables respectively. If column N of the
+** pseudo-table is read at least once, the corresponding bit of the output
+** mask is set. If a column with an index greater than 32 is read, the
+** output mask is set to the special value 0xffffffff.
+**
*/
int sqlite3CodeRowTrigger(
Parse *pParse, /* Parse context */
@@ -740,11 +760,17 @@ int sqlite3CodeRowTrigger(
int newIdx, /* The indice of the "new" row to access */
int oldIdx, /* The indice of the "old" row to access */
int orconf, /* ON CONFLICT policy */
- int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */
+ int ignoreJump, /* Instruction to jump to for RAISE(IGNORE) */
+ u32 *piOldColMask, /* OUT: Mask of columns used from the OLD.* table */
+ u32 *piNewColMask /* OUT: Mask of columns used from the NEW.* table */
){
Trigger *p;
+ sqlite3 *db = pParse->db;
TriggerStack trigStackEntry;
+ trigStackEntry.oldColMask = 0;
+ trigStackEntry.newColMask = 0;
+
assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
assert(tr_tm == TRIGGER_BEFORE || tr_tm == TRIGGER_AFTER );
@@ -757,7 +783,7 @@ int sqlite3CodeRowTrigger(
if(
p->op==op &&
p->tr_tm==tr_tm &&
- (p->pSchema==p->pTabSchema || p->pSchema==pParse->db->aDb[1].pSchema) &&
+ (p->pSchema==p->pTabSchema || p->pSchema==db->aDb[1].pSchema) &&
(op!=TK_UPDATE||!p->pColumns||checkColumnOverLap(p->pColumns,pChanges))
){
TriggerStack *pS; /* Pointer to trigger-stack entry */
@@ -780,6 +806,11 @@ int sqlite3CodeRowTrigger(
AuthContext sContext;
NameContext sNC;
+#ifndef SQLITE_OMIT_TRACE
+ sqlite3VdbeAddOp4(pParse->pVdbe, OP_Trace, 0, 0, 0,
+ sqlite3MPrintf(db, "-- TRIGGER %s", p->name),
+ P4_DYNAMIC);
+#endif
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
@@ -795,13 +826,13 @@ int sqlite3CodeRowTrigger(
/* code the WHEN clause */
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
- whenExpr = sqlite3ExprDup(p->pWhen);
- if( sqlite3ExprResolveNames(&sNC, whenExpr) ){
+ whenExpr = sqlite3ExprDup(db, p->pWhen);
+ if( db->mallocFailed || sqlite3ExprResolveNames(&sNC, whenExpr) ){
pParse->trigStack = trigStackEntry.pNext;
sqlite3ExprDelete(whenExpr);
return 1;
}
- sqlite3ExprIfFalse(pParse, whenExpr, endTrigger, 1);
+ sqlite3ExprIfFalse(pParse, whenExpr, endTrigger, SQLITE_JUMPIFNULL);
sqlite3ExprDelete(whenExpr);
codeTriggerProgram(pParse, p->step_list, orconf);
@@ -813,6 +844,8 @@ int sqlite3CodeRowTrigger(
sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger);
}
}
+ if( piOldColMask ) *piOldColMask |= trigStackEntry.oldColMask;
+ if( piNewColMask ) *piNewColMask |= trigStackEntry.newColMask;
return 0;
}
#endif /* !defined(SQLITE_OMIT_TRIGGER) */
diff --git a/ext/pdo_sqlite/sqlite/src/update.c b/ext/pdo_sqlite/sqlite/src/update.c
index 2565787f04..19f669a29f 100644
--- a/ext/pdo_sqlite/sqlite/src/update.c
+++ b/ext/pdo_sqlite/sqlite/src/update.c
@@ -31,7 +31,7 @@ static void updateVirtualTable(
/*
** 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
+** i-th column of table pTab. This routine sets the P4 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
@@ -39,9 +39,9 @@ static void updateVirtualTable(
** was created, or added later to the table definition by an ALTER TABLE
** command. If the latter, then the row-records in the table btree on disk
** may not contain a value for the column and the default value, taken
-** from the P3 parameter of the OP_Column instruction, is returned instead.
+** from the P4 parameter of the OP_Column instruction, is returned instead.
** If the former, then all row-records are guaranteed to include a value
-** for the column and the P3 value is not required.
+** for the column and the P4 value is not required.
**
** Column definitions created by an ALTER TABLE command may only have
** literal default values specified: a number, null or a string. (If a more
@@ -49,7 +49,7 @@ static void updateVirtualTable(
** when the ALTER TABLE is executed and one of the literal values written
** into the sqlite_master table.)
**
-** Therefore, the P3 parameter is only required if the default value for
+** Therefore, the P4 parameter is only required if the default value for
** the column is a literal number, string or null. The sqlite3ValueFromExpr()
** function is capable of transforming these types of expressions into
** sqlite3_value objects.
@@ -59,11 +59,12 @@ void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i){
sqlite3_value *pValue;
u8 enc = ENC(sqlite3VdbeDb(v));
Column *pCol = &pTab->aCol[i];
- sqlite3ValueFromExpr(pCol->pDflt, enc, pCol->affinity, &pValue);
+ VdbeComment((v, "%s.%s", pTab->zName, pCol->zName));
+ assert( i<pTab->nCol );
+ sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc,
+ pCol->affinity, &pValue);
if( pValue ){
- sqlite3VdbeChangeP3(v, -1, (const char *)pValue, P3_MEM);
- }else{
- VdbeComment((v, "# %s.%s", pTab->zName, pCol->zName));
+ sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM);
}
}
}
@@ -89,11 +90,9 @@ void sqlite3Update(
Vdbe *v; /* The virtual database engine */
Index *pIdx; /* For looping over indices */
int nIdx; /* Number of indices that need updating */
- int nIdxTotal; /* Total number of indices */
int iCur; /* VDBE Cursor number of pTab */
sqlite3 *db; /* The database structure */
- Index **apIdx = 0; /* An array of indices that need updating too */
- char *aIdxUsed = 0; /* aIdxUsed[i]==1 if the i-th index is used */
+ int *aRegIdx = 0; /* One register assigned to each index to be updated */
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
** an expression for the i-th column of the table.
** aXRef[i]==-1 if the i-th column is not changed. */
@@ -103,20 +102,33 @@ void sqlite3Update(
AuthContext sContext; /* The authorization context */
NameContext sNC; /* The name-context to resolve expressions in */
int iDb; /* Database containing the table being updated */
+ int j1; /* Addresses of jump instructions */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* Trying to update a view */
int triggers_exist = 0; /* True if any row triggers exist */
#endif
+ int iBeginAfterTrigger; /* Address of after trigger program */
+ int iEndAfterTrigger; /* Exit of after trigger program */
+ int iBeginBeforeTrigger; /* Address of before trigger program */
+ int iEndBeforeTrigger; /* Exit of before trigger program */
+ u32 old_col_mask = 0; /* Mask of OLD.* columns in use */
+ u32 new_col_mask = 0; /* Mask of NEW.* columns in use */
int newIdx = -1; /* index of trigger "new" temp table */
int oldIdx = -1; /* index of trigger "old" temp table */
+ /* Register Allocations */
+ int regRowCount = 0; /* A count of rows changed */
+ int regOldRowid; /* The old rowid */
+ int regNewRowid; /* The new rowid */
+ int regData; /* New data for the row */
+
sContext.pParse = 0;
- if( pParse->nErr || sqlite3MallocFailed() ){
+ db = pParse->db;
+ if( pParse->nErr || db->mallocFailed ){
goto update_cleanup;
}
- db = pParse->db;
assert( pTabList->nSrc==1 );
/* Locate the table which we want to update.
@@ -146,7 +158,7 @@ void sqlite3Update(
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto update_cleanup;
}
- aXRef = sqliteMallocRaw( sizeof(int) * pTab->nCol );
+ aXRef = sqlite3DbMallocRaw(db, sizeof(int) * pTab->nCol );
if( aXRef==0 ) goto update_cleanup;
for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
@@ -217,42 +229,48 @@ void sqlite3Update(
#endif
}
- /* Allocate memory for the array apIdx[] and fill it with pointers to every
- ** index that needs to be updated. Indices only need updating if their
- ** key includes one of the columns named in pChanges or if the record
- ** number of the original table entry is changing.
+ /* Allocate memory for the array aRegIdx[]. There is one entry in the
+ ** array for each index associated with table being updated. Fill in
+ ** the value with a register number for indices that are to be used
+ ** and with zero for unused indices.
*/
- for(nIdx=nIdxTotal=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdxTotal++){
- if( chngRowid ){
- i = 0;
- }else {
- for(i=0; i<pIdx->nColumn; i++){
- if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
- }
- }
- if( i<pIdx->nColumn ) nIdx++;
+ for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){}
+ if( nIdx>0 ){
+ aRegIdx = sqlite3DbMallocRaw(db, sizeof(Index*) * nIdx );
+ if( aRegIdx==0 ) goto update_cleanup;
}
- if( nIdxTotal>0 ){
- apIdx = sqliteMallocRaw( sizeof(Index*) * nIdx + nIdxTotal );
- if( apIdx==0 ) goto update_cleanup;
- aIdxUsed = (char*)&apIdx[nIdx];
- }
- for(nIdx=j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
+ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
+ int reg;
if( chngRowid ){
- i = 0;
+ reg = ++pParse->nMem;
}else{
+ reg = 0;
for(i=0; i<pIdx->nColumn; i++){
- if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
+ if( aXRef[pIdx->aiColumn[i]]>=0 ){
+ reg = ++pParse->nMem;
+ break;
+ }
}
}
- if( i<pIdx->nColumn ){
- apIdx[nIdx++] = pIdx;
- aIdxUsed[j] = 1;
- }else{
- aIdxUsed[j] = 0;
- }
+ aRegIdx[j] = reg;
}
+ /* Allocate a block of register used to store the change record
+ ** sent to sqlite3GenerateConstraintChecks(). There are either
+ ** one or two registers for holding the rowid. One rowid register
+ ** is used if chngRowid is false and two are used if chngRowid is
+ ** true. Following these are pTab->nCol register holding column
+ ** data.
+ */
+ regOldRowid = regNewRowid = pParse->nMem + 1;
+ pParse->nMem += pTab->nCol + 1;
+ if( chngRowid ){
+ regNewRowid++;
+ pParse->nMem++;
+ }
+ regData = regNewRowid+1;
+
+
/* Begin generating code.
*/
v = sqlite3GetVdbe(pParse);
@@ -284,25 +302,58 @@ void sqlite3Update(
sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
}
+ /* Generate the code for triggers.
+ */
+ if( triggers_exist ){
+ int iGoto;
+
+ /* Create pseudo-tables for NEW and OLD
+ */
+ sqlite3VdbeAddOp2(v, OP_OpenPseudo, oldIdx, 0);
+ sqlite3VdbeAddOp2(v, OP_SetNumColumns, oldIdx, pTab->nCol);
+ sqlite3VdbeAddOp2(v, OP_OpenPseudo, newIdx, 0);
+ sqlite3VdbeAddOp2(v, OP_SetNumColumns, newIdx, pTab->nCol);
+
+ iGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
+ addr = sqlite3VdbeMakeLabel(v);
+ iBeginBeforeTrigger = sqlite3VdbeCurrentAddr(v);
+ if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab,
+ newIdx, oldIdx, onError, addr, &old_col_mask, &new_col_mask) ){
+ goto update_cleanup;
+ }
+ iEndBeforeTrigger = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
+ iBeginAfterTrigger = sqlite3VdbeCurrentAddr(v);
+ if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab,
+ newIdx, oldIdx, onError, addr, &old_col_mask, &new_col_mask) ){
+ goto update_cleanup;
+ }
+ iEndAfterTrigger = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
+ sqlite3VdbeJumpHere(v, iGoto);
+ }
+
/* 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_EphemTab, iCur, 0, 0, 0, 0);
+ SelectDest dest;
+
+ pView = sqlite3SelectDup(db, pTab->pSelect);
+ sqlite3SelectMask(pParse, pView, old_col_mask|new_col_mask);
+ sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
+ sqlite3Select(pParse, pView, &dest, 0, 0, 0, 0);
sqlite3SelectDelete(pView);
}
/* Begin the database scan
*/
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0);
if( pWInfo==0 ) goto update_cleanup;
/* Remember the rowid of every item to be updated.
*/
- sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0);
- sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
+ sqlite3VdbeAddOp2(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid,iCur,regOldRowid);
+ sqlite3VdbeAddOp2(v, OP_FifoWrite, regOldRowid, 0);
/* End the database scan loop.
*/
@@ -311,201 +362,195 @@ void sqlite3Update(
/* Initialize the count of updated rows
*/
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
- sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
+ regRowCount = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
}
- if( triggers_exist ){
- /* Create pseudo-tables for NEW and OLD
+ 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_OpenPseudo, oldIdx, 0);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
- sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
+ sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
+ if( onError==OE_Replace ){
+ openAll = 1;
+ }else{
+ openAll = 0;
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( pIdx->onError==OE_Replace ){
+ openAll = 1;
+ break;
+ }
+ }
+ }
+ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
+ if( openAll || aRegIdx[i]>0 ){
+ KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
+ sqlite3VdbeAddOp4(v, OP_OpenWrite, iCur+i+1, pIdx->tnum, iDb,
+ (char*)pKey, P4_KEYINFO_HANDOFF);
+ assert( pParse->nTab>iCur+i+1 );
+ }
+ }
+ }
+
+ /* Jump back to this point if a trigger encounters an IGNORE constraint. */
+ if( triggers_exist ){
+ sqlite3VdbeResolveLabel(v, addr);
+ }
- /* The top of the update loop for when there are triggers.
- */
- addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
+ /* Top of the update loop */
+ addr = sqlite3VdbeAddOp2(v, OP_FifoRead, regOldRowid, 0);
- if( !isView ){
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- /* Open a cursor and make it point to the record that is
- ** being updated.
- */
- sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
- }
- sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
+ if( triggers_exist ){
+ int regRowid;
+ int regRow;
+ int regCols;
+
+ /* Make cursor iCur point to the record that is being updated.
+ */
+ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);
/* Generate the OLD table
*/
- sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
- sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
- sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0);
+ regRowid = sqlite3GetTempReg(pParse);
+ regRow = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regRowid);
+ if( !old_col_mask ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regRow);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_RowData, iCur, regRow);
+ }
+ sqlite3VdbeAddOp3(v, OP_Insert, oldIdx, regRow, regRowid);
/* Generate the NEW table
*/
if( chngRowid ){
- sqlite3ExprCodeAndCache(pParse, pRowidExpr);
+ sqlite3ExprCodeAndCache(pParse, pRowidExpr, regRowid);
}else{
- sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regRowid);
}
+ regCols = sqlite3GetTempRange(pParse, pTab->nCol);
for(i=0; i<pTab->nCol; i++){
if( i==pTab->iPKey ){
- sqlite3VdbeAddOp(v, OP_Null, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regCols+i);
continue;
}
j = aXRef[i];
- if( j<0 ){
- sqlite3VdbeAddOp(v, OP_Column, iCur, i);
- sqlite3ColumnDefault(v, pTab, i);
+ if( new_col_mask&((u32)1<<i) || new_col_mask==0xffffffff ){
+ if( j<0 ){
+ sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regCols+i);
+ sqlite3ColumnDefault(v, pTab, i);
+ }else{
+ sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr, regCols+i);
+ }
}else{
- sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regCols+i);
}
}
- sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regCols, pTab->nCol, regRow);
if( !isView ){
sqlite3TableAffinityStr(v, pTab);
}
+ sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol);
if( pParse->nErr ) goto update_cleanup;
- sqlite3VdbeAddOp(v, OP_Insert, newIdx, 0);
- if( !isView ){
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }
+ sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRow, regRowid);
+ sqlite3ReleaseTempReg(pParse, regRowid);
+ sqlite3ReleaseTempReg(pParse, regRow);
- /* Fire the BEFORE and INSTEAD OF triggers
- */
- if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab,
- newIdx, oldIdx, onError, addr) ){
- goto update_cleanup;
- }
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginBeforeTrigger);
+ sqlite3VdbeJumpHere(v, iEndBeforeTrigger);
}
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.
- */
- sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
- if( onError==OE_Replace ){
- openAll = 1;
- }else{
- openAll = 0;
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->onError==OE_Replace ){
- openAll = 1;
- break;
- }
- }
- }
- for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
- if( openAll || aIdxUsed[i] ){
- KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
- sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
- sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum,
- (char*)pKey, P3_KEYINFO_HANDOFF);
- assert( pParse->nTab>iCur+i+1 );
- }
- }
-
/* 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 entries.
** So make the cursor point at the old record.
*/
- if( !triggers_exist ){
- addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- }
- sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
+ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);
/* If the record number will change, push the record number as it
** will be after the update. (The old record number is currently
** on top of the stack.)
*/
if( chngRowid ){
- sqlite3ExprCode(pParse, pRowidExpr);
- sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
+ sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
+ sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid);
}
/* Compute new data for this record.
*/
for(i=0; i<pTab->nCol; i++){
if( i==pTab->iPKey ){
- sqlite3VdbeAddOp(v, OP_Null, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regData+i);
continue;
}
j = aXRef[i];
if( j<0 ){
- sqlite3VdbeAddOp(v, OP_Column, iCur, i);
+ sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regData+i);
sqlite3ColumnDefault(v, pTab, i);
}else{
- sqlite3ExprCode(pParse, pChanges->a[j].pExpr);
+ sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regData+i);
}
}
/* Do constraint checks
*/
- sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRowid, 1,
- onError, addr);
+ sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid,
+ aRegIdx, chngRowid, 1,
+ onError, addr);
/* Delete the old indices for the current record.
*/
- sqlite3GenerateRowIndexDelete(v, pTab, iCur, aIdxUsed);
+ j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid);
+ sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx);
/* If changing the record number, delete the old record.
*/
if( chngRowid ){
- sqlite3VdbeAddOp(v, OP_Delete, iCur, 0);
+ sqlite3VdbeAddOp2(v, OP_Delete, iCur, 0);
}
+ sqlite3VdbeJumpHere(v, j1);
/* Create the new index entries and the new record.
*/
- sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, -1);
+ sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid,
+ aRegIdx, chngRowid, 1, -1, 0);
}
/* Increment the row counter
*/
if( db->flags & SQLITE_CountRows && !pParse->trigStack){
- sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
+ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
}
/* If there are triggers, close all the cursors after each iteration
** through the loop. The fire the after triggers.
*/
if( triggers_exist ){
- if( !isView ){
- for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
- if( openAll || aIdxUsed[i] )
- sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
- }
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }
- if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab,
- newIdx, oldIdx, onError, addr) ){
- goto update_cleanup;
- }
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginAfterTrigger);
+ sqlite3VdbeJumpHere(v, iEndAfterTrigger);
}
/* Repeat the above with the next record to be updated, until
** all record selected by the WHERE clause have been updated.
*/
- sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
sqlite3VdbeJumpHere(v, addr);
- /* Close all tables if there were no FOR EACH ROW triggers */
- if( !triggers_exist ){
- for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
- if( openAll || aIdxUsed[i] ){
- sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
- }
+ /* Close all tables */
+ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
+ if( openAll || aRegIdx[i]>0 ){
+ sqlite3VdbeAddOp2(v, OP_Close, iCur+i+1, 0);
}
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }else{
- sqlite3VdbeAddOp(v, OP_Close, newIdx, 0);
- sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0);
+ }
+ sqlite3VdbeAddOp2(v, OP_Close, iCur, 0);
+ if( triggers_exist ){
+ sqlite3VdbeAddOp2(v, OP_Close, newIdx, 0);
+ sqlite3VdbeAddOp2(v, OP_Close, oldIdx, 0);
}
/*
@@ -514,15 +559,15 @@ void sqlite3Update(
** invoke the callback function.
*/
if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){
- sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P3_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P4_STATIC);
}
update_cleanup:
sqlite3AuthContextPop(&sContext);
- sqliteFree(apIdx);
- sqliteFree(aXRef);
+ sqlite3_free(aRegIdx);
+ sqlite3_free(aXRef);
sqlite3SrcListDelete(pTabList);
sqlite3ExprListDelete(pChanges);
sqlite3ExprDelete(pWhere);
@@ -565,56 +610,58 @@ static void updateVirtualTable(
int ephemTab; /* Table holding the result of the SELECT */
int i; /* Loop counter */
int addr; /* Address of top of loop */
+ int iReg; /* First register in set passed to OP_VUpdate */
+ sqlite3 *db = pParse->db; /* Database connection */
+ const char *pVtab = (const char*)pTab->pVtab;
+ SelectDest dest;
/* Construct the SELECT statement that will find the new values for
** all updated rows.
*/
- pEList = sqlite3ExprListAppend(0, sqlite3CreateIdExpr("_rowid_"), 0);
+ pEList = sqlite3ExprListAppend(pParse, 0,
+ sqlite3CreateIdExpr(pParse, "_rowid_"), 0);
if( pRowid ){
- pEList = sqlite3ExprListAppend(pEList, sqlite3ExprDup(pRowid), 0);
+ pEList = sqlite3ExprListAppend(pParse, pEList,
+ sqlite3ExprDup(db, pRowid), 0);
}
assert( pTab->iPKey<0 );
for(i=0; i<pTab->nCol; i++){
if( aXRef[i]>=0 ){
- pExpr = sqlite3ExprDup(pChanges->a[aXRef[i]].pExpr);
+ pExpr = sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr);
}else{
- pExpr = sqlite3CreateIdExpr(pTab->aCol[i].zName);
+ pExpr = sqlite3CreateIdExpr(pParse, pTab->aCol[i].zName);
}
- pEList = sqlite3ExprListAppend(pEList, pExpr, 0);
+ pEList = sqlite3ExprListAppend(pParse, pEList, pExpr, 0);
}
- pSelect = sqlite3SelectNew(pEList, pSrc, pWhere, 0, 0, 0, 0, 0, 0);
+ pSelect = sqlite3SelectNew(pParse, 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));
+ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0));
/* fill the ephemeral table
*/
- sqlite3Select(pParse, pSelect, SRT_Table, ephemTab, 0, 0, 0, 0);
+ sqlite3SelectDestInit(&dest, SRT_Table, ephemTab);
+ sqlite3Select(pParse, pSelect, &dest, 0, 0, 0, 0);
- /*
- ** Generate code to scan the ephemeral table and call VDelete and
- ** VInsert
- */
- sqlite3VdbeAddOp(v, OP_Rewind, ephemTab, 0);
+ /* Generate code to scan the ephemeral table and call VUpdate. */
+ iReg = ++pParse->nMem;
+ pParse->nMem += pTab->nCol+1;
+ sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0);
addr = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeAddOp(v, OP_Column, ephemTab, 0);
- if( pRowid ){
- sqlite3VdbeAddOp(v, OP_Column, ephemTab, 1);
- }else{
- sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
- }
+ sqlite3VdbeAddOp3(v, OP_Column, ephemTab, 0, iReg);
+ sqlite3VdbeAddOp3(v, OP_Column, ephemTab, (pRowid?1:0), iReg+1);
for(i=0; i<pTab->nCol; i++){
- sqlite3VdbeAddOp(v, OP_Column, ephemTab, i+1+(pRowid!=0));
+ sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i);
}
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);
+ sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVtab, P4_VTAB);
+ sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr);
+ sqlite3VdbeJumpHere(v, addr-1);
+ sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
/* Cleanup */
sqlite3SelectDelete(pSelect);
diff --git a/ext/pdo_sqlite/sqlite/src/utf.c b/ext/pdo_sqlite/sqlite/src/utf.c
index 05d238433a..76c98e7050 100644
--- a/ext/pdo_sqlite/sqlite/src/utf.c
+++ b/ext/pdo_sqlite/sqlite/src/utf.c
@@ -34,101 +34,32 @@
** 0xff 0xfe little-endian utf-16 follows
** 0xfe 0xff big-endian utf-16 follows
**
-**
-** Handling of malformed strings:
-**
-** SQLite accepts and processes malformed strings without an error wherever
-** possible. However this is not possible when converting between UTF-8 and
-** UTF-16.
-**
-** When converting malformed UTF-8 strings to UTF-16, one instance of the
-** replacement character U+FFFD for each byte that cannot be interpeted as
-** part of a valid unicode character.
-**
-** When converting malformed UTF-16 strings to UTF-8, one instance of the
-** replacement character U+FFFD for each pair of bytes that cannot be
-** interpeted as part of a valid unicode character.
-**
-** This file contains the following public routines:
-**
-** sqlite3VdbeMemTranslate() - Translate the encoding used by a Mem* string.
-** sqlite3VdbeMemHandleBom() - Handle byte-order-marks in UTF16 Mem* strings.
-** sqlite3utf16ByteLen() - Calculate byte-length of a void* UTF16 string.
-** sqlite3utf8CharLen() - Calculate char-length of a char* UTF8 string.
-** sqlite3utf8LikeCompare() - Do a LIKE match given two UTF8 char* strings.
-**
*/
#include "sqliteInt.h"
#include <assert.h>
#include "vdbeInt.h"
/*
-** This table maps from the first byte of a UTF-8 character to the number
-** of trailing bytes expected. A value '255' indicates that the table key
-** is not a legal first byte for a UTF-8 character.
+** The following constant value is used by the SQLITE_BIGENDIAN and
+** SQLITE_LITTLEENDIAN macros.
*/
-static const u8 xtra_utf8_bytes[256] = {
-/* 0xxxxxxx */
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
-/* 10wwwwww */
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-
-/* 110yyyyy */
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-
-/* 1110zzzz */
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-
-/* 11110yyy */
-3, 3, 3, 3, 3, 3, 3, 3, 255, 255, 255, 255, 255, 255, 255, 255,
-};
+const int sqlite3one = 1;
/*
-** This table maps from the number of trailing bytes in a UTF-8 character
-** to an integer constant that is effectively calculated for each character
-** read by a naive implementation of a UTF-8 character reader. The code
-** in the READ_UTF8 macro explains things best.
+** This lookup table is used to help decode the first byte of
+** a multi-byte UTF8 character.
*/
-static const int xtra_utf8_bits[4] = {
-0,
-12416, /* (0xC0 << 6) + (0x80) */
-925824, /* (0xE0 << 12) + (0x80 << 6) + (0x80) */
-63447168 /* (0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */
+static const unsigned char sqlite3UtfTrans1[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
};
-#define READ_UTF8(zIn, c) { \
- int xtra; \
- c = *(zIn)++; \
- xtra = xtra_utf8_bytes[c]; \
- switch( xtra ){ \
- case 255: c = (int)0xFFFD; break; \
- case 3: c = (c<<6) + *(zIn)++; \
- case 2: c = (c<<6) + *(zIn)++; \
- case 1: c = (c<<6) + *(zIn)++; \
- c -= xtra_utf8_bits[xtra]; \
- } \
-}
-int sqlite3ReadUtf8(const unsigned char *z){
- int c;
- READ_UTF8(z, c);
- return c;
-}
-
-#define SKIP_UTF8(zIn) { \
- zIn += (xtra_utf8_bytes[*(u8 *)zIn] + 1); \
-}
#define WRITE_UTF8(zOut, c) { \
if( c<0x00080 ){ \
@@ -177,54 +108,72 @@ int sqlite3ReadUtf8(const unsigned char *z){
#define READ_UTF16LE(zIn, c){ \
c = (*zIn++); \
c += ((*zIn++)<<8); \
- if( c>=0xD800 && c<=0xE000 ){ \
+ if( c>=0xD800 && c<0xE000 ){ \
int c2 = (*zIn++); \
c2 += ((*zIn++)<<8); \
c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
+ if( (c & 0xFFFF0000)==0 ) c = 0xFFFD; \
} \
}
#define READ_UTF16BE(zIn, c){ \
c = ((*zIn++)<<8); \
c += (*zIn++); \
- if( c>=0xD800 && c<=0xE000 ){ \
+ if( c>=0xD800 && c<0xE000 ){ \
int c2 = ((*zIn++)<<8); \
c2 += (*zIn++); \
c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
+ if( (c & 0xFFFF0000)==0 ) c = 0xFFFD; \
} \
}
-#define SKIP_UTF16BE(zIn){ \
- if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn+1)==0x00)) ){ \
- zIn += 4; \
- }else{ \
- zIn += 2; \
- } \
-}
-#define SKIP_UTF16LE(zIn){ \
- zIn++; \
- if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn-1)==0x00)) ){ \
- zIn += 3; \
- }else{ \
- zIn += 1; \
- } \
+/*
+** Translate a single UTF-8 character. Return the unicode value.
+**
+** During translation, assume that the byte that zTerm points
+** is a 0x00.
+**
+** Write a pointer to the next unread byte back into *pzNext.
+**
+** Notes On Invalid UTF-8:
+**
+** * This routine never allows a 7-bit character (0x00 through 0x7f) to
+** be encoded as a multi-byte character. Any multi-byte character that
+** attempts to encode a value between 0x00 and 0x7f is rendered as 0xfffd.
+**
+** * This routine never allows a UTF16 surrogate value to be encoded.
+** If a multi-byte character attempts to encode a value between
+** 0xd800 and 0xe000 then it is rendered as 0xfffd.
+**
+** * Bytes in the range of 0x80 through 0xbf which occur as the first
+** byte of a character are interpreted as single-byte characters
+** and rendered as themselves even though they are technically
+** invalid characters.
+**
+** * This routine accepts an infinite number of different UTF8 encodings
+** for unicode values 0x80 and greater. It do not change over-length
+** encodings to 0xfffd as some systems recommend.
+*/
+int sqlite3Utf8Read(
+ const unsigned char *z, /* First byte of UTF-8 character */
+ const unsigned char *zTerm, /* Pretend this byte is 0x00 */
+ const unsigned char **pzNext /* Write first byte past UTF-8 char here */
+){
+ int c = *(z++);
+ if( c>=0xc0 ){
+ c = sqlite3UtfTrans1[c-0xc0];
+ while( z!=zTerm && (*z & 0xc0)==0x80 ){
+ c = (c<<6) + (0x3f & *(z++));
+ }
+ if( c<0x80
+ || (c&0xFFFFF800)==0xD800
+ || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; }
+ }
+ *pzNext = z;
+ return c;
}
-#define RSKIP_UTF16LE(zIn){ \
- if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn-1)==0x00)) ){ \
- zIn -= 4; \
- }else{ \
- zIn -= 2; \
- } \
-}
-#define RSKIP_UTF16BE(zIn){ \
- zIn--; \
- if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn+1)==0x00)) ){ \
- zIn -= 3; \
- }else{ \
- zIn -= 1; \
- } \
-}
+
/*
** If the TRANSLATE_TRACE macro is defined, the value of each Mem is
@@ -245,8 +194,9 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
unsigned char *zIn; /* Input iterator */
unsigned char *zTerm; /* End of input */
unsigned char *z; /* Output iterator */
- int c;
+ unsigned int c;
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( pMem->flags&MEM_Str );
assert( pMem->enc!=desiredEnc );
assert( pMem->enc!=0 );
@@ -305,14 +255,16 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
** byte past the end.
**
** Variable zOut is set to point at the output buffer. This may be space
- ** obtained from malloc(), or Mem.zShort, if it large enough and not in
- ** use, or the zShort array on the stack (see above).
+ ** obtained from sqlite3_malloc(), or Mem.zShort, if it large enough and
+ ** not in use, or the zShort array on the stack (see above).
*/
zIn = (u8*)pMem->z;
zTerm = &zIn[pMem->n];
if( len>NBFS ){
- zOut = sqliteMallocRaw(len);
- if( !zOut ) return SQLITE_NOMEM;
+ zOut = sqlite3DbMallocRaw(pMem->db, len);
+ if( !zOut ){
+ return SQLITE_NOMEM;
+ }
}else{
zOut = zShort;
}
@@ -322,14 +274,14 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
if( desiredEnc==SQLITE_UTF16LE ){
/* UTF-8 -> UTF-16 Little-endian */
while( zIn<zTerm ){
- READ_UTF8(zIn, c);
+ c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn);
WRITE_UTF16LE(z, c);
}
}else{
assert( desiredEnc==SQLITE_UTF16BE );
/* UTF-8 -> UTF-16 Big-endian */
while( zIn<zTerm ){
- READ_UTF8(zIn, c);
+ c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn);
WRITE_UTF16BE(z, c);
}
}
@@ -415,7 +367,8 @@ int sqlite3VdbeMemHandleBom(Mem *pMem){
char *z = pMem->z;
pMem->z = 0;
pMem->xDel = 0;
- rc = sqlite3VdbeMemSetStr(pMem, &z[2], pMem->n-2, bom, SQLITE_TRANSIENT);
+ rc = sqlite3VdbeMemSetStr(pMem, &z[2], pMem->n-2, bom,
+ SQLITE_TRANSIENT);
xDel(z);
}else{
rc = sqlite3VdbeMemSetStr(pMem, &pMem->z[2], pMem->n-2, bom,
@@ -433,38 +386,74 @@ int sqlite3VdbeMemHandleBom(Mem *pMem){
** number of unicode characters in the first nByte of pZ (or up to
** the first 0x00, whichever comes first).
*/
-int sqlite3utf8CharLen(const char *z, int nByte){
+int sqlite3Utf8CharLen(const char *zIn, int nByte){
int r = 0;
- const char *zTerm;
+ const u8 *z = (const u8*)zIn;
+ const u8 *zTerm;
if( nByte>=0 ){
zTerm = &z[nByte];
}else{
- zTerm = (const char *)(-1);
+ zTerm = (const u8*)(-1);
}
assert( z<=zTerm );
while( *z!=0 && z<zTerm ){
- SKIP_UTF8(z);
+ SQLITE_SKIP_UTF8(z);
r++;
}
return r;
}
+/* This test function is not currently used by the automated test-suite.
+** Hence it is only available in debug builds.
+*/
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+/*
+** Translate UTF-8 to UTF-8.
+**
+** This has the effect of making sure that the string is well-formed
+** UTF-8. Miscoded characters are removed.
+**
+** The translation is done in-place (since it is impossible for the
+** correct UTF-8 encoding to be longer than a malformed encoding).
+*/
+int sqlite3Utf8To8(unsigned char *zIn){
+ unsigned char *zOut = zIn;
+ unsigned char *zStart = zIn;
+ unsigned char *zTerm;
+ u32 c;
+
+ while( zIn[0] ){
+ c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn);
+ if( c!=0xfffd ){
+ WRITE_UTF8(zOut, c);
+ }
+ }
+ *zOut = 0;
+ return zOut - zStart;
+}
+#endif
+
#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.
+** Memory to hold the UTF-8 string is obtained from sqlite3_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){
+char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte){
Mem m;
memset(&m, 0, sizeof(m));
+ m.db = db;
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);
+ if( db->mallocFailed ){
+ sqlite3VdbeMemRelease(&m);
+ m.z = 0;
+ }
+ assert( (m.flags & MEM_Term)!=0 || db->mallocFailed );
+ assert( (m.flags & MEM_Str)!=0 || db->mallocFailed );
+ return (m.flags & MEM_Dyn)!=0 ? m.z : sqlite3DbStrDup(db, m.z);
}
/*
@@ -474,8 +463,8 @@ char *sqlite3utf16to8(const void *z, int nByte){
** then return the number of bytes in the first nChar unicode characters
** in pZ (or up until the first pair of 0x00 bytes, whichever comes first).
*/
-int sqlite3utf16ByteLen(const void *zIn, int nChar){
- int c = 1;
+int sqlite3Utf16ByteLen(const void *zIn, int nChar){
+ unsigned int c = 1;
char const *z = zIn;
int n = 0;
if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
@@ -501,91 +490,51 @@ int sqlite3utf16ByteLen(const void *zIn, int nChar){
return (z-(char const *)zIn)-((c==0)?2:0);
}
-/*
-** UTF-16 implementation of the substr()
-*/
-void sqlite3utf16Substr(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- int y, z;
- unsigned char const *zStr;
- unsigned char const *zStrEnd;
- unsigned char const *zStart;
- unsigned char const *zEnd;
- int i;
-
- zStr = (unsigned char const *)sqlite3_value_text16(argv[0]);
- zStrEnd = &zStr[sqlite3_value_bytes16(argv[0])];
- y = sqlite3_value_int(argv[1]);
- z = sqlite3_value_int(argv[2]);
-
- if( y>0 ){
- y = y-1;
- zStart = zStr;
- if( SQLITE_UTF16BE==SQLITE_UTF16NATIVE ){
- for(i=0; i<y && zStart<zStrEnd; i++) SKIP_UTF16BE(zStart);
- }else{
- for(i=0; i<y && zStart<zStrEnd; i++) SKIP_UTF16LE(zStart);
- }
- }else{
- zStart = zStrEnd;
- if( SQLITE_UTF16BE==SQLITE_UTF16NATIVE ){
- for(i=y; i<0 && zStart>zStr; i++) RSKIP_UTF16BE(zStart);
- }else{
- for(i=y; i<0 && zStart>zStr; i++) RSKIP_UTF16LE(zStart);
- }
- for(; i<0; i++) z -= 1;
- }
-
- zEnd = zStart;
- if( SQLITE_UTF16BE==SQLITE_UTF16NATIVE ){
- for(i=0; i<z && zEnd<zStrEnd; i++) SKIP_UTF16BE(zEnd);
- }else{
- for(i=0; i<z && zEnd<zStrEnd; i++) SKIP_UTF16LE(zEnd);
- }
-
- sqlite3_result_text16(context, zStart, zEnd-zStart, SQLITE_TRANSIENT);
-}
-
#if defined(SQLITE_TEST)
/*
** This routine is called from the TCL test function "translate_selftest".
** It checks that the primitives for serializing and deserializing
** characters in each encoding are inverses of each other.
*/
-void sqlite3utfSelfTest(){
- int i;
+void sqlite3UtfSelfTest(){
+ unsigned int i, t;
unsigned char zBuf[20];
unsigned char *z;
+ unsigned char *zTerm;
int n;
- int c;
+ unsigned int c;
for(i=0; i<0x00110000; i++){
z = zBuf;
WRITE_UTF8(z, i);
n = z-zBuf;
+ z[0] = 0;
+ zTerm = z;
z = zBuf;
- READ_UTF8(z, c);
- assert( c==i );
+ c = sqlite3Utf8Read(z, zTerm, (const u8**)&z);
+ t = i;
+ if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD;
+ if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD;
+ assert( c==t );
assert( (z-zBuf)==n );
}
for(i=0; i<0x00110000; i++){
- if( i>=0xD800 && i<=0xE000 ) continue;
+ if( i>=0xD800 && i<0xE000 ) continue;
z = zBuf;
WRITE_UTF16LE(z, i);
n = z-zBuf;
+ z[0] = 0;
z = zBuf;
READ_UTF16LE(z, c);
assert( c==i );
assert( (z-zBuf)==n );
}
for(i=0; i<0x00110000; i++){
- if( i>=0xD800 && i<=0xE000 ) continue;
+ if( i>=0xD800 && i<0xE000 ) continue;
z = zBuf;
WRITE_UTF16BE(z, i);
n = z-zBuf;
+ z[0] = 0;
z = zBuf;
READ_UTF16BE(z, c);
assert( c==i );
diff --git a/ext/pdo_sqlite/sqlite/src/util.c b/ext/pdo_sqlite/sqlite/src/util.c
index 5ca9ec4086..d12e0fbb8d 100644
--- a/ext/pdo_sqlite/sqlite/src/util.c
+++ b/ext/pdo_sqlite/sqlite/src/util.c
@@ -17,759 +17,9 @@
** $Id$
*/
#include "sqliteInt.h"
-#include "os.h"
#include <stdarg.h>
#include <ctype.h>
-/*
-** 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))
-
-#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;
- }
- sqlite3ReleaseThreadData();
-}
-
-/*
-** Release memory held by SQLite instances created by the current thread.
-*/
-int sqlite3_release_memory(int n){
- return sqlite3pager_release_memory(n);
-}
-#else
-/* 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
-
-/*
-** 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.
-*/
-#ifndef TESTALLOC_NGUARD
-# define TESTALLOC_NGUARD 2
-#endif
-
-/*
-** Size reserved for storing file-name along with each malloc()ed blob.
-*/
-#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
-** is used to check for memory leaks. The iMallocFail and iMallocReset
-** values are used to simulate malloc() failures during testing in
-** order to verify that the library correctly handles an out-of-memory
-** condition.
-*/
-int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */
-int sqlite3_nFree; /* Number of sqliteFree() calls */
-int sqlite3_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 */
-
-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.
-*/
-int sqlite3TestMallocFail(){
- if( sqlite3_isFail ){
- return 1;
- }
- if( sqlite3_iMallocFail>=0 ){
- sqlite3_iMallocFail--;
- if( sqlite3_iMallocFail==0 ){
- sqlite3_iMallocFail = sqlite3_iMallocReset;
- sqlite3_isFail = 1;
- return 1;
- }
- }
- return 0;
-}
-
-/*
-** 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.
-*/
-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);
- }
-
- /* 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);
- }
-}
-
-/*
-** 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;
- }
-
- /* 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);
-}
-
-/*
-** The argument is a malloc()ed pointer as returned by the test-wrapper.
-** Return a pointer to the Os level allocation.
-*/
-static void *getOsPointer(void *p)
-{
- char *z = (char *)p;
- return (void *)(&z[-1 * TESTALLOC_OFFSET_DATA(p)]);
-}
-
-
-#if SQLITE_MEMDEBUG>1
-/*
-** The argument points to an Os level allocation. Link it into the threads list
-** of allocations.
-*/
-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;
-}
-
-/*
-** The argument points to an Os level allocation. Unlinke it from the threads
-** list of allocations.
-*/
-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;
- }
- }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;
- }
- }
-}
-
-/*
-** 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.
-*/
-static void relinkAlloc(void *p)
-{
- void **pp = (void **)p;
- if( pp[0] ){
- ((void **)(pp[0]))[1] = p;
- }else{
- sqlite3_pFirst = p;
- }
- if( pp[1] ){
- ((void **)(pp[1]))[0] = p;
- }
-}
-#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);
- }
-
- Tcl_ResetResult(interp);
- Tcl_SetObjResult(interp, pRes);
- Tcl_DecrRefCount(pRes);
- return TCL_OK;
-}
-#endif
-
-/*
-** This is the test layer's wrapper around sqlite3OsMalloc().
-*/
-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;
-}
-
-static int OSSIZEOF(void *p){
- if( p ){
- u32 *pOs = (u32 *)getOsPointer(p);
- return sqlite3OsAllocationSize(pOs) - TESTALLOC_OVERHEAD;
- }
- return 0;
-}
-
-/*
-** This is the test layer's wrapper around sqlite3OsFree(). The argument is a
-** pointer to the space allocated for the application to use.
-*/
-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();
-}
-
-/*
-** This is the test layer's wrapper around sqlite3OsRealloc().
-*/
-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 */
-/*
-** 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
-*/
-#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();
- }
- }
-}
-#else
-#define updateMemoryUsedCount(x) /* no-op */
-#endif
-
-/*
-** 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, 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;
-}
-
-/*
-** 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 ){
- updateMemoryUsedCount(0 - OSSIZEOF(p));
- OSFREE(p);
- }
-}
-
-/*
-** 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 *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);
- }
- return p;
-}
-void sqlite3ReallocOrFree(void **pp, int n){
- void *p = sqlite3Realloc(*pp, n);
- if( !p ){
- sqlite3FreeX(*pp);
- }
- *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);
- }
-}
-#endif
-
-
-/*
-** 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 = 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 = sqlite3MallocRaw(n+1, 1);
- if( zNew ){
- memcpy(zNew, z, n);
- zNew[n] = 0;
- }
- return zNew;
-}
-
-/*
-** Create a string from the 2nd and subsequent arguments (up to the
-** first NULL argument), store the string in memory obtained from
-** sqliteMalloc() and make the pointer indicated by the 1st argument
-** point to that string. The 1st argument must either be NULL or
-** point to memory obtained from sqliteMalloc().
-*/
-void sqlite3SetString(char **pz, ...){
- va_list ap;
- int nByte;
- const char *z;
- char *zResult;
-
- if( pz==0 ) return;
- nByte = 1;
- va_start(ap, pz);
- while( (z = va_arg(ap, const char*))!=0 ){
- nByte += strlen(z);
- }
- va_end(ap);
- sqliteFree(*pz);
- *pz = zResult = sqliteMallocRaw( nByte );
- if( zResult==0 ){
- return;
- }
- *zResult = 0;
- va_start(ap, pz);
- while( (z = va_arg(ap, const char*))!=0 ){
- strcpy(zResult, z);
- zResult += strlen(zResult);
- }
- va_end(ap);
-}
/*
** Set the most recent error code and error string for the sqlite
@@ -793,15 +43,15 @@ void sqlite3SetString(char **pz, ...){
** to NULL.
*/
void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
- if( db && (db->pErr || (db->pErr = sqlite3ValueNew())!=0) ){
+ if( db && (db->pErr || (db->pErr = sqlite3ValueNew(db))!=0) ){
db->errCode = err_code;
if( zFormat ){
char *z;
va_list ap;
va_start(ap, zFormat);
- z = sqlite3VMPrintf(zFormat, ap);
+ z = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap);
- sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, sqlite3FreeX);
+ sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, sqlite3_free);
}else{
sqlite3ValueSetStr(db->pErr, 0, 0, SQLITE_UTF8, SQLITE_STATIC);
}
@@ -828,17 +78,20 @@ void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
va_list ap;
pParse->nErr++;
- sqliteFree(pParse->zErrMsg);
+ sqlite3_free(pParse->zErrMsg);
va_start(ap, zFormat);
- pParse->zErrMsg = sqlite3VMPrintf(zFormat, ap);
+ pParse->zErrMsg = sqlite3VMPrintf(pParse->db, zFormat, ap);
va_end(ap);
+ if( pParse->rc==SQLITE_OK ){
+ pParse->rc = SQLITE_ERROR;
+ }
}
/*
** Clear the error message in pParse, if any
*/
void sqlite3ErrorClear(Parse *pParse){
- sqliteFree(pParse->zErrMsg);
+ sqlite3_free(pParse->zErrMsg);
pParse->zErrMsg = 0;
pParse->nErr = 0;
}
@@ -992,7 +245,7 @@ int sqlite3AtoF(const char *z, double *pResult){
int sign = 1;
const char *zBegin = z;
LONGDOUBLE_TYPE v1 = 0.0;
- while( isspace(*z) ) z++;
+ while( isspace(*(u8*)z) ) z++;
if( *z=='-' ){
sign = -1;
z++;
@@ -1041,26 +294,48 @@ int sqlite3AtoF(const char *z, double *pResult){
*pResult = sign<0 ? -v1 : v1;
return z - zBegin;
#else
- return sqlite3atoi64(z, pResult);
+ return sqlite3Atoi64(z, pResult);
#endif /* SQLITE_OMIT_FLOATING_POINT */
}
/*
+** Compare the 19-character string zNum against the text representation
+** value 2^63: 9223372036854775808. Return negative, zero, or positive
+** if zNum is less than, equal to, or greater than the string.
+**
+** Unlike memcmp() this routine is guaranteed to return the difference
+** in the values of the last digit if the only difference is in the
+** last digit. So, for example,
+**
+** compare2pow63("9223372036854775800")
+**
+** will return -8.
+*/
+static int compare2pow63(const char *zNum){
+ int c;
+ c = memcmp(zNum,"922337203685477580",18);
+ if( c==0 ){
+ c = zNum[18] - '8';
+ }
+ return c;
+}
+
+
+/*
** Return TRUE if zNum is a 64-bit signed integer and write
** the value of the integer into *pNum. If zNum is not an integer
** or is an integer that is too large to be expressed with 64 bits,
-** then return false. If n>0 and the integer is string is not
-** exactly n bytes long, return false.
+** then return false.
**
** When this routine was originally written it dealt with only
** 32-bit numbers. At that time, it was much faster than the
** atoi() library routine in RedHat 7.2.
*/
-int sqlite3atoi64(const char *zNum, i64 *pNum){
+int sqlite3Atoi64(const char *zNum, i64 *pNum){
i64 v = 0;
int neg;
int i, c;
- while( isspace(*zNum) ) zNum++;
+ while( isspace(*(u8*)zNum) ) zNum++;
if( *zNum=='-' ){
neg = 1;
zNum++;
@@ -1070,42 +345,24 @@ int sqlite3atoi64(const char *zNum, i64 *pNum){
}else{
neg = 0;
}
+ while( zNum[0]=='0' ){ zNum++; } /* Skip over leading zeros. Ticket #2454 */
for(i=0; (c=zNum[i])>='0' && c<='9'; i++){
v = v*10 + c - '0';
}
*pNum = neg ? -v : v;
- return c==0 && i>0 &&
- (i<19 || (i==19 && memcmp(zNum,"9223372036854775807",19)<=0));
-}
-
-/*
-** The string zNum represents an integer. There might be some other
-** information following the integer too, but that part is ignored.
-** If the integer that the prefix of zNum represents will fit in a
-** 32-bit signed integer, return TRUE. Otherwise return FALSE.
-**
-** This routine returns FALSE for the string -2147483648 even that
-** that number will in fact fit in a 32-bit integer. But positive
-** 2147483648 will not fit in 32 bits. So it seems safer to return
-** false.
-*/
-static int sqlite3FitsIn32Bits(const char *zNum){
- int i, c;
- if( *zNum=='-' || *zNum=='+' ) zNum++;
- for(i=0; (c=zNum[i])>='0' && c<='9'; i++){}
- return i<10 || (i==10 && memcmp(zNum,"2147483647",10)<=0);
-}
-
-/*
-** If zNum represents an integer that will fit in 32-bits, then set
-** *pValue to that integer and return true. Otherwise return false.
-*/
-int sqlite3GetInt32(const char *zNum, int *pValue){
- if( sqlite3FitsIn32Bits(zNum) ){
- *pValue = atoi(zNum);
+ if( c!=0 || i==0 || i>19 ){
+ /* zNum is empty or contains non-numeric text or is longer
+ ** than 19 digits (thus guaranting that it is too large) */
+ return 0;
+ }else if( i<19 ){
+ /* Less than 19 digits, so we know that it fits in 64 bits */
return 1;
+ }else{
+ /* 19-digit numbers must be no larger than 9223372036854775807 if positive
+ ** or 9223372036854775808 if negative. Note that 9223372036854665808
+ ** is 2^63. */
+ return compare2pow63(zNum)<neg;
}
- return 0;
}
/*
@@ -1119,79 +376,74 @@ int sqlite3GetInt32(const char *zNum, int *pValue){
** 9223373036854775808 will not fit in 64 bits. So it seems safer to return
** false.
*/
-int sqlite3FitsIn64Bits(const char *zNum){
+int sqlite3FitsIn64Bits(const char *zNum, int negFlag){
int i, c;
- if( *zNum=='-' || *zNum=='+' ) zNum++;
+ int neg = 0;
+ if( *zNum=='-' ){
+ neg = 1;
+ zNum++;
+ }else if( *zNum=='+' ){
+ zNum++;
+ }
+ if( negFlag ) neg = 1-neg;
+ while( *zNum=='0' ){
+ zNum++; /* Skip leading zeros. Ticket #2454 */
+ }
for(i=0; (c=zNum[i])>='0' && c<='9'; i++){}
- return i<19 || (i==19 && memcmp(zNum,"9223372036854775807",19)<=0);
+ if( i<19 ){
+ /* Guaranteed to fit if less than 19 digits */
+ return 1;
+ }else if( i>19 ){
+ /* Guaranteed to be too big if greater than 19 digits */
+ return 0;
+ }else{
+ /* Compare against 2^63. */
+ return compare2pow63(zNum)<neg;
+ }
}
-
/*
-** Change the sqlite.magic from SQLITE_MAGIC_OPEN to SQLITE_MAGIC_BUSY.
-** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN
-** when this routine is called.
-**
-** This routine is a attempt to detect if two threads use the
-** same sqlite* pointer at the same time. There is a race
-** condition so it is possible that the error is not detected.
-** But usually the problem will be seen. The result will be an
-** error which can be used to debug the application that is
-** using SQLite incorrectly.
+** If zNum represents an integer that will fit in 32-bits, then set
+** *pValue to that integer and return true. Otherwise return false.
**
-** Ticket #202: If db->magic is not a valid open value, take care not
-** to modify the db structure at all. It could be that db is a stale
-** pointer. In other words, it could be that there has been a prior
-** call to sqlite3_close(db) and db has been deallocated. And we do
-** not want to write into deallocated memory.
+** Any non-numeric characters that following zNum are ignored.
+** This is different from sqlite3Atoi64() which requires the
+** input number to be zero-terminated.
*/
-int sqlite3SafetyOn(sqlite3 *db){
- if( db->magic==SQLITE_MAGIC_OPEN ){
- db->magic = SQLITE_MAGIC_BUSY;
- return 0;
- }else if( db->magic==SQLITE_MAGIC_BUSY ){
- db->magic = SQLITE_MAGIC_ERROR;
- db->u1.isInterrupted = 1;
+int sqlite3GetInt32(const char *zNum, int *pValue){
+ sqlite_int64 v = 0;
+ int i, c;
+ int neg = 0;
+ if( zNum[0]=='-' ){
+ neg = 1;
+ zNum++;
+ }else if( zNum[0]=='+' ){
+ zNum++;
+ }
+ while( zNum[0]=='0' ) zNum++;
+ for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){
+ v = v*10 + c;
}
- return 1;
-}
-/*
-** Change the magic from SQLITE_MAGIC_BUSY to SQLITE_MAGIC_OPEN.
-** Return an error (non-zero) if the magic was not SQLITE_MAGIC_BUSY
-** when this routine is called.
-*/
-int sqlite3SafetyOff(sqlite3 *db){
- if( db->magic==SQLITE_MAGIC_BUSY ){
- db->magic = SQLITE_MAGIC_OPEN;
+ /* The longest decimal representation of a 32 bit integer is 10 digits:
+ **
+ ** 1234567890
+ ** 2^31 -> 2147483648
+ */
+ if( i>10 ){
return 0;
- }else if( db->magic==SQLITE_MAGIC_OPEN ){
- db->magic = SQLITE_MAGIC_ERROR;
- db->u1.isInterrupted = 1;
}
+ if( v-neg>2147483647 ){
+ return 0;
+ }
+ if( neg ){
+ v = -v;
+ }
+ *pValue = (int)v;
return 1;
}
/*
-** Check to make sure we have a valid db pointer. This test is not
-** foolproof but it does provide some measure of protection against
-** misuse of the interface such as passing in db pointers that are
-** NULL or which have been previously closed. If this routine returns
-** TRUE it means that the db pointer is invalid and should not be
-** dereferenced for any reason. The calling function should invoke
-** SQLITE_MISUSE immediately.
-*/
-int sqlite3SafetyCheck(sqlite3 *db){
- int magic;
- if( db==0 ) return 1;
- magic = db->magic;
- if( magic!=SQLITE_MAGIC_CLOSED &&
- magic!=SQLITE_MAGIC_OPEN &&
- magic!=SQLITE_MAGIC_BUSY ) return 1;
- return 0;
-}
-
-/*
** The variable-length integer encoding is as follows:
**
** KEY:
@@ -1326,6 +578,22 @@ int sqlite3VarintLen(u64 v){
return i;
}
+
+/*
+** Read or write a four-byte big-endian integer value.
+*/
+u32 sqlite3Get4byte(const u8 *p){
+ return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
+}
+void sqlite3Put4byte(unsigned char *p, u32 v){
+ p[0] = v>>24;
+ p[1] = v>>16;
+ p[2] = v>>8;
+ p[3] = v;
+}
+
+
+
#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) \
|| defined(SQLITE_TEST)
/*
@@ -1350,138 +618,107 @@ static int hexToInt(int h){
** binary value has been obtained from malloc and must be freed by
** the calling routine.
*/
-void *sqlite3HexToBlob(const char *z){
+void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
char *zBlob;
int i;
- int n = strlen(z);
- if( n%2 ) return 0;
- zBlob = (char *)sqliteMalloc(n/2);
+ zBlob = (char *)sqlite3DbMallocRaw(db, n/2 + 1);
+ n--;
if( zBlob ){
for(i=0; i<n; i+=2){
zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]);
}
+ zBlob[i/2] = 0;
}
return zBlob;
}
#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
-#if defined(SQLITE_TEST)
+
/*
-** Convert text generated by the "%p" conversion format back into
-** a pointer.
+** Change the sqlite.magic from SQLITE_MAGIC_OPEN to SQLITE_MAGIC_BUSY.
+** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN
+** when this routine is called.
+**
+** This routine is called when entering an SQLite API. The SQLITE_MAGIC_OPEN
+** value indicates that the database connection passed into the API is
+** open and is not being used by another thread. By changing the value
+** to SQLITE_MAGIC_BUSY we indicate that the connection is in use.
+** sqlite3SafetyOff() below will change the value back to SQLITE_MAGIC_OPEN
+** when the API exits.
+**
+** This routine is a attempt to detect if two threads use the
+** same sqlite* pointer at the same time. There is a race
+** condition so it is possible that the error is not detected.
+** But usually the problem will be seen. The result will be an
+** error which can be used to debug the application that is
+** using SQLite incorrectly.
+**
+** Ticket #202: If db->magic is not a valid open value, take care not
+** to modify the db structure at all. It could be that db is a stale
+** pointer. In other words, it could be that there has been a prior
+** call to sqlite3_close(db) and db has been deallocated. And we do
+** not want to write into deallocated memory.
*/
-void *sqlite3TextToPtr(const char *z){
- void *p;
- u64 v;
- u32 v2;
- if( z[0]=='0' && z[1]=='x' ){
- z += 2;
- }
- v = 0;
- while( *z ){
- v = (v<<4) + hexToInt(*z);
- z++;
- }
- if( sizeof(p)==sizeof(v) ){
- p = *(void**)&v;
- }else{
- assert( sizeof(p)==sizeof(v2) );
- v2 = (u32)v;
- p = *(void**)&v2;
+#ifdef SQLITE_DEBUG
+int sqlite3SafetyOn(sqlite3 *db){
+ if( db->magic==SQLITE_MAGIC_OPEN ){
+ db->magic = SQLITE_MAGIC_BUSY;
+ return 0;
+ }else if( db->magic==SQLITE_MAGIC_BUSY ){
+ db->magic = SQLITE_MAGIC_ERROR;
+ db->u1.isInterrupted = 1;
}
- return p;
+ return 1;
}
#endif
/*
-** Return a pointer to the ThreadData associated with the calling thread.
+** Change the magic from SQLITE_MAGIC_BUSY to SQLITE_MAGIC_OPEN.
+** Return an error (non-zero) if the magic was not SQLITE_MAGIC_BUSY
+** when this routine is called.
*/
-ThreadData *sqlite3ThreadData(){
- ThreadData *p = (ThreadData*)sqlite3OsThreadSpecificData(1);
- if( !p ){
- sqlite3FailedMalloc();
+#ifdef SQLITE_DEBUG
+int sqlite3SafetyOff(sqlite3 *db){
+ if( db->magic==SQLITE_MAGIC_BUSY ){
+ db->magic = SQLITE_MAGIC_OPEN;
+ return 0;
+ }else{
+ db->magic = SQLITE_MAGIC_ERROR;
+ db->u1.isInterrupted = 1;
+ return 1;
}
- 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);
}
+#endif
/*
-** 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.
+** Check to make sure we have a valid db pointer. This test is not
+** foolproof but it does provide some measure of protection against
+** misuse of the interface such as passing in db pointers that are
+** NULL or which have been previously closed. If this routine returns
+** 1 it means that the db pointer is valid and 0 if it should not be
+** dereferenced for any reason. The calling function should invoke
+** SQLITE_MISUSE immediately.
**
-** 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.
+** sqlite3SafetyCheckOk() requires that the db pointer be valid for
+** use. sqlite3SafetyCheckSickOrOk() allows a db pointer that failed to
+** open properly and is not fit for general use but which can be
+** used as an argument to sqlite3_errmsg() or sqlite3_close().
*/
-void sqlite3MallocDisallow(){
- assert( sqlite3_mallocDisallowed>=0 );
- sqlite3_mallocDisallowed++;
+int sqlite3SafetyCheckOk(sqlite3 *db){
+ int magic;
+ if( db==0 ) return 0;
+ magic = db->magic;
+ if( magic!=SQLITE_MAGIC_OPEN &&
+ magic!=SQLITE_MAGIC_BUSY ) return 0;
+ return 1;
}
-
-/*
-** This function clears the flag set in the thread-specific-data structure set
-** by sqlite3MallocDisallow().
-*/
-void sqlite3MallocAllow(){
- assert( sqlite3_mallocDisallowed>0 );
- sqlite3_mallocDisallowed--;
+int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
+ int magic;
+ if( db==0 ) return 0;
+ magic = db->magic;
+ if( magic!=SQLITE_MAGIC_SICK &&
+ magic!=SQLITE_MAGIC_OPEN &&
+ magic!=SQLITE_MAGIC_BUSY ) return 0;
+ return 1;
}
-#endif
diff --git a/ext/pdo_sqlite/sqlite/src/vacuum.c b/ext/pdo_sqlite/sqlite/src/vacuum.c
index 336df67ccb..224c26d9a1 100644
--- a/ext/pdo_sqlite/sqlite/src/vacuum.c
+++ b/ext/pdo_sqlite/sqlite/src/vacuum.c
@@ -18,28 +18,16 @@
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
-#include "os.h"
-
-#ifndef SQLITE_OMIT_VACUUM
-/*
-** Generate a random name of 20 character in length.
-*/
-static void randomName(unsigned char *zBuf){
- static const unsigned char zChars[] =
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789";
- int i;
- sqlite3Randomness(20, zBuf);
- for(i=0; i<20; i++){
- zBuf[i] = zChars[ zBuf[i]%(sizeof(zChars)-1) ];
- }
-}
+#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
/*
** Execute zSql on database db. Return an error code.
*/
static int execSql(sqlite3 *db, const char *zSql){
sqlite3_stmt *pStmt;
+ if( !zSql ){
+ return SQLITE_NOMEM;
+ }
if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
return sqlite3_errcode(db);
}
@@ -69,8 +57,6 @@ static int execExecSql(sqlite3 *db, const char *zSql){
return sqlite3_finalize(pStmt);
}
-#endif
-
/*
** The non-standard VACUUM command is used to clean up the database,
** collapse free space, etc. It is modelled after the VACUUM command
@@ -84,7 +70,7 @@ static int execExecSql(sqlite3 *db, const char *zSql){
void sqlite3Vacuum(Parse *pParse){
Vdbe *v = sqlite3GetVdbe(pParse);
if( v ){
- sqlite3VdbeAddOp(v, OP_Vacuum, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0);
}
return;
}
@@ -94,15 +80,11 @@ void sqlite3Vacuum(Parse *pParse){
*/
int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
int rc = SQLITE_OK; /* Return code from service routines */
-#ifndef SQLITE_OMIT_VACUUM
- const char *zFilename; /* full pathname of the database file */
- int nFilename; /* number of characters in zFilename[] */
- char *zTemp = 0; /* a temporary file in same directory as zFilename */
Btree *pMain; /* The database being vacuumed */
- Btree *pTemp;
- char *zSql = 0;
- int saved_flags; /* Saved value of the db->flags */
- Db *pDb = 0; /* Database to detach at end of vacuum */
+ Btree *pTemp; /* The temporary database we vacuum into */
+ char *zSql = 0; /* SQL statements */
+ 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. */
saved_flags = db->flags;
@@ -114,40 +96,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
rc = SQLITE_ERROR;
goto end_of_vacuum;
}
-
- /* Get the full pathname of the database file and create a
- ** temporary filename in the same directory as the original file.
- */
pMain = db->aDb[0].pBt;
- zFilename = sqlite3BtreeGetFilename(pMain);
- assert( zFilename );
- if( zFilename[0]=='\0' ){
- /* The in-memory database. Do nothing. Return directly to avoid causing
- ** an error trying to DETACH the vacuum_db (which never got attached)
- ** in the exit-handler.
- */
- return SQLITE_OK;
- }
- nFilename = strlen(zFilename);
- zTemp = sqliteMalloc( nFilename+100 );
- if( zTemp==0 ){
- rc = SQLITE_NOMEM;
- goto end_of_vacuum;
- }
- strcpy(zTemp, zFilename);
-
- /* The randomName() procedure in the following loop uses an excellent
- ** source of randomness to generate a name from a space of 1.3e+31
- ** possibilities. So unless the directory already contains on the order
- ** of 1.3e+31 files, the probability that the following loop will
- ** run more than once or twice is vanishingly small. We are certain
- ** enough that this loop will always terminate (and terminate quickly)
- ** that we don't even bother to set a maximum loop count.
- */
- do {
- zTemp[nFilename] = '-';
- randomName((unsigned char*)&zTemp[nFilename+1]);
- } while( sqlite3OsFileExists(zTemp) );
/* Attach the temporary database as 'vacuum_db'. The synchronous pragma
** can be set to 'off' for this file, as it is not recovered if a crash
@@ -157,20 +106,18 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
**
** An optimisation would be to use a non-journaled pager.
*/
- zSql = sqlite3MPrintf("ATTACH '%q' AS vacuum_db;", zTemp);
- if( !zSql ){
- rc = SQLITE_NOMEM;
- goto end_of_vacuum;
- }
+ zSql = "ATTACH '' AS vacuum_db;";
rc = execSql(db, zSql);
- 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));
+ if( db->mallocFailed ){
+ rc = SQLITE_NOMEM;
+ goto end_of_vacuum;
+ }
assert( sqlite3BtreeGetPageSize(pTemp)==sqlite3BtreeGetPageSize(pMain) );
rc = execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
if( rc!=SQLITE_OK ){
@@ -178,7 +125,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
}
#ifndef SQLITE_OMIT_AUTOVACUUM
- sqlite3BtreeSetAutoVacuum(pTemp, sqlite3BtreeGetAutoVacuum(pMain));
+ sqlite3BtreeSetAutoVacuum(pTemp, db->nextAutovac>=0 ? db->nextAutovac :
+ sqlite3BtreeGetAutoVacuum(pMain));
#endif
/* Begin a transaction */
@@ -189,22 +137,19 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
** in the temporary database.
*/
rc = execExecSql(db,
- "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14,100000000) "
- " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'");
+ "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) "
+ " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
+ " AND rootpage>0"
+ );
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execExecSql(db,
- "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14,100000000)"
+ "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)"
" FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' ");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execExecSql(db,
- "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21,100000000) "
+ "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) "
" FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
- rc = execExecSql(db,
- "SELECT 'CREATE VIEW vacuum_db.' || substr(sql,13,100000000) "
- " FROM sqlite_master WHERE type='view'"
- );
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Loop through the tables in the main database. For each, do
** an "INSERT INTO vacuum_db.xxx SELECT * FROM xxx;" to copy
@@ -214,7 +159,9 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
"|| ' SELECT * FROM ' || quote(name) || ';'"
"FROM sqlite_master "
- "WHERE type = 'table' AND name!='sqlite_sequence';"
+ "WHERE type = 'table' AND name!='sqlite_sequence' "
+ " AND rootpage>0"
+
);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
@@ -233,17 +180,19 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
if( rc!=SQLITE_OK ) goto end_of_vacuum;
- /* Copy the triggers from the main database to the temporary database.
- ** This was deferred before in case the triggers interfered with copying
- ** the data. It's possible the indices should be deferred until this
- ** point also.
+ /* Copy the triggers, views, and virtual tables from the main database
+ ** over to the temporary database. None of these objects has any
+ ** associated storage, so all we have to do is copy their entries
+ ** from the SQLITE_MASTER table.
*/
- rc = execExecSql(db,
- "SELECT 'CREATE TRIGGER vacuum_db.' || substr(sql, 16, 1000000) "
- "FROM sqlite_master WHERE type='trigger'"
+ rc = execSql(db,
+ "INSERT INTO vacuum_db.sqlite_master "
+ " SELECT type, name, tbl_name, rootpage, sql"
+ " FROM sqlite_master"
+ " WHERE type='view' OR type='trigger'"
+ " OR (type='table' AND rootpage=0)"
);
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
-
+ if( rc ) goto end_of_vacuum;
/* At this point, unless the main db was completely empty, there is now a
** transaction open on the vacuum database, but not on the main database.
@@ -302,28 +251,13 @@ end_of_vacuum:
db->autoCommit = 1;
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);
- }
- sqliteFree( zSql );
sqlite3ResetInternalSchema(db, 0);
-#endif
return rc;
}
+#endif /* SQLITE_OMIT_VACUUM && SQLITE_OMIT_ATTACH */
diff --git a/ext/pdo_sqlite/sqlite/src/vdbe.c b/ext/pdo_sqlite/sqlite/src/vdbe.c
index 98b9916abe..ea163b8fe2 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbe.c
+++ b/ext/pdo_sqlite/sqlite/src/vdbe.c
@@ -22,13 +22,13 @@
** the VDBE to do the work of the SQL statement. VDBE programs are
** similar in form to assembly language. The program consists of
** a linear sequence of operations. Each operation has an opcode
-** and 3 operands. Operands P1 and P2 are integers. Operand P3
-** is a null-terminated string. The P2 operand must be non-negative.
-** Opcodes will typically ignore one or more operands. Many opcodes
-** ignore all three operands.
+** and 5 operands. Operands P1, P2, and P3 are integers. Operand P4
+** is a null-terminated string. Operand P5 is an unsigned character.
+** Few opcodes use all 5 operands.
**
-** Computation results are stored on a stack. Each entry on the
-** stack is either an integer, a null-terminated string, a floating point
+** Computation results are stored on a set of registers numbered beginning
+** with 1 and going up to Vdbe.nMem. Each register can store
+** either an integer, a null-terminated string, a floating point
** number, or the SQL "NULL" value. An inplicit conversion from one
** type to the other occurs as necessary.
**
@@ -46,7 +46,6 @@
** $Id$
*/
#include "sqliteInt.h"
-#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"
@@ -85,13 +84,39 @@ int sqlite3_sort_count = 0;
#endif
/*
-** Release the memory associated with the given stack level. This
+** The next global variable records the size of the largest MEM_Blob
+** or MEM_Str that has been used by a VDBE opcode. The test procedures
+** use this information to make sure that the zero-blob functionality
+** is working correctly. This variable has no function other than to
+** help verify the correct operation of the library.
+*/
+#ifdef SQLITE_TEST
+int sqlite3_max_blobsize = 0;
+static void updateMaxBlobsize(Mem *p){
+ if( (p->flags & (MEM_Str|MEM_Blob))!=0 && p->n>sqlite3_max_blobsize ){
+ sqlite3_max_blobsize = p->n;
+ }
+}
+#endif
+
+/*
+** Test a register to see if it exceeds the current maximum blob size.
+** If it does, record the new maximum blob size.
+*/
+#ifdef SQLITE_TEST
+# define UPDATE_MAX_BLOBSIZE(P) updateMaxBlobsize(P)
+#else
+# define UPDATE_MAX_BLOBSIZE(P)
+#endif
+
+/*
+** Release the memory associated with a register. This
** leaves the Mem.flags field in an inconsistent state.
*/
#define Release(P) if((P)->flags&MEM_Dyn){ sqlite3VdbeMemRelease(P); }
/*
-** Convert the given stack entity into a string if it isn't one
+** Convert the given register into a string if it isn't one
** already. Return non-zero if a malloc() fails.
*/
#define Stringify(P, enc) \
@@ -99,15 +124,6 @@ int sqlite3_sort_count = 0;
{ goto no_mem; }
/*
-** Convert the given stack entity into a string that has been obtained
-** from sqliteMalloc(). This is different from Stringify() above in that
-** Stringify() will use the NBFS bytes of static string space if the string
-** will fit but this routine always mallocs for space.
-** Return non-zero if we run out of memory.
-*/
-#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
@@ -127,12 +143,12 @@ int sqlite3_sort_count = 0;
/*
** An ephemeral string value (signified by the MEM_Ephem flag) contains
** a pointer to a dynamically allocated string where some other entity
-** is responsible for deallocating that string. Because the stack entry
-** does not control the string, it might be deleted without the stack
-** entry knowing it.
+** is responsible for deallocating that string. Because the register
+** does not control the string, it might be deleted without the register
+** knowing it.
**
** This routine converts an ephemeral string into a dynamically allocated
-** string that the stack entry itself controls. In other words, it
+** string that the register itself controls. In other words, it
** converts an MEM_Ephem string into an MEM_Dyn string.
*/
#define Deephemeralize(P) \
@@ -140,10 +156,16 @@ int sqlite3_sort_count = 0;
&& sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;}
/*
-** Argument pMem points at a memory cell that will be passed to a
+** Call sqlite3VdbeMemExpandBlob() on the supplied value (type Mem*)
+** P if required.
+*/
+#define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0)
+
+/*
+** Argument pMem points at a regiser 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
-** stack variables. This routine sets the pMem->enc and pMem->type
+** register variables. This routine sets the pMem->enc and pMem->type
** variables used by the sqlite3_value_*() routines.
*/
#define storeTypeInfo(A,B) _storeTypeInfo(A)
@@ -166,16 +188,20 @@ static void _storeTypeInfo(Mem *pMem){
}
/*
-** Pop the stack N times.
+** Properties of opcodes. The OPFLG_INITIALIZER macro is
+** created by mkopcodeh.awk during compilation. Data is obtained
+** from the comments following the "case OP_xxxx:" statements in
+** this file.
*/
-static void popStack(Mem **ppTos, int N){
- Mem *pTos = *ppTos;
- while( N>0 ){
- N--;
- Release(pTos);
- pTos--;
- }
- *ppTos = pTos;
+static unsigned char opcodeProperty[] = OPFLG_INITIALIZER;
+
+/*
+** Return true if an opcode has any of the OPFLG_xxx properties
+** specified by mask.
+*/
+int sqlite3VdbeOpcodeHasProperty(int opcode, int mask){
+ assert( opcode>0 && opcode<sizeof(opcodeProperty) );
+ return (opcodeProperty[opcode]&mask)!=0;
}
/*
@@ -188,7 +214,7 @@ static Cursor *allocateCursor(Vdbe *p, int iCur, int iDb){
if( p->apCsr[iCur] ){
sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
}
- p->apCsr[iCur] = pCx = sqliteMalloc( sizeof(Cursor) );
+ p->apCsr[iCur] = pCx = sqlite3MallocZero( sizeof(Cursor) );
if( pCx ){
pCx->iDb = iDb;
}
@@ -209,9 +235,9 @@ static void applyNumericAffinity(Mem *pRec){
&& sqlite3IsNumber(pRec->z, &realnum, pRec->enc) ){
i64 value;
sqlite3VdbeChangeEncoding(pRec, SQLITE_UTF8);
- if( !realnum && sqlite3atoi64(pRec->z, &value) ){
+ if( !realnum && sqlite3Atoi64(pRec->z, &value) ){
sqlite3VdbeMemRelease(pRec);
- pRec->i = value;
+ pRec->u.i = value;
pRec->flags = MEM_Int;
}else{
sqlite3VdbeMemRealify(pRec);
@@ -238,7 +264,11 @@ static void applyNumericAffinity(Mem *pRec){
** SQLITE_AFF_NONE:
** No-op. pRec is unchanged.
*/
-static void applyAffinity(Mem *pRec, char affinity, u8 enc){
+static void applyAffinity(
+ Mem *pRec, /* The value to apply affinity to */
+ char affinity, /* The affinity to be applied */
+ u8 enc /* Use this text encoding */
+){
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
@@ -277,7 +307,11 @@ int sqlite3_value_numeric_type(sqlite3_value *pVal){
** Exported version of applyAffinity(). This one works on sqlite3_value*,
** not the internal Mem* type.
*/
-void sqlite3ValueApplyAffinity(sqlite3_value *pVal, u8 affinity, u8 enc){
+void sqlite3ValueApplyAffinity(
+ sqlite3_value *pVal,
+ u8 affinity,
+ u8 enc
+){
applyAffinity((Mem *)pVal, affinity, enc);
}
@@ -308,10 +342,13 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
c = 's';
}
- zCsr += sprintf(zCsr, "%c", c);
- zCsr += sprintf(zCsr, "%d[", pMem->n);
+ sqlite3_snprintf(100, zCsr, "%c", c);
+ zCsr += strlen(zCsr);
+ sqlite3_snprintf(100, zCsr, "%d[", pMem->n);
+ zCsr += strlen(zCsr);
for(i=0; i<16 && i<pMem->n; i++){
- zCsr += sprintf(zCsr, "%02X ", ((int)pMem->z[i] & 0xFF));
+ sqlite3_snprintf(100, zCsr, "%02X", ((int)pMem->z[i] & 0xFF));
+ zCsr += strlen(zCsr);
}
for(i=0; i<16 && i<pMem->n; i++){
char z = pMem->z[i];
@@ -319,7 +356,12 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
else *zCsr++ = z;
}
- zCsr += sprintf(zCsr, "]");
+ sqlite3_snprintf(100, zCsr, "]%s", encnames[pMem->enc]);
+ zCsr += strlen(zCsr);
+ if( f & MEM_Zero ){
+ sqlite3_snprintf(100, zCsr,"+%lldz",pMem->u.i);
+ zCsr += strlen(zCsr);
+ }
*zCsr = '\0';
}else if( f & MEM_Str ){
int j, k;
@@ -337,7 +379,8 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
zBuf[1] = 's';
}
k = 2;
- k += sprintf(&zBuf[k], "%d", pMem->n);
+ sqlite3_snprintf(100, &zBuf[k], "%d", pMem->n);
+ k += strlen(&zBuf[k]);
zBuf[k++] = '[';
for(j=0; j<15 && j<pMem->n; j++){
u8 c = pMem->z[j];
@@ -348,12 +391,46 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
}
}
zBuf[k++] = ']';
- k += sprintf(&zBuf[k], encnames[pMem->enc]);
+ sqlite3_snprintf(100,&zBuf[k], encnames[pMem->enc]);
+ k += strlen(&zBuf[k]);
zBuf[k++] = 0;
}
}
#endif
+#ifdef SQLITE_DEBUG
+/*
+** Print the value of a register for tracing purposes:
+*/
+static void memTracePrint(FILE *out, Mem *p){
+ if( p->flags & MEM_Null ){
+ fprintf(out, " NULL");
+ }else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
+ fprintf(out, " si:%lld", p->u.i);
+ }else if( p->flags & MEM_Int ){
+ fprintf(out, " i:%lld", p->u.i);
+ }else if( p->flags & MEM_Real ){
+ fprintf(out, " r:%g", p->r);
+ }else{
+ char zBuf[200];
+ sqlite3VdbeMemPrettyPrint(p, zBuf);
+ fprintf(out, " ");
+ fprintf(out, "%s", zBuf);
+ }
+}
+static void registerTrace(FILE *out, int iReg, Mem *p){
+ fprintf(out, "REG[%d] = ", iReg);
+ memTracePrint(out, p);
+ fprintf(out, "\n");
+}
+#endif
+
+#ifdef SQLITE_DEBUG
+# define REGISTER_TRACE(R,M) if(p->trace&&R>0)registerTrace(p->trace,R,M)
+#else
+# define REGISTER_TRACE(R,M)
+#endif
+
#ifdef VDBE_PROFILE
/*
@@ -401,7 +478,7 @@ __inline__ unsigned long long int hwtime(void){
** return SQLITE_BUSY.
**
** If an error occurs, an error message is written to memory obtained
-** from sqliteMalloc() and p->zErrMsg is made to point to that memory.
+** from sqlite3_malloc() and p->zErrMsg is made to point to that memory.
** The error code is stored in p->rc and this routine returns SQLITE_ERROR.
**
** If the callback ever returns non-zero, then the program exits
@@ -424,7 +501,9 @@ int sqlite3VdbeExec(
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 */
+ Mem *pIn1, *pIn2, *pIn3; /* Input operands */
+ Mem *pOut; /* Output operand */
+ u8 opProperty;
#ifdef VDBE_PROFILE
unsigned long long start; /* CPU clock count at start of opcode */
int origPc; /* Program counter at start of opcode */
@@ -432,13 +511,10 @@ int sqlite3VdbeExec(
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
int nProgressOps = 0; /* Opcodes executed since progress callback. */
#endif
-#ifndef NDEBUG
- Mem *pStackLimit;
-#endif
- if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
+ assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */
assert( db->magic==SQLITE_MAGIC_BUSY );
- pTos = p->pTos;
+ sqlite3BtreeMutexArrayEnter(&p->aMutex);
if( p->rc==SQLITE_NOMEM ){
/* This happens if a malloc() inside a call to sqlite3_column_text() or
** sqlite3_column_text16() failed. */
@@ -447,17 +523,28 @@ int sqlite3VdbeExec(
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY );
p->rc = SQLITE_OK;
assert( p->explain==0 );
- if( p->popStack ){
- popStack(&pTos, p->popStack);
- p->popStack = 0;
- }
- p->resOnStack = 0;
+ p->pResultSet = 0;
db->busyHandler.nBusy = 0;
CHECK_FOR_INTERRUPT;
+ sqlite3VdbeIOTraceSql(p);
+#ifdef SQLITE_DEBUG
+ if( p->pc==0 && ((p->db->flags & SQLITE_VdbeListing)!=0
+ || sqlite3OsAccess(db->pVfs, "vdbe_explain", SQLITE_ACCESS_EXISTS))
+ ){
+ int i;
+ printf("VDBE Program Listing:\n");
+ sqlite3VdbePrintSql(p);
+ for(i=0; i<p->nOp; i++){
+ sqlite3VdbePrintOp(stdout, i, &p->aOp[i]);
+ }
+ }
+ if( sqlite3OsAccess(db->pVfs, "vdbe_trace", SQLITE_ACCESS_EXISTS) ){
+ p->trace = stdout;
+ }
+#endif
for(pc=p->pc; rc==SQLITE_OK; pc++){
assert( pc>=0 && pc<p->nOp );
- assert( pTos<=&p->aStack[pc] );
- if( sqlite3MallocFailed() ) goto no_mem;
+ if( db->mallocFailed ) goto no_mem;
#ifdef VDBE_PROFILE
origPc = pc;
start = hwtime();
@@ -474,7 +561,8 @@ int sqlite3VdbeExec(
}
sqlite3VdbePrintOp(p->trace, pc, pOp);
}
- if( p->trace==0 && pc==0 && sqlite3OsFileExists("vdbe_sqltrace") ){
+ if( p->trace==0 && pc==0
+ && sqlite3OsAccess(db->pVfs, "vdbe_sqltrace", SQLITE_ACCESS_EXISTS) ){
sqlite3VdbePrintSql(p);
}
#endif
@@ -501,35 +589,77 @@ int sqlite3VdbeExec(
*/
if( db->xProgress ){
if( db->nProgressOps==nProgressOps ){
+ int prc;
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 */
+ prc =db->xProgress(db->pProgressArg);
+ if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+ if( prc!=0 ){
+ rc = SQLITE_INTERRUPT;
+ goto vdbe_error_halt;
}
nProgressOps = 0;
- if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
}
nProgressOps++;
}
#endif
-#ifndef NDEBUG
- /* This is to check that the return value of static function
- ** opcodeNoPush() (see vdbeaux.c) returns values that match the
- ** implementation of the virtual machine in this file. If
- ** opcodeNoPush() returns non-zero, then the stack is guarenteed
- ** not to grow when the opcode is executed. If it returns zero, then
- ** the stack may grow by at most 1.
+ /* Do common setup processing for any opcode that is marked
+ ** with the "out2-prerelease" tag. Such opcodes have a single
+ ** output which is specified by the P2 parameter. The P2 register
+ ** is initialized to a NULL.
+ */
+ opProperty = opcodeProperty[pOp->opcode];
+ if( (opProperty & OPFLG_OUT2_PRERELEASE)!=0 ){
+ assert( pOp->p2>0 );
+ assert( pOp->p2<=p->nMem );
+ pOut = &p->aMem[pOp->p2];
+ sqlite3VdbeMemRelease(pOut);
+ pOut->flags = MEM_Null;
+ }else
+
+ /* Do common setup for opcodes marked with one of the following
+ ** combinations of properties.
**
- ** The global wrapper function sqlite3VdbeOpcodeUsesStack() is not
- ** available if NDEBUG is defined at build time.
- */
- pStackLimit = pTos;
- if( !sqlite3VdbeOpcodeNoPush(pOp->opcode) ){
- pStackLimit++;
+ ** in1
+ ** in1 in2
+ ** in1 in2 out3
+ ** in1 in3
+ **
+ ** Variables pIn1, pIn2, and pIn3 are made to point to appropriate
+ ** registers for inputs. Variable pOut points to the output register.
+ */
+ if( (opProperty & OPFLG_IN1)!=0 ){
+ assert( pOp->p1>0 );
+ assert( pOp->p1<=p->nMem );
+ pIn1 = &p->aMem[pOp->p1];
+ REGISTER_TRACE(pOp->p1, pIn1);
+ if( (opProperty & OPFLG_IN2)!=0 ){
+ assert( pOp->p2>0 );
+ assert( pOp->p2<=p->nMem );
+ pIn2 = &p->aMem[pOp->p2];
+ REGISTER_TRACE(pOp->p2, pIn2);
+ if( (opProperty & OPFLG_OUT3)!=0 ){
+ assert( pOp->p3>0 );
+ assert( pOp->p3<=p->nMem );
+ pOut = &p->aMem[pOp->p3];
+ }
+ }else if( (opProperty & OPFLG_IN3)!=0 ){
+ assert( pOp->p3>0 );
+ assert( pOp->p3<=p->nMem );
+ pIn3 = &p->aMem[pOp->p3];
+ REGISTER_TRACE(pOp->p3, pIn3);
+ }
+ }else if( (opProperty & OPFLG_IN2)!=0 ){
+ assert( pOp->p2>0 );
+ assert( pOp->p2<=p->nMem );
+ pIn2 = &p->aMem[pOp->p2];
+ REGISTER_TRACE(pOp->p2, pIn2);
+ }else if( (opProperty & OPFLG_IN3)!=0 ){
+ assert( pOp->p3>0 );
+ assert( pOp->p3<=p->nMem );
+ pIn3 = &p->aMem[pOp->p3];
+ REGISTER_TRACE(pOp->p3, pIn3);
}
-#endif
switch( pOp->opcode ){
@@ -551,10 +681,10 @@ int sqlite3VdbeExec(
** case statement is followed by a comment of the form "/# same as ... #/"
** that comment is used to determine the particular value of the opcode.
**
-** If a comment on the same line as the "case OP_" construction contains
-** the word "no-push", then the opcode is guarenteed not to grow the
-** vdbe stack when it is executed. See function opcode() in
-** vdbeaux.c for details.
+** Other keywords in the comment that follows each case are used to
+** construct the OPFLG_INITIALIZER value that initializes opcodeProperty[].
+** Keywords include: in1, in2, in3, out2_prerelease, out2, out3. See
+** the mkopcodeh.awk script for additional information.
**
** Documentation about VDBE opcodes is generated by scanning this file
** for lines of that contain "Opcode:". That line and all subsequent
@@ -568,20 +698,20 @@ int sqlite3VdbeExec(
**
*****************************************************************************/
-/* Opcode: Goto * P2 *
+/* Opcode: Goto * P2 * * *
**
** An unconditional jump to address P2.
** The next instruction executed will be
** the one at index P2 from the beginning of
** the program.
*/
-case OP_Goto: { /* no-push */
+case OP_Goto: { /* jump */
CHECK_FOR_INTERRUPT;
pc = pOp->p2 - 1;
break;
}
-/* Opcode: Gosub * P2 *
+/* Opcode: Gosub * P2 * * *
**
** Push the current address plus 1 onto the return address stack
** and then jump to address P2.
@@ -591,27 +721,27 @@ case OP_Goto: { /* no-push */
** the return address stack will fill up and processing will abort
** with a fatal error.
*/
-case OP_Gosub: { /* no-push */
+case OP_Gosub: { /* jump */
assert( p->returnDepth<sizeof(p->returnStack)/sizeof(p->returnStack[0]) );
p->returnStack[p->returnDepth++] = pc+1;
pc = pOp->p2 - 1;
break;
}
-/* Opcode: Return * * *
+/* Opcode: Return * * * * *
**
** Jump immediately to the next instruction after the last unreturned
** OP_Gosub. If an OP_Return has occurred for all OP_Gosubs, then
** processing aborts with a fatal error.
*/
-case OP_Return: { /* no-push */
+case OP_Return: {
assert( p->returnDepth>0 );
p->returnDepth--;
pc = p->returnStack[p->returnDepth] - 1;
break;
}
-/* Opcode: Halt P1 P2 P3
+/* Opcode: Halt P1 P2 * P4 *
**
** Exit immediately. All open cursors, Fifos, etc are closed
** automatically.
@@ -624,307 +754,225 @@ case OP_Return: { /* no-push */
** then back out all changes that have occurred during this execution of the
** VDBE, but do not rollback the transaction.
**
-** If P3 is not null then it is an error message string.
+** If P4 is not null then it is an error message string.
**
** There is an implied "Halt 0 0 0" instruction inserted at the very end of
** every program. So a jump past the last instruction of the program
** is the same as executing Halt.
*/
-case OP_Halt: { /* no-push */
- p->pTos = pTos;
+case OP_Halt: {
p->rc = pOp->p1;
p->pc = pc;
p->errorAction = pOp->p2;
- if( pOp->p3 ){
- sqlite3SetString(&p->zErrMsg, pOp->p3, (char*)0);
+ if( pOp->p4.z ){
+ sqlite3SetString(&p->zErrMsg, pOp->p4.z, (char*)0);
}
rc = sqlite3VdbeHalt(p);
assert( rc==SQLITE_BUSY || rc==SQLITE_OK );
if( rc==SQLITE_BUSY ){
- p->rc = SQLITE_BUSY;
- return SQLITE_BUSY;
+ p->rc = rc = SQLITE_BUSY;
+ }else{
+ rc = p->rc ? SQLITE_ERROR : SQLITE_DONE;
}
- return p->rc ? SQLITE_ERROR : SQLITE_DONE;
+ goto vdbe_return;
}
-/* Opcode: Integer P1 * *
+/* Opcode: Integer P1 P2 * * *
**
-** The 32-bit integer value P1 is pushed onto the stack.
+** The 32-bit integer value P1 is written into register P2.
*/
-case OP_Integer: {
- pTos++;
- pTos->flags = MEM_Int;
- pTos->i = pOp->p1;
+case OP_Integer: { /* out2-prerelease */
+ pOut->flags = MEM_Int;
+ pOut->u.i = pOp->p1;
break;
}
-/* Opcode: Int64 * * P3
+/* Opcode: Int64 * P2 * P4 *
**
-** P3 is a string representation of an integer. Convert that integer
-** to a 64-bit value and push it onto the stack.
+** P4 is a pointer to a 64-bit integer value.
+** Write that value into register P2.
*/
-case OP_Int64: {
- pTos++;
- assert( pOp->p3!=0 );
- pTos->flags = MEM_Str|MEM_Static|MEM_Term;
- pTos->z = pOp->p3;
- pTos->n = strlen(pTos->z);
- pTos->enc = SQLITE_UTF8;
- pTos->i = sqlite3VdbeIntValue(pTos);
- pTos->flags |= MEM_Int;
+case OP_Int64: { /* out2-prerelease */
+ assert( pOp->p4.pI64!=0 );
+ pOut->flags = MEM_Int;
+ pOut->u.i = *pOp->p4.pI64;
break;
}
-/* Opcode: Real * * P3
+/* Opcode: Real * P2 * P4 *
**
-** The string value P3 is converted to a real and pushed on to the stack.
+** P4 is a pointer to a 64-bit floating point value.
+** Write that value into register P2.
*/
-case OP_Real: { /* same as TK_FLOAT, */
- pTos++;
- pTos->flags = MEM_Str|MEM_Static|MEM_Term;
- pTos->z = pOp->p3;
- pTos->n = strlen(pTos->z);
- pTos->enc = SQLITE_UTF8;
- pTos->r = sqlite3VdbeRealValue(pTos);
- pTos->flags |= MEM_Real;
- sqlite3VdbeChangeEncoding(pTos, encoding);
+case OP_Real: { /* same as TK_FLOAT, out2-prerelease */
+ pOut->flags = MEM_Real;
+ pOut->r = *pOp->p4.pReal;
break;
}
-/* Opcode: String8 * * P3
+/* Opcode: String8 * P2 * P4 *
**
-** P3 points to a nul terminated UTF-8 string. This opcode is transformed
+** P4 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 */
- assert( pOp->p3!=0 );
+case OP_String8: { /* same as TK_STRING, out2-prerelease */
+ assert( pOp->p4.z!=0 );
pOp->opcode = OP_String;
- pOp->p1 = strlen(pOp->p3);
+ pOp->p1 = strlen(pOp->p4.z);
#ifndef SQLITE_OMIT_UTF16
if( encoding!=SQLITE_UTF8 ){
- pTos++;
- sqlite3VdbeMemSetStr(pTos, pOp->p3, -1, SQLITE_UTF8, SQLITE_STATIC);
- 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;
- if( pOp->p3type==P3_DYNAMIC ){
- sqliteFree(pOp->p3);
+ sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC);
+ if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem;
+ if( SQLITE_OK!=sqlite3VdbeMemDynamicify(pOut) ) goto no_mem;
+ pOut->flags &= ~(MEM_Dyn);
+ pOut->flags |= MEM_Static;
+ if( pOp->p4type==P4_DYNAMIC ){
+ sqlite3_free(pOp->p4.z);
+ }
+ pOp->p4type = P4_DYNAMIC;
+ pOp->p4.z = pOut->z;
+ pOp->p1 = pOut->n;
+ if( pOp->p1>SQLITE_MAX_LENGTH ){
+ goto too_big;
}
- pOp->p3type = P3_DYNAMIC;
- pOp->p3 = pTos->z;
- pOp->p1 = pTos->n;
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
#endif
- /* Otherwise fall through to the next case, OP_String */
+ if( pOp->p1>SQLITE_MAX_LENGTH ){
+ goto too_big;
+ }
+ /* Fall through to the next case, OP_String */
}
-/* Opcode: String P1 * P3
+/* Opcode: String P1 P2 * P4 *
**
-** The string value P3 of length P1 (bytes) is pushed onto the stack.
+** The string value P4 of length P1 (bytes) is stored in register P2.
*/
-case OP_String: {
- pTos++;
- assert( pOp->p3!=0 );
- pTos->flags = MEM_Str|MEM_Static|MEM_Term;
- pTos->z = pOp->p3;
- pTos->n = pOp->p1;
- pTos->enc = encoding;
+case OP_String: { /* out2-prerelease */
+ assert( pOp->p4.z!=0 );
+ pOut->flags = MEM_Str|MEM_Static|MEM_Term;
+ pOut->z = pOp->p4.z;
+ pOut->n = pOp->p1;
+ pOut->enc = encoding;
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
-/* Opcode: Null * * *
+/* Opcode: Null * P2 * * *
**
-** Push a NULL onto the stack.
+** Write a NULL into register P2.
*/
-case OP_Null: {
- pTos++;
- pTos->flags = MEM_Null;
- pTos->n = 0;
+case OP_Null: { /* out2-prerelease */
break;
}
#ifndef SQLITE_OMIT_BLOB_LITERAL
-/* Opcode: HexBlob * * P3
-**
-** P3 is an UTF-8 SQL hex encoding of a blob. The blob is pushed onto the
-** vdbe stack.
-**
-** The first time this instruction executes, in transforms itself into a
-** 'Blob' opcode with a binary blob as P3.
-*/
-case OP_HexBlob: { /* same as TK_BLOB */
- pOp->opcode = OP_Blob;
- pOp->p1 = strlen(pOp->p3)/2;
- if( pOp->p1 ){
- char *zBlob = sqlite3HexToBlob(pOp->p3);
- if( !zBlob ) goto no_mem;
- if( pOp->p3type==P3_DYNAMIC ){
- sqliteFree(pOp->p3);
- }
- pOp->p3 = zBlob;
- pOp->p3type = P3_DYNAMIC;
- }else{
- if( pOp->p3type==P3_DYNAMIC ){
- sqliteFree(pOp->p3);
- }
- pOp->p3type = P3_STATIC;
- pOp->p3 = "";
- }
-
- /* Fall through to the next case, OP_Blob. */
-}
-
-/* Opcode: Blob P1 * P3
+/* Opcode: Blob P1 P2 * P4
**
-** P3 points to a blob of data P1 bytes long. Push this
-** value onto the stack. This instruction is not coded directly
+** P4 points to a blob of data P1 bytes long. Store this
+** blob in register P2. This instruction is not coded directly
** by the compiler. Instead, the compiler layer specifies
** an OP_HexBlob opcode, with the hex string representation of
-** the blob as P3. This opcode is transformed to an OP_Blob
+** the blob as P4. This opcode is transformed to an OP_Blob
** the first time it is executed.
*/
-case OP_Blob: {
- pTos++;
- sqlite3VdbeMemSetStr(pTos, pOp->p3, pOp->p1, 0, 0);
+case OP_Blob: { /* out2-prerelease */
+ assert( pOp->p1 <= SQLITE_MAX_LENGTH );
+ sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0);
+ pOut->enc = encoding;
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
#endif /* SQLITE_OMIT_BLOB_LITERAL */
-/* Opcode: Variable P1 * *
+/* Opcode: Variable P1 P2 * * *
**
-** Push the value of variable P1 onto the stack. A variable is
+** The value of variable P1 is written into register P2. A variable is
** an unknown in the original SQL string as handed to sqlite3_compile().
** Any occurance of the '?' character in the original SQL is considered
** a variable. Variables in the SQL string are number from left to
** right beginning with 1. The values of variables are set using the
** sqlite3_bind() API.
*/
-case OP_Variable: {
+case OP_Variable: { /* out2-prerelease */
int j = pOp->p1 - 1;
+ Mem *pVar;
assert( j>=0 && j<p->nVar );
- pTos++;
- sqlite3VdbeMemShallowCopy(pTos, &p->aVar[j], MEM_Static);
+ pVar = &p->aVar[j];
+ if( sqlite3VdbeMemTooBig(pVar) ){
+ goto too_big;
+ }
+ sqlite3VdbeMemShallowCopy(pOut, &p->aVar[j], MEM_Static);
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
-/* Opcode: Pop P1 * *
+/* Opcode: Move P1 P2 * * *
**
-** P1 elements are popped off of the top of stack and discarded.
+** Move the value in register P1 over into register P2. Register P1
+** is left holding a NULL. It is an error for P1 and P2 to be the
+** same register.
*/
-case OP_Pop: { /* no-push */
- assert( pOp->p1>=0 );
- popStack(&pTos, pOp->p1);
- assert( pTos>=&p->aStack[-1] );
- break;
-}
-
-/* Opcode: Dup P1 P2 *
-**
-** A copy of the P1-th element of the stack
-** is made and pushed onto the top of the stack.
-** The top of the stack is element 0. So the
-** instruction "Dup 0 0 0" will make a copy of the
-** top of the stack.
+/* Opcode: Copy P1 P2 * * *
**
-** If the content of the P1-th element is a dynamically
-** allocated string, then a new copy of that string
-** is made if P2==0. If P2!=0, then just a pointer
-** to the string is copied.
+** Make a copy of register P1 into register P2.
**
-** Also see the Pull instruction.
+** This instruction makes a deep copy of the value. A duplicate
+** is made of any string or blob constant. See also OP_SCopy.
*/
-case OP_Dup: {
- Mem *pFrom = &pTos[-pOp->p1];
- assert( pFrom<=pTos && pFrom>=p->aStack );
- pTos++;
- sqlite3VdbeMemShallowCopy(pTos, pFrom, MEM_Ephem);
- if( pOp->p2 ){
- Deephemeralize(pTos);
- }
- break;
-}
-
-/* Opcode: Pull P1 * *
+/* Opcode: SCopy P1 P2 * * *
**
-** The P1-th element is removed from its current location on
-** the stack and pushed back on top of the stack. The
-** top of the stack is element 0, so "Pull 0 0 0" is
-** a no-op. "Pull 1 0 0" swaps the top two elements of
-** the stack.
+** Make a shallow copy of register P1 into register P2.
**
-** See also the Dup instruction.
+** This instruction makes a shallow copy of the value. If the value
+** is a string or blob, then the copy is only a pointer to the
+** original and hence if the original changes so will the copy.
+** Worse, if the original is deallocated, the copy becomes invalid.
+** Thus the program must guarantee that the original will not change
+** during the lifetime of the copy. Use OP_Copy to make a complete
+** copy.
*/
-case OP_Pull: { /* no-push */
- Mem *pFrom = &pTos[-pOp->p1];
- int i;
- Mem ts;
-
- ts = *pFrom;
- Deephemeralize(pTos);
- for(i=0; i<pOp->p1; i++, pFrom++){
- Deephemeralize(&pFrom[1]);
- assert( (pFrom->flags & MEM_Ephem)==0 );
- *pFrom = pFrom[1];
- if( pFrom->flags & MEM_Short ){
- assert( pFrom->flags & (MEM_Str|MEM_Blob) );
- assert( pFrom->z==pFrom[1].zShort );
- pFrom->z = pFrom->zShort;
+case OP_Move:
+case OP_Copy:
+case OP_SCopy: {
+ assert( pOp->p1>0 );
+ assert( pOp->p1<=p->nMem );
+ pIn1 = &p->aMem[pOp->p1];
+ REGISTER_TRACE(pOp->p1, pIn1);
+ assert( pOp->p2>0 );
+ assert( pOp->p2<=p->nMem );
+ pOut = &p->aMem[pOp->p2];
+ assert( pOut!=pIn1 );
+ if( pOp->opcode==OP_Move ){
+ sqlite3VdbeMemMove(pOut, pIn1);
+ }else{
+ sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
+ if( pOp->opcode==OP_Copy ){
+ Deephemeralize(pOut);
}
}
- *pTos = ts;
- if( pTos->flags & MEM_Short ){
- assert( pTos->flags & (MEM_Str|MEM_Blob) );
- assert( pTos->z==pTos[-pOp->p1].zShort );
- pTos->z = pTos->zShort;
- }
+ REGISTER_TRACE(pOp->p2, pOut);
break;
}
-/* Opcode: Push P1 * *
+/* Opcode: ResultRow P1 P2 * * *
**
-** Overwrite the value of the P1-th element down on the
-** stack (P1==0 is the top of the stack) with the value
-** of the top of the stack. Then pop the top of the stack.
-*/
-case OP_Push: { /* no-push */
- Mem *pTo = &pTos[-pOp->p1];
-
- assert( pTo>=p->aStack );
- sqlite3VdbeMemMove(pTo, pTos);
- pTos--;
- break;
-}
-
-/* Opcode: Callback P1 * *
-**
-** The top P1 values on the stack represent a single result row from
-** a query. This opcode causes the sqlite3_step() call to terminate
+** The registers P1 throught P1+P2-1 contain a single row of
+** results. 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.
+** row.
*/
-case OP_Callback: { /* no-push */
+case OP_ResultRow: {
Mem *pMem;
- Mem *pFirstColumn;
- assert( p->nResColumn==pOp->p1 );
-
- /* 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);
- }
+ int i;
+ assert( p->nResColumn==pOp->p2 );
+ assert( pOp->p1>0 );
+ assert( pOp->p1+pOp->p2<=p->nMem );
/* Invalidate all ephemeral cursor row caches */
p->cacheCtr = (p->cacheCtr + 2)|1;
@@ -933,221 +981,175 @@ case OP_Callback: { /* no-push */
** and have an assigned type. The results are deephemeralized as
** as side effect.
*/
- for(; pMem<=pTos; pMem++ ){
- sqlite3VdbeMemNulTerminate(pMem);
- storeTypeInfo(pMem, encoding);
+ pMem = p->pResultSet = &p->aMem[pOp->p1];
+ for(i=0; i<pOp->p2; i++){
+ sqlite3VdbeMemNulTerminate(&pMem[i]);
+ storeTypeInfo(&pMem[i], encoding);
}
- /* Set up the statement structure so that it will pop the current
- ** results from the stack when the statement returns.
+ /* Return SQLITE_ROW
*/
- p->resOnStack = 1;
p->nCallback++;
- p->popStack = pOp->p1;
p->pc = pc + 1;
- p->pTos = pTos;
- return SQLITE_ROW;
+ rc = SQLITE_ROW;
+ goto vdbe_return;
}
-/* Opcode: Concat P1 P2 *
+/* Opcode: Concat P1 P2 P3 * *
**
-** Look at the first P1+2 elements of the stack. Append them all
-** together with the lowest element first. The original P1+2 elements
-** are popped from the stack if P2==0 and retained if P2==1. If
-** any element of the stack is NULL, then the result is NULL.
-**
-** When P1==1, this routine makes a copy of the top stack element
-** into memory obtained from sqliteMalloc().
+** Add the text in register P1 onto the end of the text in
+** register P2 and store the result in register P3.
+** If either the P1 or P2 text are NULL then store NULL in P3.
*/
-case OP_Concat: { /* same as TK_CONCAT */
+case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
char *zNew;
- int nByte;
- int nField;
- int i, j;
- Mem *pTerm;
-
- /* Loop through the stack elements to see how long the result will be. */
- nField = pOp->p1 + 2;
- pTerm = &pTos[1-nField];
- nByte = 0;
- for(i=0; i<nField; i++, pTerm++){
- assert( pOp->p2==0 || (pTerm->flags&MEM_Str) );
- if( pTerm->flags&MEM_Null ){
- nByte = -1;
- break;
- }
- Stringify(pTerm, encoding);
- nByte += pTerm->n;
- }
+ i64 nByte;
- if( nByte<0 ){
- /* If nByte is less than zero, then there is a NULL value on the stack.
- ** In this case just pop the values off the stack (if required) and
- ** push on a NULL.
- */
- if( pOp->p2==0 ){
- popStack(&pTos, nField);
- }
- pTos++;
- pTos->flags = MEM_Null;
- }else{
- /* Otherwise malloc() space for the result and concatenate all the
- ** stack values.
- */
- zNew = sqliteMallocRaw( nByte+2 );
- if( zNew==0 ) goto no_mem;
- j = 0;
- pTerm = &pTos[1-nField];
- for(i=j=0; i<nField; i++, pTerm++){
- int n = pTerm->n;
- assert( pTerm->flags & (MEM_Str|MEM_Blob) );
- memcpy(&zNew[j], pTerm->z, n);
- j += n;
- }
- zNew[j] = 0;
- zNew[j+1] = 0;
- assert( j==nByte );
-
- if( pOp->p2==0 ){
- popStack(&pTos, nField);
- }
- pTos++;
- pTos->n = j;
- pTos->flags = MEM_Str|MEM_Dyn|MEM_Term;
- pTos->xDel = 0;
- pTos->enc = encoding;
- pTos->z = zNew;
+ if( (pIn1->flags | pIn2->flags) & MEM_Null ){
+ Release(pOut);
+ pOut->flags = MEM_Null;
+ break;
+ }
+ ExpandBlob(pIn1);
+ Stringify(pIn1, encoding);
+ ExpandBlob(pIn2);
+ Stringify(pIn2, encoding);
+ nByte = pIn1->n + pIn2->n;
+ if( nByte>SQLITE_MAX_LENGTH ){
+ goto too_big;
+ }
+ zNew = sqlite3DbMallocRaw(db, nByte+2);
+ if( zNew==0 ){
+ goto no_mem;
}
+ memcpy(zNew, pIn2->z, pIn2->n);
+ memcpy(&zNew[pIn2->n], pIn1->z, pIn1->n);
+ zNew[nByte] = 0;
+ zNew[nByte+1] = 0;
+ Release(pOut);
+ pOut->n = nByte;
+ pOut->flags = MEM_Str|MEM_Dyn|MEM_Term;
+ pOut->xDel = 0;
+ pOut->enc = encoding;
+ pOut->z = zNew;
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
-/* Opcode: Add * * *
+/* Opcode: Add P1 P2 P3 * *
**
-** Pop the top two elements from the stack, add them together,
-** and push the result back onto the stack. If either element
-** is a string then it is converted to a double using the atof()
-** function before the addition.
-** If either operand is NULL, the result is NULL.
+** Add the value in register P1 to the value in register P2
+** and store the result in regiser P3.
+** If either input is NULL, the result is NULL.
*/
-/* Opcode: Multiply * * *
+/* Opcode: Multiply P1 P2 P3 * *
**
-** Pop the top two elements from the stack, multiply them together,
-** and push the result back onto the stack. If either element
-** is a string then it is converted to a double using the atof()
-** function before the multiplication.
-** If either operand is NULL, the result is NULL.
+**
+** Multiply the value in regiser P1 by the value in regiser P2
+** and store the result in register P3.
+** If either input is NULL, the result is NULL.
*/
-/* Opcode: Subtract * * *
+/* Opcode: Subtract P1 P2 P3 * *
**
-** Pop the top two elements from the stack, subtract the
-** first (what was on top of the stack) from the second (the
-** next on stack)
-** and push the result back onto the stack. If either element
-** is a string then it is converted to a double using the atof()
-** function before the subtraction.
-** If either operand is NULL, the result is NULL.
+** Subtract the value in register P1 from the value in register P2
+** and store the result in register P3.
+** If either input is NULL, the result is NULL.
*/
-/* Opcode: Divide * * *
+/* Opcode: Divide P1 P2 P3 * *
**
-** Pop the top two elements from the stack, divide the
-** first (what was on top of the stack) from the second (the
-** next on stack)
-** and push the result back onto the stack. If either element
-** is a string then it is converted to a double using the atof()
-** function before the division. Division by zero returns NULL.
-** If either operand is NULL, the result is NULL.
+** Divide the value in register P1 by the value in register P2
+** and store the result in register P3. If the value in register P2
+** is zero, then the result is NULL.
+** If either input is NULL, the result is NULL.
*/
-/* Opcode: Remainder * * *
+/* Opcode: Remainder P1 P2 P3 * *
**
-** Pop the top two elements from the stack, divide the
-** first (what was on top of the stack) from the second (the
-** next on stack)
-** and push the remainder after division onto the stack. If either element
-** is a string then it is converted to a double using the atof()
-** function before the division. Division by zero returns NULL.
+** Compute the remainder after integer division of the value in
+** register P1 by the value in register P2 and store the result in P3.
+** If the value in register P2 is zero the result is NULL.
** If either operand is NULL, the result is NULL.
*/
-case OP_Add: /* same as TK_PLUS, no-push */
-case OP_Subtract: /* same as TK_MINUS, no-push */
-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];
+case OP_Add: /* same as TK_PLUS, in1, in2, out3 */
+case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
+case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
+case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
+case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
int flags;
- assert( pNos>=p->aStack );
- flags = pTos->flags | pNos->flags;
- if( (flags & MEM_Null)!=0 ){
- Release(pTos);
- pTos--;
- Release(pTos);
- pTos->flags = MEM_Null;
- }else if( (pTos->flags & pNos->flags & MEM_Int)==MEM_Int ){
+ flags = pIn1->flags | pIn2->flags;
+ if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
+ if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){
i64 a, b;
- a = pTos->i;
- b = pNos->i;
+ a = pIn1->u.i;
+ b = pIn2->u.i;
switch( pOp->opcode ){
case OP_Add: b += a; break;
case OP_Subtract: b -= a; break;
case OP_Multiply: b *= a; break;
case OP_Divide: {
- if( a==0 ) goto divide_by_zero;
+ if( a==0 ) goto arithmetic_result_is_null;
+ /* Dividing the largest possible negative 64-bit integer (1<<63) by
+ ** -1 returns an integer to large to store in a 64-bit data-type. On
+ ** some architectures, the value overflows to (1<<63). On others,
+ ** a SIGFPE is issued. The following statement normalizes this
+ ** behaviour so that all architectures behave as if integer
+ ** overflow occured.
+ */
+ if( a==-1 && b==(((i64)1)<<63) ) a = 1;
b /= a;
break;
}
default: {
- if( a==0 ) goto divide_by_zero;
+ if( a==0 ) goto arithmetic_result_is_null;
+ if( a==-1 ) a = 1;
b %= a;
break;
}
}
- Release(pTos);
- pTos--;
- Release(pTos);
- pTos->i = b;
- pTos->flags = MEM_Int;
+ Release(pOut);
+ pOut->u.i = b;
+ pOut->flags = MEM_Int;
}else{
double a, b;
- a = sqlite3VdbeRealValue(pTos);
- b = sqlite3VdbeRealValue(pNos);
+ a = sqlite3VdbeRealValue(pIn1);
+ b = sqlite3VdbeRealValue(pIn2);
switch( pOp->opcode ){
case OP_Add: b += a; break;
case OP_Subtract: b -= a; break;
case OP_Multiply: b *= a; break;
case OP_Divide: {
- if( a==0.0 ) goto divide_by_zero;
+ if( a==0.0 ) goto arithmetic_result_is_null;
b /= a;
break;
}
default: {
- int ia = (int)a;
- int ib = (int)b;
- if( ia==0.0 ) goto divide_by_zero;
+ i64 ia = (i64)a;
+ i64 ib = (i64)b;
+ if( ia==0 ) goto arithmetic_result_is_null;
+ if( ia==-1 ) ia = 1;
b = ib % ia;
break;
}
}
- Release(pTos);
- pTos--;
- Release(pTos);
- pTos->r = b;
- pTos->flags = MEM_Real;
+ if( sqlite3_isnan(b) ){
+ goto arithmetic_result_is_null;
+ }
+ Release(pOut);
+ pOut->r = b;
+ pOut->flags = MEM_Real;
if( (flags & MEM_Real)==0 ){
- sqlite3VdbeIntegerAffinity(pTos);
+ sqlite3VdbeIntegerAffinity(pOut);
}
}
break;
-divide_by_zero:
- Release(pTos);
- pTos--;
- Release(pTos);
- pTos->flags = MEM_Null;
+arithmetic_result_is_null:
+ sqlite3VdbeMemSetNull(pOut);
break;
}
-/* Opcode: CollSeq * * P3
+/* Opcode: CollSeq * * P4
**
-** P3 is a pointer to a CollSeq struct. If the next call to a user function
+** P4 is a pointer to a CollSeq struct. If the next call to a user function
** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will
** be returned. This is used by the built-in min(), max() and nullif()
** functions.
@@ -1156,16 +1158,16 @@ divide_by_zero:
** to retrieve the collation sequence set by this opcode is not available
** publicly, only to user functions defined in func.c.
*/
-case OP_CollSeq: { /* no-push */
- assert( pOp->p3type==P3_COLLSEQ );
+case OP_CollSeq: {
+ assert( pOp->p4type==P4_COLLSEQ );
break;
}
-/* Opcode: Function P1 P2 P3
+/* Opcode: Function P1 P2 P3 P4 P5
**
-** Invoke a user function (P3 is a pointer to a Function structure that
-** defines the function) with P2 arguments taken from the stack. Pop all
-** arguments from the stack and push back the result.
+** Invoke a user function (P4 is a pointer to a Function structure that
+** defines the function) with P5 arguments taken from register P2 and
+** successors. The result of the function is stored in register P3.
**
** P1 is a 32-bit bitmask indicating whether or not each argument to the
** function was determined to be constant at compile time. If the first
@@ -1181,264 +1183,264 @@ case OP_Function: {
Mem *pArg;
sqlite3_context ctx;
sqlite3_value **apVal;
- int n = pOp->p2;
+ int n = pOp->p5;
apVal = p->apArg;
assert( apVal || n==0 );
- pArg = &pTos[1-n];
+ assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem) );
+ pArg = &p->aMem[pOp->p2];
for(i=0; i<n; i++, pArg++){
apVal[i] = pArg;
storeTypeInfo(pArg, encoding);
+ REGISTER_TRACE(pOp->p2, pArg);
}
- assert( pOp->p3type==P3_FUNCDEF || pOp->p3type==P3_VDBEFUNC );
- if( pOp->p3type==P3_FUNCDEF ){
- ctx.pFunc = (FuncDef*)pOp->p3;
+ assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC );
+ if( pOp->p4type==P4_FUNCDEF ){
+ ctx.pFunc = pOp->p4.pFunc;
ctx.pVdbeFunc = 0;
}else{
- ctx.pVdbeFunc = (VdbeFunc*)pOp->p3;
+ ctx.pVdbeFunc = (VdbeFunc*)pOp->p4.pVdbeFunc;
ctx.pFunc = ctx.pVdbeFunc->pFunc;
}
ctx.s.flags = MEM_Null;
ctx.s.z = 0;
ctx.s.xDel = 0;
+ ctx.s.db = db;
ctx.isError = 0;
if( ctx.pFunc->needCollSeq ){
assert( pOp>p->aOp );
- assert( pOp[-1].p3type==P3_COLLSEQ );
+ assert( pOp[-1].p4type==P4_COLLSEQ );
assert( pOp[-1].opcode==OP_CollSeq );
- ctx.pColl = (CollSeq *)pOp[-1].p3;
+ ctx.pColl = pOp[-1].p4.pColl;
}
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
(*ctx.pFunc->xFunc)(&ctx, n, apVal);
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
- if( sqlite3MallocFailed() ) goto no_mem;
- popStack(&pTos, n);
+ if( db->mallocFailed ){
+ /* Even though a malloc() has failed, the implementation of the
+ ** user function may have called an sqlite3_result_XXX() function
+ ** to return a value. The following call releases any resources
+ ** associated with such a value.
+ **
+ ** Note: Maybe MemRelease() should be called if sqlite3SafetyOn()
+ ** fails also (the if(...) statement above). But if people are
+ ** misusing sqlite, they have bigger problems than a leaked value.
+ */
+ sqlite3VdbeMemRelease(&ctx.s);
+ goto no_mem;
+ }
/* If any auxilary data functions have been called by this user function,
** immediately call the destructor for any non-static values.
*/
if( ctx.pVdbeFunc ){
sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p1);
- pOp->p3 = (char *)ctx.pVdbeFunc;
- pOp->p3type = P3_VDBEFUNC;
+ pOp->p4.pVdbeFunc = ctx.pVdbeFunc;
+ pOp->p4type = P4_VDBEFUNC;
}
/* If the function returned an error, throw an exception */
if( ctx.isError ){
sqlite3SetString(&p->zErrMsg, sqlite3_value_text(&ctx.s), (char*)0);
- rc = SQLITE_ERROR;
+ rc = ctx.isError;
}
- /* Copy the result of the function to the top of the stack */
+ /* Copy the result of the function into register P3 */
sqlite3VdbeChangeEncoding(&ctx.s, encoding);
- pTos++;
- pTos->flags = 0;
- sqlite3VdbeMemMove(pTos, &ctx.s);
+ assert( pOp->p3>0 && pOp->p3<=p->nMem );
+ pOut = &p->aMem[pOp->p3];
+ sqlite3VdbeMemMove(pOut, &ctx.s);
+ if( sqlite3VdbeMemTooBig(pOut) ){
+ goto too_big;
+ }
+ REGISTER_TRACE(pOp->p3, pOut);
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
-/* Opcode: BitAnd * * *
+/* Opcode: BitAnd P1 P2 P3 * *
**
-** Pop the top two elements from the stack. Convert both elements
-** to integers. Push back onto the stack the bit-wise AND of the
-** two elements.
-** If either operand is NULL, the result is NULL.
+** Take the bit-wise AND of the values in register P1 and P2 and
+** store the result in register P3.
+** If either input is NULL, the result is NULL.
*/
-/* Opcode: BitOr * * *
+/* Opcode: BitOr P1 P2 P3 * *
**
-** Pop the top two elements from the stack. Convert both elements
-** to integers. Push back onto the stack the bit-wise OR of the
-** two elements.
-** If either operand is NULL, the result is NULL.
+** Take the bit-wise OR of the values in register P1 and P2 and
+** store the result in register P3.
+** If either input is NULL, the result is NULL.
*/
-/* Opcode: ShiftLeft * * *
+/* Opcode: ShiftLeft P1 P2 P3 * *
**
-** Pop the top two elements from the stack. Convert both elements
-** to integers. Push back onto the stack the second element shifted
-** left by N bits where N is the top element on the stack.
-** If either operand is NULL, the result is NULL.
+** Shift the integer value in register P2 to the left by the
+** number of bits specified by the integer in regiser P1.
+** Store the result in register P3.
+** If either input is NULL, the result is NULL.
*/
-/* Opcode: ShiftRight * * *
+/* Opcode: ShiftRight P1 P2 P3 * *
**
-** Pop the top two elements from the stack. Convert both elements
-** to integers. Push back onto the stack the second element shifted
-** right by N bits where N is the top element on the stack.
-** If either operand is NULL, the result is NULL.
+** Shift the integer value in register P2 to the right by the
+** number of bits specified by the integer in register P1.
+** Store the result in register P3.
+** If either input is NULL, the result is NULL.
*/
-case OP_BitAnd: /* same as TK_BITAND, no-push */
-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];
+case OP_BitAnd: /* same as TK_BITAND, in1, in2, out3 */
+case OP_BitOr: /* same as TK_BITOR, in1, in2, out3 */
+case OP_ShiftLeft: /* same as TK_LSHIFT, in1, in2, out3 */
+case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */
i64 a, b;
- assert( pNos>=p->aStack );
- if( (pTos->flags | pNos->flags) & MEM_Null ){
- popStack(&pTos, 2);
- pTos++;
- pTos->flags = MEM_Null;
+ if( (pIn1->flags | pIn2->flags) & MEM_Null ){
+ sqlite3VdbeMemSetNull(pOut);
break;
}
- a = sqlite3VdbeIntValue(pNos);
- b = sqlite3VdbeIntValue(pTos);
+ a = sqlite3VdbeIntValue(pIn2);
+ b = sqlite3VdbeIntValue(pIn1);
switch( pOp->opcode ){
case OP_BitAnd: a &= b; break;
case OP_BitOr: a |= b; break;
case OP_ShiftLeft: a <<= b; break;
- case OP_ShiftRight: a >>= b; break;
- default: /* CANT HAPPEN */ break;
- }
- Release(pTos);
- pTos--;
- Release(pTos);
- pTos->i = a;
- pTos->flags = MEM_Int;
+ default: assert( pOp->opcode==OP_ShiftRight );
+ a >>= b; break;
+ }
+ Release(pOut);
+ pOut->u.i = a;
+ pOut->flags = MEM_Int;
break;
}
-/* Opcode: AddImm P1 * *
+/* Opcode: AddImm P1 P2 * * *
**
-** Add the value P1 to whatever is on top of the stack. The result
-** is always an integer.
+** Add the constant P2 the value in register P1.
+** The result is always an integer.
**
-** To force the top of the stack to be an integer, just add 0.
+** To force any register to be an integer, just add 0.
*/
-case OP_AddImm: { /* no-push */
- assert( pTos>=p->aStack );
- sqlite3VdbeMemIntegerify(pTos);
- pTos->i += pOp->p1;
+case OP_AddImm: { /* in1 */
+ sqlite3VdbeMemIntegerify(pIn1);
+ pIn1->u.i += pOp->p2;
break;
}
-/* Opcode: ForceInt P1 P2 *
+/* Opcode: ForceInt P1 P2 P3 * *
**
-** Convert the top of the stack into an integer. If the current top of
-** the stack is not numeric (meaning that is is a NULL or a string that
-** does not look like an integer or floating point number) then pop the
-** stack and jump to P2. If the top of the stack is numeric then
+** Convert value in register P1 into an integer. If the value
+** in P1 is not numeric (meaning that is is a NULL or a string that
+** does not look like an integer or floating point number) then
+** jump to P2. If the value in P1 is numeric then
** convert it into the least integer that is greater than or equal to its
-** current value if P1==0, or to the least integer that is strictly
-** greater than its current value if P1==1.
+** current value if P3==0, or to the least integer that is strictly
+** greater than its current value if P3==1.
*/
-case OP_ForceInt: { /* no-push */
+case OP_ForceInt: { /* jump, in1 */
i64 v;
- assert( pTos>=p->aStack );
- applyAffinity(pTos, SQLITE_AFF_NUMERIC, encoding);
- if( (pTos->flags & (MEM_Int|MEM_Real))==0 ){
- Release(pTos);
- pTos--;
+ applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
+ if( (pIn1->flags & (MEM_Int|MEM_Real))==0 ){
pc = pOp->p2 - 1;
break;
}
- if( pTos->flags & MEM_Int ){
- v = pTos->i + (pOp->p1!=0);
+ if( pIn1->flags & MEM_Int ){
+ v = pIn1->u.i + (pOp->p3!=0);
}else{
- /* 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++;
- }
- Release(pTos);
- pTos->i = v;
- pTos->flags = MEM_Int;
+ assert( pIn1->flags & MEM_Real );
+ v = (sqlite3_int64)pIn1->r;
+ if( pIn1->r>(double)v ) v++;
+ if( pOp->p3 && pIn1->r==(double)v ) v++;
+ }
+ Release(pIn1);
+ pIn1->u.i = v;
+ pIn1->flags = MEM_Int;
break;
}
-/* Opcode: MustBeInt P1 P2 *
+/* Opcode: MustBeInt P1 P2 * * *
**
-** Force the top of the stack to be an integer. If the top of the
-** stack is not an integer and cannot be converted into an integer
-** with out data loss, then jump immediately to P2, or if P2==0
+** Force the value in register P1 to be an integer. If the value
+** in P1 is not an integer and cannot be converted into an integer
+** without data loss, then jump immediately to P2, or if P2==0
** raise an SQLITE_MISMATCH exception.
-**
-** If the top of the stack is not an integer and P2 is not zero and
-** P1 is 1, then the stack is popped. In all other cases, the depth
-** of the stack is unchanged.
*/
-case OP_MustBeInt: { /* no-push */
- assert( pTos>=p->aStack );
- applyAffinity(pTos, SQLITE_AFF_NUMERIC, encoding);
- if( (pTos->flags & MEM_Int)==0 ){
+case OP_MustBeInt: { /* jump, in1 */
+ applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
+ if( (pIn1->flags & MEM_Int)==0 ){
if( pOp->p2==0 ){
rc = SQLITE_MISMATCH;
goto abort_due_to_error;
}else{
- if( pOp->p1 ) popStack(&pTos, 1);
pc = pOp->p2 - 1;
}
}else{
- Release(pTos);
- pTos->flags = MEM_Int;
+ Release(pIn1);
+ pIn1->flags = MEM_Int;
}
break;
}
-/* Opcode: RealAffinity * * *
+/* Opcode: RealAffinity P1 * * * *
**
-** If the top of the stack is an integer, convert it to a real value.
+** If register P1 holds an integer convert it to a real value.
**
** 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_RealAffinity: { /* no-push */
- assert( pTos>=p->aStack );
- if( pTos->flags & MEM_Int ){
- sqlite3VdbeMemRealify(pTos);
+case OP_RealAffinity: { /* in1 */
+ if( pIn1->flags & MEM_Int ){
+ sqlite3VdbeMemRealify(pIn1);
}
break;
}
#ifndef SQLITE_OMIT_CAST
-/* Opcode: ToText * * *
+/* Opcode: ToText P1 * * * *
**
-** Force the value on the top of the stack to be text.
+** Force the value in register P1 to be text.
** 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: { /* same as TK_TO_TEXT, no-push */
- assert( pTos>=p->aStack );
- if( pTos->flags & MEM_Null ) break;
+case OP_ToText: { /* same as TK_TO_TEXT, in1 */
+ if( pIn1->flags & MEM_Null ) break;
assert( MEM_Str==(MEM_Blob>>3) );
- pTos->flags |= (pTos->flags&MEM_Blob)>>3;
- applyAffinity(pTos, SQLITE_AFF_TEXT, encoding);
- assert( pTos->flags & MEM_Str );
- pTos->flags &= ~(MEM_Int|MEM_Real|MEM_Blob);
+ pIn1->flags |= (pIn1->flags&MEM_Blob)>>3;
+ applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding);
+ rc = ExpandBlob(pIn1);
+ assert( pIn1->flags & MEM_Str );
+ pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Blob);
+ UPDATE_MAX_BLOBSIZE(pIn1);
break;
}
-/* Opcode: ToBlob * * *
+/* Opcode: ToBlob P1 * * * *
**
-** Force the value on the top of the stack to be a BLOB.
+** Force the value in register P1 to be a BLOB.
** If the value is numeric, convert it to a string first.
** Strings are simply reinterpreted as blobs with no change
** to the underlying data.
**
** A NULL value is not changed by this routine. It remains NULL.
*/
-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, encoding);
- assert( pTos->flags & MEM_Str );
- pTos->flags |= MEM_Blob;
+case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */
+ if( pIn1->flags & MEM_Null ) break;
+ if( (pIn1->flags & MEM_Blob)==0 ){
+ applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding);
+ assert( pIn1->flags & MEM_Str );
+ pIn1->flags |= MEM_Blob;
}
- pTos->flags &= ~(MEM_Int|MEM_Real|MEM_Str);
+ pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Str);
+ UPDATE_MAX_BLOBSIZE(pIn1);
break;
}
-/* Opcode: ToNumeric * * *
+/* Opcode: ToNumeric P1 * * * *
**
-** Force the value on the top of the stack to be numeric (either an
+** Force the value in register P1 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
@@ -1446,175 +1448,169 @@ case OP_ToBlob: { /* same as TK_TO_BLOB, no-push */
**
** 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);
+case OP_ToNumeric: { /* same as TK_TO_NUMERIC, in1 */
+ if( (pIn1->flags & (MEM_Null|MEM_Int|MEM_Real))==0 ){
+ sqlite3VdbeMemNumerify(pIn1);
}
break;
}
#endif /* SQLITE_OMIT_CAST */
-/* Opcode: ToInt * * *
+/* Opcode: ToInt P1 * * * *
**
-** Force the value on the top of the stack to be an integer. If
+** Force the value in register P1 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);
+case OP_ToInt: { /* same as TK_TO_INT, in1 */
+ if( (pIn1->flags & MEM_Null)==0 ){
+ sqlite3VdbeMemIntegerify(pIn1);
}
break;
}
#ifndef SQLITE_OMIT_CAST
-/* Opcode: ToReal * * *
+/* Opcode: ToReal P1 * * * *
**
-** Force the value on the top of the stack to be a floating point number.
+** Force the value in register P1 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.
+** equivalent of atoi() and store 0.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);
+case OP_ToReal: { /* same as TK_TO_REAL, in1 */
+ if( (pIn1->flags & MEM_Null)==0 ){
+ sqlite3VdbeMemRealify(pIn1);
}
break;
}
#endif /* SQLITE_OMIT_CAST */
-/* Opcode: Eq P1 P2 P3
+/* Opcode: Lt P1 P2 P3 P4 P5
**
-** Pop the top two elements from the stack. If they are equal, then
-** jump to instruction P2. Otherwise, continue to the next instruction.
+** Compare the values in register P1 and P3. If reg(P3)<reg(P1) then
+** jump to address P2.
**
-** If the 0x100 bit of P1 is true and either operand is NULL then take the
-** jump. If the 0x100 bit of P1 is clear then fall thru if either operand
-** is NULL.
+** If the SQLITE_JUMPIFNULL bit of P5 is set and either reg(P1) or
+** reg(P3) is NULL then take the jump. If the SQLITE_JUMPIFNULL
+** bit is clear then fall thru if either operand is NULL.
**
-** If the 0x200 bit of P1 is set and either operand is NULL then
-** both operands are converted to integers prior to comparison.
-** NULL operands are converted to zero and non-NULL operands are
-** converted to 1. Thus, for example, with 0x200 set, NULL==NULL is true
-** whereas it would normally be NULL. Similarly, NULL==123 is false when
-** 0x200 is set but is NULL when the 0x200 bit of P1 is clear.
+** If the SQLITE_NULLEQUAL bit of P5 is set then treat NULL operands
+** as being equal to one another. Normally NULLs are not equal to
+** anything including other NULLs.
**
-** The least significant byte of P1 (mask 0xff) must be an affinity character -
+** The SQLITE_AFF_MASK portion of P5 must be an affinity character -
** 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.
+** to coerce both inputs according to this affinity before the
+** comparison is made. If the SQLITE_AFF_MASK is 0x00, then numeric
+** affinity is used. Note that the affinity conversions are stored
+** back into the input registers P1 and P3. So this opcode can cause
+** persistent changes to registers P1 and P3.
**
** Once any conversions have taken place, and neither value is NULL,
-** the values are compared. If both values are blobs, or both are text,
-** then memcmp() is used to determine the results of the comparison. If
-** both values are numeric, then a numeric comparison is used. If the
-** two values are of different types, then they are inequal.
-**
-** If P2 is zero, do not jump. Instead, push an integer 1 onto the
-** stack if the jump would have been taken, or a 0 if not. Push a
-** NULL if either operand was NULL.
-**
-** If P3 is not NULL it is a pointer to a collating sequence (a CollSeq
-** structure) that defines how to compare text.
-*/
-/* Opcode: Ne P1 P2 P3
-**
-** This works just like the Eq opcode except that the jump is taken if
-** the operands from the stack are not equal. See the Eq opcode for
+** the values are compared. If both values are blobs then memcmp() is
+** used to determine the results of the comparison. If both values
+** are text, then the appropriate collating function specified in
+** P4 is used to do the comparison. If P4 is not specified then
+** memcmp() is used to compare text string. If both values are
+** numeric, then a numeric comparison is used. If the two values
+** are of different types, then numbers are considered less than
+** strings and strings are considered less than blobs.
+**
+** If the SQLITE_STOREP2 bit of P5 is set, then do not jump. Instead,
+** store a boolean result (either 0, or 1, or NULL) in register P2.
+*/
+/* Opcode: Ne P1 P2 P3 P4 P5
+**
+** This works just like the Lt opcode except that the jump is taken if
+** the operands in registers P1 and P3 are not equal. See the Lt opcode for
** additional information.
*/
-/* Opcode: Lt P1 P2 P3
+/* Opcode: Eq P1 P2 P3 P4 P5
**
-** This works just like the Eq opcode except that the jump is taken if
-** the 2nd element down on the stack is less than the top of the stack.
-** See the Eq opcode for additional information.
+** This works just like the Lt opcode except that the jump is taken if
+** the operands in registers P1 and P3 are equal.
+** See the Lt opcode for additional information.
*/
-/* Opcode: Le P1 P2 P3
+/* Opcode: Le P1 P2 P3 P4 P5
**
-** This works just like the Eq opcode except that the jump is taken if
-** the 2nd element down on the stack is less than or equal to the
-** top of the stack. See the Eq opcode for additional information.
+** This works just like the Lt opcode except that the jump is taken if
+** the content of register P3 is less than or equal to the content of
+** register P1. See the Lt opcode for additional information.
*/
-/* Opcode: Gt P1 P2 P3
+/* Opcode: Gt P1 P2 P3 P4 P5
**
-** This works just like the Eq opcode except that the jump is taken if
-** the 2nd element down on the stack is greater than the top of the stack.
-** See the Eq opcode for additional information.
+** This works just like the Lt opcode except that the jump is taken if
+** the content of register P3 is greater than the content of
+** register P1. See the Lt opcode for additional information.
*/
-/* Opcode: Ge P1 P2 P3
+/* Opcode: Ge P1 P2 P3 P4 P5
**
-** This works just like the Eq opcode except that the jump is taken if
-** the 2nd element down on the stack is greater than or equal to the
-** top of the stack. See the Eq opcode for additional information.
+** This works just like the Lt opcode except that the jump is taken if
+** the content of register P3 is greater than or equal to the content of
+** register P1. See the Lt opcode for additional information.
*/
-case OP_Eq: /* same as TK_EQ, no-push */
-case OP_Ne: /* same as TK_NE, no-push */
-case OP_Lt: /* same as TK_LT, no-push */
-case OP_Le: /* same as TK_LE, no-push */
-case OP_Gt: /* same as TK_GT, no-push */
-case OP_Ge: { /* same as TK_GE, no-push */
- Mem *pNos;
+case OP_Eq: /* same as TK_EQ, jump, in1, in3 */
+case OP_Ne: /* same as TK_NE, jump, in1, in3 */
+case OP_Lt: /* same as TK_LT, jump, in1, in3 */
+case OP_Le: /* same as TK_LE, jump, in1, in3 */
+case OP_Gt: /* same as TK_GT, jump, in1, in3 */
+case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
int flags;
int res;
char affinity;
+ Mem x1, x3;
- pNos = &pTos[-1];
- flags = pTos->flags|pNos->flags;
+ flags = pIn1->flags|pIn3->flags;
- /* If either value is a NULL P2 is not zero, take the jump if the least
- ** significant byte of P1 is true. If P2 is zero, then push a NULL onto
- ** the stack.
- */
if( flags&MEM_Null ){
- if( (pOp->p1 & 0x200)!=0 ){
- /* The 0x200 bit of P1 means, roughly "do not treat NULL as the
- ** magic SQL value it normally is - treat it as if it were another
- ** integer".
- **
- ** With 0x200 set, if either operand is NULL then both operands
- ** are converted to integers prior to being passed down into the
- ** normal comparison logic below. NULL operands are converted to
- ** zero and non-NULL operands are converted to 1. Thus, for example,
- ** with 0x200 set, NULL==NULL is true whereas it would normally
- ** be NULL. Similarly, NULL!=123 is true.
+ if( (pOp->p5 & SQLITE_NULLEQUAL)!=0 ){
+ /*
+ ** When SQLITE_NULLEQUAL set and either operand is NULL
+ ** then both operands are converted to integers prior to being
+ ** passed down into the normal comparison logic below.
+ ** NULL operands are converted to zero and non-NULL operands
+ ** are converted to 1. Thus, for example, with SQLITE_NULLEQUAL
+ ** set, NULL==NULL is true whereas it would normally NULL.
+ ** Similarly, NULL!=123 is true.
*/
- sqlite3VdbeMemSetInt64(pTos, (pTos->flags & MEM_Null)==0);
- sqlite3VdbeMemSetInt64(pNos, (pNos->flags & MEM_Null)==0);
+ x1.flags = MEM_Int;
+ x1.u.i = (pIn1->flags & MEM_Null)==0;
+ pIn1 = &x1;
+ x3.flags = MEM_Int;
+ x3.u.i = (pIn3->flags & MEM_Null)==0;
+ pIn3 = &x3;
}else{
- /* If the 0x200 bit of P1 is clear and either operand is NULL then
- ** the result is always NULL. The jump is taken if the 0x100 bit
- ** of P1 is set.
+ /* If the SQLITE_NULLEQUAL bit is clear and either operand is NULL then
+ ** the result is always NULL. The jump is taken if the
+ ** SQLITE_JUMPIFNULL bit is set.
*/
- popStack(&pTos, 2);
- if( pOp->p2 ){
- if( pOp->p1 & 0x100 ){
- pc = pOp->p2-1;
- }
- }else{
- pTos++;
- pTos->flags = MEM_Null;
+ if( pOp->p5 & SQLITE_STOREP2 ){
+ pOut = &p->aMem[pOp->p2];
+ Release(pOut);
+ pOut->flags = MEM_Null;
+ REGISTER_TRACE(pOp->p2, pOut);
+ }else if( pOp->p5 & SQLITE_JUMPIFNULL ){
+ pc = pOp->p2-1;
}
break;
}
}
- affinity = pOp->p1 & 0xFF;
+ affinity = pOp->p5 & SQLITE_AFF_MASK;
if( affinity ){
- applyAffinity(pNos, affinity, encoding);
- applyAffinity(pTos, affinity, encoding);
+ applyAffinity(pIn1, affinity, encoding);
+ applyAffinity(pIn3, affinity, encoding);
}
- assert( pOp->p3type==P3_COLLSEQ || pOp->p3==0 );
- res = sqlite3MemCompare(pNos, pTos, (CollSeq*)pOp->p3);
+ assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 );
+ ExpandBlob(pIn1);
+ ExpandBlob(pIn3);
+ res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
switch( pOp->opcode ){
case OP_Eq: res = res==0; break;
case OP_Ne: res = res!=0; break;
@@ -1624,233 +1620,157 @@ case OP_Ge: { /* same as TK_GE, no-push */
default: res = res>=0; break;
}
- popStack(&pTos, 2);
- if( pOp->p2 ){
- if( res ){
- pc = pOp->p2-1;
- }
- }else{
- pTos++;
- pTos->flags = MEM_Int;
- pTos->i = res;
+ if( pOp->p5 & SQLITE_STOREP2 ){
+ pOut = &p->aMem[pOp->p2];
+ Release(pOut);
+ pOut->flags = MEM_Int;
+ pOut->u.i = res;
+ REGISTER_TRACE(pOp->p2, pOut);
+ }else if( res ){
+ pc = pOp->p2-1;
}
break;
}
-/* Opcode: And * * *
+/* Opcode: And P1 P2 P3 * *
+**
+** Take the logical AND of the values in registers P1 and P2 and
+** write the result into register P3.
**
-** Pop two values off the stack. Take the logical AND of the
-** two values and push the resulting boolean value back onto the
-** stack.
+** If either P1 or P2 is 0 (false) then the result is 0 even if
+** the other input is NULL. A NULL and true or two NULLs give
+** a NULL output.
*/
-/* Opcode: Or * * *
+/* Opcode: Or P1 P2 P3 * *
**
-** Pop two values off the stack. Take the logical OR of the
-** two values and push the resulting boolean value back onto the
-** stack.
+** Take the logical OR of the values in register P1 and P2 and
+** store the answer in register P3.
+**
+** If either P1 or P2 is nonzero (true) then the result is 1 (true)
+** even if the other input is NULL. A NULL and false or two NULLs
+** give a NULL output.
*/
-case OP_And: /* same as TK_AND, no-push */
-case OP_Or: { /* same as TK_OR, no-push */
- Mem *pNos = &pTos[-1];
- int v1, v2; /* 0==TRUE, 1==FALSE, 2==UNKNOWN or NULL */
+case OP_And: /* same as TK_AND, in1, in2, out3 */
+case OP_Or: { /* same as TK_OR, in1, in2, out3 */
+ int v1, v2; /* 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */
- assert( pNos>=p->aStack );
- if( pTos->flags & MEM_Null ){
+ if( pIn1->flags & MEM_Null ){
v1 = 2;
}else{
- sqlite3VdbeMemIntegerify(pTos);
- v1 = pTos->i==0;
+ v1 = sqlite3VdbeIntValue(pIn1)!=0;
}
- if( pNos->flags & MEM_Null ){
+ if( pIn2->flags & MEM_Null ){
v2 = 2;
}else{
- sqlite3VdbeMemIntegerify(pNos);
- v2 = pNos->i==0;
+ v2 = sqlite3VdbeIntValue(pIn2)!=0;
}
if( pOp->opcode==OP_And ){
- static const unsigned char and_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 };
+ static const unsigned char and_logic[] = { 0, 0, 0, 0, 1, 2, 0, 2, 2 };
v1 = and_logic[v1*3+v2];
}else{
- static const unsigned char or_logic[] = { 0, 0, 0, 0, 1, 2, 0, 2, 2 };
+ static const unsigned char or_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 };
v1 = or_logic[v1*3+v2];
}
- popStack(&pTos, 2);
- pTos++;
+ Release(pOut);
if( v1==2 ){
- pTos->flags = MEM_Null;
- }else{
- pTos->i = v1==0;
- pTos->flags = MEM_Int;
- }
- break;
-}
-
-/* Opcode: Negative * * *
-**
-** Treat the top of the stack as a numeric quantity. Replace it
-** with its additive inverse. If the top of the stack is NULL
-** its value is unchanged.
-*/
-/* Opcode: AbsValue * * *
-**
-** Treat the top of the stack as a numeric quantity. Replace it
-** with its absolute value. If the top of the stack is NULL
-** its value is unchanged.
-*/
-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;
- }
- pTos->flags = MEM_Real;
- }else if( pTos->flags & MEM_Int ){
- Release(pTos);
- if( pOp->opcode==OP_Negative || pTos->i<0 ){
- pTos->i = -pTos->i;
- }
- pTos->flags = MEM_Int;
- }else if( pTos->flags & MEM_Null ){
- /* Do nothing */
+ pOut->flags = MEM_Null;
}else{
- sqlite3VdbeMemNumerify(pTos);
- goto neg_abs_real_case;
+ pOut->u.i = v1;
+ pOut->flags = MEM_Int;
}
break;
}
-/* Opcode: Not * * *
+/* Opcode: Not P1 * * * *
**
-** Interpret the top of the stack as a boolean value. Replace it
-** with its complement. If the top of the stack is NULL its value
+** Interpret the value in register P1 as a boolean value. Replace it
+** with its complement. If the value in register P1 is NULL its value
** is unchanged.
*/
-case OP_Not: { /* same as TK_NOT, no-push */
- assert( pTos>=p->aStack );
- if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */
- sqlite3VdbeMemIntegerify(pTos);
- assert( (pTos->flags & MEM_Dyn)==0 );
- pTos->i = !pTos->i;
- pTos->flags = MEM_Int;
+case OP_Not: { /* same as TK_NOT, in1 */
+ if( pIn1->flags & MEM_Null ) break; /* Do nothing to NULLs */
+ sqlite3VdbeMemIntegerify(pIn1);
+ pIn1->u.i = !pIn1->u.i;
+ assert( pIn1->flags==MEM_Int );
break;
}
-/* Opcode: BitNot * * *
+/* Opcode: BitNot P1 * * * *
**
-** Interpret the top of the stack as an value. Replace it
-** with its ones-complement. If the top of the stack is NULL its
-** value is unchanged.
+** Interpret the content of register P1 as an integer. Replace it
+** with its ones-complement. If the value is originally NULL, leave
+** it unchanged.
*/
-case OP_BitNot: { /* same as TK_BITNOT, no-push */
- assert( pTos>=p->aStack );
- if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */
- sqlite3VdbeMemIntegerify(pTos);
- assert( (pTos->flags & MEM_Dyn)==0 );
- pTos->i = ~pTos->i;
- pTos->flags = MEM_Int;
+case OP_BitNot: { /* same as TK_BITNOT, in1 */
+ if( pIn1->flags & MEM_Null ) break; /* Do nothing to NULLs */
+ sqlite3VdbeMemIntegerify(pIn1);
+ pIn1->u.i = ~pIn1->u.i;
+ assert( pIn1->flags==MEM_Int );
break;
}
-/* Opcode: Noop * * *
+/* Opcode: If P1 P2 P3 * *
**
-** Do nothing. This instruction is often useful as a jump
-** destination.
+** Jump to P2 if the value in register P1 is true. The value is
+** is considered true if it is numeric and non-zero. If the value
+** in P1 is NULL then take the jump if P3 is true.
*/
-/*
-** The magic Explain opcode are only inserted when explain==2 (which
-** is to say when the EXPLAIN QUERY PLAN syntax is used.)
-** This opcode records information from the optimizer. It is the
-** the same as a no-op. This opcodesnever appears in a real VM program.
-*/
-case OP_Explain:
-case OP_Noop: { /* no-push */
- break;
-}
-
-/* Opcode: If P1 P2 *
-**
-** Pop a single boolean from the stack. If the boolean popped is
-** true, then jump to p2. Otherwise continue to the next instruction.
-** An integer is false if zero and true otherwise. A string is
-** false if it has zero length and true otherwise.
-**
-** If the value popped of the stack is NULL, then take the jump if P1
-** is true and fall through if P1 is false.
-*/
-/* Opcode: IfNot P1 P2 *
-**
-** Pop a single boolean from the stack. If the boolean popped is
-** false, then jump to p2. Otherwise continue to the next instruction.
-** An integer is false if zero and true otherwise. A string is
-** false if it has zero length and true otherwise.
+/* Opcode: IfNot P1 P2 P3 * *
**
-** If the value popped of the stack is NULL, then take the jump if P1
-** is true and fall through if P1 is false.
+** Jump to P2 if the value in register P1 is False. The value is
+** is considered true if it has a numeric value of zero. If the value
+** in P1 is NULL then take the jump if P3 is true.
*/
-case OP_If: /* no-push */
-case OP_IfNot: { /* no-push */
+case OP_If: /* jump, in1 */
+case OP_IfNot: { /* jump, in1 */
int c;
- assert( pTos>=p->aStack );
- if( pTos->flags & MEM_Null ){
- c = pOp->p1;
+ if( pIn1->flags & MEM_Null ){
+ c = pOp->p3;
}else{
#ifdef SQLITE_OMIT_FLOATING_POINT
- c = sqlite3VdbeIntValue(pTos);
+ c = sqlite3VdbeIntValue(pIn1);
#else
- c = sqlite3VdbeRealValue(pTos)!=0.0;
+ c = sqlite3VdbeRealValue(pIn1)!=0.0;
#endif
if( pOp->opcode==OP_IfNot ) c = !c;
}
- Release(pTos);
- pTos--;
- if( c ) pc = pOp->p2-1;
+ if( c ){
+ pc = pOp->p2-1;
+ }
break;
}
-/* Opcode: IsNull P1 P2 *
-**
-** If any of the top abs(P1) values on the stack are NULL, then jump
-** to P2. Pop the stack P1 times if P1>0. If P1<0 leave the stack
-** unchanged.
-*/
-case OP_IsNull: { /* same as TK_ISNULL, no-push */
- int i, cnt;
- Mem *pTerm;
- cnt = pOp->p1;
- if( cnt<0 ) cnt = -cnt;
- pTerm = &pTos[1-cnt];
- assert( pTerm>=p->aStack );
- for(i=0; i<cnt; i++, pTerm++){
- if( pTerm->flags & MEM_Null ){
- pc = pOp->p2-1;
+/* Opcode: IsNull P1 P2 P3 * *
+**
+** Jump to P2 if the value in register P1 is NULL. If P3 is greater
+** than zero, then check all values reg(P1), reg(P1+1),
+** reg(P1+2), ..., reg(P1+P3-1).
+*/
+case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
+ int n = pOp->p3;
+ assert( pOp->p3==0 || pOp->p1>0 );
+ do{
+ if( (pIn1->flags & MEM_Null)!=0 ){
+ pc = pOp->p2 - 1;
break;
}
- }
- if( pOp->p1>0 ) popStack(&pTos, cnt);
+ pIn1++;
+ }while( --n > 0 );
break;
}
-/* Opcode: NotNull P1 P2 *
+/* Opcode: NotNull P1 P2 * * *
**
-** Jump to P2 if the top P1 values on the stack are all not NULL. Pop the
-** stack if P1 times if P1 is greater than zero. If P1 is less than
-** zero then leave the stack unchanged.
+** Jump to P2 if the value in register P1 is not NULL.
*/
-case OP_NotNull: { /* same as TK_NOTNULL, no-push */
- int i, cnt;
- cnt = pOp->p1;
- if( cnt<0 ) cnt = -cnt;
- assert( &pTos[1-cnt] >= p->aStack );
- for(i=0; i<cnt && (pTos[1+i-cnt].flags & MEM_Null)==0; i++){}
- if( i>=cnt ) pc = pOp->p2-1;
- if( pOp->p1>0 ) popStack(&pTos, cnt);
+case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
+ if( (pIn1->flags & MEM_Null)==0 ){
+ pc = pOp->p2 - 1;
+ }
break;
}
-/* Opcode: SetNumColumns P1 P2 *
+/* Opcode: SetNumColumns P1 P2 * * *
**
** Before the OP_Column opcode can be executed on a cursor, this
** opcode must be called to set the number of fields in the table.
@@ -1860,7 +1780,7 @@ case OP_NotNull: { /* same as TK_NOTNULL, no-push */
** If OP_KeyAsData is to be applied to cursor P1, it must be executed
** before this op-code.
*/
-case OP_SetNumColumns: { /* no-push */
+case OP_SetNumColumns: {
Cursor *pC;
assert( (pOp->p1)<p->nCursor );
assert( p->apCsr[pOp->p1]!=0 );
@@ -1869,23 +1789,22 @@ case OP_SetNumColumns: { /* no-push */
break;
}
-/* Opcode: Column P1 P2 P3
+/* Opcode: Column P1 P2 P3 P4 *
**
** Interpret the data that cursor P1 points to as a structure built using
** the MakeRecord instruction. (See the MakeRecord opcode for additional
-** information about the format of the data.) Push onto the stack the value
-** of the P2-th column contained in the data. If there are less that (P2+1)
-** values in the record, push a NULL onto the stack.
+** information about the format of the data.) Extract the P2-th column
+** from this record. If there are less that (P2+1)
+** values in the record, extract a NULL.
+**
+** The value extracted is stored in register P3.
**
** If the KeyAsData opcode has previously executed on this cursor, then the
** field might be extracted from the key rather than the data.
**
-** 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
-** ADD COLUMN command. If P3 is an ordinary string, just push a NULL.
-** When P3 is a string it is really just a comment describing the value
-** to be pushed, not a default value.
+** If the column contains fewer than P2 fields, then extract a NULL. Or,
+** if the P4 argument is a P4_MEM use the value of the P4 argument as
+** the result.
*/
case OP_Column: {
u32 payloadSize; /* Number of bytes in the record */
@@ -1900,12 +1819,14 @@ case OP_Column: {
int len; /* The length of the serialized data for the column */
int i; /* Loop counter */
char *zData; /* Part of the record being decoded */
+ Mem *pDest; /* Where to write the extracted value */
Mem sMem; /* For storing the record being decoded */
sMem.flags = 0;
assert( p1<p->nCursor );
- pTos++;
- pTos->flags = MEM_Null;
+ assert( pOp->p3>0 && pOp->p3<=p->nMem );
+ pDest = &p->aMem[pOp->p3];
+ sqlite3VdbeMemSetNull(pDest);
/* This block sets the variable payloadSize to be the total number of
** bytes in the record.
@@ -1917,12 +1838,13 @@ case OP_Column: {
** 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.
+ ** the number of columns is stored in the Cursor.nField element.
*/
pC = p->apCsr[p1];
assert( pC!=0 );
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ assert( pC->pVtabCursor==0 );
+#endif
if( pC->pCursor!=0 ){
/* The record is stored in a B-Tree */
rc = sqlite3VdbeCursorMoveto(pC);
@@ -1942,7 +1864,8 @@ case OP_Column: {
sqlite3BtreeDataSize(pCrsr, &payloadSize);
}
nField = pC->nField;
- }else if( pC->pseudoTable ){
+ }else{
+ assert( pC->pseudoTable );
/* The record is the sole entry of a pseudo-table */
payloadSize = pC->nData;
zRec = pC->pData;
@@ -1950,17 +1873,15 @@ case OP_Column: {
assert( payloadSize==0 || zRec!=0 );
nField = pC->nField;
pCrsr = 0;
- }else{
- zRec = 0;
- payloadSize = 0;
- pCrsr = 0;
- nField = 0;
}
- /* If payloadSize is 0, then just push a NULL onto the stack. */
+ /* If payloadSize is 0, then just store a NULL */
if( payloadSize==0 ){
- assert( pTos->flags==MEM_Null );
- break;
+ assert( pDest->flags==MEM_Null );
+ goto op_column_out;
+ }
+ if( payloadSize>SQLITE_MAX_LENGTH ){
+ goto too_big;
}
assert( p2<nField );
@@ -1968,7 +1889,7 @@ 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->cacheStatus==p->cacheCtr ){
+ if( pC->cacheStatus==p->cacheCtr ){
aType = pC->aType;
aOffset = pC->aOffset;
}else{
@@ -1980,7 +1901,7 @@ case OP_Column: {
aType = pC->aType;
if( aType==0 ){
- pC->aType = aType = sqliteMallocRaw( 2*nField*sizeof(aType) );
+ pC->aType = aType = sqlite3DbMallocRaw(db, 2*nField*sizeof(aType) );
}
if( aType==0 ){
goto no_mem;
@@ -2010,7 +1931,9 @@ case OP_Column: {
pC->aRow = 0;
}
}
- assert( zRec!=0 || avail>=payloadSize || avail>=9 );
+ /* The following assert is true in all cases accept when
+ ** the database file has been corrupted externally.
+ ** assert( zRec!=0 || avail>=payloadSize || avail>=9 ); */
szHdrSz = GetVarint((u8*)zData, offset);
/* The KeyFetch() or DataFetch() above are fast and will get the entire
@@ -2043,8 +1966,8 @@ case OP_Column: {
/* 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.
+ ** the record to 0. This tells code below to store a NULL
+ ** instead of deserializing a value from the record.
*/
aOffset[i] = 0;
}
@@ -2065,7 +1988,7 @@ case OP_Column: {
/* Get the column information. If aOffset[p2] is non-zero, then
** deserialize the value from the record. If aOffset[p2] is zero,
** then there are not enough fields in the record to satisfy the
- ** request. In this case, set the value NULL or to P3 if P3 is
+ ** request. In this case, set the value NULL or to P4 if P4 is
** a pointer to a Mem object.
*/
if( aOffset[p2] ){
@@ -2074,47 +1997,49 @@ case OP_Column: {
zData = &zRec[aOffset[p2]];
}else{
len = sqlite3VdbeSerialTypeLen(aType[p2]);
- rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex,&sMem);
+ rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex, &sMem);
if( rc!=SQLITE_OK ){
goto op_column_out;
}
zData = sMem.z;
}
- sqlite3VdbeSerialGet((u8*)zData, aType[p2], pTos);
- pTos->enc = encoding;
+ sqlite3VdbeSerialGet((u8*)zData, aType[p2], pDest);
+ pDest->enc = encoding;
}else{
- if( pOp->p3type==P3_MEM ){
- sqlite3VdbeMemShallowCopy(pTos, (Mem *)(pOp->p3), MEM_Static);
+ if( pOp->p4type==P4_MEM ){
+ sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static);
}else{
- pTos->flags = MEM_Null;
+ assert( pDest->flags==MEM_Null );
}
}
/* 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.
+ ** dynamically allocated space over to the pDest structure.
** This prevents a memory copy.
*/
if( (sMem.flags & MEM_Dyn)!=0 ){
- assert( pTos->flags & MEM_Ephem );
- assert( pTos->flags & (MEM_Str|MEM_Blob) );
- assert( pTos->z==sMem.z );
+ assert( pDest->flags & MEM_Ephem );
+ assert( pDest->flags & (MEM_Str|MEM_Blob) );
+ assert( pDest->z==sMem.z );
assert( sMem.flags & MEM_Term );
- pTos->flags &= ~MEM_Ephem;
- pTos->flags |= MEM_Dyn|MEM_Term;
+ pDest->flags &= ~MEM_Ephem;
+ pDest->flags |= MEM_Dyn|MEM_Term;
}
- /* pTos->z might be pointing to sMem.zShort[]. Fix that so that we
+ /* pDest->z might be pointing to sMem.zShort[]. Fix that so that we
** can abandon sMem */
- rc = sqlite3VdbeMemMakeWriteable(pTos);
+ rc = sqlite3VdbeMemMakeWriteable(pDest);
op_column_out:
+ UPDATE_MAX_BLOBSIZE(pDest);
+ REGISTER_TRACE(pOp->p3, pDest);
break;
}
-/* Opcode: MakeRecord P1 P2 P3
+/* Opcode: MakeRecord P1 P2 P3 P4 *
**
-** Convert the top abs(P1) entries of the stack into a single entry
+** Convert P2 registers beginning with P1 into a single entry
** suitable for use as a data record in a database table or as a key
** in an index. The details of the format are irrelavant as long as
** the OP_Column opcode can decode the record later and as long as the
@@ -2122,33 +2047,15 @@ op_column_out:
** records. Refer to source code comments for the details of the record
** format.
**
-** The original stack entries are popped from the stack if P1>0 but
-** remain on the stack if P1<0.
-**
-** If P2 is not zero and one or more of the entries are NULL, then jump
-** to the address given by P2. This feature can be used to skip a
-** uniqueness test on indices.
-**
-** P3 may be a string that is P1 characters long. The nth character of the
+** P4 may be a string that is P1 characters long. The nth character of the
** string indicates the column affinity that should be used for the nth
-** field of the index key (i.e. the first character of P3 corresponds to the
-** lowest element on the stack).
+** field of the index key.
**
** 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: 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)
-** and appends that extra integer to the end of the record as a varint.
-** This results in an index key.
+** If P4 is NULL then all index fields have the affinity NONE.
*/
-case OP_MakeIdxRec:
case OP_MakeRecord: {
/* Assuming the record contains N fields, the record format looks
** like this:
@@ -2157,71 +2064,60 @@ case OP_MakeRecord: {
** | hdr-size | type 0 | type 1 | ... | type N-1 | data0 | ... | data N-1 |
** ------------------------------------------------------------------------
**
- ** Data(0) is taken from the lowest element of the stack and data(N-1) is
- ** the top of the stack.
+ ** Data(0) is taken from register P1. Data(1) comes from register P1+1
+ ** and so froth.
**
** Each type field is a varint representing the serial type of the
** corresponding data element (see sqlite3VdbeSerialType()). The
** hdr-size field is also a varint which is the offset from the beginning
** of the record to data0.
*/
- unsigned char *zNewRecord;
- unsigned char *zCsr;
- Mem *pRec;
- Mem *pRowid = 0;
- int nData = 0; /* Number of bytes of data space */
+ u8 *zNewRecord; /* A buffer to hold the data for the new record */
+ Mem *pRec; /* The new record */
+ u64 nData = 0; /* Number of bytes of data space */
int nHdr = 0; /* Number of bytes of header space */
- int nByte = 0; /* Space required for this record */
+ u64 nByte = 0; /* Data space required for this record */
+ int nZero = 0; /* Number of zero bytes at the end of the record */
int nVarint; /* Number of bytes in a varint */
u32 serial_type; /* Type field */
- int containsNull = 0; /* True if any of the data fields are NULL */
- char zTemp[NBFS]; /* Space to hold small records */
- Mem *pData0;
-
- int leaveOnStack; /* If true, leave the entries on the stack */
+ Mem *pData0; /* First field to be combined into the record */
+ Mem *pLast; /* Last field of the record */
int nField; /* Number of fields in the record */
- 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 */
+ int i; /* Space used in zNewRecord[] */
+ char zTemp[NBFS]; /* Space to hold small records */
- leaveOnStack = ((pOp->p1<0)?1:0);
- nField = pOp->p1 * (leaveOnStack?-1:1);
- jumpIfNull = pOp->p2;
- addRowid = pOp->opcode==OP_MakeIdxRec;
- zAffinity = pOp->p3;
-
- pData0 = &pTos[1-nField];
- assert( pData0>=p->aStack );
- containsNull = 0;
+ nField = pOp->p1;
+ zAffinity = pOp->p4.z;
+ assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem );
+ pData0 = &p->aMem[nField];
+ nField = pOp->p2;
+ pLast = &pData0[nField-1];
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++){
+ for(pRec=pData0; pRec<=pLast; pRec++){
+ int len;
if( zAffinity ){
applyAffinity(pRec, zAffinity[pRec-pData0], encoding);
}
- if( pRec->flags&MEM_Null ){
- containsNull = 1;
+ if( pRec->flags&MEM_Zero && pRec->n>0 ){
+ sqlite3VdbeMemExpandBlob(pRec);
}
serial_type = sqlite3VdbeSerialType(pRec, file_format);
- nData += sqlite3VdbeSerialTypeLen(serial_type);
- nHdr += sqlite3VarintLen(serial_type);
- }
-
- /* If we have to append a varint rowid to this record, set 'rowid'
- ** to the value of the rowid and increase nByte by the amount of space
- ** required to store it and the 0x00 seperator byte.
- */
- if( addRowid ){
- pRowid = &pTos[0-nField];
- assert( pRowid>=p->aStack );
- sqlite3VdbeMemIntegerify(pRowid);
- serial_type = sqlite3VdbeSerialType(pRowid, 0);
- nData += sqlite3VdbeSerialTypeLen(serial_type);
+ len = sqlite3VdbeSerialTypeLen(serial_type);
+ nData += len;
nHdr += sqlite3VarintLen(serial_type);
+ if( pRec->flags & MEM_Zero ){
+ /* Only pure zero-filled BLOBs can be input to this Opcode.
+ ** We do not allow blobs with a prefix and a zero-filled tail. */
+ nZero += pRec->u.i;
+ }else if( len ){
+ nZero = 0;
+ }
}
/* Add the initial header varint and total the size */
@@ -2229,11 +2125,14 @@ case OP_MakeRecord: {
if( nVarint<sqlite3VarintLen(nHdr) ){
nHdr++;
}
- nByte = nHdr+nData;
+ nByte = nHdr+nData-nZero;
+ if( nByte>SQLITE_MAX_LENGTH ){
+ goto too_big;
+ }
/* Allocate space for the new record. */
if( nByte>sizeof(zTemp) ){
- zNewRecord = sqliteMallocRaw(nByte);
+ zNewRecord = sqlite3DbMallocRaw(db, nByte);
if( !zNewRecord ){
goto no_mem;
}
@@ -2242,50 +2141,42 @@ case OP_MakeRecord: {
}
/* Write the record */
- zCsr = zNewRecord;
- zCsr += sqlite3PutVarint(zCsr, nHdr);
- for(pRec=pData0; pRec<=pTos; pRec++){
+ i = sqlite3PutVarint(zNewRecord, nHdr);
+ for(pRec=pData0; pRec<=pLast; pRec++){
serial_type = sqlite3VdbeSerialType(pRec, file_format);
- zCsr += sqlite3PutVarint(zCsr, serial_type); /* serial type */
- }
- if( addRowid ){
- zCsr += sqlite3PutVarint(zCsr, sqlite3VdbeSerialType(pRowid, 0));
+ i += sqlite3PutVarint(&zNewRecord[i], serial_type); /* serial type */
}
- for(pRec=pData0; pRec<=pTos; pRec++){
- zCsr += sqlite3VdbeSerialPut(zCsr, pRec, file_format); /* serial data */
+ for(pRec=pData0; pRec<=pLast; pRec++){ /* serial data */
+ i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRec, file_format);
}
- if( addRowid ){
- zCsr += sqlite3VdbeSerialPut(zCsr, pRowid, 0);
- }
- assert( zCsr==(zNewRecord+nByte) );
+ assert( i==nByte );
- /* Pop entries off the stack if required. Push the new record on. */
- if( !leaveOnStack ){
- popStack(&pTos, nField+addRowid);
- }
- pTos++;
- pTos->n = nByte;
+ assert( pOp->p3>0 && pOp->p3<=p->nMem );
+ pOut = &p->aMem[pOp->p3];
+ Release(pOut);
+ pOut->n = nByte;
if( nByte<=sizeof(zTemp) ){
assert( zNewRecord==(unsigned char *)zTemp );
- pTos->z = pTos->zShort;
- memcpy(pTos->zShort, zTemp, nByte);
- pTos->flags = MEM_Blob | MEM_Short;
+ pOut->z = pOut->zShort;
+ memcpy(pOut->zShort, zTemp, nByte);
+ pOut->flags = MEM_Blob | MEM_Short;
}else{
assert( zNewRecord!=(unsigned char *)zTemp );
- pTos->z = (char*)zNewRecord;
- pTos->flags = MEM_Blob | MEM_Dyn;
- pTos->xDel = 0;
+ pOut->z = (char*)zNewRecord;
+ pOut->flags = MEM_Blob | MEM_Dyn;
+ pOut->xDel = 0;
}
- pTos->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */
-
- /* If a NULL was encountered and jumpIfNull is non-zero, take the jump. */
- if( jumpIfNull && containsNull ){
- pc = jumpIfNull - 1;
+ if( nZero ){
+ pOut->u.i = nZero;
+ pOut->flags |= MEM_Zero;
}
+ pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */
+ REGISTER_TRACE(pOp->p3, pOut);
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
-/* Opcode: Statement P1 * *
+/* Opcode: Statement P1 * * * *
**
** Begin an individual statement transaction which is part of a larger
** BEGIN..COMMIT transaction. This is needed so that the statement
@@ -2297,19 +2188,24 @@ case OP_MakeRecord: {
** database file has an index of 0 and the file used for temporary tables
** has an index of 1.
*/
-case OP_Statement: { /* no-push */
- int i = pOp->p1;
- Btree *pBt;
- if( i>=0 && i<db->nDb && (pBt = db->aDb[i].pBt)!=0 && !(db->autoCommit) ){
+case OP_Statement: {
+ if( db->autoCommit==0 || db->activeVdbeCnt>1 ){
+ int i = pOp->p1;
+ Btree *pBt;
+ assert( i>=0 && i<db->nDb );
+ assert( db->aDb[i].pBt!=0 );
+ pBt = db->aDb[i].pBt;
assert( sqlite3BtreeIsInTrans(pBt) );
+ assert( (p->btreeMask & (1<<i))!=0 );
if( !sqlite3BtreeIsInStmt(pBt) ){
rc = sqlite3BtreeBeginStmt(pBt);
+ p->openedStatement = 1;
}
}
break;
}
-/* Opcode: AutoCommit P1 P2 *
+/* Opcode: AutoCommit P1 P2 * * *
**
** Set the database auto-commit flag to P1 (1 or 0). If P2 is true, roll
** back any currently active btree transactions. If there are any active
@@ -2317,7 +2213,7 @@ case OP_Statement: { /* no-push */
**
** This instruction causes the VM to halt.
*/
-case OP_AutoCommit: { /* no-push */
+case OP_AutoCommit: {
u8 i = pOp->p1;
u8 rollback = pOp->p2;
@@ -2342,14 +2238,18 @@ case OP_AutoCommit: { /* no-push */
}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;
+ p->rc = rc = SQLITE_BUSY;
+ goto vdbe_return;
}
}
- return SQLITE_DONE;
+ if( p->rc==SQLITE_OK ){
+ rc = SQLITE_DONE;
+ }else{
+ rc = SQLITE_ERROR;
+ }
+ goto vdbe_return;
}else{
sqlite3SetString(&p->zErrMsg,
(!i)?"cannot start a transaction within a transaction":(
@@ -2361,7 +2261,7 @@ case OP_AutoCommit: { /* no-push */
break;
}
-/* Opcode: Transaction P1 P2 *
+/* Opcode: Transaction P1 P2 * * *
**
** Begin a transaction. The transaction ends when a Commit or Rollback
** opcode is encountered. Depending on the ON CONFLICT setting, the
@@ -2369,7 +2269,8 @@ case OP_AutoCommit: { /* no-push */
**
** P1 is the index of the database file on which the transaction is
** started. Index 0 is the main database file and index 1 is the
-** file used for temporary tables.
+** file used for temporary tables. Indices of 2 or more are used for
+** attached databases.
**
** If P2 is non-zero, then a write-transaction is started. A RESERVED lock is
** obtained on the database file when a write-transaction is started. No
@@ -2381,20 +2282,20 @@ case OP_AutoCommit: { /* no-push */
**
** If P2 is zero, then a read-lock is obtained on the database file.
*/
-case OP_Transaction: { /* no-push */
+case OP_Transaction: {
int i = pOp->p1;
Btree *pBt;
assert( i>=0 && i<db->nDb );
+ assert( (p->btreeMask & (1<<i))!=0 );
pBt = db->aDb[i].pBt;
if( pBt ){
rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
if( rc==SQLITE_BUSY ){
p->pc = pc;
- p->rc = SQLITE_BUSY;
- p->pTos = pTos;
- return SQLITE_BUSY;
+ p->rc = rc = SQLITE_BUSY;
+ goto vdbe_return;
}
if( rc!=SQLITE_OK && rc!=SQLITE_READONLY /* && rc!=SQLITE_BUSY */ ){
goto abort_due_to_error;
@@ -2403,23 +2304,36 @@ case OP_Transaction: { /* no-push */
break;
}
-/* Opcode: ReadCookie P1 P2 *
+/* Opcode: ReadCookie P1 P2 P3 * *
**
-** Read cookie number P2 from database P1 and push it onto the stack.
-** P2==0 is the schema version. P2==1 is the database format.
-** P2==2 is the recommended pager cache size, and so forth. P1==0 is
+** Read cookie number P3 from database P1 and write it into register P2.
+** P3==0 is the schema version. P3==1 is the database format.
+** P3==2 is the recommended pager cache size, and so forth. P1==0 is
** the main database file and P1==1 is the database file used to store
** temporary tables.
**
+** If P1 is negative, then this is a request to read the size of a
+** databases free-list. P3 must be set to 1 in this case. The actual
+** database accessed is ((P1+1)*-1). For example, a P1 parameter of -1
+** corresponds to database 0 ("main"), a P1 of -2 is database 1 ("temp").
+**
** There must be a read-lock on the database (either a transaction
** must be started or there must be an open cursor) before
** executing this instruction.
*/
-case OP_ReadCookie: {
+case OP_ReadCookie: { /* out2-prerelease */
int iMeta;
- assert( pOp->p2<SQLITE_N_BTREE_META );
- assert( pOp->p1>=0 && pOp->p1<db->nDb );
- assert( db->aDb[pOp->p1].pBt!=0 );
+ int iDb = pOp->p1;
+ int iCookie = pOp->p3;
+
+ assert( pOp->p3<SQLITE_N_BTREE_META );
+ if( iDb<0 ){
+ iDb = (-1*(iDb+1));
+ iCookie *= -1;
+ }
+ assert( iDb>=0 && iDb<db->nDb );
+ assert( db->aDb[iDb].pBt!=0 );
+ assert( (p->btreeMask & (1<<iDb))!=0 );
/* The indexing of meta values at the schema layer is off by one from
** the indexing in the btree layer. The btree considers meta[0] to
** be the number of free pages in the database (a read-only value)
@@ -2427,16 +2341,16 @@ case OP_ReadCookie: {
** meta[1] to be the schema cookie. So we have to shift the index
** by one in the following statement.
*/
- rc = sqlite3BtreeGetMeta(db->aDb[pOp->p1].pBt, 1 + pOp->p2, (u32 *)&iMeta);
- pTos++;
- pTos->i = iMeta;
- pTos->flags = MEM_Int;
+ rc = sqlite3BtreeGetMeta(db->aDb[iDb].pBt, 1 + iCookie, (u32 *)&iMeta);
+ pOut->u.i = iMeta;
+ pOut->flags = MEM_Int;
break;
}
-/* Opcode: SetCookie P1 P2 *
+/* Opcode: SetCookie P1 P2 P3 * *
**
-** Write the top of the stack into cookie number P2 of database P1.
+** Write the content of register P3 (interpreted as an integer)
+** into cookie number P2 of database P1.
** P2==0 is the schema version. P2==1 is the database format.
** P2==2 is the recommended pager cache size, and so forth. P1==0 is
** the main database file and P1==1 is the database file used to store
@@ -2444,26 +2358,24 @@ case OP_ReadCookie: {
**
** A transaction must be started before executing this opcode.
*/
-case OP_SetCookie: { /* no-push */
+case OP_SetCookie: { /* in3 */
Db *pDb;
assert( pOp->p2<SQLITE_N_BTREE_META );
assert( pOp->p1>=0 && pOp->p1<db->nDb );
+ assert( (p->btreeMask & (1<<pOp->p1))!=0 );
pDb = &db->aDb[pOp->p1];
assert( pDb->pBt!=0 );
- assert( pTos>=p->aStack );
- sqlite3VdbeMemIntegerify(pTos);
+ sqlite3VdbeMemIntegerify(pIn3);
/* See note about index shifting on OP_ReadCookie */
- rc = sqlite3BtreeUpdateMeta(pDb->pBt, 1+pOp->p2, (int)pTos->i);
+ rc = sqlite3BtreeUpdateMeta(pDb->pBt, 1+pOp->p2, (int)pIn3->u.i);
if( pOp->p2==0 ){
/* When the schema cookie changes, record the new cookie internally */
- pDb->pSchema->schema_cookie = pTos->i;
+ pDb->pSchema->schema_cookie = pIn3->u.i;
db->flags |= SQLITE_InternChanges;
}else if( pOp->p2==1 ){
/* Record changes in the file format */
- pDb->pSchema->file_format = pTos->i;
+ pDb->pSchema->file_format = pIn3->u.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 */
@@ -2488,10 +2400,11 @@ case OP_SetCookie: { /* no-push */
** to be executed (to establish a read lock) before this opcode is
** invoked.
*/
-case OP_VerifyCookie: { /* no-push */
+case OP_VerifyCookie: {
int iMeta;
Btree *pBt;
assert( pOp->p1>=0 && pOp->p1<db->nDb );
+ assert( (p->btreeMask & (1<<pOp->p1))!=0 );
pBt = db->aDb[pOp->p1].pBt;
if( pBt ){
rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&iMeta);
@@ -2500,23 +2413,43 @@ case OP_VerifyCookie: { /* no-push */
iMeta = 0;
}
if( rc==SQLITE_OK && iMeta!=pOp->p2 ){
- sqlite3SetString(&p->zErrMsg, "database schema has changed", (char*)0);
+ sqlite3_free(p->zErrMsg);
+ p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
+ /* If the schema-cookie from the database file matches the cookie
+ ** stored with the in-memory representation of the schema, do
+ ** not reload the schema from the database file.
+ **
+ ** If virtual-tables are in use, this is not just an optimisation.
+ ** Often, v-tables store their data in other SQLite tables, which
+ ** are queried from within xNext() and other v-table methods using
+ ** prepared queries. If such a query is out-of-date, we do not want to
+ ** discard the database schema, as the user code implementing the
+ ** v-table would have to be ready for the sqlite3_vtab structure itself
+ ** to be invalidated whenever sqlite3_step() is called from within
+ ** a v-table method.
+ */
+ if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){
+ sqlite3ResetInternalSchema(db, pOp->p1);
+ }
+
+ sqlite3ExpirePreparedStatements(db);
rc = SQLITE_SCHEMA;
}
break;
}
-/* Opcode: OpenRead P1 P2 P3
+/* Opcode: OpenRead P1 P2 P3 P4 P5
**
** Open a read-only cursor for the database table whose root page is
-** P2 in a database file. The database file is determined by an
-** integer from the top of the stack. 0 means the main database and
-** 1 means the database used for temporary tables. Give the new
-** cursor an identifier of P1. The P1 values need not be contiguous
-** but all P1 values should be small integers. It is an error for
-** P1 to be negative.
+** P2 in a database file. The database file is determined by P3.
+** P3==0 means the main database, P3==1 means the database used for
+** temporary tables, and P3>1 means used the corresponding attached
+** database. Give the new cursor an identifier of P1. The P1
+** values need not be contiguous but all P1 values should be small integers.
+** It is an error for P1 to be negative.
**
-** If P2==0 then take the root page number from the next of the stack.
+** If P5!=0 then use the content of register P2 as the root page, not
+** the value of P2 itself.
**
** There will be a read lock on the database whenever there is an
** open cursor. If the database was unlocked prior to this instruction
@@ -2527,19 +2460,20 @@ case OP_VerifyCookie: { /* no-push */
** to get a read lock but fails, the script terminates with an
** SQLITE_BUSY error code.
**
-** The P3 value is a pointer to a KeyInfo structure that defines the
-** content and collating sequence of indices. P3 is NULL for cursors
+** The P4 value is a pointer to a KeyInfo structure that defines the
+** content and collating sequence of indices. P4 is NULL for cursors
** that are not pointing to indices.
**
** See also OpenWrite.
*/
-/* Opcode: OpenWrite P1 P2 P3
+/* Opcode: OpenWrite P1 P2 P3 P4 P5
**
** Open a read/write cursor named P1 on the table or index whose root
-** page is P2. If P2==0 then take the root page number from the stack.
+** page is P2. Or if P5!=0 use the content of register P2 to find the
+** root page.
**
-** The P3 value is a pointer to a KeyInfo structure that defines the
-** content and collating sequence of indices. P3 is NULL for cursors
+** The P4 value is a pointer to a KeyInfo structure that defines the
+** content and collating sequence of indices. P4 is NULL for cursors
** that are not pointing to indices.
**
** This instruction works just like OpenRead except that it opens the cursor
@@ -2548,22 +2482,18 @@ case OP_VerifyCookie: { /* no-push */
**
** See also OpenRead.
*/
-case OP_OpenRead: /* no-push */
-case OP_OpenWrite: { /* no-push */
+case OP_OpenRead:
+case OP_OpenWrite: {
int i = pOp->p1;
int p2 = pOp->p2;
+ int iDb = pOp->p3;
int wrFlag;
Btree *pX;
- int iDb;
Cursor *pCur;
Db *pDb;
- assert( pTos>=p->aStack );
- sqlite3VdbeMemIntegerify(pTos);
- iDb = pTos->i;
- assert( (pTos->flags & MEM_Dyn)==0 );
- pTos--;
assert( iDb>=0 && iDb<db->nDb );
+ assert( (p->btreeMask & (1<<iDb))!=0 );
pDb = &db->aDb[iDb];
pX = pDb->pBt;
assert( pX!=0 );
@@ -2575,26 +2505,25 @@ case OP_OpenWrite: { /* no-push */
}else{
wrFlag = 0;
}
- if( p2<=0 ){
- assert( pTos>=p->aStack );
- sqlite3VdbeMemIntegerify(pTos);
- p2 = pTos->i;
- assert( (pTos->flags & MEM_Dyn)==0 );
- pTos--;
+ if( pOp->p5 ){
+ assert( p2>0 );
+ assert( p2<=p->nMem );
+ pIn2 = &p->aMem[p2];
+ sqlite3VdbeMemIntegerify(pIn2);
+ p2 = pIn2->u.i;
assert( p2>=2 );
}
assert( i>=0 );
pCur = allocateCursor(p, i, iDb);
if( pCur==0 ) goto no_mem;
pCur->nullRow = 1;
- if( pX==0 ) break;
/* We always provide a key comparison function. If the table being
** opened is of type INTKEY, the comparision function will be ignored. */
rc = sqlite3BtreeCursor(pX, p2, wrFlag,
- sqlite3VdbeRecordCompare, pOp->p3,
+ sqlite3VdbeRecordCompare, pOp->p4.p,
&pCur->pCursor);
- if( pOp->p3type==P3_KEYINFO ){
- pCur->pKeyInfo = (KeyInfo*)pOp->p3;
+ if( pOp->p4type==P4_KEYINFO ){
+ pCur->pKeyInfo = pOp->p4.pKeyInfo;
pCur->pIncrKey = &pCur->pKeyInfo->incrKey;
pCur->pKeyInfo->enc = ENC(p->db);
}else{
@@ -2604,9 +2533,8 @@ case OP_OpenWrite: { /* no-push */
switch( rc ){
case SQLITE_BUSY: {
p->pc = pc;
- p->rc = SQLITE_BUSY;
- p->pTos = &pTos[1 + (pOp->p2<=0)]; /* Operands must remain on stack */
- return SQLITE_BUSY;
+ p->rc = rc = SQLITE_BUSY;
+ goto vdbe_return;
}
case SQLITE_OK: {
int flags = sqlite3BtreeFlags(pCur->pCursor);
@@ -2622,19 +2550,19 @@ case OP_OpenWrite: { /* no-push */
}
pCur->isTable = (flags & BTREE_INTKEY)!=0;
pCur->isIndex = (flags & BTREE_ZERODATA)!=0;
- /* If P3==0 it means we are expected to open a table. If P3!=0 then
+ /* If P4==0 it means we are expected to open a table. If P4!=0 then
** we expect to be opening an index. If this is not what happened,
** then the database is corrupt
*/
- if( (pCur->isTable && pOp->p3type==P3_KEYINFO)
- || (pCur->isIndex && pOp->p3type!=P3_KEYINFO) ){
+ if( (pCur->isTable && pOp->p4type==P4_KEYINFO)
+ || (pCur->isIndex && pOp->p4type!=P4_KEYINFO) ){
rc = SQLITE_CORRUPT_BKPT;
goto abort_due_to_error;
}
break;
}
case SQLITE_EMPTY: {
- pCur->isTable = pOp->p3type!=P3_KEYINFO;
+ pCur->isTable = pOp->p4type!=P4_KEYINFO;
pCur->isIndex = !pCur->isTable;
rc = SQLITE_OK;
break;
@@ -2646,7 +2574,7 @@ case OP_OpenWrite: { /* no-push */
break;
}
-/* Opcode: OpenEphemeral P1 P2 P3
+/* Opcode: OpenEphemeral P1 P2 * P4 *
**
** Open a new cursor P1 to a transient table.
** The cursor is always opened read/write even if
@@ -2654,8 +2582,8 @@ case OP_OpenWrite: { /* no-push */
** table is deleted automatically when the cursor is closed.
**
** P2 is the number of columns in the virtual table.
-** 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
+** The cursor points to a BTree table if P4==0 and to a BTree index
+** if P4 is not 0. If P4 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
@@ -2664,14 +2592,22 @@ case OP_OpenWrite: { /* no-push */
** this opcode. Then this opcode was call OpenVirtual. But
** that created confusion with the whole virtual-table idea.
*/
-case OP_OpenEphemeral: { /* no-push */
+case OP_OpenEphemeral: {
int i = pOp->p1;
Cursor *pCx;
+ static const int openFlags =
+ SQLITE_OPEN_READWRITE |
+ SQLITE_OPEN_CREATE |
+ SQLITE_OPEN_EXCLUSIVE |
+ SQLITE_OPEN_DELETEONCLOSE |
+ SQLITE_OPEN_TRANSIENT_DB;
+
assert( i>=0 );
pCx = allocateCursor(p, i, -1);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
- rc = sqlite3BtreeFactory(db, 0, 1, TEMP_PAGES, &pCx->pBt);
+ rc = sqlite3BtreeFactory(db, 0, 1, SQLITE_DEFAULT_TEMP_CACHE_SIZE, openFlags,
+ &pCx->pBt);
if( rc==SQLITE_OK ){
rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
}
@@ -2681,15 +2617,15 @@ case OP_OpenEphemeral: { /* no-push */
** opening it. If a transient table is required, just use the
** automatically created table with root-page 1 (an INTKEY table).
*/
- if( pOp->p3 ){
+ if( pOp->p4.pKeyInfo ){
int pgno;
- assert( pOp->p3type==P3_KEYINFO );
+ assert( pOp->p4type==P4_KEYINFO );
rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_ZERODATA);
if( rc==SQLITE_OK ){
assert( pgno==MASTER_ROOT+1 );
rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, sqlite3VdbeRecordCompare,
- pOp->p3, &pCx->pCursor);
- pCx->pKeyInfo = (KeyInfo*)pOp->p3;
+ pOp->p4.z, &pCx->pCursor);
+ pCx->pKeyInfo = pOp->p4.pKeyInfo;
pCx->pKeyInfo->enc = ENC(p->db);
pCx->pIncrKey = &pCx->pKeyInfo->incrKey;
}
@@ -2705,7 +2641,7 @@ case OP_OpenEphemeral: { /* no-push */
break;
}
-/* Opcode: OpenPseudo P1 * *
+/* Opcode: OpenPseudo P1 * * * *
**
** Open a new cursor that points to a fake table that contains a single
** row of data. Any attempt to write a second row of data causes the
@@ -2717,7 +2653,7 @@ case OP_OpenEphemeral: { /* no-push */
** 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 */
+case OP_OpenPseudo: {
int i = pOp->p1;
Cursor *pCx;
assert( i>=0 );
@@ -2731,68 +2667,73 @@ case OP_OpenPseudo: { /* no-push */
break;
}
-/* Opcode: Close P1 * *
+/* Opcode: Close P1 * * * *
**
** Close a cursor previously opened as P1. If P1 is not
** currently open, this instruction is a no-op.
*/
-case OP_Close: { /* no-push */
+case OP_Close: {
int i = pOp->p1;
- if( i>=0 && i<p->nCursor ){
- sqlite3VdbeFreeCursor(p, p->apCsr[i]);
- p->apCsr[i] = 0;
- }
+ assert( i>=0 && i<p->nCursor );
+ sqlite3VdbeFreeCursor(p, p->apCsr[i]);
+ p->apCsr[i] = 0;
break;
}
-/* Opcode: MoveGe P1 P2 *
+/* Opcode: MoveGe P1 P2 P3 * *
**
-** Pop the top of the stack and use its value as a key. Reposition
+** Use the value in register P3 as a key. Reposition
** cursor P1 so that it points to the smallest entry that is greater
-** than or equal to the key that was popped ffrom the stack.
+** than or equal to the key in register P3.
** If there are no records greater than or equal to the key and P2
** is not zero, then jump to P2.
**
+** A special feature of this opcode (and different from the
+** related OP_MoveGt, OP_MoveLt, and OP_MoveLe) is that if P2 is
+** zero and P1 is an SQL table (a b-tree with integer keys) then
+** the seek is deferred until it is actually needed. It might be
+** the case that the cursor is never accessed. By deferring the
+** seek, we avoid unnecessary seeks.
+**
** See also: Found, NotFound, Distinct, MoveLt, MoveGt, MoveLe
*/
-/* Opcode: MoveGt P1 P2 *
+/* Opcode: MoveGt P1 P2 P3 * *
**
-** Pop the top of the stack and use its value as a key. Reposition
+** Use the value in register P3 as a key. Reposition
** cursor P1 so that it points to the smallest entry that is greater
-** than the key from the stack.
-** If there are no records greater than the key and P2 is not zero,
+** than the key in register P3.
+** If there are no records greater than the key
** then jump to P2.
**
** See also: Found, NotFound, Distinct, MoveLt, MoveGe, MoveLe
*/
-/* Opcode: MoveLt P1 P2 *
+/* Opcode: MoveLt P1 P2 P3 * *
**
-** Pop the top of the stack and use its value as a key. Reposition
+** Use the value in register P3 as a key. Reposition
** cursor P1 so that it points to the largest entry that is less
-** than the key from the stack.
-** If there are no records less than the key and P2 is not zero,
+** than the key in register P3.
+** If there are no records less than the key
** then jump to P2.
**
** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLe
*/
-/* Opcode: MoveLe P1 P2 *
+/* Opcode: MoveLe P1 P2 P3 * *
**
-** Pop the top of the stack and use its value as a key. Reposition
+** Use the value in register P3 as a key. Reposition
** cursor P1 so that it points to the largest entry that is less than
-** or equal to the key that was popped from the stack.
-** If there are no records less than or eqal to the key and P2 is not zero,
+** or equal to the key.
+** If there are no records less than or eqal to the key
** then jump to P2.
**
** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLt
*/
-case OP_MoveLt: /* no-push */
-case OP_MoveLe: /* no-push */
-case OP_MoveGe: /* no-push */
-case OP_MoveGt: { /* no-push */
+case OP_MoveLt: /* jump, in3 */
+case OP_MoveLe: /* jump, in3 */
+case OP_MoveGe: /* jump, in3 */
+case OP_MoveGt: { /* jump, in3 */
int i = pOp->p1;
Cursor *pC;
- assert( pTos>=p->aStack );
assert( i>=0 && i<p->nCursor );
pC = p->apCsr[i];
assert( pC!=0 );
@@ -2802,26 +2743,24 @@ case OP_MoveGt: { /* no-push */
pC->nullRow = 0;
*pC->pIncrKey = oc==OP_MoveGt || oc==OP_MoveLe;
if( pC->isTable ){
- i64 iKey;
- sqlite3VdbeMemIntegerify(pTos);
- iKey = intToKey(pTos->i);
- if( pOp->p2==0 && pOp->opcode==OP_MoveGe ){
+ i64 iKey = sqlite3VdbeIntValue(pIn3);
+ if( pOp->p2==0 ){
+ assert( pOp->opcode==OP_MoveGe );
pC->movetoTarget = iKey;
+ pC->rowidIsValid = 0;
pC->deferredMoveto = 1;
- assert( (pTos->flags & MEM_Dyn)==0 );
- pTos--;
break;
}
- rc = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)iKey, &res);
+ rc = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)iKey, 0, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- pC->lastRowid = pTos->i;
+ pC->lastRowid = iKey;
pC->rowidIsValid = res==0;
}else{
- assert( pTos->flags & MEM_Blob );
- /* Stringify(pTos, encoding); */
- rc = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
+ assert( pIn3->flags & MEM_Blob );
+ ExpandBlob(pIn3);
+ rc = sqlite3BtreeMoveto(pC->pCursor, pIn3->z, pIn3->n, 0, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
@@ -2854,82 +2793,64 @@ case OP_MoveGt: { /* no-push */
res = sqlite3BtreeEof(pC->pCursor);
}
}
+ assert( pOp->p2>0 );
if( res ){
- if( pOp->p2>0 ){
- pc = pOp->p2 - 1;
- }else{
- pC->nullRow = 1;
- }
+ pc = pOp->p2 - 1;
}
}
- Release(pTos);
- pTos--;
break;
}
-/* Opcode: Distinct P1 P2 *
-**
-** Use the top of the stack as a record created using MakeRecord. P1 is a
-** cursor on a table that declared as an index. If that table contains an
-** entry that matches the top of the stack fall thru. If the top of the stack
-** matches no entry in P1 then jump to P2.
-**
-** The cursor is left pointing at the matching entry if it exists. The
-** record on the top of the stack is not popped.
-**
-** This instruction is similar to NotFound except that this operation
-** does not pop the key from the stack.
+/* Opcode: Found P1 P2 P3 * *
**
-** The instruction is used to implement the DISTINCT operator on SELECT
-** statements. The P1 table is not a true index but rather a record of
-** all results that have produced so far.
-**
-** See also: Found, NotFound, MoveTo, IsUnique, NotExists
-*/
-/* Opcode: Found P1 P2 *
-**
-** Top of the stack holds a blob constructed by MakeRecord. P1 is an index.
-** If an entry that matches the top of the stack exists in P1 then
-** jump to P2. If the top of the stack does not match any entry in P1
+** Register P3 holds a blob constructed by MakeRecord. P1 is an index.
+** If an entry that matches the value in register p3 exists in P1 then
+** jump to P2. If the P3 value does not match any entry in P1
** then fall thru. The P1 cursor is left pointing at the matching entry
-** if it exists. The blob is popped off the top of the stack.
+** if it exists.
**
** This instruction is used to implement the IN operator where the
-** left-hand side is a SELECT statement. P1 is not a true index but
-** is instead a temporary index that holds the results of the SELECT
-** statement. This instruction just checks to see if the left-hand side
-** of the IN operator (stored on the top of the stack) exists in the
-** result of the SELECT statement.
+** left-hand side is a SELECT statement. P1 may be a true index, or it
+** may be a temporary index that holds the results of the SELECT
+** statement. This instruction is also used to implement the
+** DISTINCT keyword in SELECT statements.
+**
+** This instruction checks if index P1 contains a record for which
+** the first N serialised values exactly match the N serialised values
+** in the record in register P3, where N is the total number of values in
+** the P3 record (the P3 record is a prefix of the P1 record).
**
-** See also: Distinct, NotFound, MoveTo, IsUnique, NotExists
+** See also: NotFound, MoveTo, IsUnique, NotExists
*/
-/* Opcode: NotFound P1 P2 *
+/* Opcode: NotFound P1 P2 P3 * *
**
-** The top of the stack holds a blob constructed by MakeRecord. P1 is
+** Register P3 holds a blob constructed by MakeRecord. P1 is
** an index. If no entry exists in P1 that matches the blob then jump
-** to P1. If an entry does existing, fall through. The cursor is left
-** pointing to the entry that matches. The blob is popped from the stack.
+** to P2. If an entry does existing, fall through. The cursor is left
+** pointing to the entry that matches.
**
-** The difference between this operation and Distinct is that
-** Distinct does not pop the key from the stack.
-**
-** See also: Distinct, Found, MoveTo, NotExists, IsUnique
+** See also: Found, MoveTo, NotExists, IsUnique
*/
-case OP_Distinct: /* no-push */
-case OP_NotFound: /* no-push */
-case OP_Found: { /* no-push */
+case OP_NotFound: /* jump, in3 */
+case OP_Found: { /* jump, in3 */
int i = pOp->p1;
int alreadyExists = 0;
Cursor *pC;
- assert( pTos>=p->aStack );
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
if( (pC = p->apCsr[i])->pCursor!=0 ){
- int res, rx;
+ int res;
assert( pC->isTable==0 );
- Stringify(pTos, encoding);
- rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
- alreadyExists = rx==SQLITE_OK && res==0;
+ assert( pIn3->flags & MEM_Blob );
+ if( pOp->opcode==OP_Found ){
+ pC->pKeyInfo->prefixIsEqual = 1;
+ }
+ rc = sqlite3BtreeMoveto(pC->pCursor, pIn3->z, pIn3->n, 0, &res);
+ pC->pKeyInfo->prefixIsEqual = 0;
+ if( rc!=SQLITE_OK ){
+ break;
+ }
+ alreadyExists = (res==0);
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
}
@@ -2938,19 +2859,14 @@ case OP_Found: { /* no-push */
}else{
if( !alreadyExists ) pc = pOp->p2 - 1;
}
- if( pOp->opcode!=OP_Distinct ){
- Release(pTos);
- pTos--;
- }
break;
}
-/* Opcode: IsUnique P1 P2 *
+/* Opcode: IsUnique P1 P2 P3 P4 *
**
-** 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 MakeIdxRec. Call it K. This instruction pops R from the
-** stack but it leaves K unchanged.
+** The P3 register contains an integer record number. Call this
+** record number R. The P4 register contains an index key created
+** using MakeIdxRec. Call it K.
**
** P1 is an index. So it has no data and its key consists of a
** record generated by OP_MakeRecord where the last field is the
@@ -2961,26 +2877,27 @@ case OP_Found: { /* no-push */
** If there is no such entry, then there is an immediate
** jump to P2. If any entry does exist where the index string
** matches K but the record number is not R, then the record
-** number for that entry is pushed onto the stack and control
+** number for that entry is written into P3 and control
** falls through to the next instruction.
**
-** See also: Distinct, NotFound, NotExists, Found
+** See also: NotFound, NotExists, Found
*/
-case OP_IsUnique: { /* no-push */
+case OP_IsUnique: { /* jump, in3 */
int i = pOp->p1;
- Mem *pNos = &pTos[-1];
Cursor *pCx;
BtCursor *pCrsr;
+ Mem *pK;
i64 R;
/* Pop the value R off the top of the stack
*/
- assert( pNos>=p->aStack );
- sqlite3VdbeMemIntegerify(pTos);
- R = pTos->i;
- assert( (pTos->flags & MEM_Dyn)==0 );
- pTos--;
- assert( i>=0 && i<=p->nCursor );
+ assert( pOp->p4type==P4_INT32 );
+ assert( pOp->p4.i>0 && pOp->p4.i<=p->nMem );
+ pK = &p->aMem[pOp->p4.i];
+ sqlite3VdbeMemIntegerify(pIn3);
+ R = pIn3->u.i;
+ assert( (pIn3->flags & MEM_Dyn)==0 );
+ assert( i>=0 && i<p->nCursor );
pCx = p->apCsr[i];
assert( pCx!=0 );
pCrsr = pCx->pCursor;
@@ -2994,9 +2911,9 @@ case OP_IsUnique: { /* no-push */
/* Make sure K is a string and make zKey point to K
*/
- Stringify(pNos, encoding);
- zKey = pNos->z;
- nKey = pNos->n;
+ assert( pK->flags & MEM_Blob );
+ zKey = pK->z;
+ nKey = pK->n;
szRowid = sqlite3VdbeIdxRowidLen((u8*)zKey);
len = nKey-szRowid;
@@ -3006,7 +2923,7 @@ case OP_IsUnique: { /* no-push */
*/
assert( pCx->deferredMoveto==0 );
pCx->cacheStatus = CACHE_STALE;
- rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res);
+ rc = sqlite3BtreeMoveto(pCrsr, zKey, len, 0, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
@@ -3038,92 +2955,92 @@ case OP_IsUnique: { /* no-push */
break;
}
- /* The final varint of the key is different from R. Push it onto
- ** the stack. (The record number of an entry that violates a UNIQUE
- ** constraint.)
+ /* The final varint of the key is different from R. Store it back
+ ** into register R3. (The record number of an entry that violates
+ ** a UNIQUE constraint.)
*/
- pTos++;
- pTos->i = v;
- pTos->flags = MEM_Int;
+ pIn3->u.i = v;
+ assert( pIn3->flags==MEM_Int );
}
break;
}
-/* Opcode: NotExists P1 P2 *
+/* Opcode: NotExists P1 P2 P3 * *
**
-** Use the top of the stack as a integer key. If a record with that key
-** does not exist in table of P1, then jump to P2. If the record
-** does exist, then fall thru. The cursor is left pointing to the
-** record if it exists. The integer key is popped from the stack.
+** Use the content of register P3 as a integer key. If a record
+** with that key does not exist in table of P1, then jump to P2.
+** If the record does exist, then fall thru. The cursor is left
+** pointing to the record if it exists.
**
** The difference between this operation and NotFound is that this
** operation assumes the key is an integer and that P1 is a table whereas
** NotFound assumes key is a blob constructed from MakeRecord and
** P1 is an index.
**
-** See also: Distinct, Found, MoveTo, NotFound, IsUnique
+** See also: Found, MoveTo, NotFound, IsUnique
*/
-case OP_NotExists: { /* no-push */
+case OP_NotExists: { /* jump, in3 */
int i = pOp->p1;
Cursor *pC;
BtCursor *pCrsr;
- assert( pTos>=p->aStack );
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
int res;
u64 iKey;
- assert( pTos->flags & MEM_Int );
+ assert( pIn3->flags & MEM_Int );
assert( p->apCsr[i]->isTable );
- iKey = intToKey(pTos->i);
- rc = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res);
- pC->lastRowid = pTos->i;
+ iKey = intToKey(pIn3->u.i);
+ rc = sqlite3BtreeMoveto(pCrsr, 0, iKey, 0,&res);
+ pC->lastRowid = pIn3->u.i;
pC->rowidIsValid = res==0;
pC->nullRow = 0;
pC->cacheStatus = CACHE_STALE;
+ /* res might be uninitialized if rc!=SQLITE_OK. But if rc!=SQLITE_OK
+ ** processing is about to abort so we really do not care whether or not
+ ** the following jump is taken. (In other words, do not stress over
+ ** the error that valgrind sometimes shows on the next statement when
+ ** running ioerr.test and similar failure-recovery test scripts.) */
if( res!=0 ){
pc = pOp->p2 - 1;
- pC->rowidIsValid = 0;
+ assert( pC->rowidIsValid==0 );
}
}
- Release(pTos);
- pTos--;
break;
}
-/* Opcode: Sequence P1 * *
+/* Opcode: Sequence P1 P2 * * *
**
-** Push an integer onto the stack which is the next available
-** sequence number for cursor P1. The sequence number on the
-** cursor is incremented after the push.
+** Find the next available sequence number for cursor P1.
+** Write the sequence number into register P2.
+** The sequence number on the cursor is incremented after this
+** instruction.
*/
-case OP_Sequence: {
+case OP_Sequence: { /* out2-prerelease */
int i = pOp->p1;
- assert( pTos>=p->aStack );
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
- pTos++;
- pTos->i = p->apCsr[i]->seqCount++;
- pTos->flags = MEM_Int;
+ pOut->u.i = p->apCsr[i]->seqCount++;
+ pOut->flags = MEM_Int;
break;
}
-/* Opcode: NewRowid P1 P2 *
+/* Opcode: NewRowid P1 P2 P3 * *
**
** Get a new integer record number (a.k.a "rowid") used as the key to a table.
** The record number is not previously used as a key in the database
-** table that cursor P1 points to. The new record number is pushed
-** onto the stack.
+** table that cursor P1 points to. The new record number is written
+** written to register P2.
**
-** If P2>0 then P2 is a memory cell that holds the largest previously
+** If P3>0 then P3 is a register that holds the largest previously
** generated record number. No new record numbers are allowed to be less
** than this value. When this value reaches its maximum, a SQLITE_FULL
-** error is generated. The P2 memory cell is updated with the generated
-** record number. This P2 mechanism is used to help implement the
+** error is generated. The P3 register is updated with the generated
+** record number. This P3 mechanism is used to help implement the
** AUTOINCREMENT feature.
*/
-case OP_NewRowid: {
+case OP_NewRowid: { /* out2-prerelease */
int i = pOp->p1;
i64 v = 0;
Cursor *pC;
@@ -3206,20 +3123,21 @@ case OP_NewRowid: {
}
#ifndef SQLITE_OMIT_AUTOINCREMENT
- if( pOp->p2 ){
+ if( pOp->p3 ){
Mem *pMem;
- assert( pOp->p2>0 && pOp->p2<p->nMem ); /* P2 is a valid memory cell */
- pMem = &p->aMem[pOp->p2];
+ assert( pOp->p3>0 && pOp->p3<=p->nMem ); /* P3 is a valid memory cell */
+ pMem = &p->aMem[pOp->p3];
+ REGISTER_TRACE(pOp->p3, pMem);
sqlite3VdbeMemIntegerify(pMem);
- assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P2) holds an integer */
- if( pMem->i==MAX_ROWID || pC->useRandomRowid ){
+ assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */
+ if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){
rc = SQLITE_FULL;
goto abort_due_to_error;
}
- if( v<pMem->i+1 ){
- v = pMem->i + 1;
+ if( v<pMem->u.i+1 ){
+ v = pMem->u.i + 1;
}
- pMem->i = v;
+ pMem->u.i = v;
}
#endif
@@ -3231,23 +3149,21 @@ case OP_NewRowid: {
}
}
if( pC->useRandomRowid ){
- assert( pOp->p2==0 ); /* SQLITE_FULL must have occurred prior to this */
+ assert( pOp->p3==0 ); /* SQLITE_FULL must have occurred prior to this */
v = db->priorNewRowid;
cnt = 0;
do{
- if( v==0 || cnt>2 ){
+ if( cnt==0 && (v&0xffffff)==v ){
+ v++;
+ }else{
sqlite3Randomness(sizeof(v), &v);
if( cnt<5 ) v &= 0xffffff;
- }else{
- unsigned char r;
- sqlite3Randomness(1, &r);
- v += r + 1;
}
if( v==0 ) continue;
x = intToKey(v);
- rx = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)x, &res);
+ rx = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)x, 0, &res);
cnt++;
- }while( cnt<1000 && rx==SQLITE_OK && res==0 );
+ }while( cnt<100 && rx==SQLITE_OK && res==0 );
db->priorNewRowid = v;
if( rx==SQLITE_OK && res==0 ){
rc = SQLITE_FULL;
@@ -3258,96 +3174,110 @@ case OP_NewRowid: {
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
}
- pTos++;
- pTos->i = v;
- pTos->flags = MEM_Int;
+ pOut->flags = MEM_Int;
+ pOut->u.i = v;
break;
}
-/* Opcode: Insert P1 P2 P3
+/* Opcode: Insert P1 P2 P3 P4 P5
**
** 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
-** entry is overwritten. The data is the value on the top of the
-** stack. The key is the next value down on the stack. The key must
-** be an integer. The stack is popped twice by this instruction.
+** entry is overwritten. The data is the value stored register
+** number P2. The key is stored in register P3. The key must
+** be an integer.
**
-** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
-** incremented (otherwise not). If the OPFLAG_LASTROWID flag of P2 is set,
+** If the OPFLAG_NCHANGE flag of P5 is set, then the row change count is
+** incremented (otherwise not). If the OPFLAG_LASTROWID flag of P5 is set,
** then rowid is stored for subsequent return by the
-** sqlite3_last_insert_rowid() function (otherwise it's unmodified).
+** sqlite3_last_insert_rowid() function (otherwise it is unmodified).
**
-** Parameter P3 may point to a string containing the table-name, or
+** Parameter P4 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.
**
+** (WARNING/TODO: If P1 is a pseudo-cursor and P2 is dynamically
+** allocated, then ownership of P2 is transferred to the pseudo-cursor
+** and register P2 becomes ephemeral. If the cursor is changed, the
+** value of register P2 will then change. Make sure this does not
+** cause any problems.)
+**
** This instruction only works on tables. The equivalent instruction
** for indices is OP_IdxInsert.
*/
-case OP_Insert: { /* no-push */
- Mem *pNos = &pTos[-1];
+case OP_Insert: {
+ Mem *pData = &p->aMem[pOp->p2];
+ Mem *pKey = &p->aMem[pOp->p3];
+
+ i64 iKey; /* The integer ROWID or key for the record to be inserted */
int i = pOp->p1;
Cursor *pC;
- assert( pNos>=p->aStack );
assert( i>=0 && i<p->nCursor );
- assert( p->apCsr[i]!=0 );
- if( ((pC = p->apCsr[i])->pCursor!=0 || pC->pseudoTable) ){
- i64 iKey; /* The integer ROWID or key for the record to be inserted */
-
- assert( pNos->flags & MEM_Int );
- assert( pC->isTable );
- iKey = intToKey(pNos->i);
-
- if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
- if( pOp->p2 & OPFLAG_LASTROWID ) db->lastRowid = pNos->i;
- if( pC->nextRowidValid && pNos->i>=pC->nextRowid ){
- pC->nextRowidValid = 0;
- }
- if( pTos->flags & MEM_Null ){
- pTos->z = 0;
- pTos->n = 0;
+ pC = p->apCsr[i];
+ assert( pC!=0 );
+ assert( pC->pCursor!=0 || pC->pseudoTable );
+ assert( pKey->flags & MEM_Int );
+ assert( pC->isTable );
+ REGISTER_TRACE(pOp->p2, pData);
+ REGISTER_TRACE(pOp->p3, pKey);
+
+ iKey = intToKey(pKey->u.i);
+ if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
+ if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = pKey->u.i;
+ if( pC->nextRowidValid && pKey->u.i>=pC->nextRowid ){
+ pC->nextRowidValid = 0;
+ }
+ if( pData->flags & MEM_Null ){
+ pData->z = 0;
+ pData->n = 0;
+ }else{
+ assert( pData->flags & (MEM_Blob|MEM_Str) );
+ }
+ if( pC->pseudoTable ){
+ sqlite3_free(pC->pData);
+ pC->iKey = iKey;
+ pC->nData = pData->n;
+ if( pData->flags & MEM_Dyn ){
+ pC->pData = pData->z;
+ pData->flags &= ~MEM_Dyn;
+ pData->flags |= MEM_Ephem;
}else{
- assert( pTos->flags & (MEM_Blob|MEM_Str) );
+ pC->pData = sqlite3_malloc( pC->nData+2 );
+ if( !pC->pData ) goto no_mem;
+ memcpy(pC->pData, pData->z, pC->nData);
+ pC->pData[pC->nData] = 0;
+ pC->pData[pC->nData+1] = 0;
}
- if( pC->pseudoTable ){
- sqliteFree(pC->pData);
- pC->iKey = iKey;
- pC->nData = pTos->n;
- if( pTos->flags & MEM_Dyn ){
- pC->pData = pTos->z;
- pTos->flags = MEM_Null;
- }else{
- pC->pData = sqliteMallocRaw( pC->nData+2 );
- if( !pC->pData ) goto no_mem;
- memcpy(pC->pData, pTos->z, pC->nData);
- pC->pData[pC->nData] = 0;
- pC->pData[pC->nData+1] = 0;
- }
- pC->nullRow = 0;
+ pC->nullRow = 0;
+ }else{
+ int nZero;
+ if( pData->flags & MEM_Zero ){
+ nZero = pData->u.i;
}else{
- rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, pTos->z, pTos->n);
- }
-
- pC->rowidIsValid = 0;
- pC->deferredMoveto = 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 );
+ nZero = 0;
}
+ rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey,
+ pData->z, pData->n, nZero,
+ pOp->p5 & OPFLAG_APPEND);
+ }
+
+ pC->rowidIsValid = 0;
+ pC->deferredMoveto = 0;
+ pC->cacheStatus = CACHE_STALE;
+
+ /* Invoke the update-hook if required. */
+ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
+ const char *zDb = db->aDb[pC->iDb].zName;
+ const char *zTbl = pOp->p4.z;
+ int op = ((pOp->p5 & 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 P3
+/* Opcode: Delete P1 P2 * P4 *
**
** Delete the record at which the P1 cursor is currently pointing.
**
@@ -3359,46 +3289,45 @@ case OP_Insert: { /* no-push */
** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
** incremented (otherwise not).
**
-** If P1 is a pseudo-table, then this instruction is a no-op.
+** P1 must not be pseudo-table. It has to be a real table with
+** multiple rows.
+**
+** If P4 is not NULL, then it is the name of the table that P1 is
+** pointing to. The update hook will be invoked, if it exists.
+** If P4 is not NULL then the P1 cursor must have been positioned
+** using OP_NotFound prior to invoking this opcode.
*/
-case OP_Delete: { /* no-push */
+case OP_Delete: {
int i = pOp->p1;
+ i64 iKey;
Cursor *pC;
+
assert( i>=0 && i<p->nCursor );
pC = p->apCsr[i];
assert( pC!=0 );
- if( pC->pCursor!=0 ){
- i64 iKey;
+ assert( pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */
- /* 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);
- }
- }
+ /* If the update-hook will be invoked, set iKey to the rowid of the
+ ** row being deleted.
+ */
+ if( db->xUpdateCallback && pOp->p4.z ){
+ assert( pC->isTable );
+ assert( pC->rowidIsValid ); /* lastRowid set by previous OP_NotFound */
+ iKey = pC->lastRowid;
+ }
- rc = sqlite3VdbeCursorMoveto(pC);
- if( rc ) goto abort_due_to_error;
- rc = sqlite3BtreeDelete(pC->pCursor);
- pC->nextRowidValid = 0;
- pC->cacheStatus = CACHE_STALE;
+ rc = sqlite3VdbeCursorMoveto(pC);
+ if( rc ) goto abort_due_to_error;
+ rc = sqlite3BtreeDelete(pC->pCursor);
+ pC->nextRowidValid = 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 );
- }
+ /* Invoke the update-hook if required. */
+ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
+ const char *zDb = db->aDb[pC->iDb].zName;
+ const char *zTbl = pOp->p4.z;
+ db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey);
+ assert( pC->iDb>=0 );
}
if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
break;
@@ -3411,7 +3340,7 @@ case OP_Delete: { /* no-push */
** change counter (returned by subsequent calls to sqlite3_changes())
** before it is reset. This is used by trigger programs.
*/
-case OP_ResetCount: { /* no-push */
+case OP_ResetCount: {
if( pOp->p1 ){
sqlite3VdbeSetChanges(db, p->nChange);
}
@@ -3419,87 +3348,86 @@ case OP_ResetCount: { /* no-push */
break;
}
-/* Opcode: RowData P1 * *
+/* Opcode: RowData P1 P2 * * *
**
-** Push onto the stack the complete row data for cursor P1.
-** There is no interpretation of the data. It is just copied
-** onto the stack exactly as it is found in the database file.
+** Write into register P2 the complete row data for cursor P1.
+** There is no interpretation of the data.
+** It is just copied onto the P2 register exactly as
+** it is found in the database file.
**
-** If the cursor is not pointing to a valid row, a NULL is pushed
-** onto the stack.
+** If the P1 cursor must be pointing to a valid row (not a NULL row)
+** of a real table, not a pseudo-table.
*/
-/* Opcode: RowKey P1 * *
+/* Opcode: RowKey P1 P2 * * *
**
-** Push onto the stack the complete row key for cursor P1.
-** There is no interpretation of the key. It is just copied
-** onto the stack exactly as it is found in the database file.
+** Write into register P2 the complete row key for cursor P1.
+** There is no interpretation of the data.
+** The key is copied onto the P3 register exactly as
+** it is found in the database file.
**
-** If the cursor is not pointing to a valid row, a NULL is pushed
-** onto the stack.
+** If the P1 cursor must be pointing to a valid row (not a NULL row)
+** of a real table, not a pseudo-table.
*/
-case OP_RowKey:
-case OP_RowData: {
+case OP_RowKey: /* out2-prerelease */
+case OP_RowData: { /* out2-prerelease */
int i = pOp->p1;
Cursor *pC;
+ BtCursor *pCrsr;
u32 n;
/* Note that RowKey and RowData are really exactly the same instruction */
- pTos++;
assert( i>=0 && i<p->nCursor );
pC = p->apCsr[i];
assert( pC->isTable || pOp->opcode==OP_RowKey );
assert( pC->isIndex || pOp->opcode==OP_RowData );
assert( pC!=0 );
- if( pC->nullRow ){
- pTos->flags = MEM_Null;
- }else if( pC->pCursor!=0 ){
- BtCursor *pCrsr = pC->pCursor;
- rc = sqlite3VdbeCursorMoveto(pC);
- if( rc ) goto abort_due_to_error;
- if( pC->nullRow ){
- pTos->flags = MEM_Null;
- break;
- }else if( pC->isIndex ){
- i64 n64;
- assert( !pC->isTable );
- sqlite3BtreeKeySize(pCrsr, &n64);
- n = n64;
- }else{
- sqlite3BtreeDataSize(pCrsr, &n);
- }
- pTos->n = n;
- if( n<=NBFS ){
- pTos->flags = MEM_Blob | MEM_Short;
- pTos->z = pTos->zShort;
- }else{
- char *z = sqliteMallocRaw( n );
- if( z==0 ) goto no_mem;
- pTos->flags = MEM_Blob | MEM_Dyn;
- pTos->xDel = 0;
- pTos->z = z;
+ assert( pC->nullRow==0 );
+ assert( pC->pseudoTable==0 );
+ assert( pC->pCursor!=0 );
+ pCrsr = pC->pCursor;
+ rc = sqlite3VdbeCursorMoveto(pC);
+ if( rc ) goto abort_due_to_error;
+ if( pC->isIndex ){
+ i64 n64;
+ assert( !pC->isTable );
+ sqlite3BtreeKeySize(pCrsr, &n64);
+ if( n64>SQLITE_MAX_LENGTH ){
+ goto too_big;
}
- if( pC->isIndex ){
- sqlite3BtreeKey(pCrsr, 0, n, pTos->z);
- }else{
- sqlite3BtreeData(pCrsr, 0, n, pTos->z);
+ n = n64;
+ }else{
+ sqlite3BtreeDataSize(pCrsr, &n);
+ if( n>SQLITE_MAX_LENGTH ){
+ goto too_big;
}
- }else if( pC->pseudoTable ){
- pTos->n = pC->nData;
- pTos->z = pC->pData;
- pTos->flags = MEM_Blob|MEM_Ephem;
+ }
+ pOut->n = n;
+ if( n<=NBFS ){
+ pOut->flags = MEM_Blob | MEM_Short;
+ pOut->z = pOut->zShort;
+ }else{
+ char *z = sqlite3_malloc( n );
+ if( z==0 ) goto no_mem;
+ pOut->flags = MEM_Blob | MEM_Dyn;
+ pOut->xDel = 0;
+ pOut->z = z;
+ }
+ if( pC->isIndex ){
+ rc = sqlite3BtreeKey(pCrsr, 0, n, pOut->z);
}else{
- pTos->flags = MEM_Null;
+ rc = sqlite3BtreeData(pCrsr, 0, n, pOut->z);
}
- pTos->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */
+ pOut->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
-/* Opcode: Rowid P1 * *
+/* Opcode: Rowid P1 P2 * * *
**
-** Push onto the stack an integer which is the key of the table entry that
-** P1 is currently point to.
+** Store in register P2 an integer which is the key of the table entry that
+** P1 is currently point to. If p2==0 then push the integer.
*/
-case OP_Rowid: {
+case OP_Rowid: { /* out2-prerelease */
int i = pOp->p1;
Cursor *pC;
i64 v;
@@ -3509,31 +3437,30 @@ case OP_Rowid: {
assert( pC!=0 );
rc = sqlite3VdbeCursorMoveto(pC);
if( rc ) goto abort_due_to_error;
- pTos++;
if( pC->rowidIsValid ){
v = pC->lastRowid;
}else if( pC->pseudoTable ){
v = keyToInt(pC->iKey);
- }else if( pC->nullRow || pC->pCursor==0 ){
- pTos->flags = MEM_Null;
+ }else if( pC->nullRow ){
+ /* Leave the rowid set to a NULL */
break;
}else{
assert( pC->pCursor!=0 );
sqlite3BtreeKeySize(pC->pCursor, &v);
v = keyToInt(v);
}
- pTos->i = v;
- pTos->flags = MEM_Int;
+ pOut->u.i = v;
+ pOut->flags = MEM_Int;
break;
}
-/* Opcode: NullRow P1 * *
+/* Opcode: NullRow P1 * * * *
**
** Move the cursor P1 to a null row. Any OP_Column operations
-** that occur while the cursor is on the null row will always push
-** a NULL onto the stack.
+** that occur while the cursor is on the null row will always
+** write a NULL.
*/
-case OP_NullRow: { /* no-push */
+case OP_NullRow: {
int i = pOp->p1;
Cursor *pC;
@@ -3545,7 +3472,7 @@ case OP_NullRow: { /* no-push */
break;
}
-/* Opcode: Last P1 P2 *
+/* Opcode: Last P1 P2 * * *
**
** The next use of the Rowid or Column or Next instruction for P1
** will refer to the last entry in the database table or index.
@@ -3553,31 +3480,29 @@ case OP_NullRow: { /* no-push */
** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction.
*/
-case OP_Last: { /* no-push */
+case OP_Last: { /* jump */
int i = pOp->p1;
Cursor *pC;
BtCursor *pCrsr;
+ int res;
assert( i>=0 && i<p->nCursor );
pC = p->apCsr[i];
assert( pC!=0 );
- if( (pCrsr = pC->pCursor)!=0 ){
- int res;
- rc = sqlite3BtreeLast(pCrsr, &res);
- pC->nullRow = res;
- pC->deferredMoveto = 0;
- pC->cacheStatus = CACHE_STALE;
- if( res && pOp->p2>0 ){
- pc = pOp->p2 - 1;
- }
- }else{
- pC->nullRow = 0;
+ pCrsr = pC->pCursor;
+ assert( pCrsr!=0 );
+ rc = sqlite3BtreeLast(pCrsr, &res);
+ pC->nullRow = res;
+ pC->deferredMoveto = 0;
+ pC->cacheStatus = CACHE_STALE;
+ if( res && pOp->p2>0 ){
+ pc = pOp->p2 - 1;
}
break;
}
-/* Opcode: Sort P1 P2 *
+/* Opcode: Sort P1 P2 * * *
**
** This opcode does exactly the same thing as OP_Rewind except that
** it increments an undocumented global variable used for testing.
@@ -3589,14 +3514,14 @@ case OP_Last: { /* no-push */
** regression tests can determine whether or not the optimizer is
** correctly optimizing out sorts.
*/
-case OP_Sort: { /* no-push */
+case OP_Sort: { /* jump */
#ifdef SQLITE_TEST
sqlite3_sort_count++;
sqlite3_search_count--;
#endif
/* Fall through into OP_Rewind */
}
-/* Opcode: Rewind P1 P2 *
+/* Opcode: Rewind P1 P2 * * *
**
** The next use of the Rowid or Column or Next instruction for P1
** will refer to the first entry in the database table or index.
@@ -3604,7 +3529,7 @@ case OP_Sort: { /* no-push */
** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction.
*/
-case OP_Rewind: { /* no-push */
+case OP_Rewind: { /* jump */
int i = pOp->p1;
Cursor *pC;
BtCursor *pCrsr;
@@ -3622,293 +3547,243 @@ case OP_Rewind: { /* no-push */
res = 1;
}
pC->nullRow = res;
- if( res && pOp->p2>0 ){
+ assert( pOp->p2>0 && pOp->p2<p->nOp );
+ if( res ){
pc = pOp->p2 - 1;
}
break;
}
-/* Opcode: Next P1 P2 *
+/* Opcode: Next P1 P2 * * *
**
** Advance cursor P1 so that it points to the next key/data pair in its
** table or index. If there are no more key/value pairs then fall through
** to the following instruction. But if the cursor advance was successful,
** jump immediately to P2.
**
+** The P1 cursor must be for a real table, not a pseudo-table.
+**
** See also: Prev
*/
-/* Opcode: Prev P1 P2 *
+/* Opcode: Prev P1 P2 * * *
**
** Back up cursor P1 so that it points to the previous key/data pair in its
** table or index. If there is no previous key/value pairs then fall through
** to the following instruction. But if the cursor backup was successful,
** jump immediately to P2.
+**
+** The P1 cursor must be for a real table, not a pseudo-table.
*/
-case OP_Prev: /* no-push */
-case OP_Next: { /* no-push */
+case OP_Prev: /* jump */
+case OP_Next: { /* jump */
Cursor *pC;
BtCursor *pCrsr;
+ int res;
CHECK_FOR_INTERRUPT;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
- assert( pC!=0 );
- if( (pCrsr = pC->pCursor)!=0 ){
- int res;
- if( pC->nullRow ){
- res = 1;
- }else{
- assert( pC->deferredMoveto==0 );
- rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) :
- sqlite3BtreePrevious(pCrsr, &res);
- pC->nullRow = res;
- pC->cacheStatus = CACHE_STALE;
- }
+ if( pC==0 ){
+ break; /* See ticket #2273 */
+ }
+ pCrsr = pC->pCursor;
+ assert( pCrsr );
+ if( pC->nullRow ){
+ res = 1;
+ }else{
+ assert( pC->deferredMoveto==0 );
+ rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) :
+ sqlite3BtreePrevious(pCrsr, &res);
+ pC->nullRow = res;
+ pC->cacheStatus = CACHE_STALE;
if( res==0 ){
pc = pOp->p2 - 1;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
}
- }else{
- pC->nullRow = 1;
}
pC->rowidIsValid = 0;
break;
}
-/* Opcode: IdxInsert P1 * *
+/* Opcode: IdxInsert P1 P2 P3 * *
**
-** The top of the stack holds a SQL index key made using either the
-** MakeIdxRec or MakeRecord instructions. This opcode writes that key
+** Register P2 holds a SQL index key made using the
+** MakeIdxRec instructions. This opcode writes that key
** into the index P1. Data for the entry is nil.
**
+** P3 is a flag that provides a hint to the b-tree layer that this
+** insert is likely to be an append.
+**
** This instruction only works for indices. The equivalent instruction
** for tables is OP_Insert.
*/
-case OP_IdxInsert: { /* no-push */
+case OP_IdxInsert: { /* in2 */
int i = pOp->p1;
Cursor *pC;
BtCursor *pCrsr;
- assert( pTos>=p->aStack );
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
- assert( pTos->flags & MEM_Blob );
- assert( pOp->p2==0 );
+ assert( pIn2->flags & MEM_Blob );
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
- int nKey = pTos->n;
- const char *zKey = pTos->z;
assert( pC->isTable==0 );
- rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0);
- assert( pC->deferredMoveto==0 );
- pC->cacheStatus = CACHE_STALE;
+ rc = ExpandBlob(pIn2);
+ if( rc==SQLITE_OK ){
+ int nKey = pIn2->n;
+ const char *zKey = pIn2->z;
+ rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0, 0, pOp->p3);
+ assert( pC->deferredMoveto==0 );
+ pC->cacheStatus = CACHE_STALE;
+ }
}
- Release(pTos);
- pTos--;
break;
}
-/* Opcode: IdxDelete P1 * *
+/* Opcode: IdxDelete P1 P2 * * *
**
-** 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.
+** The content of register P2 is an index key built using the either the
+** MakeIdxRec opcode. Removes that entry from the index.
*/
-case OP_IdxDelete: { /* no-push */
+case OP_IdxDelete: { /* in2 */
int i = pOp->p1;
Cursor *pC;
BtCursor *pCrsr;
- assert( pTos>=p->aStack );
- assert( pTos->flags & MEM_Blob );
+ assert( pIn2->flags & MEM_Blob );
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
int res;
- rc = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res);
+ rc = sqlite3BtreeMoveto(pCrsr, pIn2->z, pIn2->n, 0, &res);
if( rc==SQLITE_OK && res==0 ){
rc = sqlite3BtreeDelete(pCrsr);
}
assert( pC->deferredMoveto==0 );
pC->cacheStatus = CACHE_STALE;
}
- Release(pTos);
- pTos--;
break;
}
-/* Opcode: IdxRowid P1 * *
+/* Opcode: IdxRowid P1 P2 * * *
**
-** Push onto the stack an integer which is the last entry in the record at
+** Write into register P2 an integer which is the last entry in the record at
** 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, MakeIdxRec.
*/
-case OP_IdxRowid: {
+case OP_IdxRowid: { /* out2-prerelease */
int i = pOp->p1;
BtCursor *pCrsr;
Cursor *pC;
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
- pTos++;
- pTos->flags = MEM_Null;
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
i64 rowid;
assert( pC->deferredMoveto==0 );
assert( pC->isTable==0 );
- if( pC->nullRow ){
- pTos->flags = MEM_Null;
- }else{
+ if( !pC->nullRow ){
rc = sqlite3VdbeIdxRowid(pCrsr, &rowid);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- pTos->flags = MEM_Int;
- pTos->i = rowid;
+ pOut->flags = MEM_Int;
+ pOut->u.i = rowid;
}
}
break;
}
-/* Opcode: IdxGT P1 P2 *
-**
-** The top of the stack is an index entry that omits the ROWID. Compare
-** the top of stack against the index that P1 is currently pointing to.
-** Ignore the ROWID on the P1 index.
-**
-** The top of the stack might have fewer columns that P1.
-**
-** If the P1 index entry is greater than the top of the stack
-** then jump to P2. Otherwise fall through to the next instruction.
-** In either case, the stack is popped once.
-*/
-/* Opcode: IdxGE P1 P2 P3
+/* Opcode: IdxGE P1 P2 P3 * P5
**
-** The top of the stack is an index entry that omits the ROWID. Compare
-** the top of stack against the index that P1 is currently pointing to.
+** The value in register P3 is an index entry that omits the ROWID. Compare
+** this value against the index that P1 is currently pointing to.
** Ignore the ROWID on the P1 index.
**
-** If the P1 index entry is greater than or equal to the top of the stack
-** then jump to P2. Otherwise fall through to the next instruction.
-** In either case, the stack is popped once.
+** If the P1 index entry is greater than or equal to the value in
+** register P3 then jump to P2. Otherwise fall through to the next
+** instruction.
**
-** If P3 is the "+" string (or any other non-NULL string) then the
-** index taken from the top of the stack is temporarily increased by
-** an epsilon prior to the comparison. This make the opcode work
-** like IdxGT except that if the key from the stack is a prefix of
+** If P5 is non-zero then the value in register P3 is temporarily
+** increased by an epsilon prior to the comparison. This make the opcode work
+** like IdxGT except that if the key from register P3 is a prefix of
** the key in the cursor, the result is false whereas it would be
** true with IdxGT.
*/
-/* Opcode: IdxLT P1 P2 P3
+/* Opcode: IdxLT P1 P2 P3 * P5
**
-** The top of the stack is an index entry that omits the ROWID. Compare
-** the top of stack against the index that P1 is currently pointing to.
+** The value in register P3 is an index entry that omits the ROWID. Compare
+** the this value against the index that P1 is currently pointing to.
** Ignore the ROWID on the P1 index.
**
-** If the P1 index entry is less than the top of the stack
+** If the P1 index entry is less than the register P3 value
** then jump to P2. Otherwise fall through to the next instruction.
-** In either case, the stack is popped once.
**
-** If P3 is the "+" string (or any other non-NULL string) then the
-** index taken from the top of the stack is temporarily increased by
+** If P5 is non-zero then the
+** index taken from register P3 is temporarily increased by
** an epsilon prior to the comparison. This makes the opcode work
** like IdxLE.
*/
-case OP_IdxLT: /* no-push */
-case OP_IdxGT: /* no-push */
-case OP_IdxGE: { /* no-push */
+case OP_IdxLT: /* jump, in3 */
+case OP_IdxGE: { /* jump, in3 */
int i= pOp->p1;
Cursor *pC;
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
- assert( pTos>=p->aStack );
if( (pC = p->apCsr[i])->pCursor!=0 ){
int res;
- assert( pTos->flags & MEM_Blob ); /* Created using OP_Make*Key */
- Stringify(pTos, encoding);
+ assert( pIn3->flags & MEM_Blob ); /* Created using OP_MakeRecord */
assert( pC->deferredMoveto==0 );
- *pC->pIncrKey = pOp->p3!=0;
- assert( pOp->p3==0 || pOp->opcode!=OP_IdxGT );
- rc = sqlite3VdbeIdxKeyCompare(pC, pTos->n, (u8*)pTos->z, &res);
+ ExpandBlob(pIn3);
+ assert( pOp->p5==0 || pOp->p5==1 );
+ *pC->pIncrKey = pOp->p5;
+ rc = sqlite3VdbeIdxKeyCompare(pC, pIn3->n, (u8*)pIn3->z, &res);
*pC->pIncrKey = 0;
if( rc!=SQLITE_OK ){
break;
}
if( pOp->opcode==OP_IdxLT ){
res = -res;
- }else if( pOp->opcode==OP_IdxGE ){
+ }else{
+ assert( pOp->opcode==OP_IdxGE );
res++;
}
if( res>0 ){
pc = pOp->p2 - 1 ;
}
}
- Release(pTos);
- pTos--;
break;
}
-/* Opcode: IdxIsNull P1 P2 *
-**
-** The top of the stack contains an index entry such as might be generated
-** 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.
-**
-** The index entry is always popped from the stack.
-*/
-case OP_IdxIsNull: { /* no-push */
- int i = pOp->p1;
- int k, n;
- const char *z;
- u32 serial_type;
-
- assert( pTos>=p->aStack );
- assert( pTos->flags & MEM_Blob );
- z = pTos->z;
- n = pTos->n;
- k = sqlite3GetVarint32((u8*)z, &serial_type);
- for(; k<n && i>0; i--){
- k += sqlite3GetVarint32((u8*)&z[k], &serial_type);
- if( serial_type==0 ){ /* Serial type 0 is a NULL */
- pc = pOp->p2-1;
- break;
- }
- }
- Release(pTos);
- pTos--;
- break;
-}
-
-/* Opcode: Destroy P1 P2 *
+/* Opcode: Destroy P1 P2 P3 * *
**
** Delete an entire database table or index whose root page in the database
** file is given by P1.
**
-** The table being destroyed is in the main database file if P2==0. If
-** P2==1 then the table to be clear is in the auxiliary database file
+** The table being destroyed is in the main database file if P3==0. If
+** P3==1 then the table to be clear is in the auxiliary database file
** that is used to store tables create using CREATE TEMPORARY TABLE.
**
** If AUTOVACUUM is enabled then it is possible that another root page
** might be moved into the newly deleted root page in order to keep all
** root pages contiguous at the beginning of the database. The former
** value of the root page that moved - its value before the move occurred -
-** is pushed onto the stack. If no page movement was required (because
-** the table being dropped was already the last one in the database) then
-** a zero is pushed onto the stack. If AUTOVACUUM is disabled
-** then a zero is pushed onto the stack.
+** is stored in register P2. If no page
+** movement was required (because the table being dropped was already
+** the last one in the database) then a zero is stored in register P2.
+** If AUTOVACUUM is disabled then a zero is stored in register P2.
**
** See also: Clear
*/
-case OP_Destroy: {
+case OP_Destroy: { /* out2-prerelease */
int iMoved;
- Vdbe *pVdbe;
int iCnt;
#ifndef SQLITE_OMIT_VIRTUALTABLE
+ Vdbe *pVdbe;
iCnt = 0;
for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
if( pVdbe->magic==VDBE_MAGIC_RUN && pVdbe->inVtabMethod<2 && pVdbe->pc>=0 ){
@@ -3920,15 +3795,17 @@ case OP_Destroy: {
#endif
if( iCnt>1 ){
rc = SQLITE_LOCKED;
+ p->errorAction = OE_Abort;
}else{
+ int iDb = pOp->p3;
assert( iCnt==1 );
- rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1, &iMoved);
- pTos++;
- pTos->flags = MEM_Int;
- pTos->i = iMoved;
+ assert( (p->btreeMask & (1<<iDb))!=0 );
+ rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved);
+ pOut->flags = MEM_Int;
+ pOut->u.i = iMoved;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( rc==SQLITE_OK && iMoved!=0 ){
- sqlite3RootPageMoved(&db->aDb[pOp->p2], iMoved, pOp->p1);
+ sqlite3RootPageMoved(&db->aDb[iDb], iMoved, pOp->p1);
}
#endif
}
@@ -3947,51 +3824,18 @@ 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
+case OP_Clear: {
+ assert( (p->btreeMask & (1<<pOp->p2))!=0 );
rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
break;
}
-/* Opcode: CreateTable P1 * *
+/* Opcode: CreateTable P1 P2 * * *
**
-** Allocate a new table in the main database file if P2==0 or in the
-** auxiliary database file if P2==1. Push the page number
-** for the root page of the new table onto the stack.
+** Allocate a new table in the main database file if P1==0 or in the
+** auxiliary database file if P1==1 or in an attached database if
+** P1>1. Write the root page number of the new table into
+** register P2
**
** The difference between a table and an index is this: A table must
** have a 4-byte integer key and can have arbitrary data. An index
@@ -3999,20 +3843,22 @@ case OP_Clear: { /* no-push */
**
** See also: CreateIndex
*/
-/* Opcode: CreateIndex P1 * *
+/* Opcode: CreateIndex P1 P2 * * *
**
-** Allocate a new index in the main database file if P2==0 or in the
-** auxiliary database file if P2==1. Push the page number of the
-** root page of the new index onto the stack.
+** Allocate a new index in the main database file if P1==0 or in the
+** auxiliary database file if P1==1 or in an attached database if
+** P1>1. Write the root page number of the new table into
+** register P2.
**
** See documentation on OP_CreateTable for additional information.
*/
-case OP_CreateIndex:
-case OP_CreateTable: {
+case OP_CreateIndex: /* out2-prerelease */
+case OP_CreateTable: { /* out2-prerelease */
int pgno;
int flags;
Db *pDb;
assert( pOp->p1>=0 && pOp->p1<db->nDb );
+ assert( (p->btreeMask & (1<<pOp->p1))!=0 );
pDb = &db->aDb[pOp->p1];
assert( pDb->pBt!=0 );
if( pOp->opcode==OP_CreateTable ){
@@ -4022,190 +3868,200 @@ case OP_CreateTable: {
flags = BTREE_ZERODATA;
}
rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags);
- pTos++;
if( rc==SQLITE_OK ){
- pTos->i = pgno;
- pTos->flags = MEM_Int;
- }else{
- pTos->flags = MEM_Null;
+ pOut->u.i = pgno;
+ pOut->flags = MEM_Int;
}
break;
}
-/* Opcode: ParseSchema P1 * P3
+/* Opcode: ParseSchema P1 P2 * P4 *
**
** Read and parse all entries from the SQLITE_MASTER table of database P1
-** that match the WHERE clause P3.
+** that match the WHERE clause P4. P2 is the "force" flag. Always do
+** the parsing if P2 is true. If P2 is false, then this routine is a
+** no-op if the schema is not currently loaded. In other words, if P2
+** is false, the SQLITE_MASTER table is only parsed if the rest of the
+** schema is already loaded into the symbol table.
**
** This opcode invokes the parser to create a new virtual machine,
** then runs the new virtual machine. It is thus a reentrant opcode.
*/
-case OP_ParseSchema: { /* no-push */
+case OP_ParseSchema: {
char *zSql;
int iDb = pOp->p1;
const char *zMaster;
InitData initData;
assert( iDb>=0 && iDb<db->nDb );
- if( !DbHasProperty(db, iDb, DB_SchemaLoaded) ) break;
+ if( !pOp->p2 && !DbHasProperty(db, iDb, DB_SchemaLoaded) ){
+ break;
+ }
zMaster = SCHEMA_TABLE(iDb);
initData.db = db;
+ initData.iDb = pOp->p1;
initData.pzErrMsg = &p->zErrMsg;
- zSql = sqlite3MPrintf(
- "SELECT name, rootpage, sql, %d FROM '%q'.%s WHERE %s",
- pOp->p1, db->aDb[iDb].zName, zMaster, pOp->p3);
+ zSql = sqlite3MPrintf(db,
+ "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s",
+ db->aDb[iDb].zName, zMaster, pOp->p4.z);
if( zSql==0 ) goto no_mem;
- sqlite3SafetyOff(db);
+ (void)sqlite3SafetyOff(db);
assert( db->init.busy==0 );
db->init.busy = 1;
- assert( !sqlite3MallocFailed() );
+ assert( !db->mallocFailed );
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
if( rc==SQLITE_ABORT ) rc = initData.rc;
- sqliteFree(zSql);
+ sqlite3_free(zSql);
db->init.busy = 0;
- sqlite3SafetyOn(db);
+ (void)sqlite3SafetyOn(db);
if( rc==SQLITE_NOMEM ){
- sqlite3FailedMalloc();
goto no_mem;
}
break;
}
#if !defined(SQLITE_OMIT_ANALYZE) && !defined(SQLITE_OMIT_PARSER)
-/* Opcode: LoadAnalysis P1 * *
+/* Opcode: LoadAnalysis P1 * * * *
**
** Read the sqlite_stat1 table for database P1 and load the content
** of that table into the internal index hash table. This will cause
** the analysis to be used when preparing all subsequent queries.
*/
-case OP_LoadAnalysis: { /* no-push */
+case OP_LoadAnalysis: {
int iDb = pOp->p1;
assert( iDb>=0 && iDb<db->nDb );
- sqlite3AnalysisLoad(db, iDb);
+ rc = sqlite3AnalysisLoad(db, iDb);
break;
}
#endif /* !defined(SQLITE_OMIT_ANALYZE) && !defined(SQLITE_OMIT_PARSER) */
-/* Opcode: DropTable P1 * P3
+/* Opcode: DropTable P1 * * P4 *
**
** Remove the internal (in-memory) data structures that describe
-** the table named P3 in database P1. This is called after a table
+** the table named P4 in database P1. This is called after a table
** is dropped in order to keep the internal representation of the
** schema consistent with what is on disk.
*/
-case OP_DropTable: { /* no-push */
- sqlite3UnlinkAndDeleteTable(db, pOp->p1, pOp->p3);
+case OP_DropTable: {
+ sqlite3UnlinkAndDeleteTable(db, pOp->p1, pOp->p4.z);
break;
}
-/* Opcode: DropIndex P1 * P3
+/* Opcode: DropIndex P1 * * P4 *
**
** Remove the internal (in-memory) data structures that describe
-** the index named P3 in database P1. This is called after an index
+** the index named P4 in database P1. This is called after an index
** is dropped in order to keep the internal representation of the
** schema consistent with what is on disk.
*/
-case OP_DropIndex: { /* no-push */
- sqlite3UnlinkAndDeleteIndex(db, pOp->p1, pOp->p3);
+case OP_DropIndex: {
+ sqlite3UnlinkAndDeleteIndex(db, pOp->p1, pOp->p4.z);
break;
}
-/* Opcode: DropTrigger P1 * P3
+/* Opcode: DropTrigger P1 * * P4 *
**
** Remove the internal (in-memory) data structures that describe
-** the trigger named P3 in database P1. This is called after a trigger
+** the trigger named P4 in database P1. This is called after a trigger
** is dropped in order to keep the internal representation of the
** schema consistent with what is on disk.
*/
-case OP_DropTrigger: { /* no-push */
- sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p3);
+case OP_DropTrigger: {
+ sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p4.z);
break;
}
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
-/* Opcode: IntegrityCk * P2 *
+/* Opcode: IntegrityCk P1 P2 P3 * P5
+**
+** Do an analysis of the currently open database. Store in
+** register P1 the text of an error message describing any problems.
+** If no problems are found, store a NULL in register P1.
**
-** Do an analysis of the currently open database. Push onto the
-** stack the text of an error message describing any problems.
-** If there are no errors, push a "ok" onto the stack.
+** The register P3 contains the maximum number of allowed errors.
+** At most reg(P3) errors will be reported.
+** In other words, the analysis stops as soon as reg(P1) errors are
+** seen. Reg(P1) is updated with the number of errors remaining.
**
** The root page numbers of all tables in the database are integer
-** values on the stack. This opcode pulls as many integers as it
-** can off of the stack and uses those numbers as the root pages.
+** stored in reg(P1), reg(P1+1), reg(P1+2), .... There are P2 tables
+** total.
**
-** If P2 is not zero, the check is done on the auxiliary database
+** If P5 is not zero, the check is done on the auxiliary database
** file, not the main database file.
**
-** This opcode is used for testing purposes only.
+** This opcode is used to implement the integrity_check pragma.
*/
case OP_IntegrityCk: {
- int nRoot;
- int *aRoot;
- int j;
- char *z;
-
- for(nRoot=0; &pTos[-nRoot]>=p->aStack; nRoot++){
- if( (pTos[-nRoot].flags & MEM_Int)==0 ) break;
- }
+ int nRoot; /* Number of tables to check. (Number of root pages.) */
+ int *aRoot; /* Array of rootpage numbers for tables to be checked */
+ int j; /* Loop counter */
+ int nErr; /* Number of errors reported */
+ char *z; /* Text of the error report */
+ Mem *pnErr; /* Register keeping track of errors remaining */
+
+ nRoot = pOp->p2;
assert( nRoot>0 );
- aRoot = sqliteMallocRaw( sizeof(int*)*(nRoot+1) );
+ aRoot = sqlite3_malloc( sizeof(int)*(nRoot+1) );
if( aRoot==0 ) goto no_mem;
+ assert( pOp->p3>0 && pOp->p3<=p->nMem );
+ pnErr = &p->aMem[pOp->p3];
+ assert( (pnErr->flags & MEM_Int)!=0 );
+ assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
+ pIn1 = &p->aMem[pOp->p1];
for(j=0; j<nRoot; j++){
- Mem *pMem = &pTos[-j];
- aRoot[j] = pMem->i;
+ aRoot[j] = sqlite3VdbeIntValue(&pIn1[j]);
}
aRoot[j] = 0;
- popStack(&pTos, nRoot);
- pTos++;
- z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot);
- if( z==0 || z[0]==0 ){
- if( z ) sqliteFree(z);
- pTos->z = "ok";
- pTos->n = 2;
- pTos->flags = MEM_Str | MEM_Static | MEM_Term;
+ assert( pOp->p5<db->nDb );
+ assert( (p->btreeMask & (1<<pOp->p5))!=0 );
+ z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot,
+ pnErr->u.i, &nErr);
+ pnErr->u.i -= nErr;
+ sqlite3VdbeMemSetNull(pIn1);
+ if( nErr==0 ){
+ assert( z==0 );
}else{
- pTos->z = z;
- pTos->n = strlen(z);
- pTos->flags = MEM_Str | MEM_Dyn | MEM_Term;
- pTos->xDel = 0;
- }
- pTos->enc = SQLITE_UTF8;
- sqlite3VdbeChangeEncoding(pTos, encoding);
- sqliteFree(aRoot);
+ pIn1->z = z;
+ pIn1->n = strlen(z);
+ pIn1->flags = MEM_Str | MEM_Dyn | MEM_Term;
+ pIn1->xDel = 0;
+ }
+ pIn1->enc = SQLITE_UTF8;
+ UPDATE_MAX_BLOBSIZE(pIn1);
+ sqlite3VdbeChangeEncoding(pIn1, encoding);
+ sqlite3_free(aRoot);
break;
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
-/* Opcode: FifoWrite * * *
+/* Opcode: FifoWrite P1 * * * *
**
-** Write the integer on the top of the stack
-** into the Fifo.
+** Write the integer from register P1 into the Fifo.
*/
-case OP_FifoWrite: { /* no-push */
- assert( pTos>=p->aStack );
- sqlite3VdbeMemIntegerify(pTos);
- sqlite3VdbeFifoPush(&p->sFifo, pTos->i);
- assert( (pTos->flags & MEM_Dyn)==0 );
- pTos--;
+case OP_FifoWrite: { /* in1 */
+ if( sqlite3VdbeFifoPush(&p->sFifo, sqlite3VdbeIntValue(pIn1))==SQLITE_NOMEM ){
+ goto no_mem;
+ }
break;
}
-/* Opcode: FifoRead * P2 *
+/* Opcode: FifoRead P1 P2 * * *
**
-** Attempt to read a single integer from the Fifo
-** and push it onto the stack. If the Fifo is empty
-** push nothing but instead jump to P2.
+** Attempt to read a single integer from the Fifo. Store that
+** integer in register P1.
+**
+** If the Fifo is empty jump to P2.
*/
-case OP_FifoRead: {
- i64 v;
+case OP_FifoRead: { /* jump */
CHECK_FOR_INTERRUPT;
- if( sqlite3VdbeFifoPop(&p->sFifo, &v)==SQLITE_DONE ){
+ assert( pOp->p1>0 && pOp->p1<=p->nMem );
+ pOut = &p->aMem[pOp->p1];
+ Release(pOut);
+ pOut->flags = MEM_Int;
+ if( sqlite3VdbeFifoPop(&p->sFifo, &pOut->u.i)==SQLITE_DONE ){
pc = pOp->p2 - 1;
- }else{
- pTos++;
- pTos->i = v;
- pTos->flags = MEM_Int;
}
break;
}
@@ -4217,7 +4073,7 @@ case OP_FifoRead: {
** opcode. The context stores the last insert row id, the last statement change
** count, and the current statement change count.
*/
-case OP_ContextPush: { /* no-push */
+case OP_ContextPush: {
int i = p->contextStackTop++;
Context *pContext;
@@ -4225,7 +4081,8 @@ 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;
- sqliteReallocOrFree((void**)&p->contextStack, sizeof(Context)*(i+1));
+ p->contextStack = sqlite3DbReallocOrFree(db, p->contextStack,
+ sizeof(Context)*(i+1));
if( p->contextStack==0 ) goto no_mem;
}
pContext = &p->contextStack[i];
@@ -4242,7 +4099,7 @@ case OP_ContextPush: { /* no-push */
** executed. The context stores the last insert row id, the last statement
** change count, and the current statement change count.
*/
-case OP_ContextPop: { /* no-push */
+case OP_ContextPop: {
Context *pContext = &p->contextStack[--p->contextStackTop];
assert( p->contextStackTop>=0 );
db->lastRowid = pContext->lastRowid;
@@ -4253,266 +4110,187 @@ case OP_ContextPop: { /* no-push */
}
#endif /* #ifndef SQLITE_OMIT_TRIGGER */
-/* Opcode: MemStore P1 P2 *
-**
-** Write the top of the stack into memory location P1.
-** P1 should be a small integer since space is allocated
-** for all memory locations between 0 and P1 inclusive.
-**
-** After the data is stored in the memory location, the
-** stack is popped once if P2 is 1. If P2 is zero, then
-** the original data remains on the stack.
-*/
-case OP_MemStore: { /* no-push */
- assert( pTos>=p->aStack );
- assert( pOp->p1>=0 && pOp->p1<p->nMem );
- rc = sqlite3VdbeMemMove(&p->aMem[pOp->p1], pTos);
- pTos--;
-
- /* If P2 is 0 then fall thru to the next opcode, OP_MemLoad, that will
- ** restore the top of the stack to its original value.
- */
- if( pOp->p2 ){
- break;
- }
-}
-/* Opcode: MemLoad P1 * *
-**
-** Push a copy of the value in memory location P1 onto the stack.
-**
-** If the value is a string, then the value pushed is a pointer to
-** the string that is stored in the memory location. If the memory
-** location is subsequently changed (using OP_MemStore) then the
-** value pushed onto the stack will change too.
-*/
-case OP_MemLoad: {
- int i = pOp->p1;
- assert( i>=0 && i<p->nMem );
- pTos++;
- sqlite3VdbeMemShallowCopy(pTos, &p->aMem[i], MEM_Ephem);
- break;
-}
-
#ifndef SQLITE_OMIT_AUTOINCREMENT
-/* Opcode: MemMax P1 * *
+/* Opcode: MemMax P1 P2 * * *
**
-** Set the value of memory cell P1 to the maximum of its current value
-** and the value on the top of the stack. The stack is unchanged.
+** Set the value of register P1 to the maximum of its current value
+** and the value in register P2.
**
** This instruction throws an error if the memory cell is not initially
** an integer.
*/
-case OP_MemMax: { /* no-push */
- int i = pOp->p1;
- Mem *pMem;
- assert( pTos>=p->aStack );
- assert( i>=0 && i<p->nMem );
- pMem = &p->aMem[i];
- sqlite3VdbeMemIntegerify(pMem);
- sqlite3VdbeMemIntegerify(pTos);
- if( pMem->i<pTos->i){
- pMem->i = pTos->i;
+case OP_MemMax: { /* in1, in2 */
+ sqlite3VdbeMemIntegerify(pIn1);
+ sqlite3VdbeMemIntegerify(pIn2);
+ if( pIn1->u.i<pIn2->u.i){
+ pIn1->u.i = pIn2->u.i;
}
break;
}
#endif /* SQLITE_OMIT_AUTOINCREMENT */
-/* Opcode: MemIncr P1 P2 *
+/* Opcode: IfPos P1 P2 * * *
**
-** Increment the integer valued memory cell P2 by the value in P1.
+** If the value of register P1 is 1 or greater, jump to P2.
**
-** It is illegal to use this instruction on a memory cell that does
+** It is illegal to use this instruction on a register that does
** not contain an integer. An assertion fault will result if you try.
*/
-case OP_MemIncr: { /* no-push */
- int i = pOp->p2;
- Mem *pMem;
- assert( i>=0 && i<p->nMem );
- pMem = &p->aMem[i];
- assert( pMem->flags==MEM_Int );
- pMem->i += pOp->p1;
- break;
-}
-
-/* Opcode: IfMemPos P1 P2 *
-**
-** 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;
- Mem *pMem;
- assert( i>=0 && i<p->nMem );
- pMem = &p->aMem[i];
- assert( pMem->flags==MEM_Int );
- if( pMem->i>0 ){
+case OP_IfPos: { /* jump, in1 */
+ assert( pIn1->flags==MEM_Int );
+ if( pIn1->u.i>0 ){
pc = pOp->p2 - 1;
}
break;
}
-/* Opcode: IfMemNeg P1 P2 *
+/* Opcode: IfNeg P1 P2 * * *
**
-** If the value of memory cell P1 is less than zero, jump to P2.
+** If the value of register P1 is less than zero, jump to P2.
**
-** It is illegal to use this instruction on a memory cell that does
+** It is illegal to use this instruction on a register 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 ){
+case OP_IfNeg: { /* jump, in1 */
+ assert( pIn1->flags==MEM_Int );
+ if( pIn1->u.i<0 ){
pc = pOp->p2 - 1;
}
break;
}
-/* Opcode: IfMemZero P1 P2 *
+/* Opcode: IfZero P1 P2 * * *
**
-** If the value of memory cell P1 is exactly 0, jump to P2.
+** If the value of register P1 is exactly 0, jump to P2.
**
-** It is illegal to use this instruction on a memory cell that does
+** It is illegal to use this instruction on a register 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 ){
+case OP_IfZero: { /* jump, in1 */
+ assert( pIn1->flags==MEM_Int );
+ if( pIn1->u.i==0 ){
pc = pOp->p2 - 1;
}
break;
}
-/* Opcode: MemNull P1 * *
-**
-** Store a NULL in memory cell P1
-*/
-case OP_MemNull: {
- assert( pOp->p1>=0 && pOp->p1<p->nMem );
- sqlite3VdbeMemSetNull(&p->aMem[pOp->p1]);
- break;
-}
-
-/* Opcode: MemInt P1 P2 *
-**
-** Store the integer value P1 in memory cell P2.
-*/
-case OP_MemInt: {
- assert( pOp->p2>=0 && pOp->p2<p->nMem );
- sqlite3VdbeMemSetInt64(&p->aMem[pOp->p2], pOp->p1);
- break;
-}
-
-/* Opcode: MemMove P1 P2 *
-**
-** Move the content of memory cell P2 over to memory cell P1.
-** Any prior content of P1 is erased. Memory cell P2 is left
-** containing a NULL.
-*/
-case OP_MemMove: {
- assert( pOp->p1>=0 && pOp->p1<p->nMem );
- assert( pOp->p2>=0 && pOp->p2<p->nMem );
- rc = sqlite3VdbeMemMove(&p->aMem[pOp->p1], &p->aMem[pOp->p2]);
- break;
-}
-
-/* Opcode: AggStep P1 P2 P3
+/* Opcode: AggStep * P2 P3 P4 P5
**
** Execute the step function for an aggregate. The
-** function has P2 arguments. P3 is a pointer to the FuncDef
-** structure that specifies the function. Use memory location
-** P1 as the accumulator.
+** function has P5 arguments. P4 is a pointer to the FuncDef
+** structure that specifies the function. Use register
+** P3 as the accumulator.
**
-** The P2 arguments are popped from the stack.
+** The P5 arguments are taken from register P2 and its
+** successors.
*/
-case OP_AggStep: { /* no-push */
- int n = pOp->p2;
+case OP_AggStep: {
+ int n = pOp->p5;
int i;
Mem *pMem, *pRec;
sqlite3_context ctx;
sqlite3_value **apVal;
assert( n>=0 );
- pRec = &pTos[1-n];
- assert( pRec>=p->aStack );
+ pRec = &p->aMem[pOp->p2];
apVal = p->apArg;
assert( apVal || n==0 );
for(i=0; i<n; i++, pRec++){
apVal[i] = pRec;
storeTypeInfo(pRec, encoding);
}
- ctx.pFunc = (FuncDef*)pOp->p3;
- assert( pOp->p1>=0 && pOp->p1<p->nMem );
- ctx.pMem = pMem = &p->aMem[pOp->p1];
+ ctx.pFunc = pOp->p4.pFunc;
+ assert( pOp->p3>0 && pOp->p3<=p->nMem );
+ ctx.pMem = pMem = &p->aMem[pOp->p3];
pMem->n++;
ctx.s.flags = MEM_Null;
ctx.s.z = 0;
ctx.s.xDel = 0;
+ ctx.s.db = db;
ctx.isError = 0;
ctx.pColl = 0;
if( ctx.pFunc->needCollSeq ){
assert( pOp>p->aOp );
- assert( pOp[-1].p3type==P3_COLLSEQ );
+ assert( pOp[-1].p4type==P4_COLLSEQ );
assert( pOp[-1].opcode==OP_CollSeq );
- ctx.pColl = (CollSeq *)pOp[-1].p3;
+ ctx.pColl = pOp[-1].p4.pColl;
}
(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;
+ rc = ctx.isError;
}
sqlite3VdbeMemRelease(&ctx.s);
break;
}
-/* Opcode: AggFinal P1 P2 P3
+/* Opcode: AggFinal P1 P2 * P4 *
**
** Execute the finalizer function for an aggregate. P1 is
** the memory location that is the accumulator for the aggregate.
**
** P2 is the number of arguments that the step function takes and
-** P3 is a pointer to the FuncDef for this function. The P2
+** P4 is a pointer to the FuncDef for this function. The P2
** argument is not used by this opcode. It is only there to disambiguate
** functions that can take varying numbers of arguments. The
-** P3 argument is only needed for the degenerate case where
+** P4 argument is only needed for the degenerate case where
** the step function was not previously called.
*/
-case OP_AggFinal: { /* no-push */
+case OP_AggFinal: {
Mem *pMem;
- assert( pOp->p1>=0 && pOp->p1<p->nMem );
+ assert( pOp->p1>0 && pOp->p1<=p->nMem );
pMem = &p->aMem[pOp->p1];
assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
- rc = sqlite3VdbeMemFinalize(pMem, (FuncDef*)pOp->p3);
+ rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
if( rc==SQLITE_ERROR ){
sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pMem), (char*)0);
}
+ UPDATE_MAX_BLOBSIZE(pMem);
+ if( sqlite3VdbeMemTooBig(pMem) ){
+ goto too_big;
+ }
break;
}
-/* Opcode: Vacuum * * *
+#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
+/* Opcode: Vacuum * * * * *
**
** Vacuum the entire database. This opcode will cause other virtual
** machines to be created and run. It may not be called from within
** a transaction.
*/
-case OP_Vacuum: { /* no-push */
+case OP_Vacuum: {
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
rc = sqlite3RunVacuum(&p->zErrMsg, db);
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
break;
}
+#endif
+
+#if !defined(SQLITE_OMIT_AUTOVACUUM)
+/* Opcode: IncrVacuum P1 P2 * * *
+**
+** Perform a single step of the incremental vacuum procedure on
+** the P1 database. If the vacuum has finished, jump to instruction
+** P2. Otherwise, fall through to the next instruction.
+*/
+case OP_IncrVacuum: { /* jump */
+ Btree *pBt;
+
+ assert( pOp->p1>=0 && pOp->p1<db->nDb );
+ assert( (p->btreeMask & (1<<pOp->p1))!=0 );
+ pBt = db->aDb[pOp->p1].pBt;
+ rc = sqlite3BtreeIncrVacuum(pBt);
+ if( rc==SQLITE_DONE ){
+ pc = pOp->p2 - 1;
+ rc = SQLITE_OK;
+ }
+ break;
+}
+#endif
-/* Opcode: Expire P1 * *
+/* Opcode: Expire P1 * * * *
**
** Cause precompiled statements to become expired. An expired statement
** fails with an error code of SQLITE_SCHEMA if it is ever executed
@@ -4521,7 +4299,7 @@ case OP_Vacuum: { /* no-push */
** If P1 is 0, then all SQL statements become expired. If P1 is non-zero,
** then only the currently executing statement is affected.
*/
-case OP_Expire: { /* no-push */
+case OP_Expire: {
if( !pOp->p1 ){
sqlite3ExpirePreparedStatements(db);
}else{
@@ -4531,7 +4309,7 @@ case OP_Expire: { /* no-push */
}
#ifndef SQLITE_OMIT_SHARED_CACHE
-/* Opcode: TableLock P1 P2 P3
+/* Opcode: TableLock P1 P2 * P4 *
**
** Obtain a lock on a particular table. This instruction is only used when
** the shared-cache feature is enabled.
@@ -4544,18 +4322,20 @@ case OP_Expire: { /* no-push */
**
** 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
+** P4 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 */
+case OP_TableLock: {
int p1 = pOp->p1;
u8 isWriteLock = (p1<0);
if( isWriteLock ){
p1 = (-1*p1)-1;
}
+ assert( p1>=0 && p1<db->nDb );
+ assert( (p->btreeMask & (1<<p1))!=0 );
rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock);
if( rc==SQLITE_LOCKED ){
- const char *z = (const char *)pOp->p3;
+ const char *z = pOp->p4.z;
sqlite3SetString(&p->zErrMsg, "database table is locked: ", z, (char*)0);
}
break;
@@ -4563,55 +4343,55 @@ case OP_TableLock: { /* no-push */
#endif /* SQLITE_OMIT_SHARED_CACHE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
-/* Opcode: VBegin * * P3
+/* Opcode: VBegin * * * P4 *
**
-** P3 a pointer to an sqlite3_vtab structure. Call the xBegin method
+** P4 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);
+case OP_VBegin: {
+ rc = sqlite3VtabBegin(db, pOp->p4.pVtab);
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
-/* Opcode: VCreate P1 * P3
+/* Opcode: VCreate P1 * * P4 *
**
-** P3 is the name of a virtual table in database P1. Call the xCreate method
+** P4 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);
+case OP_VCreate: {
+ rc = sqlite3VtabCallCreate(db, pOp->p1, pOp->p4.z, &p->zErrMsg);
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
-/* Opcode: VDestroy P1 * P3
+/* Opcode: VDestroy P1 * * P4 *
**
-** P3 is the name of a virtual table in database P1. Call the xDestroy method
+** P4 is the name of a virtual table in database P1. Call the xDestroy method
** of that table.
*/
-case OP_VDestroy: { /* no-push */
+case OP_VDestroy: {
p->inVtabMethod = 2;
- rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p3);
+ rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z);
p->inVtabMethod = 0;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
-/* Opcode: VOpen P1 * P3
+/* Opcode: VOpen P1 * * P4 *
**
-** P3 is a pointer to a virtual table object, an sqlite3_vtab structure.
+** P4 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 */
+case OP_VOpen: {
Cursor *pCur = 0;
sqlite3_vtab_cursor *pVtabCursor = 0;
- sqlite3_vtab *pVtab = (sqlite3_vtab *)(pOp->p3);
+ sqlite3_vtab *pVtab = pOp->p4.pVtab;
sqlite3_module *pModule = (sqlite3_module *)pVtab->pModule;
assert(pVtab && pModule);
@@ -4628,6 +4408,7 @@ case OP_VOpen: { /* no-push */
pCur->pVtabCursor = pVtabCursor;
pCur->pModule = pVtabCursor->pVtab->pModule;
}else{
+ db->mallocFailed = 1;
pModule->xClose(pVtabCursor);
}
}
@@ -4636,55 +4417,55 @@ case OP_VOpen: { /* no-push */
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
-/* Opcode: VFilter P1 P2 P3
+/* Opcode: VFilter P1 P2 P3 P4 *
**
** 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
+** P4 is either NULL or a string that was generated by the xBestIndex
+** method of the module. The interpretation of the P4 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.
+** by P1. The integer query plan parameter to xFilter is stored in register
+** P3. Register P3+1 stores the argc parameter to be passed to the
+** xFilter method. Registers P3+2..P3+1+argc are the argc additional
+** parametersneath additional parameters which are passed to
+** xFilter as argv. Register P3+2 becomes argv[0] 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.
+** A jump is made to P2 if the result set after filtering would be empty.
*/
-case OP_VFilter: { /* no-push */
+case OP_VFilter: { /* jump */
int nArg;
-
+ int iQuery;
const sqlite3_module *pModule;
+ Mem *pQuery = &p->aMem[pOp->p3];
+ Mem *pArgc = &pQuery[1];
Cursor *pCur = p->apCsr[pOp->p1];
+
+ REGISTER_TRACE(pOp->p3, pQuery);
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;
+ /* Grab the index number and argc parameters */
+ assert( (pQuery->flags&MEM_Int)!=0 && pArgc->flags==MEM_Int );
+ nArg = pArgc->u.i;
+ iQuery = pQuery->u.i;
- /* Invoke the xFilter method if one is defined. */
- if( pModule->xFilter ){
- int res;
+ /* Invoke the xFilter method */
+ {
+ int res = 0;
int i;
Mem **apArg = p->apArg;
for(i = 0; i<nArg; i++){
- apArg[i] = &pTos[i+1-2-nArg];
+ apArg[i] = &pArgc[i+1];
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);
+ rc = pModule->xFilter(pCur->pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
p->inVtabMethod = 0;
if( rc==SQLITE_OK ){
res = pModule->xEof(pCur->pVtabCursor);
@@ -4695,142 +4476,168 @@ case OP_VFilter: { /* no-push */
pc = pOp->p2 - 1;
}
}
+ pCur->nullRow = 0;
- /* 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 * *
+/* Opcode: VRowid P1 P2 * * *
**
-** Push an integer onto the stack which is the rowid of
+** Store into register P2 the rowid of
** the virtual-table that the P1 cursor is pointing to.
*/
-case OP_VRowid: {
+case OP_VRowid: { /* out2-prerelease */
const sqlite3_module *pModule;
-
+ sqlite_int64 iRow;
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;
+ assert( pCur->pVtabCursor );
+ if( pCur->nullRow ){
+ break;
}
-
+ pModule = pCur->pVtabCursor->pVtab->pModule;
+ assert( pModule->xRowid );
+ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+ rc = pModule->xRowid(pCur->pVtabCursor, &iRow);
+ if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+ pOut->flags = MEM_Int;
+ pOut->u.i = iRow;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
-/* Opcode: VColumn P1 P2 *
+/* Opcode: VColumn P1 P2 P3 * *
**
-** 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.
+** Store the value of the P2-th column of
+** the row of the virtual-table that the
+** P1 cursor is pointing to into register P3.
*/
case OP_VColumn: {
const sqlite3_module *pModule;
+ Mem *pDest;
+ sqlite3_context sContext;
Cursor *pCur = p->apCsr[pOp->p1];
assert( pCur->pVtabCursor );
+ assert( pOp->p3>0 && pOp->p3<=p->nMem );
+ pDest = &p->aMem[pOp->p3];
+ if( pCur->nullRow ){
+ sqlite3VdbeMemSetNull(pDest);
+ break;
+ }
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);
+ assert( pModule->xColumn );
+ memset(&sContext, 0, sizeof(sContext));
+ sContext.s.flags = MEM_Null;
+ sContext.s.db = db;
+ 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);
+ /* Copy the result of the function to the P3 register. 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);
+ REGISTER_TRACE(pOp->p3, pDest);
+ sqlite3VdbeMemMove(pDest, &sContext.s);
+ UPDATE_MAX_BLOBSIZE(pDest);
- if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+ if( sqlite3SafetyOn(db) ){
+ goto abort_due_to_misuse;
+ }
+ if( sqlite3VdbeMemTooBig(pDest) ){
+ goto too_big;
}
-
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
-/* Opcode: VNext P1 P2 *
+/* 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 */
+case OP_VNext: { /* jump */
const sqlite3_module *pModule;
int res = 0;
Cursor *pCur = p->apCsr[pOp->p1];
assert( pCur->pVtabCursor );
+ if( pCur->nullRow ){
+ break;
+ }
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;
+ assert( pModule->xNext );
- if( !res ){
- /* If there is data, jump to P2 */
- pc = pOp->p2 - 1;
- }
+ /* 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: VRename P1 * * P4 *
+**
+** P4 is a pointer to a virtual table object, an sqlite3_vtab structure.
+** This opcode invokes the corresponding xRename method. The value
+** in register P1 is passed as the zName argument to the xRename method.
+*/
+case OP_VRename: {
+ sqlite3_vtab *pVtab = pOp->p4.pVtab;
+ Mem *pName = &p->aMem[pOp->p1];
+ assert( pVtab->pModule->xRename );
+ REGISTER_TRACE(pOp->p1, pName);
+
+ Stringify(pName, encoding);
+
+ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+ sqlite3VtabLock(pVtab);
+ rc = pVtab->pModule->xRename(pVtab, pName->z);
+ sqlite3VtabUnlock(db, pVtab);
+ if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+
+ break;
+}
+#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
-/* Opcode: VUpdate P1 P2 P3
+/* Opcode: VUpdate P1 P2 P3 P4 *
**
-** P3 is a pointer to a virtual table object, an sqlite3_vtab structure.
+** P4 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.
+** are contiguous memory cells starting at P3 to pass to the xUpdate
+** invocation. The value in register (P3+P2-1) 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.
+** The argv[0] element (which corresponds to memory cell P3)
+** 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 subsequent elements in the array 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.
@@ -4839,11 +4646,11 @@ case OP_VNext: { /* no-push */
** 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);
+case OP_VUpdate: {
+ sqlite3_vtab *pVtab = pOp->p4.pVtab;
sqlite3_module *pModule = (sqlite3_module *)pVtab->pModule;
int nArg = pOp->p2;
- assert( pOp->p3type==P3_VTAB );
+ assert( pOp->p4type==P4_VTAB );
if( pModule->xUpdate==0 ){
sqlite3SetString(&p->zErrMsg, "read-only table", 0);
rc = SQLITE_ERROR;
@@ -4851,28 +4658,60 @@ case OP_VUpdate: { /* no-push */
int i;
sqlite_int64 rowid;
Mem **apArg = p->apArg;
- Mem *pX = &pTos[1-nArg];
- for(i = 0; i<nArg; i++, pX++){
+ Mem *pX = &p->aMem[pOp->p3];
+ for(i=0; i<nArg; i++){
storeTypeInfo(pX, 0);
apArg[i] = pX;
+ pX++;
}
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+ sqlite3VtabLock(pVtab);
rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
+ sqlite3VtabUnlock(db, pVtab);
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...
+#ifndef SQLITE_OMIT_TRACE
+/* Opcode: Trace * * * P4 *
+**
+** If tracing is enabled (by the sqlite3_trace()) interface, then
+** the UTF-8 string contained in P4 is emitted on the trace callback.
*/
-default: {
- assert( 0 );
+case OP_Trace: {
+ if( pOp->p4.z ){
+ if( db->xTrace ){
+ db->xTrace(db->pTraceArg, pOp->p4.z);
+ }
+#ifdef SQLITE_DEBUG
+ if( (db->flags & SQLITE_SqlTrace)!=0 ){
+ sqlite3DebugPrintf("SQL-trace: %s\n", pOp->p4.z);
+ }
+#endif /* SQLITE_DEBUG */
+ }
+ break;
+}
+#endif
+
+
+/* Opcode: Noop * * * * *
+**
+** Do nothing. This instruction is often useful as a jump
+** destination.
+*/
+/*
+** The magic Explain opcode are only inserted when explain==2 (which
+** is to say when the EXPLAIN QUERY PLAN syntax is used.)
+** This opcode records information from the optimizer. It is the
+** the same as a no-op. This opcodesnever appears in a real VM program.
+*/
+default: { /* This is really OP_Noop and OP_Explain */
break;
}
@@ -4884,9 +4723,6 @@ default: {
*****************************************************************************/
}
- /* Make sure the stack limit was not exceeded */
- assert( pTos<=pStackLimit );
-
#ifdef VDBE_PROFILE
{
long long elapse = hwtime() - start;
@@ -4905,63 +4741,53 @@ 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 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
- /* Code for tracing the vdbe stack. */
- if( p->trace && pTos>=p->aStack ){
- int i;
- fprintf(p->trace, "Stack:");
- for(i=0; i>-5 && &pTos[i]>=p->aStack; i--){
- if( pTos[i].flags & MEM_Null ){
- fprintf(p->trace, " NULL");
- }else if( (pTos[i].flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
- fprintf(p->trace, " si:%lld", pTos[i].i);
- }else if( pTos[i].flags & MEM_Int ){
- fprintf(p->trace, " i:%lld", pTos[i].i);
- }else if( pTos[i].flags & MEM_Real ){
- fprintf(p->trace, " r:%g", pTos[i].r);
- }else{
- char zBuf[100];
- sqlite3VdbeMemPrettyPrint(&pTos[i], zBuf);
- fprintf(p->trace, " ");
- fprintf(p->trace, "%s", zBuf);
- }
+ if( p->trace ){
+ if( rc!=0 ) fprintf(p->trace,"rc=%d\n",rc);
+ if( opProperty & OPFLG_OUT2_PRERELEASE ){
+ registerTrace(p->trace, pOp->p2, pOut);
+ }
+ if( opProperty & OPFLG_OUT3 ){
+ registerTrace(p->trace, pOp->p3, pOut);
}
- if( rc!=0 ) fprintf(p->trace," rc=%d",rc);
- fprintf(p->trace,"\n");
}
#endif /* SQLITE_DEBUG */
#endif /* NDEBUG */
} /* The end of the for(;;) loop the loops through opcodes */
- /* If we reach this point, it means that execution is finished.
+ /* If we reach this point, it means that execution is finished with
+ ** an error of some kind.
*/
-vdbe_halt:
- if( rc ){
- p->rc = rc;
- rc = SQLITE_ERROR;
- }else{
- rc = SQLITE_DONE;
- }
+vdbe_error_halt:
+ assert( rc );
+ p->rc = rc;
+ rc = SQLITE_ERROR;
sqlite3VdbeHalt(p);
- p->pTos = pTos;
+
+ /* This is the only way out of this procedure. We have to
+ ** release the mutexes on btrees that were acquired at the
+ ** top. */
+vdbe_return:
+ sqlite3BtreeMutexArrayLeave(&p->aMutex);
return rc;
- /* Jump to here if a malloc() fails. It's hard to get a malloc()
- ** to fail on a modern VM computer, so this code is untested.
+ /* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH
+ ** is encountered.
+ */
+too_big:
+ sqlite3SetString(&p->zErrMsg, "string or blob too big", (char*)0);
+ rc = SQLITE_TOOBIG;
+ goto vdbe_error_halt;
+
+ /* Jump to here if a malloc() fails.
*/
no_mem:
+ db->mallocFailed = 1;
sqlite3SetString(&p->zErrMsg, "out of memory", (char*)0);
rc = SQLITE_NOMEM;
- goto vdbe_halt;
+ goto vdbe_error_halt;
/* Jump to here for an SQLITE_MISUSE error.
*/
@@ -4973,23 +4799,18 @@ abort_due_to_misuse:
** should hold the error number.
*/
abort_due_to_error:
- if( p->zErrMsg==0 ){
- if( sqlite3MallocFailed() ) rc = SQLITE_NOMEM;
- sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0);
- }
- goto vdbe_halt;
+ assert( p->zErrMsg==0 );
+ if( db->mallocFailed ) rc = SQLITE_NOMEM;
+ sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0);
+ goto vdbe_error_halt;
/* Jump to here if the sqlite3_interrupt() API sets the interrupt
** flag.
*/
abort_due_to_interrupt:
assert( db->u1.isInterrupted );
- if( db->magic!=SQLITE_MAGIC_BUSY ){
- rc = SQLITE_MISUSE;
- }else{
- rc = SQLITE_INTERRUPT;
- }
+ rc = SQLITE_INTERRUPT;
p->rc = rc;
sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0);
- goto vdbe_halt;
+ goto vdbe_error_halt;
}
diff --git a/ext/pdo_sqlite/sqlite/src/vdbe.h b/ext/pdo_sqlite/sqlite/src/vdbe.h
index 903a18dcd2..11bd3f76d5 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbe.h
+++ b/ext/pdo_sqlite/sqlite/src/vdbe.h
@@ -29,16 +29,41 @@
typedef struct Vdbe Vdbe;
/*
+** The names of the following types declared in vdbeInt.h are required
+** for the VdbeOp definition.
+*/
+typedef struct VdbeFunc VdbeFunc;
+typedef struct Mem Mem;
+
+/*
** A single instruction of the virtual machine has an opcode
** and as many as three operands. The instruction is recorded
** as an instance of the following structure:
*/
struct VdbeOp {
u8 opcode; /* What operation to perform */
+ signed char p4type; /* One of the P4_xxx constants for p4 */
+ u8 flags; /* Flags for internal use */
+ u8 p5; /* Fifth parameter is an unsigned character */
int p1; /* First operand */
int p2; /* Second parameter (often the jump destination) */
- char *p3; /* Third parameter */
- int p3type; /* One of the P3_xxx constants defined below */
+ int p3; /* The third parameter */
+ union { /* forth parameter */
+ int i; /* Integer value if p4type==P4_INT32 */
+ void *p; /* Generic pointer */
+ char *z; /* Pointer to data for string (char array) types */
+ i64 *pI64; /* Used when p4type is P4_INT64 */
+ double *pReal; /* Used when p4type is P4_REAL */
+ FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */
+ VdbeFunc *pVdbeFunc; /* Used when p4type is P4_VDBEFUNC */
+ CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */
+ Mem *pMem; /* Used when p4type is P4_MEM */
+ sqlite3_vtab *pVtab; /* Used when p4type is P4_VTAB */
+ KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
+ } p4;
+#ifdef SQLITE_DEBUG
+ char *zComment; /* Comment to improve readability */
+#endif
#ifdef VDBE_PROFILE
int cnt; /* Number of times this instruction was executed */
long long cycles; /* Total time spend executing this instruction */
@@ -53,34 +78,37 @@ typedef struct VdbeOp VdbeOp;
struct VdbeOpList {
u8 opcode; /* What operation to perform */
signed char p1; /* First operand */
- short int p2; /* Second parameter (often the jump destination) */
- char *p3; /* Third parameter */
+ signed char p2; /* Second parameter (often the jump destination) */
+ signed char p3; /* Third parameter */
};
typedef struct VdbeOpList VdbeOpList;
/*
** Allowed values of VdbeOp.p3type
*/
-#define P3_NOTUSED 0 /* The P3 parameter is not used */
-#define P3_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */
-#define P3_STATIC (-2) /* Pointer to a static string */
-#define P3_COLLSEQ (-4) /* P3 is a pointer to a CollSeq structure */
-#define P3_FUNCDEF (-5) /* P3 is a pointer to a FuncDef structure */
-#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() */
+#define P4_NOTUSED 0 /* The P4 parameter is not used */
+#define P4_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */
+#define P4_STATIC (-2) /* Pointer to a static string */
+#define P4_COLLSEQ (-4) /* P4 is a pointer to a CollSeq structure */
+#define P4_FUNCDEF (-5) /* P4 is a pointer to a FuncDef structure */
+#define P4_KEYINFO (-6) /* P4 is a pointer to a KeyInfo structure */
+#define P4_VDBEFUNC (-7) /* P4 is a pointer to a VdbeFunc structure */
+#define P4_MEM (-8) /* P4 is a pointer to a Mem* structure */
+#define P4_TRANSIENT (-9) /* P4 is a pointer to a transient string */
+#define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */
+#define P4_MPRINTF (-11) /* P4 is a string obtained from sqlite3_mprintf() */
+#define P4_REAL (-12) /* P4 is a 64-bit floating point value */
+#define P4_INT64 (-13) /* P4 is a 64-bit signed integer */
+#define P4_INT32 (-14) /* P4 is a 32-bit signed integer */
-/* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure
+/* When adding a P4 argument using P4_KEYINFO, a copy of the KeyInfo structure
** is made. That copy is freed when the Vdbe is finalized. But if the
-** argument is P3_KEYINFO_HANDOFF, the passed in pointer is used. It still
+** argument is P4_KEYINFO_HANDOFF, the passed in pointer is used. It still
** gets freed when the Vdbe is finalized so it still should be obtained
** from a single sqliteMalloc(). But no copy is made and the calling
** function should *not* try to free the KeyInfo.
*/
-#define P3_KEYINFO_HANDOFF (-9)
+#define P4_KEYINFO_HANDOFF (-9)
/*
** The Vdbe.aColName array contains 5n Mem structures, where n is the
@@ -112,15 +140,20 @@ typedef struct VdbeOpList VdbeOpList;
** for a description of what each of these routines does.
*/
Vdbe *sqlite3VdbeCreate(sqlite3*);
-void sqlite3VdbeCreateCallback(Vdbe*, int*);
-int sqlite3VdbeAddOp(Vdbe*,int,int,int);
-int sqlite3VdbeOp3(Vdbe*,int,int,int,const char *zP3,int);
+int sqlite3VdbeAddOp0(Vdbe*,int);
+int sqlite3VdbeAddOp1(Vdbe*,int,int);
+int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
+int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
+int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
+void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3);
+void sqlite3VdbeChangeP5(Vdbe*, u8 P5);
void sqlite3VdbeJumpHere(Vdbe*, int addr);
void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N);
-void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
+void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
+void sqlite3VdbeUsesBtree(Vdbe*, int);
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
int sqlite3VdbeMakeLabel(Vdbe*);
void sqlite3VdbeDelete(Vdbe*);
@@ -128,13 +161,17 @@ void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int);
int sqlite3VdbeFinalize(Vdbe*);
void sqlite3VdbeResolveLabel(Vdbe*, int);
int sqlite3VdbeCurrentAddr(Vdbe*);
-void sqlite3VdbeTrace(Vdbe*,FILE*);
+#ifdef SQLITE_DEBUG
+ void sqlite3VdbeTrace(Vdbe*,FILE*);
+#endif
+void sqlite3VdbeResetStepResult(Vdbe*);
int sqlite3VdbeReset(Vdbe*);
-int sqliteVdbeSetVariables(Vdbe*,int,const char**);
void sqlite3VdbeSetNumCols(Vdbe*,int);
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int);
void sqlite3VdbeCountChanges(Vdbe*);
sqlite3 *sqlite3VdbeDb(Vdbe*);
+void sqlite3VdbeSetSql(Vdbe*, const char *z, int n);
+void sqlite3VdbeSwap(Vdbe*,Vdbe*);
#ifndef NDEBUG
void sqlite3VdbeComment(Vdbe*, const char*, ...);
diff --git a/ext/pdo_sqlite/sqlite/src/vdbeInt.h b/ext/pdo_sqlite/sqlite/src/vdbeInt.h
index db8034061b..407ed49c92 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbeInt.h
+++ b/ext/pdo_sqlite/sqlite/src/vdbeInt.h
@@ -15,6 +15,8 @@
** 6000 lines long) it was split up into several smaller files and
** this header information was factored out.
*/
+#ifndef _VDBEINT_H_
+#define _VDBEINT_H_
/*
** intToKey() and keyToInt() used to transform the rowid. But with
@@ -23,13 +25,6 @@
#define keyToInt(X) (X)
#define intToKey(X) (X)
-/*
-** The makefile scans the vdbe.c source file and creates the following
-** array of string constants which are the names of all VDBE opcodes. This
-** array is defined in a separate source code file named opcode.c which is
-** automatically generated by the makefile.
-*/
-extern char *sqlite3OpcodeNames[];
/*
** SQL is translated into a sequence of instructions to be
@@ -123,17 +118,20 @@ typedef struct Cursor Cursor;
** SQLITE_BLOB.
*/
struct Mem {
- i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */
+ union {
+ i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */
+ FuncDef *pDef; /* Used only when flags==MEM_Agg */
+ } u;
double r; /* Real value */
+ sqlite3 *db; /* The associated database connection */
char *z; /* String or BLOB value */
- int n; /* Number of characters in string value, including '\0' */
+ int n; /* Number of characters in string value, excluding '\0' */
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
- u8 type; /* One of MEM_Null, MEM_Str, etc. */
- u8 enc; /* TEXT_Utf8, TEXT_Utf16le, or TEXT_Utf16be */
+ u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */
+ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
char zShort[NBFS]; /* Space for short strings */
};
-typedef struct Mem Mem;
/* One or more of the following flags are set to indicate the validOK
** representations of the value stored in the Mem struct.
@@ -167,6 +165,12 @@ typedef struct Mem Mem;
#define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */
#define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */
#define MEM_Agg 0x0400 /* Mem.z points to an agg function context */
+#define MEM_Zero 0x0800 /* Mem.i contains count of 0s appended to blob */
+
+#ifdef SQLITE_OMIT_INCRBLOB
+ #undef MEM_Zero
+ #define MEM_Zero 0x0000
+#endif
/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
@@ -186,7 +190,6 @@ struct VdbeFunc {
void (*xDelete)(void *); /* Destructor for the aux data */
} apAux[1]; /* One slot for each function argument */
};
-typedef struct VdbeFunc VdbeFunc;
/*
** The "context" argument for a installable function. A pointer to an
@@ -206,7 +209,7 @@ struct sqlite3_context {
VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
Mem s; /* The return value is stored here */
Mem *pMem; /* Memory cell used to store aggregate context */
- u8 isError; /* Set to true for an error */
+ int isError; /* Error code returned by the function. */
CollSeq *pColl; /* Collating sequence */
};
@@ -282,15 +285,12 @@ struct Context {
struct Vdbe {
sqlite3 *db; /* The whole database */
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
- FILE *trace; /* Write an execution trace here, if not NULL */
int nOp; /* Number of instructions in the program */
int nOpAlloc; /* Number of slots allocated for aOp[] */
Op *aOp; /* Space to hold the virtual machine's program */
int nLabel; /* Number of labels used */
int nLabelAlloc; /* Number of slots allocated in aLabel[] */
int *aLabel; /* Space to hold the labels */
- Mem *aStack; /* The operand stack, except string values */
- Mem *pTos; /* Top entry in the operand stack */
Mem **apArg; /* Arguments to currently executing user function */
Mem *aColName; /* Column names to return */
int nCursor; /* Number of slots in apCsr[] */
@@ -313,13 +313,12 @@ struct Vdbe {
unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */
int errorAction; /* Recovery action to do in case of an error */
int inTempTrans; /* True if temp database is transactioned */
- int returnStack[100]; /* Return address stack for OP_Gosub & OP_Return */
+ int returnStack[25]; /* Return address stack for OP_Gosub & OP_Return */
int returnDepth; /* Next unused element in returnStack[] */
int nResColumn; /* Number of columns in one row of the result set */
char **azResColumn; /* Values for one row of result */
- int popStack; /* Pop the stack this much on entry to VdbeExec() */
char *zErrMsg; /* Error message written here */
- u8 resOnStack; /* True if there are result values on the stack */
+ Mem *pResultSet; /* Pointer to an array of results */
u8 explain; /* True if EXPLAIN present on SQL command */
u8 changeCntOn; /* True to update the change-counter */
u8 aborted; /* True if ROLLBACK in another VM causes an abort */
@@ -328,6 +327,14 @@ struct Vdbe {
u8 inVtabMethod; /* See comments above */
int nChange; /* Number of db changes made since last reset */
i64 startTime; /* Time when query started - used for profiling */
+ int btreeMask; /* Bitmask of db->aDb[] entries referenced */
+ BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
+ int nSql; /* Number of bytes in zSql */
+ char *zSql; /* Text of the SQL statement that generated this */
+#ifdef SQLITE_DEBUG
+ FILE *trace; /* Write an execution trace here, if not NULL */
+#endif
+ int openedStatement; /* True if this VM has opened a statement journal */
#ifdef SQLITE_SSE
int fetchId; /* Statement number used by sqlite3_fetch_statement */
int lru; /* Counter used for LRU cache replacement */
@@ -351,17 +358,14 @@ int sqlite3VdbeCursorMoveto(Cursor*);
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
void sqlite3VdbePrintOp(FILE*, int, Op*);
#endif
-#ifdef SQLITE_DEBUG
-void sqlite3VdbePrintSql(Vdbe*);
-#endif
int sqlite3VdbeSerialTypeLen(u32);
u32 sqlite3VdbeSerialType(Mem*, int);
-int sqlite3VdbeSerialPut(unsigned char*, Mem*, int);
+int sqlite3VdbeSerialPut(unsigned char*, int, Mem*, int);
int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
-int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int*);
+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*);
@@ -370,14 +374,16 @@ int sqlite3VdbeExec(Vdbe*);
int sqlite3VdbeList(Vdbe*);
int sqlite3VdbeHalt(Vdbe*);
int sqlite3VdbeChangeEncoding(Mem *, int);
+int sqlite3VdbeMemTooBig(Mem*);
int sqlite3VdbeMemCopy(Mem*, const Mem*);
void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);
-int sqlite3VdbeMemMove(Mem*, Mem*);
+void sqlite3VdbeMemMove(Mem*, Mem*);
int sqlite3VdbeMemNulTerminate(Mem*);
int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*));
void sqlite3VdbeMemSetInt64(Mem*, i64);
void sqlite3VdbeMemSetDouble(Mem*, double);
void sqlite3VdbeMemSetNull(Mem*);
+void sqlite3VdbeMemSetZeroBlob(Mem*,int);
int sqlite3VdbeMemMakeWriteable(Mem*);
int sqlite3VdbeMemDynamicify(Mem*);
int sqlite3VdbeMemStringify(Mem*, int);
@@ -390,14 +396,27 @@ int sqlite3VdbeMemNumerify(Mem*);
int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
void sqlite3VdbeMemRelease(Mem *p);
int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
+const char *sqlite3OpcodeName(int);
+int sqlite3VdbeOpcodeHasProperty(int, int);
+
#ifndef NDEBUG
-void sqlite3VdbeMemSanity(Mem*);
-int sqlite3VdbeOpcodeNoPush(u8);
+ void sqlite3VdbeMemSanity(Mem*);
#endif
int sqlite3VdbeMemTranslate(Mem*, u8);
-void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf);
+#ifdef SQLITE_DEBUG
+ void sqlite3VdbePrintSql(Vdbe*);
+ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf);
+#endif
int sqlite3VdbeMemHandleBom(Mem *pMem);
void sqlite3VdbeFifoInit(Fifo*);
int sqlite3VdbeFifoPush(Fifo*, i64);
int sqlite3VdbeFifoPop(Fifo*, i64*);
void sqlite3VdbeFifoClear(Fifo*);
+
+#ifndef SQLITE_OMIT_INCRBLOB
+ int sqlite3VdbeMemExpandBlob(Mem *);
+#else
+ #define sqlite3VdbeMemExpandBlob(x) SQLITE_OK
+#endif
+
+#endif /* !defined(_VDBEINT_H_) */
diff --git a/ext/pdo_sqlite/sqlite/src/vdbeapi.c b/ext/pdo_sqlite/sqlite/src/vdbeapi.c
index a0ced3d791..e756c70515 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbeapi.c
+++ b/ext/pdo_sqlite/sqlite/src/vdbeapi.c
@@ -15,7 +15,6 @@
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
-#include "os.h"
/*
** Return TRUE (non-zero) of the statement supplied as an argument needs
@@ -30,6 +29,72 @@ int sqlite3_expired(sqlite3_stmt *pStmt){
return p==0 || p->expired;
}
+/*
+** The following routine destroys a virtual machine that is created by
+** the sqlite3_compile() routine. The integer returned is an SQLITE_
+** success/failure code that describes the result of executing the virtual
+** machine.
+**
+** This routine sets the error code and string returned by
+** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
+*/
+int sqlite3_finalize(sqlite3_stmt *pStmt){
+ int rc;
+ if( pStmt==0 ){
+ rc = SQLITE_OK;
+ }else{
+ Vdbe *v = (Vdbe*)pStmt;
+#ifndef SQLITE_MUTEX_NOOP
+ sqlite3_mutex *mutex = v->db->mutex;
+#endif
+ sqlite3_mutex_enter(mutex);
+ rc = sqlite3VdbeFinalize(v);
+ sqlite3_mutex_leave(mutex);
+ }
+ return rc;
+}
+
+/*
+** Terminate the current execution of an SQL statement and reset it
+** back to its starting state so that it can be reused. A success code from
+** the prior execution is returned.
+**
+** This routine sets the error code and string returned by
+** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
+*/
+int sqlite3_reset(sqlite3_stmt *pStmt){
+ int rc;
+ if( pStmt==0 ){
+ rc = SQLITE_OK;
+ }else{
+ Vdbe *v = (Vdbe*)pStmt;
+ sqlite3_mutex_enter(v->db->mutex);
+ rc = sqlite3VdbeReset(v);
+ sqlite3VdbeMakeReady(v, -1, 0, 0, 0);
+ assert( (rc & (v->db->errMask))==rc );
+ sqlite3_mutex_leave(v->db->mutex);
+ }
+ return rc;
+}
+
+/*
+** Set all the parameters in the compiled SQL statement to NULL.
+*/
+int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
+ int i;
+ int rc = SQLITE_OK;
+#ifndef SQLITE_MUTEX_NOOP
+ sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->mutex;
+#endif
+ sqlite3_mutex_enter(mutex);
+ for(i=1; rc==SQLITE_OK && i<=sqlite3_bind_parameter_count(pStmt); i++){
+ rc = sqlite3_bind_null(pStmt, i);
+ }
+ sqlite3_mutex_leave(mutex);
+ return rc;
+}
+
+
/**************************** sqlite3_value_ *******************************
** The following routines extract information from a Mem or sqlite3_value
** structure.
@@ -37,6 +102,9 @@ int sqlite3_expired(sqlite3_stmt *pStmt){
const void *sqlite3_value_blob(sqlite3_value *pVal){
Mem *p = (Mem*)pVal;
if( p->flags & (MEM_Blob|MEM_Str) ){
+ sqlite3VdbeMemExpandBlob(p);
+ p->flags &= ~MEM_Str;
+ p->flags |= MEM_Blob;
return p->z;
}else{
return sqlite3_value_text(pVal);
@@ -74,7 +142,6 @@ 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
@@ -87,28 +154,35 @@ void sqlite3_result_blob(
void (*xDel)(void *)
){
assert( n>=0 );
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, 0, xDel);
}
void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetDouble(&pCtx->s, rVal);
}
void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
- pCtx->isError = 1;
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
+ pCtx->isError = SQLITE_ERROR;
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;
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
+ pCtx->isError = SQLITE_ERROR;
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
}
#endif
void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal);
}
void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetInt64(&pCtx->s, iVal);
}
void sqlite3_result_null(sqlite3_context *pCtx){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetNull(&pCtx->s);
}
void sqlite3_result_text(
@@ -117,6 +191,7 @@ void sqlite3_result_text(
int n,
void (*xDel)(void *)
){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, xDel);
}
#ifndef SQLITE_OMIT_UTF16
@@ -126,6 +201,7 @@ void sqlite3_result_text16(
int n,
void (*xDel)(void *)
){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, xDel);
}
void sqlite3_result_text16be(
@@ -134,6 +210,7 @@ void sqlite3_result_text16be(
int n,
void (*xDel)(void *)
){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16BE, xDel);
}
void sqlite3_result_text16le(
@@ -142,29 +219,58 @@ void sqlite3_result_text16le(
int n,
void (*xDel)(void *)
){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16LE, xDel);
}
#endif /* SQLITE_OMIT_UTF16 */
void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemCopy(&pCtx->s, pValue);
}
+void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
+ sqlite3VdbeMemSetZeroBlob(&pCtx->s, n);
+}
+void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
+ pCtx->isError = errCode;
+}
+/* Force an SQLITE_TOOBIG error. */
+void sqlite3_result_error_toobig(sqlite3_context *pCtx){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
+ sqlite3VdbeMemSetZeroBlob(&pCtx->s, SQLITE_MAX_LENGTH+1);
+}
+
+/* An SQLITE_NOMEM error. */
+void sqlite3_result_error_nomem(sqlite3_context *pCtx){
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
+ sqlite3VdbeMemSetNull(&pCtx->s);
+ pCtx->isError = SQLITE_NOMEM;
+ pCtx->s.db->mallocFailed = 1;
+}
/*
** Execute the statement pStmt, either until a row of data is ready, the
** statement is completely executed or an error occurs.
+**
+** This routine implements the bulk of the logic behind the sqlite_step()
+** API. The only thing omitted is the automatic recompile if a
+** schema change has occurred. That detail is handled by the
+** outer sqlite3_step() wrapper procedure.
*/
-int sqlite3_step(sqlite3_stmt *pStmt){
- Vdbe *p = (Vdbe*)pStmt;
+static int sqlite3Step(Vdbe *p){
sqlite3 *db;
int rc;
- /* Assert that malloc() has not failed */
- assert( !sqlite3MallocFailed() );
-
- if( p==0 || p->magic!=VDBE_MAGIC_RUN ){
+ assert(p);
+ if( p->magic!=VDBE_MAGIC_RUN ){
return SQLITE_MISUSE;
}
+
+ /* Assert that malloc() has not failed */
+ db = p->db;
+ assert( !db->mallocFailed );
+
if( p->aborted ){
return SQLITE_ABORT;
}
@@ -172,9 +278,9 @@ int sqlite3_step(sqlite3_stmt *pStmt){
if( p->rc==SQLITE_OK ){
p->rc = SQLITE_SCHEMA;
}
- return SQLITE_ERROR;
+ rc = SQLITE_ERROR;
+ goto end_of_step;
}
- db = p->db;
if( sqlite3SafetyOn(db) ){
p->rc = SQLITE_MISUSE;
return SQLITE_MISUSE;
@@ -189,36 +295,13 @@ int sqlite3_step(sqlite3_stmt *pStmt){
}
#ifndef SQLITE_OMIT_TRACE
- /* Invoke the trace callback if there is one
- */
- if( db->xTrace && !db->init.busy ){
- assert( p->nOp>0 );
- assert( p->aOp[p->nOp-1].opcode==OP_Noop );
- assert( p->aOp[p->nOp-1].p3!=0 );
- assert( p->aOp[p->nOp-1].p3type==P3_DYNAMIC );
- sqlite3SafetyOff(db);
- db->xTrace(db->pTraceArg, p->aOp[p->nOp-1].p3);
- if( sqlite3SafetyOn(db) ){
- p->rc = SQLITE_MISUSE;
- return SQLITE_MISUSE;
- }
- }
if( db->xProfile && !db->init.busy ){
double rNow;
- sqlite3OsCurrentTime(&rNow);
+ sqlite3OsCurrentTime(db->pVfs, &rNow);
p->startTime = (rNow - (int)rNow)*3600.0*24.0*1000000000.0;
}
#endif
- /* Print a copy of SQL as it is executed if the SQL_TRACE pragma is turned
- ** on in debugging mode.
- */
-#ifdef SQLITE_DEBUG
- if( (db->flags & SQLITE_SqlTrace)!=0 ){
- sqlite3DebugPrintf("SQL-trace: %s\n", p->aOp[p->nOp-1].p3);
- }
-#endif /* SQLITE_DEBUG */
-
db->activeVdbeCnt++;
p->pc = 0;
}
@@ -238,24 +321,88 @@ int sqlite3_step(sqlite3_stmt *pStmt){
#ifndef SQLITE_OMIT_TRACE
/* Invoke the profile callback if there is one
*/
- if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy ){
+ if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->nOp>0
+ && p->aOp[0].opcode==OP_Trace && p->aOp[0].p4.z!=0 ){
double rNow;
u64 elapseTime;
- sqlite3OsCurrentTime(&rNow);
+ sqlite3OsCurrentTime(db->pVfs, &rNow);
elapseTime = (rNow - (int)rNow)*3600.0*24.0*1000000000.0 - p->startTime;
- assert( p->nOp>0 );
- assert( p->aOp[p->nOp-1].opcode==OP_Noop );
- assert( p->aOp[p->nOp-1].p3!=0 );
- assert( p->aOp[p->nOp-1].p3type==P3_DYNAMIC );
- db->xProfile(db->pProfileArg, p->aOp[p->nOp-1].p3, elapseTime);
+ db->xProfile(db->pProfileArg, p->aOp[0].p4.z, elapseTime);
}
#endif
sqlite3Error(p->db, rc, 0);
p->rc = sqlite3ApiExit(p->db, p->rc);
+end_of_step:
+ assert( (rc&0xff)==rc );
+ if( p->zSql && (rc&0xff)<SQLITE_ROW ){
+ /* This behavior occurs if sqlite3_prepare_v2() was used to build
+ ** the prepared statement. Return error codes directly */
+ sqlite3Error(p->db, p->rc, 0);
+ return p->rc;
+ }else{
+ /* This is for legacy sqlite3_prepare() builds and when the code
+ ** is SQLITE_ROW or SQLITE_DONE */
+ return rc;
+ }
+}
+
+/*
+** This is the top-level implementation of sqlite3_step(). Call
+** sqlite3Step() to do most of the work. If a schema error occurs,
+** call sqlite3Reprepare() and try again.
+*/
+#ifdef SQLITE_OMIT_PARSER
+int sqlite3_step(sqlite3_stmt *pStmt){
+ int rc = SQLITE_MISUSE;
+ if( pStmt ){
+ Vdbe *v;
+ v = (Vdbe*)pStmt;
+ sqlite3_mutex_enter(v->db->mutex);
+ rc = sqlite3Step(v);
+ sqlite3_mutex_leave(v->db->mutex);
+ }
+ return rc;
+}
+#else
+int sqlite3_step(sqlite3_stmt *pStmt){
+ int rc = SQLITE_MISUSE;
+ if( pStmt ){
+ int cnt = 0;
+ Vdbe *v = (Vdbe*)pStmt;
+ sqlite3 *db = v->db;
+ sqlite3_mutex_enter(db->mutex);
+ while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
+ && cnt++ < 5
+ && sqlite3Reprepare(v) ){
+ sqlite3_reset(pStmt);
+ v->expired = 0;
+ }
+ if( rc==SQLITE_SCHEMA && v->zSql && db->pErr ){
+ /* This case occurs after failing to recompile an sql statement.
+ ** The error message from the SQL compiler has already been loaded
+ ** into the database handle. This block copies the error message
+ ** from the database handle into the statement and sets the statement
+ ** program counter to 0 to ensure that when the statement is
+ ** finalized or reset the parser error message is available via
+ ** sqlite3_errmsg() and sqlite3_errcode().
+ */
+ const char *zErr = (const char *)sqlite3_value_text(db->pErr);
+ sqlite3_free(v->zErrMsg);
+ if( !db->mallocFailed ){
+ v->zErrMsg = sqlite3DbStrDup(db, zErr);
+ } else {
+ v->zErrMsg = 0;
+ v->rc = SQLITE_NOMEM;
+ }
+ }
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
+ }
return rc;
}
+#endif
/*
** Extract the user data from a sqlite3_context structure and return a
@@ -267,27 +414,45 @@ void *sqlite3_user_data(sqlite3_context *p){
}
/*
+** The following is the implementation of an SQL function that always
+** fails with an error message stating that the function is used in the
+** wrong context. The sqlite3_overload_function() API might construct
+** SQL function that use this routine so that the functions will exist
+** for name resolution but are actually overloaded by the xFindFunction
+** method of virtual tables.
+*/
+void sqlite3InvalidFunction(
+ sqlite3_context *context, /* The function calling context */
+ int argc, /* Number of arguments to the function */
+ sqlite3_value **argv /* Value of each argument */
+){
+ const char *zName = context->pFunc->zName;
+ char *zErr;
+ zErr = sqlite3MPrintf(0,
+ "unable to use function %s in the requested context", zName);
+ sqlite3_result_error(context, zErr, -1);
+ sqlite3_free(zErr);
+}
+
+/*
** Allocate or return the aggregate context for a user function. A new
** context is allocated on the first call. Subsequent calls return the
** same context that was returned on prior calls.
*/
void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
- Mem *pMem = p->pMem;
+ Mem *pMem;
assert( p && p->pFunc && p->pFunc->xStep );
+ assert( sqlite3_mutex_held(p->s.db->mutex) );
+ pMem = p->pMem;
if( (pMem->flags & MEM_Agg)==0 ){
if( nByte==0 ){
assert( pMem->flags==MEM_Null );
pMem->z = 0;
}else{
pMem->flags = MEM_Agg;
- pMem->xDel = sqlite3FreeX;
- *(FuncDef**)&pMem->i = p->pFunc;
- if( nByte<=NBFS ){
- pMem->z = pMem->zShort;
- memset(pMem->z, 0, nByte);
- }else{
- pMem->z = sqliteMalloc( nByte );
- }
+ pMem->xDel = sqlite3_free;
+ pMem->u.pDef = p->pFunc;
+ pMem->z = sqlite3DbMallocZero(p->s.db, nByte);
}
}
return (void*)pMem->z;
@@ -298,7 +463,10 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
** the user-function defined by pCtx.
*/
void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
- VdbeFunc *pVdbeFunc = pCtx->pVdbeFunc;
+ VdbeFunc *pVdbeFunc;
+
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
+ pVdbeFunc = pCtx->pVdbeFunc;
if( !pVdbeFunc || iArg>=pVdbeFunc->nAux || iArg<0 ){
return 0;
}
@@ -318,16 +486,19 @@ void sqlite3_set_auxdata(
){
struct AuxData *pAuxData;
VdbeFunc *pVdbeFunc;
- if( iArg<0 ) return;
+ if( iArg<0 ) goto failed;
+ assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
pVdbeFunc = pCtx->pVdbeFunc;
if( !pVdbeFunc || pVdbeFunc->nAux<=iArg ){
+ int nAux = (pVdbeFunc ? pVdbeFunc->nAux : 0);
int nMalloc = sizeof(VdbeFunc) + sizeof(struct AuxData)*iArg;
- pVdbeFunc = sqliteRealloc(pVdbeFunc, nMalloc);
- if( !pVdbeFunc ) return;
+ pVdbeFunc = sqlite3DbRealloc(pCtx->s.db, pVdbeFunc, nMalloc);
+ if( !pVdbeFunc ){
+ goto failed;
+ }
pCtx->pVdbeFunc = pVdbeFunc;
- memset(&pVdbeFunc->apAux[pVdbeFunc->nAux], 0,
- sizeof(struct AuxData)*(iArg+1-pVdbeFunc->nAux));
+ memset(&pVdbeFunc->apAux[nAux], 0, sizeof(struct AuxData)*(iArg+1-nAux));
pVdbeFunc->nAux = iArg+1;
pVdbeFunc->pFunc = pCtx->pFunc;
}
@@ -338,6 +509,12 @@ void sqlite3_set_auxdata(
}
pAuxData->pAux = pAux;
pAuxData->xDelete = xDelete;
+ return;
+
+failed:
+ if( xDelete ){
+ xDelete(pAux);
+ }
}
/*
@@ -368,7 +545,7 @@ int sqlite3_column_count(sqlite3_stmt *pStmt){
*/
int sqlite3_data_count(sqlite3_stmt *pStmt){
Vdbe *pVm = (Vdbe *)pStmt;
- if( pVm==0 || !pVm->resOnStack ) return 0;
+ if( pVm==0 || pVm->pResultSet==0 ) return 0;
return pVm->nResColumn;
}
@@ -380,14 +557,24 @@ int sqlite3_data_count(sqlite3_stmt *pStmt){
** of NULL.
*/
static Mem *columnMem(sqlite3_stmt *pStmt, int i){
- Vdbe *pVm = (Vdbe *)pStmt;
- int vals = sqlite3_data_count(pStmt);
- if( i>=vals || i<0 ){
- static const Mem nullMem = {0, 0.0, "", 0, MEM_Null, MEM_Null };
- sqlite3Error(pVm->db, SQLITE_RANGE, 0);
- return (Mem*)&nullMem;
+ Vdbe *pVm;
+ int vals;
+ Mem *pOut;
+
+ pVm = (Vdbe *)pStmt;
+ if( pVm && pVm->pResultSet!=0 && i<pVm->nResColumn && i>=0 ){
+ sqlite3_mutex_enter(pVm->db->mutex);
+ vals = sqlite3_data_count(pStmt);
+ pOut = &pVm->pResultSet[i];
+ }else{
+ static const Mem nullMem = {{0}, 0.0, 0, "", 0, MEM_Null, SQLITE_NULL };
+ if( pVm->db ){
+ sqlite3_mutex_enter(pVm->db->mutex);
+ sqlite3Error(pVm->db, SQLITE_RANGE, 0);
+ }
+ pOut = (Mem*)&nullMem;
}
- return &pVm->pTos[(1-vals)+i];
+ return pOut;
}
/*
@@ -397,7 +584,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
** 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:
+** Specifically, this is called from within:
**
** sqlite3_column_int()
** sqlite3_column_int64()
@@ -417,7 +604,10 @@ static void columnMallocFailure(sqlite3_stmt *pStmt)
** and _finalize() will return NOMEM.
*/
Vdbe *p = (Vdbe *)pStmt;
- p->rc = sqlite3ApiExit(0, p->rc);
+ if( p ){
+ p->rc = sqlite3ApiExit(p->db, p->rc);
+ sqlite3_mutex_leave(p->db->mutex);
+ }
}
/**************************** sqlite3_column_ *******************************
@@ -426,9 +616,12 @@ static void columnMallocFailure(sqlite3_stmt *pStmt)
*/
const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
const void *val;
- sqlite3MallocDisallow();
val = sqlite3_value_blob( columnMem(pStmt,i) );
- sqlite3MallocAllow();
+ /* Even though there is no encoding conversion, value_blob() might
+ ** need to call malloc() to expand the result of a zeroblob()
+ ** expression.
+ */
+ columnMallocFailure(pStmt);
return val;
}
int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
@@ -462,7 +655,9 @@ const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
return val;
}
sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
- return columnMem(pStmt, i);
+ sqlite3_value *pOut = columnMem(pStmt, i);
+ columnMallocFailure(pStmt);
+ return pOut;
}
#ifndef SQLITE_OMIT_UTF16
const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
@@ -472,7 +667,9 @@ const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
}
#endif /* SQLITE_OMIT_UTF16 */
int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
- return sqlite3_value_type( columnMem(pStmt,i) );
+ int iType = sqlite3_value_type( columnMem(pStmt,i) );
+ columnMallocFailure(pStmt);
+ return iType;
}
/* The following function is experimental and subject to change or
@@ -504,20 +701,28 @@ static const void *columnName(
const void *(*xFunc)(Mem*),
int useType
){
- const void *ret;
+ const void *ret = 0;
Vdbe *p = (Vdbe *)pStmt;
- int n = sqlite3_column_count(pStmt);
+ int n;
+
- if( p==0 || N>=n || N<0 ){
- return 0;
- }
- N += useType*n;
- ret = xFunc(&p->aColName[N]);
+ if( p!=0 ){
+ n = sqlite3_column_count(pStmt);
+ if( N<n && N>=0 ){
+ N += useType*n;
+ sqlite3_mutex_enter(p->db->mutex);
+ 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);
+ /* A malloc may have failed inside of the xFunc() call. If this
+ ** is the case, clear the mallocFailed flag and return NULL.
+ */
+ if( p->db && p->db->mallocFailed ){
+ p->db->mallocFailed = 0;
+ ret = 0;
+ }
+ sqlite3_mutex_leave(p->db->mutex);
+ }
+ }
return ret;
}
@@ -636,29 +841,33 @@ static int vdbeUnbind(Vdbe *p, int i){
** Bind a text or BLOB value.
*/
static int bindText(
- sqlite3_stmt *pStmt,
- int i,
- const void *zData,
- int nData,
- void (*xDel)(void*),
- int encoding
+ sqlite3_stmt *pStmt, /* The statement to bind against */
+ int i, /* Index of the parameter to bind */
+ const void *zData, /* Pointer to the data to be bound */
+ int nData, /* Number of bytes of data to be bound */
+ void (*xDel)(void*), /* Destructor for the data */
+ int encoding /* Encoding for the data */
){
Vdbe *p = (Vdbe *)pStmt;
Mem *pVar;
int rc;
- rc = vdbeUnbind(p, i);
- if( rc || zData==0 ){
- return rc;
+ if( p==0 ){
+ return SQLITE_MISUSE;
}
- pVar = &p->aVar[i-1];
- rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel);
- if( rc==SQLITE_OK && encoding!=0 ){
- rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db));
+ sqlite3_mutex_enter(p->db->mutex);
+ rc = vdbeUnbind(p, i);
+ if( rc==SQLITE_OK && zData!=0 ){
+ pVar = &p->aVar[i-1];
+ rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel);
+ if( rc==SQLITE_OK && encoding!=0 ){
+ rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db));
+ }
+ sqlite3Error(p->db, rc, 0);
+ rc = sqlite3ApiExit(p->db, rc);
}
-
- sqlite3Error(((Vdbe *)pStmt)->db, rc, 0);
- return sqlite3ApiExit(((Vdbe *)pStmt)->db, rc);
+ sqlite3_mutex_leave(p->db->mutex);
+ return rc;
}
@@ -677,10 +886,12 @@ int sqlite3_bind_blob(
int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
+ sqlite3_mutex_enter(p->db->mutex);
rc = vdbeUnbind(p, i);
if( rc==SQLITE_OK ){
sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
}
+ sqlite3_mutex_leave(p->db->mutex);
return rc;
}
int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
@@ -689,14 +900,21 @@ int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
+ sqlite3_mutex_enter(p->db->mutex);
rc = vdbeUnbind(p, i);
if( rc==SQLITE_OK ){
sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
}
+ sqlite3_mutex_leave(p->db->mutex);
return rc;
}
-int sqlite3_bind_null(sqlite3_stmt* p, int i){
- return vdbeUnbind((Vdbe *)p, i);
+int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
+ int rc;
+ Vdbe *p = (Vdbe*)pStmt;
+ sqlite3_mutex_enter(p->db->mutex);
+ rc = vdbeUnbind(p, i);
+ sqlite3_mutex_leave(p->db->mutex);
+ return rc;
}
int sqlite3_bind_text(
sqlite3_stmt *pStmt,
@@ -721,10 +939,23 @@ int sqlite3_bind_text16(
int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
+ sqlite3_mutex_enter(p->db->mutex);
+ rc = vdbeUnbind(p, i);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3VdbeMemCopy(&p->aVar[i-1], pValue);
+ }
+ sqlite3_mutex_leave(p->db->mutex);
+ return rc;
+}
+int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
+ int rc;
+ Vdbe *p = (Vdbe *)pStmt;
+ sqlite3_mutex_enter(p->db->mutex);
rc = vdbeUnbind(p, i);
if( rc==SQLITE_OK ){
- sqlite3VdbeMemCopy(&p->aVar[i-1], pValue);
+ sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
}
+ sqlite3_mutex_leave(p->db->mutex);
return rc;
}
@@ -744,15 +975,19 @@ int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
*/
static void createVarMap(Vdbe *p){
if( !p->okVar ){
- int j;
- Op *pOp;
- for(j=0, pOp=p->aOp; j<p->nOp; j++, pOp++){
- if( pOp->opcode==OP_Variable ){
- assert( pOp->p1>0 && pOp->p1<=p->nVar );
- p->azVar[pOp->p1-1] = pOp->p3;
+ sqlite3_mutex_enter(p->db->mutex);
+ if( !p->okVar ){
+ int j;
+ Op *pOp;
+ for(j=0, pOp=p->aOp; j<p->nOp; j++, pOp++){
+ if( pOp->opcode==OP_Variable ){
+ assert( pOp->p1>0 && pOp->p1<=p->nVar );
+ p->azVar[pOp->p1-1] = pOp->p4.z;
+ }
}
+ p->okVar = 1;
}
- p->okVar = 1;
+ sqlite3_mutex_leave(p->db->mutex);
}
}
@@ -804,17 +1039,19 @@ int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
Vdbe *pTo = (Vdbe*)pToStmt;
int i, rc = SQLITE_OK;
if( (pFrom->magic!=VDBE_MAGIC_RUN && pFrom->magic!=VDBE_MAGIC_HALT)
- || (pTo->magic!=VDBE_MAGIC_RUN && pTo->magic!=VDBE_MAGIC_HALT) ){
+ || (pTo->magic!=VDBE_MAGIC_RUN && pTo->magic!=VDBE_MAGIC_HALT)
+ || pTo->db!=pFrom->db ){
return SQLITE_MISUSE;
}
if( pFrom->nVar!=pTo->nVar ){
return SQLITE_ERROR;
}
+ sqlite3_mutex_enter(pTo->db->mutex);
for(i=0; rc==SQLITE_OK && i<pFrom->nVar; i++){
- sqlite3MallocDisallow();
- rc = sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]);
- sqlite3MallocAllow();
+ sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]);
}
+ sqlite3_mutex_leave(pTo->db->mutex);
+ assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
return rc;
}
diff --git a/ext/pdo_sqlite/sqlite/src/vdbeaux.c b/ext/pdo_sqlite/sqlite/src/vdbeaux.c
index c71c8f4ea6..c15207b9be 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbeaux.c
+++ b/ext/pdo_sqlite/sqlite/src/vdbeaux.c
@@ -15,11 +15,11 @@
** But that file was getting too big so this subroutines were split out.
*/
#include "sqliteInt.h"
-#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"
+
/*
** When debugging the code generator in a symbolic debugger, one can
** set the sqlite3_vdbe_addop_trace to 1 and all opcodes will be printed
@@ -35,7 +35,7 @@ int sqlite3_vdbe_addop_trace = 0;
*/
Vdbe *sqlite3VdbeCreate(sqlite3 *db){
Vdbe *p;
- p = sqliteMalloc( sizeof(Vdbe) );
+ p = sqlite3DbMallocZero(db, sizeof(Vdbe) );
if( p==0 ) return 0;
p->db = db;
if( db->pVdbe ){
@@ -49,18 +49,57 @@ Vdbe *sqlite3VdbeCreate(sqlite3 *db){
}
/*
+** Remember the SQL string for a prepared statement.
+*/
+void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n){
+ if( p==0 ) return;
+ assert( p->zSql==0 );
+ p->zSql = sqlite3DbStrNDup(p->db, z, n);
+}
+
+/*
+** Return the SQL associated with a prepared statement
+*/
+const char *sqlite3_sql(sqlite3_stmt *pStmt){
+ return ((Vdbe *)pStmt)->zSql;
+}
+
+/*
+** Swap all content between two VDBE structures.
+*/
+void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
+ Vdbe tmp, *pTmp;
+ char *zTmp;
+ int nTmp;
+ tmp = *pA;
+ *pA = *pB;
+ *pB = tmp;
+ pTmp = pA->pNext;
+ pA->pNext = pB->pNext;
+ pB->pNext = pTmp;
+ pTmp = pA->pPrev;
+ pA->pPrev = pB->pPrev;
+ pB->pPrev = pTmp;
+ zTmp = pA->zSql;
+ pA->zSql = pB->zSql;
+ pB->zSql = zTmp;
+ nTmp = pA->nSql;
+ pA->nSql = pB->nSql;
+ pB->nSql = nTmp;
+}
+
+#ifdef SQLITE_DEBUG
+/*
** Turn tracing on or off
*/
void sqlite3VdbeTrace(Vdbe *p, FILE *trace){
p->trace = trace;
}
+#endif
/*
** 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. Vdbe.nOpAlloc is set to reflect the new size of
-** the array.
+** elements.
**
** If an out-of-memory error occurs while resizing the array,
** Vdbe.aOp and Vdbe.nOpAlloc remain unchanged (this is so that
@@ -68,18 +107,14 @@ void sqlite3VdbeTrace(Vdbe *p, FILE *trace){
** along with the rest of the Vdbe).
*/
static void resizeOpArray(Vdbe *p, int N){
- int runMode = p->magic==VDBE_MAGIC_RUN;
- if( runMode || p->nOpAlloc<N ){
- VdbeOp *pNew;
- int nNew = N + 100*(!runMode);
- int oldSize = p->nOpAlloc;
- pNew = sqliteRealloc(p->aOp, nNew*sizeof(Op));
- if( pNew ){
- p->nOpAlloc = nNew;
- p->aOp = pNew;
- if( nNew>oldSize ){
- memset(&p->aOp[oldSize], 0, (nNew-oldSize)*sizeof(Op));
- }
+ VdbeOp *pNew;
+ int oldSize = p->nOpAlloc;
+ pNew = sqlite3DbRealloc(p->db, p->aOp, N*sizeof(Op));
+ if( pNew ){
+ p->nOpAlloc = N;
+ p->aOp = pNew;
+ if( N>oldSize ){
+ memset(&p->aOp[oldSize], 0, (N-oldSize)*sizeof(Op));
}
}
}
@@ -94,44 +129,63 @@ static void resizeOpArray(Vdbe *p, int N){
**
** op The opcode for this instruction
**
-** p1, p2 First two of the three possible operands.
+** p1, p2, p3 Operands
**
** Use the sqlite3VdbeResolveLabel() function to fix an address and
-** the sqlite3VdbeChangeP3() function to change the value of the P3
+** the sqlite3VdbeChangeP4() function to change the value of the P4
** operand.
*/
-int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
+int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
int i;
VdbeOp *pOp;
i = p->nOp;
- p->nOp++;
assert( p->magic==VDBE_MAGIC_INIT );
if( p->nOpAlloc<=i ){
- resizeOpArray(p, i+1);
- if( sqlite3MallocFailed() ){
+ resizeOpArray(p, p->nOpAlloc*2 + 100);
+ if( p->db->mallocFailed ){
return 0;
}
}
+ p->nOp++;
pOp = &p->aOp[i];
pOp->opcode = op;
pOp->p1 = p1;
pOp->p2 = p2;
- pOp->p3 = 0;
- pOp->p3type = P3_NOTUSED;
+ pOp->p3 = p3;
+ pOp->p4.p = 0;
+ pOp->p4type = P4_NOTUSED;
p->expired = 0;
#ifdef SQLITE_DEBUG
if( sqlite3_vdbe_addop_trace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
#endif
return i;
}
+int sqlite3VdbeAddOp0(Vdbe *p, int op){
+ return sqlite3VdbeAddOp3(p, op, 0, 0, 0);
+}
+int sqlite3VdbeAddOp1(Vdbe *p, int op, int p1){
+ return sqlite3VdbeAddOp3(p, op, p1, 0, 0);
+}
+int sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){
+ return sqlite3VdbeAddOp3(p, op, p1, p2, 0);
+}
+
/*
-** Add an opcode that includes the p3 value.
+** Add an opcode that includes the p4 value as a pointer.
*/
-int sqlite3VdbeOp3(Vdbe *p, int op, int p1, int p2, const char *zP3,int p3type){
- int addr = sqlite3VdbeAddOp(p, op, p1, p2);
- sqlite3VdbeChangeP3(p, addr, zP3, p3type);
+int sqlite3VdbeAddOp4(
+ Vdbe *p, /* Add the opcode to this VM */
+ int op, /* The new opcode */
+ int p1, /* The P1 operand */
+ int p2, /* The P2 operand */
+ int p3, /* The P3 operand */
+ const char *zP4, /* The P4 operand */
+ int p4type /* P4 operand type */
+){
+ int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3);
+ sqlite3VdbeChangeP4(p, addr, zP4, p4type);
return addr;
}
@@ -155,8 +209,8 @@ int sqlite3VdbeMakeLabel(Vdbe *p){
assert( p->magic==VDBE_MAGIC_INIT );
if( i>=p->nLabelAlloc ){
p->nLabelAlloc = p->nLabelAlloc*2 + 10;
- sqliteReallocOrFree((void**)&p->aLabel,
- p->nLabelAlloc*sizeof(p->aLabel[0]));
+ p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel,
+ p->nLabelAlloc*sizeof(p->aLabel[0]));
}
if( p->aLabel ){
p->aLabel[i] = -1;
@@ -179,51 +233,9 @@ void sqlite3VdbeResolveLabel(Vdbe *p, int x){
}
/*
-** Return non-zero if opcode 'op' is guarenteed not to push more values
-** onto the VDBE stack than it pops off.
-*/
-static int opcodeNoPush(u8 op){
- /* The 10 NOPUSH_MASK_n constants are defined in the automatically
- ** generated header file opcodes.h. Each is a 16-bit bitmask, one
- ** bit corresponding to each opcode implemented by the virtual
- ** machine in vdbe.c. The bit is true if the word "no-push" appears
- ** in a comment on the same line as the "case OP_XXX:" in
- ** sqlite3VdbeExec() in vdbe.c.
- **
- ** If the bit is true, then the corresponding opcode is guarenteed not
- ** to grow the stack when it is executed. Otherwise, it may grow the
- ** stack by at most one entry.
- **
- ** NOPUSH_MASK_0 corresponds to opcodes 0 to 15. NOPUSH_MASK_1 contains
- ** one bit for opcodes 16 to 31, and so on.
- **
- ** 16-bit bitmasks (rather than 32-bit) are specified in opcodes.h
- ** because the file is generated by an awk program. Awk manipulates
- ** all numbers as floating-point and we don't want to risk a rounding
- ** error if someone builds with an awk that uses (for example) 32-bit
- ** IEEE floats.
- */
- static const u32 masks[5] = {
- 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)));
-}
-
-#ifndef NDEBUG
-int sqlite3VdbeOpcodeNoPush(u8 op){
- return opcodeNoPush(op);
-}
-#endif
-
-/*
-** Loop through the program looking for P2 values that are negative.
-** Each such value is a label. Resolve the label by setting the P2
-** value to its correct non-zero value.
+** Loop through the program looking for P2 values that are negative
+** on jump instructions. Each such value is a label. Resolve the
+** label by setting the P2 value to its correct non-zero value.
**
** This routine is called once after all opcodes have been inserted.
**
@@ -231,19 +243,22 @@ int sqlite3VdbeOpcodeNoPush(u8 op){
** 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
-** entries that static analysis reveals this program might need.
-**
** This routine also does the following optimization: It scans for
-** Halt instructions where P1==SQLITE_CONSTRAINT or P2==OE_Abort or for
-** IdxInsert instructions where P2!=0. If no such instruction is
-** found, then every Statement instruction is changed to a Noop. In
-** this way, we avoid creating the statement journal file unnecessarily.
+** instructions that might cause a statement rollback. Such instructions
+** are:
+**
+** * OP_Halt with P1=SQLITE_CONSTRAINT and P2=OE_Abort.
+** * OP_Destroy
+** * OP_VUpdate
+** * OP_VRename
+**
+** If no such instruction is found, then every Statement instruction
+** is changed to a Noop. In this way, we avoid creating the statement
+** journal file unnecessarily.
*/
-static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
+static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
int i;
int nMaxArgs = 0;
- int nMaxStack = p->nOp;
Op *pOp;
int *aLabel = p->aLabel;
int doesStatementRollback = 0;
@@ -251,38 +266,44 @@ 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 ){
+ if( pOp->p5>nMaxArgs ) nMaxArgs = pOp->p5;
+ }else if( opcode==OP_AggStep
#ifndef SQLITE_OMIT_VIRTUALTABLE
|| opcode==OP_VUpdate
#endif
){
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
- }else if( opcode==OP_Halt ){
+ }
+ if( opcode==OP_Halt ){
if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){
doesStatementRollback = 1;
}
}else if( opcode==OP_Statement ){
hasStatementBegin = 1;
+ }else if( opcode==OP_Destroy ){
+ doesStatementRollback = 1;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ }else if( opcode==OP_VUpdate || opcode==OP_VRename ){
+ doesStatementRollback = 1;
}else if( opcode==OP_VFilter ){
int n;
assert( p->nOp - i >= 3 );
- assert( pOp[-2].opcode==OP_Integer );
- n = pOp[-2].p1;
+ assert( pOp[-1].opcode==OP_Integer );
+ n = pOp[-1].p1;
if( n>nMaxArgs ) nMaxArgs = n;
- }
- if( opcodeNoPush(opcode) ){
- nMaxStack--;
+#endif
}
- if( pOp->p2>=0 ) continue;
- assert( -1-pOp->p2<p->nLabel );
- pOp->p2 = aLabel[-1-pOp->p2];
+ if( sqlite3VdbeOpcodeHasProperty(opcode, OPFLG_JUMP) && pOp->p2<0 ){
+ assert( -1-pOp->p2<p->nLabel );
+ pOp->p2 = aLabel[-1-pOp->p2];
+ }
}
- sqliteFree(p->aLabel);
+ sqlite3_free(p->aLabel);
p->aLabel = 0;
*pMaxFuncArgs = nMaxArgs;
- *pMaxStack = nMaxStack;
/* If we never rollback a statement transaction, then statement
** transactions are not needed. So change every OP_Statement
@@ -313,8 +334,10 @@ int sqlite3VdbeCurrentAddr(Vdbe *p){
int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
int addr;
assert( p->magic==VDBE_MAGIC_INIT );
- resizeOpArray(p, p->nOp + nOp);
- if( sqlite3MallocFailed() ){
+ if( p->nOp + nOp > p->nOpAlloc ){
+ resizeOpArray(p, p->nOp*2 + nOp);
+ }
+ if( p->db->mallocFailed ){
return 0;
}
addr = p->nOp;
@@ -326,9 +349,15 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
VdbeOp *pOut = &p->aOp[i+addr];
pOut->opcode = pIn->opcode;
pOut->p1 = pIn->p1;
- pOut->p2 = p2<0 ? addr + ADDR(p2) : p2;
+ if( p2<0 && sqlite3VdbeOpcodeHasProperty(pOut->opcode, OPFLG_JUMP) ){
+ pOut->p2 = addr + ADDR(p2);
+ }else{
+ pOut->p2 = p2;
+ }
pOut->p3 = pIn->p3;
- pOut->p3type = pIn->p3 ? P3_STATIC : P3_NOTUSED;
+ pOut->p4type = P4_NOTUSED;
+ pOut->p4.p = 0;
+ pOut->p5 = 0;
#ifdef SQLITE_DEBUG
if( sqlite3_vdbe_addop_trace ){
sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
@@ -358,7 +387,6 @@ void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
** This routine is useful for setting a jump destination.
*/
void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
- assert( val>=0 );
assert( p==0 || p->magic==VDBE_MAGIC_INIT );
if( p && addr>=0 && p->nOp>addr && p->aOp ){
p->aOp[addr].p2 = val;
@@ -366,6 +394,28 @@ void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
}
/*
+** Change the value of the P3 operand for a specific instruction.
+*/
+void sqlite3VdbeChangeP3(Vdbe *p, int addr, int val){
+ assert( p==0 || p->magic==VDBE_MAGIC_INIT );
+ if( p && addr>=0 && p->nOp>addr && p->aOp ){
+ p->aOp[addr].p3 = val;
+ }
+}
+
+/*
+** Change the value of the P5 operand for the most recently
+** added operation.
+*/
+void sqlite3VdbeChangeP5(Vdbe *p, u8 val){
+ assert( p==0 || p->magic==VDBE_MAGIC_INIT );
+ if( p && p->aOp ){
+ assert( p->nOp>0 );
+ p->aOp[p->nOp-1].p5 = val;
+ }
+}
+
+/*
** Change the P2 operand of instruction addr so that it points to
** the address of the next instruction to be coded.
*/
@@ -380,38 +430,37 @@ void sqlite3VdbeJumpHere(Vdbe *p, int addr){
*/
static void freeEphemeralFunction(FuncDef *pDef){
if( pDef && (pDef->flags & SQLITE_FUNC_EPHEM)!=0 ){
- sqliteFree(pDef);
+ sqlite3_free(pDef);
}
}
/*
-** Delete a P3 value if necessary.
+** Delete a P4 value if necessary.
*/
-static void freeP3(int p3type, void *p3){
+static void freeP4(int p4type, void *p3){
if( p3 ){
- switch( p3type ){
- case P3_DYNAMIC:
- case P3_KEYINFO:
- case P3_KEYINFO_HANDOFF: {
- sqliteFree(p3);
- break;
- }
- case P3_MPRINTF: {
+ switch( p4type ){
+ case P4_REAL:
+ case P4_INT64:
+ case P4_MPRINTF:
+ case P4_DYNAMIC:
+ case P4_KEYINFO:
+ case P4_KEYINFO_HANDOFF: {
sqlite3_free(p3);
break;
}
- case P3_VDBEFUNC: {
+ case P4_VDBEFUNC: {
VdbeFunc *pVdbeFunc = (VdbeFunc *)p3;
freeEphemeralFunction(pVdbeFunc->pFunc);
sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
- sqliteFree(pVdbeFunc);
+ sqlite3_free(pVdbeFunc);
break;
}
- case P3_FUNCDEF: {
+ case P4_FUNCDEF: {
freeEphemeralFunction((FuncDef*)p3);
break;
}
- case P3_MEM: {
+ case P4_MEM: {
sqlite3ValueFree((sqlite3_value*)p3);
break;
}
@@ -424,105 +473,121 @@ 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++;
+ if( p && p->aOp ){
+ VdbeOp *pOp = &p->aOp[addr];
+ while( N-- ){
+ freeP4(pOp->p4type, pOp->p4.p);
+ memset(pOp, 0, sizeof(pOp[0]));
+ pOp->opcode = OP_Noop;
+ pOp++;
+ }
}
}
/*
-** Change the value of the P3 operand for a specific instruction.
+** Change the value of the P4 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
** few minor changes to the program.
**
-** If n>=0 then the P3 operand is dynamic, meaning that a copy of
-** the string is made into memory obtained from sqliteMalloc().
-** A value of n==0 means copy bytes of zP3 up to and including the
-** first null byte. If n>0 then copy n+1 bytes of zP3.
+** If n>=0 then the P4 operand is dynamic, meaning that a copy of
+** the string is made into memory obtained from sqlite3_malloc().
+** A value of n==0 means copy bytes of zP4 up to and including the
+** first null byte. If n>0 then copy n+1 bytes of zP4.
**
-** If n==P3_KEYINFO it means that zP3 is a pointer to a KeyInfo structure.
+** If n==P4_KEYINFO it means that zP4 is a pointer to a KeyInfo structure.
** A copy is made of the KeyInfo structure into memory obtained from
-** sqliteMalloc, to be freed when the Vdbe is finalized.
-** n==P3_KEYINFO_HANDOFF indicates that zP3 points to a KeyInfo structure
-** stored in memory that the caller has obtained from sqliteMalloc. The
+** sqlite3_malloc, to be freed when the Vdbe is finalized.
+** n==P4_KEYINFO_HANDOFF indicates that zP4 points to a KeyInfo structure
+** stored in memory that the caller has obtained from sqlite3_malloc. The
** caller should not free the allocation, it will be freed when the Vdbe is
** finalized.
**
-** Other values of n (P3_STATIC, P3_COLLSEQ etc.) indicate that zP3 points
+** Other values of n (P4_STATIC, P4_COLLSEQ etc.) indicate that zP4 points
** to a string or structure that is guaranteed to exist for the lifetime of
** the Vdbe. In these cases we can just copy the pointer.
**
-** If addr<0 then change P3 on the most recently inserted instruction.
+** If addr<0 then change P4 on the most recently inserted instruction.
*/
-void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
+void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
Op *pOp;
- assert( p==0 || p->magic==VDBE_MAGIC_INIT );
- if( p==0 || p->aOp==0 || sqlite3MallocFailed() ){
- if (n != P3_KEYINFO) {
- freeP3(n, (void*)*(char**)&zP3);
+ assert( p!=0 );
+ assert( p->magic==VDBE_MAGIC_INIT );
+ if( p->aOp==0 || p->db->mallocFailed ){
+ if (n != P4_KEYINFO) {
+ freeP4(n, (void*)*(char**)&zP4);
}
return;
}
- if( addr<0 || addr>=p->nOp ){
+ assert( addr<p->nOp );
+ if( addr<0 ){
addr = p->nOp - 1;
if( addr<0 ) return;
}
pOp = &p->aOp[addr];
- freeP3(pOp->p3type, pOp->p3);
- pOp->p3 = 0;
- if( zP3==0 ){
- pOp->p3 = 0;
- pOp->p3type = P3_NOTUSED;
- }else if( n==P3_KEYINFO ){
+ freeP4(pOp->p4type, pOp->p4.p);
+ pOp->p4.p = 0;
+ if( n==P4_INT32 ){
+ pOp->p4.i = (int)zP4;
+ pOp->p4type = n;
+ }else if( zP4==0 ){
+ pOp->p4.p = 0;
+ pOp->p4type = P4_NOTUSED;
+ }else if( n==P4_KEYINFO ){
KeyInfo *pKeyInfo;
int nField, nByte;
- nField = ((KeyInfo*)zP3)->nField;
+ nField = ((KeyInfo*)zP4)->nField;
nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]) + nField;
- pKeyInfo = sqliteMallocRaw( nByte );
- pOp->p3 = (char*)pKeyInfo;
+ pKeyInfo = sqlite3_malloc( nByte );
+ pOp->p4.pKeyInfo = pKeyInfo;
if( pKeyInfo ){
- unsigned char *aSortOrder;
- memcpy(pKeyInfo, zP3, nByte);
+ memcpy(pKeyInfo, zP4, nByte);
+ /* In the current implementation, P4_KEYINFO is only ever used on
+ ** KeyInfo structures that have no aSortOrder component. Elements
+ ** with an aSortOrder always use P4_KEYINFO_HANDOFF. So we do not
+ ** need to bother with duplicating the aSortOrder. */
+ assert( pKeyInfo->aSortOrder==0 );
+#if 0
aSortOrder = pKeyInfo->aSortOrder;
if( aSortOrder ){
pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
memcpy(pKeyInfo->aSortOrder, aSortOrder, nField);
}
- pOp->p3type = P3_KEYINFO;
+#endif
+ pOp->p4type = P4_KEYINFO;
}else{
- pOp->p3type = P3_NOTUSED;
+ p->db->mallocFailed = 1;
+ pOp->p4type = P4_NOTUSED;
}
- }else if( n==P3_KEYINFO_HANDOFF ){
- pOp->p3 = (char*)zP3;
- pOp->p3type = P3_KEYINFO;
+ }else if( n==P4_KEYINFO_HANDOFF ){
+ pOp->p4.p = (void*)zP4;
+ pOp->p4type = P4_KEYINFO;
}else if( n<0 ){
- pOp->p3 = (char*)zP3;
- pOp->p3type = n;
+ pOp->p4.p = (void*)zP4;
+ pOp->p4type = n;
}else{
- if( n==0 ) n = strlen(zP3);
- pOp->p3 = sqliteStrNDup(zP3, n);
- pOp->p3type = P3_DYNAMIC;
+ if( n==0 ) n = strlen(zP4);
+ pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n);
+ pOp->p4type = P4_DYNAMIC;
}
}
#ifndef NDEBUG
/*
-** Replace the P3 field of the most recently coded instruction with
-** comment text.
+** Change the comment on the the most recently coded instruction.
*/
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
- || sqlite3MallocFailed() );
- va_start(ap, zFormat);
- sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC);
- va_end(ap);
+ assert( p->nOp>0 || p->aOp==0 );
+ assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed );
+ if( p->nOp ){
+ char **pz = &p->aOp[p->nOp-1].zComment;
+ va_start(ap, zFormat);
+ sqlite3_free(*pz);
+ *pz = sqlite3VMPrintf(p->db, zFormat, ap);
+ va_end(ap);
+ }
}
#endif
@@ -531,95 +596,137 @@ void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){
*/
VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
assert( p->magic==VDBE_MAGIC_INIT );
- assert( addr>=0 && addr<p->nOp );
- return &p->aOp[addr];
+ assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed );
+ return ((addr>=0 && addr<p->nOp)?(&p->aOp[addr]):0);
}
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
|| defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
/*
-** Compute a string that describes the P3 parameter for an opcode.
+** Compute a string that describes the P4 parameter for an opcode.
** Use zTemp for any required temporary buffer space.
*/
-static char *displayP3(Op *pOp, char *zTemp, int nTemp){
- char *zP3;
+static char *displayP4(Op *pOp, char *zTemp, int nTemp){
+ char *zP4 = zTemp;
assert( nTemp>=20 );
- switch( pOp->p3type ){
- case P3_KEYINFO: {
+ switch( pOp->p4type ){
+ case P4_KEYINFO: {
int i, j;
- KeyInfo *pKeyInfo = (KeyInfo*)pOp->p3;
- sprintf(zTemp, "keyinfo(%d", pKeyInfo->nField);
+ KeyInfo *pKeyInfo = pOp->p4.pKeyInfo;
+ sqlite3_snprintf(nTemp, zTemp, "keyinfo(%d", pKeyInfo->nField);
i = strlen(zTemp);
for(j=0; j<pKeyInfo->nField; j++){
CollSeq *pColl = pKeyInfo->aColl[j];
if( pColl ){
int n = strlen(pColl->zName);
if( i+n>nTemp-6 ){
- strcpy(&zTemp[i],",...");
+ memcpy(&zTemp[i],",...",4);
break;
}
zTemp[i++] = ',';
if( pKeyInfo->aSortOrder && pKeyInfo->aSortOrder[j] ){
zTemp[i++] = '-';
}
- strcpy(&zTemp[i], pColl->zName);
+ memcpy(&zTemp[i], pColl->zName,n+1);
i += n;
}else if( i+4<nTemp-6 ){
- strcpy(&zTemp[i],",nil");
+ memcpy(&zTemp[i],",nil",4);
i += 4;
}
}
zTemp[i++] = ')';
zTemp[i] = 0;
assert( i<nTemp );
- zP3 = zTemp;
break;
}
- case P3_COLLSEQ: {
- CollSeq *pColl = (CollSeq*)pOp->p3;
- sprintf(zTemp, "collseq(%.20s)", pColl->zName);
- zP3 = zTemp;
+ case P4_COLLSEQ: {
+ CollSeq *pColl = pOp->p4.pColl;
+ sqlite3_snprintf(nTemp, zTemp, "collseq(%.20s)", pColl->zName);
break;
}
- case P3_FUNCDEF: {
- FuncDef *pDef = (FuncDef*)pOp->p3;
+ case P4_FUNCDEF: {
+ FuncDef *pDef = pOp->p4.pFunc;
sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg);
- zP3 = zTemp;
+ break;
+ }
+ case P4_INT64: {
+ sqlite3_snprintf(nTemp, zTemp, "%lld", *pOp->p4.pI64);
+ break;
+ }
+ case P4_INT32: {
+ sqlite3_snprintf(nTemp, zTemp, "%d", pOp->p4.i);
+ break;
+ }
+ case P4_REAL: {
+ sqlite3_snprintf(nTemp, zTemp, "%.16g", *pOp->p4.pReal);
+ break;
+ }
+ case P4_MEM: {
+ Mem *pMem = pOp->p4.pMem;
+ assert( (pMem->flags & MEM_Null)==0 );
+ if( pMem->flags & MEM_Str ){
+ zP4 = pMem->z;
+ }else if( pMem->flags & MEM_Int ){
+ sqlite3_snprintf(nTemp, zTemp, "%lld", pMem->u.i);
+ }else if( pMem->flags & MEM_Real ){
+ sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->r);
+ }
break;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
- case P3_VTAB: {
- sqlite3_vtab *pVtab = (sqlite3_vtab*)pOp->p3;
+ case P4_VTAB: {
+ sqlite3_vtab *pVtab = pOp->p4.pVtab;
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 ){
- zP3 = "";
+ zP4 = pOp->p4.z;
+ if( zP4==0 ){
+ zP4 = zTemp;
+ zTemp[0] = 0;
}
}
}
- assert( zP3!=0 );
- return zP3;
+ assert( zP4!=0 );
+ return zP4;
}
#endif
+/*
+** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
+**
+*/
+void sqlite3VdbeUsesBtree(Vdbe *p, int i){
+ int mask;
+ assert( i>=0 && i<p->db->nDb );
+ assert( i<sizeof(p->btreeMask)*8 );
+ mask = 1<<i;
+ if( (p->btreeMask & mask)==0 ){
+ p->btreeMask |= mask;
+ sqlite3BtreeMutexArrayInsert(&p->aMutex, p->db->aDb[i].pBt);
+ }
+}
+
#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
/*
** Print a single opcode. This routine is used for debugging only.
*/
void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
- char *zP3;
+ char *zP4;
char zPtr[50];
- static const char *zFormat1 = "%4d %-13s %4d %4d %s\n";
+ static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-4s %.2X %s\n";
if( pOut==0 ) pOut = stdout;
- zP3 = displayP3(pOp, zPtr, sizeof(zPtr));
- fprintf(pOut, zFormat1,
- pc, sqlite3OpcodeNames[pOp->opcode], pOp->p1, pOp->p2, zP3);
+ zP4 = displayP4(pOp, zPtr, sizeof(zPtr));
+ fprintf(pOut, zFormat1, pc,
+ sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5,
+#ifdef SQLITE_DEBUG
+ pOp->zComment ? pOp->zComment : ""
+#else
+ ""
+#endif
+ );
fflush(pOut);
}
#endif
@@ -630,7 +737,8 @@ void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
static void releaseMemArray(Mem *p, int N){
if( p ){
while( N-->0 ){
- sqlite3VdbeMemRelease(p++);
+ assert( N<2 || p[0].db==p[1].db );
+ sqlite3VdbeMemSetNull(p++);
}
}
}
@@ -642,6 +750,11 @@ static void releaseMemArray(Mem *p, int N){
** The interface is the same as sqlite3VdbeExec(). But instead of
** running the code, it invokes the callback once for each instruction.
** This feature is used to implement "EXPLAIN".
+**
+** When p->explain==1, each instruction is listed. When
+** p->explain==2, only OP_Explain instructions are listed and these
+** are shown in a different format. p->explain==2 is used to implement
+** EXPLAIN QUERY PLAN.
*/
int sqlite3VdbeList(
Vdbe *p /* The VDBE */
@@ -649,20 +762,18 @@ int sqlite3VdbeList(
sqlite3 *db = p->db;
int i;
int rc = SQLITE_OK;
+ Mem *pMem = p->pResultSet = &p->aMem[1];
assert( p->explain );
if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
assert( db->magic==SQLITE_MAGIC_BUSY );
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY );
- /* Even though this opcode does not put dynamic strings onto the
- ** the stack, they may become dynamic if the user calls
+ /* Even though this opcode does not use dynamic strings for
+ ** the result, result columns may become dynamic if the user calls
** sqlite3_column_text16(), causing a translation to UTF-16 encoding.
*/
- if( p->pTos==&p->aStack[4] ){
- releaseMemArray(p->aStack, 5);
- }
- p->resOnStack = 0;
+ releaseMemArray(pMem, p->nMem);
do{
i = p->pc++;
@@ -676,63 +787,120 @@ int sqlite3VdbeList(
sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(p->rc), (char*)0);
}else{
Op *pOp = &p->aOp[i];
- Mem *pMem = p->aStack;
- pMem->flags = MEM_Int;
- pMem->type = SQLITE_INTEGER;
- pMem->i = i; /* Program counter */
- pMem++;
-
- 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;
- pMem++;
+ if( p->explain==1 ){
+ pMem->flags = MEM_Int;
+ pMem->type = SQLITE_INTEGER;
+ pMem->u.i = i; /* Program counter */
+ pMem++;
+
+ pMem->flags = MEM_Static|MEM_Str|MEM_Term;
+ pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
+ assert( pMem->z!=0 );
+ pMem->n = strlen(pMem->z);
+ pMem->type = SQLITE_TEXT;
+ pMem->enc = SQLITE_UTF8;
+ pMem++;
+ }
pMem->flags = MEM_Int;
- pMem->i = pOp->p1; /* P1 */
+ pMem->u.i = pOp->p1; /* P1 */
pMem->type = SQLITE_INTEGER;
pMem++;
pMem->flags = MEM_Int;
- pMem->i = pOp->p2; /* P2 */
+ pMem->u.i = pOp->p2; /* P2 */
pMem->type = SQLITE_INTEGER;
pMem++;
- pMem->flags = MEM_Ephem|MEM_Str|MEM_Term; /* P3 */
- pMem->z = displayP3(pOp, pMem->zShort, sizeof(pMem->zShort));
+ if( p->explain==1 ){
+ pMem->flags = MEM_Int;
+ pMem->u.i = pOp->p3; /* P3 */
+ pMem->type = SQLITE_INTEGER;
+ pMem++;
+ }
+
+ pMem->flags = MEM_Ephem|MEM_Str|MEM_Term; /* P4 */
+ pMem->z = displayP4(pOp, pMem->zShort, sizeof(pMem->zShort));
assert( pMem->z!=0 );
pMem->n = strlen(pMem->z);
pMem->type = SQLITE_TEXT;
pMem->enc = SQLITE_UTF8;
+ pMem++;
- p->nResColumn = 5 - 2*(p->explain-1);
- p->pTos = pMem;
+ if( p->explain==1 ){
+ pMem->flags = MEM_Str|MEM_Term|MEM_Short;
+ pMem->n = sprintf(pMem->zShort, "%.2x", pOp->p5); /* P5 */
+ pMem->z = pMem->zShort;
+ pMem->type = SQLITE_TEXT;
+ pMem->enc = SQLITE_UTF8;
+ pMem++;
+
+ pMem->flags = MEM_Null; /* Comment */
+#ifdef SQLITE_DEBUG
+ if( pOp->zComment ){
+ pMem->flags = MEM_Str|MEM_Term;
+ pMem->z = pOp->zComment;
+ pMem->n = strlen(pMem->z);
+ pMem->enc = SQLITE_UTF8;
+ }
+#endif
+ }
+
+ p->nResColumn = 8 - 5*(p->explain-1);
p->rc = SQLITE_OK;
- p->resOnStack = 1;
rc = SQLITE_ROW;
}
return rc;
}
#endif /* SQLITE_OMIT_EXPLAIN */
+#ifdef SQLITE_DEBUG
/*
** Print the SQL that was used to generate a VDBE program.
*/
void sqlite3VdbePrintSql(Vdbe *p){
-#ifdef SQLITE_DEBUG
int nOp = p->nOp;
VdbeOp *pOp;
if( nOp<1 ) return;
- pOp = &p->aOp[nOp-1];
- if( pOp->opcode==OP_Noop && pOp->p3!=0 ){
- const char *z = pOp->p3;
+ pOp = &p->aOp[0];
+ if( pOp->opcode==OP_Trace && pOp->p4.z!=0 ){
+ const char *z = pOp->p4.z;
while( isspace(*(u8*)z) ) z++;
printf("SQL: [%s]\n", z);
}
+}
#endif
+
+#if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE)
+/*
+** Print an IOTRACE message showing SQL content.
+*/
+void sqlite3VdbeIOTraceSql(Vdbe *p){
+ int nOp = p->nOp;
+ VdbeOp *pOp;
+ if( sqlite3_io_trace==0 ) return;
+ if( nOp<1 ) return;
+ pOp = &p->aOp[0];
+ if( pOp->opcode==OP_Trace && pOp->p4.z!=0 ){
+ int i, j;
+ char z[1000];
+ sqlite3_snprintf(sizeof(z), z, "%s", pOp->p4.z);
+ for(i=0; isspace((unsigned char)z[i]); i++){}
+ for(j=0; z[i]; i++){
+ if( isspace((unsigned char)z[i]) ){
+ if( z[i-1]!=' ' ){
+ z[j++] = ' ';
+ }
+ }else{
+ z[j++] = z[i];
+ }
+ }
+ z[j] = 0;
+ sqlite3_io_trace("SQL %s\n", z);
+ }
}
+#endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */
+
/*
** Prepare a virtual machine for execution. This involves things such
@@ -751,6 +919,7 @@ void sqlite3VdbeMakeReady(
int isExplain /* True if the EXPLAIN keywords is present */
){
int n;
+ sqlite3 *db = p->db;
assert( p!=0 );
assert( p->magic==VDBE_MAGIC_INIT );
@@ -766,37 +935,28 @@ void sqlite3VdbeMakeReady(
*/
p->magic = VDBE_MAGIC_RUN;
- /* No instruction ever pushes more than a single element onto the
- ** stack. And the stack never grows on successive executions of the
- ** same loop. So the total number of instructions is an upper bound
- ** on the maximum stack depth required. (Added later:) The
- ** resolveP2Values() call computes a tighter upper bound on the
- ** stack size.
- **
- ** Allocation all the stack space we will ever need.
+ /*
+ ** Allocation space for registers.
*/
- if( p->aStack==0 ){
+ if( p->aMem==0 ){
int nArg; /* Maximum number of args passed to a user function. */
- int nStack; /* Maximum number of stack entries required */
- resolveP2Values(p, &nArg, &nStack);
+ resolveP2Values(p, &nArg);
resizeOpArray(p, p->nOp);
assert( nVar>=0 );
- assert( nStack<p->nOp );
- if( isExplain ){
- nStack = 10;
+ if( isExplain && nMem<10 ){
+ p->nMem = nMem = 10;
}
- p->aStack = sqliteMalloc(
- nStack*sizeof(p->aStack[0]) /* aStack */
- + nArg*sizeof(Mem*) /* apArg */
+ p->aMem = sqlite3DbMallocZero(db,
+ nMem*sizeof(Mem) /* aMem */
+ nVar*sizeof(Mem) /* aVar */
+ + nArg*sizeof(Mem*) /* apArg */
+ nVar*sizeof(char*) /* azVar */
- + nMem*sizeof(Mem) /* aMem */
- + nCursor*sizeof(Cursor*) /* apCsr */
+ + nCursor*sizeof(Cursor*) + 1 /* apCsr */
);
- if( !sqlite3MallocFailed() ){
- p->aMem = &p->aStack[nStack];
- p->nMem = nMem;
- p->aVar = &p->aMem[nMem];
+ if( !db->mallocFailed ){
+ p->aMem--; /* aMem[] goes from 1..nMem */
+ p->nMem = nMem; /* not from 0..nMem-1 */
+ p->aVar = &p->aMem[nMem+1];
p->nVar = nVar;
p->okVar = 0;
p->apArg = (Mem**)&p->aVar[nVar];
@@ -805,40 +965,32 @@ void sqlite3VdbeMakeReady(
p->nCursor = nCursor;
for(n=0; n<nVar; n++){
p->aVar[n].flags = MEM_Null;
+ p->aVar[n].db = db;
+ }
+ for(n=1; n<=nMem; n++){
+ p->aMem[n].flags = MEM_Null;
+ p->aMem[n].db = db;
}
}
}
- for(n=0; n<p->nMem; n++){
- p->aMem[n].flags = MEM_Null;
- }
-
#ifdef SQLITE_DEBUG
- if( (p->db->flags & SQLITE_VdbeListing)!=0
- || sqlite3OsFileExists("vdbe_explain")
- ){
- int i;
- printf("VDBE Program Listing:\n");
- sqlite3VdbePrintSql(p);
- for(i=0; i<p->nOp; i++){
- sqlite3VdbePrintOp(stdout, i, &p->aOp[i]);
- }
- }
- if( sqlite3OsFileExists("vdbe_trace") ){
- p->trace = stdout;
+ for(n=1; n<p->nMem; n++){
+ assert( p->aMem[n].db==db );
+ assert( p->aMem[n].flags==MEM_Null );
}
#endif
- p->pTos = &p->aStack[-1];
+
p->pc = -1;
p->rc = SQLITE_OK;
p->uniqueCnt = 0;
p->returnDepth = 0;
p->errorAction = OE_Abort;
- p->popStack = 0;
p->explain |= isExplain;
p->magic = VDBE_MAGIC_RUN;
p->nChange = 0;
p->cacheCtr = 1;
p->minWriteFileFormat = 255;
+ p->openedStatement = 0;
#ifdef VDBE_PROFILE
{
int i;
@@ -851,7 +1003,7 @@ void sqlite3VdbeMakeReady(
}
/*
-** Close a cursor and release all the resources that cursor happens
+** Close a VDBE cursor and release all the resources that cursor happens
** to hold.
*/
void sqlite3VdbeFreeCursor(Vdbe *p, Cursor *pCx){
@@ -869,26 +1021,28 @@ void sqlite3VdbeFreeCursor(Vdbe *p, Cursor *pCx){
sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
const sqlite3_module *pModule = pCx->pModule;
p->inVtabMethod = 1;
- sqlite3SafetyOff(p->db);
+ (void)sqlite3SafetyOff(p->db);
pModule->xClose(pVtabCursor);
- sqlite3SafetyOn(p->db);
+ (void)sqlite3SafetyOn(p->db);
p->inVtabMethod = 0;
}
#endif
- sqliteFree(pCx->pData);
- sqliteFree(pCx->aType);
- sqliteFree(pCx);
+ sqlite3_free(pCx->pData);
+ sqlite3_free(pCx->aType);
+ sqlite3_free(pCx);
}
/*
-** Close all cursors
+** Close all cursors except for VTab cursors that are currently
+** in use.
*/
-static void closeAllCursors(Vdbe *p){
+static void closeAllCursorsExceptActiveVtabs(Vdbe *p){
int i;
if( p->apCsr==0 ) return;
for(i=0; i<p->nCursor; i++){
- if( !p->inVtabMethod || (p->apCsr[i] && !p->apCsr[i]->pVtabCursor) ){
- sqlite3VdbeFreeCursor(p, p->apCsr[i]);
+ Cursor *pC = p->apCsr[i];
+ if( pC && (!p->inVtabMethod || !pC->pVtabCursor) ){
+ sqlite3VdbeFreeCursor(p, pC);
p->apCsr[i] = 0;
}
}
@@ -903,24 +1057,21 @@ static void closeAllCursors(Vdbe *p){
*/
static void Cleanup(Vdbe *p){
int i;
- if( p->aStack ){
- releaseMemArray(p->aStack, 1 + (p->pTos - p->aStack));
- p->pTos = &p->aStack[-1];
- }
- closeAllCursors(p);
- releaseMemArray(p->aMem, p->nMem);
+ closeAllCursorsExceptActiveVtabs(p);
+ releaseMemArray(&p->aMem[1], p->nMem);
sqlite3VdbeFifoClear(&p->sFifo);
if( p->contextStack ){
for(i=0; i<p->contextStackTop; i++){
sqlite3VdbeFifoClear(&p->contextStack[i].sFifo);
}
- sqliteFree(p->contextStack);
+ sqlite3_free(p->contextStack);
}
p->contextStack = 0;
p->contextStackDepth = 0;
p->contextStackTop = 0;
- sqliteFree(p->zErrMsg);
+ sqlite3_free(p->zErrMsg);
p->zErrMsg = 0;
+ p->pResultSet = 0;
}
/*
@@ -932,14 +1083,17 @@ static void Cleanup(Vdbe *p){
void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
Mem *pColName;
int n;
+
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
- sqliteFree(p->aColName);
+ sqlite3_free(p->aColName);
n = nResColumn*COLNAME_N;
p->nResColumn = nResColumn;
- p->aColName = pColName = (Mem*)sqliteMalloc( sizeof(Mem)*n );
+ p->aColName = pColName = (Mem*)sqlite3DbMallocZero(p->db, sizeof(Mem)*n );
if( p->aColName==0 ) return;
while( n-- > 0 ){
- (pColName++)->flags = MEM_Null;
+ pColName->flags = MEM_Null;
+ pColName->db = p->db;
+ pColName++;
}
}
@@ -949,9 +1103,9 @@ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
**
** This call must be made after a call to sqlite3VdbeSetNumCols().
**
-** If N==P3_STATIC it means that zName is a pointer to a constant static
-** string and we can just copy the pointer. If it is P3_DYNAMIC, then
-** the string is freed using sqliteFree() when the vdbe is finished with
+** If N==P4_STATIC it means that zName is a pointer to a constant static
+** string and we can just copy the pointer. If it is P4_DYNAMIC, then
+** the string is freed using sqlite3_free() when the vdbe is finished with
** it. Otherwise, N bytes of zName are copied.
*/
int sqlite3VdbeSetColName(Vdbe *p, int idx, int var, const char *zName, int N){
@@ -959,15 +1113,15 @@ int sqlite3VdbeSetColName(Vdbe *p, int idx, int var, const char *zName, int N){
Mem *pColName;
assert( idx<p->nResColumn );
assert( var<COLNAME_N );
- if( sqlite3MallocFailed() ) return SQLITE_NOMEM;
+ if( p->db->mallocFailed ) return SQLITE_NOMEM;
assert( p->aColName!=0 );
pColName = &(p->aColName[idx+var*p->nResColumn]);
- if( N==P3_DYNAMIC || N==P3_STATIC ){
+ if( N==P4_DYNAMIC || N==P4_STATIC ){
rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, SQLITE_STATIC);
}else{
rc = sqlite3VdbeMemSetStr(pColName, zName, N, SQLITE_UTF8,SQLITE_TRANSIENT);
}
- if( rc==SQLITE_OK && N==P3_DYNAMIC ){
+ if( rc==SQLITE_OK && N==P4_DYNAMIC ){
pColName->flags = (pColName->flags&(~MEM_Static))|MEM_Dyn;
pColName->xDel = 0;
}
@@ -1005,7 +1159,7 @@ static int vdbeCommit(sqlite3 *db){
*/
for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
- if( pBt && sqlite3BtreeIsInTrans(pBt) ){
+ if( sqlite3BtreeIsInTrans(pBt) ){
needXcommit = 1;
if( i!=1 ) nTrans++;
}
@@ -1013,9 +1167,9 @@ static int vdbeCommit(sqlite3 *db){
/* If there are any write-transactions at all, invoke the commit hook */
if( needXcommit && db->xCommitCallback ){
- sqlite3SafetyOff(db);
+ (void)sqlite3SafetyOff(db);
rc = db->xCommitCallback(db->pCommitArg);
- sqlite3SafetyOn(db);
+ (void)sqlite3SafetyOn(db);
if( rc ){
return SQLITE_CONSTRAINT;
}
@@ -1034,18 +1188,22 @@ static int vdbeCommit(sqlite3 *db){
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
- rc = sqlite3BtreeSync(pBt, 0);
+ rc = sqlite3BtreeCommitPhaseOne(pBt, 0);
}
}
- /* Do the commit only if all databases successfully synced */
- if( rc==SQLITE_OK ){
- for(i=0; i<db->nDb; i++){
- Btree *pBt = db->aDb[i].pBt;
- if( pBt ){
- sqlite3BtreeCommit(pBt);
- }
+ /* Do the commit only if all databases successfully complete phase 1.
+ ** If one of the BtreeCommitPhaseOne() calls fails, this indicates an
+ ** IO error while deleting or truncating a journal file. It is unlikely,
+ ** but could happen. In this case abandon processing and return the error.
+ */
+ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ rc = sqlite3BtreeCommitPhaseTwo(pBt);
}
+ }
+ if( rc==SQLITE_OK ){
sqlite3VtabCommit(db);
}
}
@@ -1056,26 +1214,31 @@ static int vdbeCommit(sqlite3 *db){
*/
#ifndef SQLITE_OMIT_DISKIO
else{
+ sqlite3_vfs *pVfs = db->pVfs;
int needSync = 0;
char *zMaster = 0; /* File-name for the master journal */
char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
- OsFile *master = 0;
+ sqlite3_file *pMaster = 0;
+ i64 offset = 0;
/* Select a master journal file name */
do {
u32 random;
- sqliteFree(zMaster);
+ sqlite3_free(zMaster);
sqlite3Randomness(sizeof(random), &random);
- zMaster = sqlite3MPrintf("%s-mj%08X", zMainFile, random&0x7fffffff);
+ zMaster = sqlite3MPrintf(db, "%s-mj%08X", zMainFile, random&0x7fffffff);
if( !zMaster ){
return SQLITE_NOMEM;
}
- }while( sqlite3OsFileExists(zMaster) );
+ }while( sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS) );
/* Open the master journal. */
- rc = sqlite3OsOpenExclusive(zMaster, &master, 0);
+ rc = sqlite3OsOpenMalloc(pVfs, zMaster, &pMaster,
+ SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
+ SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_MASTER_JOURNAL, 0
+ );
if( rc!=SQLITE_OK ){
- sqliteFree(zMaster);
+ sqlite3_free(zMaster);
return rc;
}
@@ -1085,36 +1248,36 @@ static int vdbeCommit(sqlite3 *db){
** still have 'null' as the master journal pointer, so they will roll
** back independently if a failure occurs.
*/
- for(i=0; i<db->nDb; i++){
+ for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( i==1 ) continue; /* Ignore the TEMP database */
- if( pBt && sqlite3BtreeIsInTrans(pBt) ){
+ if( sqlite3BtreeIsInTrans(pBt) ){
char const *zFile = sqlite3BtreeGetJournalname(pBt);
if( zFile[0]==0 ) continue; /* Ignore :memory: databases */
if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
needSync = 1;
}
- rc = sqlite3OsWrite(master, zFile, strlen(zFile)+1);
+ rc = sqlite3OsWrite(pMaster, zFile, strlen(zFile)+1, offset);
+ offset += strlen(zFile)+1;
if( rc!=SQLITE_OK ){
- sqlite3OsClose(&master);
- sqlite3OsDelete(zMaster);
- sqliteFree(zMaster);
+ sqlite3OsCloseFree(pMaster);
+ sqlite3OsDelete(pVfs, zMaster, 0);
+ sqlite3_free(zMaster);
return rc;
}
}
}
-
- /* Sync the master journal file. Before doing this, open the directory
- ** the master journal file is store in so that it gets synced too.
+ /* Sync the master journal file. If the IOCAP_SEQUENTIAL device
+ ** flag is set this is not required.
*/
zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
- rc = sqlite3OsOpenDirectory(master, zMainFile);
- if( rc!=SQLITE_OK ||
- (needSync && (rc=sqlite3OsSync(master,0))!=SQLITE_OK) ){
- sqlite3OsClose(&master);
- sqlite3OsDelete(zMaster);
- sqliteFree(zMaster);
+ if( (needSync
+ && (0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL))
+ && (rc=sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL))!=SQLITE_OK) ){
+ sqlite3OsCloseFree(pMaster);
+ sqlite3OsDelete(pVfs, zMaster, 0);
+ sqlite3_free(zMaster);
return rc;
}
@@ -1122,21 +1285,21 @@ static int vdbeCommit(sqlite3 *db){
** sets the master journal pointer in each individual journal. If
** an error occurs here, do not delete the master journal file.
**
- ** If the error occurs during the first call to sqlite3BtreeSync(),
- ** then there is a chance that the master journal file will be
- ** orphaned. But we cannot delete it, in case the master journal
- ** file name was written into the journal file before the failure
- ** occured.
+ ** If the error occurs during the first call to
+ ** sqlite3BtreeCommitPhaseOne(), then there is a chance that the
+ ** master journal file will be orphaned. But we cannot delete it,
+ ** in case the master journal file name was written into the journal
+ ** file before the failure occured.
*/
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( pBt ){
+ rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster);
}
}
- sqlite3OsClose(&master);
+ sqlite3OsCloseFree(pMaster);
if( rc!=SQLITE_OK ){
- sqliteFree(zMaster);
+ sqlite3_free(zMaster);
return rc;
}
@@ -1144,35 +1307,29 @@ static int vdbeCommit(sqlite3 *db){
** doing this the directory is synced again before any individual
** transaction files are deleted.
*/
- rc = sqlite3OsDelete(zMaster);
- assert( rc==SQLITE_OK );
- sqliteFree(zMaster);
+ rc = sqlite3OsDelete(pVfs, zMaster, 1);
+ sqlite3_free(zMaster);
zMaster = 0;
- rc = sqlite3OsSyncDirectory(zMainFile);
- if( rc!=SQLITE_OK ){
- /* This is not good. The master journal file has been deleted, but
- ** the directory sync failed. There is no completely safe course of
- ** action from here. The individual journals contain the name of the
- ** master journal file, but there is no way of knowing if that
- ** master journal exists now or if it will exist after the operating
- ** system crash that may follow the fsync() failure.
- */
+ if( rc ){
return rc;
}
/* All files and directories have already been synced, so the following
- ** calls to sqlite3BtreeCommit() are only closing files and deleting
- ** journals. If something goes wrong while this is happening we don't
- ** really care. The integrity of the transaction is already guaranteed,
- ** but some stray 'cold' journals may be lying around. Returning an
- ** error code won't help matters.
+ ** calls to sqlite3BtreeCommitPhaseTwo() are only closing files and
+ ** deleting or truncating journals. If something goes wrong while
+ ** this is happening we don't really care. The integrity of the
+ ** transaction is already guaranteed, but some stray 'cold' journals
+ ** may be lying around. Returning an error code won't help matters.
*/
+ disable_simulated_io_errors();
for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
- sqlite3BtreeCommit(pBt);
+ sqlite3BtreeCommitPhaseTwo(pBt);
}
}
+ enable_simulated_io_errors();
+
sqlite3VtabCommit(db);
}
#endif
@@ -1207,21 +1364,28 @@ 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.
+** For every Btree that in database connection db which
+** has been modified, "trip" or invalidate each cursor in
+** that Btree might have been modified so that the cursor
+** can never be used again. This happens when a rollback
+*** occurs. We have to trip all the other cursors, even
+** cursor from other VMs in different database connections,
+** so that none of them try to use the data at which they
+** were pointing and which now may have been changed due
+** to the rollback.
+**
+** Remember that a rollback can delete tables complete and
+** reorder rootpages. So it is not sufficient just to save
+** the state of the cursor. We have to invalidate the cursor
+** so that it is never used again.
*/
-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;
+static void invalidateCursorsOnModifiedBtrees(sqlite3 *db){
+ int i;
+ for(i=0; i<db->nDb; i++){
+ Btree *p = db->aDb[i].pBt;
+ if( p && sqlite3BtreeIsInTrans(p) ){
+ sqlite3BtreeTripAllCursors(p, SQLITE_ABORT);
+ }
}
}
@@ -1231,7 +1395,8 @@ void sqlite3AbortOtherActiveVdbes(sqlite3 *db, Vdbe *pExcept){
** changes. If a rollback is needed, then do the rollback.
**
** This routine is the only way to move the state of a VM from
-** SQLITE_MAGIC_RUN to SQLITE_MAGIC_HALT.
+** SQLITE_MAGIC_RUN to SQLITE_MAGIC_HALT. It is harmless to
+** call this on a VM that is in the SQLITE_MAGIC_HALT state.
**
** Return an error code. If the commit could not complete because of
** lock contention, return SQLITE_BUSY. If SQLITE_BUSY is returned, it
@@ -1247,49 +1412,38 @@ int sqlite3VdbeHalt(Vdbe *p){
** 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:
+ ** If any of the following errors occur:
**
- ** No error:
+ ** SQLITE_NOMEM
+ ** SQLITE_IOERR
+ ** SQLITE_FULL
+ ** SQLITE_INTERRUPT
**
+ ** Then the internal cache might have been left in an inconsistent
+ ** state. We need to rollback the statement transaction, if there is
+ ** one, or the complete transaction if there is no statement transaction.
*/
- if( sqlite3MallocFailed() ){
+ if( p->db->mallocFailed ){
p->rc = SQLITE_NOMEM;
}
+ closeAllCursorsExceptActiveVtabs(p);
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);
/* No commit or rollback needed if the program never started */
if( p->pc>=0 ){
+ int mrc; /* Primary error code from p->rc */
+
+ /* Lock all btrees used by the statement */
+ sqlite3BtreeMutexArrayEnter(&p->aMutex);
- /* Check for one of the special errors - SQLITE_NOMEM or SQLITE_IOERR */
- isSpecialError = ((p->rc==SQLITE_NOMEM || p->rc==SQLITE_IOERR)?1:0);
+ /* Check for one of the special errors */
+ mrc = p->rc & 0xff;
+ isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR
+ || mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL;
if( isSpecialError ){
/* This loop does static analysis of the query to see which of the
** following three categories it falls into:
@@ -1304,31 +1458,35 @@ int sqlite3VdbeHalt(Vdbe *p){
** this is probably easier. Todo: Might be an opportunity to reduce
** code size a very small amount though...
*/
- int isReadOnly = 1;
+ int notReadOnly = 0;
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;
+ notReadOnly |= p->aOp[i].p2;
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 ){
+ if( notReadOnly || mrc!=SQLITE_INTERRUPT ){
+ if( p->rc==SQLITE_IOERR_BLOCKED && isStatement ){
+ xFunc = sqlite3BtreeRollbackStmt;
+ p->rc = SQLITE_BUSY;
+ } else if( (mrc==SQLITE_NOMEM || mrc==SQLITE_FULL) && 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);
+ invalidateCursorsOnModifiedBtrees(db);
sqlite3RollbackAll(db);
db->autoCommit = 1;
}
@@ -1343,12 +1501,13 @@ int sqlite3VdbeHalt(Vdbe *p){
*/
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
+ /* 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 ){
+ sqlite3BtreeMutexArrayLeave(&p->aMutex);
return SQLITE_BUSY;
}else if( rc!=SQLITE_OK ){
p->rc = rc;
@@ -1361,11 +1520,13 @@ int sqlite3VdbeHalt(Vdbe *p){
}
}else if( !xFunc ){
if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
- xFunc = sqlite3BtreeCommitStmt;
+ if( p->openedStatement ){
+ xFunc = sqlite3BtreeCommitStmt;
+ }
}else if( p->errorAction==OE_Abort ){
xFunc = sqlite3BtreeRollbackStmt;
}else{
- sqlite3AbortOtherActiveVdbes(db, p);
+ invalidateCursorsOnModifiedBtrees(db);
sqlite3RollbackAll(db);
db->autoCommit = 1;
}
@@ -1409,6 +1570,9 @@ int sqlite3VdbeHalt(Vdbe *p){
sqlite3ResetInternalSchema(db, 0);
db->flags = (db->flags | SQLITE_InternChanges);
}
+
+ /* Release the locks */
+ sqlite3BtreeMutexArrayLeave(&p->aMutex);
}
/* We have successfully halted and closed the VM. Record this fact. */
@@ -1417,10 +1581,23 @@ int sqlite3VdbeHalt(Vdbe *p){
}
p->magic = VDBE_MAGIC_HALT;
checkActiveVdbeCnt(db);
+ if( p->db->mallocFailed ){
+ p->rc = SQLITE_NOMEM;
+ }
+ checkActiveVdbeCnt(db);
return SQLITE_OK;
}
+
+/*
+** Each VDBE holds the result of the most recent sqlite3_step() call
+** in p->rc. This routine sets that result back to SQLITE_OK.
+*/
+void sqlite3VdbeResetStepResult(Vdbe *p){
+ p->rc = SQLITE_OK;
+}
+
/*
** Clean up a VDBE after execution but do not delete the VDBE just yet.
** Write any error messages into *pzErrMsg. Return the result code.
@@ -1433,18 +1610,16 @@ int sqlite3VdbeHalt(Vdbe *p){
** VDBE_MAGIC_INIT.
*/
int sqlite3VdbeReset(Vdbe *p){
- if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
- sqlite3Error(p->db, SQLITE_MISUSE, 0);
- return SQLITE_MISUSE;
- }
+ sqlite3 *db;
+ db = p->db;
/* If the VM did not run to completion or if it encountered an
** error, then it might not have been halted properly. So halt
** it now.
*/
- sqlite3SafetyOn(p->db);
+ (void)sqlite3SafetyOn(db);
sqlite3VdbeHalt(p);
- sqlite3SafetyOff(p->db);
+ (void)sqlite3SafetyOff(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
@@ -1453,21 +1628,22 @@ int sqlite3VdbeReset(Vdbe *p){
*/
if( p->pc>=0 ){
if( p->zErrMsg ){
- sqlite3* db = p->db;
- sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, sqlite3FreeX);
+ sqlite3ValueSetStr(db->pErr,-1,p->zErrMsg,SQLITE_UTF8,sqlite3_free);
db->errCode = p->rc;
p->zErrMsg = 0;
}else if( p->rc ){
- sqlite3Error(p->db, p->rc, 0);
+ sqlite3Error(db, p->rc, 0);
}else{
- sqlite3Error(p->db, SQLITE_OK, 0);
+ sqlite3Error(db, SQLITE_OK, 0);
}
}else if( p->rc && p->expired ){
/* The expired flag was set on the VDBE before the first call
** to sqlite3_step(). For consistency (since sqlite3_step() was
** called), set the database error in this case as well.
*/
- sqlite3Error(p->db, p->rc, 0);
+ sqlite3Error(db, p->rc, 0);
+ sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, sqlite3_free);
+ p->zErrMsg = 0;
}
/* Reclaim all memory used by the VDBE
@@ -1476,7 +1652,6 @@ int sqlite3VdbeReset(Vdbe *p){
/* Save profiling information from this VDBE run.
*/
- assert( p->pTos<&p->aStack[p->pc<0?0:p->pc] || !p->aStack );
#ifdef VDBE_PROFILE
{
FILE *out = fopen("vdbe_profile.out", "a");
@@ -1501,10 +1676,7 @@ int sqlite3VdbeReset(Vdbe *p){
#endif
p->magic = VDBE_MAGIC_INIT;
p->aborted = 0;
- if( p->rc==SQLITE_SCHEMA ){
- sqlite3ResetInternalSchema(p->db, 0);
- }
- return p->rc;
+ return p->rc & db->errMask;
}
/*
@@ -1515,6 +1687,7 @@ int sqlite3VdbeFinalize(Vdbe *p){
int rc = SQLITE_OK;
if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){
rc = sqlite3VdbeReset(p);
+ assert( (rc & p->db->errMask)==rc );
}else if( p->magic!=VDBE_MAGIC_INIT ){
return SQLITE_MISUSE;
}
@@ -1558,19 +1731,25 @@ void sqlite3VdbeDelete(Vdbe *p){
p->pNext->pPrev = p->pPrev;
}
if( p->aOp ){
- for(i=0; i<p->nOp; i++){
- Op *pOp = &p->aOp[i];
- freeP3(pOp->p3type, pOp->p3);
+ Op *pOp = p->aOp;
+ for(i=0; i<p->nOp; i++, pOp++){
+ freeP4(pOp->p4type, pOp->p4.p);
+#ifdef SQLITE_DEBUG
+ sqlite3_free(pOp->zComment);
+#endif
}
- sqliteFree(p->aOp);
+ sqlite3_free(p->aOp);
}
releaseMemArray(p->aVar, p->nVar);
- sqliteFree(p->aLabel);
- sqliteFree(p->aStack);
+ sqlite3_free(p->aLabel);
+ if( p->aMem ){
+ sqlite3_free(&p->aMem[1]);
+ }
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
- sqliteFree(p->aColName);
+ sqlite3_free(p->aColName);
+ sqlite3_free(p->zSql);
p->magic = VDBE_MAGIC_DEAD;
- sqliteFree(p);
+ sqlite3_free(p);
}
/*
@@ -1585,12 +1764,7 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
extern int sqlite3_search_count;
#endif
assert( p->isTable );
- if( p->isTable ){
- rc = sqlite3BtreeMoveto(p->pCursor, 0, p->movetoTarget, &res);
- }else{
- rc = sqlite3BtreeMoveto(p->pCursor,(char*)&p->movetoTarget,
- sizeof(i64),&res);
- }
+ rc = sqlite3BtreeMoveto(p->pCursor, 0, p->movetoTarget, 0, &res);
if( rc ) return rc;
*p->pIncrKey = 0;
p->lastRowid = keyToInt(p->movetoTarget);
@@ -1655,6 +1829,7 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
*/
u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
int flags = pMem->flags;
+ int n;
if( flags&MEM_Null ){
return 0;
@@ -1662,7 +1837,7 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
if( flags&MEM_Int ){
/* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
# define MAX_6BYTE ((((i64)0x00001000)<<32)-1)
- i64 i = pMem->i;
+ i64 i = pMem->u.i;
u64 u;
if( file_format>=4 && (i&1)==i ){
return 8+i;
@@ -1678,15 +1853,13 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
if( flags&MEM_Real ){
return 7;
}
- if( flags&MEM_Str ){
- int n = pMem->n;
- assert( n>=0 );
- return ((n*2) + 13);
- }
- if( flags&MEM_Blob ){
- return (pMem->n*2 + 12);
+ assert( flags&(MEM_Str|MEM_Blob) );
+ n = pMem->n;
+ if( flags & MEM_Zero ){
+ n += pMem->u.i;
}
- return 0;
+ assert( n>=0 );
+ return ((n*2) + 12 + ((flags&MEM_Str)!=0));
}
/*
@@ -1702,11 +1875,77 @@ int sqlite3VdbeSerialTypeLen(u32 serial_type){
}
/*
+** If we are on an architecture with mixed-endian floating
+** points (ex: ARM7) then swap the lower 4 bytes with the
+** upper 4 bytes. Return the result.
+**
+** For most architectures, this is a no-op.
+**
+** (later): It is reported to me that the mixed-endian problem
+** on ARM7 is an issue with GCC, not with the ARM7 chip. It seems
+** that early versions of GCC stored the two words of a 64-bit
+** float in the wrong order. And that error has been propagated
+** ever since. The blame is not necessarily with GCC, though.
+** GCC might have just copying the problem from a prior compiler.
+** I am also told that newer versions of GCC that follow a different
+** ABI get the byte order right.
+**
+** Developers using SQLite on an ARM7 should compile and run their
+** application using -DSQLITE_DEBUG=1 at least once. With DEBUG
+** enabled, some asserts below will ensure that the byte order of
+** floating point values is correct.
+**
+** (2007-08-30) Frank van Vugt has studied this problem closely
+** and has send his findings to the SQLite developers. Frank
+** writes that some Linux kernels offer floating point hardware
+** emulation that uses only 32-bit mantissas instead of a full
+** 48-bits as required by the IEEE standard. (This is the
+** CONFIG_FPE_FASTFPE option.) On such systems, floating point
+** byte swapping becomes very complicated. To avoid problems,
+** the necessary byte swapping is carried out using a 64-bit integer
+** rather than a 64-bit float. Frank assures us that the code here
+** works for him. We, the developers, have no way to independently
+** verify this, but Frank seems to know what he is talking about
+** so we trust him.
+*/
+#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
+static u64 floatSwap(u64 in){
+ union {
+ u64 r;
+ u32 i[2];
+ } u;
+ u32 t;
+
+ u.r = in;
+ t = u.i[0];
+ u.i[0] = u.i[1];
+ u.i[1] = t;
+ return u.r;
+}
+# define swapMixedEndianFloat(X) X = floatSwap(X)
+#else
+# define swapMixedEndianFloat(X)
+#endif
+
+/*
** Write the serialized data blob for the value stored in pMem into
** buf. It is assumed that the caller has allocated sufficient space.
** Return the number of bytes written.
+**
+** nBuf is the amount of space left in buf[]. nBuf must always be
+** large enough to hold the entire field. Except, if the field is
+** a blob with a zero-filled tail, then buf[] might be just the right
+** size to hold everything except for the zero-filled tail. If buf[]
+** is only big enough to hold the non-zero prefix, then only write that
+** prefix into buf[]. But if buf[] is large enough to hold both the
+** prefix and the tail then write the prefix and set the tail to all
+** zeros.
+**
+** Return the number of bytes actually written into buf[]. The number
+** of bytes in the zero-filled tail is included in the return value only
+** if those bytes were zeroed in buf[].
*/
-int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem, int file_format){
+int sqlite3VdbeSerialPut(u8 *buf, int nBuf, Mem *pMem, int file_format){
u32 serial_type = sqlite3VdbeSerialType(pMem, file_format);
int len;
@@ -1715,11 +1954,14 @@ int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem, int file_format){
u64 v;
int i;
if( serial_type==7 ){
- v = *(u64*)&pMem->r;
+ assert( sizeof(v)==sizeof(pMem->r) );
+ memcpy(&v, &pMem->r, sizeof(v));
+ swapMixedEndianFloat(v);
}else{
- v = *(u64*)&pMem->i;
+ v = pMem->u.i;
}
len = i = sqlite3VdbeSerialTypeLen(serial_type);
+ assert( len<=nBuf );
while( i-- ){
buf[i] = (v&0xFF);
v >>= 8;
@@ -1729,8 +1971,18 @@ int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem, int file_format){
/* String or blob */
if( serial_type>=12 ){
- len = sqlite3VdbeSerialTypeLen(serial_type);
+ assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.i:0)
+ == sqlite3VdbeSerialTypeLen(serial_type) );
+ assert( pMem->n<=nBuf );
+ len = pMem->n;
memcpy(buf, pMem->z, len);
+ if( pMem->flags & MEM_Zero ){
+ len += pMem->u.i;
+ if( len>nBuf ){
+ len = nBuf;
+ }
+ memset(&buf[pMem->n], 0, len-pMem->n);
+ }
return len;
}
@@ -1755,22 +2007,22 @@ int sqlite3VdbeSerialGet(
break;
}
case 1: { /* 1-byte signed integer */
- pMem->i = (signed char)buf[0];
+ pMem->u.i = (signed char)buf[0];
pMem->flags = MEM_Int;
return 1;
}
case 2: { /* 2-byte signed integer */
- pMem->i = (((signed char)buf[0])<<8) | buf[1];
+ pMem->u.i = (((signed char)buf[0])<<8) | buf[1];
pMem->flags = MEM_Int;
return 2;
}
case 3: { /* 3-byte signed integer */
- pMem->i = (((signed char)buf[0])<<16) | (buf[1]<<8) | buf[2];
+ pMem->u.i = (((signed char)buf[0])<<16) | (buf[1]<<8) | buf[2];
pMem->flags = MEM_Int;
return 3;
}
case 4: { /* 4-byte signed integer */
- pMem->i = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
+ pMem->u.i = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
pMem->flags = MEM_Int;
return 4;
}
@@ -1778,7 +2030,7 @@ int sqlite3VdbeSerialGet(
u64 x = (((signed char)buf[0])<<8) | buf[1];
u32 y = (buf[2]<<24) | (buf[3]<<16) | (buf[4]<<8) | buf[5];
x = (x<<32) | y;
- pMem->i = *(i64*)&x;
+ pMem->u.i = *(i64*)&x;
pMem->flags = MEM_Int;
return 6;
}
@@ -1788,27 +2040,34 @@ int sqlite3VdbeSerialGet(
u32 y;
#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.
+ ** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is
+ ** defined that 64-bit floating point values really are mixed
+ ** endian.
*/
static const u64 t1 = ((u64)0x3ff00000)<<32;
- assert( 1.0==*(double*)&t1 );
+ static const double r1 = 1.0;
+ u64 t2 = t1;
+ swapMixedEndianFloat(t2);
+ assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 );
#endif
x = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
y = (buf[4]<<24) | (buf[5]<<16) | (buf[6]<<8) | buf[7];
x = (x<<32) | y;
if( serial_type==6 ){
- pMem->i = *(i64*)&x;
+ pMem->u.i = *(i64*)&x;
pMem->flags = MEM_Int;
}else{
- pMem->r = *(double*)&x;
+ assert( sizeof(x)==8 && sizeof(pMem->r)==8 );
+ swapMixedEndianFloat(x);
+ memcpy(&pMem->r, &x, sizeof(x));
pMem->flags = MEM_Real;
}
return 8;
}
case 8: /* Integer 0 */
case 9: { /* Integer 1 */
- pMem->i = serial_type-8;
+ pMem->u.i = serial_type-8;
pMem->flags = MEM_Int;
return 0;
}
@@ -1851,6 +2110,9 @@ int sqlite3VdbeSerialGet(
** or positive integer if {nKey1, pKey1} is less than, equal to or
** greater than {nKey2, pKey2}. Both Key1 and Key2 must be byte strings
** composed by the OP_MakeRecord opcode of the VDBE.
+**
+** Key1 and Key2 do not have to contain the same number of fields.
+** But if the lengths differ, Key2 must be the shorter of the two.
*/
int sqlite3VdbeRecordCompare(
void *userData,
@@ -1870,7 +2132,9 @@ int sqlite3VdbeRecordCompare(
Mem mem1;
Mem mem2;
mem1.enc = pKeyInfo->enc;
+ mem1.db = pKeyInfo->db;
mem2.enc = pKeyInfo->enc;
+ mem2.db = pKeyInfo->db;
idx1 = GetVarint(aKey1, szHdr1);
d1 = szHdr1;
@@ -1887,14 +2151,13 @@ int sqlite3VdbeRecordCompare(
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
- ** data to go with the serial type just read. This assert may fail if
- ** the file is corrupted. Then read the value from each key into mem1
- ** and mem2 respectively.
+ /* Extract the values to be compared.
*/
d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1);
d2 += sqlite3VdbeSerialGet(&aKey2[d2], serial_type2, &mem2);
+ /* Do the comparison
+ */
rc = sqlite3MemCompare(&mem1, &mem2, i<nField ? pKeyInfo->aColl[i] : 0);
if( mem1.flags & MEM_Dyn ) sqlite3VdbeMemRelease(&mem1);
if( mem2.flags & MEM_Dyn ) sqlite3VdbeMemRelease(&mem2);
@@ -1911,10 +2174,12 @@ int sqlite3VdbeRecordCompare(
if( rc==0 ){
if( pKeyInfo->incrKey ){
rc = -1;
- }else if( d1<nKey1 ){
- rc = 1;
- }else if( d2<nKey2 ){
- rc = -1;
+ }else if( !pKeyInfo->prefixIsEqual ){
+ if( d1<nKey1 ){
+ rc = 1;
+ }else if( d2<nKey2 ){
+ rc = -1; /* Only occurs on a corrupt database file */
+ }
}
}else if( pKeyInfo->aSortOrder && i<pKeyInfo->nField
&& pKeyInfo->aSortOrder[i] ){
@@ -1946,7 +2211,7 @@ int sqlite3VdbeIdxRowidLen(const u8 *aKey){
** Return SQLITE_OK if everything works, or an error code otherwise.
*/
int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
- i64 nCellKey;
+ i64 nCellKey = 0;
int rc;
u32 szHdr; /* Size of the header */
u32 typeRowid; /* Serial type of the rowid */
@@ -1965,7 +2230,7 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
sqlite3GetVarint32((u8*)&m.z[szHdr-1], &typeRowid);
lenRowid = sqlite3VdbeSerialTypeLen(typeRowid);
sqlite3VdbeSerialGet((u8*)&m.z[m.n-lenRowid], typeRowid, &v);
- *rowid = v.i;
+ *rowid = v.u.i;
sqlite3VdbeMemRelease(&m);
return SQLITE_OK;
}
@@ -1985,7 +2250,7 @@ int sqlite3VdbeIdxKeyCompare(
int nKey, const u8 *pKey, /* The key to compare */
int *res /* Write the comparison result here */
){
- i64 nCellKey;
+ i64 nCellKey = 0;
int rc;
BtCursor *pCur = pC->pCursor;
int lenRowid;
@@ -2011,6 +2276,7 @@ int sqlite3VdbeIdxKeyCompare(
** sqlite3_changes() on the database handle 'db'.
*/
void sqlite3VdbeSetChanges(sqlite3 *db, int nChange){
+ assert( sqlite3_mutex_held(db->mutex) );
db->nChange = nChange;
db->nTotalChange += nChange;
}
diff --git a/ext/pdo_sqlite/sqlite/src/vdbeblob.c b/ext/pdo_sqlite/sqlite/src/vdbeblob.c
new file mode 100644
index 0000000000..1538fae4ed
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/src/vdbeblob.c
@@ -0,0 +1,337 @@
+/*
+** 2007 May 1
+**
+** 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 implement incremental BLOB I/O.
+**
+** $Id$
+*/
+
+#include "sqliteInt.h"
+#include "vdbeInt.h"
+
+#ifndef SQLITE_OMIT_INCRBLOB
+
+/*
+** Valid sqlite3_blob* handles point to Incrblob structures.
+*/
+typedef struct Incrblob Incrblob;
+struct Incrblob {
+ int flags; /* Copy of "flags" passed to sqlite3_blob_open() */
+ int nByte; /* Size of open blob, in bytes */
+ int iOffset; /* Byte offset of blob in cursor data */
+ BtCursor *pCsr; /* Cursor pointing at blob row */
+ sqlite3_stmt *pStmt; /* Statement holding cursor open */
+ sqlite3 *db; /* The associated database */
+};
+
+/*
+** Open a blob handle.
+*/
+int sqlite3_blob_open(
+ sqlite3* db, /* The database connection */
+ const char *zDb, /* The attached database containing the blob */
+ const char *zTable, /* The table containing the blob */
+ const char *zColumn, /* The column containing the blob */
+ sqlite_int64 iRow, /* The row containing the glob */
+ int flags, /* True -> read/write access, false -> read-only */
+ sqlite3_blob **ppBlob /* Handle for accessing the blob returned here */
+){
+ int nAttempt = 0;
+ int iCol; /* Index of zColumn in row-record */
+
+ /* This VDBE program seeks a btree cursor to the identified
+ ** db/table/row entry. The reason for using a vdbe program instead
+ ** of writing code to use the b-tree layer directly is that the
+ ** vdbe program will take advantage of the various transaction,
+ ** locking and error handling infrastructure built into the vdbe.
+ **
+ ** After seeking the cursor, the vdbe executes an OP_ResultRow.
+ ** Code external to the Vdbe then "borrows" the b-tree cursor and
+ ** uses it to implement the blob_read(), blob_write() and
+ ** blob_bytes() functions.
+ **
+ ** The sqlite3_blob_close() function finalizes the vdbe program,
+ ** which closes the b-tree cursor and (possibly) commits the
+ ** transaction.
+ */
+ static const VdbeOpList openBlob[] = {
+ {OP_Transaction, 0, 0, 0}, /* 0: Start a transaction */
+ {OP_VerifyCookie, 0, 0, 0}, /* 1: Check the schema cookie */
+
+ /* One of the following two instructions is replaced by an
+ ** OP_Noop before exection.
+ */
+ {OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */
+ {OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */
+ {OP_SetNumColumns, 0, 0, 0}, /* 4: Num cols for cursor */
+
+ {OP_Variable, 1, 1, 0}, /* 5: Push the rowid to the stack */
+ {OP_NotExists, 0, 10, 1}, /* 6: Seek the cursor */
+ {OP_Column, 0, 0, 1}, /* 7 */
+ {OP_ResultRow, 1, 0, 0}, /* 8 */
+ {OP_Close, 0, 0, 0}, /* 9 */
+ {OP_Halt, 0, 0, 0}, /* 10 */
+ };
+
+ Vdbe *v = 0;
+ int rc = SQLITE_OK;
+ char zErr[128];
+
+ zErr[0] = 0;
+ sqlite3_mutex_enter(db->mutex);
+ do {
+ Parse sParse;
+ Table *pTab;
+
+ memset(&sParse, 0, sizeof(Parse));
+ sParse.db = db;
+
+ rc = sqlite3SafetyOn(db);
+ if( rc!=SQLITE_OK ){
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
+ }
+
+ sqlite3BtreeEnterAll(db);
+ pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb);
+ if( !pTab ){
+ if( sParse.zErrMsg ){
+ sqlite3_snprintf(sizeof(zErr), zErr, "%s", sParse.zErrMsg);
+ }
+ sqlite3_free(sParse.zErrMsg);
+ rc = SQLITE_ERROR;
+ (void)sqlite3SafetyOff(db);
+ sqlite3BtreeLeaveAll(db);
+ goto blob_open_out;
+ }
+
+ /* Now search pTab for the exact column. */
+ for(iCol=0; iCol < pTab->nCol; iCol++) {
+ if( sqlite3StrICmp(pTab->aCol[iCol].zName, zColumn)==0 ){
+ break;
+ }
+ }
+ if( iCol==pTab->nCol ){
+ sqlite3_snprintf(sizeof(zErr), zErr, "no such column: \"%s\"", zColumn);
+ rc = SQLITE_ERROR;
+ (void)sqlite3SafetyOff(db);
+ sqlite3BtreeLeaveAll(db);
+ goto blob_open_out;
+ }
+
+ /* If the value is being opened for writing, check that the
+ ** column is not indexed. It is against the rules to open an
+ ** indexed column for writing.
+ */
+ if( flags ){
+ Index *pIdx;
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ int j;
+ for(j=0; j<pIdx->nColumn; j++){
+ if( pIdx->aiColumn[j]==iCol ){
+ sqlite3_snprintf(sizeof(zErr), zErr,
+ "cannot open indexed column for writing");
+ rc = SQLITE_ERROR;
+ (void)sqlite3SafetyOff(db);
+ sqlite3BtreeLeaveAll(db);
+ goto blob_open_out;
+ }
+ }
+ }
+ }
+
+ v = sqlite3VdbeCreate(db);
+ if( v ){
+ int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob);
+
+ /* Configure the OP_Transaction */
+ sqlite3VdbeChangeP1(v, 0, iDb);
+ sqlite3VdbeChangeP2(v, 0, (flags ? 1 : 0));
+
+ /* Configure the OP_VerifyCookie */
+ sqlite3VdbeChangeP1(v, 1, iDb);
+ sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie);
+
+ /* Make sure a mutex is held on the table to be accessed */
+ sqlite3VdbeUsesBtree(v, iDb);
+
+ /* Remove either the OP_OpenWrite or OpenRead. Set the P2
+ ** parameter of the other to pTab->tnum.
+ */
+ sqlite3VdbeChangeToNoop(v, (flags ? 2 : 3), 1);
+ sqlite3VdbeChangeP2(v, (flags ? 3 : 2), pTab->tnum);
+ sqlite3VdbeChangeP3(v, (flags ? 3 : 2), iDb);
+
+ /* Configure the OP_SetNumColumns. Configure the cursor to
+ ** think that the table has one more column than it really
+ ** does. An OP_Column to retrieve this imaginary column will
+ ** always return an SQL NULL. This is useful because it means
+ ** we can invoke OP_Column to fill in the vdbe cursors type
+ ** and offset cache without causing any IO.
+ */
+ sqlite3VdbeChangeP2(v, 4, pTab->nCol+1);
+ if( !db->mallocFailed ){
+ sqlite3VdbeMakeReady(v, 1, 1, 1, 0);
+ }
+ }
+
+ sqlite3BtreeLeaveAll(db);
+ rc = sqlite3SafetyOff(db);
+ if( rc!=SQLITE_OK || db->mallocFailed ){
+ goto blob_open_out;
+ }
+
+ sqlite3_bind_int64((sqlite3_stmt *)v, 1, iRow);
+ rc = sqlite3_step((sqlite3_stmt *)v);
+ if( rc!=SQLITE_ROW ){
+ nAttempt++;
+ rc = sqlite3_finalize((sqlite3_stmt *)v);
+ sqlite3_snprintf(sizeof(zErr), zErr, sqlite3_errmsg(db));
+ v = 0;
+ }
+ } while( nAttempt<5 && rc==SQLITE_SCHEMA );
+
+ if( rc==SQLITE_ROW ){
+ /* The row-record has been opened successfully. Check that the
+ ** column in question contains text or a blob. If it contains
+ ** text, it is up to the caller to get the encoding right.
+ */
+ Incrblob *pBlob;
+ u32 type = v->apCsr[0]->aType[iCol];
+
+ if( type<12 ){
+ sqlite3_snprintf(sizeof(zErr), zErr, "cannot open value of type %s",
+ type==0?"null": type==7?"real": "integer"
+ );
+ rc = SQLITE_ERROR;
+ goto blob_open_out;
+ }
+ pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
+ if( db->mallocFailed ){
+ sqlite3_free(pBlob);
+ goto blob_open_out;
+ }
+ pBlob->flags = flags;
+ pBlob->pCsr = v->apCsr[0]->pCursor;
+ sqlite3BtreeEnterCursor(pBlob->pCsr);
+ sqlite3BtreeCacheOverflow(pBlob->pCsr);
+ sqlite3BtreeLeaveCursor(pBlob->pCsr);
+ pBlob->pStmt = (sqlite3_stmt *)v;
+ pBlob->iOffset = v->apCsr[0]->aOffset[iCol];
+ pBlob->nByte = sqlite3VdbeSerialTypeLen(type);
+ pBlob->db = db;
+ *ppBlob = (sqlite3_blob *)pBlob;
+ rc = SQLITE_OK;
+ }else if( rc==SQLITE_OK ){
+ sqlite3_snprintf(sizeof(zErr), zErr, "no such rowid: %lld", iRow);
+ rc = SQLITE_ERROR;
+ }
+
+blob_open_out:
+ zErr[sizeof(zErr)-1] = '\0';
+ if( rc!=SQLITE_OK || db->mallocFailed ){
+ sqlite3_finalize((sqlite3_stmt *)v);
+ }
+ sqlite3Error(db, rc, (rc==SQLITE_OK?0:zErr));
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
+}
+
+/*
+** Close a blob handle that was previously created using
+** sqlite3_blob_open().
+*/
+int sqlite3_blob_close(sqlite3_blob *pBlob){
+ Incrblob *p = (Incrblob *)pBlob;
+ int rc;
+
+ rc = sqlite3_finalize(p->pStmt);
+ sqlite3_free(p);
+ return rc;
+}
+
+/*
+** Perform a read or write operation on a blob
+*/
+static int blobReadWrite(
+ sqlite3_blob *pBlob,
+ void *z,
+ int n,
+ int iOffset,
+ int (*xCall)(BtCursor*, u32, u32, void*)
+){
+ int rc;
+ Incrblob *p = (Incrblob *)pBlob;
+ Vdbe *v;
+ sqlite3 *db = p->db;
+
+ /* Request is out of range. Return a transient error. */
+ if( (iOffset+n)>p->nByte ){
+ return SQLITE_ERROR;
+ }
+ sqlite3_mutex_enter(db->mutex);
+
+ /* If there is no statement handle, then the blob-handle has
+ ** already been invalidated. Return SQLITE_ABORT in this case.
+ */
+ v = (Vdbe*)p->pStmt;
+ if( v==0 ){
+ rc = SQLITE_ABORT;
+ }else{
+ /* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is
+ ** returned, clean-up the statement handle.
+ */
+ assert( db == v->db );
+ sqlite3BtreeEnterCursor(p->pCsr);
+ rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
+ sqlite3BtreeLeaveCursor(p->pCsr);
+ if( rc==SQLITE_ABORT ){
+ sqlite3VdbeFinalize(v);
+ p->pStmt = 0;
+ }else{
+ db->errCode = rc;
+ v->rc = rc;
+ }
+ }
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
+}
+
+/*
+** Read data from a blob handle.
+*/
+int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
+ return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreeData);
+}
+
+/*
+** Write data to a blob handle.
+*/
+int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
+ return blobReadWrite(pBlob, (void *)z, n, iOffset, sqlite3BtreePutData);
+}
+
+/*
+** Query a blob handle for the size of the data.
+**
+** The Incrblob.nByte field is fixed for the lifetime of the Incrblob
+** so no mutex is required for access.
+*/
+int sqlite3_blob_bytes(sqlite3_blob *pBlob){
+ Incrblob *p = (Incrblob *)pBlob;
+ return p->nByte;
+}
+
+#endif /* #ifndef SQLITE_OMIT_INCRBLOB */
diff --git a/ext/pdo_sqlite/sqlite/src/vdbefifo.c b/ext/pdo_sqlite/sqlite/src/vdbefifo.c
index 7ea6c050f9..f03f5c6e9e 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbefifo.c
+++ b/ext/pdo_sqlite/sqlite/src/vdbefifo.c
@@ -19,12 +19,12 @@
** Allocate a new FifoPage and return a pointer to it. Return NULL if
** we run out of memory. Leave space on the page for nEntry entries.
*/
-static FifoPage *allocatePage(int nEntry){
+static FifoPage *allocateFifoPage(int nEntry){
FifoPage *pPage;
if( nEntry>32767 ){
nEntry = 32767;
}
- pPage = sqliteMallocRaw( sizeof(FifoPage) + sizeof(i64)*(nEntry-1) );
+ pPage = sqlite3_malloc( sizeof(FifoPage) + sizeof(i64)*(nEntry-1) );
if( pPage ){
pPage->nSlot = nEntry;
pPage->iWrite = 0;
@@ -50,12 +50,12 @@ int sqlite3VdbeFifoPush(Fifo *pFifo, i64 val){
FifoPage *pPage;
pPage = pFifo->pLast;
if( pPage==0 ){
- pPage = pFifo->pLast = pFifo->pFirst = allocatePage(20);
+ pPage = pFifo->pLast = pFifo->pFirst = allocateFifoPage(20);
if( pPage==0 ){
return SQLITE_NOMEM;
}
}else if( pPage->iWrite>=pPage->nSlot ){
- pPage->pNext = allocatePage(pFifo->nEntry);
+ pPage->pNext = allocateFifoPage(pFifo->nEntry);
if( pPage->pNext==0 ){
return SQLITE_NOMEM;
}
@@ -87,7 +87,7 @@ int sqlite3VdbeFifoPop(Fifo *pFifo, i64 *pVal){
pFifo->nEntry--;
if( pPage->iRead>=pPage->iWrite ){
pFifo->pFirst = pPage->pNext;
- sqliteFree(pPage);
+ sqlite3_free(pPage);
if( pFifo->nEntry==0 ){
assert( pFifo->pLast==pPage );
pFifo->pLast = 0;
@@ -108,7 +108,7 @@ void sqlite3VdbeFifoClear(Fifo *pFifo){
FifoPage *pPage, *pNextPage;
for(pPage=pFifo->pFirst; pPage; pPage=pNextPage){
pNextPage = pPage->pNext;
- sqliteFree(pPage);
+ sqlite3_free(pPage);
}
sqlite3VdbeFifoInit(pFifo);
}
diff --git a/ext/pdo_sqlite/sqlite/src/vdbemem.c b/ext/pdo_sqlite/sqlite/src/vdbemem.c
index f53a4a4d26..fa407b671c 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbemem.c
+++ b/ext/pdo_sqlite/sqlite/src/vdbemem.c
@@ -16,11 +16,16 @@
** name sqlite_value
*/
#include "sqliteInt.h"
-#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"
/*
+** Call sqlite3VdbeMemExpandBlob() on the supplied value (type Mem*)
+** P if required.
+*/
+#define expandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0)
+
+/*
** If pMem is an object with a valid string representation, this routine
** ensures the internal encoding for the string representation is
** 'desiredEnc', one of SQLITE_UTF8, SQLITE_UTF16LE or SQLITE_UTF16BE.
@@ -38,11 +43,11 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
return SQLITE_OK;
}
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
#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.
*/
@@ -50,14 +55,6 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int 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
}
@@ -68,14 +65,17 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
*/
int sqlite3VdbeMemDynamicify(Mem *pMem){
- int n = pMem->n;
+ int n;
u8 *z;
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
+ expandBlob(pMem);
if( (pMem->flags & (MEM_Ephem|MEM_Static|MEM_Short))==0 ){
return SQLITE_OK;
}
assert( (pMem->flags & MEM_Dyn)==0 );
+ n = pMem->n;
assert( pMem->flags & (MEM_Str|MEM_Blob) );
- z = sqliteMallocRaw( n+2 );
+ z = sqlite3DbMallocRaw(pMem->db, n+2 );
if( z==0 ){
return SQLITE_NOMEM;
}
@@ -90,6 +90,37 @@ int sqlite3VdbeMemDynamicify(Mem *pMem){
}
/*
+** If the given Mem* has a zero-filled tail, turn it into an ordinary
+** blob stored in dynamically allocated space.
+*/
+#ifndef SQLITE_OMIT_INCRBLOB
+int sqlite3VdbeMemExpandBlob(Mem *pMem){
+ if( pMem->flags & MEM_Zero ){
+ char *pNew;
+ int nByte;
+ assert( (pMem->flags & MEM_Blob)!=0 );
+ nByte = pMem->n + pMem->u.i;
+ if( nByte<=0 ) nByte = 1;
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
+ pNew = sqlite3DbMallocRaw(pMem->db, nByte);
+ if( pNew==0 ){
+ return SQLITE_NOMEM;
+ }
+ memcpy(pNew, pMem->z, pMem->n);
+ memset(&pNew[pMem->n], 0, pMem->u.i);
+ sqlite3VdbeMemRelease(pMem);
+ pMem->z = pNew;
+ pMem->n += pMem->u.i;
+ pMem->u.i = 0;
+ pMem->flags &= ~(MEM_Zero|MEM_Static|MEM_Ephem|MEM_Short|MEM_Term);
+ pMem->flags |= MEM_Dyn;
+ }
+ return SQLITE_OK;
+}
+#endif
+
+
+/*
** Make the given Mem object either MEM_Short or MEM_Dyn so that bytes
** of the Mem.z[] array can be modified.
**
@@ -98,6 +129,8 @@ int sqlite3VdbeMemDynamicify(Mem *pMem){
int sqlite3VdbeMemMakeWriteable(Mem *pMem){
int n;
u8 *z;
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
+ expandBlob(pMem);
if( (pMem->flags & (MEM_Ephem|MEM_Static))==0 ){
return SQLITE_OK;
}
@@ -107,7 +140,7 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
z = (u8*)pMem->zShort;
pMem->flags |= MEM_Short|MEM_Term;
}else{
- z = sqliteMallocRaw( n+2 );
+ z = sqlite3DbMallocRaw(pMem->db, n+2 );
if( z==0 ){
return SQLITE_NOMEM;
}
@@ -127,33 +160,30 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
** Make sure the given Mem is \u0000 terminated.
*/
int sqlite3VdbeMemNulTerminate(Mem *pMem){
- /* In SQLite, a string without a nul terminator occurs when a string
- ** is loaded from disk (in this case the memory management is ephemeral),
- ** or when it is supplied by the user as a bound variable or function
- ** return value. Therefore, the memory management of the string must be
- ** either ephemeral, static or controlled by a user-supplied destructor.
- */
- assert(
- !(pMem->flags&MEM_Str) || /* it's not a string, or */
- (pMem->flags&MEM_Term) || /* it's nul term. already, or */
- (pMem->flags&(MEM_Ephem|MEM_Static)) || /* it's static or ephem, or */
- (pMem->flags&MEM_Dyn && pMem->xDel) /* external management */
- );
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
if( (pMem->flags & MEM_Term)!=0 || (pMem->flags & MEM_Str)==0 ){
return SQLITE_OK; /* Nothing to do */
}
-
if( pMem->flags & (MEM_Static|MEM_Ephem) ){
return sqlite3VdbeMemMakeWriteable(pMem);
}else{
- char *z = sqliteMalloc(pMem->n+2);
- if( !z ) return SQLITE_NOMEM;
+ char *z;
+ sqlite3VdbeMemExpandBlob(pMem);
+ z = sqlite3DbMallocRaw(pMem->db, pMem->n+2);
+ if( !z ){
+ return SQLITE_NOMEM;
+ }
memcpy(z, pMem->z, pMem->n);
z[pMem->n] = 0;
z[pMem->n+1] = 0;
- pMem->xDel(pMem->z);
+ if( pMem->xDel ){
+ pMem->xDel(pMem->z);
+ }else{
+ sqlite3_free(pMem->z);
+ }
pMem->xDel = 0;
pMem->z = z;
+ pMem->flags |= MEM_Term;
}
return SQLITE_OK;
}
@@ -176,6 +206,8 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
int fg = pMem->flags;
char *z = pMem->zShort;
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
+ assert( !(fg&MEM_Zero) );
assert( !(fg&(MEM_Str|MEM_Blob)) );
assert( fg&(MEM_Int|MEM_Real) );
@@ -186,7 +218,7 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16.
*/
if( fg & MEM_Int ){
- sqlite3_snprintf(NBFS, z, "%lld", pMem->i);
+ sqlite3_snprintf(NBFS, z, "%lld", pMem->u.i);
}else{
assert( fg & MEM_Real );
sqlite3_snprintf(NBFS, z, "%!.15g", pMem->r);
@@ -211,23 +243,23 @@ 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 );
+ assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
ctx.s.flags = MEM_Null;
ctx.s.z = pMem->zShort;
+ ctx.s.db = pMem->db;
ctx.pMem = pMem;
ctx.pFunc = pFunc;
ctx.isError = 0;
pFunc->xFinalize(&ctx);
if( pMem->z && pMem->z!=pMem->zShort ){
- sqliteFree( pMem->z );
+ sqlite3_free( pMem->z );
}
*pMem = ctx.s;
if( pMem->flags & MEM_Short ){
pMem->z = pMem->zShort;
}
- if( ctx.isError ){
- rc = SQLITE_ERROR;
- }
+ rc = (ctx.isError?SQLITE_ERROR:SQLITE_OK);
}
return rc;
}
@@ -238,17 +270,18 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
** (Mem.type==SQLITE_TEXT).
*/
void sqlite3VdbeMemRelease(Mem *p){
+ assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) );
if( p->flags & (MEM_Dyn|MEM_Agg) ){
if( p->xDel ){
if( p->flags & MEM_Agg ){
- sqlite3VdbeMemFinalize(p, *(FuncDef**)&p->i);
+ sqlite3VdbeMemFinalize(p, p->u.pDef);
assert( (p->flags & MEM_Agg)==0 );
sqlite3VdbeMemRelease(p);
}else{
p->xDel((void *)p->z);
}
}else{
- sqliteFree(p->z);
+ sqlite3_free(p->z);
}
p->z = 0;
p->xDel = 0;
@@ -256,6 +289,38 @@ void sqlite3VdbeMemRelease(Mem *p){
}
/*
+** Convert a 64-bit IEEE double into a 64-bit signed integer.
+** If the double is too large, return 0x8000000000000000.
+**
+** Most systems appear to do this simply by assigning
+** variables and without the extra range tests. But
+** there are reports that windows throws an expection
+** if the floating point value is out of range. (See ticket #2880.)
+** Because we do not completely understand the problem, we will
+** take the conservative approach and always do range tests
+** before attempting the conversion.
+*/
+static i64 doubleToInt64(double r){
+ /*
+ ** Many compilers we encounter do not define constants for the
+ ** minimum and maximum 64-bit integers, or they define them
+ ** inconsistently. And many do not understand the "LL" notation.
+ ** So we define our own static constants here using nothing
+ ** larger than a 32-bit integer constant.
+ */
+ static const i64 maxInt = (((i64)0x7fffffff)<<32)|0xffffffff;
+ static const i64 minInt = ((i64)0x80000000)<<32;
+
+ if( r<(double)minInt ){
+ return minInt;
+ }else if( r>(double)maxInt ){
+ return minInt;
+ }else{
+ return (i64)r;
+ }
+}
+
+/*
** Return some kind of integer value which is the best we can do
** at representing the value that *pMem describes as an integer.
** If pMem is an integer, then the value is exact. If pMem is
@@ -266,19 +331,22 @@ void sqlite3VdbeMemRelease(Mem *p){
** If pMem is a string, its encoding might be changed.
*/
i64 sqlite3VdbeIntValue(Mem *pMem){
- int flags = pMem->flags;
+ int flags;
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
+ flags = pMem->flags;
if( flags & MEM_Int ){
- return pMem->i;
+ return pMem->u.i;
}else if( flags & MEM_Real ){
- return (i64)pMem->r;
+ return doubleToInt64(pMem->r);
}else if( flags & (MEM_Str|MEM_Blob) ){
i64 value;
+ pMem->flags |= MEM_Str;
if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
|| sqlite3VdbeMemNulTerminate(pMem) ){
return 0;
}
assert( pMem->z );
- sqlite3atoi64(pMem->z, &value);
+ sqlite3Atoi64(pMem->z, &value);
return value;
}else{
return 0;
@@ -292,12 +360,14 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
** If it is a NULL, return 0.0.
*/
double sqlite3VdbeRealValue(Mem *pMem){
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
if( pMem->flags & MEM_Real ){
return pMem->r;
}else if( pMem->flags & MEM_Int ){
- return (double)pMem->i;
+ return (double)pMem->u.i;
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
double val = 0.0;
+ pMem->flags |= MEM_Str;
if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
|| sqlite3VdbeMemNulTerminate(pMem) ){
return 0.0;
@@ -316,8 +386,10 @@ double sqlite3VdbeRealValue(Mem *pMem){
*/
void sqlite3VdbeIntegerAffinity(Mem *pMem){
assert( pMem->flags & MEM_Real );
- pMem->i = pMem->r;
- if( ((double)pMem->i)==pMem->r ){
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
+
+ pMem->u.i = doubleToInt64(pMem->r);
+ if( pMem->r==(double)pMem->u.i ){
pMem->flags |= MEM_Int;
}
}
@@ -326,7 +398,8 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){
** Convert pMem to type integer. Invalidate any prior representations.
*/
int sqlite3VdbeMemIntegerify(Mem *pMem){
- pMem->i = sqlite3VdbeIntValue(pMem);
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
+ pMem->u.i = sqlite3VdbeIntValue(pMem);
sqlite3VdbeMemRelease(pMem);
pMem->flags = MEM_Int;
return SQLITE_OK;
@@ -337,6 +410,7 @@ int sqlite3VdbeMemIntegerify(Mem *pMem){
** Invalidate any prior representations.
*/
int sqlite3VdbeMemRealify(Mem *pMem){
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
pMem->r = sqlite3VdbeRealValue(pMem);
sqlite3VdbeMemRelease(pMem);
pMem->flags = MEM_Real;
@@ -348,8 +422,21 @@ int sqlite3VdbeMemRealify(Mem *pMem){
** Invalidate any prior representations.
*/
int sqlite3VdbeMemNumerify(Mem *pMem){
- sqlite3VdbeMemRealify(pMem);
- sqlite3VdbeIntegerAffinity(pMem);
+ double r1, r2;
+ i64 i;
+ assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 );
+ assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
+ r1 = sqlite3VdbeRealValue(pMem);
+ i = doubleToInt64(r1);
+ r2 = (double)i;
+ if( r1==r2 ){
+ sqlite3VdbeMemIntegerify(pMem);
+ }else{
+ pMem->r = r1;
+ pMem->flags = MEM_Real;
+ sqlite3VdbeMemRelease(pMem);
+ }
return SQLITE_OK;
}
@@ -364,12 +451,27 @@ void sqlite3VdbeMemSetNull(Mem *pMem){
}
/*
+** Delete any previous value and set the value to be a BLOB of length
+** n containing all zeros.
+*/
+void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){
+ sqlite3VdbeMemRelease(pMem);
+ pMem->flags = MEM_Blob|MEM_Zero|MEM_Short;
+ pMem->type = SQLITE_BLOB;
+ pMem->n = 0;
+ if( n<0 ) n = 0;
+ pMem->u.i = n;
+ pMem->z = pMem->zShort;
+ pMem->enc = SQLITE_UTF8;
+}
+
+/*
** Delete any previous value and set the value stored in *pMem to val,
** manifest type INTEGER.
*/
void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
sqlite3VdbeMemRelease(pMem);
- pMem->i = val;
+ pMem->u.i = val;
pMem->flags = MEM_Int;
pMem->type = SQLITE_INTEGER;
}
@@ -379,19 +481,39 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
** manifest type REAL.
*/
void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
- sqlite3VdbeMemRelease(pMem);
- pMem->r = val;
- pMem->flags = MEM_Real;
- pMem->type = SQLITE_FLOAT;
+ if( sqlite3_isnan(val) ){
+ sqlite3VdbeMemSetNull(pMem);
+ }else{
+ sqlite3VdbeMemRelease(pMem);
+ pMem->r = val;
+ pMem->flags = MEM_Real;
+ pMem->type = SQLITE_FLOAT;
+ }
+}
+
+/*
+** Return true if the Mem object contains a TEXT or BLOB that is
+** too large - whose size exceeds SQLITE_MAX_LENGTH.
+*/
+int sqlite3VdbeMemTooBig(Mem *p){
+ if( p->flags & (MEM_Str|MEM_Blob) ){
+ int n = p->n;
+ if( p->flags & MEM_Zero ){
+ n += p->u.i;
+ }
+ return n>SQLITE_MAX_LENGTH;
+ }
+ return 0;
}
/*
** Make an shallow copy of pFrom into pTo. Prior contents of
-** pTo are overwritten. The pFrom->z field is not duplicated. If
+** pTo are freed. The pFrom->z field is not duplicated. If
** pFrom->z is used, then pTo->z points to the same thing as pFrom->z
** and flags gets srcType (either MEM_Ephem or MEM_Static).
*/
void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
+ sqlite3VdbeMemRelease(pTo);
memcpy(pTo, pFrom, sizeof(*pFrom)-sizeof(pFrom->zShort));
pTo->xDel = 0;
if( pTo->flags & (MEM_Str|MEM_Blob) ){
@@ -407,9 +529,6 @@ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
*/
int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
int rc;
- if( pTo->flags & MEM_Dyn ){
- sqlite3VdbeMemRelease(pTo);
- }
sqlite3VdbeMemShallowCopy(pTo, pFrom, MEM_Ephem);
if( pTo->flags & MEM_Ephem ){
rc = sqlite3VdbeMemMakeWriteable(pTo);
@@ -423,12 +542,12 @@ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
** Transfer the contents of pFrom to pTo. Any existing value in pTo is
** freed. If pFrom contains ephemeral data, a copy is made.
**
-** pFrom contains an SQL NULL when this routine returns. SQLITE_NOMEM
-** might be returned if pFrom held ephemeral data and we were unable
-** to allocate enough space to make a copy.
+** pFrom contains an SQL NULL when this routine returns.
*/
-int sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){
- int rc;
+void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){
+ assert( pFrom->db==0 || sqlite3_mutex_held(pFrom->db->mutex) );
+ assert( pTo->db==0 || sqlite3_mutex_held(pTo->db->mutex) );
+ assert( pFrom->db==0 || pTo->db==0 || pFrom->db==pTo->db );
if( pTo->flags & MEM_Dyn ){
sqlite3VdbeMemRelease(pTo);
}
@@ -438,12 +557,6 @@ int sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){
}
pFrom->flags = MEM_Null;
pFrom->xDel = 0;
- if( pTo->flags & MEM_Ephem ){
- rc = sqlite3VdbeMemMakeWriteable(pTo);
- }else{
- rc = SQLITE_OK;
- }
- return rc;
}
/*
@@ -456,13 +569,13 @@ int sqlite3VdbeMemSetStr(
u8 enc, /* Encoding of z. 0 for BLOBs */
void (*xDel)(void*) /* Destructor function */
){
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
sqlite3VdbeMemRelease(pMem);
if( !z ){
pMem->flags = MEM_Null;
pMem->type = SQLITE_NULL;
return SQLITE_OK;
}
-
pMem->z = (char *)z;
if( xDel==SQLITE_STATIC ){
pMem->flags = MEM_Static;
@@ -498,7 +611,7 @@ int sqlite3VdbeMemSetStr(
case SQLITE_UTF16BE:
pMem->flags |= MEM_Str;
if( pMem->n<0 ){
- pMem->n = sqlite3utf16ByteLen(pMem->z,-1);
+ pMem->n = sqlite3Utf16ByteLen(pMem->z,-1);
pMem->flags |= MEM_Term;
}
if( sqlite3VdbeMemHandleBom(pMem) ){
@@ -554,12 +667,12 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
if( (f1 & f2 & MEM_Int)==0 ){
double r1, r2;
if( (f1&MEM_Real)==0 ){
- r1 = pMem1->i;
+ r1 = pMem1->u.i;
}else{
r1 = pMem1->r;
}
if( (f2&MEM_Real)==0 ){
- r2 = pMem2->i;
+ r2 = pMem2->u.i;
}else{
r2 = pMem2->r;
}
@@ -569,8 +682,8 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
}else{
assert( f1&MEM_Int );
assert( f2&MEM_Int );
- if( pMem1->i < pMem2->i ) return -1;
- if( pMem1->i > pMem2->i ) return 1;
+ if( pMem1->u.i < pMem2->u.i ) return -1;
+ if( pMem1->u.i > pMem2->u.i ) return 1;
return 0;
}
}
@@ -653,15 +766,20 @@ int sqlite3VdbeMemFromBtree(
int key, /* If true, retrieve from the btree key, not data. */
Mem *pMem /* OUT: Return data in this Mem structure. */
){
- char *zData; /* Data from the btree layer */
- int available; /* Number of bytes available on the local btree page */
+ char *zData; /* Data from the btree layer */
+ int available = 0; /* Number of bytes available on the local btree page */
+ sqlite3 *db; /* Database connection */
+ db = sqlite3BtreeCursorDb(pCur);
+ assert( sqlite3_mutex_held(db->mutex) );
if( key ){
zData = (char *)sqlite3BtreeKeyFetch(pCur, &available);
}else{
zData = (char *)sqlite3BtreeDataFetch(pCur, &available);
}
+ assert( zData!=0 );
+ pMem->db = db;
pMem->n = amt;
if( offset+amt<=available ){
pMem->z = &zData[offset];
@@ -669,7 +787,7 @@ int sqlite3VdbeMemFromBtree(
}else{
int rc;
if( amt>NBFS-2 ){
- zData = (char *)sqliteMallocRaw(amt+2);
+ zData = (char *)sqlite3DbMallocRaw(db, amt+2);
if( !zData ){
return SQLITE_NOMEM;
}
@@ -694,7 +812,7 @@ int sqlite3VdbeMemFromBtree(
if( amt>NBFS-2 ){
assert( zData!=pMem->zShort );
assert( pMem->flags & MEM_Dyn );
- sqliteFree(zData);
+ sqlite3_free(zData);
} else {
assert( zData==pMem->zShort );
assert( pMem->flags & MEM_Short );
@@ -706,7 +824,7 @@ int sqlite3VdbeMemFromBtree(
return SQLITE_OK;
}
-#ifndef NDEBUG
+#if 0
/*
** Perform various checks on the memory cell pMem. An assert() will
** fail if pMem is internally inconsistent.
@@ -714,14 +832,14 @@ int sqlite3VdbeMemFromBtree(
void sqlite3VdbeMemSanity(Mem *pMem){
int flags = pMem->flags;
assert( flags!=0 ); /* Must define some type */
- if( pMem->flags & (MEM_Str|MEM_Blob) ){
- int x = pMem->flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short);
+ if( flags & (MEM_Str|MEM_Blob) ){
+ int x = flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short);
assert( x!=0 ); /* Strings must define a string subtype */
assert( (x & (x-1))==0 ); /* Only one string subtype can be defined */
assert( pMem->z!=0 ); /* Strings must have a value */
/* Mem.z points to Mem.zShort iff the subtype is MEM_Short */
- assert( (pMem->flags & MEM_Short)==0 || pMem->z==pMem->zShort );
- assert( (pMem->flags & MEM_Short)!=0 || pMem->z!=pMem->zShort );
+ assert( (x & MEM_Short)==0 || pMem->z==pMem->zShort );
+ assert( (x & MEM_Short)!=0 || pMem->z!=pMem->zShort );
/* No destructor unless there is MEM_Dyn */
assert( pMem->xDel==0 || (pMem->flags & MEM_Dyn)!=0 );
@@ -751,7 +869,7 @@ void sqlite3VdbeMemSanity(Mem *pMem){
|| (pMem->flags&MEM_Null)==0 );
/* If the MEM is both real and integer, the values are equal */
assert( (pMem->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real)
- || pMem->r==pMem->i );
+ || pMem->r==pMem->u.i );
}
#endif
@@ -761,12 +879,14 @@ void sqlite3VdbeMemSanity(Mem *pMem){
** parameter, which must be one of SQLITE_UTF16BE, SQLITE_UTF16LE or
** SQLITE_UTF8.
**
-** (2007-02-16:) The enc value can be or-ed with SQLITE_UTF16_ALIGNED.
+** (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( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) );
assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) );
if( pVal->flags&MEM_Null ){
@@ -774,6 +894,7 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
}
assert( (MEM_Blob>>3) == MEM_Str );
pVal->flags |= (pVal->flags & MEM_Blob)>>3;
+ expandBlob(pVal);
if( pVal->flags&MEM_Str ){
sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED);
if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&(int)pVal->z) ){
@@ -782,11 +903,14 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
return 0;
}
}
- }else if( !(pVal->flags&MEM_Blob) ){
+ sqlite3VdbeMemNulTerminate(pVal);
+ }else{
+ assert( (pVal->flags&MEM_Blob)==0 );
sqlite3VdbeMemStringify(pVal, enc);
assert( 0==(1&(int)pVal->z) );
}
- assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || sqlite3MallocFailed() );
+ assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0
+ || pVal->db->mallocFailed );
if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){
return pVal->z;
}else{
@@ -797,11 +921,12 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
/*
** Create a new sqlite3_value object.
*/
-sqlite3_value* sqlite3ValueNew(void){
- Mem *p = sqliteMalloc(sizeof(*p));
+sqlite3_value *sqlite3ValueNew(sqlite3 *db){
+ Mem *p = sqlite3DbMallocZero(db, sizeof(*p));
if( p ){
p->flags = MEM_Null;
p->type = SQLITE_NULL;
+ p->db = db;
}
return p;
}
@@ -810,17 +935,18 @@ sqlite3_value* sqlite3ValueNew(void){
** Create a new sqlite3_value object, containing the value of pExpr.
**
** This only works for very simple expressions that consist of one constant
-** token (i.e. "5", "5.1", "NULL", "'a string'"). If the expression can
+** token (i.e. "5", "5.1", "'a string'"). If the expression can
** be converted directly into a value, then the value is allocated and
** a pointer written to *ppVal. The caller is responsible for deallocating
** the value by passing it to sqlite3ValueFree() later on. If the expression
** cannot be converted to a value, then *ppVal is set to NULL.
*/
int sqlite3ValueFromExpr(
- Expr *pExpr,
- u8 enc,
- u8 affinity,
- sqlite3_value **ppVal
+ sqlite3 *db, /* The database connection */
+ Expr *pExpr, /* The expression to evaluate */
+ u8 enc, /* Encoding to use */
+ u8 affinity, /* Affinity to use */
+ sqlite3_value **ppVal /* Write the new value here */
){
int op;
char *zVal = 0;
@@ -833,32 +959,34 @@ int sqlite3ValueFromExpr(
op = pExpr->op;
if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
- zVal = sqliteStrNDup((char*)pExpr->token.z, pExpr->token.n);
- pVal = sqlite3ValueNew();
+ zVal = sqlite3StrNDup((char*)pExpr->token.z, pExpr->token.n);
+ pVal = sqlite3ValueNew(db);
if( !zVal || !pVal ) goto no_mem;
sqlite3Dequote(zVal);
- sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, sqlite3FreeX);
+ sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, sqlite3_free);
if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){
sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, enc);
}else{
sqlite3ValueApplyAffinity(pVal, affinity, enc);
}
}else if( op==TK_UMINUS ) {
- if( SQLITE_OK==sqlite3ValueFromExpr(pExpr->pLeft, enc, affinity, &pVal) ){
- pVal->i = -1 * pVal->i;
+ if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){
+ pVal->u.i = -1 * pVal->u.i;
pVal->r = -1.0 * pVal->r;
}
}
#ifndef SQLITE_OMIT_BLOB_LITERAL
else if( op==TK_BLOB ){
int nVal;
- pVal = sqlite3ValueNew();
- zVal = sqliteStrNDup((char*)pExpr->token.z+1, pExpr->token.n-1);
- if( !zVal || !pVal ) goto no_mem;
- sqlite3Dequote(zVal);
- nVal = strlen(zVal)/2;
- sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(zVal), nVal, 0, sqlite3FreeX);
- sqliteFree(zVal);
+ assert( pExpr->token.n>=3 );
+ assert( pExpr->token.z[0]=='x' || pExpr->token.z[0]=='X' );
+ assert( pExpr->token.z[1]=='\'' );
+ assert( pExpr->token.z[pExpr->token.n-1]=='\'' );
+ pVal = sqlite3ValueNew(db);
+ nVal = pExpr->token.n - 3;
+ zVal = (char*)pExpr->token.z + 2;
+ sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(db, zVal, nVal), nVal/2,
+ 0, sqlite3_free);
}
#endif
@@ -866,7 +994,8 @@ int sqlite3ValueFromExpr(
return SQLITE_OK;
no_mem:
- sqliteFree(zVal);
+ db->mallocFailed = 1;
+ sqlite3_free(zVal);
sqlite3ValueFree(pVal);
*ppVal = 0;
return SQLITE_NOMEM;
@@ -876,11 +1005,11 @@ no_mem:
** Change the string value of an sqlite3_value object
*/
void sqlite3ValueSetStr(
- sqlite3_value *v,
- int n,
- const void *z,
- u8 enc,
- void (*xDel)(void*)
+ sqlite3_value *v, /* Value to be set */
+ int n, /* Length of string z */
+ const void *z, /* Text of the new string */
+ u8 enc, /* Encoding to use */
+ void (*xDel)(void*) /* Destructor for the string */
){
if( v ) sqlite3VdbeMemSetStr((Mem *)v, z, n, enc, xDel);
}
@@ -891,7 +1020,7 @@ void sqlite3ValueSetStr(
void sqlite3ValueFree(sqlite3_value *v){
if( !v ) return;
sqlite3ValueSetStr(v, 0, 0, SQLITE_UTF8, SQLITE_STATIC);
- sqliteFree(v);
+ sqlite3_free(v);
}
/*
@@ -901,7 +1030,11 @@ void sqlite3ValueFree(sqlite3_value *v){
int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
Mem *p = (Mem*)pVal;
if( (p->flags & MEM_Blob)!=0 || sqlite3ValueText(pVal, enc) ){
- return p->n;
+ if( p->flags & MEM_Zero ){
+ return p->n+p->u.i;
+ }else{
+ return p->n;
+ }
}
return 0;
}
diff --git a/ext/pdo_sqlite/sqlite/src/vtab.c b/ext/pdo_sqlite/sqlite/src/vtab.c
index 1f236246a7..1ffe2c8b8e 100644
--- a/ext/pdo_sqlite/sqlite/src/vtab.c
+++ b/ext/pdo_sqlite/sqlite/src/vtab.c
@@ -1,5 +1,5 @@
/*
-** 2007 June 10
+** 2006 June 10
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -16,28 +16,93 @@
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"
-/*
-** External API function used to create a new virtual-table module.
-*/
-int sqlite3_create_module(
+static int createModule(
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);
+ void *pAux, /* Context pointer for xCreate/xConnect */
+ void (*xDestroy)(void *) /* Module destructor function */
+) {
+ int rc, nName;
+ Module *pMod;
+
+ sqlite3_mutex_enter(db->mutex);
+ nName = strlen(zName);
+ pMod = (Module *)sqlite3DbMallocRaw(db, sizeof(Module) + nName + 1);
if( pMod ){
char *zCopy = (char *)(&pMod[1]);
- strcpy(zCopy, zName);
+ memcpy(zCopy, zName, nName+1);
pMod->zName = zCopy;
pMod->pModule = pModule;
pMod->pAux = pAux;
+ pMod->xDestroy = xDestroy;
pMod = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod);
- sqliteFree(pMod);
+ if( pMod && pMod->xDestroy ){
+ pMod->xDestroy(pMod->pAux);
+ }
+ sqlite3_free(pMod);
sqlite3ResetInternalSchema(db, 0);
}
- return sqlite3ApiExit(db, SQLITE_OK);
+ rc = sqlite3ApiExit(db, SQLITE_OK);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
+}
+
+
+/*
+** 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 */
+){
+ return createModule(db, zName, pModule, pAux, 0);
+}
+
+/*
+** External API function used to create a new virtual-table module.
+*/
+int sqlite3_create_module_v2(
+ 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 */
+ void (*xDestroy)(void *) /* Module destructor function */
+){
+ return createModule(db, zName, pModule, pAux, xDestroy);
+}
+
+/*
+** Lock the virtual table so that it cannot be disconnected.
+** Locks nest. Every lock should have a corresponding unlock.
+** If an unlock is omitted, resources leaks will occur.
+**
+** If a disconnect is attempted while a virtual table is locked,
+** the disconnect is deferred until all locks have been removed.
+*/
+void sqlite3VtabLock(sqlite3_vtab *pVtab){
+ pVtab->nRef++;
+}
+
+/*
+** Unlock a virtual table. When the last lock is removed,
+** disconnect the virtual table.
+*/
+void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){
+ pVtab->nRef--;
+ assert(db);
+ assert( sqlite3SafetyCheckOk(db) );
+ if( pVtab->nRef==0 ){
+ if( db->magic==SQLITE_MAGIC_BUSY ){
+ (void)sqlite3SafetyOff(db);
+ pVtab->pModule->xDisconnect(pVtab);
+ (void)sqlite3SafetyOn(db);
+ } else {
+ pVtab->pModule->xDisconnect(pVtab);
+ }
+ }
}
/*
@@ -49,18 +114,15 @@ 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);
- }
+ sqlite3VtabUnlock(p->pSchema->db, pVtab);
p->pVtab = 0;
}
if( p->azModuleArg ){
int i;
for(i=0; i<p->nModuleArg; i++){
- sqliteFree(p->azModuleArg[i]);
+ sqlite3_free(p->azModuleArg[i]);
}
- sqliteFree(p->azModuleArg);
+ sqlite3_free(p->azModuleArg);
}
}
@@ -70,18 +132,18 @@ void sqlite3VtabClear(Table *p){
** string will be freed automatically when the table is
** deleted.
*/
-static void addModuleArgument(Table *pTable, char *zArg){
+static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){
int i = pTable->nModuleArg++;
int nBytes = sizeof(char *)*(1+pTable->nModuleArg);
char **azModuleArg;
- azModuleArg = sqliteRealloc(pTable->azModuleArg, nBytes);
+ azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes);
if( azModuleArg==0 ){
int j;
for(j=0; j<i; j++){
- sqliteFree(pTable->azModuleArg[j]);
+ sqlite3_free(pTable->azModuleArg[j]);
}
- sqliteFree(zArg);
- sqliteFree(pTable->azModuleArg);
+ sqlite3_free(zArg);
+ sqlite3_free(pTable->azModuleArg);
pTable->nModuleArg = 0;
}else{
azModuleArg[i] = zArg;
@@ -103,20 +165,27 @@ void sqlite3VtabBeginParse(
){
int iDb; /* The database the table is being created in */
Table *pTable; /* The new virtual table */
+ sqlite3 *db; /* Database connection */
+
+ if( pParse->db->flags & SQLITE_SharedCache ){
+ sqlite3ErrorMsg(pParse, "Cannot use virtual tables in shared-cache mode");
+ return;
+ }
sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0);
pTable = pParse->pNewTable;
if( pTable==0 || pParse->nErr ) return;
assert( 0==pTable->pIndex );
- iDb = sqlite3SchemaToIndex(pParse->db, pTable->pSchema);
+ db = pParse->db;
+ iDb = sqlite3SchemaToIndex(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));
+ addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
+ addModuleArgument(db, pTable, sqlite3DbStrDup(db, db->aDb[iDb].zName));
+ addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
pParse->sNameToken.n = pModuleName->z + pModuleName->n - pName1->z;
#ifndef SQLITE_OMIT_AUTHORIZATION
@@ -139,9 +208,10 @@ void sqlite3VtabBeginParse(
*/
static void addArgumentToVtab(Parse *pParse){
if( pParse->sArg.z && pParse->pNewTable ){
- const char *z = pParse->sArg.z;
+ const char *z = (const char*)pParse->sArg.z;
int n = pParse->sArg.n;
- addModuleArgument(pParse->pNewTable, sqliteStrNDup(z, n));
+ sqlite3 *db = pParse->db;
+ addModuleArgument(db, pParse->pNewTable, sqlite3DbStrNDup(db, z, n));
}
}
@@ -183,35 +253,36 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
if( pEnd ){
pParse->sNameToken.n = pEnd->z - pParse->sNameToken.z + pEnd->n;
}
- zStmt = sqlite3MPrintf("CREATE VIRTUAL TABLE %T", &pParse->sNameToken);
+ zStmt = sqlite3MPrintf(db, "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.
+ ** The VM register number pParse->regRowid holds the rowid of an
+ ** entry in the sqlite_master table tht was created for this vtab
+ ** by sqlite3StartTable().
*/
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",
+ "WHERE rowid=#%d",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
pTab->zName,
pTab->zName,
- zStmt
+ zStmt,
+ pParse->regRowid
);
- sqliteFree(zStmt);
+ sqlite3_free(zStmt);
v = sqlite3GetVdbe(pParse);
- sqlite3ChangeCookie(db, v, iDb);
+ sqlite3ChangeCookie(pParse, 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);
+ sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
+ zWhere = sqlite3MPrintf(db, "name='%q'", pTab->zName);
+ sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 1, 0, zWhere, P4_DYNAMIC);
+ sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0,
+ pTab->zName, strlen(pTab->zName) + 1);
}
/* If we are rereading the sqlite_master table create the in-memory
@@ -225,9 +296,11 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
int nName = strlen(zName) + 1;
pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab);
if( pOld ){
+ db->mallocFailed = 1;
assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */
return;
}
+ pSchema->db = pParse->db;
pParse->pNewTable = 0;
}
}
@@ -266,14 +339,20 @@ static int vtabCallConstructor(
sqlite3 *db,
Table *pTab,
Module *pMod,
- int (*xConstruct)(sqlite3*, void *, int, char **, sqlite3_vtab **),
+ int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
char **pzErr
){
int rc;
int rc2;
- char **azArg = pTab->azModuleArg;
+ sqlite3_vtab *pVtab = 0;
+ const char *const*azArg = (const char *const*)pTab->azModuleArg;
int nArg = pTab->nModuleArg;
- char *zErr = sqlite3MPrintf("vtable constructor failed: %s", pTab->zName);
+ char *zErr = 0;
+ char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
+
+ if( !zModuleName ){
+ return SQLITE_NOMEM;
+ }
assert( !db->pVTab );
assert( xConstruct );
@@ -281,26 +360,69 @@ static int vtabCallConstructor(
db->pVTab = pTab;
rc = sqlite3SafetyOff(db);
assert( rc==SQLITE_OK );
- rc = xConstruct(db, pMod->pAux, nArg, azArg, &pTab->pVtab);
+ rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVtab, &zErr);
rc2 = sqlite3SafetyOn(db);
- if( rc==SQLITE_OK && pTab->pVtab ){
- pTab->pVtab->pModule = pMod->pModule;
- pTab->pVtab->nRef = 1;
+ if( rc==SQLITE_OK && pVtab ){
+ pVtab->pModule = pMod->pModule;
+ pVtab->nRef = 1;
+ pTab->pVtab = pVtab;
}
if( SQLITE_OK!=rc ){
- *pzErr = zErr;
- zErr = 0;
- } else if( db->pVTab ){
+ if( zErr==0 ){
+ *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName);
+ }else {
+ *pzErr = sqlite3MPrintf(db, "%s", zErr);
+ sqlite3_free(zErr);
+ }
+ }else if( db->pVTab ){
const char *zFormat = "vtable constructor did not declare schema: %s";
- *pzErr = sqlite3MPrintf(zFormat, pTab->zName);
+ *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
rc = SQLITE_ERROR;
}
if( rc==SQLITE_OK ){
rc = rc2;
}
db->pVTab = 0;
- sqliteFree(zErr);
+ sqlite3_free(zModuleName);
+
+ /* If everything went according to plan, loop through the columns
+ ** of the table to see if any of them contain the token "hidden".
+ ** If so, set the Column.isHidden flag and remove the token from
+ ** the type string.
+ */
+ if( rc==SQLITE_OK ){
+ int iCol;
+ for(iCol=0; iCol<pTab->nCol; iCol++){
+ char *zType = pTab->aCol[iCol].zType;
+ int nType;
+ int i = 0;
+ if( !zType ) continue;
+ nType = strlen(zType);
+ if( sqlite3StrNICmp("hidden", zType, 6) || (zType[6] && zType[6]!=' ') ){
+ for(i=0; i<nType; i++){
+ if( (0==sqlite3StrNICmp(" hidden", &zType[i], 7))
+ && (zType[i+7]=='\0' || zType[i+7]==' ')
+ ){
+ i++;
+ break;
+ }
+ }
+ }
+ if( i<nType ){
+ int j;
+ int nDel = 6 + (zType[i+6] ? 1 : 0);
+ for(j=i; (j+nDel)<=nType; j++){
+ zType[j] = zType[j+nDel];
+ }
+ if( zType[i]=='\0' && i>0 ){
+ assert(zType[i-1]==' ');
+ zType[i-1] = '\0';
+ }
+ pTab->aCol[iCol].isHidden = 1;
+ }
+ }
+ }
return rc;
}
@@ -313,7 +435,6 @@ static int vtabCallConstructor(
*/
int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
Module *pMod;
- const char *zModule;
int rc = SQLITE_OK;
if( !pTab || !pTab->isVirtual || pTab->pVtab ){
@@ -321,7 +442,6 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
}
pMod = pTab->pMod;
- zModule = pTab->azModuleArg[0];
if( !pMod ){
const char *zModule = pTab->azModuleArg[0];
sqlite3ErrorMsg(pParse, "no such module: %s", zModule);
@@ -333,7 +453,7 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
if( rc!=SQLITE_OK ){
sqlite3ErrorMsg(pParse, "%s", zErr);
}
- sqliteFree(zErr);
+ sqlite3_free(zErr);
}
return rc;
@@ -349,7 +469,7 @@ static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
if( (db->nVTrans%ARRAY_INCR)==0 ){
sqlite3_vtab **aVTrans;
int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR);
- aVTrans = sqliteRealloc((void *)db->aVTrans, nBytes);
+ aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes);
if( !aVTrans ){
return SQLITE_NOMEM;
}
@@ -359,7 +479,7 @@ static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
/* Add pVtab to the end of sqlite3.aVTrans */
db->aVTrans[db->nVTrans++] = pVtab;
- pVtab->nRef++;
+ sqlite3VtabLock(pVtab);
return SQLITE_OK;
}
@@ -369,7 +489,7 @@ static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
**
** 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.
+** In this case the caller must call sqlite3_free() on *pzErr.
*/
int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
int rc = SQLITE_OK;
@@ -387,7 +507,7 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
** error. Otherwise, do nothing.
*/
if( !pMod ){
- *pzErr = sqlite3MPrintf("no such module: %s", zModule);
+ *pzErr = sqlite3MPrintf(db, "no such module: %s", zModule);
rc = SQLITE_ERROR;
}else{
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr);
@@ -409,11 +529,14 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
Parse sParse;
int rc = SQLITE_OK;
- Table *pTab = db->pVTab;
+ Table *pTab;
char *zErr = 0;
+ sqlite3_mutex_enter(db->mutex);
+ pTab = db->pVTab;
if( !pTab ){
sqlite3Error(db, SQLITE_MISUSE, 0);
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_MISUSE;
}
assert(pTab->isVirtual && pTab->nCol==0 && pTab->aCol==0);
@@ -432,18 +555,21 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
pTab->nCol = sParse.pNewTable->nCol;
sParse.pNewTable->nCol = 0;
sParse.pNewTable->aCol = 0;
+ db->pVTab = 0;
} else {
sqlite3Error(db, SQLITE_ERROR, zErr);
- sqliteFree(zErr);
+ sqlite3_free(zErr);
rc = SQLITE_ERROR;
}
sParse.declareVtab = 0;
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
- sqlite3DeleteTable(0, sParse.pNewTable);
+ sqlite3DeleteTable(sParse.pNewTable);
sParse.pNewTable = 0;
- db->pVTab = 0;
+ assert( (rc&0xff)==rc );
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
return rc;
}
@@ -468,7 +594,7 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab)
if( xDestroy ){
rc = xDestroy(pTab->pVtab);
}
- sqlite3SafetyOn(db);
+ (void)sqlite3SafetyOn(db);
if( rc==SQLITE_OK ){
pTab->pVtab = 0;
}
@@ -487,19 +613,18 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab)
*/
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);
+ if( db->aVTrans ){
+ for(i=0; i<db->nVTrans && db->aVTrans[i]; i++){
+ sqlite3_vtab *pVtab = db->aVTrans[i];
+ int (*x)(sqlite3_vtab *);
+ x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset);
+ if( x ) x(pVtab);
+ sqlite3VtabUnlock(db, pVtab);
}
+ sqlite3_free(db->aVTrans);
+ db->nVTrans = 0;
+ db->aVTrans = 0;
}
- sqliteFree(db->aVTrans);
- db->nVTrans = 0;
- db->aVTrans = 0;
}
/*
@@ -613,6 +738,7 @@ int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
** SQLITE_FUNC_EPHEM flag.
*/
FuncDef *sqlite3VtabOverloadFunction(
+ sqlite3 *db, /* Database connection for reporting malloc problems */
FuncDef *pDef, /* Function to possibly overload */
int nArg, /* Number of arguments to the function */
Expr *pExpr /* First argument to the function */
@@ -623,6 +749,10 @@ FuncDef *sqlite3VtabOverloadFunction(
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
void *pArg;
FuncDef *pNew;
+ int rc = 0;
+ char *zLowerName;
+ unsigned char *z;
+
/* Check to see the left operand is a column in a virtual table */
if( pExpr==0 ) return pDef;
@@ -636,20 +766,29 @@ FuncDef *sqlite3VtabOverloadFunction(
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 ){
+ /* Call the xFindFunction method on the virtual table implementation
+ ** to see if the implementation wants to overload this function
+ */
+ zLowerName = sqlite3DbStrDup(db, pDef->zName);
+ if( zLowerName ){
+ for(z=(unsigned char*)zLowerName; *z; z++){
+ *z = sqlite3UpperToLower[*z];
+ }
+ rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg);
+ sqlite3_free(zLowerName);
+ }
+ if( rc==0 ){
return pDef;
}
/* Create a new ephemeral function definition for the overloaded
** function */
- pNew = sqliteMalloc( sizeof(*pNew) + strlen(pDef->zName) );
+ pNew = sqlite3DbMallocZero(db, sizeof(*pNew) + strlen(pDef->zName) );
if( pNew==0 ){
return pDef;
}
*pNew = *pDef;
- strcpy(pNew->zName, pDef->zName);
+ memcpy(pNew->zName, pDef->zName, strlen(pDef->zName)+1);
pNew->xFunc = xFunc;
pNew->pUserData = pArg;
pNew->flags |= SQLITE_FUNC_EPHEM;
diff --git a/ext/pdo_sqlite/sqlite/src/where.c b/ext/pdo_sqlite/sqlite/src/where.c
index bdbac8112c..b753d5edd5 100644
--- a/ext/pdo_sqlite/sqlite/src/where.c
+++ b/ext/pdo_sqlite/sqlite/src/where.c
@@ -26,23 +26,19 @@
#define BMS (sizeof(Bitmask)*8)
/*
-** Determine the number of elements in an array.
-*/
-#define ARRAYSIZE(X) (sizeof(X)/sizeof(X[0]))
-
-/*
** Trace output macros
*/
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
int sqlite3_where_trace = 0;
-# define TRACE(X) if(sqlite3_where_trace) sqlite3DebugPrintf X
+# define WHERETRACE(X) if(sqlite3_where_trace) sqlite3DebugPrintf X
#else
-# define TRACE(X)
+# define WHERETRACE(X)
#endif
/* Forward reference
*/
typedef struct WhereClause WhereClause;
+typedef struct ExprMaskSet ExprMaskSet;
/*
** The query generator uses an array of instances of this structure to
@@ -106,6 +102,7 @@ struct WhereTerm {
*/
struct WhereClause {
Parse *pParse; /* The parser context */
+ ExprMaskSet *pMaskSet; /* Mapping of table indices to bitmasks */
int nTerm; /* Number of terms */
int nSlot; /* Number of entries in a[] */
WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */
@@ -138,7 +135,6 @@ struct WhereClause {
** numbers all get mapped into bit numbers that begin with 0 and contain
** no gaps.
*/
-typedef struct ExprMaskSet ExprMaskSet;
struct ExprMaskSet {
int n; /* Number of assigned cursor values */
int ix[sizeof(Bitmask)*8]; /* Cursor assigned to each bit */
@@ -157,30 +153,44 @@ struct ExprMaskSet {
#define WO_GT (WO_EQ<<(TK_GT-TK_EQ))
#define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
#define WO_MATCH 64
+#define WO_ISNULL 128
/*
-** Value for flags returned by bestIndex()
+** Value for flags returned by bestIndex().
+**
+** The least significant byte is reserved as a mask for WO_ values above.
+** The WhereLevel.flags field is usually set to WO_IN|WO_EQ|WO_ISNULL.
+** But if the table is the right table of a left join, WhereLevel.flags
+** is set to WO_IN|WO_EQ. The WhereLevel.flags field can then be used as
+** the "op" parameter to findTerm when we are resolving equality constraints.
+** ISNULL constraints will then not be used on the right table of a left
+** join. Tickets #2177 and #2189.
*/
-#define WHERE_ROWID_EQ 0x0001 /* rowid=EXPR or rowid IN (...) */
-#define WHERE_ROWID_RANGE 0x0002 /* rowid<EXPR and/or rowid>EXPR */
-#define WHERE_COLUMN_EQ 0x0010 /* x=EXPR or x IN (...) */
-#define WHERE_COLUMN_RANGE 0x0020 /* x<EXPR and/or x>EXPR */
-#define WHERE_COLUMN_IN 0x0040 /* x IN (...) */
-#define WHERE_TOP_LIMIT 0x0100 /* x<EXPR or x<=EXPR constraint */
-#define WHERE_BTM_LIMIT 0x0200 /* x>EXPR or x>=EXPR constraint */
-#define WHERE_IDX_ONLY 0x0800 /* Use index only - omit table */
-#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 */
+#define WHERE_ROWID_EQ 0x000100 /* rowid=EXPR or rowid IN (...) */
+#define WHERE_ROWID_RANGE 0x000200 /* rowid<EXPR and/or rowid>EXPR */
+#define WHERE_COLUMN_EQ 0x001000 /* x=EXPR or x IN (...) */
+#define WHERE_COLUMN_RANGE 0x002000 /* x<EXPR and/or x>EXPR */
+#define WHERE_COLUMN_IN 0x004000 /* x IN (...) */
+#define WHERE_TOP_LIMIT 0x010000 /* x<EXPR or x<=EXPR constraint */
+#define WHERE_BTM_LIMIT 0x020000 /* x>EXPR or x>=EXPR constraint */
+#define WHERE_IDX_ONLY 0x080000 /* Use index only - omit table */
+#define WHERE_ORDERBY 0x100000 /* Output will appear in correct order */
+#define WHERE_REVERSE 0x200000 /* Scan in reverse order */
+#define WHERE_UNIQUE 0x400000 /* Selects no more than one row */
+#define WHERE_VIRTUALTABLE 0x800000 /* Use virtual-table processing */
/*
** Initialize a preallocated WhereClause structure.
*/
-static void whereClauseInit(WhereClause *pWC, Parse *pParse){
+static void whereClauseInit(
+ WhereClause *pWC, /* The WhereClause to be initialized */
+ Parse *pParse, /* The parsing context */
+ ExprMaskSet *pMaskSet /* Mapping from table indices to bitmasks */
+){
pWC->pParse = pParse;
+ pWC->pMaskSet = pMaskSet;
pWC->nTerm = 0;
- pWC->nSlot = ARRAYSIZE(pWC->aStatic);
+ pWC->nSlot = ArraySize(pWC->aStatic);
pWC->a = pWC->aStatic;
}
@@ -197,7 +207,7 @@ static void whereClauseClear(WhereClause *pWC){
}
}
if( pWC->a!=pWC->aStatic ){
- sqliteFree(pWC->a);
+ sqlite3_free(pWC->a);
}
}
@@ -205,6 +215,9 @@ static void whereClauseClear(WhereClause *pWC){
** Add a new entries to the WhereClause structure. Increase the allocated
** space as necessary.
**
+** If the flags argument includes TERM_DYNAMIC, then responsibility
+** for freeing the expression p is assumed by the WhereClause object.
+**
** WARNING: This routine might reallocate the space used to store
** WhereTerms. All pointers to WhereTerms should be invalided after
** calling this routine. Such pointers may be reinitialized by referencing
@@ -215,11 +228,18 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, int flags){
int idx;
if( pWC->nTerm>=pWC->nSlot ){
WhereTerm *pOld = pWC->a;
- pWC->a = sqliteMalloc( sizeof(pWC->a[0])*pWC->nSlot*2 );
- if( pWC->a==0 ) return 0;
+ pWC->a = sqlite3_malloc( sizeof(pWC->a[0])*pWC->nSlot*2 );
+ if( pWC->a==0 ){
+ pWC->pParse->db->mallocFailed = 1;
+ if( flags & TERM_DYNAMIC ){
+ sqlite3ExprDelete(p);
+ }
+ pWC->a = pOld;
+ return 0;
+ }
memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm);
if( pOld!=pWC->aStatic ){
- sqliteFree(pOld);
+ sqlite3_free(pOld);
}
pWC->nSlot *= 2;
}
@@ -287,7 +307,7 @@ static Bitmask getMask(ExprMaskSet *pMaskSet, int iCursor){
** array will never overflow.
*/
static void createMask(ExprMaskSet *pMaskSet, int iCursor){
- assert( pMaskSet->n < ARRAYSIZE(pMaskSet->ix) );
+ assert( pMaskSet->n < ArraySize(pMaskSet->ix) );
pMaskSet->ix[pMaskSet->n++] = iCursor;
}
@@ -331,15 +351,14 @@ static Bitmask exprListTableUsage(ExprMaskSet *pMaskSet, ExprList *pList){
return mask;
}
static Bitmask exprSelectTableUsage(ExprMaskSet *pMaskSet, Select *pS){
- Bitmask mask;
- if( pS==0 ){
- mask = 0;
- }else{
- mask = exprListTableUsage(pMaskSet, pS->pEList);
+ Bitmask mask = 0;
+ while( pS ){
+ mask |= exprListTableUsage(pMaskSet, pS->pEList);
mask |= exprListTableUsage(pMaskSet, pS->pGroupBy);
mask |= exprListTableUsage(pMaskSet, pS->pOrderBy);
mask |= exprTableUsage(pMaskSet, pS->pWhere);
mask |= exprTableUsage(pMaskSet, pS->pHaving);
+ pS = pS->pPrior;
}
return mask;
}
@@ -354,7 +373,7 @@ static int allowedOp(int op){
assert( TK_LT>TK_EQ && TK_LT<TK_GE );
assert( TK_LE>TK_EQ && TK_LE<TK_GE );
assert( TK_GE==TK_EQ+4 );
- return op==TK_IN || (op>=TK_EQ && op<=TK_GE);
+ return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL;
}
/*
@@ -365,10 +384,22 @@ static int allowedOp(int op){
/*
** Commute a comparision operator. Expressions of the form "X op Y"
** are converted into "Y op X".
+**
+** If a collation sequence is associated with either the left or right
+** side of the comparison, it remains associated with the same side after
+** the commutation. So "Y collate NOCASE op X" becomes
+** "X collate NOCASE op Y". This is because any collation sequence on
+** the left hand side of a comparison overrides any collation sequence
+** attached to the right. For the same reason the EP_ExpCollate flag
+** is not commuted.
*/
static void exprCommute(Expr *pExpr){
+ u16 expRight = (pExpr->pRight->flags & EP_ExpCollate);
+ u16 expLeft = (pExpr->pLeft->flags & EP_ExpCollate);
assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN );
SWAP(CollSeq*,pExpr->pRight->pColl,pExpr->pLeft->pColl);
+ pExpr->pRight->flags = (pExpr->pRight->flags & ~EP_ExpCollate) | expLeft;
+ pExpr->pLeft->flags = (pExpr->pLeft->flags & ~EP_ExpCollate) | expRight;
SWAP(Expr*,pExpr->pRight,pExpr->pLeft);
if( pExpr->op>=TK_GT ){
assert( TK_LT==TK_GT+2 );
@@ -388,9 +419,12 @@ static int operatorMask(int op){
assert( allowedOp(op) );
if( op==TK_IN ){
c = WO_IN;
+ }else if( op==TK_ISNULL ){
+ c = WO_ISNULL;
}else{
c = WO_EQ<<(op-TK_EQ);
}
+ assert( op!=TK_ISNULL || c==WO_ISNULL );
assert( op!=TK_IN || c==WO_IN );
assert( op!=TK_EQ || c==WO_EQ );
assert( op!=TK_LT || c==WO_LT );
@@ -422,7 +456,7 @@ static WhereTerm *findTerm(
&& pTerm->leftColumn==iColumn
&& (pTerm->eOperator & op)!=0
){
- if( iCur>=0 && pIdx ){
+ if( iCur>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){
Expr *pX = pTerm->pExpr;
CollSeq *pColl;
char idxaff;
@@ -431,15 +465,17 @@ static WhereTerm *findTerm(
idxaff = pIdx->pTable->aCol[iColumn].affinity;
if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue;
- pColl = sqlite3ExprCollSeq(pParse, pX->pLeft);
+
+ /* Figure out the collation sequence required from an index for
+ ** it to be useful for optimising expression pX. Store this
+ ** value in variable pColl.
+ */
+ assert(pX->pLeft);
+ pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
if( !pColl ){
- if( pX->pRight ){
- pColl = sqlite3ExprCollSeq(pParse, pX->pRight);
- }
- if( !pColl ){
- pColl = pParse->db->pDfltColl;
- }
+ pColl = pParse->db->pDfltColl;
}
+
for(j=0; j<pIdx->nColumn && pIdx->aiColumn[j]!=iColumn; j++){}
assert( j<pIdx->nColumn );
if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue;
@@ -451,7 +487,7 @@ static WhereTerm *findTerm(
}
/* Forward reference */
-static void exprAnalyze(SrcList*, ExprMaskSet*, WhereClause*, int);
+static void exprAnalyze(SrcList*, WhereClause*, int);
/*
** Call exprAnalyze on all terms in a WHERE clause.
@@ -460,12 +496,11 @@ static void exprAnalyze(SrcList*, ExprMaskSet*, WhereClause*, int);
*/
static void exprAnalyzeAll(
SrcList *pTabList, /* the FROM clause */
- ExprMaskSet *pMaskSet, /* table masks */
WhereClause *pWC /* the WHERE clause to be analyzed */
){
int i;
for(i=pWC->nTerm-1; i>=0; i--){
- exprAnalyze(pTabList, pMaskSet, pWC, i);
+ exprAnalyze(pTabList, pWC, i);
}
}
@@ -505,16 +540,21 @@ static int isLikeOrGlob(
return 0;
}
pColl = pLeft->pColl;
+ assert( pColl!=0 || pLeft->iColumn==-1 );
if( pColl==0 ){
+ /* No collation is defined for the ROWID. Use the default. */
pColl = db->pDfltColl;
}
if( (pColl->type!=SQLITE_COLL_BINARY || noCase) &&
(pColl->type!=SQLITE_COLL_NOCASE || !noCase) ){
return 0;
}
- sqlite3DequoteExpr(pRight);
+ sqlite3DequoteExpr(db, pRight);
z = (char *)pRight->token.z;
- for(cnt=0; (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2]; cnt++){}
+ cnt = 0;
+ if( z ){
+ while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; }
+ }
if( cnt==0 || 255==(u8)z[cnt] ){
return 0;
}
@@ -565,6 +605,92 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
pDerived->iRightJoinTable = pBase->iRightJoinTable;
}
+#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY)
+/*
+** Return TRUE if the given term of an OR clause can be converted
+** into an IN clause. The iCursor and iColumn define the left-hand
+** side of the IN clause.
+**
+** The context is that we have multiple OR-connected equality terms
+** like this:
+**
+** a=<expr1> OR a=<expr2> OR b=<expr3> OR ...
+**
+** The pOrTerm input to this routine corresponds to a single term of
+** this OR clause. In order for the term to be a condidate for
+** conversion to an IN operator, the following must be true:
+**
+** * The left-hand side of the term must be the column which
+** is identified by iCursor and iColumn.
+**
+** * If the right-hand side is also a column, then the affinities
+** of both right and left sides must be such that no type
+** conversions are required on the right. (Ticket #2249)
+**
+** If both of these conditions are true, then return true. Otherwise
+** return false.
+*/
+static int orTermIsOptCandidate(WhereTerm *pOrTerm, int iCursor, int iColumn){
+ int affLeft, affRight;
+ assert( pOrTerm->eOperator==WO_EQ );
+ if( pOrTerm->leftCursor!=iCursor ){
+ return 0;
+ }
+ if( pOrTerm->leftColumn!=iColumn ){
+ return 0;
+ }
+ affRight = sqlite3ExprAffinity(pOrTerm->pExpr->pRight);
+ if( affRight==0 ){
+ return 1;
+ }
+ affLeft = sqlite3ExprAffinity(pOrTerm->pExpr->pLeft);
+ if( affRight!=affLeft ){
+ return 0;
+ }
+ return 1;
+}
+
+/*
+** Return true if the given term of an OR clause can be ignored during
+** a check to make sure all OR terms are candidates for optimization.
+** In other words, return true if a call to the orTermIsOptCandidate()
+** above returned false but it is not necessary to disqualify the
+** optimization.
+**
+** Suppose the original OR phrase was this:
+**
+** a=4 OR a=11 OR a=b
+**
+** During analysis, the third term gets flipped around and duplicate
+** so that we are left with this:
+**
+** a=4 OR a=11 OR a=b OR b=a
+**
+** Since the last two terms are duplicates, only one of them
+** has to qualify in order for the whole phrase to qualify. When
+** this routine is called, we know that pOrTerm did not qualify.
+** This routine merely checks to see if pOrTerm has a duplicate that
+** might qualify. If there is a duplicate that has not yet been
+** disqualified, then return true. If there are no duplicates, or
+** the duplicate has also been disqualifed, return false.
+*/
+static int orTermHasOkDuplicate(WhereClause *pOr, WhereTerm *pOrTerm){
+ if( pOrTerm->flags & TERM_COPIED ){
+ /* This is the original term. The duplicate is to the left had
+ ** has not yet been analyzed and thus has not yet been disqualified. */
+ return 1;
+ }
+ if( (pOrTerm->flags & TERM_VIRTUAL)!=0
+ && (pOr->a[pOrTerm->iParent].flags & TERM_OR_OK)!=0 ){
+ /* This is a duplicate term. The original qualified so this one
+ ** does not have to. */
+ return 1;
+ }
+ /* This is either a singleton term or else it is a duplicate for
+ ** which the original did not qualify. Either way we are done for. */
+ return 0;
+}
+#endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */
/*
** The input to this routine is an WhereTerm structure with only the
@@ -580,23 +706,34 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
*/
static void exprAnalyze(
SrcList *pSrc, /* the FROM clause */
- ExprMaskSet *pMaskSet, /* table masks */
WhereClause *pWC, /* the WHERE clause */
int idxTerm /* Index of the term to be analyzed */
){
- WhereTerm *pTerm = &pWC->a[idxTerm];
- Expr *pExpr = pTerm->pExpr;
+ WhereTerm *pTerm;
+ ExprMaskSet *pMaskSet;
+ Expr *pExpr;
Bitmask prereqLeft;
Bitmask prereqAll;
int nPattern;
int isComplete;
+ int op;
+ Parse *pParse = pWC->pParse;
+ sqlite3 *db = pParse->db;
- if( sqlite3MallocFailed() ) return;
+ if( db->mallocFailed ){
+ return;
+ }
+ pTerm = &pWC->a[idxTerm];
+ pMaskSet = pWC->pMaskSet;
+ pExpr = pTerm->pExpr;
prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
- if( pExpr->op==TK_IN ){
+ op = pExpr->op;
+ if( op==TK_IN ){
assert( pExpr->pRight==0 );
pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->pList)
| exprSelectTableUsage(pMaskSet, pExpr->pSelect);
+ }else if( op==TK_ISNULL ){
+ pTerm->prereqRight = 0;
}else{
pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
}
@@ -608,20 +745,24 @@ static void exprAnalyze(
pTerm->leftCursor = -1;
pTerm->iParent = -1;
pTerm->eOperator = 0;
- if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){
+ if( allowedOp(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->eOperator = operatorMask(pExpr->op);
+ pTerm->eOperator = operatorMask(op);
}
if( pRight && pRight->op==TK_COLUMN ){
WhereTerm *pNew;
Expr *pDup;
if( pTerm->leftCursor>=0 ){
int idxNew;
- pDup = sqlite3ExprDup(pExpr);
+ pDup = sqlite3ExprDup(db, pExpr);
+ if( db->mallocFailed ){
+ sqlite3ExprDelete(pDup);
+ return;
+ }
idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC);
if( idxNew==0 ) return;
pNew = &pWC->a[idxNew];
@@ -656,10 +797,10 @@ static void exprAnalyze(
for(i=0; i<2; i++){
Expr *pNewExpr;
int idxNew;
- pNewExpr = sqlite3Expr(ops[i], sqlite3ExprDup(pExpr->pLeft),
- sqlite3ExprDup(pList->a[i].pExpr), 0);
+ pNewExpr = sqlite3Expr(db, ops[i], sqlite3ExprDup(db, pExpr->pLeft),
+ sqlite3ExprDup(db, pList->a[i].pExpr), 0);
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
- exprAnalyze(pSrc, pMaskSet, pWC, idxNew);
+ exprAnalyze(pSrc, pWC, idxNew);
pTerm = &pWC->a[idxTerm];
pWC->a[idxNew].iParent = idxTerm;
}
@@ -688,12 +829,13 @@ static void exprAnalyze(
WhereTerm *pOrTerm;
assert( (pTerm->flags & TERM_DYNAMIC)==0 );
- whereClauseInit(&sOr, pWC->pParse);
+ whereClauseInit(&sOr, pWC->pParse, pMaskSet);
whereSplit(&sOr, pExpr, TK_OR);
- exprAnalyzeAll(pSrc, pMaskSet, &sOr);
- assert( sOr.nTerm>0 );
+ exprAnalyzeAll(pSrc, &sOr);
+ assert( sOr.nTerm>=2 );
j = 0;
do{
+ assert( j<sOr.nTerm );
iColumn = sOr.a[j].leftColumn;
iCursor = sOr.a[j].leftCursor;
ok = iCursor>=0;
@@ -701,37 +843,34 @@ static void exprAnalyze(
if( pOrTerm->eOperator!=WO_EQ ){
goto or_not_possible;
}
- if( pOrTerm->leftCursor==iCursor && pOrTerm->leftColumn==iColumn ){
+ if( orTermIsOptCandidate(pOrTerm, iCursor, iColumn) ){
pOrTerm->flags |= TERM_OR_OK;
- }else if( (pOrTerm->flags & TERM_COPIED)!=0 ||
- ((pOrTerm->flags & TERM_VIRTUAL)!=0 &&
- (sOr.a[pOrTerm->iParent].flags & TERM_OR_OK)!=0) ){
+ }else if( orTermHasOkDuplicate(&sOr, pOrTerm) ){
pOrTerm->flags &= ~TERM_OR_OK;
}else{
ok = 0;
}
}
- }while( !ok && (sOr.a[j++].flags & TERM_COPIED)!=0 && j<sOr.nTerm );
+ }while( !ok && (sOr.a[j++].flags & TERM_COPIED)!=0 && j<2 );
if( ok ){
ExprList *pList = 0;
Expr *pNew, *pDup;
+ Expr *pLeft = 0;
for(i=sOr.nTerm-1, pOrTerm=sOr.a; i>=0 && ok; i--, pOrTerm++){
if( (pOrTerm->flags & TERM_OR_OK)==0 ) continue;
- pDup = sqlite3ExprDup(pOrTerm->pExpr->pRight);
- pList = sqlite3ExprListAppend(pList, pDup, 0);
- }
- pDup = sqlite3Expr(TK_COLUMN, 0, 0, 0);
- if( pDup ){
- pDup->iTable = iCursor;
- pDup->iColumn = iColumn;
+ pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight);
+ pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup, 0);
+ pLeft = pOrTerm->pExpr->pLeft;
}
- pNew = sqlite3Expr(TK_IN, pDup, 0, 0);
+ assert( pLeft!=0 );
+ pDup = sqlite3ExprDup(db, pLeft);
+ pNew = sqlite3Expr(db, 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);
+ exprAnalyze(pSrc, pWC, idxNew);
pTerm = &pWC->a[idxTerm];
pWC->a[idxNew].iParent = idxTerm;
pTerm->nChild = 1;
@@ -748,7 +887,7 @@ or_not_possible:
/* Add constraints to reduce the search space on a LIKE or GLOB
** operator.
*/
- if( isLikeOrGlob(pWC->pParse->db, pExpr, &nPattern, &isComplete) ){
+ if( isLikeOrGlob(db, pExpr, &nPattern, &isComplete) ){
Expr *pLeft, *pRight;
Expr *pStr1, *pStr2;
Expr *pNewExpr1, *pNewExpr2;
@@ -756,22 +895,23 @@ or_not_possible:
pLeft = pExpr->pList->a[1].pExpr;
pRight = pExpr->pList->a[0].pExpr;
- pStr1 = sqlite3Expr(TK_STRING, 0, 0, 0);
+ pStr1 = sqlite3PExpr(pParse, TK_STRING, 0, 0, 0);
if( pStr1 ){
- sqlite3TokenCopy(&pStr1->token, &pRight->token);
+ sqlite3TokenCopy(db, &pStr1->token, &pRight->token);
pStr1->token.n = nPattern;
+ pStr1->flags = EP_Dequoted;
}
- pStr2 = sqlite3ExprDup(pStr1);
- if( pStr2 ){
+ pStr2 = sqlite3ExprDup(db, pStr1);
+ if( !db->mallocFailed ){
assert( pStr2->token.dyn );
++*(u8*)&pStr2->token.z[nPattern-1];
}
- pNewExpr1 = sqlite3Expr(TK_GE, sqlite3ExprDup(pLeft), pStr1, 0);
+ pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprDup(db,pLeft), pStr1, 0);
idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
- exprAnalyze(pSrc, pMaskSet, pWC, idxNew1);
- pNewExpr2 = sqlite3Expr(TK_LT, sqlite3ExprDup(pLeft), pStr2, 0);
+ exprAnalyze(pSrc, pWC, idxNew1);
+ pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprDup(db,pLeft), pStr2, 0);
idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
- exprAnalyze(pSrc, pMaskSet, pWC, idxNew2);
+ exprAnalyze(pSrc, pWC, idxNew2);
pTerm = &pWC->a[idxTerm];
if( isComplete ){
pWC->a[idxNew1].iParent = idxTerm;
@@ -800,7 +940,7 @@ or_not_possible:
prereqColumn = exprTableUsage(pMaskSet, pLeft);
if( (prereqExpr & prereqColumn)==0 ){
Expr *pNewExpr;
- pNewExpr = sqlite3Expr(TK_MATCH, 0, sqlite3ExprDup(pRight), 0);
+ pNewExpr = sqlite3Expr(db, TK_MATCH, 0, sqlite3ExprDup(db, pRight), 0);
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
pNewTerm = &pWC->a[idxNew];
pNewTerm->prereqRight = prereqExpr;
@@ -817,6 +957,25 @@ or_not_possible:
#endif /* SQLITE_OMIT_VIRTUALTABLE */
}
+/*
+** Return TRUE if any of the expressions in pList->a[iFirst...] contain
+** a reference to any table other than the iBase table.
+*/
+static int referencesOtherTables(
+ ExprList *pList, /* Search expressions in ths list */
+ ExprMaskSet *pMaskSet, /* Mapping from tables to bitmaps */
+ int iFirst, /* Be searching with the iFirst-th expression */
+ int iBase /* Ignore references to this table */
+){
+ Bitmask allowed = ~getMask(pMaskSet, iBase);
+ while( iFirst<pList->nExpr ){
+ if( (exprTableUsage(pMaskSet, pList->a[iFirst++].pExpr)&allowed)!=0 ){
+ return 1;
+ }
+ }
+ return 0;
+}
+
/*
** This routine decides if pIdx can be used to satisfy the ORDER BY
@@ -839,6 +998,7 @@ or_not_possible:
*/
static int isSortingIndex(
Parse *pParse, /* Parsing context */
+ ExprMaskSet *pMaskSet, /* Mapping from table indices to bitmaps */
Index *pIdx, /* The index we are testing */
int base, /* Cursor number for the table to be sorted */
ExprList *pOrderBy, /* The ORDER BY clause */
@@ -857,22 +1017,43 @@ static int isSortingIndex(
/* Match terms of the ORDER BY clause against columns of
** the index.
+ **
+ ** Note that indices have pIdx->nColumn regular columns plus
+ ** one additional column containing the rowid. The rowid column
+ ** of the index is also allowed to match against the ORDER BY
+ ** clause.
*/
- for(i=j=0, pTerm=pOrderBy->a; j<nTerm && i<pIdx->nColumn; i++){
+ 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 */
+ int iColumn; /* The i-th column of the index. -1 for rowid */
+ int iSortOrder; /* 1 for DESC, 0 for ASC on the i-th index term */
+ const char *zColl; /* Name of the collating sequence for i-th index term */
pExpr = pTerm->pExpr;
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){
/* Can not use an index sort on anything that is not a column in the
** left-most table of the FROM clause */
- return 0;
+ break;
}
pColl = sqlite3ExprCollSeq(pParse, pExpr);
- if( !pColl ) pColl = db->pDfltColl;
- if( pExpr->iColumn!=pIdx->aiColumn[i] ||
- sqlite3StrICmp(pColl->zName, pIdx->azColl[i]) ){
+ if( !pColl ){
+ pColl = db->pDfltColl;
+ }
+ if( i<pIdx->nColumn ){
+ iColumn = pIdx->aiColumn[i];
+ if( iColumn==pIdx->pTable->iPKey ){
+ iColumn = -1;
+ }
+ iSortOrder = pIdx->aSortOrder[i];
+ zColl = pIdx->azColl[i];
+ }else{
+ iColumn = -1;
+ iSortOrder = 0;
+ zColl = pColl->zName;
+ }
+ if( pExpr->iColumn!=iColumn || sqlite3StrICmp(pColl->zName, zColl) ){
/* 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
@@ -888,8 +1069,8 @@ static int isSortingIndex(
}
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;
+ assert( iSortOrder==0 || iSortOrder==1 );
+ termSortOrder = iSortOrder ^ pTerm->sortOrder;
if( i>nEqCol ){
if( termSortOrder!=sortOrder ){
/* Indices can only be used if all ORDER BY terms past the
@@ -901,13 +1082,29 @@ static int isSortingIndex(
}
j++;
pTerm++;
+ if( iColumn<0 && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){
+ /* If the indexed column is the primary key and everything matches
+ ** so far and none of the ORDER BY terms to the right reference other
+ ** tables in the join, then we are assured that the index can be used
+ ** to sort because the primary key is unique and so none of the other
+ ** columns will make any difference
+ */
+ j = nTerm;
+ }
}
- /* The index can be used for sorting if all terms of the ORDER BY clause
- ** are covered.
- */
+ *pbRev = sortOrder!=0;
if( j>=nTerm ){
- *pbRev = sortOrder!=0;
+ /* All terms of the ORDER BY clause are covered by this index so
+ ** this index can be used for sorting. */
+ return 1;
+ }
+ if( pIdx->onError!=OE_None && i==pIdx->nColumn
+ && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){
+ /* All terms of this index match some prefix of the ORDER BY clause
+ ** and the index is UNIQUE and no terms on the tail of the ORDER BY
+ ** clause reference other tables in a join. If this is all true then
+ ** the order by clause is superfluous. */
return 1;
}
return 0;
@@ -921,6 +1118,7 @@ static int isSortingIndex(
static int sortableByRowid(
int base, /* Cursor number for table to be sorted */
ExprList *pOrderBy, /* The ORDER BY clause */
+ ExprMaskSet *pMaskSet, /* Mapping from tables to bitmaps */
int *pbRev /* Set to 1 if ORDER BY is DESC */
){
Expr *p;
@@ -928,8 +1126,8 @@ static int sortableByRowid(
assert( pOrderBy!=0 );
assert( pOrderBy->nExpr>0 );
p = pOrderBy->a[0].pExpr;
- if( pOrderBy->nExpr==1 && p->op==TK_COLUMN && p->iTable==base
- && p->iColumn==-1 ){
+ if( p->op==TK_COLUMN && p->iTable==base && p->iColumn==-1
+ && !referencesOtherTables(pOrderBy, pMaskSet, 1, base) ){
*pbRev = pOrderBy->a[0].sortOrder;
return 1;
}
@@ -959,8 +1157,7 @@ static double estLog(double N){
** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines
** are no-ops.
*/
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && \
- (defined(SQLITE_TEST) || defined(SQLITE_DEBUG))
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_DEBUG)
static void TRACE_IDX_INPUTS(sqlite3_index_info *p){
int i;
if( !sqlite3_where_trace ) return;
@@ -1042,13 +1239,14 @@ static double bestVirtualIndex(
if( pIdxInfo==0 ){
WhereTerm *pTerm;
int nTerm;
- TRACE(("Recomputing index info for %s...\n", pTab->zName));
+ WHERETRACE(("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;
+ if( pTerm->eOperator==WO_ISNULL ) continue;
nTerm++;
}
@@ -1069,7 +1267,7 @@ static double bestVirtualIndex(
/* Allocate the sqlite3_index_info structure
*/
- pIdxInfo = sqliteMalloc( sizeof(*pIdxInfo)
+ pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo)
+ (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
+ sizeof(*pIdxOrderBy)*nOrderBy );
if( pIdxInfo==0 ){
@@ -1096,6 +1294,7 @@ static double bestVirtualIndex(
for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
if( pTerm->leftCursor != pSrc->iCursor ) continue;
if( pTerm->eOperator==WO_IN ) continue;
+ if( pTerm->eOperator==WO_ISNULL ) continue;
pIdxCons[j].iColumn = pTerm->leftColumn;
pIdxCons[j].iTermOffset = i;
pIdxCons[j].op = pTerm->eOperator;
@@ -1125,13 +1324,19 @@ static double bestVirtualIndex(
** xBestIndex.
*/
- /* The module name must be defined */
+ /* The module name must be defined. Also, by this point there must
+ ** be a pointer to an sqlite3_vtab structure. Otherwise
+ ** sqlite3ViewGetColumnNames() would have picked up the error.
+ */
assert( pTab->azModuleArg && pTab->azModuleArg[0] );
+ assert( pTab->pVtab );
+#if 0
if( pTab->pVtab==0 ){
sqlite3ErrorMsg(pParse, "undefined module %s for table %s",
pTab->azModuleArg[0], pTab->zName);
return 0.0;
}
+#endif
/* Set the aConstraint[].usable fields and initialize all
** output variables to zero.
@@ -1174,22 +1379,21 @@ static double bestVirtualIndex(
*(int*)&pIdxInfo->nOrderBy = 0;
}
- sqlite3SafetyOff(pParse->db);
- TRACE(("xBestIndex for %s\n", pTab->zName));
+ (void)sqlite3SafetyOff(pParse->db);
+ WHERETRACE(("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();
+ pParse->db->mallocFailed = 1;
}else {
sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc));
}
- sqlite3SafetyOn(pParse->db);
- }else{
- rc = sqlite3SafetyOn(pParse->db);
}
+ (void)sqlite3SafetyOn(pParse->db);
*(int*)&pIdxInfo->nOrderBy = nOrderBy;
+
return pIdxInfo->estimatedCost;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -1232,9 +1436,10 @@ static double bestIndex(
int rev; /* True to scan in reverse order */
int flags; /* Flags associated with pProbe */
int nEq; /* Number of == or IN constraints */
+ int eqTermMask; /* Mask of valid equality operators */
double cost; /* Cost of using pProbe */
- TRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady));
+ WHERETRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady));
lowestCost = SQLITE_BIG_DBL;
pProbe = pSrc->pTab->pIndex;
@@ -1246,7 +1451,7 @@ static double bestIndex(
*/
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)) ){
+ (pOrderBy==0 || !sortableByRowid(iCur, pOrderBy, pWC->pMaskSet, &rev)) ){
*pFlags = 0;
*ppIndex = 0;
*pnEq = 0;
@@ -1265,7 +1470,7 @@ static double bestIndex(
** a single row is generated, output is always in sorted order */
*pFlags = WHERE_ROWID_EQ | WHERE_UNIQUE;
*pnEq = 1;
- TRACE(("... best is rowid\n"));
+ WHERETRACE(("... best is rowid\n"));
return 0.0;
}else if( (pExpr = pTerm->pExpr)->pList!=0 ){
/* Rowid IN (LIST): cost is NlogN where N is the number of list
@@ -1278,14 +1483,14 @@ static double bestIndex(
** that value so make a wild guess. */
lowestCost = 200;
}
- TRACE(("... rowid IN cost: %.9g\n", lowestCost));
+ WHERETRACE(("... rowid IN cost: %.9g\n", lowestCost));
}
/* 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.
*/
cost = pProbe ? pProbe->aiRowEst[0] : 1000000;
- TRACE(("... table scan base cost: %.9g\n", cost));
+ WHERETRACE(("... table scan base cost: %.9g\n", cost));
flags = WHERE_ROWID_RANGE;
/* Check for constraints on a range of rowids in a table scan.
@@ -1300,7 +1505,7 @@ static double bestIndex(
flags |= WHERE_BTM_LIMIT;
cost /= 3; /* Guess that rowid>EXPR eliminates two-thirds of rows */
}
- TRACE(("... rowid range reduces cost to %.9g\n", cost));
+ WHERETRACE(("... rowid range reduces cost to %.9g\n", cost));
}else{
flags = 0;
}
@@ -1308,14 +1513,14 @@ static double bestIndex(
/* If the table scan does not satisfy the ORDER BY clause, increase
** the cost by NlogN to cover the expense of sorting. */
if( pOrderBy ){
- if( sortableByRowid(iCur, pOrderBy, &rev) ){
+ if( sortableByRowid(iCur, pOrderBy, pWC->pMaskSet, &rev) ){
flags |= WHERE_ORDERBY|WHERE_ROWID_RANGE;
if( rev ){
flags |= WHERE_REVERSE;
}
}else{
cost += cost*estLog(cost);
- TRACE(("... sorting increases cost to %.9g\n", cost));
+ WHERETRACE(("... sorting increases cost to %.9g\n", cost));
}
}
if( cost<lowestCost ){
@@ -1323,13 +1528,24 @@ static double bestIndex(
bestFlags = flags;
}
+ /* If the pSrc table is the right table of a LEFT JOIN then we may not
+ ** use an index to satisfy IS NULL constraints on that table. This is
+ ** because columns might end up being NULL if the table does not match -
+ ** a circumstance which the index cannot help us discover. Ticket #2177.
+ */
+ if( (pSrc->jointype & JT_LEFT)!=0 ){
+ eqTermMask = WO_EQ|WO_IN;
+ }else{
+ eqTermMask = WO_EQ|WO_IN|WO_ISNULL;
+ }
+
/* Look at each index.
*/
for(; pProbe; pProbe=pProbe->pNext){
int i; /* Loop counter */
double inMultiplier = 1;
- TRACE(("... index %s:\n", pProbe->zName));
+ WHERETRACE(("... index %s:\n", pProbe->zName));
/* Count the number of columns in the index that are satisfied
** by x=EXPR constraints or x IN (...) constraints.
@@ -1337,7 +1553,7 @@ static double bestIndex(
flags = 0;
for(i=0; i<pProbe->nColumn; i++){
int j = pProbe->aiColumn[i];
- pTerm = findTerm(pWC, iCur, j, notReady, WO_EQ|WO_IN, pProbe);
+ pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pProbe);
if( pTerm==0 ) break;
flags |= WHERE_COLUMN_EQ;
if( pTerm->eOperator & WO_IN ){
@@ -1356,7 +1572,7 @@ static double bestIndex(
&& nEq==pProbe->nColumn ){
flags |= WHERE_UNIQUE;
}
- TRACE(("...... nEq=%d inMult=%.9g cost=%.9g\n", nEq, inMultiplier, cost));
+ WHERETRACE(("...... nEq=%d inMult=%.9g cost=%.9g\n",nEq,inMultiplier,cost));
/* Look for range constraints
*/
@@ -1373,7 +1589,7 @@ static double bestIndex(
flags |= WHERE_BTM_LIMIT;
cost /= 3;
}
- TRACE(("...... range reduces cost to %.9g\n", cost));
+ WHERETRACE(("...... range reduces cost to %.9g\n", cost));
}
}
@@ -1381,7 +1597,7 @@ static double bestIndex(
*/
if( pOrderBy ){
if( (flags & WHERE_COLUMN_IN)==0 &&
- isSortingIndex(pParse,pProbe,iCur,pOrderBy,nEq,&rev) ){
+ isSortingIndex(pParse,pWC->pMaskSet,pProbe,iCur,pOrderBy,nEq,&rev) ){
if( flags==0 ){
flags = WHERE_COLUMN_RANGE;
}
@@ -1391,7 +1607,7 @@ static double bestIndex(
}
}else{
cost += cost*estLog(cost);
- TRACE(("...... orderby increases cost to %.9g\n", cost));
+ WHERETRACE(("...... orderby increases cost to %.9g\n", cost));
}
}
@@ -1411,16 +1627,15 @@ static double bestIndex(
if( m==0 ){
flags |= WHERE_IDX_ONLY;
cost /= 2;
- TRACE(("...... idx-only reduces cost to %.9g\n", cost));
+ WHERETRACE(("...... idx-only reduces cost to %.9g\n", cost));
}
}
/* If this index has achieved the lowest cost so far, then use it.
*/
- if( cost < lowestCost ){
+ if( flags && cost < lowestCost ){
bestIdx = pProbe;
lowestCost = cost;
- assert( flags!=0 );
bestFlags = flags;
bestNEq = nEq;
}
@@ -1429,9 +1644,9 @@ static double bestIndex(
/* Report the best result
*/
*ppIndex = bestIdx;
- TRACE(("best index is %s, cost=%.9g, flags=%x, nEq=%d\n",
+ WHERETRACE(("best index is %s, cost=%.9g, flags=%x, nEq=%d\n",
bestIdx ? bestIdx->zName : "(none)", lowestCost, bestFlags, bestNEq));
- *pFlags = bestFlags;
+ *pFlags = bestFlags | eqTermMask;
*pnEq = bestNEq;
return lowestCost;
}
@@ -1476,31 +1691,23 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
}
/*
-** Generate code that builds a probe for an index. Details:
-**
-** * 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. 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.
-** Only nColumn elements are popped from the stack in this case
-** (by OP_MakeRecord).
+** Generate code that builds a probe for an index.
**
+** There should be nColumn values on the stack. The index
+** to be probed is pIdx. Pop the values from the stack and
+** replace them all with a single record that is the index
+** problem.
*/
static void buildIndexProbe(
- Vdbe *v,
- int nColumn,
- int nExtra,
- int brk,
- Index *pIdx
+ Vdbe *v, /* Generate code into this VM */
+ int nColumn, /* The number of columns to check for NULL */
+ Index *pIdx, /* Index that we will be searching */
+ int regSrc, /* Take values from this register */
+ int regDest /* Write the result into this register */
){
- sqlite3VdbeAddOp(v, OP_NotNull, -nColumn, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Pop, nColumn+nExtra, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
- sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
+ assert( regSrc>0 );
+ assert( regDest>0 );
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regSrc, nColumn, regDest);
sqlite3IndexAffinityStr(v, pIdx);
}
@@ -1510,7 +1717,7 @@ static void buildIndexProbe(
** term can be either X=expr or X IN (...). pTerm is the term to be
** coded.
**
-** The current value for the constraint is left on the top of the stack.
+** The current value for the constraint is left in register iReg.
**
** For a constraint of the form X=expr, the expression is evaluated and its
** result is left on the stack. For constraints of the form X IN (...)
@@ -1519,31 +1726,44 @@ static void buildIndexProbe(
static void codeEqualityTerm(
Parse *pParse, /* The parsing context */
WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
- int brk, /* Jump here to abandon the loop */
- WhereLevel *pLevel /* When level of the FROM clause we are working on */
+ WhereLevel *pLevel, /* When level of the FROM clause we are working on */
+ int iReg /* Leave results in this register */
){
Expr *pX = pTerm->pExpr;
- if( pX->op!=TK_IN ){
- assert( pX->op==TK_EQ );
- sqlite3ExprCode(pParse, pX->pRight);
+ Vdbe *v = pParse->pVdbe;
+
+ assert( iReg>0 && iReg<=pParse->nMem );
+ if( pX->op==TK_EQ ){
+ sqlite3ExprCode(pParse, pX->pRight, iReg);
+ }else if( pX->op==TK_ISNULL ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, iReg);
#ifndef SQLITE_OMIT_SUBQUERY
}else{
+ int eType;
int iTab;
- int *aIn;
- Vdbe *v = pParse->pVdbe;
+ struct InLoop *pIn;
- sqlite3CodeSubselect(pParse, pX);
+ assert( pX->op==TK_IN );
+ eType = sqlite3FindInIndex(pParse, pX, 1);
iTab = pX->iTable;
- sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0);
- VdbeComment((v, "# %.*s", pX->span.n, pX->span.z));
+ sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
+ VdbeComment((v, "%.*s", pX->span.n, pX->span.z));
+ if( pLevel->nIn==0 ){
+ pLevel->nxt = sqlite3VdbeMakeLabel(v);
+ }
pLevel->nIn++;
- sqliteReallocOrFree((void**)&pLevel->aInLoop,
- sizeof(pLevel->aInLoop[0])*2*pLevel->nIn);
- aIn = pLevel->aInLoop;
- if( aIn ){
- aIn += pLevel->nIn*2 - 2;
- aIn[0] = iTab;
- aIn[1] = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
+ pLevel->aInLoop = sqlite3DbReallocOrFree(pParse->db, pLevel->aInLoop,
+ sizeof(pLevel->aInLoop[0])*pLevel->nIn);
+ pIn = pLevel->aInLoop;
+ if( pIn ){
+ pIn += pLevel->nIn - 1;
+ pIn->iCur = iTab;
+ if( eType==IN_INDEX_ROWID ){
+ pIn->topAddr = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg);
+ }else{
+ pIn->topAddr = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg);
+ }
+ sqlite3VdbeAddOp1(v, OP_IsNull, iReg);
}else{
pLevel->nIn = 0;
}
@@ -1575,53 +1795,44 @@ static void codeEqualityTerm(
** this routine allocates an additional nEq memory cells for internal
** use.
*/
-static void codeAllEqualityTerms(
+static int codeAllEqualityTerms(
Parse *pParse, /* Parsing context */
WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */
WhereClause *pWC, /* The WHERE clause */
Bitmask notReady, /* Which parts of FROM have not yet been coded */
- int brk /* Jump here to end the loop */
+ int nExtraReg /* Number of extra registers to allocate */
){
int nEq = pLevel->nEq; /* The number of == or IN constraints to code */
- int termsInMem = 0; /* If true, store value in mem[] cells */
Vdbe *v = pParse->pVdbe; /* The virtual machine under construction */
Index *pIdx = pLevel->pIdx; /* The index being used for this loop */
int iCur = pLevel->iTabCur; /* The cursor of the table */
WhereTerm *pTerm; /* A single constraint term */
int j; /* Loop counter */
+ int regBase; /* Base register */
/* Figure out how many memory cells we will need then allocate them.
** We always need at least one used to store the loop terminator
** value. If there are IN operators we'll need one for each == or
** IN constraint.
*/
- pLevel->iMem = pParse->nMem++;
- if( pLevel->flags & WHERE_COLUMN_IN ){
- pParse->nMem += pLevel->nEq;
- termsInMem = 1;
- }
+ pLevel->iMem = pParse->nMem + 1;
+ regBase = pParse->nMem + 2;
+ pParse->nMem += pLevel->nEq + 2 + nExtraReg;
/* Evaluate the equality constraints
*/
- for(j=0; j<pIdx->nColumn; j++){
+ assert( pIdx->nColumn>=nEq );
+ for(j=0; j<nEq; j++){
int k = pIdx->aiColumn[j];
- pTerm = findTerm(pWC, iCur, k, notReady, WO_EQ|WO_IN, pIdx);
+ pTerm = findTerm(pWC, iCur, k, notReady, pLevel->flags, pIdx);
if( pTerm==0 ) break;
assert( (pTerm->flags & TERM_CODED)==0 );
- codeEqualityTerm(pParse, pTerm, brk, pLevel);
- if( termsInMem ){
- sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem+j+1, 1);
- }
- }
- assert( j==nEq );
-
- /* Make sure all the constraint values are on the top of the stack
- */
- if( termsInMem ){
- for(j=0; j<nEq; j++){
- sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem+j+1, 0);
+ codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
+ if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
+ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->brk);
}
}
+ return regBase;
}
#if defined(SQLITE_TEST)
@@ -1646,13 +1857,11 @@ static void whereInfoFree(WhereInfo *pWInfo){
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);
+ assert( pInfo->needToFreeIdxStr==0 );
+ sqlite3_free(pInfo);
}
}
- sqliteFree(pWInfo);
+ sqlite3_free(pWInfo);
}
}
@@ -1749,7 +1958,8 @@ WhereInfo *sqlite3WhereBegin(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* A list of all tables to be scanned */
Expr *pWhere, /* The WHERE clause */
- ExprList **ppOrderBy /* An ORDER BY clause, or NULL */
+ ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */
+ u8 obflag /* One of ORDERBY_MIN, ORDERBY_MAX or ORDERBY_NORMAL */
){
int i; /* Loop counter */
WhereInfo *pWInfo; /* Will become the return value of this function */
@@ -1763,6 +1973,8 @@ WhereInfo *sqlite3WhereBegin(
WhereLevel *pLevel; /* A single level in the pWInfo list */
int iFrom; /* First unused FROM clause element */
int andFlags; /* AND-ed combination of all wc.a[].flags */
+ sqlite3 *db; /* Database connection */
+ ExprList *pOrderBy = 0;
/* The number of tables in the FROM clause is limited by the number of
** bits in a Bitmask
@@ -1772,18 +1984,24 @@ WhereInfo *sqlite3WhereBegin(
return 0;
}
+ if( ppOrderBy ){
+ pOrderBy = *ppOrderBy;
+ }
+
/* Split the WHERE clause into separate subexpressions where each
** subexpression is separated by an AND operator.
*/
initMaskSet(&maskSet);
- whereClauseInit(&wc, pParse);
+ whereClauseInit(&wc, pParse, &maskSet);
whereSplit(&wc, pWhere, TK_AND);
/* Allocate and initialize the WhereInfo structure that will become the
** return value.
*/
- pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));
- if( sqlite3MallocFailed() ){
+ db = pParse->db;
+ pWInfo = sqlite3DbMallocZero(db,
+ sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));
+ if( db->mallocFailed ){
goto whereBeginNoMem;
}
pWInfo->nLevel = pTabList->nSrc;
@@ -1794,8 +2012,8 @@ WhereInfo *sqlite3WhereBegin(
/* Special case: a WHERE clause that is constant. Evaluate the
** expression and either jump over all of the code or fall thru.
*/
- if( pWhere && (pTabList->nSrc==0 || sqlite3ExprIsConstant(pWhere)) ){
- sqlite3ExprIfFalse(pParse, pWhere, pWInfo->iBreak, 1);
+ if( pWhere && (pTabList->nSrc==0 || sqlite3ExprIsConstantNotJoin(pWhere)) ){
+ sqlite3ExprIfFalse(pParse, pWhere, pWInfo->iBreak, SQLITE_JUMPIFNULL);
pWhere = 0;
}
@@ -1807,8 +2025,8 @@ WhereInfo *sqlite3WhereBegin(
for(i=0; i<pTabList->nSrc; i++){
createMask(&maskSet, pTabList->a[i].iCursor);
}
- exprAnalyzeAll(pTabList, &maskSet, &wc);
- if( sqlite3MallocFailed() ){
+ exprAnalyzeAll(pTabList, &wc);
+ if( db->mallocFailed ){
goto whereBeginNoMem;
}
@@ -1830,7 +2048,7 @@ WhereInfo *sqlite3WhereBegin(
pTabItem = pTabList->a;
pLevel = pWInfo->a;
andFlags = ~0;
- TRACE(("*** Optimizer Start ***\n"));
+ WHERETRACE(("*** Optimizer Start ***\n"));
for(i=iFrom=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
Index *pIdx; /* Index for FROM table at pTabItem */
int flags; /* Flags asssociated with pIdx */
@@ -1850,8 +2068,7 @@ WhereInfo *sqlite3WhereBegin(
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);
+ doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0;
if( once && doNotReorder ) break;
m = getMask(&maskSet, pTabItem->iCursor);
if( (m & notReady)==0 ){
@@ -1872,6 +2089,14 @@ WhereInfo *sqlite3WhereBegin(
}
pIdx = 0;
nEq = 0;
+ if( (SQLITE_BIG_DBL/2.0)<cost ){
+ /* The cost is not allowed to be larger than SQLITE_BIG_DBL (the
+ ** inital value of lowestCost in this loop. If it is, then
+ ** the (cost<lowestCost) test below will never be true and
+ ** pLevel->pBestIdx never set.
+ */
+ cost = (SQLITE_BIG_DBL/2.0);
+ }
}else
#endif
{
@@ -1891,7 +2116,7 @@ WhereInfo *sqlite3WhereBegin(
}
if( doNotReorder ) break;
}
- TRACE(("*** Optimizer choose table %d for loop %d\n", bestJ,
+ WHERETRACE(("*** Optimizer choose table %d for loop %d\n", bestJ,
pLevel-pWInfo->a));
if( (bestFlags & WHERE_ORDERBY)!=0 ){
*ppOrderBy = 0;
@@ -1910,7 +2135,7 @@ WhereInfo *sqlite3WhereBegin(
notReady &= ~getMask(&maskSet, pTabList->a[bestJ].iCursor);
pLevel->iFrom = bestJ;
}
- TRACE(("*** Optimizer Finished ***\n"));
+ WHERETRACE(("*** Optimizer Finished ***\n"));
/* If the total query only selects a single row, then the ORDER BY
** clause is irrelevant.
@@ -1933,26 +2158,26 @@ WhereInfo *sqlite3WhereBegin(
if( pParse->explain==2 ){
char *zMsg;
struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
- zMsg = sqlite3MPrintf("TABLE %s", pItem->zName);
+ zMsg = sqlite3MPrintf(db, "TABLE %s", pItem->zName);
if( pItem->zAlias ){
- zMsg = sqlite3MPrintf("%z AS %s", zMsg, pItem->zAlias);
+ zMsg = sqlite3MPrintf(db, "%z AS %s", zMsg, pItem->zAlias);
}
if( (pIx = pLevel->pIdx)!=0 ){
- zMsg = sqlite3MPrintf("%z WITH INDEX %s", zMsg, pIx->zName);
+ zMsg = sqlite3MPrintf(db, "%z WITH INDEX %s", zMsg, pIx->zName);
}else if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
- zMsg = sqlite3MPrintf("%z USING PRIMARY KEY", zMsg);
+ zMsg = sqlite3MPrintf(db, "%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,
+ zMsg = sqlite3MPrintf(db, "%z VIRTUAL TABLE INDEX %d:%s", zMsg,
pBestIdx->idxNum, pBestIdx->idxStr);
}
#endif
if( pLevel->flags & WHERE_ORDERBY ){
- zMsg = sqlite3MPrintf("%z ORDER BY", zMsg);
+ zMsg = sqlite3MPrintf(db, "%z ORDER BY", zMsg);
}
- sqlite3VdbeOp3(v, OP_Explain, i, pLevel->iFrom, zMsg, P3_DYNAMIC);
+ sqlite3VdbeAddOp4(v, OP_Explain, i, pLevel->iFrom, 0, zMsg, P4_DYNAMIC);
}
#endif /* SQLITE_OMIT_EXPLAIN */
pTabItem = &pTabList->a[pLevel->iFrom];
@@ -1962,7 +2187,8 @@ WhereInfo *sqlite3WhereBegin(
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( pLevel->pBestIdx ){
int iCur = pTabItem->iCursor;
- sqlite3VdbeOp3(v, OP_VOpen, iCur, 0, (const char*)pTab->pVtab, P3_VTAB);
+ sqlite3VdbeAddOp4(v, OP_VOpen, iCur, 0, 0,
+ (const char*)pTab->pVtab, P4_VTAB);
}else
#endif
if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){
@@ -1981,13 +2207,10 @@ WhereInfo *sqlite3WhereBegin(
if( (pIx = pLevel->pIdx)!=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*)pKey, P3_KEYINFO_HANDOFF);
- }
- if( (pLevel->flags & WHERE_IDX_ONLY)!=0 ){
- sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1);
+ sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, pIx->tnum, iDb,
+ (char*)pKey, P4_KEYINFO_HANDOFF);
+ VdbeComment((v, "%s", pIx->zName));
+ sqlite3VdbeAddOp2(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1);
}
sqlite3CodeVerifySchema(pParse, iDb);
}
@@ -2002,6 +2225,7 @@ WhereInfo *sqlite3WhereBegin(
int j;
int iCur = pTabItem->iCursor; /* The VDBE cursor for the table */
Index *pIdx; /* The index we will be using */
+ int nxt; /* Where to jump to continue with the next IN case */
int iIdxCur; /* The VDBE cursor for the index */
int omitTable; /* True if we use the index only */
int bRev; /* True if we need to scan in reverse order */
@@ -2017,19 +2241,23 @@ WhereInfo *sqlite3WhereBegin(
** for the current loop. Jump to brk to break out of a loop.
** Jump to cont to go immediately to the next iteration of the
** loop.
+ **
+ ** When there is an IN operator, we also have a "nxt" label that
+ ** means to continue with the next IN value combination. When
+ ** there are no IN operators in the constraints, the "nxt" label
+ ** is the same as "brk".
*/
- brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
+ brk = pLevel->brk = pLevel->nxt = sqlite3VdbeMakeLabel(v);
cont = pLevel->cont = sqlite3VdbeMakeLabel(v);
/* If this is the right table of a LEFT OUTER JOIN, allocate and
** initialize a memory cell that records if this table matches any
** row of the left table of the join.
*/
- if( pLevel->iFrom>0 && (pTabItem[-1].jointype & JT_LEFT)!=0 ){
- if( !pParse->nMem ) pParse->nMem++;
- pLevel->iLeftJoin = pParse->nMem++;
- sqlite3VdbeAddOp(v, OP_MemInt, 0, pLevel->iLeftJoin);
- VdbeComment((v, "# init LEFT JOIN no-match flag"));
+ if( pLevel->iFrom>0 && (pTabItem[0].jointype & JT_LEFT)!=0 ){
+ pLevel->iLeftJoin = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin);
+ VdbeComment((v, "init LEFT JOIN no-match flag"));
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -2038,6 +2266,7 @@ WhereInfo *sqlite3WhereBegin(
** to access the data.
*/
int j;
+ int iReg; /* P3 Value for OP_VFilter */
sqlite3_index_info *pBestIdx = pLevel->pBestIdx;
int nConstraint = pBestIdx->nConstraint;
struct sqlite3_index_constraint_usage *aUsage =
@@ -2045,21 +2274,23 @@ WhereInfo *sqlite3WhereBegin(
const struct sqlite3_index_constraint *aConstraint =
pBestIdx->aConstraint;
+ iReg = sqlite3GetTempRange(pParse, nConstraint+2);
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);
+ sqlite3ExprCode(pParse, wc.a[iTerm].pExpr->pRight, iReg+j+1);
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);
+ sqlite3VdbeAddOp2(v, OP_Integer, pBestIdx->idxNum, iReg);
+ sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1);
+ sqlite3VdbeAddOp4(v, OP_VFilter, iCur, brk, iReg, pBestIdx->idxStr,
+ pBestIdx->needToFreeIdxStr ? P4_MPRINTF : P4_STATIC);
+ sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
pBestIdx->needToFreeIdxStr = 0;
for(j=0; j<pBestIdx->nConstraint; j++){
if( aUsage[j].omit ){
@@ -2079,15 +2310,19 @@ WhereInfo *sqlite3WhereBegin(
** we reference multiple rows using a "rowid IN (...)"
** construct.
*/
+ int r1;
pTerm = findTerm(&wc, iCur, -1, notReady, WO_EQ|WO_IN, 0);
assert( pTerm!=0 );
assert( pTerm->pExpr!=0 );
assert( pTerm->leftCursor==iCur );
assert( omitTable==0 );
- codeEqualityTerm(pParse, pTerm, brk, pLevel);
- sqlite3VdbeAddOp(v, OP_MustBeInt, 1, brk);
- sqlite3VdbeAddOp(v, OP_NotExists, iCur, brk);
+ r1 = sqlite3GetTempReg(pParse);
+ codeEqualityTerm(pParse, pTerm, pLevel, r1);
+ nxt = pLevel->nxt;
+ sqlite3VdbeAddOp3(v, OP_MustBeInt, r1, nxt, 1);
+ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, nxt, r1);
VdbeComment((v, "pk"));
+ sqlite3ReleaseTempReg(pParse, r1);
pLevel->op = OP_Noop;
}else if( pLevel->flags & WHERE_ROWID_RANGE ){
/* Case 2: We have an inequality comparison against the ROWID field.
@@ -2106,25 +2341,27 @@ WhereInfo *sqlite3WhereBegin(
}
if( pStart ){
Expr *pX;
+ int r1, regFree1;
pX = pStart->pExpr;
assert( pX!=0 );
assert( pStart->leftCursor==iCur );
- sqlite3ExprCode(pParse, pX->pRight);
- sqlite3VdbeAddOp(v, OP_ForceInt, pX->op==TK_LE || pX->op==TK_GT, brk);
- sqlite3VdbeAddOp(v, bRev ? OP_MoveLt : OP_MoveGe, iCur, brk);
+ r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &regFree1);
+ sqlite3VdbeAddOp3(v, OP_ForceInt, r1, brk,
+ pX->op==TK_LE || pX->op==TK_GT);
+ sqlite3VdbeAddOp3(v, bRev ? OP_MoveLt : OP_MoveGe, iCur, brk, r1);
VdbeComment((v, "pk"));
+ sqlite3ReleaseTempReg(pParse, regFree1);
disableTerm(pLevel, pStart);
}else{
- sqlite3VdbeAddOp(v, bRev ? OP_Last : OP_Rewind, iCur, brk);
+ sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, brk);
}
if( pEnd ){
Expr *pX;
pX = pEnd->pExpr;
assert( pX!=0 );
assert( pEnd->leftCursor==iCur );
- sqlite3ExprCode(pParse, pX->pRight);
- pLevel->iMem = pParse->nMem++;
- sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
+ pLevel->iMem = ++pParse->nMem;
+ sqlite3ExprCode(pParse, pX->pRight, pLevel->iMem);
if( pX->op==TK_LT || pX->op==TK_GT ){
testOp = bRev ? OP_Le : OP_Ge;
}else{
@@ -2137,9 +2374,12 @@ WhereInfo *sqlite3WhereBegin(
pLevel->p1 = iCur;
pLevel->p2 = start;
if( testOp!=OP_Noop ){
- sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
- sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeAddOp(v, testOp, SQLITE_AFF_NUMERIC, brk);
+ int r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, r1);
+ /* sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0); */
+ sqlite3VdbeAddOp3(v, testOp, pLevel->iMem, brk, r1);
+ sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL);
+ sqlite3ReleaseTempReg(pParse, r1);
}
}else if( pLevel->flags & WHERE_COLUMN_RANGE ){
/* Case 3: The WHERE clause term that refers to the right-most
@@ -2159,29 +2399,22 @@ WhereInfo *sqlite3WhereBegin(
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;
+ int isMinQuery = 0; /* If this is an optimized SELECT min(x) ... */
+ int regBase; /* Base register holding constraint values */
+ int r1; /* Temp register */
/* Generate code to evaluate all constraint terms using == or IN
** and level the values of those terms on the stack.
*/
- codeAllEqualityTerms(pParse, pLevel, &wc, notReady, brk);
-
- /* Duplicate the equality term values because they will all be
- ** used twice: once to make the termination key and once to make the
- ** start key.
- */
- for(j=0; j<nEq; j++){
- sqlite3VdbeAddOp(v, OP_Dup, nEq-1, 0);
- }
+ regBase = codeAllEqualityTerms(pParse, pLevel, &wc, notReady, 2);
/* 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;
@@ -2191,6 +2424,22 @@ WhereInfo *sqlite3WhereBegin(
SWAP(int, topLimit, btmLimit);
}
+ /* If this loop satisfies a sort order (pOrderBy) request that
+ ** was passed to this function to implement a "SELECT min(x) ..."
+ ** query, then the caller will only allow the loop to run for
+ ** a single iteration. This means that the first row returned
+ ** should not have a NULL value stored in 'x'. If column 'x' is
+ ** the first one after the nEq equality constraints in the index,
+ ** this requires some special handling.
+ */
+ if( (obflag==ORDERBY_MIN)
+ && (pLevel->flags&WHERE_ORDERBY)
+ && (pIdx->nColumn>nEq)
+ && (pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq])
+ ){
+ isMinQuery = 1;
+ }
+
/* 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.
@@ -2198,14 +2447,16 @@ WhereInfo *sqlite3WhereBegin(
** 2002-Dec-04: On a reverse-order scan, the so-called "termination"
** key computed here really ends up being the start key.
*/
+ nxt = pLevel->nxt;
if( topLimit ){
Expr *pX;
- int k = pIdx->aiColumn[j];
+ int k = pIdx->aiColumn[nEq];
pTerm = findTerm(&wc, iCur, k, notReady, topOp, pIdx);
assert( pTerm!=0 );
pX = pTerm->pExpr;
assert( (pTerm->flags & TERM_CODED)==0 );
- sqlite3ExprCode(pParse, pX->pRight);
+ sqlite3ExprCode(pParse, pX->pRight, regBase+nEq);
+ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt);
topEq = pTerm->eOperator & (WO_LE|WO_GE);
disableTerm(pLevel, pTerm);
testOp = OP_IdxGE;
@@ -2213,20 +2464,22 @@ WhereInfo *sqlite3WhereBegin(
testOp = nEq>0 ? OP_IdxGE : OP_Noop;
topEq = 1;
}
- if( testOp!=OP_Noop ){
+ if( testOp!=OP_Noop || (isMinQuery&&bRev) ){
int nCol = nEq + topLimit;
- pLevel->iMem = pParse->nMem++;
- buildIndexProbe(v, nCol, nEq, brk, pIdx);
+ if( isMinQuery && !topLimit ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nCol);
+ nCol++;
+ topEq = 0;
+ }
+ buildIndexProbe(v, nCol, pIdx, regBase, pLevel->iMem);
if( bRev ){
int op = topEq ? OP_MoveLe : OP_MoveLt;
- sqlite3VdbeAddOp(v, op, iIdxCur, brk);
- }else{
- sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
+ sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, pLevel->iMem);
}
}else if( bRev ){
- sqlite3VdbeAddOp(v, OP_Last, iIdxCur, brk);
+ sqlite3VdbeAddOp2(v, OP_Last, iIdxCur, brk);
}
-
+
/* Generate the start key. This is the key that defines the lower
** bound on the search. There is no start key if there are no
** equality terms and if there is no "X>..." term. In
@@ -2238,32 +2491,41 @@ WhereInfo *sqlite3WhereBegin(
*/
if( btmLimit ){
Expr *pX;
- int k = pIdx->aiColumn[j];
+ int k = pIdx->aiColumn[nEq];
pTerm = findTerm(&wc, iCur, k, notReady, btmOp, pIdx);
assert( pTerm!=0 );
pX = pTerm->pExpr;
assert( (pTerm->flags & TERM_CODED)==0 );
- sqlite3ExprCode(pParse, pX->pRight);
+ sqlite3ExprCode(pParse, pX->pRight, regBase+nEq);
+ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt);
btmEq = pTerm->eOperator & (WO_LE|WO_GE);
disableTerm(pLevel, pTerm);
}else{
btmEq = 1;
}
- if( nEq>0 || btmLimit ){
+ if( nEq>0 || btmLimit || (isMinQuery&&!bRev) ){
int nCol = nEq + btmLimit;
- buildIndexProbe(v, nCol, 0, brk, pIdx);
+ if( isMinQuery && !btmLimit ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nCol);
+ nCol++;
+ btmEq = 0;
+ }
if( bRev ){
- pLevel->iMem = pParse->nMem++;
- sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
+ r1 = pLevel->iMem;
testOp = OP_IdxLT;
}else{
+ r1 = sqlite3GetTempReg(pParse);
+ }
+ buildIndexProbe(v, nCol, pIdx, regBase, r1);
+ if( !bRev ){
int op = btmEq ? OP_MoveGe : OP_MoveGt;
- sqlite3VdbeAddOp(v, op, iIdxCur, brk);
+ sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, r1);
+ sqlite3ReleaseTempReg(pParse, r1);
}
}else if( bRev ){
testOp = OP_Noop;
}else{
- sqlite3VdbeAddOp(v, OP_Rewind, iIdxCur, brk);
+ sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur, brk);
}
/* Generate the the top of the loop. If there is a termination
@@ -2272,18 +2534,21 @@ WhereInfo *sqlite3WhereBegin(
*/
start = sqlite3VdbeCurrentAddr(v);
if( testOp!=OP_Noop ){
- sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeAddOp(v, testOp, iIdxCur, brk);
+ sqlite3VdbeAddOp3(v, testOp, iIdxCur, nxt, pLevel->iMem);
if( (topEq && !bRev) || (!btmEq && bRev) ){
- sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
+ sqlite3VdbeChangeP5(v, 1);
}
}
- sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0);
- sqlite3VdbeAddOp(v, OP_IdxIsNull, nNotNull, cont);
+ r1 = sqlite3GetTempReg(pParse);
+ if( topLimit | btmLimit ){
+ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, nEq, r1);
+ sqlite3VdbeAddOp2(v, OP_IsNull, r1, cont);
+ }
if( !omitTable ){
- sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0);
- sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1);
+ sqlite3VdbeAddOp3(v, OP_MoveGe, iCur, 0, r1); /* Deferred seek */
}
+ sqlite3ReleaseTempReg(pParse, r1);
/* Record the instruction used to terminate the loop.
*/
@@ -2296,41 +2561,68 @@ WhereInfo *sqlite3WhereBegin(
*/
int start;
int nEq = pLevel->nEq;
+ int isMinQuery = 0; /* If this is an optimized SELECT min(x) ... */
+ int regBase; /* Base register of array holding constraints */
+ int r1;
/* Generate code to evaluate all constraint terms using == or IN
** and leave the values of those terms on the stack.
*/
- codeAllEqualityTerms(pParse, pLevel, &wc, notReady, brk);
-
- /* Generate a single key that will be used to both start and terminate
- ** the search
- */
- buildIndexProbe(v, nEq, 0, brk, pIdx);
- sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
+ regBase = codeAllEqualityTerms(pParse, pLevel, &wc, notReady, 1);
+ nxt = pLevel->nxt;
+
+ if( (obflag==ORDERBY_MIN)
+ && (pLevel->flags&WHERE_ORDERBY)
+ && (pIdx->nColumn>nEq)
+ && (pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq])
+ ){
+ isMinQuery = 1;
+ buildIndexProbe(v, nEq, pIdx, regBase, pLevel->iMem);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
+ r1 = ++pParse->nMem;
+ buildIndexProbe(v, nEq+1, pIdx, regBase, r1);
+ }else{
+ /* Generate a single key that will be used to both start and
+ ** terminate the search
+ */
+ r1 = pLevel->iMem;
+ buildIndexProbe(v, nEq, pIdx, regBase, r1);
+ }
/* Generate code (1) to move to the first matching element of the table.
- ** Then generate code (2) that jumps to "brk" after the cursor is past
+ ** Then generate code (2) that jumps to "nxt" after the cursor is past
** the last matching element of the table. The code (1) is executed
** once to initialize the search, the code (2) is executed before each
** iteration of the scan to see if the scan has finished. */
if( bRev ){
/* Scan in reverse order */
- sqlite3VdbeAddOp(v, OP_MoveLe, iIdxCur, brk);
- start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeAddOp(v, OP_IdxLT, iIdxCur, brk);
+ int op;
+ if( isMinQuery ){
+ op = OP_MoveLt;
+ }else{
+ op = OP_MoveLe;
+ }
+ sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, r1);
+ start = sqlite3VdbeAddOp3(v, OP_IdxLT, iIdxCur, nxt, pLevel->iMem);
pLevel->op = OP_Prev;
}else{
/* Scan in the forward order */
- sqlite3VdbeAddOp(v, OP_MoveGe, iIdxCur, brk);
- start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeOp3(v, OP_IdxGE, iIdxCur, brk, "+", P3_STATIC);
+ int op;
+ if( isMinQuery ){
+ op = OP_MoveGt;
+ }else{
+ op = OP_MoveGe;
+ }
+ sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, r1);
+ start = sqlite3VdbeAddOp3(v, OP_IdxGE, iIdxCur, nxt, pLevel->iMem);
+ sqlite3VdbeChangeP5(v, 1);
pLevel->op = OP_Next;
}
- sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0);
- sqlite3VdbeAddOp(v, OP_IdxIsNull, nEq, cont);
if( !omitTable ){
- sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0);
- sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
+ r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1);
+ sqlite3VdbeAddOp3(v, OP_MoveGe, iCur, 0, r1); /* Deferred seek */
+ sqlite3ReleaseTempReg(pParse, r1);
}
pLevel->p1 = iIdxCur;
pLevel->p2 = start;
@@ -2342,7 +2634,7 @@ WhereInfo *sqlite3WhereBegin(
assert( bRev==0 );
pLevel->op = OP_Next;
pLevel->p1 = iCur;
- pLevel->p2 = 1 + sqlite3VdbeAddOp(v, OP_Rewind, iCur, brk);
+ pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, OP_Rewind, iCur, brk);
}
notReady &= ~getMask(&maskSet, iCur);
@@ -2358,7 +2650,7 @@ WhereInfo *sqlite3WhereBegin(
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
continue;
}
- sqlite3ExprIfFalse(pParse, pE, cont, 1);
+ sqlite3ExprIfFalse(pParse, pE, cont, SQLITE_JUMPIFNULL);
pTerm->flags |= TERM_CODED;
}
@@ -2367,13 +2659,13 @@ WhereInfo *sqlite3WhereBegin(
*/
if( pLevel->iLeftJoin ){
pLevel->top = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeAddOp(v, OP_MemInt, 1, pLevel->iLeftJoin);
- VdbeComment((v, "# record LEFT JOIN hit"));
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
+ VdbeComment((v, "record LEFT JOIN hit"));
for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( (pTerm->prereqAll & notReady)!=0 ) continue;
assert( pTerm->pExpr );
- sqlite3ExprIfFalse(pParse, pTerm->pExpr, cont, 1);
+ sqlite3ExprIfFalse(pParse, pTerm->pExpr, cont, SQLITE_JUMPIFNULL);
pTerm->flags |= TERM_CODED;
}
}
@@ -2396,24 +2688,24 @@ WhereInfo *sqlite3WhereBegin(
n = strlen(z);
if( n+nQPlan < sizeof(sqlite3_query_plan)-10 ){
if( pLevel->flags & WHERE_IDX_ONLY ){
- strcpy(&sqlite3_query_plan[nQPlan], "{}");
+ memcpy(&sqlite3_query_plan[nQPlan], "{}", 2);
nQPlan += 2;
}else{
- strcpy(&sqlite3_query_plan[nQPlan], z);
+ memcpy(&sqlite3_query_plan[nQPlan], z, n);
nQPlan += n;
}
sqlite3_query_plan[nQPlan++] = ' ';
}
if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
- strcpy(&sqlite3_query_plan[nQPlan], "* ");
+ memcpy(&sqlite3_query_plan[nQPlan], "* ", 2);
nQPlan += 2;
}else if( pLevel->pIdx==0 ){
- strcpy(&sqlite3_query_plan[nQPlan], "{} ");
+ memcpy(&sqlite3_query_plan[nQPlan], "{} ", 3);
nQPlan += 3;
}else{
n = strlen(pLevel->pIdx->zName);
if( n+nQPlan < sizeof(sqlite3_query_plan)-2 ){
- strcpy(&sqlite3_query_plan[nQPlan], pLevel->pIdx->zName);
+ memcpy(&sqlite3_query_plan[nQPlan], pLevel->pIdx->zName, n);
nQPlan += n;
sqlite3_query_plan[nQPlan++] = ' ';
}
@@ -2456,26 +2748,28 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
pLevel = &pWInfo->a[i];
sqlite3VdbeResolveLabel(v, pLevel->cont);
if( pLevel->op!=OP_Noop ){
- sqlite3VdbeAddOp(v, pLevel->op, pLevel->p1, pLevel->p2);
+ sqlite3VdbeAddOp2(v, pLevel->op, pLevel->p1, pLevel->p2);
}
- sqlite3VdbeResolveLabel(v, pLevel->brk);
if( pLevel->nIn ){
- int *a;
+ struct InLoop *pIn;
int j;
- 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);
+ sqlite3VdbeResolveLabel(v, pLevel->nxt);
+ for(j=pLevel->nIn, pIn=&pLevel->aInLoop[j-1]; j>0; j--, pIn--){
+ sqlite3VdbeJumpHere(v, pIn->topAddr+1);
+ sqlite3VdbeAddOp2(v, OP_Next, pIn->iCur, pIn->topAddr);
+ sqlite3VdbeJumpHere(v, pIn->topAddr-1);
}
- sqliteFree(pLevel->aInLoop);
+ sqlite3_free(pLevel->aInLoop);
}
+ sqlite3VdbeResolveLabel(v, pLevel->brk);
if( pLevel->iLeftJoin ){
int addr;
- addr = sqlite3VdbeAddOp(v, OP_IfMemPos, pLevel->iLeftJoin, 0);
- sqlite3VdbeAddOp(v, OP_NullRow, pTabList->a[i].iCursor, 0);
+ addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin);
+ sqlite3VdbeAddOp1(v, OP_NullRow, pTabList->a[i].iCursor);
if( pLevel->iIdxCur>=0 ){
- sqlite3VdbeAddOp(v, OP_NullRow, pLevel->iIdxCur, 0);
+ sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur);
}
- sqlite3VdbeAddOp(v, OP_Goto, 0, pLevel->top);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->top);
sqlite3VdbeJumpHere(v, addr);
}
}
@@ -2493,14 +2787,18 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
assert( pTab!=0 );
if( pTab->isEphem || pTab->pSelect ) continue;
if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){
- sqlite3VdbeAddOp(v, OP_Close, pTabItem->iCursor, 0);
+ sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
}
if( pLevel->pIdx!=0 ){
- sqlite3VdbeAddOp(v, OP_Close, pLevel->iIdxCur, 0);
+ sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
}
- /* Make cursor substitutions for cases where we want to use
- ** just the index and never reference the table.
+ /* If this scan uses an index, make code substitutions to read data
+ ** from the index in preference to the table. Sometimes, this means
+ ** the table need never be read from. This is a performance boost,
+ ** as the vdbe level waits until the table is read before actually
+ ** seeking the table cursor to the record corresponding to the current
+ ** position in the index.
**
** Calls to the code generator in between sqlite3WhereBegin and
** sqlite3WhereEnd will have created code that references the table
@@ -2508,10 +2806,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
** that reference the table and converts them into opcodes that
** reference the index.
*/
- if( pLevel->flags & WHERE_IDX_ONLY ){
+ if( pLevel->pIdx ){
int k, j, last;
VdbeOp *pOp;
Index *pIdx = pLevel->pIdx;
+ int useIndexOnly = pLevel->flags & WHERE_IDX_ONLY;
assert( pIdx!=0 );
pOp = sqlite3VdbeGetOp(v, pWInfo->iTop);
@@ -2519,17 +2818,18 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
for(k=pWInfo->iTop; k<last; k++, pOp++){
if( pOp->p1!=pLevel->iTabCur ) continue;
if( pOp->opcode==OP_Column ){
- pOp->p1 = pLevel->iIdxCur;
for(j=0; j<pIdx->nColumn; j++){
if( pOp->p2==pIdx->aiColumn[j] ){
pOp->p2 = j;
+ pOp->p1 = pLevel->iIdxCur;
break;
}
}
+ assert(!useIndexOnly || j<pIdx->nColumn);
}else if( pOp->opcode==OP_Rowid ){
pOp->p1 = pLevel->iIdxCur;
pOp->opcode = OP_IdxRowid;
- }else if( pOp->opcode==OP_NullRow ){
+ }else if( pOp->opcode==OP_NullRow && useIndexOnly ){
pOp->opcode = OP_Noop;
}
}
diff --git a/ext/pdo_sqlite/sqlite/tool/fragck.tcl b/ext/pdo_sqlite/sqlite/tool/fragck.tcl
new file mode 100644
index 0000000000..35e76f482b
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/tool/fragck.tcl
@@ -0,0 +1,149 @@
+# Run this TCL script using "testfixture" to get a report that shows
+# the sequence of database pages used by a particular table or index.
+# This information is used for fragmentation analysis.
+#
+
+# Get the name of the database to analyze
+#
+
+if {[llength $argv]!=2} {
+ puts stderr "Usage: $argv0 database-name table-or-index-name"
+ exit 1
+}
+set file_to_analyze [lindex $argv 0]
+if {![file exists $file_to_analyze]} {
+ puts stderr "No such file: $file_to_analyze"
+ exit 1
+}
+if {![file readable $file_to_analyze]} {
+ puts stderr "File is not readable: $file_to_analyze"
+ exit 1
+}
+if {[file size $file_to_analyze]<512} {
+ puts stderr "Empty or malformed database: $file_to_analyze"
+ exit 1
+}
+set objname [lindex $argv 1]
+
+# Open the database
+#
+sqlite3 db [lindex $argv 0]
+set DB [btree_open [lindex $argv 0] 1000 0]
+
+# This proc is a wrapper around the btree_cursor_info command. The
+# second argument is an open btree cursor returned by [btree_cursor].
+# The first argument is the name of an array variable that exists in
+# the scope of the caller. If the third argument is non-zero, then
+# info is returned for the page that lies $up entries upwards in the
+# tree-structure. (i.e. $up==1 returns the parent page, $up==2 the
+# grandparent etc.)
+#
+# The following entries in that array are filled in with information retrieved
+# using [btree_cursor_info]:
+#
+# $arrayvar(page_no) = The page number
+# $arrayvar(entry_no) = The entry number
+# $arrayvar(page_entries) = Total number of entries on this page
+# $arrayvar(cell_size) = Cell size (local payload + header)
+# $arrayvar(page_freebytes) = Number of free bytes on this page
+# $arrayvar(page_freeblocks) = Number of free blocks on the page
+# $arrayvar(payload_bytes) = Total payload size (local + overflow)
+# $arrayvar(header_bytes) = Header size in bytes
+# $arrayvar(local_payload_bytes) = Local payload size
+# $arrayvar(parent) = Parent page number
+#
+proc cursor_info {arrayvar csr {up 0}} {
+ upvar $arrayvar a
+ foreach [list a(page_no) \
+ a(entry_no) \
+ a(page_entries) \
+ a(cell_size) \
+ a(page_freebytes) \
+ a(page_freeblocks) \
+ a(payload_bytes) \
+ a(header_bytes) \
+ a(local_payload_bytes) \
+ a(parent) \
+ a(first_ovfl) ] [btree_cursor_info $csr $up] break
+}
+
+# Determine the page-size of the database. This global variable is used
+# throughout the script.
+#
+set pageSize [db eval {PRAGMA page_size}]
+
+# Find the root page of table or index to be analyzed. Also find out
+# if the object is a table or an index.
+#
+if {$objname=="sqlite_master"} {
+ set rootpage 1
+ set type table
+} else {
+ db eval {
+ SELECT rootpage, type FROM sqlite_master
+ WHERE name=$objname
+ } break
+ if {![info exists rootpage]} {
+ puts stderr "no such table or index: $objname"
+ exit 1
+ }
+ if {$type!="table" && $type!="index"} {
+ puts stderr "$objname is something other than a table or index"
+ exit 1
+ }
+ if {![string is integer -strict $rootpage]} {
+ puts stderr "invalid root page for $objname: $rootpage"
+ exit 1
+ }
+}
+
+# The cursor $csr is pointing to an entry. Print out information
+# about the page that $up levels above that page that contains
+# the entry. If $up==0 use the page that contains the entry.
+#
+# If information about the page has been printed already, then
+# this is a no-op.
+#
+proc page_info {csr up} {
+ global seen
+ cursor_info ci $csr $up
+ set pg $ci(page_no)
+ if {[info exists seen($pg)]} return
+ set seen($pg) 1
+
+ # Do parent pages first
+ #
+ if {$ci(parent)} {
+ page_info $csr [expr {$up+1}]
+ }
+
+ # Find the depth of this page
+ #
+ set depth 1
+ set i $up
+ while {$ci(parent)} {
+ incr i
+ incr depth
+ cursor_info ci $csr $i
+ }
+
+ # print the results
+ #
+ puts [format {LEVEL %d: %6d} $depth $pg]
+}
+
+
+
+
+# Loop through the object and print out page numbers
+#
+set csr [btree_cursor $DB $rootpage 0]
+for {btree_first $csr} {![btree_eof $csr]} {btree_next $csr} {
+ page_info $csr 0
+ set i 1
+ foreach pg [btree_ovfl_info $DB $csr] {
+ puts [format {OVFL %3d: %6d} $i $pg]
+ incr i
+ }
+}
+exit 0
diff --git a/ext/pdo_sqlite/sqlite/tool/lemon.c b/ext/pdo_sqlite/sqlite/tool/lemon.c
index 759e1c3786..e613f77581 100644
--- a/ext/pdo_sqlite/sqlite/tool/lemon.c
+++ b/ext/pdo_sqlite/sqlite/tool/lemon.c
@@ -11,6 +11,7 @@
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
+#include <assert.h>
#ifndef __WIN32__
# if defined(_WIN32) || defined(WIN32)
@@ -18,6 +19,12 @@
# endif
#endif
+#ifdef __WIN32__
+extern int access();
+#else
+#include <unistd.h>
+#endif
+
/* #define PRIVATE static */
#define PRIVATE
@@ -27,20 +34,10 @@
#define MAXRHS 1000
#endif
-char *msort();
-extern void *malloc();
+static char *msort(char*,char**,int(*)(const char*,const char*));
-/******** From the file "action.h" *************************************/
-struct action *Action_new();
-struct action *Action_sort();
-
-/********* From the file "assert.h" ************************************/
-void myassert();
-#ifndef NDEBUG
-# define assert(X) if(!(X))myassert(__FILE__,__LINE__)
-#else
-# define assert(X)
-#endif
+static struct action *Action_new(void);
+static struct action *Action_sort(struct action *);
/********** From the file "build.h" ************************************/
void FindRulePrecedences();
@@ -111,7 +108,7 @@ int SetUnion(/* char *A,char *B */); /* A <- A U B, thru element N */
** Principal data structures for the LEMON parser generator.
*/
-typedef enum {B_FALSE=0, B_TRUE} Boolean;
+typedef enum {LEMON_FALSE=0, LEMON_TRUE} Boolean;
/* Symbols (terminals and nonterminals) of the grammar are stored
** in the following: */
@@ -134,6 +131,7 @@ struct symbol {
} assoc; /* Associativity if predecence is defined */
char *firstset; /* First-set for all rules of this symbol */
Boolean lambda; /* True if NT and can generate an empty string */
+ int useCnt; /* Number of times used */
char *destructor; /* Code which executes whenever this symbol is
** popped from the stack during error processing */
int destructorln; /* Line number of destructor code */
@@ -152,6 +150,7 @@ struct symbol {
struct rule {
struct symbol *lhs; /* Left-hand side of the rule */
char *lhsalias; /* Alias for the LHS (NULL if none) */
+ int lhsStart; /* True if left-hand side is the start symbol */
int ruleline; /* Line number for the rule */
int nrhs; /* Number of RHS symbols */
struct symbol **rhs; /* The RHS symbols */
@@ -193,7 +192,9 @@ struct action {
ACCEPT,
REDUCE,
ERROR,
- CONFLICT, /* Was a reduce, but part of a conflict */
+ SSCONFLICT, /* A shift/shift conflict */
+ SRCONFLICT, /* Was a reduce, but part of a conflict */
+ RRCONFLICT, /* Was a reduce, but part of a conflict */
SH_RESOLVED, /* Was a shift. Precedence resolved conflict */
RD_RESOLVED, /* Was reduce. Precedence resolved conflict */
NOT_USED /* Deleted by compression */
@@ -332,14 +333,14 @@ void Configtable_clear(/* int(*)(struct config *) */);
*/
/* Allocate a new parser action */
-struct action *Action_new(){
+static struct action *Action_new(void){
static struct action *freelist = 0;
struct action *new;
if( freelist==0 ){
int i;
int amt = 100;
- freelist = (struct action *)malloc( sizeof(struct action)*amt );
+ freelist = (struct action *)calloc(amt, sizeof(struct action));
if( freelist==0 ){
fprintf(stderr,"Unable to allocate memory for a new parser action.");
exit(1);
@@ -352,27 +353,31 @@ struct action *Action_new(){
return new;
}
-/* Compare two actions */
-static int actioncmp(ap1,ap2)
-struct action *ap1;
-struct action *ap2;
-{
+/* Compare two actions for sorting purposes. Return negative, zero, or
+** positive if the first action is less than, equal to, or greater than
+** the first
+*/
+static int actioncmp(
+ struct action *ap1,
+ struct action *ap2
+){
int rc;
rc = ap1->sp->index - ap2->sp->index;
- if( rc==0 ) rc = (int)ap1->type - (int)ap2->type;
if( rc==0 ){
- assert( ap1->type==REDUCE || ap1->type==RD_RESOLVED || ap1->type==CONFLICT);
- assert( ap2->type==REDUCE || ap2->type==RD_RESOLVED || ap2->type==CONFLICT);
+ rc = (int)ap1->type - (int)ap2->type;
+ }
+ if( rc==0 && ap1->type==REDUCE ){
rc = ap1->x.rp->index - ap2->x.rp->index;
}
return rc;
}
/* Sort parser actions */
-struct action *Action_sort(ap)
-struct action *ap;
-{
- ap = (struct action *)msort((char *)ap,(char **)&ap->next,actioncmp);
+static struct action *Action_sort(
+ struct action *ap
+){
+ ap = (struct action *)msort((char *)ap,(char **)&ap->next,
+ (int(*)(const char*,const char*))actioncmp);
return ap;
}
@@ -437,7 +442,7 @@ void acttab_free(acttab *p){
/* Allocate a new acttab structure */
acttab *acttab_alloc(void){
- acttab *p = malloc( sizeof(*p) );
+ acttab *p = calloc( 1, sizeof(*p) );
if( p==0 ){
fprintf(stderr,"Unable to allocate memory for a new acttab.");
exit(1);
@@ -558,17 +563,6 @@ int acttab_insert(acttab *p){
return i - p->mnLookahead;
}
-/********************** From the file "assert.c" ****************************/
-/*
-** A more efficient way of handling assertions.
-*/
-void myassert(file,line)
-char *file;
-int line;
-{
- fprintf(stderr,"Assertion failed on line %d of file \"%s\"\n",line,file);
- exit(1);
-}
/********************** From the file "build.c" *****************************/
/*
** Routines to construction the finite state machine for the LEMON
@@ -622,7 +616,7 @@ struct lemon *lemp;
int progress;
for(i=0; i<lemp->nsymbol; i++){
- lemp->symbols[i]->lambda = B_FALSE;
+ lemp->symbols[i]->lambda = LEMON_FALSE;
}
for(i=lemp->nterminal; i<lemp->nsymbol; i++){
lemp->symbols[i]->firstset = SetNew();
@@ -635,10 +629,10 @@ struct lemon *lemp;
if( rp->lhs->lambda ) continue;
for(i=0; i<rp->nrhs; i++){
struct symbol *sp = rp->rhs[i];
- if( sp->type!=TERMINAL || sp->lambda==B_FALSE ) break;
+ if( sp->type!=TERMINAL || sp->lambda==LEMON_FALSE ) break;
}
if( i==rp->nrhs ){
- rp->lhs->lambda = B_TRUE;
+ rp->lhs->lambda = LEMON_TRUE;
progress = 1;
}
}
@@ -661,10 +655,10 @@ struct lemon *lemp;
}
break;
}else if( s1==s2 ){
- if( s1->lambda==B_FALSE ) break;
+ if( s1->lambda==LEMON_FALSE ) break;
}else{
progress += SetUnion(s1->firstset,s2->firstset);
- if( s2->lambda==B_FALSE ) break;
+ if( s2->lambda==LEMON_FALSE ) break;
}
}
}
@@ -721,6 +715,7 @@ does not work properly.",sp->name);
** left-hand side */
for(rp=sp->rule; rp; rp=rp->nextlhs){
struct config *newcfp;
+ rp->lhsStart = 1;
newcfp = Configlist_addbasis(rp,0);
SetAdd(newcfp->fws,0);
}
@@ -972,7 +967,7 @@ struct lemon *lemp;
struct action *ap, *nap;
struct state *stp;
stp = lemp->sorted[i];
- assert( stp->ap );
+ /* assert( stp->ap ); */
stp->ap = Action_sort(stp->ap);
for(ap=stp->ap; ap && ap->next; ap=ap->next){
for(nap=ap->next; nap && nap->sp==ap->sp; nap=nap->next){
@@ -984,11 +979,11 @@ struct lemon *lemp;
}
/* Report an error for each rule that can never be reduced. */
- for(rp=lemp->rule; rp; rp=rp->next) rp->canReduce = B_FALSE;
+ for(rp=lemp->rule; rp; rp=rp->next) rp->canReduce = LEMON_FALSE;
for(i=0; i<lemp->nstate; i++){
struct action *ap;
for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){
- if( ap->type==REDUCE ) ap->x.rp->canReduce = B_TRUE;
+ if( ap->type==REDUCE ) ap->x.rp->canReduce = LEMON_TRUE;
}
}
for(rp=lemp->rule; rp; rp=rp->next){
@@ -1019,12 +1014,16 @@ struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */
struct symbol *spx, *spy;
int errcnt = 0;
assert( apx->sp==apy->sp ); /* Otherwise there would be no conflict */
+ if( apx->type==SHIFT && apy->type==SHIFT ){
+ apy->type = SSCONFLICT;
+ errcnt++;
+ }
if( apx->type==SHIFT && apy->type==REDUCE ){
spx = apx->sp;
spy = apy->x.rp->precsym;
if( spy==0 || spx->prec<0 || spy->prec<0 ){
/* Not enough precedence information. */
- apy->type = CONFLICT;
+ apy->type = SRCONFLICT;
errcnt++;
}else if( spx->prec>spy->prec ){ /* Lower precedence wins */
apy->type = RD_RESOLVED;
@@ -1036,7 +1035,7 @@ struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */
apx->type = SH_RESOLVED;
}else{
assert( spx->prec==spy->prec && spx->assoc==NONE );
- apy->type = CONFLICT;
+ apy->type = SRCONFLICT;
errcnt++;
}
}else if( apx->type==REDUCE && apy->type==REDUCE ){
@@ -1044,7 +1043,7 @@ struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */
spy = apy->x.rp->precsym;
if( spx==0 || spy==0 || spx->prec<0 ||
spy->prec<0 || spx->prec==spy->prec ){
- apy->type = CONFLICT;
+ apy->type = RRCONFLICT;
errcnt++;
}else if( spx->prec>spy->prec ){
apy->type = RD_RESOLVED;
@@ -1055,10 +1054,14 @@ struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */
assert(
apx->type==SH_RESOLVED ||
apx->type==RD_RESOLVED ||
- apx->type==CONFLICT ||
+ apx->type==SSCONFLICT ||
+ apx->type==SRCONFLICT ||
+ apx->type==RRCONFLICT ||
apy->type==SH_RESOLVED ||
apy->type==RD_RESOLVED ||
- apy->type==CONFLICT
+ apy->type==SSCONFLICT ||
+ apy->type==SRCONFLICT ||
+ apy->type==RRCONFLICT
);
/* The REDUCE/SHIFT case cannot happen because SHIFTs come before
** REDUCEs on the list. If we reach this point it must be because
@@ -1084,7 +1087,7 @@ PRIVATE struct config *newconfig(){
if( freelist==0 ){
int i;
int amt = 3;
- freelist = (struct config *)malloc( sizeof(struct config)*amt );
+ freelist = (struct config *)calloc( amt, sizeof(struct config) );
if( freelist==0 ){
fprintf(stderr,"Unable to allocate memory for a new configuration.");
exit(1);
@@ -1218,7 +1221,7 @@ struct lemon *lemp;
break;
}else{
SetUnion(newcfp->fws,xsp->firstset);
- if( xsp->lambda==B_FALSE ) break;
+ if( xsp->lambda==LEMON_FALSE ) break;
}
}
if( i==rp->nrhs ) Plink_add(&cfp->fplp,newcfp);
@@ -1435,6 +1438,7 @@ char **argv;
lem.basisflag = basisflag;
Symbol_new("$");
lem.errsym = Symbol_new("error");
+ lem.errsym->useCnt = 0;
/* Parse the input file */
Parse(&lem);
@@ -1460,7 +1464,7 @@ char **argv;
Reprint(&lem);
}else{
/* Initialize the size for all follow and first sets */
- SetSize(lem.nterminal);
+ SetSize(lem.nterminal+1);
/* Find the precedence for every production rule (that has one) */
FindRulePrecedences(&lem);
@@ -1558,12 +1562,12 @@ char **argv;
** The "next" pointers for elements in the lists a and b are
** changed.
*/
-static char *merge(a,b,cmp,offset)
-char *a;
-char *b;
-int (*cmp)();
-int offset;
-{
+static char *merge(
+ char *a,
+ char *b,
+ int (*cmp)(const char*,const char*),
+ int offset
+){
char *ptr, *head;
if( a==0 ){
@@ -1610,11 +1614,11 @@ int offset;
** The "next" pointers for elements in list are changed.
*/
#define LISTSIZE 30
-char *msort(list,next,cmp)
-char *list;
-char **next;
-int (*cmp)();
-{
+static char *msort(
+ char *list,
+ char **next,
+ int (*cmp)(const char*,const char*)
+){
unsigned long offset;
char *ep;
char *set[LISTSIZE];
@@ -2097,8 +2101,8 @@ to follow the previous rule.");
case IN_RHS:
if( x[0]=='.' ){
struct rule *rp;
- rp = (struct rule *)malloc( sizeof(struct rule) +
- sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs );
+ rp = (struct rule *)calloc( sizeof(struct rule) +
+ sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs, 1);
if( rp==0 ){
ErrorMsg(psp->filename,psp->tokenlineno,
"Can't allocate enough memory for this rule.");
@@ -2134,7 +2138,7 @@ to follow the previous rule.");
}else if( isalpha(x[0]) ){
if( psp->nrhs>=MAXRHS ){
ErrorMsg(psp->filename,psp->tokenlineno,
- "Too many symbols on RHS or rule beginning at \"%s\".",
+ "Too many symbols on RHS of rule beginning at \"%s\".",
x);
psp->errorcnt++;
psp->state = RESYNC_AFTER_RULE_ERROR;
@@ -2147,11 +2151,11 @@ to follow the previous rule.");
struct symbol *msp = psp->rhs[psp->nrhs-1];
if( msp->type!=MULTITERMINAL ){
struct symbol *origsp = msp;
- msp = malloc(sizeof(*msp));
+ msp = calloc(1,sizeof(*msp));
memset(msp, 0, sizeof(*msp));
msp->type = MULTITERMINAL;
msp->nsubsym = 1;
- msp->subsym = malloc(sizeof(struct symbol*));
+ msp->subsym = calloc(1,sizeof(struct symbol*));
msp->subsym[0] = origsp;
msp->name = origsp->name;
psp->rhs[psp->nrhs-1] = msp;
@@ -2396,9 +2400,9 @@ to follow the previous rule.");
static void preprocess_input(char *z){
int i, j, k, n;
int exclude = 0;
- int start;
+ int start = 0;
int lineno = 1;
- int start_lineno;
+ int start_lineno = 1;
for(i=0; z[i]; i++){
if( z[i]=='\n' ) lineno++;
if( z[i]!='%' || (i>0 && z[i-1]!='\n') ) continue;
@@ -2456,6 +2460,7 @@ struct lemon *gp;
char *cp, *nextcp;
int startline = 0;
+ memset(&ps, '\0', sizeof(ps));
ps.gp = gp;
ps.filename = gp->filename;
ps.errorcnt = 0;
@@ -2603,7 +2608,7 @@ struct plink *Plink_new(){
if( plink_freelist==0 ){
int i;
int amt = 100;
- plink_freelist = (struct plink *)malloc( sizeof(struct plink)*amt );
+ plink_freelist = (struct plink *)calloc( amt, sizeof(struct plink) );
if( plink_freelist==0 ){
fprintf(stderr,
"Unable to allocate memory for a new follow-set propagation link.\n");
@@ -2829,10 +2834,15 @@ int PrintAction(struct action *ap, FILE *fp, int indent){
case ERROR:
fprintf(fp,"%*s error",indent,ap->sp->name);
break;
- case CONFLICT:
+ case SRCONFLICT:
+ case RRCONFLICT:
fprintf(fp,"%*s reduce %-3d ** Parsing conflict **",
indent,ap->sp->name,ap->x.rp->index);
break;
+ case SSCONFLICT:
+ fprintf(fp,"%*s shift %d ** Parsing conflict **",
+ indent,ap->sp->name,ap->x.stp->statenum);
+ break;
case SH_RESOLVED:
case RD_RESOLVED:
case NOT_USED:
@@ -2854,7 +2864,6 @@ struct lemon *lemp;
fp = file_open(lemp,".out","wb");
if( fp==0 ) return;
- fprintf(fp," \b");
for(i=0; i<lemp->nstate; i++){
stp = lemp->sorted[i];
fprintf(fp,"State %d:\n",stp->statenum);
@@ -2884,6 +2893,27 @@ struct lemon *lemp;
}
fprintf(fp,"\n");
}
+ fprintf(fp, "----------------------------------------------------\n");
+ fprintf(fp, "Symbols:\n");
+ for(i=0; i<lemp->nsymbol; i++){
+ int j;
+ struct symbol *sp;
+
+ sp = lemp->symbols[i];
+ fprintf(fp, " %3d: %s", i, sp->name);
+ if( sp->type==NONTERMINAL ){
+ fprintf(fp, ":");
+ if( sp->lambda ){
+ fprintf(fp, " <lambda>");
+ }
+ for(j=0; j<lemp->nterminal; j++){
+ if( sp->firstset && SetFind(sp->firstset, j) ){
+ fprintf(fp, " %s", lemp->symbols[j]->name);
+ }
+ }
+ }
+ fprintf(fp, "\n");
+ }
fclose(fp);
return;
}
@@ -2898,7 +2928,6 @@ int modemask;
char *pathlist;
char *path,*cp;
char c;
- extern int access();
#ifdef __WIN32__
cp = strrchr(argv0,'\\');
@@ -3166,7 +3195,7 @@ PRIVATE char *append_str(char *zText, int n, int p1, int p2){
if( z==0 ) return "";
while( n-- > 0 ){
c = *(zText++);
- if( c=='%' && zText[0]=='d' ){
+ if( c=='%' && n>0 && zText[0]=='d' ){
sprintf(zInt, "%d", p1);
p1 = p2;
strcpy(&z[used], zInt);
@@ -3195,6 +3224,11 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){
for(i=0; i<rp->nrhs; i++) used[i] = 0;
lhsused = 0;
+ if( rp->code==0 ){
+ rp->code = "\n";
+ rp->line = rp->ruleline;
+ }
+
append_str(0,0,0,0);
for(cp=rp->code; *cp; cp++){
if( isalpha(*cp) && (cp==rp->code || (!isalnum(cp[-1]) && cp[-1]!='_')) ){
@@ -3259,8 +3293,10 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){
}
}
}
- cp = append_str(0,0,0,0);
- rp->code = Strsafe(cp);
+ if( rp->code ){
+ cp = append_str(0,0,0,0);
+ rp->code = Strsafe(cp?cp:"");
+ }
}
/*
@@ -3315,7 +3351,7 @@ int mhflag; /* True if generating makeheaders output */
/* Allocate and initialize types[] and allocate stddt[] */
arraysize = lemp->nsymbol * 2;
- types = (char**)malloc( arraysize * sizeof(char*) );
+ types = (char**)calloc( arraysize, sizeof(char*) );
for(i=0; i<arraysize; i++) types[i] = 0;
maxdtlength = 0;
if( lemp->vartype ){
@@ -3396,7 +3432,9 @@ int mhflag; /* True if generating makeheaders output */
fprintf(out," %s yy%d;\n",types[i],i+1); lineno++;
free(types[i]);
}
- fprintf(out," int yy%d;\n",lemp->errsym->dtnum); lineno++;
+ if( lemp->errsym->useCnt ){
+ fprintf(out," int yy%d;\n",lemp->errsym->dtnum); lineno++;
+ }
free(stddt);
free(types);
fprintf(out,"} YYMINORTYPE;\n"); lineno++;
@@ -3446,6 +3484,25 @@ static int axset_compare(const void *a, const void *b){
return p2->nAction - p1->nAction;
}
+/*
+** Write text on "out" that describes the rule "rp".
+*/
+static void writeRuleText(FILE *out, struct rule *rp){
+ int j;
+ fprintf(out,"%s ::=", rp->lhs->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);
+ }
+ }
+ }
+}
+
+
/* Generate C source code for the parser */
void ReportTable(lemp, mhflag)
struct lemon *lemp;
@@ -3508,18 +3565,13 @@ int mhflag; /* Output in makeheaders format if true */
lemp->wildcard->index); lineno++;
}
print_stack_union(out,lemp,&lineno,mhflag);
+ fprintf(out, "#ifndef YYSTACKDEPTH\n"); lineno++;
if( lemp->stacksize ){
- if( atoi(lemp->stacksize)<=0 ){
- ErrorMsg(lemp->filename,0,
-"Illegal stack size: [%s]. The stack size should be an integer constant.",
- lemp->stacksize);
- lemp->errorcnt++;
- lemp->stacksize = "100";
- }
fprintf(out,"#define YYSTACKDEPTH %s\n",lemp->stacksize); lineno++;
}else{
fprintf(out,"#define YYSTACKDEPTH 100\n"); lineno++;
}
+ fprintf(out, "#endif\n"); lineno++;
if( mhflag ){
fprintf(out,"#if INTERFACE\n"); lineno++;
}
@@ -3546,8 +3598,10 @@ int mhflag; /* Output in makeheaders format if true */
}
fprintf(out,"#define YYNSTATE %d\n",lemp->nstate); lineno++;
fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++;
- fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++;
- fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++;
+ if( lemp->errsym->useCnt ){
+ fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++;
+ fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++;
+ }
if( lemp->has_fallback ){
fprintf(out,"#define YYFALLBACK 1\n"); lineno++;
}
@@ -3566,7 +3620,7 @@ int mhflag; /* Output in makeheaders format if true */
*/
/* Compute the actions on all states and count them up */
- ax = malloc( sizeof(ax[0])*lemp->nstate*2 );
+ ax = calloc(lemp->nstate*2, sizeof(ax[0]));
if( ax==0 ){
fprintf(stderr,"malloc failed\n");
exit(1);
@@ -3623,7 +3677,7 @@ int mhflag; /* Output in makeheaders format if true */
n = acttab_size(pActtab);
for(i=j=0; i<n; i++){
int action = acttab_yyaction(pActtab, i);
- if( action<0 ) action = lemp->nsymbol + lemp->nrule + 2;
+ if( action<0 ) action = lemp->nstate + lemp->nrule + 2;
if( j==0 ) fprintf(out," /* %5d */ ", i);
fprintf(out, " %4d,", action);
if( j==9 || i==n-1 ){
@@ -3746,17 +3800,8 @@ 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++){
- 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," /* %3d */ \"", i);
+ writeRuleText(out, rp);
fprintf(out,"\",\n"); lineno++;
}
tplt_xfer(lemp->name,in,out,&lineno);
@@ -3769,7 +3814,8 @@ int mhflag; /* Output in makeheaders format if true */
for(i=0; i<lemp->nsymbol; i++){
struct symbol *sp = lemp->symbols[i];
if( sp==0 || sp->type!=TERMINAL ) continue;
- fprintf(out," case %d:\n",sp->index); lineno++;
+ fprintf(out," case %d: /* %s */\n",
+ sp->index, sp->name); lineno++;
}
for(i=0; i<lemp->nsymbol && lemp->symbols[i]->type!=TERMINAL; i++);
if( i<lemp->nsymbol ){
@@ -3783,7 +3829,8 @@ int mhflag; /* Output in makeheaders format if true */
struct symbol *sp = lemp->symbols[i];
if( sp==0 || sp->type==TERMINAL ||
sp->index<=0 || sp->destructor!=0 ) continue;
- fprintf(out," case %d:\n",sp->index); lineno++;
+ fprintf(out," case %d: /* %s */\n",
+ sp->index, sp->name); lineno++;
dflt_sp = sp;
}
if( dflt_sp!=0 ){
@@ -3794,7 +3841,8 @@ int mhflag; /* Output in makeheaders format if true */
for(i=0; i<lemp->nsymbol; i++){
struct symbol *sp = lemp->symbols[i];
if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue;
- fprintf(out," case %d:\n",sp->index); lineno++;
+ fprintf(out," case %d: /* %s */\n",
+ sp->index, sp->name); lineno++;
/* Combine duplicate destructors into a single case */
for(j=i+1; j<lemp->nsymbol; j++){
@@ -3802,7 +3850,8 @@ int mhflag; /* Output in makeheaders format if true */
if( sp2 && sp2->type!=TERMINAL && sp2->destructor
&& sp2->dtnum==sp->dtnum
&& strcmp(sp->destructor,sp2->destructor)==0 ){
- fprintf(out," case %d:\n",sp2->index); lineno++;
+ fprintf(out," case %d: /* %s */\n",
+ sp2->index, sp2->name); lineno++;
sp2->destructor = 0;
}
}
@@ -3828,15 +3877,19 @@ int mhflag; /* Output in makeheaders format if true */
/* Generate code which execution during each REDUCE action */
for(rp=lemp->rule; rp; rp=rp->next){
- if( rp->code ) translate_code(lemp, rp);
+ translate_code(lemp, rp);
}
for(rp=lemp->rule; rp; rp=rp->next){
struct rule *rp2;
if( rp->code==0 ) continue;
- fprintf(out," case %d:\n",rp->index); lineno++;
+ fprintf(out," case %d: /* ", rp->index);
+ writeRuleText(out, rp);
+ fprintf(out, " */\n"); lineno++;
for(rp2=rp->next; rp2; rp2=rp2->next){
if( rp2->code==rp->code ){
- fprintf(out," case %d:\n",rp2->index); lineno++;
+ fprintf(out," case %d: /* ", rp2->index);
+ writeRuleText(out, rp2);
+ fprintf(out," */\n"); lineno++;
rp2->code = 0;
}
}
@@ -3928,6 +3981,7 @@ struct lemon *lemp;
}
if( ap->type!=REDUCE ) continue;
rp = ap->x.rp;
+ if( rp->lhsStart ) continue;
if( rp==rbest ) continue;
n = 1;
for(ap2=ap->next; ap2; ap2=ap2->next){
@@ -4036,13 +4090,11 @@ int n;
/* Allocate a new set */
char *SetNew(){
char *s;
- int i;
- s = (char*)malloc( size );
+ s = (char*)calloc( size, 1);
if( s==0 ){
extern void memory_error();
memory_error();
}
- for(i=0; i<size; i++) s[i] = 0;
return s;
}
@@ -4060,6 +4112,7 @@ char *s;
int e;
{
int rv;
+ assert( e>=0 && e<size );
rv = s[e];
s[e] = 1;
return !rv;
@@ -4249,7 +4302,7 @@ char *x;
sp = Symbol_find(x);
if( sp==0 ){
- sp = (struct symbol *)malloc( sizeof(struct symbol) );
+ sp = (struct symbol *)calloc(1, sizeof(struct symbol) );
MemoryCheck(sp);
sp->name = Strsafe(x);
sp->type = isupper(*x) ? TERMINAL : NONTERMINAL;
@@ -4258,11 +4311,13 @@ char *x;
sp->prec = -1;
sp->assoc = UNK;
sp->firstset = 0;
- sp->lambda = B_FALSE;
+ sp->lambda = LEMON_FALSE;
sp->destructor = 0;
sp->datatype = 0;
+ sp->useCnt = 0;
Symbol_insert(sp,sp->name);
}
+ sp->useCnt++;
return sp;
}
@@ -4432,7 +4487,7 @@ struct symbol **Symbol_arrayof()
int i,size;
if( x2a==0 ) return 0;
size = x2a->count;
- array = (struct symbol **)malloc( sizeof(struct symbol *)*size );
+ array = (struct symbol **)calloc(size, sizeof(struct symbol *));
if( array ){
for(i=0; i<size; i++) array[i] = x2a->tbl[i].data;
}
@@ -4483,7 +4538,7 @@ struct config *a;
struct state *State_new()
{
struct state *new;
- new = (struct state *)malloc( sizeof(struct state) );
+ new = (struct state *)calloc(1, sizeof(struct state) );
MemoryCheck(new);
return new;
}
diff --git a/ext/pdo_sqlite/sqlite/tool/lempar.c b/ext/pdo_sqlite/sqlite/tool/lempar.c
index a18c43a24d..cca91ad252 100644
--- a/ext/pdo_sqlite/sqlite/tool/lempar.c
+++ b/ext/pdo_sqlite/sqlite/tool/lempar.c
@@ -44,7 +44,8 @@
** This is typically a union of many types, one of
** which is ParseTOKENTYPE. The entry in the union
** for base tokens is called "yy0".
-** YYSTACKDEPTH is the maximum depth of the parser's stack.
+** YYSTACKDEPTH is the maximum depth of the parser's stack. If
+** zero the stack is dynamically sized using realloc()
** ParseARG_SDECL A static variable declaration for the %extra_argument
** ParseARG_PDECL A parameter declaration for the %extra_argument
** ParseARG_STORE Code to store %extra_argument into yypParser
@@ -152,7 +153,12 @@ struct yyParser {
int yyidx; /* Index of top element in stack */
int yyerrcnt; /* Shifts left before out of the error */
ParseARG_SDECL /* A place to hold %extra_argument */
+#if YYSTACKDEPTH<=0
+ int yystksz; /* Current side of the stack */
+ yyStackEntry *yystack; /* The parser's stack */
+#else
yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
+#endif
};
typedef struct yyParser yyParser;
@@ -204,21 +210,29 @@ static const char *const yyRuleName[] = {
};
#endif /* NDEBUG */
+
+#if YYSTACKDEPTH<=0
/*
-** This function returns the symbolic name associated with a token
-** value.
+** Try to increase the size of the parser stack.
*/
-const char *ParseTokenName(int tokenType){
+static void yyGrowStack(yyParser *p){
+ int newSize;
+ yyStackEntry *pNew;
+
+ newSize = p->yystksz*2 + 100;
+ pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
+ if( pNew ){
+ p->yystack = pNew;
+ p->yystksz = newSize;
#ifndef NDEBUG
- if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
- return yyTokenName[tokenType];
- }else{
- return "Unknown";
- }
-#else
- return "";
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack grows to %d entries!\n",
+ yyTracePrompt, p->yystksz);
+ }
#endif
+ }
}
+#endif
/*
** This function allocates a new parser.
@@ -237,6 +251,9 @@ void *ParseAlloc(void *(*mallocProc)(size_t)){
pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
if( pParser ){
pParser->yyidx = -1;
+#if YYSTACKDEPTH<=0
+ yyGrowStack(pParser);
+#endif
}
return pParser;
}
@@ -308,6 +325,9 @@ void ParseFree(
yyParser *pParser = (yyParser*)p;
if( pParser==0 ) return;
while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
+#if YYSTACKDEPTH<=0
+ free(pParser->yystack);
+#endif
(*freeProc)((void*)pParser);
}
@@ -329,9 +349,7 @@ static int yy_find_shift_action(
if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
return yy_default[stateno];
}
- if( iLookAhead==YYNOCODE ){
- return YY_NO_ACTION;
- }
+ assert( iLookAhead!=YYNOCODE );
i += iLookAhead;
if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
if( iLookAhead>0 ){
@@ -382,21 +400,32 @@ static int yy_find_reduce_action(
YYCODETYPE iLookAhead /* The look-ahead token */
){
int i;
- /* int stateno = pParser->yystack[pParser->yyidx].stateno; */
-
- if( stateno>YY_REDUCE_MAX ||
- (i = yy_reduce_ofst[stateno])==YY_REDUCE_USE_DFLT ){
- return yy_default[stateno];
- }
- if( iLookAhead==YYNOCODE ){
- return YY_NO_ACTION;
- }
+ assert( stateno<=YY_REDUCE_MAX );
+ i = yy_reduce_ofst[stateno];
+ assert( i!=YY_REDUCE_USE_DFLT );
+ assert( iLookAhead!=YYNOCODE );
i += iLookAhead;
- if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
- return yy_default[stateno];
- }else{
- return yy_action[i];
- }
+ assert( i>=0 && i<YY_SZ_ACTTAB );
+ assert( yy_lookahead[i]==iLookAhead );
+ return yy_action[i];
+}
+
+/*
+** The following routine is called if the stack overflows.
+*/
+static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
+ ParseARG_FETCH;
+ yypParser->yyidx--;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will execute if the parser
+ ** stack every overflows */
+%%
+ ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
}
/*
@@ -410,21 +439,20 @@ static void yy_shift(
){
yyStackEntry *yytos;
yypParser->yyidx++;
+#if YYSTACKDEPTH>0
if( yypParser->yyidx>=YYSTACKDEPTH ){
- ParseARG_FETCH;
- yypParser->yyidx--;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
- }
-#endif
- while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
- /* Here code is inserted which will execute if the parser
- ** stack every overflows */
-%%
- ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
- return;
+ yyStackOverflow(yypParser, yypMinor);
+ return;
}
+#else
+ if( yypParser->yyidx>=yypParser->yystksz ){
+ yyGrowStack(yypParser);
+ if( yypParser->yyidx>=yypParser->yystksz ){
+ yyStackOverflow(yypParser, yypMinor);
+ return;
+ }
+ }
+#endif
yytos = &yypParser->yystack[yypParser->yyidx];
yytos->stateno = yyNewState;
yytos->major = yyMajor;
@@ -476,7 +504,6 @@ static void yy_reduce(
}
#endif /* NDEBUG */
-#ifndef NDEBUG
/* Silence complaints from purify about yygotominor being uninitialized
** in some cases when it is copied into the stack after the following
** switch. yygotominor is uninitialized when a rule reduces that does
@@ -484,9 +511,15 @@ static void yy_reduce(
** value of the nonterminal uninitialized is utterly harmless as long
** as the value is never used. So really the only thing this code
** accomplishes is to quieten purify.
+ **
+ ** 2007-01-16: The wireshark project (www.wireshark.org) reports that
+ ** without this code, their parser segfaults. I'm not sure what there
+ ** parser is doing to make this happen. This is the second bug report
+ ** from wireshark this week. Clearly they are stressing Lemon in ways
+ ** that it has not been previously stressed... (SQLite ticket #2172)
*/
memset(&yygotominor, 0, sizeof(yygotominor));
-#endif
+
switch( yyruleno ){
/* Beginning here are the reduction cases. A typical example
@@ -520,7 +553,8 @@ static void yy_reduce(
{
yy_shift(yypParser,yyact,yygoto,&yygotominor);
}
- }else if( yyact == YYNSTATE + YYNRULE + 1 ){
+ }else{
+ assert( yyact == YYNSTATE + YYNRULE + 1 );
yy_accept(yypParser);
}
}
@@ -605,13 +639,21 @@ void Parse(
YYMINORTYPE yyminorunion;
int yyact; /* The parser action. */
int yyendofinput; /* True if we are at the end of input */
+#ifdef YYERRORSYMBOL
int yyerrorhit = 0; /* True if yymajor has invoked an error */
+#endif
yyParser *yypParser; /* The parser */
/* (re)initialize the parser, if necessary */
yypParser = (yyParser*)yyp;
if( yypParser->yyidx<0 ){
- /* if( yymajor==0 ) return; // not sure why this was here... */
+#if YYSTACKDEPTH<=0
+ if( yypParser->yystksz <=0 ){
+ memset(&yyminorunion, 0, sizeof(yyminorunion));
+ yyStackOverflow(yypParser, &yyminorunion);
+ return;
+ }
+#endif
yypParser->yyidx = 0;
yypParser->yyerrcnt = -1;
yypParser->yystack[0].stateno = 0;
@@ -630,17 +672,17 @@ void Parse(
do{
yyact = yy_find_shift_action(yypParser,yymajor);
if( yyact<YYNSTATE ){
+ assert( !yyendofinput ); /* Impossible to shift the $ token */
yy_shift(yypParser,yyact,yymajor,&yyminorunion);
yypParser->yyerrcnt--;
- if( yyendofinput && yypParser->yyidx>=0 ){
- yymajor = 0;
- }else{
- yymajor = YYNOCODE;
- }
+ yymajor = YYNOCODE;
}else if( yyact < YYNSTATE + YYNRULE ){
yy_reduce(yypParser,yyact-YYNSTATE);
- }else if( yyact == YY_ERROR_ACTION ){
+ }else{
+ assert( yyact == YY_ERROR_ACTION );
+#ifdef YYERRORSYMBOL
int yymx;
+#endif
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
@@ -721,9 +763,6 @@ void Parse(
}
yymajor = YYNOCODE;
#endif
- }else{
- yy_accept(yypParser);
- yymajor = YYNOCODE;
}
}while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
return;
diff --git a/ext/pdo_sqlite/sqlite/tool/mkkeywordhash.c b/ext/pdo_sqlite/sqlite/tool/mkkeywordhash.c
index 3301a40e97..e5adb82731 100644
--- a/ext/pdo_sqlite/sqlite/tool/mkkeywordhash.c
+++ b/ext/pdo_sqlite/sqlite/tool/mkkeywordhash.c
@@ -8,6 +8,25 @@
#include <stdlib.h>
/*
+** A header comment placed at the beginning of generated code.
+*/
+static const char zHdr[] =
+ "/***** This file contains automatically generated code ******\n"
+ "**\n"
+ "** The code in this file has been automatically generated by\n"
+ "**\n"
+ "** $Header$\n"
+ "**\n"
+ "** The code in this file implements a function that determines whether\n"
+ "** or not a given identifier is really an SQL keyword. The same thing\n"
+ "** might be implemented more directly using a hand-written hash table.\n"
+ "** But by using this automatically generated code, the size of the code\n"
+ "** is substantially reduced. This is important for embedded applications\n"
+ "** on platforms with limited memory.\n"
+ "*/\n"
+;
+
+/*
** All the keywords of the SQL language are stored as in a hash
** table composed of instances of the following structure.
*/
@@ -21,6 +40,7 @@ struct Keyword {
int offset; /* Offset to start of name string */
int len; /* Length of this keyword, not counting final \000 */
int prefix; /* Number of characters in prefix */
+ int longestSuffix; /* Longest suffix that is a prefix on another word */
int iNext; /* Index in aKeywordTable[] of next with same hash */
int substrId; /* Id to another keyword this keyword is embedded in */
int substrOffset; /* Offset into substrId for start of this keyword */
@@ -95,7 +115,8 @@ struct Keyword {
#else
# define TRIGGER 0x00002000
#endif
-#ifdef SQLITE_OMIT_VACUUM
+#if defined(SQLITE_OMIT_AUTOVACUUM) && \
+ (defined(SQLITE_OMIT_VACUUM) || defined(SQLITE_OMIT_ATTACH))
# define VACUUM 0
#else
# define VACUUM 0x00004000
@@ -110,6 +131,11 @@ struct Keyword {
#else
# define VTAB 0x00010000
#endif
+#ifdef SQLITE_OMIT_AUTOVACUUM
+# define AUTOVACUUM 0
+#else
+# define AUTOVACUUM 0x00020000
+#endif
/*
** These are the keywords
@@ -198,8 +224,10 @@ static Keyword aKeywordTable[] = {
{ "OR", "TK_OR", ALWAYS },
{ "ORDER", "TK_ORDER", ALWAYS },
{ "OUTER", "TK_JOIN_KW", ALWAYS },
+ { "PLAN", "TK_PLAN", EXPLAIN },
{ "PRAGMA", "TK_PRAGMA", PRAGMA },
{ "PRIMARY", "TK_PRIMARY", ALWAYS },
+ { "QUERY", "TK_QUERY", EXPLAIN },
{ "RAISE", "TK_RAISE", TRIGGER },
{ "REFERENCES", "TK_REFERENCES", FKEY },
{ "REGEXP", "TK_LIKE_KW", ALWAYS },
@@ -212,7 +240,6 @@ static Keyword aKeywordTable[] = {
{ "ROW", "TK_ROW", TRIGGER },
{ "SELECT", "TK_SELECT", ALWAYS },
{ "SET", "TK_SET", ALWAYS },
- { "STATEMENT", "TK_STATEMENT", TRIGGER },
{ "TABLE", "TK_TABLE", ALWAYS },
{ "TEMP", "TK_TEMP", ALWAYS },
{ "TEMPORARY", "TK_TEMP", ALWAYS },
@@ -233,7 +260,7 @@ static Keyword aKeywordTable[] = {
};
/* Number of keywords */
-static int NKEYWORD = (sizeof(aKeywordTable)/sizeof(aKeywordTable[0]));
+static int nKeyword = (sizeof(aKeywordTable)/sizeof(aKeywordTable[0]));
/* An array to map all upper-case characters into their corresponding
** lower-case character.
@@ -272,7 +299,10 @@ static int keywordCompare1(const void *a, const void *b){
static int keywordCompare2(const void *a, const void *b){
const Keyword *pA = (Keyword*)a;
const Keyword *pB = (Keyword*)b;
- int n = strcmp(pA->zName, pB->zName);
+ int n = pB->longestSuffix - pA->longestSuffix;
+ if( n==0 ){
+ n = strcmp(pA->zName, pB->zName);
+ }
return n;
}
static int keywordCompare3(const void *a, const void *b){
@@ -287,7 +317,7 @@ static int keywordCompare3(const void *a, const void *b){
*/
static Keyword *findById(int id){
int i;
- for(i=0; i<NKEYWORD; i++){
+ for(i=0; i<nKeyword; i++){
if( aKeywordTable[i].id==id ) break;
}
return &aKeywordTable[i];
@@ -302,34 +332,36 @@ int main(int argc, char **argv){
int bestSize, bestCount;
int count;
int nChar;
- int aHash[1000]; /* 1000 is much bigger than NKEYWORD */
+ int totalLen = 0;
+ int aHash[1000]; /* 1000 is much bigger than nKeyword */
/* Remove entries from the list of keywords that have mask==0 */
- for(i=j=0; i<NKEYWORD; i++){
+ for(i=j=0; i<nKeyword; i++){
if( aKeywordTable[i].mask==0 ) continue;
if( j<i ){
aKeywordTable[j] = aKeywordTable[i];
}
j++;
}
- NKEYWORD = j;
+ nKeyword = j;
/* Fill in the lengths of strings and hashes for all entries. */
- for(i=0; i<NKEYWORD; i++){
+ for(i=0; i<nKeyword; i++){
Keyword *p = &aKeywordTable[i];
p->len = strlen(p->zName);
- p->hash = (UpperToLower[p->zName[0]]*4) ^
- (UpperToLower[p->zName[p->len-1]]*3) ^ p->len;
+ totalLen += p->len;
+ p->hash = (UpperToLower[(int)p->zName[0]]*4) ^
+ (UpperToLower[(int)p->zName[p->len-1]]*3) ^ p->len;
p->id = i+1;
}
/* Sort the table from shortest to longest keyword */
- qsort(aKeywordTable, NKEYWORD, sizeof(aKeywordTable[0]), keywordCompare1);
+ qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare1);
/* Look for short keywords embedded in longer keywords */
- for(i=NKEYWORD-2; i>=0; i--){
+ for(i=nKeyword-2; i>=0; i--){
Keyword *p = &aKeywordTable[i];
- for(j=NKEYWORD-1; j>i && p->substrId==0; j--){
+ for(j=nKeyword-1; j>i && p->substrId==0; j--){
Keyword *pOther = &aKeywordTable[j];
if( pOther->substrId ) continue;
if( pOther->len<=p->len ) continue;
@@ -343,18 +375,35 @@ int main(int argc, char **argv){
}
}
- /* Sort the table into alphabetical order */
- qsort(aKeywordTable, NKEYWORD, sizeof(aKeywordTable[0]), keywordCompare2);
+ /* Compute the longestSuffix value for every word */
+ for(i=0; i<nKeyword; i++){
+ Keyword *p = &aKeywordTable[i];
+ if( p->substrId ) continue;
+ for(j=0; j<nKeyword; j++){
+ Keyword *pOther;
+ if( j==i ) continue;
+ pOther = &aKeywordTable[j];
+ if( pOther->substrId ) continue;
+ for(k=p->longestSuffix+1; k<p->len && k<pOther->len; k++){
+ if( memcmp(&p->zName[p->len-k], pOther->zName, k)==0 ){
+ p->longestSuffix = k;
+ }
+ }
+ }
+ }
+
+ /* Sort the table into reverse order by length */
+ qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare2);
/* Fill in the offset for all entries */
nChar = 0;
- for(i=0; i<NKEYWORD; i++){
+ for(i=0; i<nKeyword; i++){
Keyword *p = &aKeywordTable[i];
if( p->offset>0 || p->substrId ) continue;
p->offset = nChar;
nChar += p->len;
for(k=p->len-1; k>=1; k--){
- for(j=i+1; j<NKEYWORD; j++){
+ for(j=i+1; j<nKeyword; j++){
Keyword *pOther = &aKeywordTable[j];
if( pOther->offset>0 || pOther->substrId ) continue;
if( pOther->len<=k ) continue;
@@ -371,7 +420,7 @@ int main(int argc, char **argv){
}
}
}
- for(i=0; i<NKEYWORD; i++){
+ for(i=0; i<nKeyword; i++){
Keyword *p = &aKeywordTable[i];
if( p->substrId ){
p->offset = findById(p->substrId)->offset + p->substrOffset;
@@ -379,15 +428,15 @@ int main(int argc, char **argv){
}
/* Sort the table by offset */
- qsort(aKeywordTable, NKEYWORD, sizeof(aKeywordTable[0]), keywordCompare3);
+ qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare3);
/* Figure out how big to make the hash table in order to minimize the
** number of collisions */
- bestSize = NKEYWORD;
- bestCount = NKEYWORD*NKEYWORD;
- for(i=NKEYWORD/2; i<=2*NKEYWORD; i++){
+ bestSize = nKeyword;
+ bestCount = nKeyword*nKeyword;
+ for(i=nKeyword/2; i<=2*nKeyword; i++){
for(j=0; j<i; j++) aHash[j] = 0;
- for(j=0; j<NKEYWORD; j++){
+ for(j=0; j<nKeyword; j++){
h = aKeywordTable[j].hash % i;
aHash[h] *= 2;
aHash[h]++;
@@ -401,18 +450,21 @@ int main(int argc, char **argv){
/* Compute the hash */
for(i=0; i<bestSize; i++) aHash[i] = 0;
- for(i=0; i<NKEYWORD; i++){
+ for(i=0; i<nKeyword; i++){
h = aKeywordTable[i].hash % bestSize;
aKeywordTable[i].iNext = aHash[h];
aHash[h] = i+1;
}
/* Begin generating code */
+ printf("%s", zHdr);
printf("/* Hash score: %d */\n", bestCount);
printf("static int keywordCode(const char *z, int n){\n");
+ printf(" /* zText[] encodes %d bytes of keywords in %d bytes */\n",
+ totalLen + nKeyword, nChar+1 );
printf(" static const char zText[%d] =\n", nChar+1);
- for(i=j=0; i<NKEYWORD; i++){
+ for(i=j=0; i<nKeyword; i++){
Keyword *p = &aKeywordTable[i];
if( p->substrId ) continue;
if( j==0 ) printf(" \"");
@@ -437,8 +489,8 @@ int main(int argc, char **argv){
}
printf("%s };\n", j==0 ? "" : "\n");
- printf(" static const unsigned char aNext[%d] = {\n", NKEYWORD);
- for(i=j=0; i<NKEYWORD; i++){
+ printf(" static const unsigned char aNext[%d] = {\n", nKeyword);
+ for(i=j=0; i<nKeyword; i++){
if( j==0 ) printf(" ");
printf(" %3d,", aKeywordTable[i].iNext);
j++;
@@ -449,8 +501,8 @@ int main(int argc, char **argv){
}
printf("%s };\n", j==0 ? "" : "\n");
- printf(" static const unsigned char aLen[%d] = {\n", NKEYWORD);
- for(i=j=0; i<NKEYWORD; i++){
+ printf(" static const unsigned char aLen[%d] = {\n", nKeyword);
+ for(i=j=0; i<nKeyword; i++){
if( j==0 ) printf(" ");
printf(" %3d,", aKeywordTable[i].len+aKeywordTable[i].prefix);
j++;
@@ -461,8 +513,8 @@ int main(int argc, char **argv){
}
printf("%s };\n", j==0 ? "" : "\n");
- printf(" static const unsigned short int aOffset[%d] = {\n", NKEYWORD);
- for(i=j=0; i<NKEYWORD; i++){
+ printf(" static const unsigned short int aOffset[%d] = {\n", nKeyword);
+ for(i=j=0; i<nKeyword; i++){
if( j==0 ) printf(" ");
printf(" %3d,", aKeywordTable[i].offset);
j++;
@@ -473,8 +525,8 @@ int main(int argc, char **argv){
}
printf("%s };\n", j==0 ? "" : "\n");
- printf(" static const unsigned char aCode[%d] = {\n", NKEYWORD);
- for(i=j=0; i<NKEYWORD; i++){
+ printf(" static const unsigned char aCode[%d] = {\n", nKeyword);
+ for(i=j=0; i<nKeyword; i++){
char *zToken = aKeywordTable[i].zTokenType;
if( j==0 ) printf(" ");
printf("%s,%*s", zToken, (int)(14-strlen(zToken)), "");
diff --git a/ext/pdo_sqlite/sqlite/tool/mksqlite3c.tcl b/ext/pdo_sqlite/sqlite/tool/mksqlite3c.tcl
new file mode 100644
index 0000000000..e7befd8fc4
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/tool/mksqlite3c.tcl
@@ -0,0 +1,278 @@
+#!/usr/bin/tclsh
+#
+# To build a single huge source file holding all of SQLite (or at
+# least the core components - the test harness, shell, and TCL
+# interface are omitted.) first do
+#
+# make target_source
+#
+# The make target above moves all of the source code files into
+# a subdirectory named "tsrc". (This script expects to find the files
+# there and will not work if they are not found.) There are a few
+# generated C code files that are also added to the tsrc directory.
+# For example, the "parse.c" and "parse.h" files to implement the
+# the parser are derived from "parse.y" using lemon. And the
+# "keywordhash.h" files is generated by a program named "mkkeywordhash".
+#
+# After the "tsrc" directory has been created and populated, run
+# this script:
+#
+# tclsh mksqlite3c.tcl
+#
+# The amalgamated SQLite code will be written into sqlite3.c
+#
+
+# Begin by reading the "sqlite3.h" header file. Count the number of lines
+# in this file and extract the version number. That information will be
+# needed in order to generate the header of the amalgamation.
+#
+if {[lsearch $argv --nostatic]>=0} {
+ set addstatic 0
+} else {
+ set addstatic 1
+}
+set in [open tsrc/sqlite3.h]
+set cnt 0
+set VERSION ?????
+while {![eof $in]} {
+ set line [gets $in]
+ if {$line=="" && [eof $in]} break
+ incr cnt
+ regexp {#define\s+SQLITE_VERSION\s+"(.*)"} $line all VERSION
+}
+close $in
+
+# Open the output file and write a header comment at the beginning
+# of the file.
+#
+set out [open sqlite3.c w]
+set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1]
+puts $out [subst \
+{/******************************************************************************
+** This file is an amalgamation of many separate C source files from SQLite
+** version $VERSION. By combining all the individual C code files into this
+** single large file, the entire code can be compiled as a one translation
+** unit. This allows many compilers to do optimizations that would not be
+** possible if the files were compiled separately. Performance improvements
+** of 5% are more are commonly seen when SQLite is compiled as a single
+** translation unit.
+**
+** This file is all you need to compile SQLite. To use SQLite in other
+** programs, you need this file and the "sqlite3.h" header file that defines
+** the programming interface to the SQLite library. (If you do not have
+** the "sqlite3.h" header file at hand, you will find a copy in the first
+** $cnt lines past this header comment.) Additional code files may be
+** needed if you want a wrapper to interface SQLite with your choice of
+** programming language. The code for the "sqlite3" command-line shell
+** is also in a separate file. This file contains only code for the core
+** SQLite library.
+**
+** This amalgamation was generated on $today.
+*/
+#define SQLITE_CORE 1
+#define SQLITE_AMALGAMATION 1}]
+if {$addstatic} {
+ puts $out \
+{#ifndef SQLITE_PRIVATE
+# define SQLITE_PRIVATE static
+#endif
+#ifndef SQLITE_API
+# define SQLITE_API
+#endif}
+}
+
+# These are the header files used by SQLite. The first time any of these
+# files are seen in a #include statement in the C code, include the complete
+# text of the file in-line. The file only needs to be included once.
+#
+foreach hdr {
+ btree.h
+ btreeInt.h
+ fts3.h
+ fts3_hash.h
+ fts3_tokenizer.h
+ hash.h
+ keywordhash.h
+ mutex.h
+ opcodes.h
+ os_common.h
+ os.h
+ os_os2.h
+ pager.h
+ parse.h
+ sqlite3ext.h
+ sqlite3.h
+ sqliteInt.h
+ sqliteLimit.h
+ vdbe.h
+ vdbeInt.h
+} {
+ set available_hdr($hdr) 1
+}
+set available_hdr(sqliteInt.h) 0
+
+# 78 stars used for comment formatting.
+set s78 \
+{*****************************************************************************}
+
+# Insert a comment into the code
+#
+proc section_comment {text} {
+ global out s78
+ set n [string length $text]
+ set nstar [expr {60 - $n}]
+ set stars [string range $s78 0 $nstar]
+ puts $out "/************** $text $stars/"
+}
+
+# Read the source file named $filename and write it into the
+# sqlite3.c output file. If any #include statements are seen,
+# process them approprately.
+#
+proc copy_file {filename} {
+ global seen_hdr available_hdr out addstatic
+ set tail [file tail $filename]
+ section_comment "Begin file $tail"
+ set in [open $filename r]
+ set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+(sqlite3[_a-zA-Z0-9]+)(\[|;| =)}
+ set declpattern {[a-zA-Z][a-zA-Z_0-9 ]+ \*?(sqlite3[_a-zA-Z0-9]+)\(}
+ if {[file extension $filename]==".h"} {
+ set declpattern " *$declpattern"
+ }
+ set declpattern ^$declpattern
+ while {![eof $in]} {
+ set line [gets $in]
+ if {[regexp {^#\s*include\s+["<]([^">]+)[">]} $line all hdr]} {
+ if {[info exists available_hdr($hdr)]} {
+ if {$available_hdr($hdr)} {
+ if {$hdr!="os_common.h"} {
+ set available_hdr($hdr) 0
+ }
+ section_comment "Include $hdr in the middle of $tail"
+ copy_file tsrc/$hdr
+ section_comment "Continuing where we left off in $tail"
+ }
+ } elseif {![info exists seen_hdr($hdr)]} {
+ set seen_hdr($hdr) 1
+ puts $out $line
+ }
+ } elseif {[regexp {^#ifdef __cplusplus} $line]} {
+ puts $out "#if 0"
+ } elseif {[regexp {^#line} $line]} {
+ # Skip #line directives.
+ } elseif {$addstatic && ![regexp {^(static|typedef)} $line]} {
+ if {[regexp $declpattern $line all funcname]} {
+ # Add the SQLITE_PRIVATE or SQLITE_API keyword before functions.
+ # so that linkage can be modified at compile-time.
+ if {[regexp {^sqlite3_} $funcname]} {
+ puts $out "SQLITE_API $line"
+ } else {
+ puts $out "SQLITE_PRIVATE $line"
+ }
+ } elseif {[regexp $varpattern $line all varname]} {
+ # Add the SQLITE_PRIVATE before variable declarations or
+ # definitions for internal use
+ if {![regexp {^sqlite3_} $varname]} {
+ regsub {^extern } $line {} line
+ puts $out "SQLITE_PRIVATE $line"
+ } elseif {![regexp {^SQLITE_EXTERN} $line]} {
+ puts $out "SQLITE_API $line"
+ } else {
+ puts $out $line
+ }
+ } elseif {[regexp {^void \(\*sqlite3_io_trace\)} $line]} {
+ puts $out "SQLITE_API $line"
+ } else {
+ puts $out $line
+ }
+ } else {
+ puts $out $line
+ }
+ }
+ close $in
+ section_comment "End of $tail"
+}
+
+
+# Process the source files. Process files containing commonly
+# used subroutines first in order to help the compiler find
+# inlining opportunities.
+#
+foreach file {
+ sqliteInt.h
+
+ date.c
+ os.c
+
+ fault.c
+ mem1.c
+ mem2.c
+ mem3.c
+ mutex.c
+ mutex_os2.c
+ mutex_unix.c
+ mutex_w32.c
+ malloc.c
+ printf.c
+ random.c
+ utf.c
+ util.c
+ hash.c
+ opcodes.c
+
+ os_os2.c
+ os_unix.c
+ os_win.c
+
+ pager.c
+
+ btmutex.c
+ btree.c
+
+ vdbefifo.c
+ vdbemem.c
+ vdbeaux.c
+ vdbeapi.c
+ vdbe.c
+ vdbeblob.c
+ journal.c
+
+ expr.c
+ alter.c
+ analyze.c
+ attach.c
+ auth.c
+ build.c
+ callback.c
+ delete.c
+ func.c
+ insert.c
+ legacy.c
+ loadext.c
+ pragma.c
+ prepare.c
+ select.c
+ table.c
+ trigger.c
+ update.c
+ vacuum.c
+ vtab.c
+ where.c
+
+ parse.c
+
+ tokenize.c
+ complete.c
+
+ main.c
+
+ fts3.c
+ fts3_hash.c
+ fts3_porter.c
+ fts3_tokenizer.c
+ fts3_tokenizer1.c
+} {
+ copy_file tsrc/$file
+}
+
+close $out
diff --git a/ext/pdo_sqlite/sqlite/tool/mksqlite3internalh.tcl b/ext/pdo_sqlite/sqlite/tool/mksqlite3internalh.tcl
new file mode 100644
index 0000000000..cacd7cbe18
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/tool/mksqlite3internalh.tcl
@@ -0,0 +1,145 @@
+#!/usr/bin/tclsh
+#
+# To build a single huge source file holding all of SQLite (or at
+# least the core components - the test harness, shell, and TCL
+# interface are omitted.) first do
+#
+# make target_source
+#
+# The make target above moves all of the source code files into
+# a subdirectory named "tsrc". (This script expects to find the files
+# there and will not work if they are not found.) There are a few
+# generated C code files that are also added to the tsrc directory.
+# For example, the "parse.c" and "parse.h" files to implement the
+# the parser are derived from "parse.y" using lemon. And the
+# "keywordhash.h" files is generated by a program named "mkkeywordhash".
+#
+# After the "tsrc" directory has been created and populated, run
+# this script:
+#
+# tclsh mksqlite3c.tcl
+#
+# The amalgamated SQLite code will be written into sqlite3.c
+#
+
+# Begin by reading the "sqlite3.h" header file. Count the number of lines
+# in this file and extract the version number. That information will be
+# needed in order to generate the header of the amalgamation.
+#
+set in [open tsrc/sqlite3.h]
+set cnt 0
+set VERSION ?????
+while {![eof $in]} {
+ set line [gets $in]
+ if {$line=="" && [eof $in]} break
+ incr cnt
+ regexp {#define\s+SQLITE_VERSION\s+"(.*)"} $line all VERSION
+}
+close $in
+
+# Open the output file and write a header comment at the beginning
+# of the file.
+#
+set out [open sqlite3internal.h w]
+set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1]
+puts $out [subst \
+{/******************************************************************************
+** This file is an amalgamation of many private header files from SQLite
+** version $VERSION.
+*/}]
+
+# These are the header files used by SQLite. The first time any of these
+# files are seen in a #include statement in the C code, include the complete
+# text of the file in-line. The file only needs to be included once.
+#
+foreach hdr {
+ btree.h
+ btreeInt.h
+ hash.h
+ keywordhash.h
+ opcodes.h
+ os_common.h
+ os.h
+ os_os2.h
+ pager.h
+ parse.h
+ sqlite3ext.h
+ sqlite3.h
+ sqliteInt.h
+ sqliteLimit.h
+ vdbe.h
+ vdbeInt.h
+} {
+ set available_hdr($hdr) 1
+}
+
+# 78 stars used for comment formatting.
+set s78 \
+{*****************************************************************************}
+
+# Insert a comment into the code
+#
+proc section_comment {text} {
+ global out s78
+ set n [string length $text]
+ set nstar [expr {60 - $n}]
+ set stars [string range $s78 0 $nstar]
+ puts $out "/************** $text $stars/"
+}
+
+# Read the source file named $filename and write it into the
+# sqlite3.c output file. If any #include statements are seen,
+# process them approprately.
+#
+proc copy_file {filename} {
+ global seen_hdr available_hdr out
+ set tail [file tail $filename]
+ section_comment "Begin file $tail"
+ set in [open $filename r]
+ while {![eof $in]} {
+ set line [gets $in]
+ if {[regexp {^#\s*include\s+["<]([^">]+)[">]} $line all hdr]} {
+ if {[info exists available_hdr($hdr)]} {
+ if {$available_hdr($hdr)} {
+ section_comment "Include $hdr in the middle of $tail"
+ copy_file tsrc/$hdr
+ section_comment "Continuing where we left off in $tail"
+ }
+ } elseif {![info exists seen_hdr($hdr)]} {
+ set seen_hdr($hdr) 1
+ puts $out $line
+ }
+ } elseif {[regexp {^#ifdef __cplusplus} $line]} {
+ puts $out "#if 0"
+ } elseif {[regexp {^#line} $line]} {
+ # Skip #line directives.
+ } else {
+ puts $out $line
+ }
+ }
+ close $in
+ section_comment "End of $tail"
+}
+
+
+# Process the source files. Process files containing commonly
+# used subroutines first in order to help the compiler find
+# inlining opportunities.
+#
+foreach file {
+ sqliteInt.h
+ sqlite3.h
+ btree.h
+ hash.h
+ os.h
+ pager.h
+ parse.h
+ sqlite3ext.h
+ vdbe.h
+} {
+ if {$available_hdr($file)} {
+ copy_file tsrc/$file
+ }
+}
+
+close $out
diff --git a/ext/pdo_sqlite/sqlite/tool/omittest.tcl b/ext/pdo_sqlite/sqlite/tool/omittest.tcl
new file mode 100644
index 0000000000..baf69c3151
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/tool/omittest.tcl
@@ -0,0 +1,176 @@
+
+set rcsid {$Id: omittest.tcl,v 1.2 2008-03-07 10:55:14 scottmac Exp $}
+
+# Documentation for this script. This may be output to stderr
+# if the script is invoked incorrectly.
+set ::USAGE_MESSAGE {
+This Tcl script is used to test the various compile time options
+available for omitting code (the SQLITE_OMIT_xxx options). It
+should be invoked as follows:
+
+ <script> ?-makefile PATH-TO-MAKEFILE?
+
+The default value for ::MAKEFILE is "../Makefile.linux.gcc".
+
+This script builds the testfixture program and runs the SQLite test suite
+once with each SQLITE_OMIT_ option defined and then once with all options
+defined together. Each run is performed in a seperate directory created
+as a sub-directory of the current directory by the script. The output
+of the build is saved in <sub-directory>/build.log. The output of the
+test-suite is saved in <sub-directory>/test.log.
+
+Almost any SQLite makefile (except those generated by configure - see below)
+should work. The following properties are required:
+
+ * The makefile should support the "testfixture" target.
+ * The makefile should support the "test" target.
+ * The makefile should support the variable "OPTS" as a way to pass
+ options from the make command line to lemon and the C compiler.
+
+More precisely, the following two invocations must be supported:
+
+ make -f $::MAKEFILE testfixture OPTS="-DSQLITE_OMIT_ALTERTABLE=1"
+ make -f $::MAKEFILE test
+
+Makefiles generated by the sqlite configure program cannot be used as
+they do not respect the OPTS variable.
+}
+
+
+# Build a testfixture executable and run quick.test using it. The first
+# parameter is the name of the directory to create and use to run the
+# test in. The second parameter is a list of OMIT symbols to define
+# when doing so. For example:
+#
+# run_quick_test /tmp/testdir {SQLITE_OMIT_TRIGGER SQLITE_OMIT_VIEW}
+#
+#
+proc run_quick_test {dir omit_symbol_list} {
+ # Compile the value of the OPTS Makefile variable.
+ set opts "-DSQLITE_MEMDEBUG=2 -DSQLITE_DEBUG -DOS_UNIX"
+ foreach sym $omit_symbol_list {
+ append opts " -D${sym}=1"
+ }
+
+ # Create the directory and do the build. If an error occurs return
+ # early without attempting to run the test suite.
+ file mkdir $dir
+ puts -nonewline "Building $dir..."
+ flush stdout
+ set rc [catch {
+ exec make -C $dir -f $::MAKEFILE testfixture OPTS=$opts >& $dir/build.log
+ }]
+ if {$rc} {
+ puts "No good. See $dir/build.log."
+ return
+ } else {
+ puts "Ok"
+ }
+
+ # Create an empty file "$dir/sqlite3". This is to trick the makefile out
+ # of trying to build the sqlite shell. The sqlite shell won't build
+ # with some of the OMIT options (i.e OMIT_COMPLETE).
+ if {![file exists $dir/sqlite3]} {
+ set wr [open $dir/sqlite3 w]
+ puts $wr "dummy"
+ close $wr
+ }
+
+ # Run the test suite.
+ puts -nonewline "Testing $dir..."
+ flush stdout
+ set rc [catch {
+ exec make -C $dir -f $::MAKEFILE test OPTS=$opts >& $dir/test.log
+ }]
+ if {$rc} {
+ puts "No good. See $dir/test.log."
+ } else {
+ puts "Ok"
+ }
+}
+
+
+# This proc processes the command line options passed to this script.
+# Currently the only option supported is "-makefile", default
+# "../Makefile.linux-gcc". Set the ::MAKEFILE variable to the value of this
+# option.
+#
+proc process_options {argv} {
+ set ::MAKEFILE ../Makefile.linux-gcc ;# Default value
+ for {set i 0} {$i < [llength $argv]} {incr i} {
+ switch -- [lindex $argv $i] {
+ -makefile {
+ incr i
+ set ::MAKEFILE [lindex $argv $i]
+ }
+
+ default {
+ puts stderr [string trim $::USAGE_MESSAGE]
+ exit -1
+ }
+ }
+ set ::MAKEFILE [file normalize $::MAKEFILE]
+ }
+}
+
+# Main routine.
+#
+
+proc main {argv} {
+ # List of SQLITE_OMIT_XXX symbols supported by SQLite.
+ set ::SYMBOLS [list \
+ SQLITE_OMIT_ALTERTABLE \
+ SQLITE_OMIT_AUTHORIZATION \
+ SQLITE_OMIT_AUTOINCREMENT \
+ SQLITE_OMIT_AUTOVACUUM \
+ SQLITE_OMIT_BLOB_LITERAL \
+ SQLITE_OMIT_COMPLETE \
+ SQLITE_OMIT_COMPOUND_SELECT \
+ SQLITE_OMIT_CONFLICT_CLAUSE \
+ SQLITE_OMIT_DATETIME_FUNCS \
+ SQLITE_OMIT_EXPLAIN \
+ SQLITE_OMIT_FLOATING_POINT \
+ SQLITE_OMIT_FOREIGN_KEY \
+ SQLITE_OMIT_INCRBLOB \
+ SQLITE_OMIT_INTEGRITY_CHECK \
+ SQLITE_OMIT_MEMORYDB \
+ SQLITE_OMIT_PAGER_PRAGMAS \
+ SQLITE_OMIT_PRAGMA \
+ SQLITE_OMIT_PROGRESS_CALLBACK \
+ SQLITE_OMIT_REINDEX \
+ SQLITE_OMIT_SCHEMA_PRAGMAS \
+ SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS \
+ SQLITE_OMIT_SUBQUERY \
+ SQLITE_OMIT_TCL_VARIABLE \
+ SQLITE_OMIT_TRIGGER \
+ SQLITE_OMIT_UTF16 \
+ SQLITE_OMIT_VACUUM \
+ SQLITE_OMIT_VIEW \
+ SQLITE_OMIT_VIRTUALTABLE \
+ ]
+
+ # Process any command line options.
+ process_options $argv
+
+ # First try a test with all OMIT symbols except SQLITE_OMIT_FLOATING_POINT
+ # and SQLITE_OMIT_PRAGMA defined. The former doesn't work (causes segfaults)
+ # and the latter is currently incompatible with the test suite (this should
+ # be fixed, but it will be a lot of work).
+ set allsyms [list]
+ foreach s $::SYMBOLS {
+ if {$s!="SQLITE_OMIT_FLOATING_POINT" && $s!="SQLITE_OMIT_PRAGMA"} {
+ lappend allsyms $s
+ }
+ }
+ run_quick_test test_OMIT_EVERYTHING $allsyms
+
+ # Now try one quick.test with each of the OMIT symbols defined. Included
+ # are the OMIT_FLOATING_POINT and OMIT_PRAGMA symbols, even though we
+ # know they will fail. It's good to be reminded of this from time to time.
+ foreach sym $::SYMBOLS {
+ set dirname "test_[string range $sym 7 end]"
+ run_quick_test $dirname $sym
+ }
+}
+
+main $argv
diff --git a/ext/pdo_sqlite/sqlite/tool/soak1.tcl b/ext/pdo_sqlite/sqlite/tool/soak1.tcl
new file mode 100644
index 0000000000..7a78b8d7dd
--- /dev/null
+++ b/ext/pdo_sqlite/sqlite/tool/soak1.tcl
@@ -0,0 +1,103 @@
+#!/usr/bin/tclsh
+#
+# Usage:
+#
+# tclsh soak1.tcl local-makefile.mk ?target? ?scenario?
+#
+# This generates many variations on local-makefile.mk (by modifing
+# the OPT = lines) and runs them will fulltest, one by one. The
+# constructed makefiles are named "soak1.mk".
+#
+# If ?target? is provided, that is the makefile target that is run.
+# The default is "fulltest"
+#
+# If ?scenario? is provided, it is the name of a single scenario to
+# be run. All other scenarios are skipped.
+#
+set localmake [lindex $argv 0]
+set target [lindex $argv 1]
+set scene [lindex $argv 2]
+if {$target==""} {set target fulltest}
+if {$scene==""} {set scene all}
+
+set in [open $localmake]
+set maketxt [read $in]
+close $in
+regsub -all {\\\n} $maketxt {} maketxt
+#set makefilename "soak1-[expr {int(rand()*1000000000)}].mk"
+set makefilename "soak1.mk"
+
+# Generate a makefile
+#
+proc generate_makefile {pattern} {
+ global makefilename maketxt
+ set out [open $makefilename w]
+ set seen_opt 0
+ foreach line [split $maketxt \n] {
+ if {[regexp {^ *#? *OPTS[ =+]} $line]} {
+ if {!$seen_opt} {
+ puts $out "OPTS += -DSQLITE_NO_SYNC=1"
+ foreach x $pattern {
+ puts $out "OPTS += -D$x"
+ }
+ set seen_opt 1
+ }
+ } else {
+ puts $out $line
+ }
+ }
+ close $out
+}
+
+# Run a test
+#
+proc scenario {id title pattern} {
+ global makefilename target scene
+ if {$scene!="all" && $scene!=$id && $scene!=$title} return
+ puts "**************** $title ***************"
+ generate_makefile $pattern
+ exec make -f $makefilename clean >@stdout 2>@stdout
+ exec make -f $makefilename $target >@stdout 2>@stdout
+}
+
+###############################################################################
+# Add new scenarios here
+#
+scenario 0 {Default} {}
+scenario 1 {Debug} {
+ SQLITE_DEBUG=1
+ SQLITE_MEMDEBUG=1
+}
+scenario 2 {Everything} {
+ SQLITE_DEBUG=1
+ SQLITE_MEMDEBUG=1
+ SQLITE_ENABLE_MEMORY_MANAGEMENT=1
+ SQLITE_ENABLE_COLUMN_METADATA=1
+ SQLITE_ENABLE_LOAD_EXTENSION=1 HAVE_DLOPEN=1
+ SQLITE_ENABLE_MEMORY_MANAGEMENT=1
+}
+scenario 3 {Customer-1} {
+ SQLITE_DEBUG=1 SQLITE_MEMDEBUG=1
+ THREADSAFE=1 OS_UNIX=1
+ SQLITE_DISABLE_LFS=1
+ SQLITE_DEFAULT_AUTOVACUUM=1
+ SQLITE_DEFAULT_PAGE_SIZE=1024
+ SQLITE_MAX_PAGE_SIZE=4096
+ SQLITE_DEFAULT_CACHE_SIZE=64
+ SQLITE_DEFAULT_TEMP_CACHE_SIZE=32
+ TEMP_STORE=3
+ SQLITE_OMIT_PROGRESS_CALLBACK=1
+ SQLITE_OMIT_LOAD_EXTENSION=1
+ SQLITE_OMIT_VIRTUALTABLE=1
+ SQLITE_ENABLE_IOTRACE=1
+}
+scenario 4 {Small-Cache} {
+ SQLITE_DEBUG=1 SQLITE_MEMDEBUG=1
+ THREADSAFE=1 OS_UNIX=1
+ SQLITE_DEFAULT_AUTOVACUUM=1
+ SQLITE_DEFAULT_PAGE_SIZE=1024
+ SQLITE_MAX_PAGE_SIZE=2048
+ SQLITE_DEFAULT_CACHE_SIZE=13
+ SQLITE_DEFAULT_TEMP_CACHE_SIZE=11
+ TEMP_STORE=1
+}
diff --git a/ext/pdo_sqlite/sqlite/tool/spaceanal.tcl b/ext/pdo_sqlite/sqlite/tool/spaceanal.tcl
index c0fe5b5d87..3718357cbb 100644
--- a/ext/pdo_sqlite/sqlite/tool/spaceanal.tcl
+++ b/ext/pdo_sqlite/sqlite/tool/spaceanal.tcl
@@ -26,6 +26,10 @@ if {[file size $file_to_analyze]<512} {
exit 1
}
+# Maximum distance between pages before we consider it a "gap"
+#
+set MAXGAP 3
+
# Open the database
#
sqlite3 db [lindex $argv 0]
@@ -53,12 +57,17 @@ set tabledef\
ovfl_pages int, -- Number of overflow pages used
int_unused int, -- Number of unused bytes on interior pages
leaf_unused int, -- Number of unused bytes on primary pages
- ovfl_unused int -- Number of unused bytes on overflow pages
+ ovfl_unused int, -- Number of unused bytes on overflow pages
+ gap_cnt int -- Number of gaps in the page layout
);}
mem eval $tabledef
proc integerify {real} {
- return [expr int($real)]
+ if {[string is double -strict $real]} {
+ return [expr {int($real)}]
+ } else {
+ return 0
+ }
}
mem function int integerify
@@ -105,7 +114,8 @@ proc cursor_info {arrayvar csr {up 0}} {
a(payload_bytes) \
a(header_bytes) \
a(local_payload_bytes) \
- a(parent) ] [btree_cursor_info $csr $up] {}
+ a(parent) \
+ a(first_ovfl) ] [btree_cursor_info $csr $up] break
}
# Determine the page-size of the database. This global variable is used
@@ -119,7 +129,8 @@ set pageSize [db eval {PRAGMA page_size}]
# database, including the sqlite_master table.
#
set sql {
- SELECT name, rootpage FROM sqlite_master WHERE type='table'
+ SELECT name, rootpage FROM sqlite_master
+ WHERE type='table' AND rootpage>0
UNION ALL
SELECT 'sqlite_master', 1
ORDER BY 1
@@ -144,6 +155,8 @@ foreach {name rootpage} [db eval $sql] {
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
+ set gap_cnt 0 ;# Number of holes in the page sequence
+ set prev_pgno 0 ;# Last page number seen
# As the btree is traversed, the array variable $seen($pgno) is set to 1
# the first time page $pgno is encountered.
@@ -179,6 +192,9 @@ foreach {name rootpage} [db eval $sql] {
set n [expr {int(ceil($ovfl/($pageSize-4.0)))}]
incr ovfl_pages $n
incr unused_ovfl [expr {$n*($pageSize-4) - $ovfl}]
+ set pglist [btree_ovfl_info $DB $csr]
+ } else {
+ set pglist {}
}
# If this is the first table entry analyzed for the page, then update
@@ -190,6 +206,7 @@ foreach {name rootpage} [db eval $sql] {
set seen($ci(page_no)) 1
incr leaf_pages
incr unused_leaf $ci(page_freebytes)
+ set pglist "$ci(page_no) $pglist"
# Now check if the page has a parent that has not been analyzed. If
# so, update the $int_pages, $cnt_int_entry and $unused_int statistics
@@ -209,7 +226,19 @@ foreach {name rootpage} [db eval $sql] {
incr int_pages
incr cnt_int_entry $ci(page_entries)
incr unused_int $ci(page_freebytes)
+
+ # parent pages come before their first child
+ set pglist "$ci(page_no) $pglist"
+ }
+ }
+
+ # Check the page list for fragmentation
+ #
+ foreach pg $pglist {
+ if {$pg!=$prev_pgno+1 && $prev_pgno>0} {
+ incr gap_cnt
}
+ set prev_pgno $pg
}
}
btree_close_cursor $csr
@@ -249,6 +278,7 @@ foreach {name rootpage} [db eval $sql] {
append sql ",$unused_int"
append sql ",$unused_leaf"
append sql ",$unused_ovfl"
+ append sql ",$gap_cnt"
append sql );
mem eval $sql
}
@@ -278,6 +308,8 @@ foreach {name tbl_name rootpage} [db eval $sql] {
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 gap_cnt 0 ;# Number of holes in the page sequence
+ set prev_pgno 0 ;# Last page number seen
# As the btree is traversed, the array variable $seen($pgno) is set to 1
# the first time page $pgno is encountered.
@@ -323,6 +355,11 @@ foreach {name tbl_name rootpage} [db eval $sql] {
set seen($ci(page_no)) 1
incr leaf_pages
incr unused_leaf $ci(page_freebytes)
+ set pg $ci(page_no)
+ if {$prev_pgno>0 && $pg!=$prev_pgno+1} {
+ incr gap_cnt
+ }
+ set prev_pgno $ci(page_no)
}
}
btree_close_cursor $csr
@@ -354,6 +391,7 @@ foreach {name tbl_name rootpage} [db eval $sql] {
append sql ",0"
append sql ",$unused_leaf"
append sql ",$unused_ovfl"
+ append sql ",$gap_cnt"
append sql );
mem eval $sql
}
@@ -419,7 +457,8 @@ proc subreport {title where} {
int(sum(ovfl_pages)) AS ovfl_pages,
int(sum(leaf_unused)) AS leaf_unused,
int(sum(int_unused)) AS int_unused,
- int(sum(ovfl_unused)) AS ovfl_unused
+ int(sum(ovfl_unused)) AS ovfl_unused,
+ int(sum(gap_cnt)) AS gap_cnt
FROM space_used WHERE $where" {} {}
# Output the sub-report title, nicely decorated with * characters.
@@ -475,6 +514,10 @@ proc subreport {title where} {
if {[info exists avg_fanout]} {
statline {Average fanout} $avg_fanout
}
+ if {$total_pages>1} {
+ set fragmentation [percent $gap_cnt [expr {$total_pages-1}] {fragmentation}]
+ statline {Fragmentation} $fragmentation
+ }
statline {Maximum payload per entry} $mx_payload
statline {Entries that use overflow} $ovfl_cnt $ovfl_cnt_percent
if {$int_pages>0} {
@@ -582,7 +625,9 @@ set user_percent [percent $user_payload $file_bytes]
# Output the summary statistics calculated above.
#
puts "/** Disk-Space Utilization Report For $file_to_analyze"
-puts "*** As of [clock format [clock seconds] -format {%Y-%b-%d %H:%M:%S}]"
+catch {
+ puts "*** As of [clock format [clock seconds] -format {%Y-%b-%d %H:%M:%S}]"
+}
puts ""
statline {Page size in bytes} $pageSize
statline {Pages in the whole file (measured)} $file_pgcnt
@@ -728,6 +773,14 @@ Average unused bytes per entry
category on a per-entry basis. This is the number of unused bytes on
all pages divided by the number of entries.
+Fragmentation
+
+ The percentage of pages in the table or index that are not
+ consecutive in the disk file. Many filesystems are optimized
+ for sequential file access so smaller fragmentation numbers
+ sometimes result in faster queries, especially for larger
+ database files that do not fit in the disk cache.
+
Maximum payload per entry
The largest payload size of any entry.