Copy php5 from old repository and update 372/head
authorW. Michael Petullo <mike@flyn.org>
Mon, 29 Sep 2014 01:56:33 +0000 (21:56 -0400)
committerW. Michael Petullo <mike@flyn.org>
Mon, 29 Sep 2014 01:56:33 +0000 (21:56 -0400)
Signed-off-by: W. Michael Petullo <mike@flyn.org>
lang/php5/Makefile [new file with mode: 0644]
lang/php5/files/php.ini [new file with mode: 0644]
lang/php5/files/php5-fastcgi.config [new file with mode: 0644]
lang/php5/files/php5-fastcgi.init [new file with mode: 0644]
lang/php5/patches/090-restore-sqlite2.patch [new file with mode: 0644]
lang/php5/patches/091-fix-sqlite2.patch [new file with mode: 0644]
lang/php5/patches/101-fix_membar_producer_link_error_gcc3x.patch [new file with mode: 0644]
lang/php5/patches/102-debian_patches_use_embedded_timezonedb.patch [new file with mode: 0644]
lang/php5/patches/103-debian_patches_use_embedded_timezonedb.patch [new file with mode: 0644]
lang/php5/patches/950-Fix-dl-cross-compiling-issue.patch [new file with mode: 0644]
lang/php5/pecl.mk [new file with mode: 0644]

diff --git a/lang/php5/Makefile b/lang/php5/Makefile
new file mode 100644 (file)
index 0000000..8216fdf
--- /dev/null
@@ -0,0 +1,538 @@
+#
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=php
+PKG_VERSION:=5.4.33
+PKG_RELEASE:=1
+
+PKG_MAINTAINER:=W. Michael Petullo <mike@flyn.org>
+
+PKG_LICENSE=PHPv3.01
+PKG_LICENSE_FILE=LICENSE
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=http://www.php.net/distributions/
+PKG_MD5SUM:=c6878bb1cdb46bfc1e1a5cd67a024737
+
+PKG_FIXUP:=libtool no-autoreconf
+PKG_BUILD_PARALLEL:=1
+
+PHP5_MODULES = \
+       calendar ctype curl \
+       fileinfo \
+       dom \
+       exif \
+       ftp \
+       gettext gd gmp \
+       hash \
+       iconv \
+       json \
+       ldap \
+       mbstring mcrypt mysql mysqli \
+       openssl \
+       pcntl pdo pdo-mysql pdo-pgsql pdo-sqlite pgsql \
+       session shmop simplexml soap sockets sqlite sqlite3 sysvmsg sysvsem sysvshm \
+       tokenizer \
+       xml xmlreader xmlwriter zip \
+
+PKG_CONFIG_DEPENDS:= \
+       $(patsubst %,CONFIG_PACKAGE_php5-mod-%,$(PHP5_MODULES)) \
+       CONFIG_PHP5_FILTER CONFIG_PHP5_LIBXML CONFIG_PHP5_SYSTEMTZDATA
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/nls.mk
+
+define Package/php5/Default
+  SUBMENU:=PHP
+  SECTION:=lang
+  CATEGORY:=Languages
+  TITLE:=PHP5 Hypertext preprocessor
+  URL:=http://www.php.net/
+  MAINTAINER:=Michael Heimpold <mhei@heimpold.de>
+  DEPENDS:=php5
+endef
+
+define Package/php5/Default/description
+  PHP is a widely-used general-purpose scripting language that is especially
+  suited for Web development and can be embedded into HTML.
+endef
+
+define Package/php5/config
+       config PHP5_FILTER
+               bool "PHP5 Filter support"
+               depends on PACKAGE_php5-cli || PACKAGE_php5-cgi
+
+       config PHP5_LIBXML
+               bool "PHP5 LIBXML support"
+               depends on PACKAGE_php5-cli || PACKAGE_php5-cgi
+
+       config PHP5_SYSTEMTZDATA
+               bool "Use system timezone data instead of php's built-in database"
+               depends on PACKAGE_php5-cli || PACKAGE_php5-cgi
+               select PACKAGE_zoneinfo-core
+               default y
+               help
+                       Enabling this feature automatically selects the zoneinfo-core package
+                       which contains data for UTC timezone. To use other timezones you have
+                       to install the corresponding zoneinfo-... package(s).
+endef
+
+define Package/php5
+  $(call Package/php5/Default)
+
+  DEPENDS:=+libpcre +zlib \
+           +PHP5_LIBXML:libxml2
+endef
+
+define Package/php5/description
+  $(call Package/php5/Default/description)
+  This package contains only the PHP config file. You must actually choose
+  your PHP flavour (cli, cgi or fastcgi).
+endef
+
+define Package/php5-cli
+  $(call Package/php5/Default)
+  TITLE+= (CLI)
+endef
+
+define Package/php5-cli/description
+  $(call Package/php5/Default/description)
+  This package contains the CLI version of the PHP5 interpreter.
+endef
+
+define Package/php5-cgi
+  $(call Package/php5/Default)
+  TITLE+= (CGI & FastCGI)
+endef
+
+define Package/php5-cgi/description
+  $(call Package/php5/Default/description)
+  This package contains the CGI version of the PHP5 interpreter.
+endef
+
+define Package/php5-fastcgi
+  $(call Package/php5/Default)
+  DEPENDS+= +php5-cgi
+  TITLE:=FastCGI startup script
+endef
+
+define Package/php5-fastcgi/description
+  As FastCGI support is now a core feature the php5-fastcgi package now depends
+  on the php5-cgi package, containing just the startup script.
+endef
+
+CONFIGURE_ARGS+= \
+       --enable-cli \
+       --enable-cgi \
+       --enable-shared \
+       --disable-static \
+       --disable-rpath \
+       --disable-debug \
+       --without-pear \
+       \
+       --with-config-file-path=/etc \
+       --with-config-file-scan-dir=/etc/php5 \
+       --disable-short-tags \
+       \
+       --with-zlib="$(STAGING_DIR)/usr" \
+         --with-zlib-dir="$(STAGING_DIR)/usr" \
+       --with-pcre-regex="$(STAGING_DIR)/usr" \
+       --disable-phar
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-calendar),)
+  CONFIGURE_ARGS+= --enable-calendar=shared
+else
+  CONFIGURE_ARGS+= --disable-calendar
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-ctype),)
+  CONFIGURE_ARGS+= --enable-ctype=shared
+else
+  CONFIGURE_ARGS+= --disable-ctype
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-curl),)
+  CONFIGURE_ARGS+= --with-curl=shared,"$(STAGING_DIR)/usr"
+else
+  CONFIGURE_ARGS+= --without-curl
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-fileinfo),)
+  CONFIGURE_ARGS+= --enable-fileinfo=shared
+else
+  CONFIGURE_ARGS+= --disable-fileinfo
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-gettext),)
+  CONFIGURE_ARGS+= --with-gettext=shared,"$(STAGING_DIR)/usr/lib/libintl-full"
+else
+  CONFIGURE_ARGS+= --without-gettext
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-dom),)
+  CONFIGURE_ARGS+= --enable-dom=shared
+else
+  CONFIGURE_ARGS+= --disable-dom
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-exif),)
+  CONFIGURE_ARGS+= --enable-exif=shared
+else
+  CONFIGURE_ARGS+= --disable-exif
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-ftp),)
+  CONFIGURE_ARGS+= --enable-ftp=shared
+else
+  CONFIGURE_ARGS+= --disable-ftp
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-gd),)
+  CONFIGURE_ARGS+= \
+       --with-gd=shared \
+       --without-freetype-dir \
+       --with-jpeg-dir="$(STAGING_DIR)/usr" \
+       --with-png-dir="$(STAGING_DIR)/usr" \
+       --without-xpm-dir \
+       --without-t1lib \
+       --enable-gd-native-ttf \
+       --disable-gd-jis-conv
+else
+  CONFIGURE_ARGS+= --without-gd
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-gmp),)
+  CONFIGURE_ARGS+= --with-gmp=shared,"$(STAGING_DIR)/usr"
+else
+  CONFIGURE_ARGS+= --without-gmp
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-hash),)
+  CONFIGURE_ARGS+= --enable-hash=shared
+else
+  CONFIGURE_ARGS+= --disable-hash
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-iconv),)
+  CONFIGURE_ARGS+= --with-iconv=shared,"$(ICONV_PREFIX)"
+else
+  CONFIGURE_ARGS+= --without-iconv
+endif
+
+ifneq ($(CONFIG_PACKAGE_php5-mod-json),)
+  CONFIGURE_ARGS+= --enable-json=shared
+else
+  CONFIGURE_ARGS+= --disable-json
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-ldap),)
+  CONFIGURE_ARGS+= \
+       --with-ldap=shared,"$(STAGING_DIR)/usr" \
+       --with-ldap-sasl="$(STAGING_DIR)/usr"
+else
+  CONFIGURE_ARGS+= --without-ldap
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-mbstring),)
+  CONFIGURE_ARGS+= --enable-mbstring=shared --enable-mbregex
+else
+  CONFIGURE_ARGS+= --disable-mbstring
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-mcrypt),)
+  CONFIGURE_ARGS+=  --with-mcrypt=shared,"$(STAGING_DIR)/usr"
+else
+  CONFIGURE_ARGS+= --without-mcrypt
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-mysql),)
+  CONFIGURE_ARGS+= --with-mysql=shared,"$(STAGING_DIR)/usr"
+else
+  CONFIGURE_ARGS+= --without-mysql
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-mysqli),)
+  CONFIGURE_ARGS+= --with-mysqli=shared,"$(STAGING_DIR)/usr/bin/mysql_config"
+else
+  CONFIGURE_ARGS+= --without-mysqli
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-openssl),)
+  CONFIGURE_ARGS+= \
+       --with-openssl=shared,"$(STAGING_DIR)/usr" \
+       --with-kerberos=no \
+       --with-openssl-dir="$(STAGING_DIR)/usr"
+else
+  CONFIGURE_ARGS+= --without-openssl
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-pcntl),)
+  CONFIGURE_ARGS+= --enable-pcntl=shared
+else
+  CONFIGURE_ARGS+= --disable-pcntl
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-pdo),)
+  CONFIGURE_ARGS+= --enable-pdo=shared
+  ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-pdo-mysql),)
+    CONFIGURE_ARGS+= --with-pdo-mysql=shared,"$(STAGING_DIR)/usr"
+  else
+    CONFIGURE_ARGS+= --without-pdo-mysql
+  endif
+  ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-pdo-pgsql),)
+    CONFIGURE_ARGS+= --with-pdo-pgsql=shared,"$(STAGING_DIR)/usr"
+  else
+    CONFIGURE_ARGS+= --without-pdo-pgsql
+  endif
+  ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-pdo-sqlite),)
+    CONFIGURE_ARGS+= --with-pdo-sqlite=shared,"$(STAGING_DIR)/usr"
+  else
+    CONFIGURE_ARGS+= --without-pdo-sqlite
+  endif
+else
+  CONFIGURE_ARGS+= --disable-pdo
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-pgsql),)
+  CONFIGURE_ARGS+= --with-pgsql=shared,"$(STAGING_DIR)/usr"
+else
+  CONFIGURE_ARGS+= --without-pgsql
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-session),)
+  CONFIGURE_ARGS+= --enable-session=shared
+else
+  CONFIGURE_ARGS+= --disable-session
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-shmop),)
+  CONFIGURE_ARGS+= --enable-shmop=shared
+else
+  CONFIGURE_ARGS+= --disable-shmop
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-simplexml),)
+  CONFIGURE_ARGS+= --enable-simplexml=shared
+else
+  CONFIGURE_ARGS+= --disable-simplexml
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-soap),)
+  CONFIGURE_ARGS+= --enable-soap=shared
+else
+  CONFIGURE_ARGS+= --disable-soap
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-sockets),)
+  CONFIGURE_ARGS+= --enable-sockets=shared
+else
+  CONFIGURE_ARGS+= --disable-sockets
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-sqlite),)
+  CONFIGURE_ARGS+= --with-sqlite=shared,"$(STAGING_DIR)/usr"
+else
+  CONFIGURE_ARGS+= --without-sqlite
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-sqlite3),)
+  CONFIGURE_ARGS+= --with-sqlite3=shared,"$(STAGING_DIR)/usr"
+else
+  CONFIGURE_ARGS+= --without-sqlite3
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-sysvmsg),)
+  CONFIGURE_ARGS+= --enable-sysvmsg=shared
+else
+  CONFIGURE_ARGS+= --disable-sysvmsg
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-sysvsem),)
+  CONFIGURE_ARGS+= --enable-sysvsem=shared
+else
+  CONFIGURE_ARGS+= --disable-sysvsem
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-sysvshm),)
+  CONFIGURE_ARGS+= --enable-sysvshm=shared
+else
+  CONFIGURE_ARGS+= --disable-sysvshm
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-tokenizer),)
+  CONFIGURE_ARGS+= --enable-tokenizer=shared
+else
+  CONFIGURE_ARGS+= --disable-tokenizer
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-xml),)
+  CONFIGURE_ARGS+= --enable-xml=shared,"$(STAGING_DIR)/usr"
+  ifneq ($(CONFIG_PHP5_LIBXML),)
+    CONFIGURE_ARGS+= --with-libxml-dir="$(STAGING_DIR)/usr/include/libxml2"
+  else
+    CONFIGURE_ARGS+= --with-libexpat-dir="$(STAGING_DIR)/usr"
+  endif
+else
+  CONFIGURE_ARGS+= --disable-xml
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-xmlreader),)
+  CONFIGURE_ARGS+= --enable-xmlreader=shared,"$(STAGING_DIR)/usr"
+else
+  CONFIGURE_ARGS+= --disable-xmlreader
+endif
+
+ifneq ($(SDK)$(CONFIG_PACKAGE_php5-mod-xmlwriter),)
+  CONFIGURE_ARGS+= --enable-xmlwriter=shared,"$(STAGING_DIR)/usr"
+else
+  CONFIGURE_ARGS+= --disable-xmlwriter
+endif
+
+ifneq ($(CONFIG_PACKAGE_php5-mod-zip),)
+  CONFIGURE_ARGS+= --enable-zip=shared
+else
+  CONFIGURE_ARGS+= --disable-zip
+endif
+
+ifneq ($(SDK)$(CONFIG_PHP5_FILTER),)
+  CONFIGURE_ARGS+= --enable-filter
+else
+  CONFIGURE_ARGS+= --disable-filter
+endif
+
+ifneq ($(SDK)$(CONFIG_PHP5_LIBXML),)
+  CONFIGURE_ARGS+= --enable-libxml
+  CONFIGURE_ARGS+= --with-libxml-dir="$(STAGING_DIR)/usr/include/libxml2"
+else
+  CONFIGURE_ARGS+= --disable-libxml
+endif
+
+ifneq ($(CONFIG_PHP5_SYSTEMTZDATA),)
+  CONFIGURE_ARGS+= --with-system-tzdata
+else
+  CONFIGURE_ARGS+= --without-system-tzdata
+endif
+
+CONFIGURE_VARS+= \
+       ac_cv_c_bigendian_php=$(if $(CONFIG_BIG_ENDIAN),yes,no) \
+       php_cv_cc_rpath="no" \
+       iconv_impl_name="gnu_libiconv" \
+       ac_cv_php_xml2_config_path="$(STAGING_DIR)/host/bin/xml2-config" \
+
+define Package/php5/conffiles
+/etc/php.ini
+endef
+
+define Package/php5/install
+       $(INSTALL_DIR) $(1)/etc
+       $(INSTALL_DATA) ./files/php.ini $(1)/etc/
+endef
+
+define Package/php5-cli/install
+       $(INSTALL_DIR) $(1)/usr/bin
+       $(CP) $(PKG_BUILD_DIR)/sapi/cli/php $(1)/usr/bin/php-cli
+endef
+
+define Package/php5-cgi/install
+       $(INSTALL_DIR) $(1)/usr/bin
+       $(CP) $(PKG_BUILD_DIR)/sapi/cgi/php-cgi $(1)/usr/bin/php-cgi
+       ln -sf php-cgi $(1)/usr/bin/php-fcgi
+endef
+
+define Package/php5-fastcgi/install
+       $(INSTALL_DIR) $(1)/etc/config
+       $(INSTALL_DATA) ./files/php5-fastcgi.config $(1)/etc/config/php5-fastcgi
+
+       $(INSTALL_DIR) $(1)/etc/init.d
+       $(INSTALL_BIN) ./files/php5-fastcgi.init $(1)/etc/init.d/php5-fastcgi
+endef
+
+define Build/Prepare
+       $(call Build/Prepare/Default)
+       ( cd $(PKG_BUILD_DIR); touch configure.in; ./buildconf --force )
+endef
+
+define Build/InstallDev
+       mkdir -p $(PKG_BUILD_DIR)/staging/usr/bin
+       make -C $(PKG_BUILD_DIR) install INSTALL_ROOT=$(PKG_BUILD_DIR)/staging
+       rm -f $(PKG_BUILD_DIR)/staging/usr/bin/php
+       $(CP) $(PKG_BUILD_DIR)/staging/* $(STAGING_DIR_HOST)
+       sed -i -e "s#prefix='/usr'#prefix='$(STAGING_DIR_HOST)/usr'#" $(STAGING_DIR_HOST)/usr/bin/phpize
+       sed -i -e "s#exec_prefix=\"\`eval echo /usr\`\"#exec_prefix='$(STAGING_DIR_HOST)/usr'#" $(STAGING_DIR_HOST)/usr/bin/phpize
+       sed -i -e "s#prefix=\"/usr\"#prefix=\"$(STAGING_DIR_HOST)/usr\"#" $(STAGING_DIR_HOST)/usr/bin/php-config
+endef
+
+define BuildModule
+
+  define Package/php5-mod-$(1)
+    $(call Package/php5/Default)
+
+    ifneq ($(3),)
+      DEPENDS+=$(3)
+    endif
+
+    TITLE:=$(2) shared module
+  endef
+
+  define Package/php5-mod-$(1)/install
+       $(INSTALL_DIR) $$(1)/usr/lib/php
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/modules/$(subst -,_,$(1)).so $$(1)/usr/lib/php/
+       $(INSTALL_DIR) $$(1)/etc/php5
+       echo "extension=$(subst -,_,$(1)).so" > $$(1)/etc/php5/$(subst -,_,$(1)).ini
+  endef
+
+  $$(eval $$(call BuildPackage,php5-mod-$(1)))
+
+endef
+
+$(eval $(call BuildPackage,php5))
+$(eval $(call BuildPackage,php5-cli))
+$(eval $(call BuildPackage,php5-cgi))
+$(eval $(call BuildPackage,php5-fastcgi))
+
+#$(eval $(call BuildModule,NAME,TITLE[,PKG DEPENDS]))
+$(eval $(call BuildModule,calendar,Calendar))
+$(eval $(call BuildModule,ctype,Ctype))
+$(eval $(call BuildModule,curl,cURL,+PACKAGE_php5-mod-curl:libcurl))
+$(eval $(call BuildModule,fileinfo,Fileinfo,+PACKAGE_php5-mod-fileinfo:libmagic))
+$(eval $(call BuildModule,dom,DOM,+@PHP5_LIBXML +PACKAGE_php5-mod-dom:libxml2))
+$(eval $(call BuildModule,exif,EXIF))
+$(eval $(call BuildModule,ftp,FTP,+PACKAGE_php5-mod-ftp:libopenssl))
+$(eval $(call BuildModule,gettext,Gettext,+PACKAGE_php5-mod-gettext:libintl-full))
+$(eval $(call BuildModule,gd,GD graphics,+PACKAGE_php5-mod-gd:libjpeg +PACKAGE_php5-mod-gd:libpng))
+$(eval $(call BuildModule,gmp,GMP,+PACKAGE_php5-mod-gmp:libgmp))
+$(eval $(call BuildModule,hash,Hash))
+$(eval $(call BuildModule,iconv,iConv,+PACKAGE_php5-mod-iconv:libiconv))
+$(eval $(call BuildModule,json,JSON))
+$(eval $(call BuildModule,ldap,LDAP,+PACKAGE_php5-mod-ldap:libopenldap +PACKAGE_php5-mod-ldap:libsasl2))
+$(eval $(call BuildModule,mbstring,MBString))
+$(eval $(call BuildModule,mcrypt,Mcrypt,+PACKAGE_php5-mod-mcrypt:libmcrypt +PACKAGE_php5-mod-mcrypt:libltdl))
+$(eval $(call BuildModule,mysql,MySQL,+PACKAGE_php5-mod-mysql:libmysqlclient))
+$(eval $(call BuildModule,mysqli,MySQL Improved Extension,+PACKAGE_php5-mod-mysqli:libmysqlclient))
+$(eval $(call BuildModule,openssl,OpenSSL,+PACKAGE_php5-mod-openssl:libopenssl))
+$(eval $(call BuildModule,pcntl,PCNTL))
+$(eval $(call BuildModule,pdo,PHP Data Objects))
+$(eval $(call BuildModule,pdo-mysql,PDO driver for MySQL,+php5-mod-pdo +PACKAGE_php5-mod-pdo-mysql:libmysqlclient))
+$(eval $(call BuildModule,pdo-pgsql,PDO driver for PostgreSQL,+php5-mod-pdo +PACKAGE_php5-mod-pdo-pgsql:libpq))
+$(eval $(call BuildModule,pdo-sqlite,PDO driver for SQLite 3.x,+php5-mod-pdo +PACKAGE_php5-mod-pdo-sqlite:libsqlite3 +PACKAGE_php5-mod-pdo-sqlite:libpthread +PACKAGE_php5-mod-pdo-sqlite:librt))
+$(eval $(call BuildModule,pgsql,PostgreSQL,+PACKAGE_php5-mod-pgsql:libpq))
+$(eval $(call BuildModule,session,Session))
+$(eval $(call BuildModule,shmop,Shared Memory))
+$(eval $(call BuildModule,simplexml,SimpleXML,+@PHP5_LIBXML +PACKAGE_php5-mod-simplexml:libxml2))
+$(eval $(call BuildModule,soap,SOAP,+@PHP5_LIBXML +PACKAGE_php5-mod-soap:libxml2))
+$(eval $(call BuildModule,sockets,Sockets))
+$(eval $(call BuildModule,sqlite3,SQLite3,+PACKAGE_php5-mod-sqlite3:libsqlite3 +PACKAGE_php5-mod-sqlite3:libpthread))
+$(eval $(call BuildModule,sysvmsg,System V messages))
+$(eval $(call BuildModule,sysvsem,System V shared memory))
+$(eval $(call BuildModule,sysvshm,System V semaphore))
+$(eval $(call BuildModule,tokenizer,Tokenizer))
+$(eval $(call BuildModule,xml,XML,+PHP5_LIBXML:libxml2 +!PHP5_LIBXML:libexpat))
+$(eval $(call BuildModule,xmlreader,XMLReader,+@PHP5_LIBXML +PACKAGE_php5-mod-xmlreader:libxml2 +PACKAGE_php5-mod-xmlreader:libiconv))
+$(eval $(call BuildModule,xmlwriter,XMLWriter,+@PHP5_LIBXML +PACKAGE_php5-mod-xmlwriter:libxml2 +PACKAGE_php5-mod-xmlwriter:libiconv))
+$(eval $(call BuildModule,zip,ZIP,+PACKAGE_php5-mod-zip:zlib))
diff --git a/lang/php5/files/php.ini b/lang/php5/files/php.ini
new file mode 100644 (file)
index 0000000..6fe2a31
--- /dev/null
@@ -0,0 +1,311 @@
+[PHP]
+
+zend.ze1_compatibility_mode = Off
+
+; Language Options
+
+engine = On
+;short_open_tag = Off
+precision    =  12
+y2k_compliance = On
+output_buffering = Off
+;output_handler =
+zlib.output_compression = Off
+;zlib.output_compression_level = -1
+;zlib.output_handler =
+implicit_flush = Off
+unserialize_callback_func =
+serialize_precision = 100
+
+;open_basedir =
+disable_functions =
+disable_classes =
+
+; Colors for Syntax Highlighting mode.  Anything that's acceptable in
+; <span style="color: ???????"> would work.
+;highlight.string  = #DD0000
+;highlight.comment = #FF9900
+;highlight.keyword = #007700
+;highlight.bg      = #FFFFFF
+;highlight.default = #0000BB
+;highlight.html    = #000000
+
+;ignore_user_abort = On
+;realpath_cache_size = 16k
+;realpath_cache_ttl = 120
+
+; Miscellaneous
+
+expose_php = On
+
+; Resource Limits
+
+max_execution_time = 30        ; Maximum execution time of each script, in seconds.
+max_input_time = 60    ; Maximum amount of time each script may spend parsing request data.
+;max_input_nesting_level = 64
+memory_limit = 8M      ; Maximum amount of memory a script may consume.
+
+; Error handling and logging
+
+; Error Level Constants:
+; E_ALL             - All errors and warnings (includes E_STRICT as of PHP 6.0.0)
+; E_ERROR           - fatal run-time errors
+; E_RECOVERABLE_ERROR  - almost fatal run-time errors
+; E_WARNING         - run-time warnings (non-fatal errors)
+; E_PARSE           - compile-time parse errors
+; E_NOTICE          - run-time notices (these are warnings which often result
+;                     from a bug in your code, but it's possible that it was
+;                     intentional (e.g., using an uninitialized variable and
+;                     relying on the fact it's automatically initialized to an
+;                     empty string)
+; E_STRICT                     - run-time notices, enable to have PHP suggest changes
+;                     to your code which will ensure the best interoperability
+;                     and forward compatibility of your code
+; E_CORE_ERROR      - fatal errors that occur during PHP's initial startup
+; E_CORE_WARNING    - warnings (non-fatal errors) that occur during PHP's
+;                     initial startup
+; E_COMPILE_ERROR   - fatal compile-time errors
+; E_COMPILE_WARNING - compile-time warnings (non-fatal errors)
+; E_USER_ERROR      - user-generated error message
+; E_USER_WARNING    - user-generated warning message
+; E_USER_NOTICE     - user-generated notice message
+; E_DEPRECATED      - warn about code that will not work in future versions
+;                     of PHP
+; E_USER_DEPRECATED - user-generated deprecation warnings
+;
+; Common Values:
+;   E_ALL & ~E_NOTICE  (Show all errors, except for notices and coding standards warnings.)
+;   E_ALL & ~E_NOTICE | E_STRICT  (Show all errors, except for notices)
+;   E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR  (Show only errors)
+;   E_ALL | E_STRICT  (Show all errors, warnings and notices including coding standards.)
+; Default Value: E_ALL & ~E_NOTICE
+error_reporting  =  E_ALL & ~E_NOTICE & ~E_STRICT
+
+display_errors = On
+display_startup_errors = Off
+log_errors = Off
+log_errors_max_len = 1024
+ignore_repeated_errors = Off
+ignore_repeated_source = Off
+report_memleaks = On
+;report_zend_debug = 0
+track_errors = Off
+;html_errors = Off
+;docref_root = "/phpmanual/"
+;docref_ext = .html
+;error_prepend_string = "<font color=#ff0000>"
+;error_append_string = "</font>"
+; Log errors to specified file.
+;error_log = /var/log/php_errors.log
+; Log errors to syslog.
+;error_log = syslog
+
+; Data Handling
+
+;arg_separator.output = "&amp;"
+;arg_separator.input = ";&"
+variables_order = "EGPCS"
+request_order = "GP"
+register_globals = Off
+register_long_arrays = Off
+register_argc_argv = On
+auto_globals_jit = On
+post_max_size = 8M
+;magic_quotes_gpc = Off
+magic_quotes_runtime = Off
+magic_quotes_sybase = Off
+auto_prepend_file =
+auto_append_file =
+default_mimetype = "text/html"
+;default_charset = "iso-8859-1"
+;always_populate_raw_post_data = On
+
+; Paths and Directories
+
+; UNIX: "/path1:/path2"
+;include_path = ".:/php/includes"
+doc_root = "/www"
+user_dir =
+extension_dir = "/usr/lib/php"
+enable_dl = On
+;cgi.force_redirect = 1
+;cgi.nph = 1
+;cgi.redirect_status_env = ;
+cgi.fix_pathinfo=1
+;fastcgi.impersonate = 1;
+;fastcgi.logging = 0
+;cgi.rfc2616_headers = 0
+
+; File Uploads
+
+file_uploads = On
+upload_tmp_dir = "/tmp"
+upload_max_filesize = 2M
+max_file_uploads = 20
+
+; Fopen wrappers
+
+allow_url_fopen = On
+allow_url_include = Off
+;from="john@doe.com"
+;user_agent="PHP"
+default_socket_timeout = 60
+;auto_detect_line_endings = Off
+
+; Dynamic Extensions
+
+;extension=ctype.so
+;extension=curl.so
+;extension=dom.so
+;extension=exif.so
+;extension=ftp.so
+;extension=gd.so
+;extension=gmp.so
+;extension=hash.so
+;extension=iconv.so
+;extension=json.so
+;extension=ldap.so
+;extension=mbstring.so
+;extension=mcrypt.so
+;extension=mysql.so
+;extension=openssl.so
+;extension=pcre.so
+;extension=pdo.so
+;extension=pdo-mysql.so
+;extension=pdo-pgsql.so
+;extension=pdo_sqlite.so
+;extension=pgsql.so
+;extension=session.so
+;extension=soap.so
+;extension=sockets.so
+;extension=sqlite.so
+;extension=sqlite3.so
+;extension=tokenizer.so
+;extension=xml.so
+;extension=xmlreader.so
+;extension=xmlwriter.so
+
+; Module Settings
+
+[APC]
+apc.enabled = 1
+apc.shm_segments = 1   ;The number of shared memory segments to allocate for the compiler cache.
+apc.shm_size = 4M      ;The size of each shared memory segment.
+
+[Date]
+;date.timezone =
+;date.default_latitude = 31.7667
+;date.default_longitude = 35.2333
+;date.sunrise_zenith = 90.583333
+;date.sunset_zenith = 90.583333
+
+[filter]
+;filter.default = unsafe_raw
+;filter.default_flags =
+
+[iconv]
+;iconv.input_encoding = ISO-8859-1
+;iconv.internal_encoding = ISO-8859-1
+;iconv.output_encoding = ISO-8859-1
+
+[sqlite]
+;sqlite.assoc_case = 0
+
+[sqlite3]
+;sqlite3.extension_dir =
+
+[Pdo_mysql]
+pdo_mysql.cache_size = 2000
+pdo_mysql.default_socket=
+
+[MySQL]
+mysql.allow_local_infile = On
+mysql.allow_persistent = On
+mysql.cache_size = 2000
+mysql.max_persistent = -1
+mysql.max_links = -1
+mysql.default_port =
+mysql.default_socket =
+mysql.default_host =
+mysql.default_user =
+mysql.default_password =
+mysql.connect_timeout = 60
+mysql.trace_mode = Off
+
+[PostgresSQL]
+pgsql.allow_persistent = On
+pgsql.auto_reset_persistent = Off
+pgsql.max_persistent = -1
+pgsql.max_links = -1
+pgsql.ignore_notice = 0
+pgsql.log_notice = 0
+
+[Session]
+session.save_handler = files
+session.save_path = "/tmp"
+session.use_cookies = 1
+;session.cookie_secure =
+session.use_only_cookies = 1
+session.name = PHPSESSID
+session.auto_start = 0
+session.cookie_lifetime = 0
+session.cookie_path = /
+session.cookie_domain =
+session.cookie_httponly =
+session.serialize_handler = php
+session.gc_probability = 1
+session.gc_divisor     = 100
+session.gc_maxlifetime = 1440
+session.bug_compat_42 = On
+session.bug_compat_warn = On
+session.referer_check =
+session.entropy_length = 0
+;session.entropy_file = /dev/urandom
+session.entropy_file =
+;session.entropy_length = 16
+session.cache_limiter = nocache
+session.cache_expire = 180
+session.use_trans_sid = 0
+session.hash_function = 0
+session.hash_bits_per_character = 4
+url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=,fieldset="
+
+[mbstring]
+;mbstring.language = Japanese
+;mbstring.internal_encoding = EUC-JP
+;mbstring.http_input = auto
+;mbstring.http_output = SJIS
+;mbstring.encoding_translation = Off
+;mbstring.detect_order = auto
+;mbstring.substitute_character = none;
+;mbstring.func_overload = 0
+;mbstring.strict_detection = Off
+;mbstring.http_output_conv_mimetype=
+;mbstring.script_encoding=
+
+[gd]
+;gd.jpeg_ignore_warning = 0
+
+[exif]
+;exif.encode_unicode = ISO-8859-15
+;exif.decode_unicode_motorola = UCS-2BE
+;exif.decode_unicode_intel    = UCS-2LE
+;exif.encode_jis =
+;exif.decode_jis_motorola = JIS
+;exif.decode_jis_intel    = JIS
+
+[soap]
+soap.wsdl_cache_enabled=1
+soap.wsdl_cache_dir="/tmp"
+soap.wsdl_cache_ttl=86400
+soap.wsdl_cache_limit = 5
+
+[sysvshm]
+;sysvshm.init_mem = 10000
+
+[ldap]
+ldap.max_links = -1
+
+[mcrypt]
+;mcrypt.algorithms_dir=
+;mcrypt.modes_dir=
diff --git a/lang/php5/files/php5-fastcgi.config b/lang/php5/files/php5-fastcgi.config
new file mode 100644 (file)
index 0000000..039d3bb
--- /dev/null
@@ -0,0 +1,3 @@
+config php5-fastcgi
+       option enabled 1
+       option port '1026'
diff --git a/lang/php5/files/php5-fastcgi.init b/lang/php5/files/php5-fastcgi.init
new file mode 100644 (file)
index 0000000..0c452ad
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2010-2011 OpenWrt.org
+
+START=50
+
+SERVICE_DAEMONIZE=1
+SERVICE_WRITE_PID=1
+
+start_instance() {
+       local section="$1"
+       local enabled
+       local port
+
+       config_get_bool enabled "$section" 'enabled' 0
+       config_get port "$section" 'port' 1026
+
+       [ $enabled -gt 0 ] || return 1
+
+       PHP_FCGI_CHILDREN='' \
+       service_start /usr/bin/php-fcgi -b $port
+}
+
+start() {
+       config_load 'php5-fastcgi'
+       config_foreach start_instance 'php5-fastcgi'
+}
+
+stop() {
+       service_stop /usr/bin/php-fcgi
+}
diff --git a/lang/php5/patches/090-restore-sqlite2.patch b/lang/php5/patches/090-restore-sqlite2.patch
new file mode 100644 (file)
index 0000000..27bcec5
--- /dev/null
@@ -0,0 +1,50845 @@
+--- /dev/null
++++ b/ext/sqlite/config.m4
+@@ -0,0 +1,157 @@
++dnl $Id$
++dnl config.m4 for extension sqlite
++dnl vim:et:ts=2:sw=2
++
++PHP_ARG_WITH(sqlite, for sqlite support,
++[  --without-sqlite=DIR    Do not include sqlite support.  DIR is the sqlite base
++                          install directory [BUNDLED]], yes)
++
++PHP_ARG_ENABLE(sqlite-utf8, whether to enable UTF-8 support in sqlite (default: ISO-8859-1),
++[  --enable-sqlite-utf8      SQLite: Enable UTF-8 support for SQLite], no, no)
++
++
++
++dnl
++dnl PHP_PROG_LEMON
++dnl
++dnl Search for lemon binary and check its version
++dnl
++AC_DEFUN([PHP_PROG_LEMON],[
++  # we only support certain lemon versions
++  lemon_version_list="1.0"
++
++  AC_CHECK_PROG(LEMON, lemon, lemon)
++  if test "$LEMON"; then
++    AC_CACHE_CHECK([for lemon version], php_cv_lemon_version, [
++      lemon_version=`$LEMON -x 2>/dev/null | $SED -e 's/^.* //'`
++      php_cv_lemon_version=invalid
++      for lemon_check_version in $lemon_version_list; do
++        if test "$lemon_version" = "$lemon_check_version"; then
++          php_cv_lemon_version="$lemon_check_version (ok)"
++        fi
++      done
++    ])
++  else
++    lemon_version=none
++  fi
++  case $php_cv_lemon_version in
++    ""|invalid[)]
++      lemon_msg="lemon versions supported for regeneration of libsqlite parsers: $lemon_version_list (found: $lemon_version)."
++      AC_MSG_WARN([$lemon_msg])
++      LEMON="exit 0;"
++      ;;
++  esac
++  PHP_SUBST(LEMON)
++])
++
++
++if test "$PHP_SQLITE" != "no"; then
++  if test "$PHP_PDO" != "no"; then
++    PHP_CHECK_PDO_INCLUDES([], [AC_MSG_WARN([Cannot find php_pdo_driver.h.])])
++    if test -n "$pdo_inc_path"; then
++      AC_DEFINE([PHP_SQLITE2_HAVE_PDO], [1], [Have PDO])
++      pdo_inc_path="-I$pdo_inc_path"
++    fi
++  fi  
++
++  if test "$PHP_SQLITE" != "yes"; then
++    SEARCH_PATH="/usr/local /usr"
++    SEARCH_FOR="/include/sqlite.h"
++    if test -r $PHP_SQLITE/; then # path given as parameter
++      SQLITE_DIR=$PHP_SQLITE
++    else # search default path list
++      AC_MSG_CHECKING([for sqlite files in default path])
++      for i in $SEARCH_PATH ; do
++        if test -r $i/$SEARCH_FOR; then
++          SQLITE_DIR=$i
++          AC_MSG_RESULT(found in $i)
++        fi
++      done
++    fi
++  
++    if test -z "$SQLITE_DIR"; then
++      AC_MSG_RESULT([not found])
++      AC_MSG_ERROR([Please reinstall the sqlite distribution from http://www.sqlite.org])
++    fi
++
++    PHP_CHECK_LIBRARY(sqlite, sqlite_open, [
++      PHP_ADD_LIBRARY_WITH_PATH(sqlite, $SQLITE_DIR/$PHP_LIBDIR, SQLITE_SHARED_LIBADD)
++      PHP_ADD_INCLUDE($SQLITE_DIR/include)
++    ],[
++      AC_MSG_ERROR([wrong sqlite lib version or lib not found])
++    ],[
++      -L$SQLITE_DIR/$PHP_LIBDIR -lm
++    ])
++    SQLITE_MODULE_TYPE=external
++    PHP_SQLITE_CFLAGS=$pdo_inc_path
++    sqlite_extra_sources="libsqlite/src/encode.c"
++  else
++    # use bundled library
++    PHP_PROG_LEMON
++    SQLITE_MODULE_TYPE=builtin
++    PHP_SQLITE_CFLAGS="-I@ext_srcdir@/libsqlite/src -I@ext_builddir@/libsqlite/src $pdo_inc_path"
++    sqlite_extra_sources="libsqlite/src/opcodes.c \
++        libsqlite/src/parse.c libsqlite/src/encode.c \
++        libsqlite/src/auth.c libsqlite/src/btree.c libsqlite/src/build.c \
++        libsqlite/src/delete.c libsqlite/src/expr.c libsqlite/src/func.c \
++        libsqlite/src/hash.c libsqlite/src/insert.c libsqlite/src/main.c \
++        libsqlite/src/os.c libsqlite/src/pager.c \
++        libsqlite/src/printf.c libsqlite/src/random.c \
++        libsqlite/src/select.c libsqlite/src/table.c libsqlite/src/tokenize.c \
++        libsqlite/src/update.c libsqlite/src/util.c libsqlite/src/vdbe.c \
++        libsqlite/src/attach.c libsqlite/src/btree_rb.c libsqlite/src/pragma.c \
++        libsqlite/src/vacuum.c libsqlite/src/copy.c \
++        libsqlite/src/vdbeaux.c libsqlite/src/date.c \
++        libsqlite/src/where.c libsqlite/src/trigger.c"
++  fi
++  dnl
++  dnl Common for both bundled/external
++  dnl
++  sqlite_sources="sqlite.c sess_sqlite.c pdo_sqlite2.c $sqlite_extra_sources" 
++  PHP_NEW_EXTENSION(sqlite, $sqlite_sources, $ext_shared,,$PHP_SQLITE_CFLAGS)
++  PHP_ADD_EXTENSION_DEP(sqlite, spl, true)
++  PHP_ADD_EXTENSION_DEP(sqlite, pdo, true)
++
++  PHP_ADD_MAKEFILE_FRAGMENT
++  PHP_SUBST(SQLITE_SHARED_LIBADD)
++  PHP_INSTALL_HEADERS([$ext_builddir/libsqlite/src/sqlite.h])
++  
++  if test "$SQLITE_MODULE_TYPE" = "builtin"; then
++    PHP_ADD_BUILD_DIR($ext_builddir/libsqlite/src, 1)
++    AC_CHECK_SIZEOF(char *, 4)
++    AC_DEFINE(SQLITE_PTR_SZ, SIZEOF_CHAR_P, [Size of a pointer])
++    dnl use latin 1 for SQLite older than 2.8.9; the utf-8 handling 
++    dnl in funcs.c uses assert(), which is a bit silly and something 
++    dnl we want to avoid. This assert() was removed in SQLite 2.8.9.
++    if test "$PHP_SQLITE_UTF8" = "yes"; then
++      SQLITE_ENCODING="UTF8"
++      AC_DEFINE(SQLITE_UTF8, 1, [ ])
++    else
++      SQLITE_ENCODING="ISO8859"
++    fi
++    PHP_SUBST(SQLITE_ENCODING)
++
++    SQLITE_VERSION=`cat $ext_srcdir/libsqlite/VERSION`
++    PHP_SUBST(SQLITE_VERSION)
++
++    sed -e s/--VERS--/$SQLITE_VERSION/ -e s/--ENCODING--/$SQLITE_ENCODING/ $ext_srcdir/libsqlite/src/sqlite.h.in > $ext_builddir/libsqlite/src/sqlite.h
++
++    if test "$ext_shared" = "no" || test "$ext_srcdir" != "$abs_srcdir"; then
++      echo '#include <php_config.h>' > $ext_builddir/libsqlite/src/config.h
++    else
++      echo "#include \"$abs_builddir/config.h\"" > $ext_builddir/libsqlite/src/config.h
++    fi
++    
++    cat >> $ext_builddir/libsqlite/src/config.h <<EOF
++#if ZTS
++# define THREADSAFE 1
++#endif
++#if !ZEND_DEBUG
++# define NDEBUG
++#endif
++EOF
++  fi
++  
++  AC_CHECK_FUNCS(usleep nanosleep)
++  AC_CHECK_HEADERS(time.h)
++fi
+--- /dev/null
++++ b/ext/sqlite/config.w32
+@@ -0,0 +1,39 @@
++// $Id$
++// vim:ft=javascript
++
++ARG_WITH("sqlite", "SQLite support", "no");
++
++if (PHP_SQLITE != "no") {
++      copy_and_subst(configure_module_dirname + "\\libsqlite\\src\\sqlite.h.in",
++              configure_module_dirname + "\\libsqlite\\src\\sqlite.h", new Array(
++                      "--VERS--", file_get_contents(configure_module_dirname + "\\libsqlite\\VERSION").replace(new RegExp("[\r\n]+", "g"), ""),
++                      "--ENCODING--", "ISO8859"
++              ));
++      
++      FSO.CopyFile(configure_module_dirname + "\\libsqlite\\src\\sqlite_config.w32.h",
++              configure_module_dirname + "\\libsqlite\\src\\config.h");
++
++      if (FSO.FileExists(configure_module_dirname + "\\..\\pdo\\php_pdo_driver.h")) {
++              PHP_SQLITE2_PDO_CFLAGS = " /DPHP_SQLITE2_HAVE_PDO=1 /I " + configure_module_dirname + "\\..";
++              ADD_EXTENSION_DEP('sqlite', 'pdo')
++      } else {
++              PHP_SQLITE2_PDO_CFLAGS = "";
++      }
++      
++      EXTENSION("sqlite", "sqlite.c sess_sqlite.c pdo_sqlite2.c", null,
++              "/D PHP_SQLITE_EXPORTS /I " + configure_module_dirname + "/libsqlite/src" +
++              PHP_SQLITE2_PDO_CFLAGS);
++              
++      
++      ADD_SOURCES(configure_module_dirname + "/libsqlite/src", "opcodes.c parse.c encode.c \
++              auth.c btree.c build.c delete.c expr.c func.c hash.c insert.c \
++              main.c os.c pager.c printf.c random.c select.c table.c tokenize.c \
++              update.c util.c vdbe.c attach.c btree_rb.c pragma.c vacuum.c \
++              copy.c where.c trigger.c vdbeaux.c date.c", "sqlite");
++
++      AC_DEFINE("HAVE_SQLITE", 1, "SQLite support");
++      if (!PHP_SQLITE_SHARED) {
++              ADD_DEF_FILE(configure_module_dirname + "\\php_sqlite.def");
++      }
++      ADD_EXTENSION_DEP('sqlite', 'spl')
++}
+--- /dev/null
++++ b/ext/sqlite/CREDITS
+@@ -0,0 +1,2 @@
++SQLite
++Wez Furlong, Tal Peer, Marcus Boerger, Ilia Alshanetsky
+--- /dev/null
++++ b/ext/sqlite/libsqlite/README
+@@ -0,0 +1,37 @@
++This directory contains source code to 
++
++    SQLite: An Embeddable SQL Database Engine
++
++To compile the project, first create a directory in which to place
++the build products.  It is recommended, but not required, that the
++build directory be separate from the source directory.  Cd into the
++build directory and then from the build directory run the configure
++script found at the root of the source tree.  Then run "make".
++
++For example:
++
++    tar xzf sqlite.tar.gz    ;#  Unpack the source tree into "sqlite"
++    mkdir bld                ;#  Build will occur in a sibling directory
++    cd bld                   ;#  Change to the build directory
++    ../sqlite/configure      ;#  Run the configure script
++    make                     ;#  Run the makefile.
++
++The configure script uses autoconf 2.50 and libtool.  If the configure
++script does not work out for you, there is a generic makefile named
++"Makefile.linux-gcc" in the top directory of the source tree that you
++can copy and edit to suite your needs.  Comments on the generic makefile
++show what changes are needed.
++
++The linux binaries on the website are created using the generic makefile,
++not the configure script.  The configure script is unmaintained.  (You
++can volunteer to take over maintenance of the configure script, if you want!)
++The windows binaries on the website are created using MinGW32 configured
++as a cross-compiler running under Linux.  For details, see the ./publish.sh
++script at the top-level of the source tree.
++
++Contacts:
++
++   http://www.sqlite.org/
++   http://www.hwaci.com/sw/sqlite/
++   http://groups.yahoo.com/group/sqlite/
++   drh@hwaci.com
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/attach.c
+@@ -0,0 +1,311 @@
++/*
++** 2003 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.
++**
++*************************************************************************
++** This file contains code used to implement the ATTACH and DETACH commands.
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++
++/*
++** This routine is called by the parser to process an ATTACH statement:
++**
++**     ATTACH DATABASE filename AS dbname
++**
++** The pFilename and pDbname arguments are the tokens that define the
++** filename and dbname in the ATTACH statement.
++*/
++void sqliteAttach(Parse *pParse, Token *pFilename, Token *pDbname, Token *pKey){
++  Db *aNew;
++  int rc, i;
++  char *zFile, *zName;
++  sqlite *db;
++  Vdbe *v;
++
++  v = sqliteGetVdbe(pParse);
++  sqliteVdbeAddOp(v, OP_Halt, 0, 0);
++  if( pParse->explain ) return;
++  db = pParse->db;
++  if( db->file_format<4 ){
++    sqliteErrorMsg(pParse, "cannot attach auxiliary databases to an "
++       "older format master database", 0);
++    pParse->rc = SQLITE_ERROR;
++    return;
++  }
++  if( db->nDb>=MAX_ATTACHED+2 ){
++    sqliteErrorMsg(pParse, "too many attached databases - max %d", 
++       MAX_ATTACHED);
++    pParse->rc = SQLITE_ERROR;
++    return;
++  }
++
++  zFile = 0;
++  sqliteSetNString(&zFile, pFilename->z, pFilename->n, 0);
++  if( zFile==0 ) return;
++  sqliteDequote(zFile);
++#ifndef SQLITE_OMIT_AUTHORIZATION
++  if( sqliteAuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){
++    sqliteFree(zFile);
++    return;
++  }
++#endif /* SQLITE_OMIT_AUTHORIZATION */
++
++  zName = 0;
++  sqliteSetNString(&zName, pDbname->z, pDbname->n, 0);
++  if( zName==0 ) return;
++  sqliteDequote(zName);
++  for(i=0; i<db->nDb; i++){
++    if( db->aDb[i].zName && sqliteStrICmp(db->aDb[i].zName, zName)==0 ){
++      sqliteErrorMsg(pParse, "database %z is already in use", zName);
++      pParse->rc = SQLITE_ERROR;
++      sqliteFree(zFile);
++      return;
++    }
++  }
++
++  if( db->aDb==db->aDbStatic ){
++    aNew = sqliteMalloc( sizeof(db->aDb[0])*3 );
++    if( aNew==0 ) return;
++    memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
++  }else{
++    aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
++    if( aNew==0 ) return;
++  }
++  db->aDb = aNew;
++  aNew = &db->aDb[db->nDb++];
++  memset(aNew, 0, sizeof(*aNew));
++  sqliteHashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0);
++  sqliteHashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0);
++  sqliteHashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0);
++  sqliteHashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1);
++  aNew->zName = zName;
++  rc = sqliteBtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt);
++  if( rc ){
++    sqliteErrorMsg(pParse, "unable to open database: %s", zFile);
++  }
++#if SQLITE_HAS_CODEC
++  {
++    extern int sqliteCodecAttach(sqlite*, int, void*, int);
++    char *zKey = 0;
++    int nKey;
++    if( pKey && pKey->z && pKey->n ){
++      sqliteSetNString(&zKey, pKey->z, pKey->n, 0);
++      sqliteDequote(zKey);
++      nKey = strlen(zKey);
++    }else{
++      zKey = 0;
++      nKey = 0;
++    }
++    sqliteCodecAttach(db, db->nDb-1, zKey, nKey);
++  }
++#endif
++  sqliteFree(zFile);
++  db->flags &= ~SQLITE_Initialized;
++  if( pParse->nErr ) return;
++  if( rc==SQLITE_OK ){
++    rc = sqliteInit(pParse->db, &pParse->zErrMsg);
++  }
++  if( rc ){
++    int i = db->nDb - 1;
++    assert( i>=2 );
++    if( db->aDb[i].pBt ){
++      sqliteBtreeClose(db->aDb[i].pBt);
++      db->aDb[i].pBt = 0;
++    }
++    sqliteResetInternalSchema(db, 0);
++    pParse->nErr++;
++    pParse->rc = SQLITE_ERROR;
++  }
++}
++
++/*
++** This routine is called by the parser to process a DETACH statement:
++**
++**    DETACH DATABASE dbname
++**
++** The pDbname argument is the name of the database in the DETACH statement.
++*/
++void sqliteDetach(Parse *pParse, Token *pDbname){
++  int i;
++  sqlite *db;
++  Vdbe *v;
++  Db *pDb;
++
++  v = sqliteGetVdbe(pParse);
++  sqliteVdbeAddOp(v, OP_Halt, 0, 0);
++  if( pParse->explain ) return;
++  db = pParse->db;
++  for(i=0; i<db->nDb; i++){
++    pDb = &db->aDb[i];
++    if( pDb->pBt==0 || pDb->zName==0 ) continue;
++    if( strlen(pDb->zName)!=pDbname->n ) continue;
++    if( sqliteStrNICmp(pDb->zName, pDbname->z, pDbname->n)==0 ) break;
++  }
++  if( i>=db->nDb ){
++    sqliteErrorMsg(pParse, "no such database: %T", pDbname);
++    return;
++  }
++  if( i<2 ){
++    sqliteErrorMsg(pParse, "cannot detach database %T", pDbname);
++    return;
++  }
++#ifndef SQLITE_OMIT_AUTHORIZATION
++  if( sqliteAuthCheck(pParse,SQLITE_DETACH,db->aDb[i].zName,0,0)!=SQLITE_OK ){
++    return;
++  }
++#endif /* SQLITE_OMIT_AUTHORIZATION */
++  sqliteBtreeClose(pDb->pBt);
++  pDb->pBt = 0;
++  sqliteFree(pDb->zName);
++  sqliteResetInternalSchema(db, i);
++  if( pDb->pAux && pDb->xFreeAux ) pDb->xFreeAux(pDb->pAux);
++  db->nDb--;
++  if( i<db->nDb ){
++    db->aDb[i] = db->aDb[db->nDb];
++    memset(&db->aDb[db->nDb], 0, sizeof(db->aDb[0]));
++    sqliteResetInternalSchema(db, i);
++  }
++}
++
++/*
++** Initialize a DbFixer structure.  This routine must be called prior
++** to passing the structure to one of the sqliteFixAAAA() routines below.
++**
++** The return value indicates whether or not fixation is required.  TRUE
++** means we do need to fix the database references, FALSE means we do not.
++*/
++int sqliteFixInit(
++  DbFixer *pFix,      /* The fixer to be initialized */
++  Parse *pParse,      /* Error messages will be written here */
++  int iDb,            /* This is the database that must must be used */
++  const char *zType,  /* "view", "trigger", or "index" */
++  const Token *pName  /* Name of the view, trigger, or index */
++){
++  sqlite *db;
++
++  if( iDb<0 || iDb==1 ) return 0;
++  db = pParse->db;
++  assert( db->nDb>iDb );
++  pFix->pParse = pParse;
++  pFix->zDb = db->aDb[iDb].zName;
++  pFix->zType = zType;
++  pFix->pName = pName;
++  return 1;
++}
++
++/*
++** The following set of routines walk through the parse tree and assign
++** a specific database to all table references where the database name
++** was left unspecified in the original SQL statement.  The pFix structure
++** must have been initialized by a prior call to sqliteFixInit().
++**
++** These routines are used to make sure that an index, trigger, or
++** view in one database does not refer to objects in a different database.
++** (Exception: indices, triggers, and views in the TEMP database are
++** allowed to refer to anything.)  If a reference is explicitly made
++** to an object in a different database, an error message is added to
++** pParse->zErrMsg and these routines return non-zero.  If everything
++** checks out, these routines return 0.
++*/
++int sqliteFixSrcList(
++  DbFixer *pFix,       /* Context of the fixation */
++  SrcList *pList       /* The Source list to check and modify */
++){
++  int i;
++  const char *zDb;
++
++  if( pList==0 ) return 0;
++  zDb = pFix->zDb;
++  for(i=0; i<pList->nSrc; i++){
++    if( pList->a[i].zDatabase==0 ){
++      pList->a[i].zDatabase = sqliteStrDup(zDb);
++    }else if( sqliteStrICmp(pList->a[i].zDatabase,zDb)!=0 ){
++      sqliteErrorMsg(pFix->pParse,
++         "%s %z cannot reference objects in database %s",
++         pFix->zType, sqliteStrNDup(pFix->pName->z, pFix->pName->n),
++         pList->a[i].zDatabase);
++      return 1;
++    }
++    if( sqliteFixSelect(pFix, pList->a[i].pSelect) ) return 1;
++    if( sqliteFixExpr(pFix, pList->a[i].pOn) ) return 1;
++  }
++  return 0;
++}
++int sqliteFixSelect(
++  DbFixer *pFix,       /* Context of the fixation */
++  Select *pSelect      /* The SELECT statement to be fixed to one database */
++){
++  while( pSelect ){
++    if( sqliteFixExprList(pFix, pSelect->pEList) ){
++      return 1;
++    }
++    if( sqliteFixSrcList(pFix, pSelect->pSrc) ){
++      return 1;
++    }
++    if( sqliteFixExpr(pFix, pSelect->pWhere) ){
++      return 1;
++    }
++    if( sqliteFixExpr(pFix, pSelect->pHaving) ){
++      return 1;
++    }
++    pSelect = pSelect->pPrior;
++  }
++  return 0;
++}
++int sqliteFixExpr(
++  DbFixer *pFix,     /* Context of the fixation */
++  Expr *pExpr        /* The expression to be fixed to one database */
++){
++  while( pExpr ){
++    if( sqliteFixSelect(pFix, pExpr->pSelect) ){
++      return 1;
++    }
++    if( sqliteFixExprList(pFix, pExpr->pList) ){
++      return 1;
++    }
++    if( sqliteFixExpr(pFix, pExpr->pRight) ){
++      return 1;
++    }
++    pExpr = pExpr->pLeft;
++  }
++  return 0;
++}
++int sqliteFixExprList(
++  DbFixer *pFix,     /* Context of the fixation */
++  ExprList *pList    /* The expression to be fixed to one database */
++){
++  int i;
++  if( pList==0 ) return 0;
++  for(i=0; i<pList->nExpr; i++){
++    if( sqliteFixExpr(pFix, pList->a[i].pExpr) ){
++      return 1;
++    }
++  }
++  return 0;
++}
++int sqliteFixTriggerStep(
++  DbFixer *pFix,     /* Context of the fixation */
++  TriggerStep *pStep /* The trigger step be fixed to one database */
++){
++  while( pStep ){
++    if( sqliteFixSelect(pFix, pStep->pSelect) ){
++      return 1;
++    }
++    if( sqliteFixExpr(pFix, pStep->pWhere) ){
++      return 1;
++    }
++    if( sqliteFixExprList(pFix, pStep->pExprList) ){
++      return 1;
++    }
++    pStep = pStep->pNext;
++  }
++  return 0;
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/auth.c
+@@ -0,0 +1,219 @@
++/*
++** 2003 January 11
++**
++** 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 the sqlite_set_authorizer()
++** API.  This facility is an optional feature of the library.  Embedded
++** systems that do not need this facility may omit it by recompiling
++** the library with -DSQLITE_OMIT_AUTHORIZATION=1
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++
++/*
++** All of the code in this file may be omitted by defining a single
++** macro.
++*/
++#ifndef SQLITE_OMIT_AUTHORIZATION
++
++/*
++** Set or clear the access authorization function.
++**
++** The access authorization function is be called during the compilation
++** phase to verify that the user has read and/or write access permission on
++** various fields of the database.  The first argument to the auth function
++** is a copy of the 3rd argument to this routine.  The second argument
++** to the auth function is one of these constants:
++**
++**       SQLITE_COPY
++**       SQLITE_CREATE_INDEX
++**       SQLITE_CREATE_TABLE
++**       SQLITE_CREATE_TEMP_INDEX
++**       SQLITE_CREATE_TEMP_TABLE
++**       SQLITE_CREATE_TEMP_TRIGGER
++**       SQLITE_CREATE_TEMP_VIEW
++**       SQLITE_CREATE_TRIGGER
++**       SQLITE_CREATE_VIEW
++**       SQLITE_DELETE
++**       SQLITE_DROP_INDEX
++**       SQLITE_DROP_TABLE
++**       SQLITE_DROP_TEMP_INDEX
++**       SQLITE_DROP_TEMP_TABLE
++**       SQLITE_DROP_TEMP_TRIGGER
++**       SQLITE_DROP_TEMP_VIEW
++**       SQLITE_DROP_TRIGGER
++**       SQLITE_DROP_VIEW
++**       SQLITE_INSERT
++**       SQLITE_PRAGMA
++**       SQLITE_READ
++**       SQLITE_SELECT
++**       SQLITE_TRANSACTION
++**       SQLITE_UPDATE
++**
++** The third and fourth arguments to the auth function are the name of
++** the table and the column that are being accessed.  The auth function
++** should return either SQLITE_OK, SQLITE_DENY, or SQLITE_IGNORE.  If
++** SQLITE_OK is returned, it means that access is allowed.  SQLITE_DENY
++** means that the SQL statement will never-run - the sqlite_exec() call
++** will return with an error.  SQLITE_IGNORE means that the SQL statement
++** should run but attempts to read the specified column will return NULL
++** and attempts to write the column will be ignored.
++**
++** Setting the auth function to NULL disables this hook.  The default
++** setting of the auth function is NULL.
++*/
++int sqlite_set_authorizer(
++  sqlite *db,
++  int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
++  void *pArg
++){
++  db->xAuth = xAuth;
++  db->pAuthArg = pArg;
++  return SQLITE_OK;
++}
++
++/*
++** Write an error message into pParse->zErrMsg that explains that the
++** user-supplied authorization function returned an illegal value.
++*/
++static void sqliteAuthBadReturnCode(Parse *pParse, int rc){
++  sqliteErrorMsg(pParse, "illegal return value (%d) from the "
++    "authorization function - should be SQLITE_OK, SQLITE_IGNORE, "
++    "or SQLITE_DENY", rc);
++  pParse->rc = SQLITE_MISUSE;
++}
++
++/*
++** The pExpr should be a TK_COLUMN expression.  The table referred to
++** is in pTabList or else it is the NEW or OLD table of a trigger.  
++** Check to see if it is OK to read this particular column.
++**
++** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN 
++** instruction into a TK_NULL.  If the auth function returns SQLITE_DENY,
++** then generate an error.
++*/
++void sqliteAuthRead(
++  Parse *pParse,        /* The parser context */
++  Expr *pExpr,          /* The expression to check authorization on */
++  SrcList *pTabList     /* All table that pExpr might refer to */
++){
++  sqlite *db = pParse->db;
++  int rc;
++  Table *pTab;          /* 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 */
++  TriggerStack *pStack; /* The stack of current triggers */
++
++  if( db->xAuth==0 ) return;
++  assert( pExpr->op==TK_COLUMN );
++  for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
++    if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break;
++  }
++  if( iSrc>=0 && iSrc<pTabList->nSrc ){
++    pTab = pTabList->a[iSrc].pTab;
++  }else if( (pStack = pParse->trigStack)!=0 ){
++    /* This must be an attempt to read the NEW or OLD pseudo-tables
++    ** of a trigger.
++    */
++    assert( pExpr->iTable==pStack->newIdx || pExpr->iTable==pStack->oldIdx );
++    pTab = pStack->pTab;
++  }else{
++    return;
++  }
++  if( pTab==0 ) return;
++  if( pExpr->iColumn>=0 ){
++    assert( pExpr->iColumn<pTab->nCol );
++    zCol = pTab->aCol[pExpr->iColumn].zName;
++  }else if( pTab->iPKey>=0 ){
++    assert( pTab->iPKey<pTab->nCol );
++    zCol = pTab->aCol[pTab->iPKey].zName;
++  }else{
++    zCol = "ROWID";
++  }
++  assert( pExpr->iDb<db->nDb );
++  zDBase = db->aDb[pExpr->iDb].zName;
++  rc = db->xAuth(db->pAuthArg, SQLITE_READ, pTab->zName, zCol, zDBase, 
++                 pParse->zAuthContext);
++  if( rc==SQLITE_IGNORE ){
++    pExpr->op = TK_NULL;
++  }else if( rc==SQLITE_DENY ){
++    if( db->nDb>2 || pExpr->iDb!=0 ){
++      sqliteErrorMsg(pParse, "access to %s.%s.%s is prohibited", 
++         zDBase, pTab->zName, zCol);
++    }else{
++      sqliteErrorMsg(pParse, "access to %s.%s is prohibited", pTab->zName,zCol);
++    }
++    pParse->rc = SQLITE_AUTH;
++  }else if( rc!=SQLITE_OK ){
++    sqliteAuthBadReturnCode(pParse, rc);
++  }
++}
++
++/*
++** Do an authorization check using the code and arguments given.  Return
++** either SQLITE_OK (zero) or SQLITE_IGNORE or SQLITE_DENY.  If SQLITE_DENY
++** is returned, then the error count and error message in pParse are
++** modified appropriately.
++*/
++int sqliteAuthCheck(
++  Parse *pParse,
++  int code,
++  const char *zArg1,
++  const char *zArg2,
++  const char *zArg3
++){
++  sqlite *db = pParse->db;
++  int rc;
++
++  if( db->init.busy || db->xAuth==0 ){
++    return SQLITE_OK;
++  }
++  rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext);
++  if( rc==SQLITE_DENY ){
++    sqliteErrorMsg(pParse, "not authorized");
++    pParse->rc = SQLITE_AUTH;
++  }else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){
++    rc = SQLITE_DENY;
++    sqliteAuthBadReturnCode(pParse, rc);
++  }
++  return rc;
++}
++
++/*
++** Push an authorization context.  After this routine is called, the
++** zArg3 argument to authorization callbacks will be zContext until
++** popped.  Or if pParse==0, this routine is a no-op.
++*/
++void sqliteAuthContextPush(
++  Parse *pParse,
++  AuthContext *pContext, 
++  const char *zContext
++){
++  pContext->pParse = pParse;
++  if( pParse ){
++    pContext->zAuthContext = pParse->zAuthContext;
++    pParse->zAuthContext = zContext;
++  }
++}
++
++/*
++** Pop an authorization context that was previously pushed
++** by sqliteAuthContextPush
++*/
++void sqliteAuthContextPop(AuthContext *pContext){
++  if( pContext->pParse ){
++    pContext->pParse->zAuthContext = pContext->zAuthContext;
++    pContext->pParse = 0;
++  }
++}
++
++#endif /* SQLITE_OMIT_AUTHORIZATION */
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/btree.c
+@@ -0,0 +1,3584 @@
++/*
++** 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.
++**
++*************************************************************************
++** $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".  Up to
++** MX_LOCAL_PAYLOAD bytes of payload can be carried directly on the
++** database page.  If the payload is larger than MX_LOCAL_PAYLOAD bytes
++** 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.
++**
++** The first page of the file contains a magic string used to verify that
++** the file really is a valid BTree database, a pointer to a list of unused
++** pages in the file, and some meta information.  The root of the first
++** BTree begins on page 2 of the file.  (Pages are numbered beginning with
++** 1, not 0.)  Thus a minimum database contains 2 pages.
++*/
++#include "sqliteInt.h"
++#include "pager.h"
++#include "btree.h"
++#include <assert.h>
++
++/* Forward declarations */
++static BtOps sqliteBtreeOps;
++static BtCursorOps sqliteBtreeCursorOps;
++
++/*
++** Macros used for byteswapping.  B is a pointer to the Btree
++** structure.  This is needed to access the Btree.needSwab boolean
++** in order to tell if byte swapping is needed or not.
++** X is an unsigned integer.  SWAB16 byte swaps a 16-bit integer.
++** SWAB32 byteswaps a 32-bit integer.
++*/
++#define SWAB16(B,X)   ((B)->needSwab? swab16((u16)X) : ((u16)X))
++#define SWAB32(B,X)   ((B)->needSwab? swab32(X) : (X))
++#define SWAB_ADD(B,X,A) \
++   if((B)->needSwab){ X=swab32(swab32(X)+A); }else{ X += (A); }
++
++/*
++** The following global variable - available only if SQLITE_TEST is
++** defined - is used to determine whether new databases are created in
++** native byte order or in non-native byte order.  Non-native byte order
++** databases are created for testing purposes only.  Under normal operation,
++** only native byte-order databases should be created, but we should be
++** able to read or write existing databases regardless of the byteorder.
++*/
++#ifdef SQLITE_TEST
++int btree_native_byte_order = 1;
++#else
++# define btree_native_byte_order 1
++#endif
++
++/*
++** Forward declarations of structures used only in this file.
++*/
++typedef struct PageOne PageOne;
++typedef struct MemPage MemPage;
++typedef struct PageHdr PageHdr;
++typedef struct Cell Cell;
++typedef struct CellHdr CellHdr;
++typedef struct FreeBlk FreeBlk;
++typedef struct OverflowPage OverflowPage;
++typedef struct FreelistInfo FreelistInfo;
++
++/*
++** All structures on a database page are aligned to 4-byte boundries.
++** This routine rounds up a number of bytes to the next multiple of 4.
++**
++** This might need to change for computer architectures that require
++** and 8-byte alignment boundry for structures.
++*/
++#define ROUNDUP(X)  ((X+3) & ~3)
++
++/*
++** This is a magic string that appears at the beginning of every
++** SQLite database in order to identify the file as a real database.
++*/
++static const char zMagicHeader[] = 
++   "** This file contains an SQLite 2.1 database **";
++#define MAGIC_SIZE (sizeof(zMagicHeader))
++
++/*
++** This is a magic integer also used to test the integrity of the database
++** file.  This integer is used in addition to the string above so that
++** if the file is written on a little-endian architecture and read
++** on a big-endian architectures (or vice versa) we can detect the
++** problem.
++**
++** The number used was obtained at random and has no special
++** significance other than the fact that it represents a different
++** integer on little-endian and big-endian machines.
++*/
++#define MAGIC 0xdae37528
++
++/*
++** The first page of the database file contains a magic header string
++** to identify the file as an SQLite database file.  It also contains
++** a pointer to the first free page of the file.  Page 2 contains the
++** root of the principle BTree.  The file might contain other BTrees
++** rooted on pages above 2.
++**
++** The first page also contains SQLITE_N_BTREE_META integers that
++** can be used by higher-level routines.
++**
++** Remember that pages are numbered beginning with 1.  (See pager.c
++** for additional information.)  Page 0 does not exist and a page
++** number of 0 is used to mean "no such page".
++*/
++struct PageOne {
++  char zMagic[MAGIC_SIZE]; /* String that identifies the file as a database */
++  int iMagic;              /* Integer to verify correct byte order */
++  Pgno freeList;           /* First free page in a list of all free pages */
++  int nFree;               /* Number of pages on the free list */
++  int aMeta[SQLITE_N_BTREE_META-1];  /* User defined integers */
++};
++
++/*
++** Each database page has a header that is an instance of this
++** structure.
++**
++** PageHdr.firstFree is 0 if there is no free space on this page.
++** Otherwise, PageHdr.firstFree is the index in MemPage.u.aDisk[] of a 
++** FreeBlk structure that describes the first block of free space.  
++** All free space is defined by a linked list of FreeBlk structures.
++**
++** Data is stored in a linked list of Cell structures.  PageHdr.firstCell
++** is the index into MemPage.u.aDisk[] of the first cell on the page.  The
++** Cells are kept in sorted order.
++**
++** A Cell contains all information about a database entry and a pointer
++** to a child page that contains other entries less than itself.  In
++** other words, the i-th Cell contains both Ptr(i) and Key(i).  The
++** right-most pointer of the page is contained in PageHdr.rightChild.
++*/
++struct PageHdr {
++  Pgno rightChild;  /* Child page that comes after all cells on this page */
++  u16 firstCell;    /* Index in MemPage.u.aDisk[] of the first cell */
++  u16 firstFree;    /* Index in MemPage.u.aDisk[] of the first free block */
++};
++
++/*
++** Entries on a page of the database are called "Cells".  Each Cell
++** has a header and data.  This structure defines the header.  The
++** key and data (collectively the "payload") follow this header on
++** the database page.
++**
++** A definition of the complete Cell structure is given below.  The
++** header for the cell must be defined first in order to do some
++** of the sizing #defines that follow.
++*/
++struct CellHdr {
++  Pgno leftChild; /* Child page that comes before this cell */
++  u16 nKey;       /* Number of bytes in the key */
++  u16 iNext;      /* Index in MemPage.u.aDisk[] of next cell in sorted order */
++  u8 nKeyHi;      /* Upper 8 bits of key size for keys larger than 64K bytes */
++  u8 nDataHi;     /* Upper 8 bits of data size when the size is more than 64K */
++  u16 nData;      /* Number of bytes of data */
++};
++
++/*
++** The key and data size are split into a lower 16-bit segment and an
++** upper 8-bit segment in order to pack them together into a smaller
++** space.  The following macros reassembly a key or data size back
++** into an integer.
++*/
++#define NKEY(b,h)  (SWAB16(b,h.nKey) + h.nKeyHi*65536)
++#define NDATA(b,h) (SWAB16(b,h.nData) + h.nDataHi*65536)
++
++/*
++** The minimum size of a complete Cell.  The Cell must contain a header
++** and at least 4 bytes of payload.
++*/
++#define MIN_CELL_SIZE  (sizeof(CellHdr)+4)
++
++/*
++** The maximum number of database entries that can be held in a single
++** page of the database. 
++*/
++#define MX_CELL ((SQLITE_USABLE_SIZE-sizeof(PageHdr))/MIN_CELL_SIZE)
++
++/*
++** The amount of usable space on a single page of the BTree.  This is the
++** page size minus the overhead of the page header.
++*/
++#define USABLE_SPACE  (SQLITE_USABLE_SIZE - sizeof(PageHdr))
++
++/*
++** The maximum amount of payload (in bytes) that can be stored locally for
++** a database entry.  If the entry contains more data than this, the
++** extra goes onto overflow pages.
++**
++** This number is chosen so that at least 4 cells will fit on every page.
++*/
++#define MX_LOCAL_PAYLOAD ((USABLE_SPACE/4-(sizeof(CellHdr)+sizeof(Pgno)))&~3)
++
++/*
++** Data on a database page is stored as a linked list of Cell structures.
++** Both the key and the data are stored in aPayload[].  The key always comes
++** first.  The aPayload[] field grows as necessary to hold the key and data,
++** up to a maximum of MX_LOCAL_PAYLOAD bytes.  If the size of the key and
++** data combined exceeds MX_LOCAL_PAYLOAD bytes, then Cell.ovfl is the
++** page number of the first overflow page.
++**
++** Though this structure is fixed in size, the Cell on the database
++** page varies in size.  Every cell has a CellHdr and at least 4 bytes
++** of payload space.  Additional payload bytes (up to the maximum of
++** MX_LOCAL_PAYLOAD) and the Cell.ovfl value are allocated only as
++** needed.
++*/
++struct Cell {
++  CellHdr h;                        /* The cell header */
++  char aPayload[MX_LOCAL_PAYLOAD];  /* Key and data */
++  Pgno ovfl;                        /* The first overflow page */
++};
++
++/*
++** Free space on a page is remembered using a linked list of the FreeBlk
++** structures.  Space on a database page is allocated in increments of
++** at least 4 bytes and is always aligned to a 4-byte boundry.  The
++** linked list of FreeBlks is always kept in order by address.
++*/
++struct FreeBlk {
++  u16 iSize;      /* Number of bytes in this block of free space */
++  u16 iNext;      /* Index in MemPage.u.aDisk[] of the next free block */
++};
++
++/*
++** The number of bytes of payload that will fit on a single overflow page.
++*/
++#define OVERFLOW_SIZE (SQLITE_USABLE_SIZE-sizeof(Pgno))
++
++/*
++** When the key and data for a single entry in the BTree will not fit in
++** the MX_LOCAL_PAYLOAD bytes of space available on the database page,
++** then all extra bytes are written to a linked list of overflow pages.
++** Each overflow page is an instance of the following structure.
++**
++** Unused pages in the database are also represented by instances of
++** the OverflowPage structure.  The PageOne.freeList field is the
++** page number of the first page in a linked list of unused database
++** pages.
++*/
++struct OverflowPage {
++  Pgno iNext;
++  char aPayload[OVERFLOW_SIZE];
++};
++
++/*
++** The PageOne.freeList field points to a linked list of overflow pages
++** hold information about free pages.  The aPayload section of each
++** overflow page contains an instance of the following structure.  The
++** aFree[] array holds the page number of nFree unused pages in the disk
++** file.
++*/
++struct FreelistInfo {
++  int nFree;
++  Pgno aFree[(OVERFLOW_SIZE-sizeof(int))/sizeof(Pgno)];
++};
++
++/*
++** For every page in the database file, an instance of the following structure
++** is stored in memory.  The u.aDisk[] array contains the raw bits read from
++** the disk.  The rest is auxiliary information held in memory only. The
++** auxiliary info is only valid for regular database pages - it is not
++** used for overflow pages and pages on the freelist.
++**
++** Of particular interest in the auxiliary info is the apCell[] entry.  Each
++** apCell[] entry is a pointer to a Cell structure in u.aDisk[].  The cells are
++** put in this array so that they can be accessed in constant time, rather
++** than in linear time which would be needed if we had to walk the linked 
++** list on every access.
++**
++** Note that apCell[] contains enough space to hold up to two more Cells
++** than can possibly fit on one page.  In the steady state, every apCell[]
++** points to memory inside u.aDisk[].  But in the middle of an insert
++** operation, some apCell[] entries may temporarily point to data space
++** outside of u.aDisk[].  This is a transient situation that is quickly
++** resolved.  But while it is happening, it is possible for a database
++** page to hold as many as two more cells than it might otherwise hold.
++** The extra two entries in apCell[] are an allowance for this situation.
++**
++** 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 {
++  union u_page_data {
++    char aDisk[SQLITE_PAGE_SIZE];  /* Page data stored on disk */
++    PageHdr hdr;                   /* Overlay page header */
++  } u;
++  u8 isInit;                     /* True if auxiliary data is initialized */
++  u8 idxShift;                   /* True if apCell[] indices have changed */
++  u8 isOverfull;                 /* Some apCell[] points outside u.aDisk[] */
++  MemPage *pParent;              /* The parent of this page.  NULL for root */
++  int idxParent;                 /* Index in pParent->apCell[] of this node */
++  int nFree;                     /* Number of free bytes in u.aDisk[] */
++  int nCell;                     /* Number of entries on this page */
++  Cell *apCell[MX_CELL+2];       /* All data entires in sorted order */
++};
++
++/*
++** 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)-sizeof(union u_page_data))
++
++/*
++** Everything we need to know about an open database
++*/
++struct Btree {
++  BtOps *pOps;          /* Function table */
++  Pager *pPager;        /* The page cache */
++  BtCursor *pCursor;    /* A list of all open cursors */
++  PageOne *page1;       /* First page of the database */
++  u8 inTrans;           /* True if a transaction is in progress */
++  u8 inCkpt;            /* True if there is a checkpoint on the transaction */
++  u8 readOnly;          /* True if the underlying file is readonly */
++  u8 needSwab;          /* Need to byte-swapping */
++};
++typedef Btree Bt;
++
++/*
++** A cursor is a pointer to a particular entry in the BTree.
++** The entry is identified by its MemPage and the index in
++** MemPage.apCell[] of the entry.
++*/
++struct BtCursor {
++  BtCursorOps *pOps;        /* Function table */
++  Btree *pBt;               /* The Btree to which this cursor belongs */
++  BtCursor *pNext, *pPrev;  /* Forms a linked list of all cursors */
++  BtCursor *pShared;        /* Loop of cursors with the same root page */
++  Pgno pgnoRoot;            /* The root page of this tree */
++  MemPage *pPage;           /* Page that contains the entry */
++  int idx;                  /* Index of the entry in pPage->apCell[] */
++  u8 wrFlag;                /* True if writable */
++  u8 eSkip;                 /* Determines if next step operation is a no-op */
++  u8 iMatch;                /* compare result from last sqliteBtreeMoveto() */
++};
++
++/*
++** Legal values for BtCursor.eSkip.
++*/
++#define SKIP_NONE     0   /* Always step the cursor */
++#define SKIP_NEXT     1   /* The next sqliteBtreeNext() is a no-op */
++#define SKIP_PREV     2   /* The next sqliteBtreePrevious() is a no-op */
++#define SKIP_INVALID  3   /* Calls to Next() and Previous() are invalid */
++
++/* Forward declarations */
++static int fileBtreeCloseCursor(BtCursor *pCur);
++
++/*
++** Routines for byte swapping.
++*/
++u16 swab16(u16 x){
++  return ((x & 0xff)<<8) | ((x>>8)&0xff);
++}
++u32 swab32(u32 x){
++  return ((x & 0xff)<<24) | ((x & 0xff00)<<8) |
++         ((x>>8) & 0xff00) | ((x>>24)&0xff);
++}
++
++/*
++** Compute the total number of bytes that a Cell needs on the main
++** database page.  The number returned includes the Cell header,
++** local payload storage, and the pointer to overflow pages (if
++** applicable).  Additional space allocated on overflow pages
++** is NOT included in the value returned from this routine.
++*/
++static int cellSize(Btree *pBt, Cell *pCell){
++  int n = NKEY(pBt, pCell->h) + NDATA(pBt, pCell->h);
++  if( n>MX_LOCAL_PAYLOAD ){
++    n = MX_LOCAL_PAYLOAD + sizeof(Pgno);
++  }else{
++    n = ROUNDUP(n);
++  }
++  n += sizeof(CellHdr);
++  return n;
++}
++
++/*
++** Defragment the page given.  All Cells are moved to the
++** beginning of the page and all free space is collected 
++** into one big FreeBlk at the end of the page.
++*/
++static void defragmentPage(Btree *pBt, MemPage *pPage){
++  int pc, i, n;
++  FreeBlk *pFBlk;
++  char newPage[SQLITE_USABLE_SIZE];
++
++  assert( sqlitepager_iswriteable(pPage) );
++  assert( pPage->isInit );
++  pc = sizeof(PageHdr);
++  pPage->u.hdr.firstCell = SWAB16(pBt, pc);
++  memcpy(newPage, pPage->u.aDisk, pc);
++  for(i=0; i<pPage->nCell; i++){
++    Cell *pCell = pPage->apCell[i];
++
++    /* This routine should never be called on an overfull page.  The
++    ** following asserts verify that constraint. */
++    assert( Addr(pCell) > Addr(pPage) );
++    assert( Addr(pCell) < Addr(pPage) + SQLITE_USABLE_SIZE );
++
++    n = cellSize(pBt, pCell);
++    pCell->h.iNext = SWAB16(pBt, pc + n);
++    memcpy(&newPage[pc], pCell, n);
++    pPage->apCell[i] = (Cell*)&pPage->u.aDisk[pc];
++    pc += n;
++  }
++  assert( pPage->nFree==SQLITE_USABLE_SIZE-pc );
++  memcpy(pPage->u.aDisk, newPage, pc);
++  if( pPage->nCell>0 ){
++    pPage->apCell[pPage->nCell-1]->h.iNext = 0;
++  }
++  pFBlk = (FreeBlk*)&pPage->u.aDisk[pc];
++  pFBlk->iSize = SWAB16(pBt, SQLITE_USABLE_SIZE - pc);
++  pFBlk->iNext = 0;
++  pPage->u.hdr.firstFree = SWAB16(pBt, pc);
++  memset(&pFBlk[1], 0, SQLITE_USABLE_SIZE - pc - sizeof(FreeBlk));
++}
++
++/*
++** Allocate nByte bytes of space on a page.  nByte must be a 
++** multiple of 4.
++**
++** Return the index into pPage->u.aDisk[] of the first byte of
++** the new allocation. Or return 0 if there is not enough free
++** space on the page to satisfy the allocation request.
++**
++** If the page contains nBytes of free space but does not contain
++** nBytes of contiguous free space, then this routine automatically
++** calls defragementPage() to consolidate all free space before 
++** allocating the new chunk.
++*/
++static int allocateSpace(Btree *pBt, MemPage *pPage, int nByte){
++  FreeBlk *p;
++  u16 *pIdx;
++  int start;
++  int iSize;
++#ifndef NDEBUG
++  int cnt = 0;
++#endif
++
++  assert( sqlitepager_iswriteable(pPage) );
++  assert( nByte==ROUNDUP(nByte) );
++  assert( pPage->isInit );
++  if( pPage->nFree<nByte || pPage->isOverfull ) return 0;
++  pIdx = &pPage->u.hdr.firstFree;
++  p = (FreeBlk*)&pPage->u.aDisk[SWAB16(pBt, *pIdx)];
++  while( (iSize = SWAB16(pBt, p->iSize))<nByte ){
++    assert( cnt++ < SQLITE_USABLE_SIZE/4 );
++    if( p->iNext==0 ){
++      defragmentPage(pBt, pPage);
++      pIdx = &pPage->u.hdr.firstFree;
++    }else{
++      pIdx = &p->iNext;
++    }
++    p = (FreeBlk*)&pPage->u.aDisk[SWAB16(pBt, *pIdx)];
++  }
++  if( iSize==nByte ){
++    start = SWAB16(pBt, *pIdx);
++    *pIdx = p->iNext;
++  }else{
++    FreeBlk *pNew;
++    start = SWAB16(pBt, *pIdx);
++    pNew = (FreeBlk*)&pPage->u.aDisk[start + nByte];
++    pNew->iNext = p->iNext;
++    pNew->iSize = SWAB16(pBt, iSize - nByte);
++    *pIdx = SWAB16(pBt, start + nByte);
++  }
++  pPage->nFree -= nByte;
++  return start;
++}
++
++/*
++** Return a section of the MemPage.u.aDisk[] to the freelist.
++** The first byte of the new free block is pPage->u.aDisk[start]
++** and the size of the block is "size" bytes.  Size must be
++** a multiple of 4.
++**
++** Most of the effort here is involved in coalesing adjacent
++** free blocks into a single big free block.
++*/
++static void freeSpace(Btree *pBt, MemPage *pPage, int start, int size){
++  int end = start + size;
++  u16 *pIdx, idx;
++  FreeBlk *pFBlk;
++  FreeBlk *pNew;
++  FreeBlk *pNext;
++  int iSize;
++
++  assert( sqlitepager_iswriteable(pPage) );
++  assert( size == ROUNDUP(size) );
++  assert( start == ROUNDUP(start) );
++  assert( pPage->isInit );
++  pIdx = &pPage->u.hdr.firstFree;
++  idx = SWAB16(pBt, *pIdx);
++  while( idx!=0 && idx<start ){
++    pFBlk = (FreeBlk*)&pPage->u.aDisk[idx];
++    iSize = SWAB16(pBt, pFBlk->iSize);
++    if( idx + iSize == start ){
++      pFBlk->iSize = SWAB16(pBt, iSize + size);
++      if( idx + iSize + size == SWAB16(pBt, pFBlk->iNext) ){
++        pNext = (FreeBlk*)&pPage->u.aDisk[idx + iSize + size];
++        if( pBt->needSwab ){
++          pFBlk->iSize = swab16((u16)swab16(pNext->iSize)+iSize+size);
++        }else{
++          pFBlk->iSize += pNext->iSize;
++        }
++        pFBlk->iNext = pNext->iNext;
++      }
++      pPage->nFree += size;
++      return;
++    }
++    pIdx = &pFBlk->iNext;
++    idx = SWAB16(pBt, *pIdx);
++  }
++  pNew = (FreeBlk*)&pPage->u.aDisk[start];
++  if( idx != end ){
++    pNew->iSize = SWAB16(pBt, size);
++    pNew->iNext = SWAB16(pBt, idx);
++  }else{
++    pNext = (FreeBlk*)&pPage->u.aDisk[idx];
++    pNew->iSize = SWAB16(pBt, size + SWAB16(pBt, pNext->iSize));
++    pNew->iNext = pNext->iNext;
++  }
++  *pIdx = SWAB16(pBt, start);
++  pPage->nFree += size;
++}
++
++/*
++** Initialize the auxiliary information for a disk block.
++**
++** The pParent parameter must be a pointer to the MemPage which
++** is the parent of the page being initialized.  The root of the
++** BTree (usually page 2) has no parent and so for that page, 
++** pParent==NULL.
++**
++** Return SQLITE_OK on success.  If we see that the page does
++** not contain a well-formed database page, then return 
++** SQLITE_CORRUPT.  Note that a return of SQLITE_OK does not
++** guarantee that the page is well-formed.  It only shows that
++** we failed to detect any corruption.
++*/
++static int initPage(Bt *pBt, MemPage *pPage, Pgno pgnoThis, MemPage *pParent){
++  int idx;           /* An index into pPage->u.aDisk[] */
++  Cell *pCell;       /* A pointer to a Cell in pPage->u.aDisk[] */
++  FreeBlk *pFBlk;    /* A pointer to a free block in pPage->u.aDisk[] */
++  int sz;            /* The size of a Cell in bytes */
++  int freeSpace;     /* Amount of free space on the page */
++
++  if( pPage->pParent ){
++    assert( pPage->pParent==pParent );
++    return SQLITE_OK;
++  }
++  if( pParent ){
++    pPage->pParent = pParent;
++    sqlitepager_ref(pParent);
++  }
++  if( pPage->isInit ) return SQLITE_OK;
++  pPage->isInit = 1;
++  pPage->nCell = 0;
++  freeSpace = USABLE_SPACE;
++  idx = SWAB16(pBt, pPage->u.hdr.firstCell);
++  while( idx!=0 ){
++    if( idx>SQLITE_USABLE_SIZE-MIN_CELL_SIZE ) goto page_format_error;
++    if( idx<sizeof(PageHdr) ) goto page_format_error;
++    if( idx!=ROUNDUP(idx) ) goto page_format_error;
++    pCell = (Cell*)&pPage->u.aDisk[idx];
++    sz = cellSize(pBt, pCell);
++    if( idx+sz > SQLITE_USABLE_SIZE ) goto page_format_error;
++    freeSpace -= sz;
++    pPage->apCell[pPage->nCell++] = pCell;
++    idx = SWAB16(pBt, pCell->h.iNext);
++  }
++  pPage->nFree = 0;
++  idx = SWAB16(pBt, pPage->u.hdr.firstFree);
++  while( idx!=0 ){
++    int iNext;
++    if( idx>SQLITE_USABLE_SIZE-sizeof(FreeBlk) ) goto page_format_error;
++    if( idx<sizeof(PageHdr) ) goto page_format_error;
++    pFBlk = (FreeBlk*)&pPage->u.aDisk[idx];
++    pPage->nFree += SWAB16(pBt, pFBlk->iSize);
++    iNext = SWAB16(pBt, pFBlk->iNext);
++    if( iNext>0 && iNext <= idx ) goto page_format_error;
++    idx = iNext;
++  }
++  if( pPage->nCell==0 && pPage->nFree==0 ){
++    /* As a special case, an uninitialized root page appears to be
++    ** an empty database */
++    return SQLITE_OK;
++  }
++  if( pPage->nFree!=freeSpace ) goto page_format_error;
++  return SQLITE_OK;
++
++page_format_error:
++  return SQLITE_CORRUPT;
++}
++
++/*
++** Set up a raw page so that it looks like a database page holding
++** no entries.
++*/
++static void zeroPage(Btree *pBt, MemPage *pPage){
++  PageHdr *pHdr;
++  FreeBlk *pFBlk;
++  assert( sqlitepager_iswriteable(pPage) );
++  memset(pPage, 0, SQLITE_USABLE_SIZE);
++  pHdr = &pPage->u.hdr;
++  pHdr->firstCell = 0;
++  pHdr->firstFree = SWAB16(pBt, sizeof(*pHdr));
++  pFBlk = (FreeBlk*)&pHdr[1];
++  pFBlk->iNext = 0;
++  pPage->nFree = SQLITE_USABLE_SIZE - sizeof(*pHdr);
++  pFBlk->iSize = SWAB16(pBt, pPage->nFree);
++  pPage->nCell = 0;
++  pPage->isOverfull = 0;
++}
++
++/*
++** This routine is called when the reference count for a page
++** reaches zero.  We need to unref the pParent pointer when that
++** happens.
++*/
++static void pageDestructor(void *pData){
++  MemPage *pPage = (MemPage*)pData;
++  if( pPage->pParent ){
++    MemPage *pParent = pPage->pParent;
++    pPage->pParent = 0;
++    sqlitepager_unref(pParent);
++  }
++}
++
++/*
++** Open a new database.
++**
++** Actually, this routine just sets up the internal data structures
++** for accessing the database.  We do not open the database file 
++** until the first page is loaded.
++**
++** 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 sqliteBtreeClose() is called.
++*/
++int sqliteBtreeOpen(
++  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 */
++  Btree **ppBtree           /* Pointer to new Btree object written here */
++){
++  Btree *pBt;
++  int rc;
++
++  /*
++  ** 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(u32)==4 );
++  assert( sizeof(u16)==2 );
++  assert( sizeof(Pgno)==4 );
++  assert( sizeof(PageHdr)==8 );
++  assert( sizeof(CellHdr)==12 );
++  assert( sizeof(FreeBlk)==4 );
++  assert( sizeof(OverflowPage)==SQLITE_USABLE_SIZE );
++  assert( sizeof(FreelistInfo)==OVERFLOW_SIZE );
++  assert( sizeof(ptr)==sizeof(char*) );
++  assert( sizeof(uptr)==sizeof(ptr) );
++
++  pBt = sqliteMalloc( sizeof(*pBt) );
++  if( pBt==0 ){
++    *ppBtree = 0;
++    return SQLITE_NOMEM;
++  }
++  if( nCache<10 ) nCache = 10;
++  rc = sqlitepager_open(&pBt->pPager, zFilename, nCache, EXTRA_SIZE,
++                        !omitJournal);
++  if( rc!=SQLITE_OK ){
++    if( pBt->pPager ) sqlitepager_close(pBt->pPager);
++    sqliteFree(pBt);
++    *ppBtree = 0;
++    return rc;
++  }
++  sqlitepager_set_destructor(pBt->pPager, pageDestructor);
++  pBt->pCursor = 0;
++  pBt->page1 = 0;
++  pBt->readOnly = sqlitepager_isreadonly(pBt->pPager);
++  pBt->pOps = &sqliteBtreeOps;
++  *ppBtree = pBt;
++  return SQLITE_OK;
++}
++
++/*
++** Close an open database and invalidate all cursors.
++*/
++static int fileBtreeClose(Btree *pBt){
++  while( pBt->pCursor ){
++    fileBtreeCloseCursor(pBt->pCursor);
++  }
++  sqlitepager_close(pBt->pPager);
++  sqliteFree(pBt);
++  return SQLITE_OK;
++}
++
++/*
++** Change the limit on the number of pages allowed in the cache.
++**
++** The maximum number of cache pages is set to the absolute
++** value of mxPage.  If mxPage is negative, the pager will
++** operate asynchronously - it will not stop to do fsync()s
++** to insure data is written to the disk surface before
++** continuing.  Transactions still work if synchronous is off,
++** and the database cannot be corrupted if this program
++** crashes.  But if the operating system crashes or there is
++** an abrupt power failure when synchronous is off, the database
++** could be left in an inconsistent and unrecoverable state.
++** Synchronous is on by default so database corruption is not
++** normally a worry.
++*/
++static int fileBtreeSetCacheSize(Btree *pBt, int mxPage){
++  sqlitepager_set_cachesize(pBt->pPager, mxPage);
++  return SQLITE_OK;
++}
++
++/*
++** Change the way data is synced to disk in order to increase or decrease
++** how well the database resists damage due to OS crashes and power
++** failures.  Level 1 is the same as asynchronous (no syncs() occur and
++** there is a high probability of damage)  Level 2 is the default.  There
++** is a very low but non-zero probability of damage.  Level 3 reduces the
++** probability of damage to near zero but with a write performance reduction.
++*/
++static int fileBtreeSetSafetyLevel(Btree *pBt, int level){
++  sqlitepager_set_safety_level(pBt->pPager, level);
++  return SQLITE_OK;
++}
++
++/*
++** Get a reference to page1 of the database file.  This will
++** also acquire a readlock on that file.
++**
++** 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.
++*/
++static int lockBtree(Btree *pBt){
++  int rc;
++  if( pBt->page1 ) return SQLITE_OK;
++  rc = sqlitepager_get(pBt->pPager, 1, (void**)&pBt->page1);
++  if( rc!=SQLITE_OK ) return rc;
++
++  /* Do some checking to help insure the file we opened really is
++  ** a valid database file. 
++  */
++  if( sqlitepager_pagecount(pBt->pPager)>0 ){
++    PageOne *pP1 = pBt->page1;
++    if( strcmp(pP1->zMagic,zMagicHeader)!=0 ||
++          (pP1->iMagic!=MAGIC && swab32(pP1->iMagic)!=MAGIC) ){
++      rc = SQLITE_NOTADB;
++      goto page1_init_failed;
++    }
++    pBt->needSwab = pP1->iMagic!=MAGIC;
++  }
++  return rc;
++
++page1_init_failed:
++  sqlitepager_unref(pBt->page1);
++  pBt->page1 = 0;
++  return rc;
++}
++
++/*
++** If there are no outstanding cursors and we are not in the middle
++** of a transaction but there is a read lock on the database, then
++** this routine unrefs the first page of the database file which 
++** has the effect of releasing the read lock.
++**
++** If there are any outstanding cursors, this routine is a no-op.
++**
++** If there is a transaction in progress, this routine is a no-op.
++*/
++static void unlockBtreeIfUnused(Btree *pBt){
++  if( pBt->inTrans==0 && pBt->pCursor==0 && pBt->page1!=0 ){
++    sqlitepager_unref(pBt->page1);
++    pBt->page1 = 0;
++    pBt->inTrans = 0;
++    pBt->inCkpt = 0;
++  }
++}
++
++/*
++** Create a new database by initializing the first two pages of the
++** file.
++*/
++static int newDatabase(Btree *pBt){
++  MemPage *pRoot;
++  PageOne *pP1;
++  int rc;
++  if( sqlitepager_pagecount(pBt->pPager)>1 ) return SQLITE_OK;
++  pP1 = pBt->page1;
++  rc = sqlitepager_write(pBt->page1);
++  if( rc ) return rc;
++  rc = sqlitepager_get(pBt->pPager, 2, (void**)&pRoot);
++  if( rc ) return rc;
++  rc = sqlitepager_write(pRoot);
++  if( rc ){
++    sqlitepager_unref(pRoot);
++    return rc;
++  }
++  strcpy(pP1->zMagic, zMagicHeader);
++  if( btree_native_byte_order ){
++    pP1->iMagic = MAGIC;
++    pBt->needSwab = 0;
++  }else{
++    pP1->iMagic = swab32(MAGIC);
++    pBt->needSwab = 1;
++  }
++  zeroPage(pBt, pRoot);
++  sqlitepager_unref(pRoot);
++  return SQLITE_OK;
++}
++
++/*
++** Attempt to start a new transaction.
++**
++** A transaction must be started before attempting any changes
++** to the database.  None of the following routines will work
++** unless a transaction is started first:
++**
++**      sqliteBtreeCreateTable()
++**      sqliteBtreeCreateIndex()
++**      sqliteBtreeClearTable()
++**      sqliteBtreeDropTable()
++**      sqliteBtreeInsert()
++**      sqliteBtreeDelete()
++**      sqliteBtreeUpdateMeta()
++*/
++static int fileBtreeBeginTrans(Btree *pBt){
++  int rc;
++  if( pBt->inTrans ) return SQLITE_ERROR;
++  if( pBt->readOnly ) return SQLITE_READONLY;
++  if( pBt->page1==0 ){
++    rc = lockBtree(pBt);
++    if( rc!=SQLITE_OK ){
++      return rc;
++    }
++  }
++  rc = sqlitepager_begin(pBt->page1);
++  if( rc==SQLITE_OK ){
++    rc = newDatabase(pBt);
++  }
++  if( rc==SQLITE_OK ){
++    pBt->inTrans = 1;
++    pBt->inCkpt = 0;
++  }else{
++    unlockBtreeIfUnused(pBt);
++  }
++  return rc;
++}
++
++/*
++** Commit the transaction currently in progress.
++**
++** This will release the write lock on the database file.  If there
++** are no active cursors, it also releases the read lock.
++*/
++static int fileBtreeCommit(Btree *pBt){
++  int rc;
++  rc = pBt->readOnly ? SQLITE_OK : sqlitepager_commit(pBt->pPager);
++  pBt->inTrans = 0;
++  pBt->inCkpt = 0;
++  unlockBtreeIfUnused(pBt);
++  return rc;
++}
++
++/*
++** Rollback the transaction in progress.  All cursors will be
++** invalided by this operation.  Any attempt to use a cursor
++** that was open at the beginning of this operation will result
++** in an error.
++**
++** This will release the write lock on the database file.  If there
++** are no active cursors, it also releases the read lock.
++*/
++static int fileBtreeRollback(Btree *pBt){
++  int rc;
++  BtCursor *pCur;
++  if( pBt->inTrans==0 ) return SQLITE_OK;
++  pBt->inTrans = 0;
++  pBt->inCkpt = 0;
++  rc = pBt->readOnly ? SQLITE_OK : sqlitepager_rollback(pBt->pPager);
++  for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
++    if( pCur->pPage && pCur->pPage->isInit==0 ){
++      sqlitepager_unref(pCur->pPage);
++      pCur->pPage = 0;
++    }
++  }
++  unlockBtreeIfUnused(pBt);
++  return rc;
++}
++
++/*
++** Set the checkpoint for the current transaction.  The checkpoint serves
++** as a sub-transaction that can be rolled back independently of the
++** main transaction.  You must start a transaction before starting a
++** checkpoint.  The checkpoint is ended automatically if the transaction
++** commits or rolls back.
++**
++** Only one checkpoint may be active at a time.  It is an error to try
++** to start a new checkpoint if another checkpoint is already active.
++*/
++static int fileBtreeBeginCkpt(Btree *pBt){
++  int rc;
++  if( !pBt->inTrans || pBt->inCkpt ){
++    return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
++  }
++  rc = pBt->readOnly ? SQLITE_OK : sqlitepager_ckpt_begin(pBt->pPager);
++  pBt->inCkpt = 1;
++  return rc;
++}
++
++
++/*
++** Commit a checkpoint to transaction currently in progress.  If no
++** checkpoint is active, this is a no-op.
++*/
++static int fileBtreeCommitCkpt(Btree *pBt){
++  int rc;
++  if( pBt->inCkpt && !pBt->readOnly ){
++    rc = sqlitepager_ckpt_commit(pBt->pPager);
++  }else{
++    rc = SQLITE_OK;
++  }
++  pBt->inCkpt = 0;
++  return rc;
++}
++
++/*
++** Rollback the checkpoint to the current transaction.  If there
++** is no active checkpoint or transaction, this routine is a no-op.
++**
++** All cursors will be invalided by this operation.  Any attempt
++** to use a cursor that was open at the beginning of this operation
++** will result in an error.
++*/
++static int fileBtreeRollbackCkpt(Btree *pBt){
++  int rc;
++  BtCursor *pCur;
++  if( pBt->inCkpt==0 || pBt->readOnly ) return SQLITE_OK;
++  rc = sqlitepager_ckpt_rollback(pBt->pPager);
++  for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
++    if( pCur->pPage && pCur->pPage->isInit==0 ){
++      sqlitepager_unref(pCur->pPage);
++      pCur->pPage = 0;
++    }
++  }
++  pBt->inCkpt = 0;
++  return rc;
++}
++
++/*
++** Create a new cursor for the BTree whose root is on the page
++** iTable.  The act of acquiring a cursor gets a read lock on 
++** the database file.
++**
++** If wrFlag==0, then the cursor can only be used for reading.
++** If wrFlag==1, then the cursor can be used for reading or for
++** writing if other conditions for writing are also met.  These
++** are the conditions that must be met in order for writing to
++** be allowed:
++**
++** 1:  The cursor must have been opened with wrFlag==1
++**
++** 2:  No other cursors may be open with wrFlag==0 on the same table
++**
++** 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 sqliteBtreeNext() 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.
++*/
++static 
++int fileBtreeCursor(Btree *pBt, int iTable, int wrFlag, BtCursor **ppCur){
++  int rc;
++  BtCursor *pCur, *pRing;
++
++  if( pBt->readOnly && wrFlag ){
++    *ppCur = 0;
++    return SQLITE_READONLY;
++  }
++  if( pBt->page1==0 ){
++    rc = lockBtree(pBt);
++    if( rc!=SQLITE_OK ){
++      *ppCur = 0;
++      return rc;
++    }
++  }
++  pCur = sqliteMalloc( sizeof(*pCur) );
++  if( pCur==0 ){
++    rc = SQLITE_NOMEM;
++    goto create_cursor_exception;
++  }
++  pCur->pgnoRoot = (Pgno)iTable;
++  rc = sqlitepager_get(pBt->pPager, pCur->pgnoRoot, (void**)&pCur->pPage);
++  if( rc!=SQLITE_OK ){
++    goto create_cursor_exception;
++  }
++  rc = initPage(pBt, pCur->pPage, pCur->pgnoRoot, 0);
++  if( rc!=SQLITE_OK ){
++    goto create_cursor_exception;
++  }
++  pCur->pOps = &sqliteBtreeCursorOps;
++  pCur->pBt = pBt;
++  pCur->wrFlag = wrFlag;
++  pCur->idx = 0;
++  pCur->eSkip = SKIP_INVALID;
++  pCur->pNext = pBt->pCursor;
++  if( pCur->pNext ){
++    pCur->pNext->pPrev = pCur;
++  }
++  pCur->pPrev = 0;
++  pRing = pBt->pCursor;
++  while( pRing && pRing->pgnoRoot!=pCur->pgnoRoot ){ pRing = pRing->pNext; }
++  if( pRing ){
++    pCur->pShared = pRing->pShared;
++    pRing->pShared = pCur;
++  }else{
++    pCur->pShared = pCur;
++  }
++  pBt->pCursor = pCur;
++  *ppCur = pCur;
++  return SQLITE_OK;
++
++create_cursor_exception:
++  *ppCur = 0;
++  if( pCur ){
++    if( pCur->pPage ) sqlitepager_unref(pCur->pPage);
++    sqliteFree(pCur);
++  }
++  unlockBtreeIfUnused(pBt);
++  return rc;
++}
++
++/*
++** Close a cursor.  The read lock on the database file is released
++** when the last cursor is closed.
++*/
++static int fileBtreeCloseCursor(BtCursor *pCur){
++  Btree *pBt = pCur->pBt;
++  if( pCur->pPrev ){
++    pCur->pPrev->pNext = pCur->pNext;
++  }else{
++    pBt->pCursor = pCur->pNext;
++  }
++  if( pCur->pNext ){
++    pCur->pNext->pPrev = pCur->pPrev;
++  }
++  if( pCur->pPage ){
++    sqlitepager_unref(pCur->pPage);
++  }
++  if( pCur->pShared!=pCur ){
++    BtCursor *pRing = pCur->pShared;
++    while( pRing->pShared!=pCur ){ pRing = pRing->pShared; }
++    pRing->pShared = pCur->pShared;
++  }
++  unlockBtreeIfUnused(pBt);
++  sqliteFree(pCur);
++  return SQLITE_OK;
++}
++
++/*
++** 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){
++  memcpy(pTempCur, pCur, sizeof(*pCur));
++  pTempCur->pNext = 0;
++  pTempCur->pPrev = 0;
++  if( pTempCur->pPage ){
++    sqlitepager_ref(pTempCur->pPage);
++  }
++}
++
++/*
++** Delete a temporary cursor such as was made by the CreateTemporaryCursor()
++** function above.
++*/
++static void releaseTempCursor(BtCursor *pCur){
++  if( pCur->pPage ){
++    sqlitepager_unref(pCur->pPage);
++  }
++}
++
++/*
++** Set *pSize to the number of bytes of key in the entry the
++** cursor currently points to.  Always return SQLITE_OK.
++** Failure is not possible.  If the cursor is not currently
++** pointing to an entry (which can happen, for example, if
++** the database is empty) then *pSize is set to 0.
++*/
++static int fileBtreeKeySize(BtCursor *pCur, int *pSize){
++  Cell *pCell;
++  MemPage *pPage;
++
++  pPage = pCur->pPage;
++  assert( pPage!=0 );
++  if( pCur->idx >= pPage->nCell ){
++    *pSize = 0;
++  }else{
++    pCell = pPage->apCell[pCur->idx];
++    *pSize = NKEY(pCur->pBt, pCell->h);
++  }
++  return SQLITE_OK;
++}
++
++/*
++** 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.
++**
++** This routine does not make a distinction between key and data.
++** It just reads bytes from the payload area.
++*/
++static int getPayload(BtCursor *pCur, int offset, int amt, char *zBuf){
++  char *aPayload;
++  Pgno nextPage;
++  int rc;
++  Btree *pBt = pCur->pBt;
++  assert( pCur!=0 && pCur->pPage!=0 );
++  assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
++  aPayload = pCur->pPage->apCell[pCur->idx]->aPayload;
++  if( offset<MX_LOCAL_PAYLOAD ){
++    int a = amt;
++    if( a+offset>MX_LOCAL_PAYLOAD ){
++      a = MX_LOCAL_PAYLOAD - offset;
++    }
++    memcpy(zBuf, &aPayload[offset], a);
++    if( a==amt ){
++      return SQLITE_OK;
++    }
++    offset = 0;
++    zBuf += a;
++    amt -= a;
++  }else{
++    offset -= MX_LOCAL_PAYLOAD;
++  }
++  if( amt>0 ){
++    nextPage = SWAB32(pBt, pCur->pPage->apCell[pCur->idx]->ovfl);
++  }
++  while( amt>0 && nextPage ){
++    OverflowPage *pOvfl;
++    rc = sqlitepager_get(pBt->pPager, nextPage, (void**)&pOvfl);
++    if( rc!=0 ){
++      return rc;
++    }
++    nextPage = SWAB32(pBt, pOvfl->iNext);
++    if( offset<OVERFLOW_SIZE ){
++      int a = amt;
++      if( a + offset > OVERFLOW_SIZE ){
++        a = OVERFLOW_SIZE - offset;
++      }
++      memcpy(zBuf, &pOvfl->aPayload[offset], a);
++      offset = 0;
++      amt -= a;
++      zBuf += a;
++    }else{
++      offset -= OVERFLOW_SIZE;
++    }
++    sqlitepager_unref(pOvfl);
++  }
++  if( amt>0 ){
++    return SQLITE_CORRUPT;
++  }
++  return SQLITE_OK;
++}
++
++/*
++** Read part of the key associated with cursor pCur.  A maximum
++** of "amt" bytes will be transfered into zBuf[].  The transfer
++** begins at "offset".  The number of bytes actually read is
++** returned. 
++**
++** Change:  It used to be that the amount returned will be smaller
++** than the amount requested if there are not enough bytes in the key
++** to satisfy the request.  But now, it must be the case that there
++** is enough data available to satisfy the request.  If not, an exception
++** is raised.  The change was made in an effort to boost performance
++** by eliminating unneeded tests.
++*/
++static int fileBtreeKey(BtCursor *pCur, int offset, int amt, char *zBuf){
++  MemPage *pPage;
++
++  assert( amt>=0 );
++  assert( offset>=0 );
++  assert( pCur->pPage!=0 );
++  pPage = pCur->pPage;
++  if( pCur->idx >= pPage->nCell ){
++    return 0;
++  }
++  assert( amt+offset <= NKEY(pCur->pBt, pPage->apCell[pCur->idx]->h) );
++  getPayload(pCur, offset, amt, zBuf);
++  return amt;
++}
++
++/*
++** Set *pSize to the number of bytes of data in the entry the
++** cursor currently points to.  Always return SQLITE_OK.
++** Failure is not possible.  If the cursor is not currently
++** pointing to an entry (which can happen, for example, if
++** the database is empty) then *pSize is set to 0.
++*/
++static int fileBtreeDataSize(BtCursor *pCur, int *pSize){
++  Cell *pCell;
++  MemPage *pPage;
++
++  pPage = pCur->pPage;
++  assert( pPage!=0 );
++  if( pCur->idx >= pPage->nCell ){
++    *pSize = 0;
++  }else{
++    pCell = pPage->apCell[pCur->idx];
++    *pSize = NDATA(pCur->pBt, pCell->h);
++  }
++  return SQLITE_OK;
++}
++
++/*
++** Read part of the data associated with cursor pCur.  A maximum
++** of "amt" bytes will be transfered into zBuf[].  The transfer
++** begins at "offset".  The number of bytes actually read is
++** returned.  The amount returned will be smaller than the
++** amount requested if there are not enough bytes in the data
++** to satisfy the request.
++*/
++static int fileBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf){
++  Cell *pCell;
++  MemPage *pPage;
++
++  assert( amt>=0 );
++  assert( offset>=0 );
++  assert( pCur->pPage!=0 );
++  pPage = pCur->pPage;
++  if( pCur->idx >= pPage->nCell ){
++    return 0;
++  }
++  pCell = pPage->apCell[pCur->idx];
++  assert( amt+offset <= NDATA(pCur->pBt, pCell->h) );
++  getPayload(pCur, offset + NKEY(pCur->pBt, pCell->h), amt, zBuf);
++  return amt;
++}
++
++/*
++** Compare an external key against the key on the entry that pCur points to.
++**
++** The external key is pKey and is nKey bytes long.  The last nIgnore bytes
++** of the key associated with pCur are ignored, as if they do not exist.
++** (The normal case is for nIgnore to be zero in which case the entire
++** internal key is used in the comparison.)
++**
++** The comparison result is written to *pRes as follows:
++**
++**    *pRes<0    This means pCur<pKey
++**
++**    *pRes==0   This means pCur==pKey for all nKey bytes
++**
++**    *pRes>0    This means pCur>pKey
++**
++** When one key is an exact prefix of the other, the shorter key is
++** considered less than the longer one.  In order to be equal the
++** keys must be exactly the same length. (The length of the pCur key
++** is the actual key length minus nIgnore bytes.)
++*/
++static int fileBtreeKeyCompare(
++  BtCursor *pCur,       /* Pointer to entry to compare against */
++  const void *pKey,     /* Key to compare against entry that pCur points to */
++  int nKey,             /* Number of bytes in pKey */
++  int nIgnore,          /* Ignore this many bytes at the end of pCur */
++  int *pResult          /* Write the result here */
++){
++  Pgno nextPage;
++  int n, c, rc, nLocal;
++  Cell *pCell;
++  Btree *pBt = pCur->pBt;
++  const char *zKey  = (const char*)pKey;
++
++  assert( pCur->pPage );
++  assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
++  pCell = pCur->pPage->apCell[pCur->idx];
++  nLocal = NKEY(pBt, pCell->h) - nIgnore;
++  if( nLocal<0 ) nLocal = 0;
++  n = nKey<nLocal ? nKey : nLocal;
++  if( n>MX_LOCAL_PAYLOAD ){
++    n = MX_LOCAL_PAYLOAD;
++  }
++  c = memcmp(pCell->aPayload, zKey, n);
++  if( c!=0 ){
++    *pResult = c;
++    return SQLITE_OK;
++  }
++  zKey += n;
++  nKey -= n;
++  nLocal -= n;
++  nextPage = SWAB32(pBt, pCell->ovfl);
++  while( nKey>0 && nLocal>0 ){
++    OverflowPage *pOvfl;
++    if( nextPage==0 ){
++      return SQLITE_CORRUPT;
++    }
++    rc = sqlitepager_get(pBt->pPager, nextPage, (void**)&pOvfl);
++    if( rc ){
++      return rc;
++    }
++    nextPage = SWAB32(pBt, pOvfl->iNext);
++    n = nKey<nLocal ? nKey : nLocal;
++    if( n>OVERFLOW_SIZE ){
++      n = OVERFLOW_SIZE;
++    }
++    c = memcmp(pOvfl->aPayload, zKey, n);
++    sqlitepager_unref(pOvfl);
++    if( c!=0 ){
++      *pResult = c;
++      return SQLITE_OK;
++    }
++    nKey -= n;
++    nLocal -= n;
++    zKey += n;
++  }
++  if( c==0 ){
++    c = nLocal - nKey;
++  }
++  *pResult = c;
++  return SQLITE_OK;
++}
++
++/*
++** Move the cursor down to a new child page.  The newPgno argument is the
++** page number of the child page in the byte order of the disk image.
++*/
++static int moveToChild(BtCursor *pCur, int newPgno){
++  int rc;
++  MemPage *pNewPage;
++  Btree *pBt = pCur->pBt;
++
++  newPgno = SWAB32(pBt, newPgno);
++  rc = sqlitepager_get(pBt->pPager, newPgno, (void**)&pNewPage);
++  if( rc ) return rc;
++  rc = initPage(pBt, pNewPage, newPgno, pCur->pPage);
++  if( rc ) return rc;
++  assert( pCur->idx>=pCur->pPage->nCell
++          || pCur->pPage->apCell[pCur->idx]->h.leftChild==SWAB32(pBt,newPgno) );
++  assert( pCur->idx<pCur->pPage->nCell
++          || pCur->pPage->u.hdr.rightChild==SWAB32(pBt,newPgno) );
++  pNewPage->idxParent = pCur->idx;
++  pCur->pPage->idxShift = 0;
++  sqlitepager_unref(pCur->pPage);
++  pCur->pPage = pNewPage;
++  pCur->idx = 0;
++  if( pNewPage->nCell<1 ){
++    return SQLITE_CORRUPT;
++  }
++  return SQLITE_OK;
++}
++
++/*
++** Move the cursor up to the parent page.
++**
++** pCur->idx is set to the cell index that contains the pointer
++** to the page we are coming from.  If we are coming from the
++** right-most child page then pCur->idx is set to one more than
++** the largest cell index.
++*/
++static void moveToParent(BtCursor *pCur){
++  Pgno oldPgno;
++  MemPage *pParent;
++  MemPage *pPage;
++  int idxParent;
++  pPage = pCur->pPage;
++  assert( pPage!=0 );
++  pParent = pPage->pParent;
++  assert( pParent!=0 );
++  idxParent = pPage->idxParent;
++  sqlitepager_ref(pParent);
++  sqlitepager_unref(pPage);
++  pCur->pPage = pParent;
++  assert( pParent->idxShift==0 );
++  if( pParent->idxShift==0 ){
++    pCur->idx = idxParent;
++#ifndef NDEBUG  
++    /* Verify that pCur->idx is the correct index to point back to the child
++    ** page we just came from 
++    */
++    oldPgno = SWAB32(pCur->pBt, sqlitepager_pagenumber(pPage));
++    if( pCur->idx<pParent->nCell ){
++      assert( pParent->apCell[idxParent]->h.leftChild==oldPgno );
++    }else{
++      assert( pParent->u.hdr.rightChild==oldPgno );
++    }
++#endif
++  }else{
++    /* The MemPage.idxShift flag indicates that cell indices might have 
++    ** changed since idxParent was set and hence idxParent might be out
++    ** of date.  So recompute the parent cell index by scanning all cells
++    ** and locating the one that points to the child we just came from.
++    */
++    int i;
++    pCur->idx = pParent->nCell;
++    oldPgno = SWAB32(pCur->pBt, sqlitepager_pagenumber(pPage));
++    for(i=0; i<pParent->nCell; i++){
++      if( pParent->apCell[i]->h.leftChild==oldPgno ){
++        pCur->idx = i;
++        break;
++      }
++    }
++  }
++}
++
++/*
++** Move the cursor to the root page
++*/
++static int moveToRoot(BtCursor *pCur){
++  MemPage *pNew;
++  int rc;
++  Btree *pBt = pCur->pBt;
++
++  rc = sqlitepager_get(pBt->pPager, pCur->pgnoRoot, (void**)&pNew);
++  if( rc ) return rc;
++  rc = initPage(pBt, pNew, pCur->pgnoRoot, 0);
++  if( rc ) return rc;
++  sqlitepager_unref(pCur->pPage);
++  pCur->pPage = pNew;
++  pCur->idx = 0;
++  return SQLITE_OK;
++}
++
++/*
++** Move the cursor down to the left-most leaf entry beneath the
++** entry to which it is currently pointing.
++*/
++static int moveToLeftmost(BtCursor *pCur){
++  Pgno pgno;
++  int rc;
++
++  while( (pgno = pCur->pPage->apCell[pCur->idx]->h.leftChild)!=0 ){
++    rc = moveToChild(pCur, pgno);
++    if( rc ) return rc;
++  }
++  return SQLITE_OK;
++}
++
++/*
++** Move the cursor down to the right-most leaf entry beneath the
++** page to which it is currently pointing.  Notice the difference
++** between moveToLeftmost() and moveToRightmost().  moveToLeftmost()
++** finds the left-most entry beneath the *entry* whereas moveToRightmost()
++** finds the right-most entry beneath the *page*.
++*/
++static int moveToRightmost(BtCursor *pCur){
++  Pgno pgno;
++  int rc;
++
++  while( (pgno = pCur->pPage->u.hdr.rightChild)!=0 ){
++    pCur->idx = pCur->pPage->nCell;
++    rc = moveToChild(pCur, pgno);
++    if( rc ) return rc;
++  }
++  pCur->idx = pCur->pPage->nCell - 1;
++  return SQLITE_OK;
++}
++
++/* Move the cursor to the first entry in the table.  Return SQLITE_OK
++** on success.  Set *pRes to 0 if the cursor actually points to something
++** or set *pRes to 1 if the table is empty.
++*/
++static int fileBtreeFirst(BtCursor *pCur, int *pRes){
++  int rc;
++  if( pCur->pPage==0 ) return SQLITE_ABORT;
++  rc = moveToRoot(pCur);
++  if( rc ) return rc;
++  if( pCur->pPage->nCell==0 ){
++    *pRes = 1;
++    return SQLITE_OK;
++  }
++  *pRes = 0;
++  rc = moveToLeftmost(pCur);
++  pCur->eSkip = SKIP_NONE;
++  return rc;
++}
++
++/* Move the cursor to the last entry in the table.  Return SQLITE_OK
++** on success.  Set *pRes to 0 if the cursor actually points to something
++** or set *pRes to 1 if the table is empty.
++*/
++static int fileBtreeLast(BtCursor *pCur, int *pRes){
++  int rc;
++  if( pCur->pPage==0 ) return SQLITE_ABORT;
++  rc = moveToRoot(pCur);
++  if( rc ) return rc;
++  assert( pCur->pPage->isInit );
++  if( pCur->pPage->nCell==0 ){
++    *pRes = 1;
++    return SQLITE_OK;
++  }
++  *pRes = 0;
++  rc = moveToRightmost(pCur);
++  pCur->eSkip = SKIP_NONE;
++  return rc;
++}
++
++/* Move the cursor so that it points to an entry near pKey.
++** Return a success code.
++**
++** If an exact match is not found, then the cursor is always
++** left pointing at a leaf page which would hold the entry if it
++** were present.  The cursor might point to an entry that comes
++** before or after the key.
++**
++** The result of comparing the key with the entry to which the
++** cursor is left pointing is stored in pCur->iMatch.  The same
++** value is also written to *pRes if pRes!=NULL.  The meaning of
++** this value is as follows:
++**
++**     *pRes<0      The cursor is left pointing at an entry that
++**                  is smaller than pKey or if the table is empty
++**                  and the cursor is therefore left point to nothing.
++**
++**     *pRes==0     The cursor is left pointing at an entry that
++**                  exactly matches pKey.
++**
++**     *pRes>0      The cursor is left pointing at an entry that
++**                  is larger than pKey.
++*/
++static
++int fileBtreeMoveto(BtCursor *pCur, const void *pKey, int nKey, int *pRes){
++  int rc;
++  if( pCur->pPage==0 ) return SQLITE_ABORT;
++  pCur->eSkip = SKIP_NONE;
++  rc = moveToRoot(pCur);
++  if( rc ) return rc;
++  for(;;){
++    int lwr, upr;
++    Pgno chldPg;
++    MemPage *pPage = pCur->pPage;
++    int c = -1;  /* pRes return if table is empty must be -1 */
++    lwr = 0;
++    upr = pPage->nCell-1;
++    while( lwr<=upr ){
++      pCur->idx = (lwr+upr)/2;
++      rc = fileBtreeKeyCompare(pCur, pKey, nKey, 0, &c);
++      if( rc ) return rc;
++      if( c==0 ){
++        pCur->iMatch = c;
++        if( pRes ) *pRes = 0;
++        return SQLITE_OK;
++      }
++      if( c<0 ){
++        lwr = pCur->idx+1;
++      }else{
++        upr = pCur->idx-1;
++      }
++    }
++    assert( lwr==upr+1 );
++    assert( pPage->isInit );
++    if( lwr>=pPage->nCell ){
++      chldPg = pPage->u.hdr.rightChild;
++    }else{
++      chldPg = pPage->apCell[lwr]->h.leftChild;
++    }
++    if( chldPg==0 ){
++      pCur->iMatch = c;
++      if( pRes ) *pRes = c;
++      return SQLITE_OK;
++    }
++    pCur->idx = lwr;
++    rc = moveToChild(pCur, chldPg);
++    if( rc ) return rc;
++  }
++  /* NOT REACHED */
++}
++
++/*
++** 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.
++*/
++static int fileBtreeNext(BtCursor *pCur, int *pRes){
++  int rc;
++  MemPage *pPage = pCur->pPage;
++  assert( pRes!=0 );
++  if( pPage==0 ){
++    *pRes = 1;
++    return SQLITE_ABORT;
++  }
++  assert( pPage->isInit );
++  assert( pCur->eSkip!=SKIP_INVALID );
++  if( pPage->nCell==0 ){
++    *pRes = 1;
++    return SQLITE_OK;
++  }
++  assert( pCur->idx<pPage->nCell );
++  if( pCur->eSkip==SKIP_NEXT ){
++    pCur->eSkip = SKIP_NONE;
++    *pRes = 0;
++    return SQLITE_OK;
++  }
++  pCur->eSkip = SKIP_NONE;
++  pCur->idx++;
++  if( pCur->idx>=pPage->nCell ){
++    if( pPage->u.hdr.rightChild ){
++      rc = moveToChild(pCur, pPage->u.hdr.rightChild);
++      if( rc ) return rc;
++      rc = moveToLeftmost(pCur);
++      *pRes = 0;
++      return rc;
++    }
++    do{
++      if( pPage->pParent==0 ){
++        *pRes = 1;
++        return SQLITE_OK;
++      }
++      moveToParent(pCur);
++      pPage = pCur->pPage;
++    }while( pCur->idx>=pPage->nCell );
++    *pRes = 0;
++    return SQLITE_OK;
++  }
++  *pRes = 0;
++  if( pPage->u.hdr.rightChild==0 ){
++    return SQLITE_OK;
++  }
++  rc = moveToLeftmost(pCur);
++  return rc;
++}
++
++/*
++** Step the cursor to the back to the previous entry in the database.  If
++** successful then set *pRes=0.  If the cursor
++** was already pointing to the first entry in the database before
++** this routine was called, then set *pRes=1.
++*/
++static int fileBtreePrevious(BtCursor *pCur, int *pRes){
++  int rc;
++  Pgno pgno;
++  MemPage *pPage;
++  pPage = pCur->pPage;
++  if( pPage==0 ){
++    *pRes = 1;
++    return SQLITE_ABORT;
++  }
++  assert( pPage->isInit );
++  assert( pCur->eSkip!=SKIP_INVALID );
++  if( pPage->nCell==0 ){
++    *pRes = 1;
++    return SQLITE_OK;
++  }
++  if( pCur->eSkip==SKIP_PREV ){
++    pCur->eSkip = SKIP_NONE;
++    *pRes = 0;
++    return SQLITE_OK;
++  }
++  pCur->eSkip = SKIP_NONE;
++  assert( pCur->idx>=0 );
++  if( (pgno = pPage->apCell[pCur->idx]->h.leftChild)!=0 ){
++    rc = moveToChild(pCur, pgno);
++    if( rc ) return rc;
++    rc = moveToRightmost(pCur);
++  }else{
++    while( pCur->idx==0 ){
++      if( pPage->pParent==0 ){
++        if( pRes ) *pRes = 1;
++        return SQLITE_OK;
++      }
++      moveToParent(pCur);
++      pPage = pCur->pPage;
++    }
++    pCur->idx--;
++    rc = SQLITE_OK;
++  }
++  *pRes = 0;
++  return rc;
++}
++
++/*
++** Allocate a new page from the database file.
++**
++** The new page is marked as dirty.  (In other words, sqlitepager_write()
++** has already been called on the new page.)  The new page has also
++** been referenced and the calling routine is responsible for calling
++** sqlitepager_unref() 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 sqlitepager_unref() 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
++** attempt to keep related pages close to each other in the database file,
++** which in turn can make database access faster.
++*/
++static int allocatePage(Btree *pBt, MemPage **ppPage, Pgno *pPgno, Pgno nearby){
++  PageOne *pPage1 = pBt->page1;
++  int rc;
++  if( pPage1->freeList ){
++    OverflowPage *pOvfl;
++    FreelistInfo *pInfo;
++
++    rc = sqlitepager_write(pPage1);
++    if( rc ) return rc;
++    SWAB_ADD(pBt, pPage1->nFree, -1);
++    rc = sqlitepager_get(pBt->pPager, SWAB32(pBt, pPage1->freeList),
++                        (void**)&pOvfl);
++    if( rc ) return rc;
++    rc = sqlitepager_write(pOvfl);
++    if( rc ){
++      sqlitepager_unref(pOvfl);
++      return rc;
++    }
++    pInfo = (FreelistInfo*)pOvfl->aPayload;
++    if( pInfo->nFree==0 ){
++      *pPgno = SWAB32(pBt, pPage1->freeList);
++      pPage1->freeList = pOvfl->iNext;
++      *ppPage = (MemPage*)pOvfl;
++    }else{
++      int closest, n;
++      n = SWAB32(pBt, pInfo->nFree);
++      if( n>1 && nearby>0 ){
++        int i, dist;
++        closest = 0;
++        dist = SWAB32(pBt, pInfo->aFree[0]) - nearby;
++        if( dist<0 ) dist = -dist;
++        for(i=1; i<n; i++){
++          int d2 = SWAB32(pBt, pInfo->aFree[i]) - nearby;
++          if( d2<0 ) d2 = -d2;
++          if( d2<dist ) closest = i;
++        }
++      }else{
++        closest = 0;
++      }
++      SWAB_ADD(pBt, pInfo->nFree, -1);
++      *pPgno = SWAB32(pBt, pInfo->aFree[closest]);
++      pInfo->aFree[closest] = pInfo->aFree[n-1];
++      rc = sqlitepager_get(pBt->pPager, *pPgno, (void**)ppPage);
++      sqlitepager_unref(pOvfl);
++      if( rc==SQLITE_OK ){
++        sqlitepager_dont_rollback(*ppPage);
++        rc = sqlitepager_write(*ppPage);
++      }
++    }
++  }else{
++    *pPgno = sqlitepager_pagecount(pBt->pPager) + 1;
++    rc = sqlitepager_get(pBt->pPager, *pPgno, (void**)ppPage);
++    if( rc ) return rc;
++    rc = sqlitepager_write(*ppPage);
++  }
++  return rc;
++}
++
++/*
++** Add a page of the database file to the freelist.  Either pgno or
++** pPage but not both may be 0. 
++**
++** sqlitepager_unref() is NOT called for pPage.
++*/
++static int freePage(Btree *pBt, void *pPage, Pgno pgno){
++  PageOne *pPage1 = pBt->page1;
++  OverflowPage *pOvfl = (OverflowPage*)pPage;
++  int rc;
++  int needUnref = 0;
++  MemPage *pMemPage;
++
++  if( pgno==0 ){
++    assert( pOvfl!=0 );
++    pgno = sqlitepager_pagenumber(pOvfl);
++  }
++  assert( pgno>2 );
++  assert( sqlitepager_pagenumber(pOvfl)==pgno );
++  pMemPage = (MemPage*)pPage;
++  pMemPage->isInit = 0;
++  if( pMemPage->pParent ){
++    sqlitepager_unref(pMemPage->pParent);
++    pMemPage->pParent = 0;
++  }
++  rc = sqlitepager_write(pPage1);
++  if( rc ){
++    return rc;
++  }
++  SWAB_ADD(pBt, pPage1->nFree, 1);
++  if( pPage1->nFree!=0 && pPage1->freeList!=0 ){
++    OverflowPage *pFreeIdx;
++    rc = sqlitepager_get(pBt->pPager, SWAB32(pBt, pPage1->freeList),
++                        (void**)&pFreeIdx);
++    if( rc==SQLITE_OK ){
++      FreelistInfo *pInfo = (FreelistInfo*)pFreeIdx->aPayload;
++      int n = SWAB32(pBt, pInfo->nFree);
++      if( n<(sizeof(pInfo->aFree)/sizeof(pInfo->aFree[0])) ){
++        rc = sqlitepager_write(pFreeIdx);
++        if( rc==SQLITE_OK ){
++          pInfo->aFree[n] = SWAB32(pBt, pgno);
++          SWAB_ADD(pBt, pInfo->nFree, 1);
++          sqlitepager_unref(pFreeIdx);
++          sqlitepager_dont_write(pBt->pPager, pgno);
++          return rc;
++        }
++      }
++      sqlitepager_unref(pFreeIdx);
++    }
++  }
++  if( pOvfl==0 ){
++    assert( pgno>0 );
++    rc = sqlitepager_get(pBt->pPager, pgno, (void**)&pOvfl);
++    if( rc ) return rc;
++    needUnref = 1;
++  }
++  rc = sqlitepager_write(pOvfl);
++  if( rc ){
++    if( needUnref ) sqlitepager_unref(pOvfl);
++    return rc;
++  }
++  pOvfl->iNext = pPage1->freeList;
++  pPage1->freeList = SWAB32(pBt, pgno);
++  memset(pOvfl->aPayload, 0, OVERFLOW_SIZE);
++  if( needUnref ) rc = sqlitepager_unref(pOvfl);
++  return rc;
++}
++
++/*
++** Erase all the data out of a cell.  This involves returning overflow
++** pages back the freelist.
++*/
++static int clearCell(Btree *pBt, Cell *pCell){
++  Pager *pPager = pBt->pPager;
++  OverflowPage *pOvfl;
++  Pgno ovfl, nextOvfl;
++  int rc;
++
++  if( NKEY(pBt, pCell->h) + NDATA(pBt, pCell->h) <= MX_LOCAL_PAYLOAD ){
++    return SQLITE_OK;
++  }
++  ovfl = SWAB32(pBt, pCell->ovfl);
++  pCell->ovfl = 0;
++  while( ovfl ){
++    rc = sqlitepager_get(pPager, ovfl, (void**)&pOvfl);
++    if( rc ) return rc;
++    nextOvfl = SWAB32(pBt, pOvfl->iNext);
++    rc = freePage(pBt, pOvfl, ovfl);
++    if( rc ) return rc;
++    sqlitepager_unref(pOvfl);
++    ovfl = nextOvfl;
++  }
++  return SQLITE_OK;
++}
++
++/*
++** Create a new cell from key and data.  Overflow pages are allocated as
++** necessary and linked to this cell.  
++*/
++static int fillInCell(
++  Btree *pBt,              /* The whole Btree.  Needed to allocate pages */
++  Cell *pCell,             /* Populate this Cell structure */
++  const void *pKey, int nKey,    /* The key */
++  const void *pData,int nData    /* The data */
++){
++  OverflowPage *pOvfl, *pPrior;
++  Pgno *pNext;
++  int spaceLeft;
++  int n, rc;
++  int nPayload;
++  const char *pPayload;
++  char *pSpace;
++  Pgno nearby = 0;
++
++  pCell->h.leftChild = 0;
++  pCell->h.nKey = SWAB16(pBt, nKey & 0xffff);
++  pCell->h.nKeyHi = nKey >> 16;
++  pCell->h.nData = SWAB16(pBt, nData & 0xffff);
++  pCell->h.nDataHi = nData >> 16;
++  pCell->h.iNext = 0;
++
++  pNext = &pCell->ovfl;
++  pSpace = pCell->aPayload;
++  spaceLeft = MX_LOCAL_PAYLOAD;
++  pPayload = pKey;
++  pKey = 0;
++  nPayload = nKey;
++  pPrior = 0;
++  while( nPayload>0 ){
++    if( spaceLeft==0 ){
++      rc = allocatePage(pBt, (MemPage**)&pOvfl, pNext, nearby);
++      if( rc ){
++        *pNext = 0;
++      }else{
++        nearby = *pNext;
++      }
++      if( pPrior ) sqlitepager_unref(pPrior);
++      if( rc ){
++        clearCell(pBt, pCell);
++        return rc;
++      }
++      if( pBt->needSwab ) *pNext = swab32(*pNext);
++      pPrior = pOvfl;
++      spaceLeft = OVERFLOW_SIZE;
++      pSpace = pOvfl->aPayload;
++      pNext = &pOvfl->iNext;
++    }
++    n = nPayload;
++    if( n>spaceLeft ) n = spaceLeft;
++    memcpy(pSpace, pPayload, n);
++    nPayload -= n;
++    if( nPayload==0 && pData ){
++      pPayload = pData;
++      nPayload = nData;
++      pData = 0;
++    }else{
++      pPayload += n;
++    }
++    spaceLeft -= n;
++    pSpace += n;
++  }
++  *pNext = 0;
++  if( pPrior ){
++    sqlitepager_unref(pPrior);
++  }
++  return SQLITE_OK;
++}
++
++/*
++** Change the MemPage.pParent pointer on the page whose number is
++** given in the second argument so that MemPage.pParent holds the
++** pointer in the third argument.
++*/
++static void reparentPage(Pager *pPager, Pgno pgno, MemPage *pNewParent,int idx){
++  MemPage *pThis;
++
++  if( pgno==0 ) return;
++  assert( pPager!=0 );
++  pThis = sqlitepager_lookup(pPager, pgno);
++  if( pThis && pThis->isInit ){
++    if( pThis->pParent!=pNewParent ){
++      if( pThis->pParent ) sqlitepager_unref(pThis->pParent);
++      pThis->pParent = pNewParent;
++      if( pNewParent ) sqlitepager_ref(pNewParent);
++    }
++    pThis->idxParent = idx;
++    sqlitepager_unref(pThis);
++  }
++}
++
++/*
++** Reparent all children of the given page to be the given page.
++** In other words, for every child of pPage, invoke reparentPage()
++** to make sure that each child knows that pPage is its parent.
++**
++** This routine gets called after you memcpy() one page into
++** another.
++*/
++static void reparentChildPages(Btree *pBt, MemPage *pPage){
++  int i;
++  Pager *pPager = pBt->pPager;
++  for(i=0; i<pPage->nCell; i++){
++    reparentPage(pPager, SWAB32(pBt, pPage->apCell[i]->h.leftChild), pPage, i);
++  }
++  reparentPage(pPager, SWAB32(pBt, pPage->u.hdr.rightChild), pPage, i);
++  pPage->idxShift = 0;
++}
++
++/*
++** Remove the i-th cell from pPage.  This routine effects pPage only.
++** The cell content is not freed or deallocated.  It is assumed that
++** the cell content has been copied someplace else.  This routine just
++** removes the reference to the cell from pPage.
++**
++** "sz" must be the number of bytes in the cell.
++**
++** Do not bother maintaining the integrity of the linked list of Cells.
++** Only the pPage->apCell[] array is important.  The relinkCellList() 
++** routine will be called soon after this routine in order to rebuild 
++** the linked list.
++*/
++static void dropCell(Btree *pBt, MemPage *pPage, int idx, int sz){
++  int j;
++  assert( idx>=0 && idx<pPage->nCell );
++  assert( sz==cellSize(pBt, pPage->apCell[idx]) );
++  assert( sqlitepager_iswriteable(pPage) );
++  freeSpace(pBt, pPage, Addr(pPage->apCell[idx]) - Addr(pPage), sz);
++  for(j=idx; j<pPage->nCell-1; j++){
++    pPage->apCell[j] = pPage->apCell[j+1];
++  }
++  pPage->nCell--;
++  pPage->idxShift = 1;
++}
++
++/*
++** Insert a new cell on pPage at cell index "i".  pCell points to the
++** content of the cell.
++**
++** If the cell content will fit on the page, then put it there.  If it
++** will not fit, then just make pPage->apCell[i] point to the content
++** and set pPage->isOverfull.  
++**
++** Do not bother maintaining the integrity of the linked list of Cells.
++** Only the pPage->apCell[] array is important.  The relinkCellList() 
++** routine will be called soon after this routine in order to rebuild 
++** the linked list.
++*/
++static void insertCell(Btree *pBt, MemPage *pPage, int i, Cell *pCell, int sz){
++  int idx, j;
++  assert( i>=0 && i<=pPage->nCell );
++  assert( sz==cellSize(pBt, pCell) );
++  assert( sqlitepager_iswriteable(pPage) );
++  idx = allocateSpace(pBt, pPage, sz);
++  for(j=pPage->nCell; j>i; j--){
++    pPage->apCell[j] = pPage->apCell[j-1];
++  }
++  pPage->nCell++;
++  if( idx<=0 ){
++    pPage->isOverfull = 1;
++    pPage->apCell[i] = pCell;
++  }else{
++    memcpy(&pPage->u.aDisk[idx], pCell, sz);
++    pPage->apCell[i] = (Cell*)&pPage->u.aDisk[idx];
++  }
++  pPage->idxShift = 1;
++}
++
++/*
++** Rebuild the linked list of cells on a page so that the cells
++** occur in the order specified by the pPage->apCell[] array.  
++** Invoke this routine once to repair damage after one or more
++** invocations of either insertCell() or dropCell().
++*/
++static void relinkCellList(Btree *pBt, MemPage *pPage){
++  int i;
++  u16 *pIdx;
++  assert( sqlitepager_iswriteable(pPage) );
++  pIdx = &pPage->u.hdr.firstCell;
++  for(i=0; i<pPage->nCell; i++){
++    int idx = Addr(pPage->apCell[i]) - Addr(pPage);
++    assert( idx>0 && idx<SQLITE_USABLE_SIZE );
++    *pIdx = SWAB16(pBt, idx);
++    pIdx = &pPage->apCell[i]->h.iNext;
++  }
++  *pIdx = 0;
++}
++
++/*
++** Make a copy of the contents of pFrom into pTo.  The pFrom->apCell[]
++** pointers that point into pFrom->u.aDisk[] must be adjusted to point
++** into pTo->u.aDisk[] instead.  But some pFrom->apCell[] entries might
++** not point to pFrom->u.aDisk[].  Those are unchanged.
++*/
++static void copyPage(MemPage *pTo, MemPage *pFrom){
++  uptr from, to;
++  int i;
++  memcpy(pTo->u.aDisk, pFrom->u.aDisk, SQLITE_USABLE_SIZE);
++  pTo->pParent = 0;
++  pTo->isInit = 1;
++  pTo->nCell = pFrom->nCell;
++  pTo->nFree = pFrom->nFree;
++  pTo->isOverfull = pFrom->isOverfull;
++  to = Addr(pTo);
++  from = Addr(pFrom);
++  for(i=0; i<pTo->nCell; i++){
++    uptr x = Addr(pFrom->apCell[i]);
++    if( x>from && x<from+SQLITE_USABLE_SIZE ){
++      *((uptr*)&pTo->apCell[i]) = x + to - from;
++    }else{
++      pTo->apCell[i] = pFrom->apCell[i];
++    }
++  }
++}
++
++/*
++** The following parameters determine how many adjacent pages get involved
++** in a balancing operation.  NN is the number of neighbors on either side
++** of the page that participate in the balancing operation.  NB is the
++** total number of pages that participate, including the target page and
++** NN neighbors on either side.
++**
++** The minimum value of NN is 1 (of course).  Increasing NN above 1
++** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance
++** in exchange for a larger degradation in INSERT and UPDATE performance.
++** The value of NN appears to give the best results overall.
++*/
++#define NN 1             /* Number of neighbors on either side of pPage */
++#define NB (NN*2+1)      /* Total pages involved in the balance */
++
++/*
++** This routine redistributes Cells on pPage and up to two siblings
++** of pPage so that all pages have about the same amount of free space.
++** Usually one sibling on either side of pPage is used in the balancing,
++** though both siblings might come from one side if pPage is the first
++** or last child of its parent.  If pPage has fewer than two siblings
++** (something which can only happen if pPage is the root page or a 
++** child of root) then all available siblings participate in the balancing.
++**
++** The number of siblings of pPage might be increased or decreased by
++** one in an effort to keep pages between 66% and 100% full. The root page
++** is special and is allowed to be less than 66% full. If pPage is 
++** the root page, then the depth of the tree might be increased
++** or decreased by one, as necessary, to keep the root page from being
++** overfull or empty.
++**
++** This routine calls relinkCellList() on its input page regardless of
++** whether or not it does any real balancing.  Client routines will typically
++** invoke insertCell() or dropCell() before calling this routine, so we
++** need to call relinkCellList() to clean up the mess that those other
++** routines left behind.
++**
++** pCur is left pointing to the same cell as when this routine was called
++** even if that cell gets moved to a different page.  pCur may be NULL.
++** Set the pCur parameter to NULL if you do not care about keeping track
++** of a cell as that will save this routine the work of keeping track of it.
++**
++** Note that when this routine is called, some of the Cells on pPage
++** might not actually be stored in pPage->u.aDisk[].  This can happen
++** if the page is overfull.  Part of the job of this routine is to
++** make sure all Cells for pPage once again fit in pPage->u.aDisk[].
++**
++** In the course of balancing the siblings of pPage, the parent of pPage
++** might become overfull or underfull.  If that happens, then this routine
++** is called recursively on the parent.
++**
++** If this routine fails for any reason, it might leave the database
++** in a corrupted state.  So if this routine fails, the database should
++** be rolled back.
++*/
++static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){
++  MemPage *pParent;            /* The parent of pPage */
++  int nCell;                   /* Number of cells in apCell[] */
++  int nOld;                    /* Number of pages in apOld[] */
++  int nNew;                    /* Number of pages in apNew[] */
++  int nDiv;                    /* Number of cells in apDiv[] */
++  int i, j, k;                 /* Loop counters */
++  int idx;                     /* Index of pPage in pParent->apCell[] */
++  int nxDiv;                   /* Next divider slot in pParent->apCell[] */
++  int rc;                      /* The return code */
++  int iCur;                    /* apCell[iCur] is the cell of the cursor */
++  MemPage *pOldCurPage;        /* The cursor originally points to this page */
++  int subtotal;                /* Subtotal of bytes in cells on one page */
++  MemPage *extraUnref = 0;     /* A page that needs to be unref-ed */
++  MemPage *apOld[NB];          /* pPage and up to two siblings */
++  Pgno pgnoOld[NB];            /* Page numbers for each page in apOld[] */
++  MemPage *apNew[NB+1];        /* pPage and up to NB siblings after balancing */
++  Pgno pgnoNew[NB+1];          /* Page numbers for each page in apNew[] */
++  int idxDiv[NB];              /* Indices of divider cells in pParent */
++  Cell *apDiv[NB];             /* Divider cells in pParent */
++  Cell aTemp[NB];              /* Temporary holding area for apDiv[] */
++  int cntNew[NB+1];            /* Index in apCell[] of cell after i-th page */
++  int szNew[NB+1];             /* Combined size of cells place on i-th page */
++  MemPage aOld[NB];            /* Temporary copies of pPage and its siblings */
++  Cell *apCell[(MX_CELL+2)*NB]; /* All cells from pages being balanced */
++  int szCell[(MX_CELL+2)*NB];  /* Local size of all cells */
++
++  /* 
++  ** Return without doing any work if pPage is neither overfull nor
++  ** underfull.
++  */
++  assert( sqlitepager_iswriteable(pPage) );
++  if( !pPage->isOverfull && pPage->nFree<SQLITE_USABLE_SIZE/2 
++        && pPage->nCell>=2){
++    relinkCellList(pBt, pPage);
++    return SQLITE_OK;
++  }
++
++  /*
++  ** Find the parent of the page to be balanceed.
++  ** If there is no parent, it means this page is the root page and
++  ** special rules apply.
++  */
++  pParent = pPage->pParent;
++  if( pParent==0 ){
++    Pgno pgnoChild;
++    MemPage *pChild;
++    assert( pPage->isInit );
++    if( pPage->nCell==0 ){
++      if( pPage->u.hdr.rightChild ){
++        /*
++        ** The root page is empty.  Copy the one child page
++        ** into the root page and return.  This reduces the depth
++        ** of the BTree by one.
++        */
++        pgnoChild = SWAB32(pBt, pPage->u.hdr.rightChild);
++        rc = sqlitepager_get(pBt->pPager, pgnoChild, (void**)&pChild);
++        if( rc ) return rc;
++        memcpy(pPage, pChild, SQLITE_USABLE_SIZE);
++        pPage->isInit = 0;
++        rc = initPage(pBt, pPage, sqlitepager_pagenumber(pPage), 0);
++        assert( rc==SQLITE_OK );
++        reparentChildPages(pBt, pPage);
++        if( pCur && pCur->pPage==pChild ){
++          sqlitepager_unref(pChild);
++          pCur->pPage = pPage;
++          sqlitepager_ref(pPage);
++        }
++        freePage(pBt, pChild, pgnoChild);
++        sqlitepager_unref(pChild);
++      }else{
++        relinkCellList(pBt, pPage);
++      }
++      return SQLITE_OK;
++    }
++    if( !pPage->isOverfull ){
++      /* It is OK for the root page to be less than half full.
++      */
++      relinkCellList(pBt, pPage);
++      return SQLITE_OK;
++    }
++    /*
++    ** If we get to here, it means the root page is overfull.
++    ** When this happens, Create a new child page and copy the
++    ** contents of the root into the child.  Then make the root
++    ** page an empty page with rightChild pointing to the new
++    ** child.  Then fall thru to the code below which will cause
++    ** the overfull child page to be split.
++    */
++    rc = sqlitepager_write(pPage);
++    if( rc ) return rc;
++    rc = allocatePage(pBt, &pChild, &pgnoChild, sqlitepager_pagenumber(pPage));
++    if( rc ) return rc;
++    assert( sqlitepager_iswriteable(pChild) );
++    copyPage(pChild, pPage);
++    pChild->pParent = pPage;
++    pChild->idxParent = 0;
++    sqlitepager_ref(pPage);
++    pChild->isOverfull = 1;
++    if( pCur && pCur->pPage==pPage ){
++      sqlitepager_unref(pPage);
++      pCur->pPage = pChild;
++    }else{
++      extraUnref = pChild;
++    }
++    zeroPage(pBt, pPage);
++    pPage->u.hdr.rightChild = SWAB32(pBt, pgnoChild);
++    pParent = pPage;
++    pPage = pChild;
++  }
++  rc = sqlitepager_write(pParent);
++  if( rc ) return rc;
++  assert( pParent->isInit );
++  
++  /*
++  ** Find the Cell in the parent page whose h.leftChild points back
++  ** to pPage.  The "idx" variable is the index of that cell.  If pPage
++  ** is the rightmost child of pParent then set idx to pParent->nCell 
++  */
++  if( pParent->idxShift ){
++    Pgno pgno, swabPgno;
++    pgno = sqlitepager_pagenumber(pPage);
++    swabPgno = SWAB32(pBt, pgno);
++    for(idx=0; idx<pParent->nCell; idx++){
++      if( pParent->apCell[idx]->h.leftChild==swabPgno ){
++        break;
++      }
++    }
++    assert( idx<pParent->nCell || pParent->u.hdr.rightChild==swabPgno );
++  }else{
++    idx = pPage->idxParent;
++  }
++
++  /*
++  ** Initialize variables so that it will be safe to jump
++  ** directly to balance_cleanup at any moment.
++  */
++  nOld = nNew = 0;
++  sqlitepager_ref(pParent);
++
++  /*
++  ** Find sibling pages to pPage and the Cells in pParent that divide
++  ** the siblings.  An attempt is made to find NN siblings on either
++  ** side of pPage.  More siblings are taken from one side, however, if
++  ** pPage there are fewer than NN siblings on the other side.  If pParent
++  ** has NB or fewer children then all children of pParent are taken.
++  */
++  nxDiv = idx - NN;
++  if( nxDiv + NB > pParent->nCell ){
++    nxDiv = pParent->nCell - NB + 1;
++  }
++  if( nxDiv<0 ){
++    nxDiv = 0;
++  }
++  nDiv = 0;
++  for(i=0, k=nxDiv; i<NB; i++, k++){
++    if( k<pParent->nCell ){
++      idxDiv[i] = k;
++      apDiv[i] = pParent->apCell[k];
++      nDiv++;
++      pgnoOld[i] = SWAB32(pBt, apDiv[i]->h.leftChild);
++    }else if( k==pParent->nCell ){
++      pgnoOld[i] = SWAB32(pBt, pParent->u.hdr.rightChild);
++    }else{
++      break;
++    }
++    rc = sqlitepager_get(pBt->pPager, pgnoOld[i], (void**)&apOld[i]);
++    if( rc ) goto balance_cleanup;
++    rc = initPage(pBt, apOld[i], pgnoOld[i], pParent);
++    if( rc ) goto balance_cleanup;
++    apOld[i]->idxParent = k;
++    nOld++;
++  }
++
++  /*
++  ** Set iCur to be the index in apCell[] of the cell that the cursor
++  ** is pointing to.  We will need this later on in order to keep the
++  ** cursor pointing at the same cell.  If pCur points to a page that
++  ** has no involvement with this rebalancing, then set iCur to a large
++  ** number so that the iCur==j tests always fail in the main cell
++  ** distribution loop below.
++  */
++  if( pCur ){
++    iCur = 0;
++    for(i=0; i<nOld; i++){
++      if( pCur->pPage==apOld[i] ){
++        iCur += pCur->idx;
++        break;
++      }
++      iCur += apOld[i]->nCell;
++      if( i<nOld-1 && pCur->pPage==pParent && pCur->idx==idxDiv[i] ){
++        break;
++      }
++      iCur++;
++    }
++    pOldCurPage = pCur->pPage;
++  }
++
++  /*
++  ** Make copies of the content of pPage and its siblings into aOld[].
++  ** The rest of this function will use data from the copies rather
++  ** that the original pages since the original pages will be in the
++  ** process of being overwritten.
++  */
++  for(i=0; i<nOld; i++){
++    copyPage(&aOld[i], apOld[i]);
++  }
++
++  /*
++  ** Load pointers to all cells on sibling pages and the divider cells
++  ** into the local apCell[] array.  Make copies of the divider cells
++  ** into aTemp[] and remove the the divider Cells from pParent.
++  */
++  nCell = 0;
++  for(i=0; i<nOld; i++){
++    MemPage *pOld = &aOld[i];
++    for(j=0; j<pOld->nCell; j++){
++      apCell[nCell] = pOld->apCell[j];
++      szCell[nCell] = cellSize(pBt, apCell[nCell]);
++      nCell++;
++    }
++    if( i<nOld-1 ){
++      szCell[nCell] = cellSize(pBt, apDiv[i]);
++      memcpy(&aTemp[i], apDiv[i], szCell[nCell]);
++      apCell[nCell] = &aTemp[i];
++      dropCell(pBt, pParent, nxDiv, szCell[nCell]);
++      assert( SWAB32(pBt, apCell[nCell]->h.leftChild)==pgnoOld[i] );
++      apCell[nCell]->h.leftChild = pOld->u.hdr.rightChild;
++      nCell++;
++    }
++  }
++
++  /*
++  ** Figure out the number of pages needed to hold all nCell cells.
++  ** Store this number in "k".  Also compute szNew[] which is the total
++  ** size of all cells on the i-th page and cntNew[] which is the index
++  ** in apCell[] of the cell that divides path i from path i+1.  
++  ** cntNew[k] should equal nCell.
++  **
++  ** This little patch of code is critical for keeping the tree
++  ** balanced. 
++  */
++  for(subtotal=k=i=0; i<nCell; i++){
++    subtotal += szCell[i];
++    if( subtotal > USABLE_SPACE ){
++      szNew[k] = subtotal - szCell[i];
++      cntNew[k] = i;
++      subtotal = 0;
++      k++;
++    }
++  }
++  szNew[k] = subtotal;
++  cntNew[k] = nCell;
++  k++;
++  for(i=k-1; i>0; i--){
++    while( szNew[i]<USABLE_SPACE/2 ){
++      cntNew[i-1]--;
++      assert( cntNew[i-1]>0 );
++      szNew[i] += szCell[cntNew[i-1]];
++      szNew[i-1] -= szCell[cntNew[i-1]-1];
++    }
++  }
++  assert( cntNew[0]>0 );
++
++  /*
++  ** Allocate k new pages.  Reuse old pages where possible.
++  */
++  for(i=0; i<k; i++){
++    if( i<nOld ){
++      apNew[i] = apOld[i];
++      pgnoNew[i] = pgnoOld[i];
++      apOld[i] = 0;
++      sqlitepager_write(apNew[i]);
++    }else{
++      rc = allocatePage(pBt, &apNew[i], &pgnoNew[i], pgnoNew[i-1]);
++      if( rc ) goto balance_cleanup;
++    }
++    nNew++;
++    zeroPage(pBt, apNew[i]);
++    apNew[i]->isInit = 1;
++  }
++
++  /* Free any old pages that were not reused as new pages.
++  */
++  while( i<nOld ){
++    rc = freePage(pBt, apOld[i], pgnoOld[i]);
++    if( rc ) goto balance_cleanup;
++    sqlitepager_unref(apOld[i]);
++    apOld[i] = 0;
++    i++;
++  }
++
++  /*
++  ** Put the new pages in accending order.  This helps to
++  ** keep entries in the disk file in order so that a scan
++  ** of the table is a linear scan through the file.  That
++  ** in turn helps the operating system to deliver pages
++  ** from the disk more rapidly.
++  **
++  ** An O(n^2) insertion sort algorithm is used, but since
++  ** n is never more than NB (a small constant), that should
++  ** not be a problem.
++  **
++  ** When NB==3, this one optimization makes the database
++  ** about 25% faster for large insertions and deletions.
++  */
++  for(i=0; i<k-1; i++){
++    int minV = pgnoNew[i];
++    int minI = i;
++    for(j=i+1; j<k; j++){
++      if( pgnoNew[j]<(unsigned)minV ){
++        minI = j;
++        minV = pgnoNew[j];
++      }
++    }
++    if( minI>i ){
++      int t;
++      MemPage *pT;
++      t = pgnoNew[i];
++      pT = apNew[i];
++      pgnoNew[i] = pgnoNew[minI];
++      apNew[i] = apNew[minI];
++      pgnoNew[minI] = t;
++      apNew[minI] = pT;
++    }
++  }
++
++  /*
++  ** Evenly distribute the data in apCell[] across the new pages.
++  ** Insert divider cells into pParent as necessary.
++  */
++  j = 0;
++  for(i=0; i<nNew; i++){
++    MemPage *pNew = apNew[i];
++    while( j<cntNew[i] ){
++      assert( pNew->nFree>=szCell[j] );
++      if( pCur && iCur==j ){ pCur->pPage = pNew; pCur->idx = pNew->nCell; }
++      insertCell(pBt, pNew, pNew->nCell, apCell[j], szCell[j]);
++      j++;
++    }
++    assert( pNew->nCell>0 );
++    assert( !pNew->isOverfull );
++    relinkCellList(pBt, pNew);
++    if( i<nNew-1 && j<nCell ){
++      pNew->u.hdr.rightChild = apCell[j]->h.leftChild;
++      apCell[j]->h.leftChild = SWAB32(pBt, pgnoNew[i]);
++      if( pCur && iCur==j ){ pCur->pPage = pParent; pCur->idx = nxDiv; }
++      insertCell(pBt, pParent, nxDiv, apCell[j], szCell[j]);
++      j++;
++      nxDiv++;
++    }
++  }
++  assert( j==nCell );
++  apNew[nNew-1]->u.hdr.rightChild = aOld[nOld-1].u.hdr.rightChild;
++  if( nxDiv==pParent->nCell ){
++    pParent->u.hdr.rightChild = SWAB32(pBt, pgnoNew[nNew-1]);
++  }else{
++    pParent->apCell[nxDiv]->h.leftChild = SWAB32(pBt, pgnoNew[nNew-1]);
++  }
++  if( pCur ){
++    if( j<=iCur && pCur->pPage==pParent && pCur->idx>idxDiv[nOld-1] ){
++      assert( pCur->pPage==pOldCurPage );
++      pCur->idx += nNew - nOld;
++    }else{
++      assert( pOldCurPage!=0 );
++      sqlitepager_ref(pCur->pPage);
++      sqlitepager_unref(pOldCurPage);
++    }
++  }
++
++  /*
++  ** Reparent children of all cells.
++  */
++  for(i=0; i<nNew; i++){
++    reparentChildPages(pBt, apNew[i]);
++  }
++  reparentChildPages(pBt, pParent);
++
++  /*
++  ** balance the parent page.
++  */
++  rc = balance(pBt, pParent, pCur);
++
++  /*
++  ** Cleanup before returning.
++  */
++balance_cleanup:
++  if( extraUnref ){
++    sqlitepager_unref(extraUnref);
++  }
++  for(i=0; i<nOld; i++){
++    if( apOld[i]!=0 && apOld[i]!=&aOld[i] ) sqlitepager_unref(apOld[i]);
++  }
++  for(i=0; i<nNew; i++){
++    sqlitepager_unref(apNew[i]);
++  }
++  if( pCur && pCur->pPage==0 ){
++    pCur->pPage = pParent;
++    pCur->idx = 0;
++  }else{
++    sqlitepager_unref(pParent);
++  }
++  return rc;
++}
++
++/*
++** This routine checks all cursors that point to the same table
++** as pCur points to.  If any of those cursors were opened with
++** wrFlag==0 then this routine returns SQLITE_LOCKED.  If all
++** cursors point to the same table were opened with wrFlag==1
++** then this routine returns SQLITE_OK.
++**
++** 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 pCur so that they are pointing to the 
++** first Cell on 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(BtCursor *pCur){
++  BtCursor *p;
++  assert( pCur->wrFlag );
++  for(p=pCur->pShared; p!=pCur; p=p->pShared){
++    assert( p );
++    assert( p->pgnoRoot==pCur->pgnoRoot );
++    if( p->wrFlag==0 ) return SQLITE_LOCKED;
++    if( sqlitepager_pagenumber(p->pPage)!=p->pgnoRoot ){
++      moveToRoot(p);
++    }
++  }
++  return SQLITE_OK;
++}
++
++/*
++** Insert a new record into the BTree.  The key is given by (pKey,nKey)
++** and the data is given by (pData,nData).  The cursor is used only to
++** define what database the record should be inserted into.  The cursor
++** is left pointing at the new record.
++*/
++static int fileBtreeInsert(
++  BtCursor *pCur,                /* Insert data into the table of this cursor */
++  const void *pKey, int nKey,    /* The key of the new record */
++  const void *pData, int nData   /* The data of the new record */
++){
++  Cell newCell;
++  int rc;
++  int loc;
++  int szNew;
++  MemPage *pPage;
++  Btree *pBt = pCur->pBt;
++
++  if( pCur->pPage==0 ){
++    return SQLITE_ABORT;  /* A rollback destroyed this cursor */
++  }
++  if( !pBt->inTrans || nKey+nData==0 ){
++    /* Must start a transaction before doing an insert */
++    return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
++  }
++  assert( !pBt->readOnly );
++  if( !pCur->wrFlag ){
++    return SQLITE_PERM;   /* Cursor not open for writing */
++  }
++  if( checkReadLocks(pCur) ){
++    return SQLITE_LOCKED; /* The table pCur points to has a read lock */
++  }
++  rc = fileBtreeMoveto(pCur, pKey, nKey, &loc);
++  if( rc ) return rc;
++  pPage = pCur->pPage;
++  assert( pPage->isInit );
++  rc = sqlitepager_write(pPage);
++  if( rc ) return rc;
++  rc = fillInCell(pBt, &newCell, pKey, nKey, pData, nData);
++  if( rc ) return rc;
++  szNew = cellSize(pBt, &newCell);
++  if( loc==0 ){
++    newCell.h.leftChild = pPage->apCell[pCur->idx]->h.leftChild;
++    rc = clearCell(pBt, pPage->apCell[pCur->idx]);
++    if( rc ) return rc;
++    dropCell(pBt, pPage, pCur->idx, cellSize(pBt, pPage->apCell[pCur->idx]));
++  }else if( loc<0 && pPage->nCell>0 ){
++    assert( pPage->u.hdr.rightChild==0 );  /* Must be a leaf page */
++    pCur->idx++;
++  }else{
++    assert( pPage->u.hdr.rightChild==0 );  /* Must be a leaf page */
++  }
++  insertCell(pBt, pPage, pCur->idx, &newCell, szNew);
++  rc = balance(pCur->pBt, pPage, pCur);
++  /* sqliteBtreePageDump(pCur->pBt, pCur->pgnoRoot, 1); */
++  /* fflush(stdout); */
++  pCur->eSkip = SKIP_INVALID;
++  return rc;
++}
++
++/*
++** Delete the entry that the cursor is pointing to.
++**
++** The cursor is left pointing at either the next or the previous
++** entry.  If the cursor is left pointing to the next entry, then 
++** the pCur->eSkip flag is set to SKIP_NEXT which forces the next call to 
++** sqliteBtreeNext() to be a no-op.  That way, you can always call
++** sqliteBtreeNext() after a delete and the cursor will be left
++** pointing to the first entry after the deleted entry.  Similarly,
++** pCur->eSkip is set to SKIP_PREV is the cursor is left pointing to
++** the entry prior to the deleted entry so that a subsequent call to
++** sqliteBtreePrevious() will always leave the cursor pointing at the
++** entry immediately before the one that was deleted.
++*/
++static int fileBtreeDelete(BtCursor *pCur){
++  MemPage *pPage = pCur->pPage;
++  Cell *pCell;
++  int rc;
++  Pgno pgnoChild;
++  Btree *pBt = pCur->pBt;
++
++  assert( pPage->isInit );
++  if( pCur->pPage==0 ){
++    return SQLITE_ABORT;  /* A rollback destroyed this cursor */
++  }
++  if( !pBt->inTrans ){
++    /* Must start a transaction before doing a delete */
++    return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
++  }
++  assert( !pBt->readOnly );
++  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(pCur) ){
++    return SQLITE_LOCKED; /* The table pCur points to has a read lock */
++  }
++  rc = sqlitepager_write(pPage);
++  if( rc ) return rc;
++  pCell = pPage->apCell[pCur->idx];
++  pgnoChild = SWAB32(pBt, pCell->h.leftChild);
++  clearCell(pBt, pCell);
++  if( pgnoChild ){
++    /*
++    ** The entry we are about to delete is not a leaf so if we do not
++    ** do something we will leave a hole on an internal page.
++    ** We have to fill the hole by moving in a cell from a leaf.  The
++    ** next Cell after the one to be deleted is guaranteed to exist and
++    ** to be a leaf so we can use it.
++    */
++    BtCursor leafCur;
++    Cell *pNext;
++    int szNext;
++    int notUsed;
++    getTempCursor(pCur, &leafCur);
++    rc = fileBtreeNext(&leafCur, &notUsed);
++    if( rc!=SQLITE_OK ){
++      if( rc!=SQLITE_NOMEM ) rc = SQLITE_CORRUPT;
++      return rc;
++    }
++    rc = sqlitepager_write(leafCur.pPage);
++    if( rc ) return rc;
++    dropCell(pBt, pPage, pCur->idx, cellSize(pBt, pCell));
++    pNext = leafCur.pPage->apCell[leafCur.idx];
++    szNext = cellSize(pBt, pNext);
++    pNext->h.leftChild = SWAB32(pBt, pgnoChild);
++    insertCell(pBt, pPage, pCur->idx, pNext, szNext);
++    rc = balance(pBt, pPage, pCur);
++    if( rc ) return rc;
++    pCur->eSkip = SKIP_NEXT;
++    dropCell(pBt, leafCur.pPage, leafCur.idx, szNext);
++    rc = balance(pBt, leafCur.pPage, pCur);
++    releaseTempCursor(&leafCur);
++  }else{
++    dropCell(pBt, pPage, pCur->idx, cellSize(pBt, pCell));
++    if( pCur->idx>=pPage->nCell ){
++      pCur->idx = pPage->nCell-1;
++      if( pCur->idx<0 ){ 
++        pCur->idx = 0;
++        pCur->eSkip = SKIP_NEXT;
++      }else{
++        pCur->eSkip = SKIP_PREV;
++      }
++    }else{
++      pCur->eSkip = SKIP_NEXT;
++    }
++    rc = balance(pBt, pPage, pCur);
++  }
++  return rc;
++}
++
++/*
++** Create a new BTree table.  Write into *piTable the page
++** number for the root page of the new table.
++**
++** In the current implementation, BTree tables and BTree indices are the 
++** the same.  In the future, we may change this so that BTree tables
++** are restricted to having a 4-byte integer key and arbitrary data and
++** BTree indices are restricted to having an arbitrary key and no data.
++** But for now, this routine also serves to create indices.
++*/
++static int fileBtreeCreateTable(Btree *pBt, int *piTable){
++  MemPage *pRoot;
++  Pgno pgnoRoot;
++  int rc;
++  if( !pBt->inTrans ){
++    /* Must start a transaction first */
++    return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
++  }
++  if( pBt->readOnly ){
++    return SQLITE_READONLY;
++  }
++  rc = allocatePage(pBt, &pRoot, &pgnoRoot, 0);
++  if( rc ) return rc;
++  assert( sqlitepager_iswriteable(pRoot) );
++  zeroPage(pBt, pRoot);
++  sqlitepager_unref(pRoot);
++  *piTable = (int)pgnoRoot;
++  return SQLITE_OK;
++}
++
++/*
++** Erase the given database page and all its children.  Return
++** the page to the freelist.
++*/
++static int clearDatabasePage(Btree *pBt, Pgno pgno, int freePageFlag){
++  MemPage *pPage;
++  int rc;
++  Cell *pCell;
++  int idx;
++
++  rc = sqlitepager_get(pBt->pPager, pgno, (void**)&pPage);
++  if( rc ) return rc;
++  rc = sqlitepager_write(pPage);
++  if( rc ) return rc;
++  rc = initPage(pBt, pPage, pgno, 0);
++  if( rc ) return rc;
++  idx = SWAB16(pBt, pPage->u.hdr.firstCell);
++  while( idx>0 ){
++    pCell = (Cell*)&pPage->u.aDisk[idx];
++    idx = SWAB16(pBt, pCell->h.iNext);
++    if( pCell->h.leftChild ){
++      rc = clearDatabasePage(pBt, SWAB32(pBt, pCell->h.leftChild), 1);
++      if( rc ) return rc;
++    }
++    rc = clearCell(pBt, pCell);
++    if( rc ) return rc;
++  }
++  if( pPage->u.hdr.rightChild ){
++    rc = clearDatabasePage(pBt, SWAB32(pBt, pPage->u.hdr.rightChild), 1);
++    if( rc ) return rc;
++  }
++  if( freePageFlag ){
++    rc = freePage(pBt, pPage, pgno);
++  }else{
++    zeroPage(pBt, pPage);
++  }
++  sqlitepager_unref(pPage);
++  return rc;
++}
++
++/*
++** Delete all information from a single table in the database.
++*/
++static int fileBtreeClearTable(Btree *pBt, int iTable){
++  int rc;
++  BtCursor *pCur;
++  if( !pBt->inTrans ){
++    return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
++  }
++  for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
++    if( pCur->pgnoRoot==(Pgno)iTable ){
++      if( pCur->wrFlag==0 ) return SQLITE_LOCKED;
++      moveToRoot(pCur);
++    }
++  }
++  rc = clearDatabasePage(pBt, (Pgno)iTable, 0);
++  if( rc ){
++    fileBtreeRollback(pBt);
++  }
++  return rc;
++}
++
++/*
++** Erase all information in a table and add the root of the table to
++** the freelist.  Except, the root of the principle table (the one on
++** page 2) is never added to the freelist.
++*/
++static int fileBtreeDropTable(Btree *pBt, int iTable){
++  int rc;
++  MemPage *pPage;
++  BtCursor *pCur;
++  if( !pBt->inTrans ){
++    return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
++  }
++  for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
++    if( pCur->pgnoRoot==(Pgno)iTable ){
++      return SQLITE_LOCKED;  /* Cannot drop a table that has a cursor */
++    }
++  }
++  rc = sqlitepager_get(pBt->pPager, (Pgno)iTable, (void**)&pPage);
++  if( rc ) return rc;
++  rc = fileBtreeClearTable(pBt, iTable);
++  if( rc ) return rc;
++  if( iTable>2 ){
++    rc = freePage(pBt, pPage, iTable);
++  }else{
++    zeroPage(pBt, pPage);
++  }
++  sqlitepager_unref(pPage);
++  return rc;  
++}
++
++#if 0 /* UNTESTED */
++/*
++** Copy all cell data from one database file into another.
++** pages back the freelist.
++*/
++static int copyCell(Btree *pBtFrom, BTree *pBtTo, Cell *pCell){
++  Pager *pFromPager = pBtFrom->pPager;
++  OverflowPage *pOvfl;
++  Pgno ovfl, nextOvfl;
++  Pgno *pPrev;
++  int rc = SQLITE_OK;
++  MemPage *pNew, *pPrevPg;
++  Pgno new;
++
++  if( NKEY(pBtTo, pCell->h) + NDATA(pBtTo, pCell->h) <= MX_LOCAL_PAYLOAD ){
++    return SQLITE_OK;
++  }
++  pPrev = &pCell->ovfl;
++  pPrevPg = 0;
++  ovfl = SWAB32(pBtTo, pCell->ovfl);
++  while( ovfl && rc==SQLITE_OK ){
++    rc = sqlitepager_get(pFromPager, ovfl, (void**)&pOvfl);
++    if( rc ) return rc;
++    nextOvfl = SWAB32(pBtFrom, pOvfl->iNext);
++    rc = allocatePage(pBtTo, &pNew, &new, 0);
++    if( rc==SQLITE_OK ){
++      rc = sqlitepager_write(pNew);
++      if( rc==SQLITE_OK ){
++        memcpy(pNew, pOvfl, SQLITE_USABLE_SIZE);
++        *pPrev = SWAB32(pBtTo, new);
++        if( pPrevPg ){
++          sqlitepager_unref(pPrevPg);
++        }
++        pPrev = &pOvfl->iNext;
++        pPrevPg = pNew;
++      }
++    }
++    sqlitepager_unref(pOvfl);
++    ovfl = nextOvfl;
++  }
++  if( pPrevPg ){
++    sqlitepager_unref(pPrevPg);
++  }
++  return rc;
++}
++#endif
++
++
++#if 0 /* UNTESTED */
++/*
++** Copy a page of data from one database over to another.
++*/
++static int copyDatabasePage(
++  Btree *pBtFrom,
++  Pgno pgnoFrom,
++  Btree *pBtTo,
++  Pgno *pTo
++){
++  MemPage *pPageFrom, *pPage;
++  Pgno to;
++  int rc;
++  Cell *pCell;
++  int idx;
++
++  rc = sqlitepager_get(pBtFrom->pPager, pgno, (void**)&pPageFrom);
++  if( rc ) return rc;
++  rc = allocatePage(pBt, &pPage, pTo, 0);
++  if( rc==SQLITE_OK ){
++    rc = sqlitepager_write(pPage);
++  }
++  if( rc==SQLITE_OK ){
++    memcpy(pPage, pPageFrom, SQLITE_USABLE_SIZE);
++    idx = SWAB16(pBt, pPage->u.hdr.firstCell);
++    while( idx>0 ){
++      pCell = (Cell*)&pPage->u.aDisk[idx];
++      idx = SWAB16(pBt, pCell->h.iNext);
++      if( pCell->h.leftChild ){
++        Pgno newChld;
++        rc = copyDatabasePage(pBtFrom, SWAB32(pBtFrom, pCell->h.leftChild),
++                              pBtTo, &newChld);
++        if( rc ) return rc;
++        pCell->h.leftChild = SWAB32(pBtFrom, newChld);
++      }
++      rc = copyCell(pBtFrom, pBtTo, pCell);
++      if( rc ) return rc;
++    }
++    if( pPage->u.hdr.rightChild ){
++      Pgno newChld;
++      rc = copyDatabasePage(pBtFrom, SWAB32(pBtFrom, pPage->u.hdr.rightChild), 
++                            pBtTo, &newChld);
++      if( rc ) return rc;
++      pPage->u.hdr.rightChild = SWAB32(pBtTo, newChild);
++    }
++  }
++  sqlitepager_unref(pPage);
++  return rc;
++}
++#endif
++
++/*
++** Read the meta-information out of a database file.
++*/
++static int fileBtreeGetMeta(Btree *pBt, int *aMeta){
++  PageOne *pP1;
++  int rc;
++  int i;
++
++  rc = sqlitepager_get(pBt->pPager, 1, (void**)&pP1);
++  if( rc ) return rc;
++  aMeta[0] = SWAB32(pBt, pP1->nFree);
++  for(i=0; i<sizeof(pP1->aMeta)/sizeof(pP1->aMeta[0]); i++){
++    aMeta[i+1] = SWAB32(pBt, pP1->aMeta[i]);
++  }
++  sqlitepager_unref(pP1);
++  return SQLITE_OK;
++}
++
++/*
++** Write meta-information back into the database.
++*/
++static int fileBtreeUpdateMeta(Btree *pBt, int *aMeta){
++  PageOne *pP1;
++  int rc, i;
++  if( !pBt->inTrans ){
++    return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
++  }
++  pP1 = pBt->page1;
++  rc = sqlitepager_write(pP1);
++  if( rc ) return rc;   
++  for(i=0; i<sizeof(pP1->aMeta)/sizeof(pP1->aMeta[0]); i++){
++    pP1->aMeta[i] = SWAB32(pBt, aMeta[i+1]);
++  }
++  return SQLITE_OK;
++}
++
++/******************************************************************************
++** The complete implementation of the BTree subsystem is above this line.
++** All the code the follows is for testing and troubleshooting the BTree
++** subsystem.  None of the code that follows is used during normal operation.
++******************************************************************************/
++
++/*
++** Print a disassembly of the given page on standard output.  This routine
++** is used for debugging and testing only.
++*/
++#ifdef SQLITE_TEST
++static int fileBtreePageDump(Btree *pBt, int pgno, int recursive){
++  int rc;
++  MemPage *pPage;
++  int i, j;
++  int nFree;
++  u16 idx;
++  char range[20];
++  unsigned char payload[20];
++  rc = sqlitepager_get(pBt->pPager, (Pgno)pgno, (void**)&pPage);
++  if( rc ){
++    return rc;
++  }
++  if( recursive ) printf("PAGE %d:\n", pgno);
++  i = 0;
++  idx = SWAB16(pBt, pPage->u.hdr.firstCell);
++  while( idx>0 && idx<=SQLITE_USABLE_SIZE-MIN_CELL_SIZE ){
++    Cell *pCell = (Cell*)&pPage->u.aDisk[idx];
++    int sz = cellSize(pBt, pCell);
++    sprintf(range,"%d..%d", idx, idx+sz-1);
++    sz = NKEY(pBt, pCell->h) + NDATA(pBt, pCell->h);
++    if( sz>sizeof(payload)-1 ) sz = sizeof(payload)-1;
++    memcpy(payload, pCell->aPayload, sz);
++    for(j=0; j<sz; j++){
++      if( payload[j]<0x20 || payload[j]>0x7f ) payload[j] = '.';
++    }
++    payload[sz] = 0;
++    printf(
++      "cell %2d: i=%-10s chld=%-4d nk=%-4d nd=%-4d payload=%s\n",
++      i, range, (int)pCell->h.leftChild, 
++      NKEY(pBt, pCell->h), NDATA(pBt, pCell->h),
++      payload
++    );
++    if( pPage->isInit && pPage->apCell[i]!=pCell ){
++      printf("**** apCell[%d] does not match on prior entry ****\n", i);
++    }
++    i++;
++    idx = SWAB16(pBt, pCell->h.iNext);
++  }
++  if( idx!=0 ){
++    printf("ERROR: next cell index out of range: %d\n", idx);
++  }
++  printf("right_child: %d\n", SWAB32(pBt, pPage->u.hdr.rightChild));
++  nFree = 0;
++  i = 0;
++  idx = SWAB16(pBt, pPage->u.hdr.firstFree);
++  while( idx>0 && idx<SQLITE_USABLE_SIZE ){
++    FreeBlk *p = (FreeBlk*)&pPage->u.aDisk[idx];
++    sprintf(range,"%d..%d", idx, idx+p->iSize-1);
++    nFree += SWAB16(pBt, p->iSize);
++    printf("freeblock %2d: i=%-10s size=%-4d total=%d\n",
++       i, range, SWAB16(pBt, p->iSize), nFree);
++    idx = SWAB16(pBt, p->iNext);
++    i++;
++  }
++  if( idx!=0 ){
++    printf("ERROR: next freeblock index out of range: %d\n", idx);
++  }
++  if( recursive && pPage->u.hdr.rightChild!=0 ){
++    idx = SWAB16(pBt, pPage->u.hdr.firstCell);
++    while( idx>0 && idx<SQLITE_USABLE_SIZE-MIN_CELL_SIZE ){
++      Cell *pCell = (Cell*)&pPage->u.aDisk[idx];
++      fileBtreePageDump(pBt, SWAB32(pBt, pCell->h.leftChild), 1);
++      idx = SWAB16(pBt, pCell->h.iNext);
++    }
++    fileBtreePageDump(pBt, SWAB32(pBt, pPage->u.hdr.rightChild), 1);
++  }
++  sqlitepager_unref(pPage);
++  return SQLITE_OK;
++}
++#endif
++
++#ifdef SQLITE_TEST
++/*
++** 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] =  Size of this entry
++**   aResult[4] =  Number of free bytes on this page
++**   aResult[5] =  Number of free blocks on the page
++**   aResult[6] =  Page number of the left child of this entry
++**   aResult[7] =  Page number of the right child for the whole page
++**
++** This routine is used for testing and debugging only.
++*/
++static int fileBtreeCursorDump(BtCursor *pCur, int *aResult){
++  int cnt, idx;
++  MemPage *pPage = pCur->pPage;
++  Btree *pBt = pCur->pBt;
++  aResult[0] = sqlitepager_pagenumber(pPage);
++  aResult[1] = pCur->idx;
++  aResult[2] = pPage->nCell;
++  if( pCur->idx>=0 && pCur->idx<pPage->nCell ){
++    aResult[3] = cellSize(pBt, pPage->apCell[pCur->idx]);
++    aResult[6] = SWAB32(pBt, pPage->apCell[pCur->idx]->h.leftChild);
++  }else{
++    aResult[3] = 0;
++    aResult[6] = 0;
++  }
++  aResult[4] = pPage->nFree;
++  cnt = 0;
++  idx = SWAB16(pBt, pPage->u.hdr.firstFree);
++  while( idx>0 && idx<SQLITE_USABLE_SIZE ){
++    cnt++;
++    idx = SWAB16(pBt, ((FreeBlk*)&pPage->u.aDisk[idx])->iNext);
++  }
++  aResult[5] = cnt;
++  aResult[7] = SWAB32(pBt, pPage->u.hdr.rightChild);
++  return SQLITE_OK;
++}
++#endif
++
++/*
++** Return the pager associated with a BTree.  This routine is used for
++** testing and debugging only.
++*/
++static Pager *fileBtreePager(Btree *pBt){
++  return 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 {
++  Btree *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. */
++};
++
++/*
++** Append a message to the error message string.
++*/
++static void checkAppendMsg(IntegrityCk *pCheck, char *zMsg1, char *zMsg2){
++  if( pCheck->zErrMsg ){
++    char *zOld = pCheck->zErrMsg;
++    pCheck->zErrMsg = 0;
++    sqliteSetString(&pCheck->zErrMsg, zOld, "\n", zMsg1, zMsg2, (char*)0);
++    sqliteFree(zOld);
++  }else{
++    sqliteSetString(&pCheck->zErrMsg, zMsg1, zMsg2, (char*)0);
++  }
++}
++
++/*
++** Add 1 to the reference count for page iPage.  If this is the second
++** reference to the page, add an error message to pCheck->zErrMsg.
++** Return 1 if there are 2 ore more references to the page and 0 if
++** if this is the first reference to the page.
++**
++** Also check that the page number is in bounds.
++*/
++static int checkRef(IntegrityCk *pCheck, int iPage, char *zContext){
++  if( iPage==0 ) return 1;
++  if( iPage>pCheck->nPage || iPage<0 ){
++    char zBuf[100];
++    sprintf(zBuf, "invalid page number %d", iPage);
++    checkAppendMsg(pCheck, zContext, zBuf);
++    return 1;
++  }
++  if( pCheck->anRef[iPage]==1 ){
++    char zBuf[100];
++    sprintf(zBuf, "2nd reference to page %d", iPage);
++    checkAppendMsg(pCheck, zContext, zBuf);
++    return 1;
++  }
++  return  (pCheck->anRef[iPage]++)>1;
++}
++
++/*
++** Check the integrity of the freelist or of an overflow page list.
++** Verify that the number of pages on the list is N.
++*/
++static void checkList(
++  IntegrityCk *pCheck,  /* Integrity checking context */
++  int isFreeList,       /* True for a freelist.  False for overflow page list */
++  int iPage,            /* Page number for first page in the list */
++  int N,                /* Expected number of pages in the list */
++  char *zContext        /* Context for error messages */
++){
++  int i;
++  char zMsg[100];
++  while( N-- > 0 ){
++    OverflowPage *pOvfl;
++    if( iPage<1 ){
++      sprintf(zMsg, "%d pages missing from overflow list", N+1);
++      checkAppendMsg(pCheck, zContext, zMsg);
++      break;
++    }
++    if( checkRef(pCheck, iPage, zContext) ) break;
++    if( sqlitepager_get(pCheck->pPager, (Pgno)iPage, (void**)&pOvfl) ){
++      sprintf(zMsg, "failed to get page %d", iPage);
++      checkAppendMsg(pCheck, zContext, zMsg);
++      break;
++    }
++    if( isFreeList ){
++      FreelistInfo *pInfo = (FreelistInfo*)pOvfl->aPayload;
++      int n = SWAB32(pCheck->pBt, pInfo->nFree);
++      for(i=0; i<n; i++){
++        checkRef(pCheck, SWAB32(pCheck->pBt, pInfo->aFree[i]), zContext);
++      }
++      N -= n;
++    }
++    iPage = SWAB32(pCheck->pBt, pOvfl->iNext);
++    sqlitepager_unref(pOvfl);
++  }
++}
++
++/*
++** Return negative if zKey1<zKey2.
++** Return zero if zKey1==zKey2.
++** Return positive if zKey1>zKey2.
++*/
++static int keyCompare(
++  const char *zKey1, int nKey1,
++  const char *zKey2, int nKey2
++){
++  int min = nKey1>nKey2 ? nKey2 : nKey1;
++  int c = memcmp(zKey1, zKey2, min);
++  if( c==0 ){
++    c = nKey1 - nKey2;
++  }
++  return c;
++}
++
++/*
++** Do various sanity checks on a single page of a tree.  Return
++** the tree depth.  Root pages return 0.  Parents of root pages
++** return 1, and so forth.
++** 
++** These checks are done:
++**
++**      1.  Make sure that cells and freeblocks do not overlap
++**          but combine to completely cover the page.
++**      2.  Make sure cell keys are in order.
++**      3.  Make sure no key is less than or equal to zLowerBound.
++**      4.  Make sure no key is greater than or equal to zUpperBound.
++**      5.  Check the integrity of overflow pages.
++**      6.  Recursively call checkTreePage on all children.
++**      7.  Verify that the depth of all children is the same.
++**      8.  Make sure this page is at least 33% full or else it is
++**          the root of the tree.
++*/
++static int checkTreePage(
++  IntegrityCk *pCheck,  /* Context for the sanity check */
++  int iPage,            /* Page number of the page to check */
++  MemPage *pParent,     /* Parent page */
++  char *zParentContext, /* Parent context */
++  char *zLowerBound,    /* All keys should be greater than this, if not NULL */
++  int nLower,           /* Number of characters in zLowerBound */
++  char *zUpperBound,    /* All keys should be less than this, if not NULL */
++  int nUpper            /* Number of characters in zUpperBound */
++){
++  MemPage *pPage;
++  int i, rc, depth, d2, pgno;
++  char *zKey1, *zKey2;
++  int nKey1, nKey2;
++  BtCursor cur;
++  Btree *pBt;
++  char zMsg[100];
++  char zContext[100];
++  char hit[SQLITE_USABLE_SIZE];
++
++  /* Check that the page exists
++  */
++  cur.pBt = pBt = pCheck->pBt;
++  if( iPage==0 ) return 0;
++  if( checkRef(pCheck, iPage, zParentContext) ) return 0;
++  sprintf(zContext, "On tree page %d: ", iPage);
++  if( (rc = sqlitepager_get(pCheck->pPager, (Pgno)iPage, (void**)&pPage))!=0 ){
++    sprintf(zMsg, "unable to get the page. error code=%d", rc);
++    checkAppendMsg(pCheck, zContext, zMsg);
++    return 0;
++  }
++  if( (rc = initPage(pBt, pPage, (Pgno)iPage, pParent))!=0 ){
++    sprintf(zMsg, "initPage() returns error code %d", rc);
++    checkAppendMsg(pCheck, zContext, zMsg);
++    sqlitepager_unref(pPage);
++    return 0;
++  }
++
++  /* Check out all the cells.
++  */
++  depth = 0;
++  if( zLowerBound ){
++    zKey1 = sqliteMalloc( nLower+1 );
++    memcpy(zKey1, zLowerBound, nLower);
++    zKey1[nLower] = 0;
++  }else{
++    zKey1 = 0;
++  }
++  nKey1 = nLower;
++  cur.pPage = pPage;
++  for(i=0; i<pPage->nCell; i++){
++    Cell *pCell = pPage->apCell[i];
++    int sz;
++
++    /* Check payload overflow pages
++    */
++    nKey2 = NKEY(pBt, pCell->h);
++    sz = nKey2 + NDATA(pBt, pCell->h);
++    sprintf(zContext, "On page %d cell %d: ", iPage, i);
++    if( sz>MX_LOCAL_PAYLOAD ){
++      int nPage = (sz - MX_LOCAL_PAYLOAD + OVERFLOW_SIZE - 1)/OVERFLOW_SIZE;
++      checkList(pCheck, 0, SWAB32(pBt, pCell->ovfl), nPage, zContext);
++    }
++
++    /* Check that keys are in the right order
++    */
++    cur.idx = i;
++    zKey2 = sqliteMallocRaw( nKey2+1 );
++    getPayload(&cur, 0, nKey2, zKey2);
++    if( zKey1 && keyCompare(zKey1, nKey1, zKey2, nKey2)>=0 ){
++      checkAppendMsg(pCheck, zContext, "Key is out of order");
++    }
++
++    /* Check sanity of left child page.
++    */
++    pgno = SWAB32(pBt, pCell->h.leftChild);
++    d2 = checkTreePage(pCheck, pgno, pPage, zContext, zKey1,nKey1,zKey2,nKey2);
++    if( i>0 && d2!=depth ){
++      checkAppendMsg(pCheck, zContext, "Child page depth differs");
++    }
++    depth = d2;
++    sqliteFree(zKey1);
++    zKey1 = zKey2;
++    nKey1 = nKey2;
++  }
++  pgno = SWAB32(pBt, pPage->u.hdr.rightChild);
++  sprintf(zContext, "On page %d at right child: ", iPage);
++  checkTreePage(pCheck, pgno, pPage, zContext, zKey1,nKey1,zUpperBound,nUpper);
++  sqliteFree(zKey1);
++ 
++  /* Check for complete coverage of the page
++  */
++  memset(hit, 0, sizeof(hit));
++  memset(hit, 1, sizeof(PageHdr));
++  for(i=SWAB16(pBt, pPage->u.hdr.firstCell); i>0 && i<SQLITE_USABLE_SIZE; ){
++    Cell *pCell = (Cell*)&pPage->u.aDisk[i];
++    int j;
++    for(j=i+cellSize(pBt, pCell)-1; j>=i; j--) hit[j]++;
++    i = SWAB16(pBt, pCell->h.iNext);
++  }
++  for(i=SWAB16(pBt,pPage->u.hdr.firstFree); i>0 && i<SQLITE_USABLE_SIZE; ){
++    FreeBlk *pFBlk = (FreeBlk*)&pPage->u.aDisk[i];
++    int j;
++    for(j=i+SWAB16(pBt,pFBlk->iSize)-1; j>=i; j--) hit[j]++;
++    i = SWAB16(pBt,pFBlk->iNext);
++  }
++  for(i=0; i<SQLITE_USABLE_SIZE; i++){
++    if( hit[i]==0 ){
++      sprintf(zMsg, "Unused space at byte %d of page %d", i, iPage);
++      checkAppendMsg(pCheck, zMsg, 0);
++      break;
++    }else if( hit[i]>1 ){
++      sprintf(zMsg, "Multiple uses for byte %d of page %d", i, iPage);
++      checkAppendMsg(pCheck, zMsg, 0);
++      break;
++    }
++  }
++
++  /* Check that free space is kept to a minimum
++  */
++#if 0
++  if( pParent && pParent->nCell>2 && pPage->nFree>3*SQLITE_USABLE_SIZE/4 ){
++    sprintf(zMsg, "free space (%d) greater than max (%d)", pPage->nFree,
++       SQLITE_USABLE_SIZE/3);
++    checkAppendMsg(pCheck, zContext, zMsg);
++  }
++#endif
++
++  sqlitepager_unref(pPage);
++  return depth;
++}
++
++/*
++** This routine does a complete check of the given BTree file.  aRoot[] is
++** an array of pages numbers were each page number is the root page of
++** a table.  nRoot is the number of entries in aRoot.
++**
++** If everything checks out, this routine returns NULL.  If something is
++** amiss, an error message is written into memory obtained from malloc()
++** and a pointer to that error message is returned.  The calling function
++** is responsible for freeing the error message when it is done.
++*/
++char *fileBtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){
++  int i;
++  int nRef;
++  IntegrityCk sCheck;
++
++  nRef = *sqlitepager_stats(pBt->pPager);
++  if( lockBtree(pBt)!=SQLITE_OK ){
++    return sqliteStrDup("Unable to acquire a read lock on the database");
++  }
++  sCheck.pBt = pBt;
++  sCheck.pPager = pBt->pPager;
++  sCheck.nPage = sqlitepager_pagecount(sCheck.pPager);
++  if( sCheck.nPage==0 ){
++    unlockBtreeIfUnused(pBt);
++    return 0;
++  }
++  sCheck.anRef = sqliteMallocRaw( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) );
++  sCheck.anRef[1] = 1;
++  for(i=2; i<=sCheck.nPage; i++){ sCheck.anRef[i] = 0; }
++  sCheck.zErrMsg = 0;
++
++  /* Check the integrity of the freelist
++  */
++  checkList(&sCheck, 1, SWAB32(pBt, pBt->page1->freeList),
++            SWAB32(pBt, pBt->page1->nFree), "Main freelist: ");
++
++  /* Check all the tables.
++  */
++  for(i=0; i<nRoot; i++){
++    if( aRoot[i]==0 ) continue;
++    checkTreePage(&sCheck, aRoot[i], 0, "List of tree roots: ", 0,0,0,0);
++  }
++
++  /* Make sure every page in the file is referenced
++  */
++  for(i=1; i<=sCheck.nPage; i++){
++    if( sCheck.anRef[i]==0 ){
++      char zBuf[100];
++      sprintf(zBuf, "Page %d is never used", i);
++      checkAppendMsg(&sCheck, zBuf, 0);
++    }
++  }
++
++  /* Make sure this analysis did not leave any unref() pages
++  */
++  unlockBtreeIfUnused(pBt);
++  if( nRef != *sqlitepager_stats(pBt->pPager) ){
++    char zBuf[100];
++    sprintf(zBuf, 
++      "Outstanding page count goes from %d to %d during this analysis",
++      nRef, *sqlitepager_stats(pBt->pPager)
++    );
++    checkAppendMsg(&sCheck, zBuf, 0);
++  }
++
++  /* Clean  up and report errors.
++  */
++  sqliteFree(sCheck.anRef);
++  return sCheck.zErrMsg;
++}
++
++/*
++** Return the full pathname of the underlying database file.
++*/
++static const char *fileBtreeGetFilename(Btree *pBt){
++  assert( pBt->pPager!=0 );
++  return sqlitepager_filename(pBt->pPager);
++}
++
++/*
++** Copy the complete content of pBtFrom into pBtTo.  A transaction
++** must be active for both files.
++**
++** The size of file pBtFrom may be reduced by this operation.
++** If anything goes wrong, the transaction on pBtFrom is rolled back.
++*/
++static int fileBtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
++  int rc = SQLITE_OK;
++  Pgno i, nPage, nToPage;
++
++  if( !pBtTo->inTrans || !pBtFrom->inTrans ) return SQLITE_ERROR;
++  if( pBtTo->needSwab!=pBtFrom->needSwab ) return SQLITE_ERROR;
++  if( pBtTo->pCursor ) return SQLITE_BUSY;
++  memcpy(pBtTo->page1, pBtFrom->page1, SQLITE_USABLE_SIZE);
++  rc = sqlitepager_overwrite(pBtTo->pPager, 1, pBtFrom->page1);
++  nToPage = sqlitepager_pagecount(pBtTo->pPager);
++  nPage = sqlitepager_pagecount(pBtFrom->pPager);
++  for(i=2; rc==SQLITE_OK && i<=nPage; i++){
++    void *pPage;
++    rc = sqlitepager_get(pBtFrom->pPager, i, &pPage);
++    if( rc ) break;
++    rc = sqlitepager_overwrite(pBtTo->pPager, i, pPage);
++    if( rc ) break;
++    sqlitepager_unref(pPage);
++  }
++  for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){
++    void *pPage;
++    rc = sqlitepager_get(pBtTo->pPager, i, &pPage);
++    if( rc ) break;
++    rc = sqlitepager_write(pPage);
++    sqlitepager_unref(pPage);
++    sqlitepager_dont_write(pBtTo->pPager, i);
++  }
++  if( !rc && nPage<nToPage ){
++    rc = sqlitepager_truncate(pBtTo->pPager, nPage);
++  }
++  if( rc ){
++    fileBtreeRollback(pBtTo);
++  }
++  return rc;  
++}
++
++/*
++** The following tables contain pointers to all of the interface
++** routines for this implementation of the B*Tree backend.  To
++** substitute a different implemention of the backend, one has merely
++** to provide pointers to alternative functions in similar tables.
++*/
++static BtOps sqliteBtreeOps = {
++    fileBtreeClose,
++    fileBtreeSetCacheSize,
++    fileBtreeSetSafetyLevel,
++    fileBtreeBeginTrans,
++    fileBtreeCommit,
++    fileBtreeRollback,
++    fileBtreeBeginCkpt,
++    fileBtreeCommitCkpt,
++    fileBtreeRollbackCkpt,
++    fileBtreeCreateTable,
++    fileBtreeCreateTable,  /* Really sqliteBtreeCreateIndex() */
++    fileBtreeDropTable,
++    fileBtreeClearTable,
++    fileBtreeCursor,
++    fileBtreeGetMeta,
++    fileBtreeUpdateMeta,
++    fileBtreeIntegrityCheck,
++    fileBtreeGetFilename,
++    fileBtreeCopyFile,
++    fileBtreePager,
++#ifdef SQLITE_TEST
++    fileBtreePageDump,
++#endif
++};
++static BtCursorOps sqliteBtreeCursorOps = {
++    fileBtreeMoveto,
++    fileBtreeDelete,
++    fileBtreeInsert,
++    fileBtreeFirst,
++    fileBtreeLast,
++    fileBtreeNext,
++    fileBtreePrevious,
++    fileBtreeKeySize,
++    fileBtreeKey,
++    fileBtreeKeyCompare,
++    fileBtreeDataSize,
++    fileBtreeData,
++    fileBtreeCloseCursor,
++#ifdef SQLITE_TEST
++    fileBtreeCursorDump,
++#endif
++};
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/btree.h
+@@ -0,0 +1,156 @@
++/*
++** 2001 September 15
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This header file defines the interface that the sqlite B-Tree file
++** subsystem.  See comments in the source code for a detailed description
++** of what each interface routine does.
++**
++** @(#) $Id$
++*/
++#ifndef _BTREE_H_
++#define _BTREE_H_
++
++/*
++** Forward declarations of structure
++*/
++typedef struct Btree Btree;
++typedef struct BtCursor BtCursor;
++typedef struct BtOps BtOps;
++typedef struct BtCursorOps BtCursorOps;
++
++
++/*
++** An instance of the following structure contains pointers to all
++** methods against an open BTree.  Alternative BTree implementations
++** (examples: file based versus in-memory) can be created by substituting
++** different methods.  Users of the BTree cannot tell the difference.
++**
++** In C++ we could do this by defining a virtual base class and then
++** creating subclasses for each different implementation.  But this is
++** C not C++ so we have to be a little more explicit.
++*/
++struct BtOps {
++    int (*Close)(Btree*);
++    int (*SetCacheSize)(Btree*, int);
++    int (*SetSafetyLevel)(Btree*, int);
++    int (*BeginTrans)(Btree*);
++    int (*Commit)(Btree*);
++    int (*Rollback)(Btree*);
++    int (*BeginCkpt)(Btree*);
++    int (*CommitCkpt)(Btree*);
++    int (*RollbackCkpt)(Btree*);
++    int (*CreateTable)(Btree*, int*);
++    int (*CreateIndex)(Btree*, int*);
++    int (*DropTable)(Btree*, int);
++    int (*ClearTable)(Btree*, int);
++    int (*Cursor)(Btree*, int iTable, int wrFlag, BtCursor **ppCur);
++    int (*GetMeta)(Btree*, int*);
++    int (*UpdateMeta)(Btree*, int*);
++    char *(*IntegrityCheck)(Btree*, int*, int);
++    const char *(*GetFilename)(Btree*);
++    int (*Copyfile)(Btree*,Btree*);
++    struct Pager *(*Pager)(Btree*);
++#ifdef SQLITE_TEST
++    int (*PageDump)(Btree*, int, int);
++#endif
++};
++
++/*
++** An instance of this structure defines all of the methods that can
++** be executed against a cursor.
++*/
++struct BtCursorOps {
++    int (*Moveto)(BtCursor*, const void *pKey, int nKey, int *pRes);
++    int (*Delete)(BtCursor*);
++    int (*Insert)(BtCursor*, const void *pKey, int nKey,
++                             const void *pData, int nData);
++    int (*First)(BtCursor*, int *pRes);
++    int (*Last)(BtCursor*, int *pRes);
++    int (*Next)(BtCursor*, int *pRes);
++    int (*Previous)(BtCursor*, int *pRes);
++    int (*KeySize)(BtCursor*, int *pSize);
++    int (*Key)(BtCursor*, int offset, int amt, char *zBuf);
++    int (*KeyCompare)(BtCursor*, const void *pKey, int nKey,
++                                 int nIgnore, int *pRes);
++    int (*DataSize)(BtCursor*, int *pSize);
++    int (*Data)(BtCursor*, int offset, int amt, char *zBuf);
++    int (*CloseCursor)(BtCursor*);
++#ifdef SQLITE_TEST
++    int (*CursorDump)(BtCursor*, int*);
++#endif
++};
++
++/*
++** The number of 4-byte "meta" values contained on the first page of each
++** database file.
++*/
++#define SQLITE_N_BTREE_META 10
++
++int sqliteBtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree);
++int sqliteRbtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree);
++
++#define btOps(pBt) (*((BtOps **)(pBt)))
++#define btCOps(pCur) (*((BtCursorOps **)(pCur)))
++
++#define sqliteBtreeClose(pBt)              (btOps(pBt)->Close(pBt))
++#define sqliteBtreeSetCacheSize(pBt, sz)   (btOps(pBt)->SetCacheSize(pBt, sz))
++#define sqliteBtreeSetSafetyLevel(pBt, sl) (btOps(pBt)->SetSafetyLevel(pBt, sl))
++#define sqliteBtreeBeginTrans(pBt)         (btOps(pBt)->BeginTrans(pBt))
++#define sqliteBtreeCommit(pBt)             (btOps(pBt)->Commit(pBt))
++#define sqliteBtreeRollback(pBt)           (btOps(pBt)->Rollback(pBt))
++#define sqliteBtreeBeginCkpt(pBt)          (btOps(pBt)->BeginCkpt(pBt))
++#define sqliteBtreeCommitCkpt(pBt)         (btOps(pBt)->CommitCkpt(pBt))
++#define sqliteBtreeRollbackCkpt(pBt)       (btOps(pBt)->RollbackCkpt(pBt))
++#define sqliteBtreeCreateTable(pBt,piTable)\
++                (btOps(pBt)->CreateTable(pBt,piTable))
++#define sqliteBtreeCreateIndex(pBt, piIndex)\
++                (btOps(pBt)->CreateIndex(pBt, piIndex))
++#define sqliteBtreeDropTable(pBt, iTable) (btOps(pBt)->DropTable(pBt, iTable))
++#define sqliteBtreeClearTable(pBt, iTable)\
++                (btOps(pBt)->ClearTable(pBt, iTable))
++#define sqliteBtreeCursor(pBt, iTable, wrFlag, ppCur)\
++                (btOps(pBt)->Cursor(pBt, iTable, wrFlag, ppCur))
++#define sqliteBtreeMoveto(pCur, pKey, nKey, pRes)\
++                (btCOps(pCur)->Moveto(pCur, pKey, nKey, pRes))
++#define sqliteBtreeDelete(pCur)           (btCOps(pCur)->Delete(pCur))
++#define sqliteBtreeInsert(pCur, pKey, nKey, pData, nData) \
++                (btCOps(pCur)->Insert(pCur, pKey, nKey, pData, nData))
++#define sqliteBtreeFirst(pCur, pRes)      (btCOps(pCur)->First(pCur, pRes))
++#define sqliteBtreeLast(pCur, pRes)       (btCOps(pCur)->Last(pCur, pRes))
++#define sqliteBtreeNext(pCur, pRes)       (btCOps(pCur)->Next(pCur, pRes))
++#define sqliteBtreePrevious(pCur, pRes)   (btCOps(pCur)->Previous(pCur, pRes))
++#define sqliteBtreeKeySize(pCur, pSize)   (btCOps(pCur)->KeySize(pCur, pSize) )
++#define sqliteBtreeKey(pCur, offset, amt, zBuf)\
++                (btCOps(pCur)->Key(pCur, offset, amt, zBuf))
++#define sqliteBtreeKeyCompare(pCur, pKey, nKey, nIgnore, pRes)\
++                (btCOps(pCur)->KeyCompare(pCur, pKey, nKey, nIgnore, pRes))
++#define sqliteBtreeDataSize(pCur, pSize)  (btCOps(pCur)->DataSize(pCur, pSize))
++#define sqliteBtreeData(pCur, offset, amt, zBuf)\
++                (btCOps(pCur)->Data(pCur, offset, amt, zBuf))
++#define sqliteBtreeCloseCursor(pCur)      (btCOps(pCur)->CloseCursor(pCur))
++#define sqliteBtreeGetMeta(pBt, aMeta)    (btOps(pBt)->GetMeta(pBt, aMeta))
++#define sqliteBtreeUpdateMeta(pBt, aMeta) (btOps(pBt)->UpdateMeta(pBt, aMeta))
++#define sqliteBtreeIntegrityCheck(pBt, aRoot, nRoot)\
++                (btOps(pBt)->IntegrityCheck(pBt, aRoot, nRoot))
++#define sqliteBtreeGetFilename(pBt)       (btOps(pBt)->GetFilename(pBt))
++#define sqliteBtreeCopyFile(pBt1, pBt2)   (btOps(pBt1)->Copyfile(pBt1, pBt2))
++#define sqliteBtreePager(pBt)             (btOps(pBt)->Pager(pBt))
++
++#ifdef SQLITE_TEST
++#define sqliteBtreePageDump(pBt, pgno, recursive)\
++                (btOps(pBt)->PageDump(pBt, pgno, recursive))
++#define sqliteBtreeCursorDump(pCur, aResult)\
++                (btCOps(pCur)->CursorDump(pCur, aResult))
++int btree_native_byte_order;
++#endif /* SQLITE_TEST */
++
++
++#endif /* _BTREE_H_ */
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/btree_rb.c
+@@ -0,0 +1,1488 @@
++/*
++** 2003 Feb 4
++**
++** 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 an in-core database using Red-Black balanced
++** binary trees.
++** 
++** It was contributed to SQLite by anonymous on 2003-Feb-04 23:24:49 UTC.
++*/
++#include "btree.h"
++#include "sqliteInt.h"
++#include <assert.h>
++
++/*
++** Omit this whole file if the SQLITE_OMIT_INMEMORYDB macro is
++** defined.  This allows a lot of code to be omitted for installations
++** that do not need it.
++*/
++#ifndef SQLITE_OMIT_INMEMORYDB
++
++
++typedef struct BtRbTree BtRbTree;
++typedef struct BtRbNode BtRbNode;
++typedef struct BtRollbackOp BtRollbackOp;
++typedef struct Rbtree Rbtree;
++typedef struct RbtCursor RbtCursor;
++
++/* Forward declarations */
++static BtOps sqliteRbtreeOps;
++static BtCursorOps sqliteRbtreeCursorOps;
++
++/*
++ * During each transaction (or checkpoint), a linked-list of
++ * "rollback-operations" is accumulated. If the transaction is rolled back,
++ * then the list of operations must be executed (to restore the database to
++ * it's state before the transaction started). If the transaction is to be
++ * committed, just delete the list.
++ *
++ * Each operation is represented as follows, depending on the value of eOp:
++ *
++ * ROLLBACK_INSERT  ->  Need to insert (pKey, pData) into table iTab.
++ * ROLLBACK_DELETE  ->  Need to delete the record (pKey) into table iTab.
++ * ROLLBACK_CREATE  ->  Need to create table iTab.
++ * ROLLBACK_DROP    ->  Need to drop table iTab.
++ */
++struct BtRollbackOp {
++  u8 eOp;
++  int iTab;
++  int nKey; 
++  void *pKey;
++  int nData;
++  void *pData;
++  BtRollbackOp *pNext;
++};
++
++/*
++** Legal values for BtRollbackOp.eOp:
++*/
++#define ROLLBACK_INSERT 1 /* Insert a record */
++#define ROLLBACK_DELETE 2 /* Delete a record */
++#define ROLLBACK_CREATE 3 /* Create a table */
++#define ROLLBACK_DROP   4 /* Drop a table */
++
++struct Rbtree {
++  BtOps *pOps;    /* Function table */
++  int aMetaData[SQLITE_N_BTREE_META];
++
++  int next_idx;   /* next available table index */
++  Hash tblHash;   /* All created tables, by index */
++  u8 isAnonymous; /* True if this Rbtree is to be deleted when closed */
++  u8 eTransState; /* State of this Rbtree wrt transactions */
++
++  BtRollbackOp *pTransRollback; 
++  BtRollbackOp *pCheckRollback;
++  BtRollbackOp *pCheckRollbackTail;
++};
++
++/*
++** Legal values for Rbtree.eTransState.
++*/
++#define TRANS_NONE           0  /* No transaction is in progress */
++#define TRANS_INTRANSACTION  1  /* A transaction is in progress */
++#define TRANS_INCHECKPOINT   2  /* A checkpoint is in progress  */
++#define TRANS_ROLLBACK       3  /* We are currently rolling back a checkpoint or
++                                 * transaction. */
++
++struct RbtCursor {
++  BtCursorOps *pOps;        /* Function table */
++  Rbtree    *pRbtree;
++  BtRbTree *pTree;
++  int       iTree;          /* Index of pTree in pRbtree */
++  BtRbNode *pNode;
++  RbtCursor *pShared;       /* List of all cursors on the same Rbtree */
++  u8 eSkip;                 /* Determines if next step operation is a no-op */
++  u8 wrFlag;                /* True if this cursor is open for writing */
++};
++
++/*
++** Legal values for RbtCursor.eSkip.
++*/
++#define SKIP_NONE     0   /* Always step the cursor */
++#define SKIP_NEXT     1   /* The next sqliteRbtreeNext() is a no-op */
++#define SKIP_PREV     2   /* The next sqliteRbtreePrevious() is a no-op */
++#define SKIP_INVALID  3   /* Calls to Next() and Previous() are invalid */
++
++struct BtRbTree {
++  RbtCursor *pCursors;     /* All cursors pointing to this tree */
++  BtRbNode *pHead;         /* Head of the tree, or NULL */
++};
++
++struct BtRbNode {
++  int nKey;
++  void *pKey;
++  int nData;
++  void *pData;
++  u8 isBlack;        /* true for a black node, 0 for a red node */
++  BtRbNode *pParent; /* Nodes parent node, NULL for the tree head */
++  BtRbNode *pLeft;   /* Nodes left child, or NULL */
++  BtRbNode *pRight;  /* Nodes right child, or NULL */
++
++  int nBlackHeight;  /* Only used during the red-black integrity check */
++};
++
++/* Forward declarations */
++static int memRbtreeMoveto(
++  RbtCursor* pCur,
++  const void *pKey,
++  int nKey,
++  int *pRes
++);
++static int memRbtreeClearTable(Rbtree* tree, int n);
++static int memRbtreeNext(RbtCursor* pCur, int *pRes);
++static int memRbtreeLast(RbtCursor* pCur, int *pRes);
++static int memRbtreePrevious(RbtCursor* pCur, int *pRes);
++
++
++/*
++** This routine checks all cursors that point to the same table
++** as pCur points to.  If any of those cursors were opened with
++** wrFlag==0 then this routine returns SQLITE_LOCKED.  If all
++** cursors point to the same table were opened with wrFlag==1
++** then this routine returns SQLITE_OK.
++**
++** In addition to checking for read-locks (where a read-lock 
++** means a cursor opened with wrFlag==0) this routine also NULLs
++** out the pNode field of all other cursors.
++** This is necessary because an insert 
++** or delete might change erase the node out from under
++** another cursor.
++*/
++static int checkReadLocks(RbtCursor *pCur){
++  RbtCursor *p;
++  assert( pCur->wrFlag );
++  for(p=pCur->pTree->pCursors; p; p=p->pShared){
++    if( p!=pCur ){
++      if( p->wrFlag==0 ) return SQLITE_LOCKED;
++      p->pNode = 0;
++    }
++  }
++  return SQLITE_OK;
++}
++
++/*
++ * The key-compare function for the red-black trees. Returns as follows:
++ *
++ * (key1 < key2)             -1
++ * (key1 == key2)             0 
++ * (key1 > key2)              1
++ *
++ * Keys are compared using memcmp(). If one key is an exact prefix of the
++ * other, then the shorter key is less than the longer key.
++ */
++static int key_compare(void const*pKey1, int nKey1, void const*pKey2, int nKey2)
++{
++  int mcmp = memcmp(pKey1, pKey2, (nKey1 <= nKey2)?nKey1:nKey2);
++  if( mcmp == 0){
++    if( nKey1 == nKey2 ) return 0;
++    return ((nKey1 < nKey2)?-1:1);
++  }
++  return ((mcmp>0)?1:-1);
++}
++
++/*
++ * Perform the LEFT-rotate transformation on node X of tree pTree. This
++ * transform is part of the red-black balancing code.
++ *
++ *        |                   |
++ *        X                   Y
++ *       / \                 / \
++ *      a   Y               X   c
++ *         / \             / \
++ *        b   c           a   b
++ *
++ *      BEFORE              AFTER
++ */
++static void leftRotate(BtRbTree *pTree, BtRbNode *pX)
++{
++  BtRbNode *pY;
++  BtRbNode *pb;
++  pY = pX->pRight;
++  pb = pY->pLeft;
++
++  pY->pParent = pX->pParent;
++  if( pX->pParent ){
++    if( pX->pParent->pLeft == pX ) pX->pParent->pLeft = pY;
++    else pX->pParent->pRight = pY;
++  }
++  pY->pLeft = pX;
++  pX->pParent = pY;
++  pX->pRight = pb;
++  if( pb ) pb->pParent = pX;
++  if( pTree->pHead == pX ) pTree->pHead = pY;
++}
++
++/*
++ * Perform the RIGHT-rotate transformation on node X of tree pTree. This
++ * transform is part of the red-black balancing code.
++ *
++ *        |                   |
++ *        X                   Y
++ *       / \                 / \
++ *      Y   c               a   X
++ *     / \                     / \
++ *    a   b                   b   c
++ *
++ *      BEFORE              AFTER
++ */
++static void rightRotate(BtRbTree *pTree, BtRbNode *pX)
++{
++  BtRbNode *pY;
++  BtRbNode *pb;
++  pY = pX->pLeft;
++  pb = pY->pRight;
++
++  pY->pParent = pX->pParent;
++  if( pX->pParent ){
++    if( pX->pParent->pLeft == pX ) pX->pParent->pLeft = pY;
++    else pX->pParent->pRight = pY;
++  }
++  pY->pRight = pX;
++  pX->pParent = pY;
++  pX->pLeft = pb;
++  if( pb ) pb->pParent = pX;
++  if( pTree->pHead == pX ) pTree->pHead = pY;
++}
++
++/*
++ * A string-manipulation helper function for check_redblack_tree(). If (orig ==
++ * NULL) a copy of val is returned. If (orig != NULL) then a copy of the *
++ * concatenation of orig and val is returned. The original orig is deleted
++ * (using sqliteFree()).
++ */
++static char *append_val(char * orig, char const * val){
++  char *z;
++  if( !orig ){
++    z = sqliteStrDup( val );
++  } else{
++    z = 0;
++    sqliteSetString(&z, orig, val, (char*)0);
++    sqliteFree( orig );
++  }
++  return z;
++}
++
++/*
++ * Append a string representation of the entire node to orig and return it.
++ * This is used to produce debugging information if check_redblack_tree() finds
++ * a problem with a red-black binary tree.
++ */
++static char *append_node(char * orig, BtRbNode *pNode, int indent)
++{
++  char buf[128];
++  int i;
++
++  for( i=0; i<indent; i++ ){
++      orig = append_val(orig, " ");
++  }
++
++  sprintf(buf, "%p", pNode);
++  orig = append_val(orig, buf);
++
++  if( pNode ){
++    indent += 3;
++    if( pNode->isBlack ){
++      orig = append_val(orig, " B \n");
++    }else{
++      orig = append_val(orig, " R \n");
++    }
++    orig = append_node( orig, pNode->pLeft, indent );
++    orig = append_node( orig, pNode->pRight, indent );
++  }else{
++    orig = append_val(orig, "\n");
++  }
++  return orig;
++}
++
++/*
++ * Print a representation of a node to stdout. This function is only included
++ * so you can call it from within a debugger if things get really bad.  It
++ * is not called from anyplace in the code.
++ */
++static void print_node(BtRbNode *pNode)
++{
++    char * str = append_node(0, pNode, 0);
++    printf("%s", str);
++
++    /* Suppress a warning message about print_node() being unused */
++    (void)print_node;
++}
++
++/* 
++ * Check the following properties of the red-black tree:
++ * (1) - If a node is red, both of it's children are black
++ * (2) - Each path from a given node to a leaf (NULL) node passes thru the
++ *       same number of black nodes 
++ *
++ * If there is a problem, append a description (using append_val() ) to *msg.
++ */
++static void check_redblack_tree(BtRbTree * tree, char ** msg)
++{
++  BtRbNode *pNode;
++
++  /* 0 -> came from parent 
++   * 1 -> came from left
++   * 2 -> came from right */
++  int prev_step = 0;
++
++  pNode = tree->pHead;
++  while( pNode ){
++    switch( prev_step ){
++      case 0:
++        if( pNode->pLeft ){
++          pNode = pNode->pLeft;
++        }else{ 
++          prev_step = 1;
++        }
++        break;
++      case 1:
++        if( pNode->pRight ){
++          pNode = pNode->pRight;
++          prev_step = 0;
++        }else{
++          prev_step = 2;
++        }
++        break;
++      case 2:
++        /* Check red-black property (1) */
++        if( !pNode->isBlack &&
++            ( (pNode->pLeft && !pNode->pLeft->isBlack) ||
++              (pNode->pRight && !pNode->pRight->isBlack) )
++          ){
++          char buf[128];
++          sprintf(buf, "Red node with red child at %p\n", pNode);
++          *msg = append_val(*msg, buf);
++          *msg = append_node(*msg, tree->pHead, 0);
++          *msg = append_val(*msg, "\n");
++        }
++
++        /* Check red-black property (2) */
++        { 
++          int leftHeight = 0;
++          int rightHeight = 0;
++          if( pNode->pLeft ){
++            leftHeight += pNode->pLeft->nBlackHeight;
++            leftHeight += (pNode->pLeft->isBlack?1:0);
++          }
++          if( pNode->pRight ){
++            rightHeight += pNode->pRight->nBlackHeight;
++            rightHeight += (pNode->pRight->isBlack?1:0);
++          }
++          if( leftHeight != rightHeight ){
++            char buf[128];
++            sprintf(buf, "Different black-heights at %p\n", pNode);
++            *msg = append_val(*msg, buf);
++            *msg = append_node(*msg, tree->pHead, 0);
++            *msg = append_val(*msg, "\n");
++          }
++          pNode->nBlackHeight = leftHeight;
++        }
++
++        if( pNode->pParent ){
++          if( pNode == pNode->pParent->pLeft ) prev_step = 1;
++          else prev_step = 2;
++        }
++        pNode = pNode->pParent;
++        break;
++      default: assert(0);
++    }
++  }
++} 
++
++/*
++ * Node pX has just been inserted into pTree (by code in sqliteRbtreeInsert()).
++ * It is possible that pX is a red node with a red parent, which is a violation
++ * of the red-black tree properties. This function performs rotations and 
++ * color changes to rebalance the tree
++ */
++static void do_insert_balancing(BtRbTree *pTree, BtRbNode *pX)
++{
++  /* In the first iteration of this loop, pX points to the red node just
++   * inserted in the tree. If the parent of pX exists (pX is not the root
++   * node) and is red, then the properties of the red-black tree are
++   * violated.
++   *
++   * At the start of any subsequent iterations, pX points to a red node
++   * with a red parent. In all other respects the tree is a legal red-black
++   * binary tree. */
++  while( pX != pTree->pHead && !pX->pParent->isBlack ){
++    BtRbNode *pUncle;
++    BtRbNode *pGrandparent;
++
++    /* Grandparent of pX must exist and must be black. */
++    pGrandparent = pX->pParent->pParent;
++    assert( pGrandparent );
++    assert( pGrandparent->isBlack );
++
++    /* Uncle of pX may or may not exist. */
++    if( pX->pParent == pGrandparent->pLeft ) 
++      pUncle = pGrandparent->pRight;
++    else 
++      pUncle = pGrandparent->pLeft;
++
++    /* If the uncle of pX exists and is red, we do the following:
++     *       |                 |
++     *      G(b)              G(r)
++     *      /  \              /  \        
++     *   U(r)   P(r)       U(b)  P(b)
++     *            \                \
++     *           X(r)              X(r)
++     *
++     *     BEFORE             AFTER
++     * pX is then set to G. If the parent of G is red, then the while loop
++     * will run again.  */
++    if( pUncle && !pUncle->isBlack ){
++      pGrandparent->isBlack = 0;
++      pUncle->isBlack = 1;
++      pX->pParent->isBlack = 1;
++      pX = pGrandparent;
++    }else{
++
++      if( pX->pParent == pGrandparent->pLeft ){
++        if( pX == pX->pParent->pRight ){
++          /* If pX is a right-child, do the following transform, essentially
++           * to change pX into a left-child: 
++           *       |                  | 
++           *      G(b)               G(b)
++           *      /  \               /  \        
++           *   P(r)   U(b)        X(r)  U(b)
++           *      \                /
++           *     X(r)            P(r) <-- new X
++           *
++           *     BEFORE             AFTER
++           */
++          pX = pX->pParent;
++          leftRotate(pTree, pX);
++        }
++
++        /* Do the following transform, which balances the tree :) 
++         *       |                  | 
++         *      G(b)               P(b)
++         *      /  \               /  \        
++         *   P(r)   U(b)        X(r)  G(r)
++         *    /                         \
++         *  X(r)                        U(b)
++         *
++         *     BEFORE             AFTER
++         */
++        assert( pGrandparent == pX->pParent->pParent );
++        pGrandparent->isBlack = 0;
++        pX->pParent->isBlack = 1;
++        rightRotate( pTree, pGrandparent );
++
++      }else{
++        /* This code is symetric to the illustrated case above. */
++        if( pX == pX->pParent->pLeft ){
++          pX = pX->pParent;
++          rightRotate(pTree, pX);
++        }
++        assert( pGrandparent == pX->pParent->pParent );
++        pGrandparent->isBlack = 0;
++        pX->pParent->isBlack = 1;
++        leftRotate( pTree, pGrandparent );
++      }
++    }
++  }
++  pTree->pHead->isBlack = 1;
++}
++
++/*
++ * A child of pParent, which in turn had child pX, has just been removed from 
++ * pTree (the figure below depicts the operation, Z is being removed). pParent
++ * or pX, or both may be NULL.  
++ *                |           |
++ *                P           P
++ *               / \         / \
++ *              Z           X
++ *             / \
++ *            X  nil
++ *
++ * This function is only called if Z was black. In this case the red-black tree
++ * properties have been violated, and pX has an "extra black". This function 
++ * performs rotations and color-changes to re-balance the tree.
++ */
++static 
++void do_delete_balancing(BtRbTree *pTree, BtRbNode *pX, BtRbNode *pParent)
++{
++  BtRbNode *pSib; 
++
++  /* TODO: Comment this code! */
++  while( pX != pTree->pHead && (!pX || pX->isBlack) ){
++    if( pX == pParent->pLeft ){
++      pSib = pParent->pRight;
++      if( pSib && !(pSib->isBlack) ){
++        pSib->isBlack = 1;
++        pParent->isBlack = 0;
++        leftRotate(pTree, pParent);
++        pSib = pParent->pRight;
++      }
++      if( !pSib ){
++        pX = pParent;
++      }else if( 
++          (!pSib->pLeft  || pSib->pLeft->isBlack) &&
++          (!pSib->pRight || pSib->pRight->isBlack) ) {
++        pSib->isBlack = 0;
++        pX = pParent;
++      }else{
++        if( (!pSib->pRight || pSib->pRight->isBlack) ){
++          if( pSib->pLeft ) pSib->pLeft->isBlack = 1;
++          pSib->isBlack = 0;
++          rightRotate( pTree, pSib );
++          pSib = pParent->pRight;
++        }
++        pSib->isBlack = pParent->isBlack;
++        pParent->isBlack = 1;
++        if( pSib->pRight ) pSib->pRight->isBlack = 1;
++        leftRotate(pTree, pParent);
++        pX = pTree->pHead;
++      }
++    }else{
++      pSib = pParent->pLeft;
++      if( pSib && !(pSib->isBlack) ){
++        pSib->isBlack = 1;
++        pParent->isBlack = 0;
++        rightRotate(pTree, pParent);
++        pSib = pParent->pLeft;
++      }
++      if( !pSib ){
++        pX = pParent;
++      }else if( 
++          (!pSib->pLeft  || pSib->pLeft->isBlack) &&
++          (!pSib->pRight || pSib->pRight->isBlack) ){
++        pSib->isBlack = 0;
++        pX = pParent;
++      }else{
++        if( (!pSib->pLeft || pSib->pLeft->isBlack) ){
++          if( pSib->pRight ) pSib->pRight->isBlack = 1;
++          pSib->isBlack = 0;
++          leftRotate( pTree, pSib );
++          pSib = pParent->pLeft;
++        }
++        pSib->isBlack = pParent->isBlack;
++        pParent->isBlack = 1;
++        if( pSib->pLeft ) pSib->pLeft->isBlack = 1;
++        rightRotate(pTree, pParent);
++        pX = pTree->pHead;
++      }
++    }
++    pParent = pX->pParent;
++  }
++  if( pX ) pX->isBlack = 1;
++}
++
++/*
++ * Create table n in tree pRbtree. Table n must not exist.
++ */
++static void btreeCreateTable(Rbtree* pRbtree, int n)
++{
++  BtRbTree *pNewTbl = sqliteMalloc(sizeof(BtRbTree));
++  sqliteHashInsert(&pRbtree->tblHash, 0, n, pNewTbl);
++}
++
++/*
++ * Log a single "rollback-op" for the given Rbtree. See comments for struct
++ * BtRollbackOp.
++ */
++static void btreeLogRollbackOp(Rbtree* pRbtree, BtRollbackOp *pRollbackOp)
++{
++  assert( pRbtree->eTransState == TRANS_INCHECKPOINT ||
++      pRbtree->eTransState == TRANS_INTRANSACTION );
++  if( pRbtree->eTransState == TRANS_INTRANSACTION ){
++    pRollbackOp->pNext = pRbtree->pTransRollback;
++    pRbtree->pTransRollback = pRollbackOp;
++  }
++  if( pRbtree->eTransState == TRANS_INCHECKPOINT ){
++    if( !pRbtree->pCheckRollback ){
++      pRbtree->pCheckRollbackTail = pRollbackOp;
++    }
++    pRollbackOp->pNext = pRbtree->pCheckRollback;
++    pRbtree->pCheckRollback = pRollbackOp;
++  }
++}
++
++int sqliteRbtreeOpen(
++  const char *zFilename,
++  int mode,
++  int nPg,
++  Btree **ppBtree
++){
++  Rbtree **ppRbtree = (Rbtree**)ppBtree;
++  *ppRbtree = (Rbtree *)sqliteMalloc(sizeof(Rbtree));
++  if( sqlite_malloc_failed ) goto open_no_mem;
++  sqliteHashInit(&(*ppRbtree)->tblHash, SQLITE_HASH_INT, 0);
++
++  /* Create a binary tree for the SQLITE_MASTER table at location 2 */
++  btreeCreateTable(*ppRbtree, 2);
++  if( sqlite_malloc_failed ) goto open_no_mem;
++  (*ppRbtree)->next_idx = 3;
++  (*ppRbtree)->pOps = &sqliteRbtreeOps;
++  /* Set file type to 4; this is so that "attach ':memory:' as ...."  does not
++  ** think that the database in uninitialised and refuse to attach
++  */
++  (*ppRbtree)->aMetaData[2] = 4;
++  
++  return SQLITE_OK;
++
++open_no_mem:
++  *ppBtree = 0;
++  return SQLITE_NOMEM;
++}
++
++/*
++ * Create a new table in the supplied Rbtree. Set *n to the new table number.
++ * Return SQLITE_OK if the operation is a success.
++ */
++static int memRbtreeCreateTable(Rbtree* tree, int* n)
++{
++  assert( tree->eTransState != TRANS_NONE );
++
++  *n = tree->next_idx++;
++  btreeCreateTable(tree, *n);
++  if( sqlite_malloc_failed ) return SQLITE_NOMEM;
++
++  /* Set up the rollback structure (if we are not doing this as part of a
++   * rollback) */
++  if( tree->eTransState != TRANS_ROLLBACK ){
++    BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp));
++    if( pRollbackOp==0 ) return SQLITE_NOMEM;
++    pRollbackOp->eOp = ROLLBACK_DROP;
++    pRollbackOp->iTab = *n;
++    btreeLogRollbackOp(tree, pRollbackOp);
++  }
++
++  return SQLITE_OK;
++}
++
++/*
++ * Delete table n from the supplied Rbtree. 
++ */
++static int memRbtreeDropTable(Rbtree* tree, int n)
++{
++  BtRbTree *pTree;
++  assert( tree->eTransState != TRANS_NONE );
++
++  memRbtreeClearTable(tree, n);
++  pTree = sqliteHashInsert(&tree->tblHash, 0, n, 0);
++  assert(pTree);
++  assert( pTree->pCursors==0 );
++  sqliteFree(pTree);
++
++  if( tree->eTransState != TRANS_ROLLBACK ){
++    BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp));
++    if( pRollbackOp==0 ) return SQLITE_NOMEM;
++    pRollbackOp->eOp = ROLLBACK_CREATE;
++    pRollbackOp->iTab = n;
++    btreeLogRollbackOp(tree, pRollbackOp);
++  }
++
++  return SQLITE_OK;
++}
++
++static int memRbtreeKeyCompare(RbtCursor* pCur, const void *pKey, int nKey,
++                                 int nIgnore, int *pRes)
++{
++  assert(pCur);
++
++  if( !pCur->pNode ) {
++    *pRes = -1;
++  } else {
++    if( (pCur->pNode->nKey - nIgnore) < 0 ){
++      *pRes = -1;
++    }else{
++      *pRes = key_compare(pCur->pNode->pKey, pCur->pNode->nKey-nIgnore, 
++          pKey, nKey);
++    }
++  }
++  return SQLITE_OK;
++}
++
++/*
++ * Get a new cursor for table iTable of the supplied Rbtree. The wrFlag
++ * parameter indicates that the cursor is open for writing.
++ *
++ * Note that RbtCursor.eSkip and RbtCursor.pNode both initialize to 0.
++ */
++static int memRbtreeCursor(
++  Rbtree* tree,
++  int iTable,
++  int wrFlag,
++  RbtCursor **ppCur
++){
++  RbtCursor *pCur;
++  assert(tree);
++  pCur = *ppCur = sqliteMalloc(sizeof(RbtCursor));
++  if( sqlite_malloc_failed ) return SQLITE_NOMEM;
++  pCur->pTree  = sqliteHashFind(&tree->tblHash, 0, iTable);
++  assert( pCur->pTree );
++  pCur->pRbtree = tree;
++  pCur->iTree  = iTable;
++  pCur->pOps = &sqliteRbtreeCursorOps;
++  pCur->wrFlag = wrFlag;
++  pCur->pShared = pCur->pTree->pCursors;
++  pCur->pTree->pCursors = pCur;
++
++  assert( (*ppCur)->pTree );
++  return SQLITE_OK;
++}
++
++/*
++ * Insert a new record into the Rbtree.  The key is given by (pKey,nKey)
++ * and the data is given by (pData,nData).  The cursor is used only to
++ * define what database the record should be inserted into.  The cursor
++ * is left pointing at the new record.
++ *
++ * If the key exists already in the tree, just replace the data. 
++ */
++static int memRbtreeInsert(
++  RbtCursor* pCur,
++  const void *pKey,
++  int nKey,
++  const void *pDataInput,
++  int nData
++){
++  void * pData;
++  int match;
++
++  /* It is illegal to call sqliteRbtreeInsert() if we are
++  ** not in a transaction */
++  assert( pCur->pRbtree->eTransState != TRANS_NONE );
++
++  /* Make sure some other cursor isn't trying to read this same table */
++  if( checkReadLocks(pCur) ){
++    return SQLITE_LOCKED; /* The table pCur points to has a read lock */
++  }
++
++  /* Take a copy of the input data now, in case we need it for the 
++   * replace case */
++  pData = sqliteMallocRaw(nData);
++  if( sqlite_malloc_failed ) return SQLITE_NOMEM;
++  memcpy(pData, pDataInput, nData);
++
++  /* Move the cursor to a node near the key to be inserted. If the key already
++   * exists in the table, then (match == 0). In this case we can just replace
++   * the data associated with the entry, we don't need to manipulate the tree.
++   * 
++   * If there is no exact match, then the cursor points at what would be either
++   * the predecessor (match == -1) or successor (match == 1) of the
++   * searched-for key, were it to be inserted. The new node becomes a child of
++   * this node.
++   * 
++   * The new node is initially red.
++   */
++  memRbtreeMoveto( pCur, pKey, nKey, &match);
++  if( match ){
++    BtRbNode *pNode = sqliteMalloc(sizeof(BtRbNode));
++    if( pNode==0 ) return SQLITE_NOMEM;
++    pNode->nKey = nKey;
++    pNode->pKey = sqliteMallocRaw(nKey);
++    if( sqlite_malloc_failed ) return SQLITE_NOMEM;
++    memcpy(pNode->pKey, pKey, nKey);
++    pNode->nData = nData;
++    pNode->pData = pData; 
++    if( pCur->pNode ){
++      switch( match ){
++        case -1:
++          assert( !pCur->pNode->pRight );
++          pNode->pParent = pCur->pNode;
++          pCur->pNode->pRight = pNode;
++          break;
++        case 1:
++          assert( !pCur->pNode->pLeft );
++          pNode->pParent = pCur->pNode;
++          pCur->pNode->pLeft = pNode;
++          break;
++        default:
++          assert(0);
++      }
++    }else{
++      pCur->pTree->pHead = pNode;
++    }
++
++    /* Point the cursor at the node just inserted, as per SQLite requirements */
++    pCur->pNode = pNode;
++
++    /* A new node has just been inserted, so run the balancing code */
++    do_insert_balancing(pCur->pTree, pNode);
++
++    /* Set up a rollback-op in case we have to roll this operation back */
++    if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
++      BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
++      if( pOp==0 ) return SQLITE_NOMEM;
++      pOp->eOp = ROLLBACK_DELETE;
++      pOp->iTab = pCur->iTree;
++      pOp->nKey = pNode->nKey;
++      pOp->pKey = sqliteMallocRaw( pOp->nKey );
++      if( sqlite_malloc_failed ) return SQLITE_NOMEM;
++      memcpy( pOp->pKey, pNode->pKey, pOp->nKey );
++      btreeLogRollbackOp(pCur->pRbtree, pOp);
++    }
++
++  }else{ 
++    /* No need to insert a new node in the tree, as the key already exists.
++     * Just clobber the current nodes data. */
++
++    /* Set up a rollback-op in case we have to roll this operation back */
++    if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
++      BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
++      if( pOp==0 ) return SQLITE_NOMEM;
++      pOp->iTab = pCur->iTree;
++      pOp->nKey = pCur->pNode->nKey;
++      pOp->pKey = sqliteMallocRaw( pOp->nKey );
++      if( sqlite_malloc_failed ) return SQLITE_NOMEM;
++      memcpy( pOp->pKey, pCur->pNode->pKey, pOp->nKey );
++      pOp->nData = pCur->pNode->nData;
++      pOp->pData = pCur->pNode->pData;
++      pOp->eOp = ROLLBACK_INSERT;
++      btreeLogRollbackOp(pCur->pRbtree, pOp);
++    }else{
++      sqliteFree( pCur->pNode->pData );
++    }
++
++    /* Actually clobber the nodes data */
++    pCur->pNode->pData = pData;
++    pCur->pNode->nData = nData;
++  }
++
++  return SQLITE_OK;
++}
++
++/* Move the cursor so that it points to an entry near pKey.
++** Return a success code.
++**
++**     *pRes<0      The cursor is left pointing at an entry that
++**                  is smaller than pKey or if the table is empty
++**                  and the cursor is therefore left point to nothing.
++**
++**     *pRes==0     The cursor is left pointing at an entry that
++**                  exactly matches pKey.
++**
++**     *pRes>0      The cursor is left pointing at an entry that
++**                  is larger than pKey.
++*/
++static int memRbtreeMoveto(
++  RbtCursor* pCur,
++  const void *pKey,
++  int nKey,
++  int *pRes
++){
++  BtRbNode *pTmp = 0;
++
++  pCur->pNode = pCur->pTree->pHead;
++  *pRes = -1;
++  while( pCur->pNode && *pRes ) {
++    *pRes = key_compare(pCur->pNode->pKey, pCur->pNode->nKey, pKey, nKey);
++    pTmp = pCur->pNode;
++    switch( *pRes ){
++      case 1:    /* cursor > key */
++        pCur->pNode = pCur->pNode->pLeft;
++        break;
++      case -1:   /* cursor < key */
++        pCur->pNode = pCur->pNode->pRight;
++        break;
++    }
++  } 
++
++  /* If (pCur->pNode == NULL), then we have failed to find a match. Set
++   * pCur->pNode to pTmp, which is either NULL (if the tree is empty) or the
++   * last node traversed in the search. In either case the relation ship
++   * between pTmp and the searched for key is already stored in *pRes. pTmp is
++   * either the successor or predecessor of the key we tried to move to. */
++  if( !pCur->pNode ) pCur->pNode = pTmp;
++  pCur->eSkip = SKIP_NONE;
++
++  return SQLITE_OK;
++}
++
++
++/*
++** Delete the entry that the cursor is pointing to.
++**
++** The cursor is left pointing at either the next or the previous
++** entry.  If the cursor is left pointing to the next entry, then 
++** the pCur->eSkip flag is set to SKIP_NEXT which forces the next call to 
++** sqliteRbtreeNext() to be a no-op.  That way, you can always call
++** sqliteRbtreeNext() after a delete and the cursor will be left
++** pointing to the first entry after the deleted entry.  Similarly,
++** pCur->eSkip is set to SKIP_PREV is the cursor is left pointing to
++** the entry prior to the deleted entry so that a subsequent call to
++** sqliteRbtreePrevious() will always leave the cursor pointing at the
++** entry immediately before the one that was deleted.
++*/
++static int memRbtreeDelete(RbtCursor* pCur)
++{
++  BtRbNode *pZ;      /* The one being deleted */
++  BtRbNode *pChild;  /* The child of the spliced out node */
++
++  /* It is illegal to call sqliteRbtreeDelete() if we are
++  ** not in a transaction */
++  assert( pCur->pRbtree->eTransState != TRANS_NONE );
++
++  /* Make sure some other cursor isn't trying to read this same table */
++  if( checkReadLocks(pCur) ){
++    return SQLITE_LOCKED; /* The table pCur points to has a read lock */
++  }
++
++  pZ = pCur->pNode;
++  if( !pZ ){
++    return SQLITE_OK;
++  }
++
++  /* If we are not currently doing a rollback, set up a rollback op for this 
++   * deletion */
++  if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
++    BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
++    if( pOp==0 ) return SQLITE_NOMEM;
++    pOp->iTab = pCur->iTree;
++    pOp->nKey = pZ->nKey;
++    pOp->pKey = pZ->pKey;
++    pOp->nData = pZ->nData;
++    pOp->pData = pZ->pData;
++    pOp->eOp = ROLLBACK_INSERT;
++    btreeLogRollbackOp(pCur->pRbtree, pOp);
++  }
++
++  /* First do a standard binary-tree delete (node pZ is to be deleted). How
++   * to do this depends on how many children pZ has:
++   *
++   * If pZ has no children or one child, then splice out pZ.  If pZ has two
++   * children, splice out the successor of pZ and replace the key and data of
++   * pZ with the key and data of the spliced out successor.  */
++  if( pZ->pLeft && pZ->pRight ){
++    BtRbNode *pTmp;
++    int dummy;
++    pCur->eSkip = SKIP_NONE;
++    memRbtreeNext(pCur, &dummy);
++    assert( dummy == 0 );
++    if( pCur->pRbtree->eTransState == TRANS_ROLLBACK ){
++      sqliteFree(pZ->pKey);
++      sqliteFree(pZ->pData);
++    }
++    pZ->pData = pCur->pNode->pData;
++    pZ->nData = pCur->pNode->nData;
++    pZ->pKey = pCur->pNode->pKey;
++    pZ->nKey = pCur->pNode->nKey;
++    pTmp = pZ;
++    pZ = pCur->pNode;
++    pCur->pNode = pTmp;
++    pCur->eSkip = SKIP_NEXT;
++  }else{
++    int res;
++    pCur->eSkip = SKIP_NONE;
++    memRbtreeNext(pCur, &res);
++    pCur->eSkip = SKIP_NEXT;
++    if( res ){
++      memRbtreeLast(pCur, &res);
++      memRbtreePrevious(pCur, &res);
++      pCur->eSkip = SKIP_PREV;
++    }
++    if( pCur->pRbtree->eTransState == TRANS_ROLLBACK ){
++        sqliteFree(pZ->pKey);
++        sqliteFree(pZ->pData);
++    }
++  }
++
++  /* pZ now points at the node to be spliced out. This block does the 
++   * splicing. */
++  {
++    BtRbNode **ppParentSlot = 0;
++    assert( !pZ->pLeft || !pZ->pRight ); /* pZ has at most one child */
++    pChild = ((pZ->pLeft)?pZ->pLeft:pZ->pRight);
++    if( pZ->pParent ){
++      assert( pZ == pZ->pParent->pLeft || pZ == pZ->pParent->pRight );
++      ppParentSlot = ((pZ == pZ->pParent->pLeft)
++          ?&pZ->pParent->pLeft:&pZ->pParent->pRight);
++      *ppParentSlot = pChild;
++    }else{
++      pCur->pTree->pHead = pChild;
++    }
++    if( pChild ) pChild->pParent = pZ->pParent;
++  }
++
++  /* pZ now points at the spliced out node. pChild is the only child of pZ, or
++   * NULL if pZ has no children. If pZ is black, and not the tree root, then we
++   * will have violated the "same number of black nodes in every path to a
++   * leaf" property of the red-black tree. The code in do_delete_balancing()
++   * repairs this. */
++  if( pZ->isBlack ){ 
++    do_delete_balancing(pCur->pTree, pChild, pZ->pParent);
++  }
++
++  sqliteFree(pZ);
++  return SQLITE_OK;
++}
++
++/*
++ * Empty table n of the Rbtree.
++ */
++static int memRbtreeClearTable(Rbtree* tree, int n)
++{
++  BtRbTree *pTree;
++  BtRbNode *pNode;
++
++  pTree = sqliteHashFind(&tree->tblHash, 0, n);
++  assert(pTree);
++
++  pNode = pTree->pHead;
++  while( pNode ){
++    if( pNode->pLeft ){
++      pNode = pNode->pLeft;
++    }
++    else if( pNode->pRight ){
++      pNode = pNode->pRight;
++    }
++    else {
++      BtRbNode *pTmp = pNode->pParent;
++      if( tree->eTransState == TRANS_ROLLBACK ){
++        sqliteFree( pNode->pKey );
++        sqliteFree( pNode->pData );
++      }else{
++        BtRollbackOp *pRollbackOp = sqliteMallocRaw(sizeof(BtRollbackOp));
++        if( pRollbackOp==0 ) return SQLITE_NOMEM;
++        pRollbackOp->eOp = ROLLBACK_INSERT;
++        pRollbackOp->iTab = n;
++        pRollbackOp->nKey = pNode->nKey;
++        pRollbackOp->pKey = pNode->pKey;
++        pRollbackOp->nData = pNode->nData;
++        pRollbackOp->pData = pNode->pData;
++        btreeLogRollbackOp(tree, pRollbackOp);
++      }
++      sqliteFree( pNode );
++      if( pTmp ){
++        if( pTmp->pLeft == pNode ) pTmp->pLeft = 0;
++        else if( pTmp->pRight == pNode ) pTmp->pRight = 0;
++      }
++      pNode = pTmp;
++    }
++  }
++
++  pTree->pHead = 0;
++  return SQLITE_OK;
++}
++
++static int memRbtreeFirst(RbtCursor* pCur, int *pRes)
++{
++  if( pCur->pTree->pHead ){
++    pCur->pNode = pCur->pTree->pHead;
++    while( pCur->pNode->pLeft ){
++      pCur->pNode = pCur->pNode->pLeft;
++    }
++  }
++  if( pCur->pNode ){
++    *pRes = 0;
++  }else{
++    *pRes = 1;
++  }
++  pCur->eSkip = SKIP_NONE;
++  return SQLITE_OK;
++}
++
++static int memRbtreeLast(RbtCursor* pCur, int *pRes)
++{
++  if( pCur->pTree->pHead ){
++    pCur->pNode = pCur->pTree->pHead;
++    while( pCur->pNode->pRight ){
++      pCur->pNode = pCur->pNode->pRight;
++    }
++  }
++  if( pCur->pNode ){
++    *pRes = 0;
++  }else{
++    *pRes = 1;
++  }
++  pCur->eSkip = SKIP_NONE;
++  return SQLITE_OK;
++}
++
++/*
++** 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.
++*/
++static int memRbtreeNext(RbtCursor* pCur, int *pRes)
++{
++  if( pCur->pNode && pCur->eSkip != SKIP_NEXT ){
++    if( pCur->pNode->pRight ){
++      pCur->pNode = pCur->pNode->pRight;
++      while( pCur->pNode->pLeft )
++        pCur->pNode = pCur->pNode->pLeft;
++    }else{
++      BtRbNode * pX = pCur->pNode;
++      pCur->pNode = pX->pParent;
++      while( pCur->pNode && (pCur->pNode->pRight == pX) ){
++        pX = pCur->pNode;
++        pCur->pNode = pX->pParent;
++      }
++    }
++  }
++  pCur->eSkip = SKIP_NONE;
++
++  if( !pCur->pNode ){
++    *pRes = 1;
++  }else{
++    *pRes = 0;
++  }
++
++  return SQLITE_OK;
++}
++
++static int memRbtreePrevious(RbtCursor* pCur, int *pRes)
++{
++  if( pCur->pNode && pCur->eSkip != SKIP_PREV ){
++    if( pCur->pNode->pLeft ){
++      pCur->pNode = pCur->pNode->pLeft;
++      while( pCur->pNode->pRight )
++        pCur->pNode = pCur->pNode->pRight;
++    }else{
++      BtRbNode * pX = pCur->pNode;
++      pCur->pNode = pX->pParent;
++      while( pCur->pNode && (pCur->pNode->pLeft == pX) ){
++        pX = pCur->pNode;
++        pCur->pNode = pX->pParent;
++      }
++    }
++  }
++  pCur->eSkip = SKIP_NONE;
++
++  if( !pCur->pNode ){
++    *pRes = 1;
++  }else{
++    *pRes = 0;
++  }
++
++  return SQLITE_OK;
++}
++
++static int memRbtreeKeySize(RbtCursor* pCur, int *pSize)
++{
++  if( pCur->pNode ){
++    *pSize = pCur->pNode->nKey;
++  }else{
++    *pSize = 0;
++  }
++  return SQLITE_OK;
++}
++
++static int memRbtreeKey(RbtCursor* pCur, int offset, int amt, char *zBuf)
++{
++  if( !pCur->pNode ) return 0;
++  if( !pCur->pNode->pKey || ((amt + offset) <= pCur->pNode->nKey) ){
++    memcpy(zBuf, ((char*)pCur->pNode->pKey)+offset, amt);
++  }else{
++    memcpy(zBuf, ((char*)pCur->pNode->pKey)+offset, pCur->pNode->nKey-offset);
++    amt = pCur->pNode->nKey-offset;
++  }
++  return amt;
++}
++
++static int memRbtreeDataSize(RbtCursor* pCur, int *pSize)
++{
++  if( pCur->pNode ){
++    *pSize = pCur->pNode->nData;
++  }else{
++    *pSize = 0;
++  }
++  return SQLITE_OK;
++}
++
++static int memRbtreeData(RbtCursor *pCur, int offset, int amt, char *zBuf)
++{
++  if( !pCur->pNode ) return 0;
++  if( (amt + offset) <= pCur->pNode->nData ){
++    memcpy(zBuf, ((char*)pCur->pNode->pData)+offset, amt);
++  }else{
++    memcpy(zBuf, ((char*)pCur->pNode->pData)+offset ,pCur->pNode->nData-offset);
++    amt = pCur->pNode->nData-offset;
++  }
++  return amt;
++}
++
++static int memRbtreeCloseCursor(RbtCursor* pCur)
++{
++  if( pCur->pTree->pCursors==pCur ){
++    pCur->pTree->pCursors = pCur->pShared;
++  }else{
++    RbtCursor *p = pCur->pTree->pCursors;
++    while( p && p->pShared!=pCur ){ p = p->pShared; }
++    assert( p!=0 );
++    if( p ){
++      p->pShared = pCur->pShared;
++    }
++  }
++  sqliteFree(pCur);
++  return SQLITE_OK;
++}
++
++static int memRbtreeGetMeta(Rbtree* tree, int* aMeta)
++{
++  memcpy( aMeta, tree->aMetaData, sizeof(int) * SQLITE_N_BTREE_META );
++  return SQLITE_OK;
++}
++
++static int memRbtreeUpdateMeta(Rbtree* tree, int* aMeta)
++{
++  memcpy( tree->aMetaData, aMeta, sizeof(int) * SQLITE_N_BTREE_META );
++  return SQLITE_OK;
++}
++
++/*
++ * Check that each table in the Rbtree meets the requirements for a red-black
++ * binary tree. If an error is found, return an explanation of the problem in 
++ * memory obtained from sqliteMalloc(). Parameters aRoot and nRoot are ignored. 
++ */
++static char *memRbtreeIntegrityCheck(Rbtree* tree, int* aRoot, int nRoot)
++{
++  char * msg = 0;
++  HashElem *p;
++
++  for(p=sqliteHashFirst(&tree->tblHash); p; p=sqliteHashNext(p)){
++    BtRbTree *pTree = sqliteHashData(p);
++    check_redblack_tree(pTree, &msg);
++  }
++
++  return msg;
++}
++
++static int memRbtreeSetCacheSize(Rbtree* tree, int sz)
++{
++  return SQLITE_OK;
++}
++
++static int memRbtreeSetSafetyLevel(Rbtree *pBt, int level){
++  return SQLITE_OK;
++}
++
++static int memRbtreeBeginTrans(Rbtree* tree)
++{
++  if( tree->eTransState != TRANS_NONE ) 
++    return SQLITE_ERROR;
++
++  assert( tree->pTransRollback == 0 );
++  tree->eTransState = TRANS_INTRANSACTION;
++  return SQLITE_OK;
++}
++
++/*
++** Delete a linked list of BtRollbackOp structures.
++*/
++static void deleteRollbackList(BtRollbackOp *pOp){
++  while( pOp ){
++    BtRollbackOp *pTmp = pOp->pNext;
++    sqliteFree(pOp->pData);
++    sqliteFree(pOp->pKey);
++    sqliteFree(pOp);
++    pOp = pTmp;
++  }
++}
++
++static int memRbtreeCommit(Rbtree* tree){
++  /* Just delete pTransRollback and pCheckRollback */
++  deleteRollbackList(tree->pCheckRollback);
++  deleteRollbackList(tree->pTransRollback);
++  tree->pTransRollback = 0;
++  tree->pCheckRollback = 0;
++  tree->pCheckRollbackTail = 0;
++  tree->eTransState = TRANS_NONE;
++  return SQLITE_OK;
++}
++
++/*
++ * Close the supplied Rbtree. Delete everything associated with it.
++ */
++static int memRbtreeClose(Rbtree* tree)
++{
++  HashElem *p;
++  memRbtreeCommit(tree);
++  while( (p=sqliteHashFirst(&tree->tblHash))!=0 ){
++    tree->eTransState = TRANS_ROLLBACK;
++    memRbtreeDropTable(tree, sqliteHashKeysize(p));
++  }
++  sqliteHashClear(&tree->tblHash);
++  sqliteFree(tree);
++  return SQLITE_OK;
++}
++
++/*
++ * Execute and delete the supplied rollback-list on pRbtree.
++ */
++static void execute_rollback_list(Rbtree *pRbtree, BtRollbackOp *pList)
++{
++  BtRollbackOp *pTmp;
++  RbtCursor cur;
++  int res;
++
++  cur.pRbtree = pRbtree;
++  cur.wrFlag = 1;
++  while( pList ){
++    switch( pList->eOp ){
++      case ROLLBACK_INSERT:
++        cur.pTree  = sqliteHashFind( &pRbtree->tblHash, 0, pList->iTab );
++        assert(cur.pTree);
++        cur.iTree  = pList->iTab;
++        cur.eSkip  = SKIP_NONE;
++        memRbtreeInsert( &cur, pList->pKey,
++            pList->nKey, pList->pData, pList->nData );
++        break;
++      case ROLLBACK_DELETE:
++        cur.pTree  = sqliteHashFind( &pRbtree->tblHash, 0, pList->iTab );
++        assert(cur.pTree);
++        cur.iTree  = pList->iTab;
++        cur.eSkip  = SKIP_NONE;
++        memRbtreeMoveto(&cur, pList->pKey, pList->nKey, &res);
++        assert(res == 0);
++        memRbtreeDelete( &cur );
++        break;
++      case ROLLBACK_CREATE:
++        btreeCreateTable(pRbtree, pList->iTab);
++        break;
++      case ROLLBACK_DROP:
++        memRbtreeDropTable(pRbtree, pList->iTab);
++        break;
++      default:
++        assert(0);
++    }
++    sqliteFree(pList->pKey);
++    sqliteFree(pList->pData);
++    pTmp = pList->pNext;
++    sqliteFree(pList);
++    pList = pTmp;
++  }
++}
++
++static int memRbtreeRollback(Rbtree* tree)
++{
++  tree->eTransState = TRANS_ROLLBACK;
++  execute_rollback_list(tree, tree->pCheckRollback);
++  execute_rollback_list(tree, tree->pTransRollback);
++  tree->pTransRollback = 0;
++  tree->pCheckRollback = 0;
++  tree->pCheckRollbackTail = 0;
++  tree->eTransState = TRANS_NONE;
++  return SQLITE_OK;
++}
++
++static int memRbtreeBeginCkpt(Rbtree* tree)
++{
++  if( tree->eTransState != TRANS_INTRANSACTION ) 
++    return SQLITE_ERROR;
++
++  assert( tree->pCheckRollback == 0 );
++  assert( tree->pCheckRollbackTail == 0 );
++  tree->eTransState = TRANS_INCHECKPOINT;
++  return SQLITE_OK;
++}
++
++static int memRbtreeCommitCkpt(Rbtree* tree)
++{
++  if( tree->eTransState == TRANS_INCHECKPOINT ){ 
++    if( tree->pCheckRollback ){
++      tree->pCheckRollbackTail->pNext = tree->pTransRollback;
++      tree->pTransRollback = tree->pCheckRollback;
++      tree->pCheckRollback = 0;
++      tree->pCheckRollbackTail = 0;
++    }
++    tree->eTransState = TRANS_INTRANSACTION;
++  }
++  return SQLITE_OK;
++}
++
++static int memRbtreeRollbackCkpt(Rbtree* tree)
++{
++  if( tree->eTransState != TRANS_INCHECKPOINT ) return SQLITE_OK;
++  tree->eTransState = TRANS_ROLLBACK;
++  execute_rollback_list(tree, tree->pCheckRollback);
++  tree->pCheckRollback = 0;
++  tree->pCheckRollbackTail = 0;
++  tree->eTransState = TRANS_INTRANSACTION;
++  return SQLITE_OK;
++}
++
++#ifdef SQLITE_TEST
++static int memRbtreePageDump(Rbtree* tree, int pgno, int rec)
++{
++  assert(!"Cannot call sqliteRbtreePageDump");
++  return SQLITE_OK;
++}
++
++static int memRbtreeCursorDump(RbtCursor* pCur, int* aRes)
++{
++  assert(!"Cannot call sqliteRbtreeCursorDump");
++  return SQLITE_OK;
++}
++#endif
++
++static struct Pager *memRbtreePager(Rbtree* tree)
++{
++  return 0;
++}
++
++/*
++** Return the full pathname of the underlying database file.
++*/
++static const char *memRbtreeGetFilename(Rbtree *pBt){
++  return 0;  /* A NULL return indicates there is no underlying file */
++}
++
++/*
++** The copy file function is not implemented for the in-memory database
++*/
++static int memRbtreeCopyFile(Rbtree *pBt, Rbtree *pBt2){
++  return SQLITE_INTERNAL;  /* Not implemented */
++}
++
++static BtOps sqliteRbtreeOps = {
++    (int(*)(Btree*)) memRbtreeClose,
++    (int(*)(Btree*,int)) memRbtreeSetCacheSize,
++    (int(*)(Btree*,int)) memRbtreeSetSafetyLevel,
++    (int(*)(Btree*)) memRbtreeBeginTrans,
++    (int(*)(Btree*)) memRbtreeCommit,
++    (int(*)(Btree*)) memRbtreeRollback,
++    (int(*)(Btree*)) memRbtreeBeginCkpt,
++    (int(*)(Btree*)) memRbtreeCommitCkpt,
++    (int(*)(Btree*)) memRbtreeRollbackCkpt,
++    (int(*)(Btree*,int*)) memRbtreeCreateTable,
++    (int(*)(Btree*,int*)) memRbtreeCreateTable,
++    (int(*)(Btree*,int)) memRbtreeDropTable,
++    (int(*)(Btree*,int)) memRbtreeClearTable,
++    (int(*)(Btree*,int,int,BtCursor**)) memRbtreeCursor,
++    (int(*)(Btree*,int*)) memRbtreeGetMeta,
++    (int(*)(Btree*,int*)) memRbtreeUpdateMeta,
++    (char*(*)(Btree*,int*,int)) memRbtreeIntegrityCheck,
++    (const char*(*)(Btree*)) memRbtreeGetFilename,
++    (int(*)(Btree*,Btree*)) memRbtreeCopyFile,
++    (struct Pager*(*)(Btree*)) memRbtreePager,
++#ifdef SQLITE_TEST
++    (int(*)(Btree*,int,int)) memRbtreePageDump,
++#endif
++};
++
++static BtCursorOps sqliteRbtreeCursorOps = {
++    (int(*)(BtCursor*,const void*,int,int*)) memRbtreeMoveto,
++    (int(*)(BtCursor*)) memRbtreeDelete,
++    (int(*)(BtCursor*,const void*,int,const void*,int)) memRbtreeInsert,
++    (int(*)(BtCursor*,int*)) memRbtreeFirst,
++    (int(*)(BtCursor*,int*)) memRbtreeLast,
++    (int(*)(BtCursor*,int*)) memRbtreeNext,
++    (int(*)(BtCursor*,int*)) memRbtreePrevious,
++    (int(*)(BtCursor*,int*)) memRbtreeKeySize,
++    (int(*)(BtCursor*,int,int,char*)) memRbtreeKey,
++    (int(*)(BtCursor*,const void*,int,int,int*)) memRbtreeKeyCompare,
++    (int(*)(BtCursor*,int*)) memRbtreeDataSize,
++    (int(*)(BtCursor*,int,int,char*)) memRbtreeData,
++    (int(*)(BtCursor*)) memRbtreeCloseCursor,
++#ifdef SQLITE_TEST
++    (int(*)(BtCursor*,int*)) memRbtreeCursorDump,
++#endif
++
++};
++
++#endif /* SQLITE_OMIT_INMEMORYDB */
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/build.c
+@@ -0,0 +1,2156 @@
++/*
++** 2001 September 15
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This file contains C code routines that are called by the SQLite parser
++** when syntax rules are reduced.  The routines in this file handle the
++** following kinds of SQL syntax:
++**
++**     CREATE TABLE
++**     DROP TABLE
++**     CREATE INDEX
++**     DROP INDEX
++**     creating ID lists
++**     BEGIN TRANSACTION
++**     COMMIT
++**     ROLLBACK
++**     PRAGMA
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++#include <ctype.h>
++
++/*
++** This routine is called when a new SQL statement is beginning to
++** be parsed.  Check to see if the schema for the database needs
++** to be read from the SQLITE_MASTER and SQLITE_TEMP_MASTER tables.
++** If it does, then read it.
++*/
++void sqliteBeginParse(Parse *pParse, int explainFlag){
++  sqlite *db = pParse->db;
++  int i;
++  pParse->explain = explainFlag;
++  if((db->flags & SQLITE_Initialized)==0 && db->init.busy==0 ){
++    int rc = sqliteInit(db, &pParse->zErrMsg);
++    if( rc!=SQLITE_OK ){
++      pParse->rc = rc;
++      pParse->nErr++;
++    }
++  }
++  for(i=0; i<db->nDb; i++){
++    DbClearProperty(db, i, DB_Locked);
++    if( !db->aDb[i].inTrans ){
++      DbClearProperty(db, i, DB_Cookie);
++    }
++  }
++  pParse->nVar = 0;
++}
++
++/*
++** This routine is called after a single SQL statement has been
++** parsed and we want to execute the VDBE code to implement 
++** that statement.  Prior action routines should have already
++** constructed VDBE code to do the work of the SQL statement.
++** This routine just has to execute the VDBE code.
++**
++** Note that if an error occurred, it might be the case that
++** no VDBE code was generated.
++*/
++void sqliteExec(Parse *pParse){
++  sqlite *db = pParse->db;
++  Vdbe *v = pParse->pVdbe;
++
++  if( v==0 && (v = sqliteGetVdbe(pParse))!=0 ){
++    sqliteVdbeAddOp(v, OP_Halt, 0, 0);
++  }
++  if( sqlite_malloc_failed ) return;
++  if( v && pParse->nErr==0 ){
++    FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
++    sqliteVdbeTrace(v, trace);
++    sqliteVdbeMakeReady(v, pParse->nVar, pParse->explain);
++    pParse->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE;
++    pParse->colNamesSet = 0;
++  }else if( pParse->rc==SQLITE_OK ){
++    pParse->rc = SQLITE_ERROR;
++  }
++  pParse->nTab = 0;
++  pParse->nMem = 0;
++  pParse->nSet = 0;
++  pParse->nAgg = 0;
++  pParse->nVar = 0;
++}
++
++/*
++** Locate the in-memory structure that describes 
++** a particular database table given the name
++** of that table and (optionally) the name of the database
++** containing the table.  Return NULL if not found.
++**
++** If zDatabase is 0, all databases are searched for the
++** table and the first matching table is returned.  (No checking
++** for duplicate table names is done.)  The search order is
++** TEMP first, then MAIN, then any auxiliary databases added
++** using the ATTACH command.
++**
++** See also sqliteLocateTable().
++*/
++Table *sqliteFindTable(sqlite *db, const char *zName, const char *zDatabase){
++  Table *p = 0;
++  int i;
++  for(i=0; i<db->nDb; i++){
++    int j = (i<2) ? i^1 : i;   /* Search TEMP before MAIN */
++    if( zDatabase!=0 && sqliteStrICmp(zDatabase, db->aDb[j].zName) ) continue;
++    p = sqliteHashFind(&db->aDb[j].tblHash, zName, strlen(zName)+1);
++    if( p ) break;
++  }
++  return p;
++}
++
++/*
++** Locate the in-memory structure that describes 
++** a particular database table given the name
++** of that table and (optionally) the name of the database
++** containing the table.  Return NULL if not found.
++** Also leave an error message in pParse->zErrMsg.
++**
++** The difference between this routine and sqliteFindTable()
++** is that this routine leaves an error message in pParse->zErrMsg
++** where sqliteFindTable() does not.
++*/
++Table *sqliteLocateTable(Parse *pParse, const char *zName, const char *zDbase){
++  Table *p;
++
++  p = sqliteFindTable(pParse->db, zName, zDbase);
++  if( p==0 ){
++    if( zDbase ){
++      sqliteErrorMsg(pParse, "no such table: %s.%s", zDbase, zName);
++    }else if( sqliteFindTable(pParse->db, zName, 0)!=0 ){
++      sqliteErrorMsg(pParse, "table \"%s\" is not in database \"%s\"",
++         zName, zDbase);
++    }else{
++      sqliteErrorMsg(pParse, "no such table: %s", zName);
++    }
++  }
++  return p;
++}
++
++/*
++** Locate the in-memory structure that describes 
++** a particular index given the name of that index
++** and the name of the database that contains the index.
++** Return NULL if not found.
++**
++** If zDatabase is 0, all databases are searched for the
++** table and the first matching index is returned.  (No checking
++** for duplicate index names is done.)  The search order is
++** TEMP first, then MAIN, then any auxiliary databases added
++** using the ATTACH command.
++*/
++Index *sqliteFindIndex(sqlite *db, const char *zName, const char *zDb){
++  Index *p = 0;
++  int i;
++  for(i=0; i<db->nDb; i++){
++    int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
++    if( zDb && sqliteStrICmp(zDb, db->aDb[j].zName) ) continue;
++    p = sqliteHashFind(&db->aDb[j].idxHash, zName, strlen(zName)+1);
++    if( p ) break;
++  }
++  return p;
++}
++
++/*
++** Remove the given index from the index hash table, and free
++** its memory structures.
++**
++** The index is removed from the database hash tables but
++** it is not unlinked from the Table that it indexes.
++** Unlinking from the Table must be done by the calling function.
++*/
++static void sqliteDeleteIndex(sqlite *db, Index *p){
++  Index *pOld;
++
++  assert( db!=0 && p->zName!=0 );
++  pOld = sqliteHashInsert(&db->aDb[p->iDb].idxHash, p->zName,
++                          strlen(p->zName)+1, 0);
++  if( pOld!=0 && pOld!=p ){
++    sqliteHashInsert(&db->aDb[p->iDb].idxHash, pOld->zName,
++                     strlen(pOld->zName)+1, pOld);
++  }
++  sqliteFree(p);
++}
++
++/*
++** Unlink the given index from its table, then remove
++** the index from the index hash table and free its memory
++** structures.
++*/
++void sqliteUnlinkAndDeleteIndex(sqlite *db, Index *pIndex){
++  if( pIndex->pTable->pIndex==pIndex ){
++    pIndex->pTable->pIndex = pIndex->pNext;
++  }else{
++    Index *p;
++    for(p=pIndex->pTable->pIndex; p && p->pNext!=pIndex; p=p->pNext){}
++    if( p && p->pNext==pIndex ){
++      p->pNext = pIndex->pNext;
++    }
++  }
++  sqliteDeleteIndex(db, pIndex);
++}
++
++/*
++** Erase all schema information from the in-memory hash tables of
++** database connection.  This routine is called to reclaim memory
++** before the connection closes.  It is also called during a rollback
++** if there were schema changes during the transaction.
++**
++** If iDb<=0 then reset the internal schema tables for all database
++** files.  If iDb>=2 then reset the internal schema for only the
++** single file indicated.
++*/
++void sqliteResetInternalSchema(sqlite *db, int iDb){
++  HashElem *pElem;
++  Hash temp1;
++  Hash temp2;
++  int i, j;
++
++  assert( iDb>=0 && iDb<db->nDb );
++  db->flags &= ~SQLITE_Initialized;
++  for(i=iDb; i<db->nDb; i++){
++    Db *pDb = &db->aDb[i];
++    temp1 = pDb->tblHash;
++    temp2 = pDb->trigHash;
++    sqliteHashInit(&pDb->trigHash, SQLITE_HASH_STRING, 0);
++    sqliteHashClear(&pDb->aFKey);
++    sqliteHashClear(&pDb->idxHash);
++    for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
++      Trigger *pTrigger = sqliteHashData(pElem);
++      sqliteDeleteTrigger(pTrigger);
++    }
++    sqliteHashClear(&temp2);
++    sqliteHashInit(&pDb->tblHash, SQLITE_HASH_STRING, 0);
++    for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
++      Table *pTab = sqliteHashData(pElem);
++      sqliteDeleteTable(db, pTab);
++    }
++    sqliteHashClear(&temp1);
++    DbClearProperty(db, i, DB_SchemaLoaded);
++    if( iDb>0 ) return;
++  }
++  assert( iDb==0 );
++  db->flags &= ~SQLITE_InternChanges;
++
++  /* If one or more of the auxiliary database files has been closed,
++  ** then remove then from the auxiliary database list.  We take the
++  ** opportunity to do this here since we have just deleted all of the
++  ** schema hash tables and therefore do not have to make any changes
++  ** to any of those tables.
++  */
++  for(i=0; i<db->nDb; i++){
++    struct Db *pDb = &db->aDb[i];
++    if( pDb->pBt==0 ){
++      if( pDb->pAux && pDb->xFreeAux ) pDb->xFreeAux(pDb->pAux);
++      pDb->pAux = 0;
++    }
++  }
++  for(i=j=2; i<db->nDb; i++){
++    struct Db *pDb = &db->aDb[i];
++    if( pDb->pBt==0 ){
++      sqliteFree(pDb->zName);
++      pDb->zName = 0;
++      continue;
++    }
++    if( j<i ){
++      db->aDb[j] = db->aDb[i];
++    }
++    j++;
++  }
++  memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j]));
++  db->nDb = j;
++  if( db->nDb<=2 && db->aDb!=db->aDbStatic ){
++    memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0]));
++    sqliteFree(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 sqliteRollbackInternalChanges(sqlite *db){
++  if( db->flags & SQLITE_InternChanges ){
++    sqliteResetInternalSchema(db, 0);
++  }
++}
++
++/*
++** This routine is called when a commit occurs.
++*/
++void sqliteCommitInternalChanges(sqlite *db){
++  db->aDb[0].schema_cookie = db->next_cookie;
++  db->flags &= ~SQLITE_InternChanges;
++}
++
++/*
++** Remove the memory data structures associated with the given
++** Table.  No changes are made to disk by this routine.
++**
++** This routine just deletes the data structure.  It does not unlink
++** the table data structure from the hash table.  Nor does it remove
++** 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 sqliteDeleteTable(sqlite *db, Table *pTable){
++  int i;
++  Index *pIndex, *pNext;
++  FKey *pFKey, *pNextFKey;
++
++  if( pTable==0 ) return;
++
++  /* Delete all indices associated with this table
++  */
++  for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
++    pNext = pIndex->pNext;
++    assert( pIndex->iDb==pTable->iDb || (pTable->iDb==0 && pIndex->iDb==1) );
++    sqliteDeleteIndex(db, pIndex);
++  }
++
++  /* Delete all foreign keys associated with this table.  The keys
++  ** should have already been unlinked from the db->aFKey hash table 
++  */
++  for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){
++    pNextFKey = pFKey->pNextFrom;
++    assert( pTable->iDb<db->nDb );
++    assert( sqliteHashFind(&db->aDb[pTable->iDb].aFKey,
++                           pFKey->zTo, strlen(pFKey->zTo)+1)!=pFKey );
++    sqliteFree(pFKey);
++  }
++
++  /* Delete the Table structure itself.
++  */
++  for(i=0; i<pTable->nCol; i++){
++    sqliteFree(pTable->aCol[i].zName);
++    sqliteFree(pTable->aCol[i].zDflt);
++    sqliteFree(pTable->aCol[i].zType);
++  }
++  sqliteFree(pTable->zName);
++  sqliteFree(pTable->aCol);
++  sqliteSelectDelete(pTable->pSelect);
++  sqliteFree(pTable);
++}
++
++/*
++** Unlink the given table from the hash tables and the delete the
++** table structure with all its indices and foreign keys.
++*/
++static void sqliteUnlinkAndDeleteTable(sqlite *db, Table *p){
++  Table *pOld;
++  FKey *pF1, *pF2;
++  int i = p->iDb;
++  assert( db!=0 );
++  pOld = sqliteHashInsert(&db->aDb[i].tblHash, p->zName, strlen(p->zName)+1, 0);
++  assert( pOld==0 || pOld==p );
++  for(pF1=p->pFKey; pF1; pF1=pF1->pNextFrom){
++    int nTo = strlen(pF1->zTo) + 1;
++    pF2 = sqliteHashFind(&db->aDb[i].aFKey, pF1->zTo, nTo);
++    if( pF2==pF1 ){
++      sqliteHashInsert(&db->aDb[i].aFKey, pF1->zTo, nTo, pF1->pNextTo);
++    }else{
++      while( pF2 && pF2->pNextTo!=pF1 ){ pF2=pF2->pNextTo; }
++      if( pF2 ){
++        pF2->pNextTo = pF1->pNextTo;
++      }
++    }
++  }
++  sqliteDeleteTable(db, p);
++}
++
++/*
++** Construct the name of a user table or index from a token.
++**
++** Space to hold the name is obtained from sqliteMalloc() and must
++** be freed by the calling function.
++*/
++char *sqliteTableNameFromToken(Token *pName){
++  char *zName = sqliteStrNDup(pName->z, pName->n);
++  sqliteDequote(zName);
++  return zName;
++}
++
++/*
++** Generate code to open the appropriate master table.  The table
++** opened will be SQLITE_MASTER for persistent tables and 
++** SQLITE_TEMP_MASTER for temporary tables.  The table is opened
++** on cursor 0.
++*/
++void sqliteOpenMasterTable(Vdbe *v, int isTemp){
++  sqliteVdbeAddOp(v, OP_Integer, isTemp, 0);
++  sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2);
++}
++
++/*
++** Begin constructing a new table representation in memory.  This is
++** the first of several action routines that get called in response
++** to a CREATE TABLE statement.  In particular, this routine is called
++** after seeing tokens "CREATE" and "TABLE" and the table name.  The
++** pStart token is the CREATE and pName is the table name.  The isTemp
++** flag is true if the table should be stored in the auxiliary database
++** file instead of in the main database file.  This is normally the case
++** when the "TEMP" or "TEMPORARY" keyword occurs in between
++** CREATE and TABLE.
++**
++** The new table record is initialized and put in pParse->pNewTable.
++** As more of the CREATE TABLE statement is parsed, additional action
++** routines will be called to add more information to this record.
++** At the end of the CREATE TABLE statement, the sqliteEndTable() routine
++** is called to complete the construction of the new table record.
++*/
++void sqliteStartTable(
++  Parse *pParse,   /* Parser context */
++  Token *pStart,   /* The "CREATE" token */
++  Token *pName,    /* Name of table or view to create */
++  int isTemp,      /* True if this is a TEMP table */
++  int isView       /* True if this is a VIEW */
++){
++  Table *pTable;
++  Index *pIdx;
++  char *zName;
++  sqlite *db = pParse->db;
++  Vdbe *v;
++  int iDb;
++
++  pParse->sFirstToken = *pStart;
++  zName = sqliteTableNameFromToken(pName);
++  if( zName==0 ) return;
++  if( db->init.iDb==1 ) isTemp = 1;
++#ifndef SQLITE_OMIT_AUTHORIZATION
++  assert( (isTemp & 1)==isTemp );
++  {
++    int code;
++    char *zDb = isTemp ? "temp" : "main";
++    if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
++      sqliteFree(zName);
++      return;
++    }
++    if( isView ){
++      if( isTemp ){
++        code = SQLITE_CREATE_TEMP_VIEW;
++      }else{
++        code = SQLITE_CREATE_VIEW;
++      }
++    }else{
++      if( isTemp ){
++        code = SQLITE_CREATE_TEMP_TABLE;
++      }else{
++        code = SQLITE_CREATE_TABLE;
++      }
++    }
++    if( sqliteAuthCheck(pParse, code, zName, 0, zDb) ){
++      sqliteFree(zName);
++      return;
++    }
++  }
++#endif
++ 
++
++  /* Before trying to create a temporary table, make sure the Btree for
++  ** holding temporary tables is open.
++  */
++  if( isTemp && db->aDb[1].pBt==0 && !pParse->explain ){
++    int rc = sqliteBtreeFactory(db, 0, 0, MAX_PAGES, &db->aDb[1].pBt);
++    if( rc!=SQLITE_OK ){
++      sqliteErrorMsg(pParse, "unable to open a temporary database "
++        "file for storing temporary tables");
++      pParse->nErr++;
++      return;
++    }
++    if( db->flags & SQLITE_InTrans ){
++      rc = sqliteBtreeBeginTrans(db->aDb[1].pBt);
++      if( rc!=SQLITE_OK ){
++        sqliteErrorMsg(pParse, "unable to get a write lock on "
++          "the temporary database file");
++        return;
++      }
++    }
++  }
++
++  /* Make sure the new table name does not collide with an existing
++  ** index or table name.  Issue an error message if it does.
++  **
++  ** If we are re-reading the sqlite_master table because of a schema
++  ** change and a new permanent table is found whose name collides with
++  ** an existing temporary table, that is not an error.
++  */
++  pTable = sqliteFindTable(db, zName, 0);
++  iDb = isTemp ? 1 : db->init.iDb;
++  if( pTable!=0 && (pTable->iDb==iDb || !db->init.busy) ){
++    sqliteErrorMsg(pParse, "table %T already exists", pName);
++    sqliteFree(zName);
++    return;
++  }
++  if( (pIdx = sqliteFindIndex(db, zName, 0))!=0 &&
++          (pIdx->iDb==0 || !db->init.busy) ){
++    sqliteErrorMsg(pParse, "there is already an index named %s", zName);
++    sqliteFree(zName);
++    return;
++  }
++  pTable = sqliteMalloc( sizeof(Table) );
++  if( pTable==0 ){
++    sqliteFree(zName);
++    return;
++  }
++  pTable->zName = zName;
++  pTable->nCol = 0;
++  pTable->aCol = 0;
++  pTable->iPKey = -1;
++  pTable->pIndex = 0;
++  pTable->iDb = iDb;
++  if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable);
++  pParse->pNewTable = pTable;
++
++  /* Begin generating the code that will insert the table record into
++  ** the SQLITE_MASTER table.  Note in particular that we must go ahead
++  ** and allocate the record number for the table entry now.  Before any
++  ** PRIMARY KEY or UNIQUE keywords are parsed.  Those keywords will cause
++  ** indices to be created and the table record must come before the 
++  ** indices.  Hence, the record number for the table must be allocated
++  ** now.
++  */
++  if( !db->init.busy && (v = sqliteGetVdbe(pParse))!=0 ){
++    sqliteBeginWriteOperation(pParse, 0, isTemp);
++    if( !isTemp ){
++      sqliteVdbeAddOp(v, OP_Integer, db->file_format, 0);
++      sqliteVdbeAddOp(v, OP_SetCookie, 0, 1);
++    }
++    sqliteOpenMasterTable(v, isTemp);
++    sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
++    sqliteVdbeAddOp(v, OP_Dup, 0, 0);
++    sqliteVdbeAddOp(v, OP_String, 0, 0);
++    sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
++  }
++}
++
++/*
++** Add a new column to the table currently being constructed.
++**
++** The parser calls this routine once for each column declaration
++** in a CREATE TABLE statement.  sqliteStartTable() gets called
++** first to get things going.  Then this routine is called for each
++** column.
++*/
++void sqliteAddColumn(Parse *pParse, Token *pName){
++  Table *p;
++  int i;
++  char *z = 0;
++  Column *pCol;
++  if( (p = pParse->pNewTable)==0 ) return;
++  sqliteSetNString(&z, pName->z, pName->n, 0);
++  if( z==0 ) return;
++  sqliteDequote(z);
++  for(i=0; i<p->nCol; i++){
++    if( sqliteStrICmp(z, p->aCol[i].zName)==0 ){
++      sqliteErrorMsg(pParse, "duplicate column name: %s", z);
++      sqliteFree(z);
++      return;
++    }
++  }
++  if( (p->nCol & 0x7)==0 ){
++    Column *aNew;
++    aNew = sqliteRealloc( p->aCol, (p->nCol+8)*sizeof(p->aCol[0]));
++    if( aNew==0 ) return;
++    p->aCol = aNew;
++  }
++  pCol = &p->aCol[p->nCol];
++  memset(pCol, 0, sizeof(p->aCol[0]));
++  pCol->zName = z;
++  pCol->sortOrder = SQLITE_SO_NUM;
++  p->nCol++;
++}
++
++/*
++** This routine is called by the parser while in the middle of
++** parsing a CREATE TABLE statement.  A "NOT NULL" constraint has
++** been seen on a column.  This routine sets the notNull flag on
++** the column currently under construction.
++*/
++void sqliteAddNotNull(Parse *pParse, int onError){
++  Table *p;
++  int i;
++  if( (p = pParse->pNewTable)==0 ) return;
++  i = p->nCol-1;
++  if( i>=0 ) p->aCol[i].notNull = onError;
++}
++
++/*
++** This routine is called by the parser while in the middle of
++** parsing a CREATE TABLE statement.  The pFirst token is the first
++** token in the sequence of tokens that describe the type of the
++** column currently under construction.   pLast is the last token
++** in the sequence.  Use this information to construct a string
++** that contains the typename of the column and store that string
++** in zType.
++*/ 
++void sqliteAddColumnType(Parse *pParse, Token *pFirst, Token *pLast){
++  Table *p;
++  int i, j;
++  int n;
++  char *z, **pz;
++  Column *pCol;
++  if( (p = pParse->pNewTable)==0 ) return;
++  i = p->nCol-1;
++  if( i<0 ) return;
++  pCol = &p->aCol[i];
++  pz = &pCol->zType;
++  n = pLast->n + Addr(pLast->z) - Addr(pFirst->z);
++  sqliteSetNString(pz, pFirst->z, n, 0);
++  z = *pz;
++  if( z==0 ) return;
++  for(i=j=0; z[i]; i++){
++    int c = z[i];
++    if( isspace(c) ) continue;
++    z[j++] = c;
++  }
++  z[j] = 0;
++  if( pParse->db->file_format>=4 ){
++    pCol->sortOrder = sqliteCollateType(z, n);
++  }else{
++    pCol->sortOrder = SQLITE_SO_NUM;
++  }
++}
++
++/*
++** The given token is the default value for the last column added to
++** the table currently under construction.  If "minusFlag" is true, it
++** means the value token was preceded by a minus sign.
++**
++** This routine is called by the parser while in the middle of
++** parsing a CREATE TABLE statement.
++*/
++void sqliteAddDefaultValue(Parse *pParse, Token *pVal, int minusFlag){
++  Table *p;
++  int i;
++  char **pz;
++  if( (p = pParse->pNewTable)==0 ) return;
++  i = p->nCol-1;
++  if( i<0 ) return;
++  pz = &p->aCol[i].zDflt;
++  if( minusFlag ){
++    sqliteSetNString(pz, "-", 1, pVal->z, pVal->n, 0);
++  }else{
++    sqliteSetNString(pz, pVal->z, pVal->n, 0);
++  }
++  sqliteDequote(*pz);
++}
++
++/*
++** Designate the PRIMARY KEY for the table.  pList is a list of names 
++** of columns that form the primary key.  If pList is NULL, then the
++** most recently added column of the table is the primary key.
++**
++** A table can have at most one primary key.  If the table already has
++** a primary key (and this is the second primary key) then create an
++** error.
++**
++** If the PRIMARY KEY is on a single column whose datatype is INTEGER,
++** then we will try to use that column as the row id.  (Exception:
++** For backwards compatibility with older databases, do not do this
++** if the file format version number is less than 1.)  Set the Table.iPKey
++** field of the table under construction to be the index of the
++** INTEGER PRIMARY KEY column.  Table.iPKey is set to -1 if there is
++** no INTEGER PRIMARY KEY.
++**
++** If the key is not an INTEGER PRIMARY KEY, then create a unique
++** index for the key.  No index is created for INTEGER PRIMARY KEYs.
++*/
++void sqliteAddPrimaryKey(Parse *pParse, IdList *pList, int onError){
++  Table *pTab = pParse->pNewTable;
++  char *zType = 0;
++  int iCol = -1, i;
++  if( pTab==0 ) goto primary_key_exit;
++  if( pTab->hasPrimKey ){
++    sqliteErrorMsg(pParse, 
++      "table \"%s\" has more than one primary key", pTab->zName);
++    goto primary_key_exit;
++  }
++  pTab->hasPrimKey = 1;
++  if( pList==0 ){
++    iCol = pTab->nCol - 1;
++    pTab->aCol[iCol].isPrimKey = 1;
++  }else{
++    for(i=0; i<pList->nId; i++){
++      for(iCol=0; iCol<pTab->nCol; iCol++){
++        if( sqliteStrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ) break;
++      }
++      if( iCol<pTab->nCol ) pTab->aCol[iCol].isPrimKey = 1;
++    }
++    if( pList->nId>1 ) iCol = -1;
++  }
++  if( iCol>=0 && iCol<pTab->nCol ){
++    zType = pTab->aCol[iCol].zType;
++  }
++  if( pParse->db->file_format>=1 && 
++           zType && sqliteStrICmp(zType, "INTEGER")==0 ){
++    pTab->iPKey = iCol;
++    pTab->keyConf = onError;
++  }else{
++    sqliteCreateIndex(pParse, 0, 0, pList, onError, 0, 0);
++    pList = 0;
++  }
++
++primary_key_exit:
++  sqliteIdListDelete(pList);
++  return;
++}
++
++/*
++** Return the appropriate collating type given a type name.
++**
++** The collation type is text (SQLITE_SO_TEXT) if the type
++** name contains the character stream "text" or "blob" or
++** "clob".  Any other type name is collated as numeric
++** (SQLITE_SO_NUM).
++*/
++int sqliteCollateType(const char *zType, int nType){
++  int i;
++  for(i=0; i<nType-3; i++){
++    int c = *(zType++) | 0x60;
++    if( (c=='b' || c=='c') && sqliteStrNICmp(zType, "lob", 3)==0 ){
++      return SQLITE_SO_TEXT;
++    }
++    if( c=='c' && sqliteStrNICmp(zType, "har", 3)==0 ){
++      return SQLITE_SO_TEXT;
++    }
++    if( c=='t' && sqliteStrNICmp(zType, "ext", 3)==0 ){
++      return SQLITE_SO_TEXT;
++    }
++  }
++  return SQLITE_SO_NUM;
++}
++
++/*
++** This routine is called by the parser while in the middle of
++** parsing a CREATE TABLE statement.  A "COLLATE" clause has
++** been seen on a column.  This routine sets the Column.sortOrder on
++** the column currently under construction.
++*/
++void sqliteAddCollateType(Parse *pParse, int collType){
++  Table *p;
++  int i;
++  if( (p = pParse->pNewTable)==0 ) return;
++  i = p->nCol-1;
++  if( i>=0 ) p->aCol[i].sortOrder = collType;
++}
++
++/*
++** Come up with a new random value for the schema cookie.  Make sure
++** the new value is different from the old.
++**
++** The schema cookie is used to determine when the schema for the
++** database changes.  After each schema change, the cookie value
++** changes.  When a process first reads the schema it records the
++** cookie.  Thereafter, whenever it goes to access the database,
++** it checks the cookie to make sure the schema has not changed
++** since it was last read.
++**
++** This plan is not completely bullet-proof.  It is possible for
++** the schema to change multiple times and for the cookie to be
++** set back to prior value.  But schema changes are infrequent
++** and the probability of hitting the same cookie value is only
++** 1 chance in 2^32.  So we're safe enough.
++*/
++void sqliteChangeCookie(sqlite *db, Vdbe *v){
++  if( db->next_cookie==db->aDb[0].schema_cookie ){
++    unsigned char r;
++    sqliteRandomness(1, &r);
++    db->next_cookie = db->aDb[0].schema_cookie + r + 1;
++    db->flags |= SQLITE_InternChanges;
++    sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0);
++    sqliteVdbeAddOp(v, OP_SetCookie, 0, 0);
++  }
++}
++
++/*
++** Measure the number of characters needed to output the given
++** identifier.  The number returned includes any quotes used
++** but does not include the null terminator.
++*/
++static int identLength(const char *z){
++  int n;
++  int needQuote = 0;
++  for(n=0; *z; n++, z++){
++    if( *z=='\'' ){ n++; needQuote=1; }
++  }
++  return n + needQuote*2;
++}
++
++/*
++** Write an identifier onto the end of the given string.  Add
++** quote characters as needed.
++*/
++static void identPut(char *z, int *pIdx, char *zIdent){
++  int i, j, needQuote;
++  i = *pIdx;
++  for(j=0; zIdent[j]; j++){
++    if( !isalnum(zIdent[j]) && zIdent[j]!='_' ) break;
++  }
++  needQuote =  zIdent[j]!=0 || isdigit(zIdent[0])
++                  || sqliteKeywordCode(zIdent, j)!=TK_ID;
++  if( needQuote ) z[i++] = '\'';
++  for(j=0; zIdent[j]; j++){
++    z[i++] = zIdent[j];
++    if( zIdent[j]=='\'' ) z[i++] = '\'';
++  }
++  if( needQuote ) z[i++] = '\'';
++  z[i] = 0;
++  *pIdx = i;
++}
++
++/*
++** Generate a CREATE TABLE statement appropriate for the given
++** 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 i, k, n;
++  char *zStmt;
++  char *zSep, *zSep2, *zEnd;
++  n = 0;
++  for(i=0; i<p->nCol; i++){
++    n += identLength(p->aCol[i].zName);
++  }
++  n += identLength(p->zName);
++  if( n<40 ){
++    zSep = "";
++    zSep2 = ",";
++    zEnd = ")";
++  }else{
++    zSep = "\n  ";
++    zSep2 = ",\n  ";
++    zEnd = "\n)";
++  }
++  n += 35 + 6*p->nCol;
++  zStmt = sqliteMallocRaw( n );
++  if( zStmt==0 ) return 0;
++  strcpy(zStmt, p->iDb==1 ? "CREATE TEMP TABLE " : "CREATE TABLE ");
++  k = strlen(zStmt);
++  identPut(zStmt, &k, p->zName);
++  zStmt[k++] = '(';
++  for(i=0; i<p->nCol; i++){
++    strcpy(&zStmt[k], zSep);
++    k += strlen(&zStmt[k]);
++    zSep = zSep2;
++    identPut(zStmt, &k, p->aCol[i].zName);
++  }
++  strcpy(&zStmt[k], zEnd);
++  return zStmt;
++}
++
++/*
++** This routine is called to report the final ")" that terminates
++** a CREATE TABLE statement.
++**
++** The table structure that other action routines have been building
++** is added to the internal hash tables, assuming no errors have
++** occurred.
++**
++** An entry for the table is made in the master table on disk, unless
++** this is a temporary table or db->init.busy==1.  When db->init.busy==1
++** it means we are reading the sqlite_master table because we just
++** connected to the database or because the sqlite_master table has
++** recently changes, so the entry for this table already exists in
++** the sqlite_master table.  We do not want to create it again.
++**
++** If the pSelect argument is not NULL, it means that this routine
++** was called to create a table generated from a 
++** "CREATE TABLE ... AS SELECT ..." statement.  The column names of
++** the new table will match the result set of the SELECT.
++*/
++void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
++  Table *p;
++  sqlite *db = pParse->db;
++
++  if( (pEnd==0 && pSelect==0) || pParse->nErr || sqlite_malloc_failed ) return;
++  p = pParse->pNewTable;
++  if( p==0 ) return;
++
++  /* If the table is generated from a SELECT, then construct the
++  ** list of columns and the text of the table.
++  */
++  if( pSelect ){
++    Table *pSelTab = sqliteResultSetOfSelect(pParse, 0, pSelect);
++    if( pSelTab==0 ) return;
++    assert( p->aCol==0 );
++    p->nCol = pSelTab->nCol;
++    p->aCol = pSelTab->aCol;
++    pSelTab->nCol = 0;
++    pSelTab->aCol = 0;
++    sqliteDeleteTable(0, pSelTab);
++  }
++
++  /* If the db->init.busy is 1 it means we are reading the SQL off the
++  ** "sqlite_master" or "sqlite_temp_master" table on the disk.
++  ** So do not write to the disk again.  Extract the root page number
++  ** for the table from the db->init.newTnum field.  (The page number
++  ** should have been put there by the sqliteOpenCb routine.)
++  */
++  if( db->init.busy ){
++    p->tnum = db->init.newTnum;
++  }
++
++  /* If not initializing, then create a record for the new table
++  ** in the SQLITE_MASTER table of the database.  The record number
++  ** for the new table entry should already be on the stack.
++  **
++  ** If this is a TEMPORARY table, write the entry into the auxiliary
++  ** file instead of into the main database file.
++  */
++  if( !db->init.busy ){
++    int n;
++    Vdbe *v;
++
++    v = sqliteGetVdbe(pParse);
++    if( v==0 ) return;
++    if( p->pSelect==0 ){
++      /* A regular table */
++      sqliteVdbeOp3(v, OP_CreateTable, 0, p->iDb, (char*)&p->tnum, P3_POINTER);
++    }else{
++      /* A view */
++      sqliteVdbeAddOp(v, OP_Integer, 0, 0);
++    }
++    p->tnum = 0;
++    sqliteVdbeAddOp(v, OP_Pull, 1, 0);
++    sqliteVdbeOp3(v, OP_String, 0, 0, p->pSelect==0?"table":"view", P3_STATIC);
++    sqliteVdbeOp3(v, OP_String, 0, 0, p->zName, 0);
++    sqliteVdbeOp3(v, OP_String, 0, 0, p->zName, 0);
++    sqliteVdbeAddOp(v, OP_Dup, 4, 0);
++    sqliteVdbeAddOp(v, OP_String, 0, 0);
++    if( pSelect ){
++      char *z = createTableStmt(p);
++      n = z ? strlen(z) : 0;
++      sqliteVdbeChangeP3(v, -1, z, n);
++      sqliteFree(z);
++    }else{
++      assert( pEnd!=0 );
++      n = Addr(pEnd->z) - Addr(pParse->sFirstToken.z) + 1;
++      sqliteVdbeChangeP3(v, -1, pParse->sFirstToken.z, n);
++    }
++    sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
++    sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
++    if( !p->iDb ){
++      sqliteChangeCookie(db, v);
++    }
++    sqliteVdbeAddOp(v, OP_Close, 0, 0);
++    if( pSelect ){
++      sqliteVdbeAddOp(v, OP_Integer, p->iDb, 0);
++      sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0);
++      pParse->nTab = 2;
++      sqliteSelect(pParse, pSelect, SRT_Table, 1, 0, 0, 0);
++    }
++    sqliteEndWriteOperation(pParse);
++  }
++
++  /* Add the table to the in-memory representation of the database.
++  */
++  if( pParse->explain==0 && pParse->nErr==0 ){
++    Table *pOld;
++    FKey *pFKey;
++    pOld = sqliteHashInsert(&db->aDb[p->iDb].tblHash, 
++                            p->zName, strlen(p->zName)+1, p);
++    if( pOld ){
++      assert( p==pOld );  /* Malloc must have failed inside HashInsert() */
++      return;
++    }
++    for(pFKey=p->pFKey; pFKey; pFKey=pFKey->pNextFrom){
++      int nTo = strlen(pFKey->zTo) + 1;
++      pFKey->pNextTo = sqliteHashFind(&db->aDb[p->iDb].aFKey, pFKey->zTo, nTo);
++      sqliteHashInsert(&db->aDb[p->iDb].aFKey, pFKey->zTo, nTo, pFKey);
++    }
++    pParse->pNewTable = 0;
++    db->nTable++;
++    db->flags |= SQLITE_InternChanges;
++  }
++}
++
++/*
++** The parser calls this routine in order to create a new VIEW
++*/
++void sqliteCreateView(
++  Parse *pParse,     /* The parsing context */
++  Token *pBegin,     /* The CREATE token that begins the statement */
++  Token *pName,      /* 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 */
++){
++  Table *p;
++  int n;
++  const char *z;
++  Token sEnd;
++  DbFixer sFix;
++
++  sqliteStartTable(pParse, pBegin, pName, isTemp, 1);
++  p = pParse->pNewTable;
++  if( p==0 || pParse->nErr ){
++    sqliteSelectDelete(pSelect);
++    return;
++  }
++  if( sqliteFixInit(&sFix, pParse, p->iDb, "view", pName)
++    && sqliteFixSelect(&sFix, pSelect)
++  ){
++    sqliteSelectDelete(pSelect);
++    return;
++  }
++
++  /* Make a copy of the entire SELECT statement that defines the view.
++  ** This will force all the Expr.token.z values to be dynamically
++  ** allocated rather than point to the input string - which means that
++  ** they will persist after the current sqlite_exec() call returns.
++  */
++  p->pSelect = sqliteSelectDup(pSelect);
++  sqliteSelectDelete(pSelect);
++  if( !pParse->db->init.busy ){
++    sqliteViewGetColumnNames(pParse, p);
++  }
++
++  /* Locate the end of the CREATE VIEW statement.  Make sEnd point to
++  ** the end.
++  */
++  sEnd = pParse->sLastToken;
++  if( sEnd.z[0]!=0 && sEnd.z[0]!=';' ){
++    sEnd.z += sEnd.n;
++  }
++  sEnd.n = 0;
++  n = sEnd.z - pBegin->z;
++  z = pBegin->z;
++  while( n>0 && (z[n-1]==';' || isspace(z[n-1])) ){ n--; }
++  sEnd.z = &z[n-1];
++  sEnd.n = 1;
++
++  /* Use sqliteEndTable() to add the view to the SQLITE_MASTER table */
++  sqliteEndTable(pParse, &sEnd, 0);
++  return;
++}
++
++/*
++** The Table structure pTable is really a VIEW.  Fill in the names of
++** the columns of the view in the pTable structure.  Return the number
++** of errors.  If an error is seen leave an error message in pParse->zErrMsg.
++*/
++int sqliteViewGetColumnNames(Parse *pParse, Table *pTable){
++  ExprList *pEList;
++  Select *pSel;
++  Table *pSelTab;
++  int nErr = 0;
++
++  assert( pTable );
++
++  /* A positive nCol means the columns names for this view are
++  ** already known.
++  */
++  if( pTable->nCol>0 ) return 0;
++
++  /* A negative nCol is a special marker meaning that we are currently
++  ** trying to compute the column names.  If we enter this routine with
++  ** a negative nCol, it means two or more views form a loop, like this:
++  **
++  **     CREATE VIEW one AS SELECT * FROM two;
++  **     CREATE VIEW two AS SELECT * FROM one;
++  **
++  ** Actually, this error is caught previously and so the following test
++  ** should always fail.  But we will leave it in place just to be safe.
++  */
++  if( pTable->nCol<0 ){
++    sqliteErrorMsg(pParse, "view %s is circularly defined", pTable->zName);
++    return 1;
++  }
++
++  /* If we get this far, it means we need to compute the table names.
++  */
++  assert( pTable->pSelect ); /* If nCol==0, then pTable must be a VIEW */
++  pSel = pTable->pSelect;
++
++  /* Note that the call to sqliteResultSetOfSelect() will expand any
++  ** "*" elements in this list.  But we will need to restore the list
++  ** back to its original configuration afterwards, so we save a copy of
++  ** the original in pEList.
++  */
++  pEList = pSel->pEList;
++  pSel->pEList = sqliteExprListDup(pEList);
++  if( pSel->pEList==0 ){
++    pSel->pEList = pEList;
++    return 1;  /* Malloc failed */
++  }
++  pTable->nCol = -1;
++  pSelTab = sqliteResultSetOfSelect(pParse, 0, pSel);
++  if( pSelTab ){
++    assert( pTable->aCol==0 );
++    pTable->nCol = pSelTab->nCol;
++    pTable->aCol = pSelTab->aCol;
++    pSelTab->nCol = 0;
++    pSelTab->aCol = 0;
++    sqliteDeleteTable(0, pSelTab);
++    DbSetProperty(pParse->db, pTable->iDb, DB_UnresetViews);
++  }else{
++    pTable->nCol = 0;
++    nErr++;
++  }
++  sqliteSelectUnbind(pSel);
++  sqliteExprListDelete(pSel->pEList);
++  pSel->pEList = pEList;
++  return nErr;  
++}
++
++/*
++** Clear the column names from the VIEW pTable.
++**
++** This routine is called whenever any other table or view is modified.
++** The view passed into this routine might depend directly or indirectly
++** on the modified or deleted table so we need to clear the old column
++** names so that they will be recomputed.
++*/
++static void sqliteViewResetColumnNames(Table *pTable){
++  int i;
++  Column *pCol;
++  assert( pTable!=0 && pTable->pSelect!=0 );
++  for(i=0, pCol=pTable->aCol; i<pTable->nCol; i++, pCol++){
++    sqliteFree(pCol->zName);
++    sqliteFree(pCol->zDflt);
++    sqliteFree(pCol->zType);
++  }
++  sqliteFree(pTable->aCol);
++  pTable->aCol = 0;
++  pTable->nCol = 0;
++}
++
++/*
++** Clear the column names from every VIEW in database idx.
++*/
++static void sqliteViewResetAll(sqlite *db, int idx){
++  HashElem *i;
++  if( !DbHasProperty(db, idx, DB_UnresetViews) ) return;
++  for(i=sqliteHashFirst(&db->aDb[idx].tblHash); i; i=sqliteHashNext(i)){
++    Table *pTab = sqliteHashData(i);
++    if( pTab->pSelect ){
++      sqliteViewResetColumnNames(pTab);
++    }
++  }
++  DbClearProperty(db, idx, DB_UnresetViews);
++}
++
++/*
++** Given a token, look up a table with that name.  If not found, leave
++** an error for the parser to find and return NULL.
++*/
++Table *sqliteTableFromToken(Parse *pParse, Token *pTok){
++  char *zName;
++  Table *pTab;
++  zName = sqliteTableNameFromToken(pTok);
++  if( zName==0 ) return 0;
++  pTab = sqliteFindTable(pParse->db, zName, 0);
++  sqliteFree(zName);
++  if( pTab==0 ){
++    sqliteErrorMsg(pParse, "no such table: %T", pTok);
++  }
++  return pTab;
++}
++
++/*
++** This routine is called to do the work of a DROP TABLE statement.
++** pName is the name of the table to be dropped.
++*/
++void sqliteDropTable(Parse *pParse, Token *pName, int isView){
++  Table *pTable;
++  Vdbe *v;
++  int base;
++  sqlite *db = pParse->db;
++  int iDb;
++
++  if( pParse->nErr || sqlite_malloc_failed ) return;
++  pTable = sqliteTableFromToken(pParse, pName);
++  if( pTable==0 ) return;
++  iDb = pTable->iDb;
++  assert( iDb>=0 && iDb<db->nDb );
++#ifndef SQLITE_OMIT_AUTHORIZATION
++  {
++    int code;
++    const char *zTab = SCHEMA_TABLE(pTable->iDb);
++    const char *zDb = db->aDb[pTable->iDb].zName;
++    if( sqliteAuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
++      return;
++    }
++    if( isView ){
++      if( iDb==1 ){
++        code = SQLITE_DROP_TEMP_VIEW;
++      }else{
++        code = SQLITE_DROP_VIEW;
++      }
++    }else{
++      if( iDb==1 ){
++        code = SQLITE_DROP_TEMP_TABLE;
++      }else{
++        code = SQLITE_DROP_TABLE;
++      }
++    }
++    if( sqliteAuthCheck(pParse, code, pTable->zName, 0, zDb) ){
++      return;
++    }
++    if( sqliteAuthCheck(pParse, SQLITE_DELETE, pTable->zName, 0, zDb) ){
++      return;
++    }
++  }
++#endif
++  if( pTable->readOnly ){
++    sqliteErrorMsg(pParse, "table %s may not be dropped", pTable->zName);
++    pParse->nErr++;
++    return;
++  }
++  if( isView && pTable->pSelect==0 ){
++    sqliteErrorMsg(pParse, "use DROP TABLE to delete table %s", pTable->zName);
++    return;
++  }
++  if( !isView && pTable->pSelect ){
++    sqliteErrorMsg(pParse, "use DROP VIEW to delete view %s", pTable->zName);
++    return;
++  }
++
++  /* Generate code to remove the table from the master table
++  ** on disk.
++  */
++  v = sqliteGetVdbe(pParse);
++  if( v ){
++    static VdbeOpList dropTable[] = {
++      { OP_Rewind,     0, ADDR(8),  0},
++      { OP_String,     0, 0,        0}, /* 1 */
++      { OP_MemStore,   1, 1,        0},
++      { OP_MemLoad,    1, 0,        0}, /* 3 */
++      { OP_Column,     0, 2,        0},
++      { OP_Ne,         0, ADDR(7),  0},
++      { OP_Delete,     0, 0,        0},
++      { OP_Next,       0, ADDR(3),  0}, /* 7 */
++    };
++    Index *pIdx;
++    Trigger *pTrigger;
++    sqliteBeginWriteOperation(pParse, 0, pTable->iDb);
++
++    /* Drop all triggers associated with the table being dropped */
++    pTrigger = pTable->pTrigger;
++    while( pTrigger ){
++      assert( pTrigger->iDb==pTable->iDb || pTrigger->iDb==1 );
++      sqliteDropTriggerPtr(pParse, pTrigger, 1);
++      if( pParse->explain ){
++        pTrigger = pTrigger->pNext;
++      }else{
++        pTrigger = pTable->pTrigger;
++      }
++    }
++
++    /* Drop all SQLITE_MASTER entries that refer to the table */
++    sqliteOpenMasterTable(v, pTable->iDb);
++    base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
++    sqliteVdbeChangeP3(v, base+1, pTable->zName, 0);
++
++    /* Drop all SQLITE_TEMP_MASTER entries that refer to the table */
++    if( pTable->iDb!=1 ){
++      sqliteOpenMasterTable(v, 1);
++      base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
++      sqliteVdbeChangeP3(v, base+1, pTable->zName, 0);
++    }
++
++    if( pTable->iDb==0 ){
++      sqliteChangeCookie(db, v);
++    }
++    sqliteVdbeAddOp(v, OP_Close, 0, 0);
++    if( !isView ){
++      sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->iDb);
++      for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){
++        sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, pIdx->iDb);
++      }
++    }
++    sqliteEndWriteOperation(pParse);
++  }
++
++  /* Delete the in-memory description of the table.
++  **
++  ** Exception: if the SQL statement began with the EXPLAIN keyword,
++  ** then no changes should be made.
++  */
++  if( !pParse->explain ){
++    sqliteUnlinkAndDeleteTable(db, pTable);
++    db->flags |= SQLITE_InternChanges;
++  }
++  sqliteViewResetAll(db, iDb);
++}
++
++/*
++** This routine constructs a P3 string suitable for an OP_MakeIdxKey
++** opcode and adds that P3 string to the most recently inserted instruction
++** in the virtual machine.  The P3 string consists of a single character
++** for each column in the index pIdx of table pTab.  If the column uses
++** a numeric sort order, then the P3 string character corresponding to
++** that column is 'n'.  If the column uses a text sort order, then the
++** P3 string is 't'.  See the OP_MakeIdxKey opcode documentation for
++** additional information.  See also the sqliteAddKeyType() routine.
++*/
++void sqliteAddIdxKeyType(Vdbe *v, Index *pIdx){
++  char *zType;
++  Table *pTab;
++  int i, n;
++  assert( pIdx!=0 && pIdx->pTable!=0 );
++  pTab = pIdx->pTable;
++  n = pIdx->nColumn;
++  zType = sqliteMallocRaw( n+1 );
++  if( zType==0 ) return;
++  for(i=0; i<n; i++){
++    int iCol = pIdx->aiColumn[i];
++    assert( iCol>=0 && iCol<pTab->nCol );
++    if( (pTab->aCol[iCol].sortOrder & SQLITE_SO_TYPEMASK)==SQLITE_SO_TEXT ){
++      zType[i] = 't';
++    }else{
++      zType[i] = 'n';
++    }
++  }
++  zType[n] = 0;
++  sqliteVdbeChangeP3(v, -1, zType, n);
++  sqliteFree(zType);
++}
++
++/*
++** This routine is called to create a new foreign key on the table
++** currently under construction.  pFromCol determines which columns
++** in the current table point to the foreign key.  If pFromCol==0 then
++** connect the key to the last column inserted.  pTo is the name of
++** the table referred to.  pToCol is a list of tables in the other
++** pTo table that the foreign key points to.  flags contains all
++** information about the conflict resolution algorithms specified
++** in the ON DELETE, ON UPDATE and ON INSERT clauses.
++**
++** An FKey structure is created and added to the table currently
++** under construction in the pParse->pNewTable field.  The new FKey
++** is not linked into db->aFKey at this point - that does not happen
++** until sqliteEndTable().
++**
++** The foreign key is set for IMMEDIATE processing.  A subsequent call
++** to sqliteDeferForeignKey() might change this to DEFERRED.
++*/
++void sqliteCreateForeignKey(
++  Parse *pParse,       /* Parsing context */
++  IdList *pFromCol,    /* Columns in this table that point to other table */
++  Token *pTo,          /* Name of the other table */
++  IdList *pToCol,      /* Columns in the other table */
++  int flags            /* Conflict resolution algorithms. */
++){
++  Table *p = pParse->pNewTable;
++  int nByte;
++  int i;
++  int nCol;
++  char *z;
++  FKey *pFKey = 0;
++
++  assert( pTo!=0 );
++  if( p==0 || pParse->nErr ) goto fk_end;
++  if( pFromCol==0 ){
++    int iCol = p->nCol-1;
++    if( iCol<0 ) goto fk_end;
++    if( pToCol && pToCol->nId!=1 ){
++      sqliteErrorMsg(pParse, "foreign key on %s"
++         " should reference only one column of table %T",
++         p->aCol[iCol].zName, pTo);
++      goto fk_end;
++    }
++    nCol = 1;
++  }else if( pToCol && pToCol->nId!=pFromCol->nId ){
++    sqliteErrorMsg(pParse,
++        "number of columns in foreign key does not match the number of "
++        "columns in the referenced table");
++    goto fk_end;
++  }else{
++    nCol = pFromCol->nId;
++  }
++  nByte = sizeof(*pFKey) + nCol*sizeof(pFKey->aCol[0]) + pTo->n + 1;
++  if( pToCol ){
++    for(i=0; i<pToCol->nId; i++){
++      nByte += strlen(pToCol->a[i].zName) + 1;
++    }
++  }
++  pFKey = sqliteMalloc( nByte );
++  if( pFKey==0 ) goto fk_end;
++  pFKey->pFrom = p;
++  pFKey->pNextFrom = p->pFKey;
++  z = (char*)&pFKey[1];
++  pFKey->aCol = (struct sColMap*)z;
++  z += sizeof(struct sColMap)*nCol;
++  pFKey->zTo = z;
++  memcpy(z, pTo->z, pTo->n);
++  z[pTo->n] = 0;
++  z += pTo->n+1;
++  pFKey->pNextTo = 0;
++  pFKey->nCol = nCol;
++  if( pFromCol==0 ){
++    pFKey->aCol[0].iFrom = p->nCol-1;
++  }else{
++    for(i=0; i<nCol; i++){
++      int j;
++      for(j=0; j<p->nCol; j++){
++        if( sqliteStrICmp(p->aCol[j].zName, pFromCol->a[i].zName)==0 ){
++          pFKey->aCol[i].iFrom = j;
++          break;
++        }
++      }
++      if( j>=p->nCol ){
++        sqliteErrorMsg(pParse, 
++          "unknown column \"%s\" in foreign key definition", 
++          pFromCol->a[i].zName);
++        goto fk_end;
++      }
++    }
++  }
++  if( pToCol ){
++    for(i=0; i<nCol; i++){
++      int n = strlen(pToCol->a[i].zName);
++      pFKey->aCol[i].zCol = z;
++      memcpy(z, pToCol->a[i].zName, n);
++      z[n] = 0;
++      z += n+1;
++    }
++  }
++  pFKey->isDeferred = 0;
++  pFKey->deleteConf = flags & 0xff;
++  pFKey->updateConf = (flags >> 8 ) & 0xff;
++  pFKey->insertConf = (flags >> 16 ) & 0xff;
++
++  /* Link the foreign key to the table as the last step.
++  */
++  p->pFKey = pFKey;
++  pFKey = 0;
++
++fk_end:
++  sqliteFree(pFKey);
++  sqliteIdListDelete(pFromCol);
++  sqliteIdListDelete(pToCol);
++}
++
++/*
++** This routine is called when an INITIALLY IMMEDIATE or INITIALLY DEFERRED
++** clause is seen as part of a foreign key definition.  The isDeferred
++** parameter is 1 for INITIALLY DEFERRED and 0 for INITIALLY IMMEDIATE.
++** The behavior of the most recently created foreign key is adjusted
++** accordingly.
++*/
++void sqliteDeferForeignKey(Parse *pParse, int isDeferred){
++  Table *pTab;
++  FKey *pFKey;
++  if( (pTab = pParse->pNewTable)==0 || (pFKey = pTab->pFKey)==0 ) return;
++  pFKey->isDeferred = isDeferred;
++}
++
++/*
++** Create a new index for an SQL table.  pIndex is the name of the index 
++** and pTable is the name of the table that is to be indexed.  Both will 
++** be NULL for a primary key or an index that is created to satisfy a
++** UNIQUE constraint.  If pTable and pIndex are NULL, use pParse->pNewTable
++** as the table to be indexed.  pParse->pNewTable is a table that is
++** currently being constructed by a CREATE TABLE statement.
++**
++** pList is a list of columns to be indexed.  pList will be NULL if this
++** is a primary key or unique-constraint on the most recent column added
++** to the table currently under construction.  
++*/
++void sqliteCreateIndex(
++  Parse *pParse,   /* All information about this parse */
++  Token *pName,    /* Name of the index.  May be NULL */
++  SrcList *pTable, /* Name of the table to index.  Use pParse->pNewTable if 0 */
++  IdList *pList,   /* A list of columns to be indexed */
++  int onError,     /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
++  Token *pStart,   /* The CREATE token that begins a CREATE TABLE statement */
++  Token *pEnd      /* The ")" that closes the CREATE INDEX statement */
++){
++  Table *pTab;     /* Table to be indexed */
++  Index *pIndex;   /* The index to be created */
++  char *zName = 0;
++  int i, j;
++  Token nullId;    /* Fake token for an empty ID list */
++  DbFixer sFix;    /* For assigning database names to pTable */
++  int isTemp;      /* True for a temporary index */
++  sqlite *db = pParse->db;
++
++  if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index;
++  if( db->init.busy 
++     && sqliteFixInit(&sFix, pParse, db->init.iDb, "index", pName)
++     && sqliteFixSrcList(&sFix, pTable)
++  ){
++    goto exit_create_index;
++  }
++
++  /*
++  ** Find the table that is to be indexed.  Return early if not found.
++  */
++  if( pTable!=0 ){
++    assert( pName!=0 );
++    assert( pTable->nSrc==1 );
++    pTab =  sqliteSrcListLookup(pParse, pTable);
++  }else{
++    assert( pName==0 );
++    pTab =  pParse->pNewTable;
++  }
++  if( pTab==0 || pParse->nErr ) goto exit_create_index;
++  if( pTab->readOnly ){
++    sqliteErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
++    goto exit_create_index;
++  }
++  if( pTab->iDb>=2 && db->init.busy==0 ){
++    sqliteErrorMsg(pParse, "table %s may not have indices added", pTab->zName);
++    goto exit_create_index;
++  }
++  if( pTab->pSelect ){
++    sqliteErrorMsg(pParse, "views may not be indexed");
++    goto exit_create_index;
++  }
++  isTemp = pTab->iDb==1;
++
++  /*
++  ** Find the name of the index.  Make sure there is not already another
++  ** index or table with the same name.  
++  **
++  ** Exception:  If we are reading the names of permanent indices from the
++  ** sqlite_master table (because some other process changed the schema) and
++  ** one of the index names collides with the name of a temporary table or
++  ** index, then we will continue to process this index.
++  **
++  ** If pName==0 it means that we are
++  ** dealing with a primary key or UNIQUE constraint.  We have to invent our
++  ** own name.
++  */
++  if( pName && !db->init.busy ){
++    Index *pISameName;    /* Another index with the same name */
++    Table *pTSameName;    /* A table with same name as the index */
++    zName = sqliteTableNameFromToken(pName);
++    if( zName==0 ) goto exit_create_index;
++    if( (pISameName = sqliteFindIndex(db, zName, 0))!=0 ){
++      sqliteErrorMsg(pParse, "index %s already exists", zName);
++      goto exit_create_index;
++    }
++    if( (pTSameName = sqliteFindTable(db, zName, 0))!=0 ){
++      sqliteErrorMsg(pParse, "there is already a table named %s", zName);
++      goto exit_create_index;
++    }
++  }else if( pName==0 ){
++    char zBuf[30];
++    int n;
++    Index *pLoop;
++    for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){}
++    sprintf(zBuf,"%d)",n);
++    zName = 0;
++    sqliteSetString(&zName, "(", pTab->zName, " autoindex ", zBuf, (char*)0);
++    if( zName==0 ) goto exit_create_index;
++  }else{
++    zName = sqliteTableNameFromToken(pName);
++  }
++
++  /* Check for authorization to create an index.
++  */
++#ifndef SQLITE_OMIT_AUTHORIZATION
++  {
++    const char *zDb = db->aDb[pTab->iDb].zName;
++
++    assert( pTab->iDb==db->init.iDb || isTemp );
++    if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
++      goto exit_create_index;
++    }
++    i = SQLITE_CREATE_INDEX;
++    if( isTemp ) i = SQLITE_CREATE_TEMP_INDEX;
++    if( sqliteAuthCheck(pParse, i, zName, pTab->zName, zDb) ){
++      goto exit_create_index;
++    }
++  }
++#endif
++
++  /* If pList==0, it means this routine was called to make a primary
++  ** key out of the last column added to the table under construction.
++  ** So create a fake list to simulate this.
++  */
++  if( pList==0 ){
++    nullId.z = pTab->aCol[pTab->nCol-1].zName;
++    nullId.n = strlen(nullId.z);
++    pList = sqliteIdListAppend(0, &nullId);
++    if( pList==0 ) goto exit_create_index;
++  }
++
++  /* 
++  ** Allocate the index structure. 
++  */
++  pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 +
++                        sizeof(int)*pList->nId );
++  if( pIndex==0 ) goto exit_create_index;
++  pIndex->aiColumn = (int*)&pIndex[1];
++  pIndex->zName = (char*)&pIndex->aiColumn[pList->nId];
++  strcpy(pIndex->zName, zName);
++  pIndex->pTable = pTab;
++  pIndex->nColumn = pList->nId;
++  pIndex->onError = onError;
++  pIndex->autoIndex = pName==0;
++  pIndex->iDb = isTemp ? 1 : db->init.iDb;
++
++  /* Scan the names of the columns of the table to be indexed and
++  ** load the column indices into the Index structure.  Report an error
++  ** if any column is not found.
++  */
++  for(i=0; i<pList->nId; i++){
++    for(j=0; j<pTab->nCol; j++){
++      if( sqliteStrICmp(pList->a[i].zName, pTab->aCol[j].zName)==0 ) break;
++    }
++    if( j>=pTab->nCol ){
++      sqliteErrorMsg(pParse, "table %s has no column named %s",
++        pTab->zName, pList->a[i].zName);
++      sqliteFree(pIndex);
++      goto exit_create_index;
++    }
++    pIndex->aiColumn[i] = j;
++  }
++
++  /* Link the new Index structure to its table and to the other
++  ** in-memory database structures. 
++  */
++  if( !pParse->explain ){
++    Index *p;
++    p = sqliteHashInsert(&db->aDb[pIndex->iDb].idxHash, 
++                         pIndex->zName, strlen(pIndex->zName)+1, pIndex);
++    if( p ){
++      assert( p==pIndex );  /* Malloc must have failed */
++      sqliteFree(pIndex);
++      goto exit_create_index;
++    }
++    db->flags |= SQLITE_InternChanges;
++  }
++
++  /* When adding an index to the list of indices for a table, make
++  ** sure all indices labeled OE_Replace come after all those labeled
++  ** OE_Ignore.  This is necessary for the correct operation of UPDATE
++  ** and INSERT.
++  */
++  if( onError!=OE_Replace || pTab->pIndex==0
++       || pTab->pIndex->onError==OE_Replace){
++    pIndex->pNext = pTab->pIndex;
++    pTab->pIndex = pIndex;
++  }else{
++    Index *pOther = pTab->pIndex;
++    while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){
++      pOther = pOther->pNext;
++    }
++    pIndex->pNext = pOther->pNext;
++    pOther->pNext = pIndex;
++  }
++
++  /* If the db->init.busy is 1 it means we are reading the SQL off the
++  ** "sqlite_master" table on the disk.  So do not write to the disk
++  ** again.  Extract the table number from the db->init.newTnum field.
++  */
++  if( db->init.busy && pTable!=0 ){
++    pIndex->tnum = db->init.newTnum;
++  }
++
++  /* If the db->init.busy is 0 then create the index on disk.  This
++  ** involves writing the index into the master table and filling in the
++  ** index with the current table contents.
++  **
++  ** The db->init.busy is 0 when the user first enters a CREATE INDEX 
++  ** command.  db->init.busy is 1 when a database is opened and 
++  ** CREATE INDEX statements are read out of the master table.  In
++  ** the latter case the index already exists on disk, which is why
++  ** we don't want to recreate it.
++  **
++  ** If pTable==0 it means this index is generated as a primary key
++  ** or UNIQUE constraint of a CREATE TABLE statement.  Since the table
++  ** has just been created, it contains no data and the index initialization
++  ** step can be skipped.
++  */
++  else if( db->init.busy==0 ){
++    int n;
++    Vdbe *v;
++    int lbl1, lbl2;
++    int i;
++    int addr;
++
++    v = sqliteGetVdbe(pParse);
++    if( v==0 ) goto exit_create_index;
++    if( pTable!=0 ){
++      sqliteBeginWriteOperation(pParse, 0, isTemp);
++      sqliteOpenMasterTable(v, isTemp);
++    }
++    sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
++    sqliteVdbeOp3(v, OP_String, 0, 0, "index", P3_STATIC);
++    sqliteVdbeOp3(v, OP_String, 0, 0, pIndex->zName, 0);
++    sqliteVdbeOp3(v, OP_String, 0, 0, pTab->zName, 0);
++    sqliteVdbeOp3(v, OP_CreateIndex, 0, isTemp,(char*)&pIndex->tnum,P3_POINTER);
++    pIndex->tnum = 0;
++    if( pTable ){
++      sqliteVdbeCode(v,
++          OP_Dup,       0,      0,
++          OP_Integer,   isTemp, 0,
++          OP_OpenWrite, 1,      0,
++      0);
++    }
++    addr = sqliteVdbeAddOp(v, OP_String, 0, 0);
++    if( pStart && pEnd ){
++      n = Addr(pEnd->z) - Addr(pStart->z) + 1;
++      sqliteVdbeChangeP3(v, addr, pStart->z, n);
++    }
++    sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
++    sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
++    if( pTable ){
++      sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
++      sqliteVdbeOp3(v, OP_OpenRead, 2, pTab->tnum, pTab->zName, 0);
++      lbl2 = sqliteVdbeMakeLabel(v);
++      sqliteVdbeAddOp(v, OP_Rewind, 2, lbl2);
++      lbl1 = sqliteVdbeAddOp(v, OP_Recno, 2, 0);
++      for(i=0; i<pIndex->nColumn; i++){
++        int iCol = pIndex->aiColumn[i];
++        if( pTab->iPKey==iCol ){
++          sqliteVdbeAddOp(v, OP_Dup, i, 0);
++        }else{
++          sqliteVdbeAddOp(v, OP_Column, 2, iCol);
++        }
++      }
++      sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0);
++      if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIndex);
++      sqliteVdbeOp3(v, OP_IdxPut, 1, pIndex->onError!=OE_None,
++                      "indexed columns are not unique", P3_STATIC);
++      sqliteVdbeAddOp(v, OP_Next, 2, lbl1);
++      sqliteVdbeResolveLabel(v, lbl2);
++      sqliteVdbeAddOp(v, OP_Close, 2, 0);
++      sqliteVdbeAddOp(v, OP_Close, 1, 0);
++    }
++    if( pTable!=0 ){
++      if( !isTemp ){
++        sqliteChangeCookie(db, v);
++      }
++      sqliteVdbeAddOp(v, OP_Close, 0, 0);
++      sqliteEndWriteOperation(pParse);
++    }
++  }
++
++  /* Clean up before exiting */
++exit_create_index:
++  sqliteIdListDelete(pList);
++  sqliteSrcListDelete(pTable);
++  sqliteFree(zName);
++  return;
++}
++
++/*
++** This routine will drop an existing named index.  This routine
++** implements the DROP INDEX statement.
++*/
++void sqliteDropIndex(Parse *pParse, SrcList *pName){
++  Index *pIndex;
++  Vdbe *v;
++  sqlite *db = pParse->db;
++
++  if( pParse->nErr || sqlite_malloc_failed ) return;
++  assert( pName->nSrc==1 );
++  pIndex = sqliteFindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
++  if( pIndex==0 ){
++    sqliteErrorMsg(pParse, "no such index: %S", pName, 0);
++    goto exit_drop_index;
++  }
++  if( pIndex->autoIndex ){
++    sqliteErrorMsg(pParse, "index associated with UNIQUE "
++      "or PRIMARY KEY constraint cannot be dropped", 0);
++    goto exit_drop_index;
++  }
++  if( pIndex->iDb>1 ){
++    sqliteErrorMsg(pParse, "cannot alter schema of attached "
++       "databases", 0);
++    goto exit_drop_index;
++  }
++#ifndef SQLITE_OMIT_AUTHORIZATION
++  {
++    int code = SQLITE_DROP_INDEX;
++    Table *pTab = pIndex->pTable;
++    const char *zDb = db->aDb[pIndex->iDb].zName;
++    const char *zTab = SCHEMA_TABLE(pIndex->iDb);
++    if( sqliteAuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
++      goto exit_drop_index;
++    }
++    if( pIndex->iDb ) code = SQLITE_DROP_TEMP_INDEX;
++    if( sqliteAuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
++      goto exit_drop_index;
++    }
++  }
++#endif
++
++  /* Generate code to remove the index and from the master table */
++  v = sqliteGetVdbe(pParse);
++  if( v ){
++    static VdbeOpList dropIndex[] = {
++      { OP_Rewind,     0, ADDR(9), 0}, 
++      { OP_String,     0, 0,       0}, /* 1 */
++      { OP_MemStore,   1, 1,       0},
++      { OP_MemLoad,    1, 0,       0}, /* 3 */
++      { OP_Column,     0, 1,       0},
++      { OP_Eq,         0, ADDR(8), 0},
++      { OP_Next,       0, ADDR(3), 0},
++      { OP_Goto,       0, ADDR(9), 0},
++      { OP_Delete,     0, 0,       0}, /* 8 */
++    };
++    int base;
++
++    sqliteBeginWriteOperation(pParse, 0, pIndex->iDb);
++    sqliteOpenMasterTable(v, pIndex->iDb);
++    base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
++    sqliteVdbeChangeP3(v, base+1, pIndex->zName, 0);
++    if( pIndex->iDb==0 ){
++      sqliteChangeCookie(db, v);
++    }
++    sqliteVdbeAddOp(v, OP_Close, 0, 0);
++    sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb);
++    sqliteEndWriteOperation(pParse);
++  }
++
++  /* Delete the in-memory description of this index.
++  */
++  if( !pParse->explain ){
++    sqliteUnlinkAndDeleteIndex(db, pIndex);
++    db->flags |= SQLITE_InternChanges;
++  }
++
++exit_drop_index:
++  sqliteSrcListDelete(pName);
++}
++
++/*
++** Append a new element to the given IdList.  Create a new IdList if
++** need be.
++**
++** A new IdList is returned, or NULL if malloc() fails.
++*/
++IdList *sqliteIdListAppend(IdList *pList, Token *pToken){
++  if( pList==0 ){
++    pList = sqliteMalloc( sizeof(IdList) );
++    if( pList==0 ) return 0;
++    pList->nAlloc = 0;
++  }
++  if( pList->nId>=pList->nAlloc ){
++    struct IdList_item *a;
++    pList->nAlloc = pList->nAlloc*2 + 5;
++    a = sqliteRealloc(pList->a, pList->nAlloc*sizeof(pList->a[0]) );
++    if( a==0 ){
++      sqliteIdListDelete(pList);
++      return 0;
++    }
++    pList->a = a;
++  }
++  memset(&pList->a[pList->nId], 0, sizeof(pList->a[0]));
++  if( pToken ){
++    char **pz = &pList->a[pList->nId].zName;
++    sqliteSetNString(pz, pToken->z, pToken->n, 0);
++    if( *pz==0 ){
++      sqliteIdListDelete(pList);
++      return 0;
++    }else{
++      sqliteDequote(*pz);
++    }
++  }
++  pList->nId++;
++  return pList;
++}
++
++/*
++** Append a new table name to the given SrcList.  Create a new SrcList if
++** need be.  A new entry is created in the SrcList even if pToken is NULL.
++**
++** A new SrcList is returned, or NULL if malloc() fails.
++**
++** If pDatabase is not null, it means that the table has an optional
++** database name prefix.  Like this:  "database.table".  The pDatabase
++** points to the table name and the pTable points to the database name.
++** The SrcList.a[].zName field is filled with the table name which might
++** come from pTable (if pDatabase is NULL) or from pDatabase.  
++** SrcList.a[].zDatabase is filled with the database name from pTable,
++** or with NULL if no database is specified.
++**
++** In other words, if call like this:
++**
++**         sqliteSrcListAppend(A,B,0);
++**
++** Then B is a table name and the database name is unspecified.  If called
++** like this:
++**
++**         sqliteSrcListAppend(A,B,C);
++**
++** Then C is the table name and B is the database name.
++*/
++SrcList *sqliteSrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){
++  if( pList==0 ){
++    pList = sqliteMalloc( sizeof(SrcList) );
++    if( pList==0 ) return 0;
++    pList->nAlloc = 1;
++  }
++  if( pList->nSrc>=pList->nAlloc ){
++    SrcList *pNew;
++    pList->nAlloc *= 2;
++    pNew = sqliteRealloc(pList,
++               sizeof(*pList) + (pList->nAlloc-1)*sizeof(pList->a[0]) );
++    if( pNew==0 ){
++      sqliteSrcListDelete(pList);
++      return 0;
++    }
++    pList = pNew;
++  }
++  memset(&pList->a[pList->nSrc], 0, sizeof(pList->a[0]));
++  if( pDatabase && pDatabase->z==0 ){
++    pDatabase = 0;
++  }
++  if( pDatabase && pTable ){
++    Token *pTemp = pDatabase;
++    pDatabase = pTable;
++    pTable = pTemp;
++  }
++  if( pTable ){
++    char **pz = &pList->a[pList->nSrc].zName;
++    sqliteSetNString(pz, pTable->z, pTable->n, 0);
++    if( *pz==0 ){
++      sqliteSrcListDelete(pList);
++      return 0;
++    }else{
++      sqliteDequote(*pz);
++    }
++  }
++  if( pDatabase ){
++    char **pz = &pList->a[pList->nSrc].zDatabase;
++    sqliteSetNString(pz, pDatabase->z, pDatabase->n, 0);
++    if( *pz==0 ){
++      sqliteSrcListDelete(pList);
++      return 0;
++    }else{
++      sqliteDequote(*pz);
++    }
++  }
++  pList->a[pList->nSrc].iCursor = -1;
++  pList->nSrc++;
++  return pList;
++}
++
++/*
++** Assign cursors to all tables in a SrcList
++*/
++void sqliteSrcListAssignCursors(Parse *pParse, SrcList *pList){
++  int i;
++  for(i=0; i<pList->nSrc; i++){
++    if( pList->a[i].iCursor<0 ){
++      pList->a[i].iCursor = pParse->nTab++;
++    }
++  }
++}
++
++/*
++** Add an alias to the last identifier on the given identifier list.
++*/
++void sqliteSrcListAddAlias(SrcList *pList, Token *pToken){
++  if( pList && pList->nSrc>0 ){
++    int i = pList->nSrc - 1;
++    sqliteSetNString(&pList->a[i].zAlias, pToken->z, pToken->n, 0);
++    sqliteDequote(pList->a[i].zAlias);
++  }
++}
++
++/*
++** Delete an IdList.
++*/
++void sqliteIdListDelete(IdList *pList){
++  int i;
++  if( pList==0 ) return;
++  for(i=0; i<pList->nId; i++){
++    sqliteFree(pList->a[i].zName);
++  }
++  sqliteFree(pList->a);
++  sqliteFree(pList);
++}
++
++/*
++** Return the index in pList of the identifier named zId.  Return -1
++** if not found.
++*/
++int sqliteIdListIndex(IdList *pList, const char *zName){
++  int i;
++  if( pList==0 ) return -1;
++  for(i=0; i<pList->nId; i++){
++    if( sqliteStrICmp(pList->a[i].zName, zName)==0 ) return i;
++  }
++  return -1;
++}
++
++/*
++** Delete an entire SrcList including all its substructure.
++*/
++void sqliteSrcListDelete(SrcList *pList){
++  int i;
++  if( pList==0 ) return;
++  for(i=0; i<pList->nSrc; i++){
++    sqliteFree(pList->a[i].zDatabase);
++    sqliteFree(pList->a[i].zName);
++    sqliteFree(pList->a[i].zAlias);
++    if( pList->a[i].pTab && pList->a[i].pTab->isTransient ){
++      sqliteDeleteTable(0, pList->a[i].pTab);
++    }
++    sqliteSelectDelete(pList->a[i].pSelect);
++    sqliteExprDelete(pList->a[i].pOn);
++    sqliteIdListDelete(pList->a[i].pUsing);
++  }
++  sqliteFree(pList);
++}
++
++/*
++** Begin a transaction
++*/
++void sqliteBeginTransaction(Parse *pParse, int onError){
++  sqlite *db;
++
++  if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
++  if( pParse->nErr || sqlite_malloc_failed ) return;
++  if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return;
++  if( db->flags & SQLITE_InTrans ){
++    sqliteErrorMsg(pParse, "cannot start a transaction within a transaction");
++    return;
++  }
++  sqliteBeginWriteOperation(pParse, 0, 0);
++  if( !pParse->explain ){
++    db->flags |= SQLITE_InTrans;
++    db->onError = onError;
++  }
++}
++
++/*
++** Commit a transaction
++*/
++void sqliteCommitTransaction(Parse *pParse){
++  sqlite *db;
++
++  if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
++  if( pParse->nErr || sqlite_malloc_failed ) return;
++  if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return;
++  if( (db->flags & SQLITE_InTrans)==0 ){
++    sqliteErrorMsg(pParse, "cannot commit - no transaction is active");
++    return;
++  }
++  if( !pParse->explain ){
++    db->flags &= ~SQLITE_InTrans;
++  }
++  sqliteEndWriteOperation(pParse);
++  if( !pParse->explain ){
++    db->onError = OE_Default;
++  }
++}
++
++/*
++** Rollback a transaction
++*/
++void sqliteRollbackTransaction(Parse *pParse){
++  sqlite *db;
++  Vdbe *v;
++
++  if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
++  if( pParse->nErr || sqlite_malloc_failed ) return;
++  if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return;
++  if( (db->flags & SQLITE_InTrans)==0 ){
++    sqliteErrorMsg(pParse, "cannot rollback - no transaction is active");
++    return; 
++  }
++  v = sqliteGetVdbe(pParse);
++  if( v ){
++    sqliteVdbeAddOp(v, OP_Rollback, 0, 0);
++  }
++  if( !pParse->explain ){
++    db->flags &= ~SQLITE_InTrans;
++    db->onError = OE_Default;
++  }
++}
++
++/*
++** Generate VDBE code that will verify the schema cookie for all
++** named database files.
++*/
++void sqliteCodeVerifySchema(Parse *pParse, int iDb){
++  sqlite *db = pParse->db;
++  Vdbe *v = sqliteGetVdbe(pParse);
++  assert( iDb>=0 && iDb<db->nDb );
++  assert( db->aDb[iDb].pBt!=0 );
++  if( iDb!=1 && !DbHasProperty(db, iDb, DB_Cookie) ){
++    sqliteVdbeAddOp(v, OP_VerifyCookie, iDb, db->aDb[iDb].schema_cookie);
++    DbSetProperty(db, iDb, DB_Cookie);
++  }
++}
++
++/*
++** Generate VDBE code that prepares for doing an operation that
++** might change the database.
++**
++** This routine starts a new transaction if we are not already within
++** a transaction.  If we are already within a transaction, then a checkpoint
++** is set if the setCheckpoint parameter is true.  A checkpoint should
++** be set for operations that might fail (due to a constraint) part of
++** the way through and which will need to undo some writes without having to
++** rollback the whole transaction.  For operations where all constraints
++** can be checked before any changes are made to the database, it is never
++** necessary to undo a write and the checkpoint should not be set.
++**
++** Only database iDb and the temp database are made writable by this call.
++** If iDb==0, then the main and temp databases are made writable.   If
++** iDb==1 then only the temp database is made writable.  If iDb>1 then the
++** specified auxiliary database and the temp database are made writable.
++*/
++void sqliteBeginWriteOperation(Parse *pParse, int setCheckpoint, int iDb){
++  Vdbe *v;
++  sqlite *db = pParse->db;
++  if( DbHasProperty(db, iDb, DB_Locked) ) return;
++  v = sqliteGetVdbe(pParse);
++  if( v==0 ) return;
++  if( !db->aDb[iDb].inTrans ){
++    sqliteVdbeAddOp(v, OP_Transaction, iDb, 0);
++    DbSetProperty(db, iDb, DB_Locked);
++    sqliteCodeVerifySchema(pParse, iDb);
++    if( iDb!=1 ){
++      sqliteBeginWriteOperation(pParse, setCheckpoint, 1);
++    }
++  }else if( setCheckpoint ){
++    sqliteVdbeAddOp(v, OP_Checkpoint, iDb, 0);
++    DbSetProperty(db, iDb, DB_Locked);
++  }
++}
++
++/*
++** Generate code that concludes an operation that may have changed
++** the database.  If a statement transaction was started, then emit
++** an OP_Commit that will cause the changes to be committed to disk.
++**
++** Note that checkpoints are automatically committed at the end of
++** a statement.  Note also that there can be multiple calls to 
++** sqliteBeginWriteOperation() but there should only be a single
++** call to sqliteEndWriteOperation() at the conclusion of the statement.
++*/
++void sqliteEndWriteOperation(Parse *pParse){
++  Vdbe *v;
++  sqlite *db = pParse->db;
++  if( pParse->trigStack ) return; /* if this is in a trigger */
++  v = sqliteGetVdbe(pParse);
++  if( v==0 ) return;
++  if( db->flags & SQLITE_InTrans ){
++    /* A BEGIN has executed.  Do not commit until we see an explicit
++    ** COMMIT statement. */
++  }else{
++    sqliteVdbeAddOp(v, OP_Commit, 0, 0);
++  }
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/config_static.w32.h
+@@ -0,0 +1 @@
++#define SQLITE_PTR_SZ 4
+\ No newline at end of file
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/copy.c
+@@ -0,0 +1,110 @@
++/*
++** 2003 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.
++**
++*************************************************************************
++** This file contains code used to implement the COPY command.
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++
++/*
++** The COPY command is for compatibility with PostgreSQL and specificially
++** for the ability to read the output of pg_dump.  The format is as
++** follows:
++**
++**    COPY table FROM file [USING DELIMITERS string]
++**
++** "table" is an existing table name.  We will read lines of code from
++** file to fill this table with data.  File might be "stdin".  The optional
++** delimiter string identifies the field separators.  The default is a tab.
++*/
++void sqliteCopy(
++  Parse *pParse,       /* The parser context */
++  SrcList *pTableName, /* The name of the table into which we will insert */
++  Token *pFilename,    /* The file from which to obtain information */
++  Token *pDelimiter,   /* Use this as the field delimiter */
++  int onError          /* What to do if a constraint fails */
++){
++  Table *pTab;
++  int i;
++  Vdbe *v;
++  int addr, end;
++  char *zFile = 0;
++  const char *zDb;
++  sqlite *db = pParse->db;
++
++
++  if( sqlite_malloc_failed  ) goto copy_cleanup;
++  assert( pTableName->nSrc==1 );
++  pTab = sqliteSrcListLookup(pParse, pTableName);
++  if( pTab==0 || sqliteIsReadOnly(pParse, pTab, 0) ) goto copy_cleanup;
++  zFile = sqliteStrNDup(pFilename->z, pFilename->n);
++  sqliteDequote(zFile);
++  assert( pTab->iDb<db->nDb );
++  zDb = db->aDb[pTab->iDb].zName;
++  if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb)
++      || sqliteAuthCheck(pParse, SQLITE_COPY, pTab->zName, zFile, zDb) ){
++    goto copy_cleanup;
++  }
++  v = sqliteGetVdbe(pParse);
++  if( v ){
++    sqliteBeginWriteOperation(pParse, 1, pTab->iDb);
++    addr = sqliteVdbeOp3(v, OP_FileOpen, 0, 0, pFilename->z, pFilename->n);
++    sqliteVdbeDequoteP3(v, addr);
++    sqliteOpenTableAndIndices(pParse, pTab, 0);
++    if( db->flags & SQLITE_CountRows ){
++      sqliteVdbeAddOp(v, OP_Integer, 0, 0);  /* Initialize the row count */
++    }
++    end = sqliteVdbeMakeLabel(v);
++    addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end);
++    if( pDelimiter ){
++      sqliteVdbeChangeP3(v, addr, pDelimiter->z, pDelimiter->n);
++      sqliteVdbeDequoteP3(v, addr);
++    }else{
++      sqliteVdbeChangeP3(v, addr, "\t", 1);
++    }
++    if( pTab->iPKey>=0 ){
++      sqliteVdbeAddOp(v, OP_FileColumn, pTab->iPKey, 0);
++      sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
++    }else{
++      sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
++    }
++    for(i=0; i<pTab->nCol; i++){
++      if( i==pTab->iPKey ){
++        /* The integer primary key column is filled with NULL since its
++        ** value is always pulled from the record number */
++        sqliteVdbeAddOp(v, OP_String, 0, 0);
++      }else{
++        sqliteVdbeAddOp(v, OP_FileColumn, i, 0);
++      }
++    }
++    sqliteGenerateConstraintChecks(pParse, pTab, 0, 0, pTab->iPKey>=0, 
++                                   0, onError, addr);
++    sqliteCompleteInsertion(pParse, pTab, 0, 0, 0, 0, -1);
++    if( (db->flags & SQLITE_CountRows)!=0 ){
++      sqliteVdbeAddOp(v, OP_AddImm, 1, 0);  /* Increment row count */
++    }
++    sqliteVdbeAddOp(v, OP_Goto, 0, addr);
++    sqliteVdbeResolveLabel(v, end);
++    sqliteVdbeAddOp(v, OP_Noop, 0, 0);
++    sqliteEndWriteOperation(pParse);
++    if( db->flags & SQLITE_CountRows ){
++      sqliteVdbeAddOp(v, OP_ColumnName, 0, 1);
++      sqliteVdbeChangeP3(v, -1, "rows inserted", P3_STATIC);
++      sqliteVdbeAddOp(v, OP_Callback, 1, 0);
++    }
++  }
++  
++copy_cleanup:
++  sqliteSrcListDelete(pTableName);
++  sqliteFree(zFile);
++  return;
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/date.c
+@@ -0,0 +1,881 @@
++/*
++** 2003 October 31
++**
++** 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 date and time
++** functions for SQLite.  
++**
++** There is only one exported symbol in this file - the function
++** sqliteRegisterDateTimeFunctions() found at the bottom of the file.
++** All other code has file scope.
++**
++** $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.
++**
++** 1970-01-01 00:00:00 is JD 2440587.5
++** 2000-01-01 00:00:00 is JD 2451544.5
++**
++** This implemention requires years to be expressed as a 4-digit number
++** which means that only dates between 0000-01-01 and 9999-12-31 can
++** be represented, even though julian day numbers allow a much wider
++** range of dates.
++**
++** The Gregorian calendar system is used for all dates and times,
++** even those that predate the Gregorian calendar.  Historians usually
++** use the Julian calendar for dates prior to 1582-10-15 and for some
++** dates afterwards, depending on locale.  Beware of this difference.
++**
++** The conversion algorithms are implemented based on descriptions
++** in the following text:
++**
++**      Jean Meeus
++**      Astronomical Algorithms, 2nd Edition, 1998
++**      ISBM 0-943396-61-1
++**      Willmann-Bell, Inc
++**      Richmond, Virginia (USA)
++*/
++#include "os.h"
++#include "sqliteInt.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
++
++/*
++** A structure for holding a single date and time.
++*/
++typedef struct DateTime DateTime;
++struct DateTime {
++  double rJD;      /* The julian day number */
++  int Y, M, D;     /* Year, month, and day */
++  int h, m;        /* Hour and minutes */
++  int tz;          /* Timezone offset in minutes */
++  double s;        /* Seconds */
++  char validYMD;   /* True if Y,M,D are valid */
++  char validHMS;   /* True if h,m,s are valid */
++  char validJD;    /* True if rJD is valid */
++  char validTZ;    /* True if tz is valid */
++};
++
++
++/*
++** Convert zDate into one or more integers.  Additional arguments
++** come in groups of 5 as follows:
++**
++**       N       number of digits in the integer
++**       min     minimum allowed value of the integer
++**       max     maximum allowed value of the integer
++**       nextC   first character after the integer
++**       pVal    where to write the integers value.
++**
++** Conversions continue until one with nextC==0 is encountered.
++** The function returns the number of successful conversions.
++*/
++static int getDigits(const char *zDate, ...){
++  va_list ap;
++  int val;
++  int N;
++  int min;
++  int max;
++  int nextC;
++  int *pVal;
++  int cnt = 0;
++  va_start(ap, zDate);
++  do{
++    N = va_arg(ap, int);
++    min = va_arg(ap, int);
++    max = va_arg(ap, int);
++    nextC = va_arg(ap, int);
++    pVal = va_arg(ap, int*);
++    val = 0;
++    while( N-- ){
++      if( !isdigit(*zDate) ){
++        return cnt;
++      }
++      val = val*10 + *zDate - '0';
++      zDate++;
++    }
++    if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
++      return cnt;
++    }
++    *pVal = val;
++    zDate++;
++    cnt++;
++  }while( nextC );
++  return cnt;
++}
++
++/*
++** Read text from z[] and convert into a floating point number.  Return
++** the number of digits converted.
++*/
++static int getValue(const char *z, double *pR){
++  const char *zEnd;
++  *pR = sqliteAtoF(z, &zEnd);
++  return zEnd - z;
++}
++
++/*
++** Parse a timezone extension on the end of a date-time.
++** The extension is of the form:
++**
++**        (+/-)HH:MM
++**
++** If the parse is successful, write the number of minutes
++** of change in *pnMin and return 0.  If a parser error occurs,
++** return 0.
++**
++** A missing specifier is not considered an error.
++*/
++static int parseTimezone(const char *zDate, DateTime *p){
++  int sgn = 0;
++  int nHr, nMn;
++  while( isspace(*zDate) ){ zDate++; }
++  p->tz = 0;
++  if( *zDate=='-' ){
++    sgn = -1;
++  }else if( *zDate=='+' ){
++    sgn = +1;
++  }else{
++    return *zDate!=0;
++  }
++  zDate++;
++  if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
++    return 1;
++  }
++  zDate += 5;
++  p->tz = sgn*(nMn + nHr*60);
++  while( isspace(*zDate) ){ zDate++; }
++  return *zDate!=0;
++}
++
++/*
++** Parse times of the form HH:MM or HH:MM:SS or HH:MM:SS.FFFF.
++** The HH, MM, and SS must each be exactly 2 digits.  The
++** fractional seconds FFFF can be one or more digits.
++**
++** Return 1 if there is a parsing error and 0 on success.
++*/
++static int parseHhMmSs(const char *zDate, DateTime *p){
++  int h, m, s;
++  double ms = 0.0;
++  if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){
++    return 1;
++  }
++  zDate += 5;
++  if( *zDate==':' ){
++    zDate++;
++    if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){
++      return 1;
++    }
++    zDate += 2;
++    if( *zDate=='.' && isdigit(zDate[1]) ){
++      double rScale = 1.0;
++      zDate++;
++      while( isdigit(*zDate) ){
++        ms = ms*10.0 + *zDate - '0';
++        rScale *= 10.0;
++        zDate++;
++      }
++      ms /= rScale;
++    }
++  }else{
++    s = 0;
++  }
++  p->validJD = 0;
++  p->validHMS = 1;
++  p->h = h;
++  p->m = m;
++  p->s = s + ms;
++  if( parseTimezone(zDate, p) ) return 1;
++  p->validTZ = p->tz!=0;
++  return 0;
++}
++
++/*
++** Convert from YYYY-MM-DD HH:MM:SS to julian day.  We always assume
++** that the YYYY-MM-DD is according to the Gregorian calendar.
++**
++** Reference:  Meeus page 61
++*/
++static void computeJD(DateTime *p){
++  int Y, M, D, A, B, X1, X2;
++
++  if( p->validJD ) return;
++  if( p->validYMD ){
++    Y = p->Y;
++    M = p->M;
++    D = p->D;
++  }else{
++    Y = 2000;  /* If no YMD specified, assume 2000-Jan-01 */
++    M = 1;
++    D = 1;
++  }
++  if( M<=2 ){
++    Y--;
++    M += 12;
++  }
++  A = Y/100;
++  B = 2 - A + (A/4);
++  X1 = 365.25*(Y+4716);
++  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->validHMS = 0;
++      p->validTZ = 0;
++    }
++  }
++}
++
++/*
++** Parse dates of the form
++**
++**     YYYY-MM-DD HH:MM:SS.FFF
++**     YYYY-MM-DD HH:MM:SS
++**     YYYY-MM-DD HH:MM
++**     YYYY-MM-DD
++**
++** Write the result into the DateTime structure and return 0
++** on success and 1 if the input string is not a well-formed
++** date.
++*/
++static int parseYyyyMmDd(const char *zDate, DateTime *p){
++  int Y, M, D, neg;
++
++  if( zDate[0]=='-' ){
++    zDate++;
++    neg = 1;
++  }else{
++    neg = 0;
++  }
++  if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
++    return 1;
++  }
++  zDate += 10;
++  while( isspace(*zDate) ){ zDate++; }
++  if( parseHhMmSs(zDate, p)==0 ){
++    /* We got the time */
++  }else if( *zDate==0 ){
++    p->validHMS = 0;
++  }else{
++    return 1;
++  }
++  p->validJD = 0;
++  p->validYMD = 1;
++  p->Y = neg ? -Y : Y;
++  p->M = M;
++  p->D = D;
++  if( p->validTZ ){
++    computeJD(p);
++  }
++  return 0;
++}
++
++/*
++** Attempt to parse the given string into a Julian Day Number.  Return
++** the number of errors.
++**
++** The following are acceptable forms for the input string:
++**
++**      YYYY-MM-DD HH:MM:SS.FFF  +/-HH:MM
++**      DDDD.DD 
++**      now
++**
++** In the first form, the +/-HH:MM is always optional.  The fractional
++** seconds extension (the ".FFF") is optional.  The seconds portion
++** (":SS.FFF") is option.  The year and date can be omitted as long
++** 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){
++  memset(p, 0, sizeof(*p));
++  if( parseYyyyMmDd(zDate,p)==0 ){
++    return 0;
++  }else if( parseHhMmSs(zDate, p)==0 ){
++    return 0;
++  }else if( sqliteStrICmp(zDate,"now")==0){
++    double r;
++    if( sqliteOsCurrentTime(&r)==0 ){
++      p->rJD = r;
++      p->validJD = 1;
++      return 0;
++    }
++    return 1;
++  }else if( sqliteIsNumber(zDate) ){
++    p->rJD = sqliteAtoF(zDate, 0);
++    p->validJD = 1;
++    return 0;
++  }
++  return 1;
++}
++
++/*
++** Compute the Year, Month, and Day from the julian day number.
++*/
++static void computeYMD(DateTime *p){
++  int Z, A, B, C, D, E, X1;
++  if( p->validYMD ) return;
++  if( !p->validJD ){
++    p->Y = 2000;
++    p->M = 1;
++    p->D = 1;
++  }else{
++    Z = p->rJD + 0.5;
++    A = (Z - 1867216.25)/36524.25;
++    A = Z + 1 + A - (A/4);
++    B = A + 1524;
++    C = (B - 122.1)/365.25;
++    D = 365.25*C;
++    E = (B-D)/30.6001;
++    X1 = 30.6001*E;
++    p->D = B - D - X1;
++    p->M = E<14 ? E-1 : E-13;
++    p->Y = p->M>2 ? C - 4716 : C - 4715;
++  }
++  p->validYMD = 1;
++}
++
++/*
++** Compute the Hour, Minute, and Seconds from the julian day number.
++*/
++static void computeHMS(DateTime *p){
++  int Z, s;
++  if( p->validHMS ) return;
++  Z = p->rJD + 0.5;
++  s = (p->rJD + 0.5 - Z)*86400000.0 + 0.5;
++  p->s = 0.001*s;
++  s = p->s;
++  p->s -= s;
++  p->h = s/3600;
++  s -= p->h*3600;
++  p->m = s/60;
++  p->s += s - p->m*60;
++  p->validHMS = 1;
++}
++
++/*
++** Compute both YMD and HMS
++*/
++static void computeYMD_HMS(DateTime *p){
++  computeYMD(p);
++  computeHMS(p);
++}
++
++/*
++** Clear the YMD and HMS and the TZ
++*/
++static void clearYMD_HMS_TZ(DateTime *p){
++  p->validYMD = 0;
++  p->validHMS = 0;
++  p->validTZ = 0;
++}
++
++/*
++** Compute the difference (in days) between localtime and UTC (a.k.a. GMT)
++** for the time value p where p is in UTC.
++*/
++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 ){
++    x.Y = 2000;
++    x.M = 1;
++    x.D = 1;
++    x.h = 0;
++    x.m = 0;
++    x.s = 0.0;
++  } else {
++    int s = x.s + 0.5;
++    x.s = s;
++  }
++  x.tz = 0;
++  x.validJD = 0;
++  computeJD(&x);
++  t = (x.rJD-2440587.5)*86400.0 + 0.5;
++  sqliteOsEnterMutex();
++  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;
++  sqliteOsLeaveMutex();
++  y.validYMD = 1;
++  y.validHMS = 1;
++  y.validJD = 0;
++  y.validTZ = 0;
++  computeJD(&y);
++  return y.rJD - x.rJD;
++}
++
++/*
++** Process a modifier to a date-time stamp.  The modifiers are
++** as follows:
++**
++**     NNN days
++**     NNN hours
++**     NNN minutes
++**     NNN.NNNN seconds
++**     NNN months
++**     NNN years
++**     start of month
++**     start of year
++**     start of week
++**     start of day
++**     weekday N
++**     unixepoch
++**     localtime
++**     utc
++**
++** Return 0 on success and 1 if there is any kind of error.
++*/
++static int parseModifier(const char *zMod, DateTime *p){
++  int rc = 1;
++  int n;
++  double r;
++  char *z, zBuf[30];
++  z = zBuf;
++  for(n=0; n<sizeof(zBuf)-1 && zMod[n]; n++){
++    z[n] = tolower(zMod[n]);
++  }
++  z[n] = 0;
++  switch( z[0] ){
++    case 'l': {
++      /*    localtime
++      **
++      ** Assuming the current time value is UTC (a.k.a. GMT), shift it to
++      ** show local time.
++      */
++      if( strcmp(z, "localtime")==0 ){
++        computeJD(p);
++        p->rJD += localtimeOffset(p);
++        clearYMD_HMS_TZ(p);
++        rc = 0;
++      }
++      break;
++    }
++    case 'u': {
++      /*
++      **    unixepoch
++      **
++      ** Treat the current value of p->rJD as the number of
++      ** seconds since 1970.  Convert to a real julian day number.
++      */
++      if( strcmp(z, "unixepoch")==0 && p->validJD ){
++        p->rJD = p->rJD/86400.0 + 2440587.5;
++        clearYMD_HMS_TZ(p);
++        rc = 0;
++      }else if( strcmp(z, "utc")==0 ){
++        double c1;
++        computeJD(p);
++        c1 = localtimeOffset(p);
++        p->rJD -= c1;
++        clearYMD_HMS_TZ(p);
++        p->rJD += c1 - localtimeOffset(p);
++        rc = 0;
++      }
++      break;
++    }
++    case 'w': {
++      /*
++      **    weekday N
++      **
++      ** Move the date to the same time on the next occurrance of
++      ** weekday N where 0==Sunday, 1==Monday, and so forth.  If the
++      ** date is already on the appropriate weekday, this is a no-op.
++      */
++      if( strncmp(z, "weekday ", 8)==0 && getValue(&z[8],&r)>0
++                 && (n=r)==r && n>=0 && r<7 ){
++        int Z;
++        computeYMD_HMS(p);
++        p->validTZ = 0;
++        p->validJD = 0;
++        computeJD(p);
++        Z = p->rJD + 1.5;
++        Z %= 7;
++        if( Z>n ) Z -= 7;
++        p->rJD += n - Z;
++        clearYMD_HMS_TZ(p);
++        rc = 0;
++      }
++      break;
++    }
++    case 's': {
++      /*
++      **    start of TTTTT
++      **
++      ** Move the date backwards to the beginning of the current day,
++      ** or month or year.
++      */
++      if( strncmp(z, "start of ", 9)!=0 ) break;
++      z += 9;
++      computeYMD(p);
++      p->validHMS = 1;
++      p->h = p->m = 0;
++      p->s = 0.0;
++      p->validTZ = 0;
++      p->validJD = 0;
++      if( strcmp(z,"month")==0 ){
++        p->D = 1;
++        rc = 0;
++      }else if( strcmp(z,"year")==0 ){
++        computeYMD(p);
++        p->M = 1;
++        p->D = 1;
++        rc = 0;
++      }else if( strcmp(z,"day")==0 ){
++        rc = 0;
++      }
++      break;
++    }
++    case '+':
++    case '-':
++    case '0':
++    case '1':
++    case '2':
++    case '3':
++    case '4':
++    case '5':
++    case '6':
++    case '7':
++    case '8':
++    case '9': {
++      n = getValue(z, &r);
++      if( n<=0 ) break;
++      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
++        ** to the time.  The ".FFF" may be omitted.  The ":SS.FFF" may be
++        ** omitted.
++        */
++        const char *z2 = z;
++        DateTime tx;
++        int day;
++        if( !isdigit(*z2) ) z2++;
++        memset(&tx, 0, sizeof(tx));
++        if( parseHhMmSs(z2, &tx) ) break;
++        computeJD(&tx);
++        tx.rJD -= 0.5;
++        day = (int)tx.rJD;
++        tx.rJD -= day;
++        if( z[0]=='-' ) tx.rJD = -tx.rJD;
++        computeJD(p);
++        clearYMD_HMS_TZ(p);
++       p->rJD += tx.rJD;
++        rc = 0;
++        break;
++      }
++      z += n;
++      while( isspace(z[0]) ) z++;
++      n = strlen(z);
++      if( n>10 || n<3 ) break;
++      if( z[n-1]=='s' ){ z[n-1] = 0; n--; }
++      computeJD(p);
++      rc = 0;
++      if( n==3 && strcmp(z,"day")==0 ){
++        p->rJD += r;
++      }else if( n==4 && strcmp(z,"hour")==0 ){
++        p->rJD += r/24.0;
++      }else if( n==6 && strcmp(z,"minute")==0 ){
++        p->rJD += r/(24.0*60.0);
++      }else if( n==6 && strcmp(z,"second")==0 ){
++        p->rJD += r/(24.0*60.0*60.0);
++      }else if( n==5 && strcmp(z,"month")==0 ){
++        int x, y;
++        computeYMD_HMS(p);
++        p->M += r;
++        x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
++        p->Y += x;
++        p->M -= x*12;
++        p->validJD = 0;
++        computeJD(p);
++        y = r;
++        if( y!=r ){
++          p->rJD += (r - y)*30.0;
++        }
++      }else if( n==4 && strcmp(z,"year")==0 ){
++        computeYMD_HMS(p);
++        p->Y += r;
++        p->validJD = 0;
++        computeJD(p);
++      }else{
++        rc = 1;
++      }
++      clearYMD_HMS_TZ(p);
++      break;
++    }
++    default: {
++      break;
++    }
++  }
++  return rc;
++}
++
++/*
++** Process time function arguments.  argv[0] is a date-time stamp.
++** 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.
++*/
++static int isDate(int argc, const char **argv, DateTime *p){
++  int i;
++  if( argc==0 ) return 1;
++  if( argv[0]==0 || parseDateOrTime(argv[0], p) ) return 1;
++  for(i=1; i<argc; i++){
++    if( argv[i]==0 || parseModifier(argv[i], p) ) return 1;
++  }
++  return 0;
++}
++
++
++/*
++** The following routines implement the various date and time functions
++** of SQLite.
++*/
++
++/*
++**    julianday( TIMESTRING, MOD, MOD, ...)
++**
++** Return the julian day number of the date specified in the arguments
++*/
++static void juliandayFunc(sqlite_func *context, int argc, const char **argv){
++  DateTime x;
++  if( isDate(argc, argv, &x)==0 ){
++    computeJD(&x);
++    sqlite_set_result_double(context, x.rJD);
++  }
++}
++
++/*
++**    datetime( TIMESTRING, MOD, MOD, ...)
++**
++** Return YYYY-MM-DD HH:MM:SS
++*/
++static void datetimeFunc(sqlite_func *context, int argc, const char **argv){
++  DateTime x;
++  if( isDate(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));
++    sqlite_set_result_string(context, zBuf, -1);
++  }
++}
++
++/*
++**    time( TIMESTRING, MOD, MOD, ...)
++**
++** Return HH:MM:SS
++*/
++static void timeFunc(sqlite_func *context, int argc, const char **argv){
++  DateTime x;
++  if( isDate(argc, argv, &x)==0 ){
++    char zBuf[100];
++    computeHMS(&x);
++    sprintf(zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s);
++    sqlite_set_result_string(context, zBuf, -1);
++  }
++}
++
++/*
++**    date( TIMESTRING, MOD, MOD, ...)
++**
++** Return YYYY-MM-DD
++*/
++static void dateFunc(sqlite_func *context, int argc, const char **argv){
++  DateTime x;
++  if( isDate(argc, argv, &x)==0 ){
++    char zBuf[100];
++    computeYMD(&x);
++    sprintf(zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D);
++    sqlite_set_result_string(context, zBuf, -1);
++  }
++}
++
++/*
++**    strftime( FORMAT, TIMESTRING, MOD, MOD, ...)
++**
++** Return a string described by FORMAT.  Conversions as follows:
++**
++**   %d  day of month
++**   %f  ** fractional seconds  SS.SSS
++**   %H  hour 00-24
++**   %j  day of year 000-366
++**   %J  ** Julian day number
++**   %m  month 01-12
++**   %M  minute 00-59
++**   %s  seconds since 1970-01-01
++**   %S  seconds 00-59
++**   %w  day of week 0-6  sunday==0
++**   %W  week of year 00-53
++**   %Y  year 0000-9999
++**   %%  %
++*/
++static void strftimeFunc(sqlite_func *context, int argc, const char **argv){
++  DateTime x;
++  int n, i, j;
++  char *z;
++  const char *zFmt = argv[0];
++  char zBuf[100];
++  if( argv[0]==0 || isDate(argc-1, argv+1, &x) ) return;
++  for(i=0, n=1; zFmt[i]; i++, n++){
++    if( zFmt[i]=='%' ){
++      switch( zFmt[i+1] ){
++        case 'd':
++        case 'H':
++        case 'm':
++        case 'M':
++        case 'S':
++        case 'W':
++          n++;
++          /* fall thru */
++        case 'w':
++        case '%':
++          break;
++        case 'f':
++          n += 8;
++          break;
++        case 'j':
++          n += 3;
++          break;
++        case 'Y':
++          n += 8;
++          break;
++        case 's':
++        case 'J':
++          n += 50;
++          break;
++        default:
++          return;  /* ERROR.  return a NULL */
++      }
++      i++;
++    }
++  }
++  if( n<sizeof(zBuf) ){
++    z = zBuf;
++  }else{
++    z = sqliteMalloc( n );
++    if( z==0 ) return;
++  }
++  computeJD(&x);
++  computeYMD_HMS(&x);
++  for(i=j=0; zFmt[i]; i++){
++    if( zFmt[i]!='%' ){
++      z[j++] = zFmt[i];
++    }else{
++      i++;
++      switch( zFmt[i] ){
++        case 'd':  sprintf(&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);
++          j += strlen(&z[j]);
++          break;
++        }
++        case 'H':  sprintf(&z[j],"%02d",x.h); j+=2; break;
++        case 'W': /* Fall thru */
++        case 'j': {
++          int n;             /* Number of days since 1st day of year */
++          DateTime y = x;
++          y.validJD = 0;
++          y.M = 1;
++          y.D = 1;
++          computeJD(&y);
++          n = x.rJD - y.rJD;
++          if( zFmt[i]=='W' ){
++            int wd;   /* 0=Monday, 1=Tuesday, ... 6=Sunday */
++            wd = ((int)(x.rJD+0.5)) % 7;
++            sprintf(&z[j],"%02d",(n+7-wd)/7);
++            j += 2;
++          }else{
++            sprintf(&z[j],"%03d",n+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 's': {
++          sprintf(&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 '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;
++      }
++    }
++  }
++  z[j] = 0;
++  sqlite_set_result_string(context, z, -1);
++  if( z!=zBuf ){
++    sqliteFree(z);
++  }
++}
++
++
++#endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */
++
++/*
++** This function registered all of the above C functions as SQL
++** functions.  This should be the only routine in this file with
++** external linkage.
++*/
++void sqliteRegisterDateTimeFunctions(sqlite *db){
++#ifndef SQLITE_OMIT_DATETIME_FUNCS
++  static struct {
++     char *zName;
++     int nArg;
++     int dataType;
++     void (*xFunc)(sqlite_func*,int,const char**);
++  } aFuncs[] = {
++    { "julianday", -1, SQLITE_NUMERIC, juliandayFunc   },
++    { "date",      -1, SQLITE_TEXT,    dateFunc        },
++    { "time",      -1, SQLITE_TEXT,    timeFunc        },
++    { "datetime",  -1, SQLITE_TEXT,    datetimeFunc    },
++    { "strftime",  -1, SQLITE_TEXT,    strftimeFunc    },
++  };
++  int i;
++
++  for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
++    sqlite_create_function(db, aFuncs[i].zName,
++           aFuncs[i].nArg, aFuncs[i].xFunc, 0);
++    if( aFuncs[i].xFunc ){
++      sqlite_function_type(db, aFuncs[i].zName, aFuncs[i].dataType);
++    }
++  }
++#endif
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/delete.c
+@@ -0,0 +1,393 @@
++/*
++** 2001 September 15
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This file contains C code routines that are called by the parser
++** to handle DELETE FROM statements.
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++
++/*
++** Look up every table that is named in pSrc.  If any table is not found,
++** add an error message to pParse->zErrMsg and return NULL.  If all tables
++** are found, return a pointer to the last table.
++*/
++Table *sqliteSrcListLookup(Parse *pParse, SrcList *pSrc){
++  Table *pTab = 0;
++  int i;
++  for(i=0; i<pSrc->nSrc; i++){
++    const char *zTab = pSrc->a[i].zName;
++    const char *zDb = pSrc->a[i].zDatabase;
++    pTab = sqliteLocateTable(pParse, zTab, zDb);
++    pSrc->a[i].pTab = pTab;
++  }
++  return pTab;
++}
++
++/*
++** Check to make sure the given table is writable.  If it is not
++** writable, generate an error message and return 1.  If it is
++** writable return 0;
++*/
++int sqliteIsReadOnly(Parse *pParse, Table *pTab, int viewOk){
++  if( pTab->readOnly ){
++    sqliteErrorMsg(pParse, "table %s may not be modified", pTab->zName);
++    return 1;
++  }
++  if( !viewOk && pTab->pSelect ){
++    sqliteErrorMsg(pParse, "cannot modify %s because it is a view",pTab->zName);
++    return 1;
++  }
++  return 0;
++}
++
++/*
++** Process a DELETE FROM statement.
++*/
++void sqliteDeleteFrom(
++  Parse *pParse,         /* The parser context */
++  SrcList *pTabList,     /* The table from which we should delete things */
++  Expr *pWhere           /* The WHERE clause.  May be null */
++){
++  Vdbe *v;               /* The virtual database engine */
++  Table *pTab;           /* The table from which records will be deleted */
++  const char *zDb;       /* Name of database holding pTab */
++  int end, addr;         /* A couple addresses of generated code */
++  int i;                 /* Loop counter */
++  WhereInfo *pWInfo;     /* Information about the WHERE clause */
++  Index *pIdx;           /* For looping over indices of the table */
++  int iCur;              /* VDBE Cursor number for pTab */
++  sqlite *db;            /* Main database structure */
++  int isView;            /* True if attempting to delete from a view */
++  AuthContext sContext;  /* Authorization context */
++
++  int row_triggers_exist = 0;  /* True if any triggers exist */
++  int before_triggers;         /* True if there are BEFORE triggers */
++  int after_triggers;          /* True if there are AFTER triggers */
++  int oldIdx = -1;             /* Cursor for the OLD table of AFTER triggers */
++
++  sContext.pParse = 0;
++  if( pParse->nErr || sqlite_malloc_failed ){
++    pTabList = 0;
++    goto delete_from_cleanup;
++  }
++  db = pParse->db;
++  assert( pTabList->nSrc==1 );
++
++  /* Locate the table which we want to delete.  This table has to be
++  ** put in an SrcList structure because some of the subroutines we
++  ** will be calling are designed to work with multiple tables and expect
++  ** an SrcList* parameter instead of just a Table* parameter.
++  */
++  pTab = sqliteSrcListLookup(pParse, pTabList);
++  if( pTab==0 )  goto delete_from_cleanup;
++  before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, 
++                         TK_DELETE, TK_BEFORE, TK_ROW, 0);
++  after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, 
++                         TK_DELETE, TK_AFTER, TK_ROW, 0);
++  row_triggers_exist = before_triggers || after_triggers;
++  isView = pTab->pSelect!=0;
++  if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){
++    goto delete_from_cleanup;
++  }
++  assert( pTab->iDb<db->nDb );
++  zDb = db->aDb[pTab->iDb].zName;
++  if( sqliteAuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
++    goto delete_from_cleanup;
++  }
++
++  /* If pTab is really a view, make sure it has been initialized.
++  */
++  if( isView && sqliteViewGetColumnNames(pParse, pTab) ){
++    goto delete_from_cleanup;
++  }
++
++  /* Allocate a cursor used to store the old.* data for a trigger.
++  */
++  if( row_triggers_exist ){ 
++    oldIdx = pParse->nTab++;
++  }
++
++  /* Resolve the column names in all the expressions.
++  */
++  assert( pTabList->nSrc==1 );
++  iCur = pTabList->a[0].iCursor = pParse->nTab++;
++  if( pWhere ){
++    if( sqliteExprResolveIds(pParse, pTabList, 0, pWhere) ){
++      goto delete_from_cleanup;
++    }
++    if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
++      goto delete_from_cleanup;
++    }
++  }
++
++  /* Start the view context
++  */
++  if( isView ){
++    sqliteAuthContextPush(pParse, &sContext, pTab->zName);
++  }
++
++  /* Begin generating code.
++  */
++  v = sqliteGetVdbe(pParse);
++  if( v==0 ){
++    goto delete_from_cleanup;
++  }
++  sqliteBeginWriteOperation(pParse, row_triggers_exist, pTab->iDb);
++
++  /* If we are trying to delete from a view, construct that view into
++  ** a temporary table.
++  */
++  if( isView ){
++    Select *pView = sqliteSelectDup(pTab->pSelect);
++    sqliteSelect(pParse, pView, SRT_TempTable, iCur, 0, 0, 0);
++    sqliteSelectDelete(pView);
++  }
++
++  /* Initialize the counter of the number of rows deleted, if
++  ** we are counting rows.
++  */
++  if( db->flags & SQLITE_CountRows ){
++    sqliteVdbeAddOp(v, OP_Integer, 0, 0);
++  }
++
++  /* Special case: A DELETE without a WHERE clause deletes everything.
++  ** It is easier just to erase the whole table.  Note, however, that
++  ** this means that the row change count will be incorrect.
++  */
++  if( pWhere==0 && !row_triggers_exist ){
++    if( db->flags & SQLITE_CountRows ){
++      /* If counting rows deleted, just count the total number of
++      ** entries in the table. */
++      int endOfLoop = sqliteVdbeMakeLabel(v);
++      int addr;
++      if( !isView ){
++        sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
++        sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
++      }
++      sqliteVdbeAddOp(v, OP_Rewind, iCur, sqliteVdbeCurrentAddr(v)+2);
++      addr = sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
++      sqliteVdbeAddOp(v, OP_Next, iCur, addr);
++      sqliteVdbeResolveLabel(v, endOfLoop);
++      sqliteVdbeAddOp(v, OP_Close, iCur, 0);
++    }
++    if( !isView ){
++      sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb);
++      for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
++        sqliteVdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->iDb);
++      }
++    }
++  }
++
++  /* The usual case: There is a WHERE clause so we have to scan through
++  ** the table and pick which records to delete.
++  */
++  else{
++    /* Begin the database scan
++    */
++    pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1, 0);
++    if( pWInfo==0 ) goto delete_from_cleanup;
++
++    /* Remember the key of every item to be deleted.
++    */
++    sqliteVdbeAddOp(v, OP_ListWrite, 0, 0);
++    if( db->flags & SQLITE_CountRows ){
++      sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
++    }
++
++    /* End the database scan loop.
++    */
++    sqliteWhereEnd(pWInfo);
++
++    /* Open the pseudo-table used to store OLD if there are triggers.
++    */
++    if( row_triggers_exist ){
++      sqliteVdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
++    }
++
++    /* Delete every item whose key was written to the list during the
++    ** database scan.  We have to delete items after the scan is complete
++    ** because deleting an item can change the scan order.
++    */
++    sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
++    end = sqliteVdbeMakeLabel(v);
++
++    /* This is the beginning of the delete loop when there are
++    ** row triggers.
++    */
++    if( row_triggers_exist ){
++      addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
++      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
++      if( !isView ){
++        sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
++        sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
++      }
++      sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
++
++      sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
++      sqliteVdbeAddOp(v, OP_RowData, iCur, 0);
++      sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
++      if( !isView ){
++        sqliteVdbeAddOp(v, OP_Close, iCur, 0);
++      }
++
++      sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, 
++          oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
++        addr);
++    }
++
++    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_ListRead 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.
++      */
++      pParse->nTab = iCur + 1;
++      sqliteOpenTableAndIndices(pParse, pTab, iCur);
++
++      /* This is the beginning of the delete loop when there are no
++      ** row triggers */
++      if( !row_triggers_exist ){ 
++        addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
++      }
++
++      /* Delete the row */
++      sqliteGenerateRowDelete(db, v, pTab, iCur, pParse->trigStack==0);
++    }
++
++    /* If there are row triggers, close all cursors then invoke
++    ** the AFTER triggers
++    */
++    if( row_triggers_exist ){
++      if( !isView ){
++        for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
++          sqliteVdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
++        }
++        sqliteVdbeAddOp(v, OP_Close, iCur, 0);
++      }
++      sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, 
++          oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
++        addr);
++    }
++
++    /* End of the delete loop */
++    sqliteVdbeAddOp(v, OP_Goto, 0, addr);
++    sqliteVdbeResolveLabel(v, end);
++    sqliteVdbeAddOp(v, OP_ListReset, 0, 0);
++
++    /* Close the cursors after the loop if there are no row triggers */
++    if( !row_triggers_exist ){
++      for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
++        sqliteVdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
++      }
++      sqliteVdbeAddOp(v, OP_Close, iCur, 0);
++      pParse->nTab = iCur;
++    }
++  }
++  sqliteVdbeAddOp(v, OP_SetCounts, 0, 0);
++  sqliteEndWriteOperation(pParse);
++
++  /*
++  ** Return the number of rows that were deleted.
++  */
++  if( db->flags & SQLITE_CountRows ){
++    sqliteVdbeAddOp(v, OP_ColumnName, 0, 1);
++    sqliteVdbeChangeP3(v, -1, "rows deleted", P3_STATIC);
++    sqliteVdbeAddOp(v, OP_Callback, 1, 0);
++  }
++
++delete_from_cleanup:
++  sqliteAuthContextPop(&sContext);
++  sqliteSrcListDelete(pTabList);
++  sqliteExprDelete(pWhere);
++  return;
++}
++
++/*
++** This routine generates VDBE code that causes a single row of a
++** single table to be deleted.
++**
++** The VDBE must be in a particular state when this routine is called.
++** These are the requirements:
++**
++**   1.  A read/write cursor pointing to pTab, the table containing the row
++**       to be deleted, must be opened as cursor number "base".
++**
++**   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.
++**
++** 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 sqliteGenerateRowDelete(
++  sqlite *db,        /* The database containing the index */
++  Vdbe *v,           /* Generate code into this VDBE */
++  Table *pTab,       /* Table containing the row to be deleted */
++  int iCur,          /* Cursor number for the table */
++  int count          /* Increment the row change counter */
++){
++  int addr;
++  addr = sqliteVdbeAddOp(v, OP_NotExists, iCur, 0);
++  sqliteGenerateRowIndexDelete(db, v, pTab, iCur, 0);
++  sqliteVdbeAddOp(v, OP_Delete, iCur,
++    (count?OPFLAG_NCHANGE:0) | OPFLAG_CSCHANGE);
++  sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
++}
++
++/*
++** This routine generates VDBE code that causes the deletion of all
++** index entries associated with a single row of a single table.
++**
++** The VDBE must be in a particular state when this routine is called.
++** These are the requirements:
++**
++**   1.  A read/write cursor pointing to pTab, the table containing the row
++**       to be deleted, must be opened as cursor number "iCur".
++**
++**   2.  Read/write cursors for all indices of pTab must be open as
++**       cursor number iCur+i for the i-th index.
++**
++**   3.  The "iCur" cursor must be pointing to the row that is to be
++**       deleted.
++*/
++void sqliteGenerateRowIndexDelete(
++  sqlite *db,        /* The database containing the index */
++  Vdbe *v,           /* Generate code into this VDBE */
++  Table *pTab,       /* Table containing the row to be deleted */
++  int iCur,          /* Cursor number for the table */
++  char *aIdxUsed     /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */
++){
++  int i;
++  Index *pIdx;
++
++  for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
++    int j;
++    if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue;
++    sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
++    for(j=0; j<pIdx->nColumn; j++){
++      int idx = pIdx->aiColumn[j];
++      if( idx==pTab->iPKey ){
++        sqliteVdbeAddOp(v, OP_Dup, j, 0);
++      }else{
++        sqliteVdbeAddOp(v, OP_Column, iCur, idx);
++      }
++    }
++    sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
++    if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx);
++    sqliteVdbeAddOp(v, OP_IdxDelete, iCur+i, 0);
++  }
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/encode.c
+@@ -0,0 +1,257 @@
++/*
++** 2002 April 25
++**
++** 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 helper routines used to translate binary data into
++** a null-terminated string (suitable for use in SQLite) and back again.
++** These are convenience routines for use by people who want to store binary
++** data in an SQLite database.  The code in this file is not used by any other
++** part of the SQLite library.
++**
++** $Id$
++*/
++#include <string.h>
++#include <assert.h>
++
++/*
++** How This Encoder Works
++**
++** The output is allowed to contain any character except 0x27 (') and
++** 0x00.  This is accomplished by using an escape character to encode
++** 0x27 and 0x00 as a two-byte sequence.  The escape character is always
++** 0x01.  An 0x00 is encoded as the two byte sequence 0x01 0x01.  The
++** 0x27 character is encoded as the two byte sequence 0x01 0x28.  Finally,
++** the escape character itself is encoded as the two-character sequence
++** 0x01 0x02.
++**
++** To summarize, the encoder works by using an escape sequences as follows:
++**
++**       0x00  ->  0x01 0x01
++**       0x01  ->  0x01 0x02
++**       0x27  ->  0x01 0x28
++**
++** If that were all the encoder did, it would work, but in certain cases
++** it could double the size of the encoded string.  For example, to
++** encode a string of 100 0x27 characters would require 100 instances of
++** the 0x01 0x03 escape sequence resulting in a 200-character output.
++** We would prefer to keep the size of the encoded string smaller than
++** this.
++**
++** To minimize the encoding size, we first add a fixed offset value to each 
++** byte in the sequence.  The addition is modulo 256.  (That is to say, if
++** the sum of the original character value and the offset exceeds 256, then
++** the higher order bits are truncated.)  The offset is chosen to minimize
++** the number of characters in the string that need to be escaped.  For
++** example, in the case above where the string was composed of 100 0x27
++** characters, the offset might be 0x01.  Each of the 0x27 characters would
++** then be converted into an 0x28 character which would not need to be
++** escaped at all and so the 100 character input string would be converted
++** into just 100 characters of output.  Actually 101 characters of output - 
++** we have to record the offset used as the first byte in the sequence so
++** that the string can be decoded.  Since the offset value is stored as
++** part of the output string and the output string is not allowed to contain
++** characters 0x00 or 0x27, the offset cannot be 0x00 or 0x27.
++**
++** Here, then, are the encoding steps:
++**
++**     (1)   Choose an offset value and make it the first character of
++**           output.
++**
++**     (2)   Copy each input character into the output buffer, one by
++**           one, adding the offset value as you copy.
++**
++**     (3)   If the value of an input character plus offset is 0x00, replace
++**           that one character by the two-character sequence 0x01 0x01.
++**           If the sum is 0x01, replace it with 0x01 0x02.  If the sum
++**           is 0x27, replace it with 0x01 0x03.
++**
++**     (4)   Put a 0x00 terminator at the end of the output.
++**
++** Decoding is obvious:
++**
++**     (5)   Copy encoded characters except the first into the decode 
++**           buffer.  Set the first encoded character aside for use as
++**           the offset in step 7 below.
++**
++**     (6)   Convert each 0x01 0x01 sequence into a single character 0x00.
++**           Convert 0x01 0x02 into 0x01.  Convert 0x01 0x28 into 0x27.
++**
++**     (7)   Subtract the offset value that was the first character of
++**           the encoded buffer from all characters in the output buffer.
++**
++** The only tricky part is step (1) - how to compute an offset value to
++** minimize the size of the output buffer.  This is accomplished by testing
++** all offset values and picking the one that results in the fewest number
++** of escapes.  To do that, we first scan the entire input and count the
++** number of occurances of each character value in the input.  Suppose
++** the number of 0x00 characters is N(0), the number of occurances of 0x01
++** is N(1), and so forth up to the number of occurances of 0xff is N(255).
++** An offset of 0 is not allowed so we don't have to test it.  The number
++** of escapes required for an offset of 1 is N(1)+N(2)+N(40).  The number
++** of escapes required for an offset of 2 is N(2)+N(3)+N(41).  And so forth.
++** In this way we find the offset that gives the minimum number of escapes,
++** and thus minimizes the length of the output string.
++*/
++
++/*
++** Encode a binary buffer "in" of size n bytes so that it contains
++** no instances of characters '\'' or '\000'.  The output is 
++** null-terminated and can be used as a string value in an INSERT
++** or UPDATE statement.  Use sqlite_decode_binary() to convert the
++** string back into its original binary.
++**
++** The result is written into a preallocated output buffer "out".
++** "out" must be able to hold at least 2 +(257*n)/254 bytes.
++** In other words, the output will be expanded by as much as 3
++** bytes for every 254 bytes of input plus 2 bytes of fixed overhead.
++** (This is approximately 2 + 1.0118*n or about a 1.2% size increase.)
++**
++** The return value is the number of characters in the encoded
++** string, excluding the "\000" terminator.
++**
++** If out==NULL then no output is generated but the routine still returns
++** the number of characters that would have been generated if out had
++** not been NULL.
++*/
++int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out){
++  int i, j, e, m;
++  unsigned char x;
++  int cnt[256];
++  if( n<=0 ){
++    if( out ){
++      out[0] = 'x';
++      out[1] = 0;
++    }
++    return 1;
++  }
++  memset(cnt, 0, sizeof(cnt));
++  for(i=n-1; i>=0; i--){ cnt[in[i]]++; }
++  m = n;
++  for(i=1; i<256; i++){
++    int sum;
++    if( i=='\'' ) continue;
++    sum = cnt[i] + cnt[(i+1)&0xff] + cnt[(i+'\'')&0xff];
++    if( sum<m ){
++      m = sum;
++      e = i;
++      if( m==0 ) break;
++    }
++  }
++  if( out==0 ){
++    return n+m+1;
++  }
++  out[0] = e;
++  j = 1;
++  for(i=0; i<n; i++){
++    x = in[i] - e;
++    if( x==0 || x==1 || x=='\''){
++      out[j++] = 1;
++      x++;
++    }
++    out[j++] = x;
++  }
++  out[j] = 0;
++  assert( j==n+m+1 );
++  return j;
++}
++
++/*
++** Decode the string "in" into binary data and write it into "out".
++** This routine reverses the encoding created by sqlite_encode_binary().
++** The output will always be a few bytes less than the input.  The number
++** of bytes of output is returned.  If the input is not a well-formed
++** encoding, -1 is returned.
++**
++** The "in" and "out" parameters may point to the same buffer in order
++** to decode a string in place.
++*/
++int sqlite_decode_binary(const unsigned char *in, unsigned char *out){
++  int i, e;
++  unsigned char c;
++  e = *(in++);
++  if (e == 0) {
++    return 0;
++  }
++  i = 0;
++  while( (c = *(in++))!=0 ){
++    if (c == 1) {
++      c = *(in++) - 1;
++    }
++    out[i++] = c + e;
++  }
++  return i;
++}
++
++#ifdef ENCODER_TEST
++#include <stdio.h>
++/*
++** The subroutines above are not tested by the usual test suite.  To test
++** these routines, compile just this one file with a -DENCODER_TEST=1 option
++** and run the result.
++*/
++int main(int argc, char **argv){
++  int i, j, n, m, nOut, nByteIn, nByteOut;
++  unsigned char in[30000];
++  unsigned char out[33000];
++
++  nByteIn = nByteOut = 0;
++  for(i=0; i<sizeof(in); i++){
++    printf("Test %d: ", i+1);
++    n = rand() % (i+1);
++    if( i%100==0 ){
++      int k;
++      for(j=k=0; j<n; j++){
++        /* if( k==0 || k=='\'' ) k++; */
++        in[j] = k;
++        k = (k+1)&0xff;
++      }
++    }else{
++      for(j=0; j<n; j++) in[j] = rand() & 0xff;
++    }
++    nByteIn += n;
++    nOut = sqlite_encode_binary(in, n, out);
++    nByteOut += nOut;
++    if( nOut!=strlen(out) ){
++      printf(" ERROR return value is %d instead of %d\n", nOut, strlen(out));
++      exit(1);
++    }
++    if( nOut!=sqlite_encode_binary(in, n, 0) ){
++      printf(" ERROR actual output size disagrees with predicted size\n");
++      exit(1);
++    }
++    m = (256*n + 1262)/253;
++    printf("size %d->%d (max %d)", n, strlen(out)+1, m);
++    if( strlen(out)+1>m ){
++      printf(" ERROR output too big\n");
++      exit(1);
++    }
++    for(j=0; out[j]; j++){
++      if( out[j]=='\'' ){
++        printf(" ERROR contains (')\n");
++        exit(1);
++      }
++    }
++    j = sqlite_decode_binary(out, out);
++    if( j!=n ){
++      printf(" ERROR decode size %d\n", j);
++      exit(1);
++    }
++    if( memcmp(in, out, n)!=0 ){
++      printf(" ERROR decode mismatch\n");
++      exit(1);
++    }
++    printf(" OK\n");
++  }
++  fprintf(stderr,"Finished.  Total encoding: %d->%d bytes\n",
++          nByteIn, nByteOut);
++  fprintf(stderr,"Avg size increase: %.3f%%\n",
++    (nByteOut-nByteIn)*100.0/(double)nByteIn);
++}
++#endif /* ENCODER_TEST */
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/expr.c
+@@ -0,0 +1,1662 @@
++/*
++** 2001 September 15
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This file contains routines used for analyzing expressions and
++** for generating VDBE code that evaluates expressions in SQLite.
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++#include <ctype.h>
++
++/*
++** Construct a new expression node and return a pointer to it.  Memory
++** for this node is obtained from sqliteMalloc().  The calling function
++** is responsible for making sure the node eventually gets freed.
++*/
++Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){
++  Expr *pNew;
++  pNew = sqliteMalloc( sizeof(Expr) );
++  if( pNew==0 ){
++    /* When malloc fails, we leak memory from pLeft and pRight */
++    return 0;
++  }
++  pNew->op = op;
++  pNew->pLeft = pLeft;
++  pNew->pRight = pRight;
++  if( pToken ){
++    assert( pToken->dyn==0 );
++    pNew->token = *pToken;
++    pNew->span = *pToken;
++  }else{
++    assert( pNew->token.dyn==0 );
++    assert( pNew->token.z==0 );
++    assert( pNew->token.n==0 );
++    if( pLeft && pRight ){
++      sqliteExprSpan(pNew, &pLeft->span, &pRight->span);
++    }else{
++      pNew->span = pNew->token;
++    }
++  }
++  return pNew;
++}
++
++/*
++** Set the Expr.span field of the given expression to span all
++** text between the two given tokens.
++*/
++void sqliteExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
++  assert( pRight!=0 );
++  assert( pLeft!=0 );
++  /* Note: pExpr might be NULL due to a prior malloc failure */
++  if( pExpr && pRight->z && pLeft->z ){
++    if( pLeft->dyn==0 && pRight->dyn==0 ){
++      pExpr->span.z = pLeft->z;
++      pExpr->span.n = pRight->n + Addr(pRight->z) - Addr(pLeft->z);
++    }else{
++      pExpr->span.z = 0;
++    }
++  }
++}
++
++/*
++** Construct a new expression node for a function with multiple
++** arguments.
++*/
++Expr *sqliteExprFunction(ExprList *pList, Token *pToken){
++  Expr *pNew;
++  pNew = sqliteMalloc( sizeof(Expr) );
++  if( pNew==0 ){
++    /* sqliteExprListDelete(pList); // Leak pList when malloc fails */
++    return 0;
++  }
++  pNew->op = TK_FUNCTION;
++  pNew->pList = pList;
++  if( pToken ){
++    assert( pToken->dyn==0 );
++    pNew->token = *pToken;
++  }else{
++    pNew->token.z = 0;
++  }
++  pNew->span = pNew->token;
++  return pNew;
++}
++
++/*
++** Recursively delete an expression tree.
++*/
++void sqliteExprDelete(Expr *p){
++  if( p==0 ) return;
++  if( p->span.dyn ) sqliteFree((char*)p->span.z);
++  if( p->token.dyn ) sqliteFree((char*)p->token.z);
++  sqliteExprDelete(p->pLeft);
++  sqliteExprDelete(p->pRight);
++  sqliteExprListDelete(p->pList);
++  sqliteSelectDelete(p->pSelect);
++  sqliteFree(p);
++}
++
++
++/*
++** The following group of routines make deep copies of expressions,
++** expression lists, ID lists, and select statements.  The copies can
++** be deleted (by being passed to their respective ...Delete() routines)
++** without effecting the originals.
++**
++** The expression list, ID, and source lists return by sqliteExprListDup(),
++** sqliteIdListDup(), and sqliteSrcListDup() can not be further expanded 
++** by subsequent calls to sqlite*ListAppend() routines.
++**
++** Any tables that the SrcList might point to are not duplicated.
++*/
++Expr *sqliteExprDup(Expr *p){
++  Expr *pNew;
++  if( p==0 ) return 0;
++  pNew = sqliteMallocRaw( sizeof(*p) );
++  if( pNew==0 ) return 0;
++  memcpy(pNew, p, sizeof(*pNew));
++  if( p->token.z!=0 ){
++    pNew->token.z = sqliteStrNDup(p->token.z, p->token.n);
++    pNew->token.dyn = 1;
++  }else{
++    assert( pNew->token.z==0 );
++  }
++  pNew->span.z = 0;
++  pNew->pLeft = sqliteExprDup(p->pLeft);
++  pNew->pRight = sqliteExprDup(p->pRight);
++  pNew->pList = sqliteExprListDup(p->pList);
++  pNew->pSelect = sqliteSelectDup(p->pSelect);
++  return pNew;
++}
++void sqliteTokenCopy(Token *pTo, Token *pFrom){
++  if( pTo->dyn ) sqliteFree((char*)pTo->z);
++  if( pFrom->z ){
++    pTo->n = pFrom->n;
++    pTo->z = sqliteStrNDup(pFrom->z, pFrom->n);
++    pTo->dyn = 1;
++  }else{
++    pTo->z = 0;
++  }
++}
++ExprList *sqliteExprListDup(ExprList *p){
++  ExprList *pNew;
++  struct ExprList_item *pItem;
++  int i;
++  if( p==0 ) return 0;
++  pNew = sqliteMalloc( sizeof(*pNew) );
++  if( pNew==0 ) return 0;
++  pNew->nExpr = pNew->nAlloc = p->nExpr;
++  pNew->a = pItem = sqliteMalloc( p->nExpr*sizeof(p->a[0]) );
++  if( pItem==0 ){
++    sqliteFree(pNew);
++    return 0;
++  }
++  for(i=0; i<p->nExpr; i++, pItem++){
++    Expr *pNewExpr, *pOldExpr;
++    pItem->pExpr = pNewExpr = sqliteExprDup(pOldExpr = p->a[i].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 */
++      sqliteTokenCopy(&pNewExpr->span, &pOldExpr->span);
++    }
++    assert( pNewExpr==0 || pNewExpr->span.z!=0 
++            || pOldExpr->span.z==0 || sqlite_malloc_failed );
++    pItem->zName = sqliteStrDup(p->a[i].zName);
++    pItem->sortOrder = p->a[i].sortOrder;
++    pItem->isAgg = p->a[i].isAgg;
++    pItem->done = 0;
++  }
++  return pNew;
++}
++SrcList *sqliteSrcListDup(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 );
++  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];
++    pNewItem->zDatabase = sqliteStrDup(pOldItem->zDatabase);
++    pNewItem->zName = sqliteStrDup(pOldItem->zName);
++    pNewItem->zAlias = sqliteStrDup(pOldItem->zAlias);
++    pNewItem->jointype = pOldItem->jointype;
++    pNewItem->iCursor = pOldItem->iCursor;
++    pNewItem->pTab = 0;
++    pNewItem->pSelect = sqliteSelectDup(pOldItem->pSelect);
++    pNewItem->pOn = sqliteExprDup(pOldItem->pOn);
++    pNewItem->pUsing = sqliteIdListDup(pOldItem->pUsing);
++  }
++  return pNew;
++}
++IdList *sqliteIdListDup(IdList *p){
++  IdList *pNew;
++  int i;
++  if( p==0 ) return 0;
++  pNew = sqliteMallocRaw( sizeof(*pNew) );
++  if( pNew==0 ) return 0;
++  pNew->nId = pNew->nAlloc = p->nId;
++  pNew->a = sqliteMallocRaw( p->nId*sizeof(p->a[0]) );
++  if( pNew->a==0 ) 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->idx = pOldItem->idx;
++  }
++  return pNew;
++}
++Select *sqliteSelectDup(Select *p){
++  Select *pNew;
++  if( p==0 ) return 0;
++  pNew = sqliteMallocRaw( sizeof(*p) );
++  if( pNew==0 ) return 0;
++  pNew->isDistinct = p->isDistinct;
++  pNew->pEList = sqliteExprListDup(p->pEList);
++  pNew->pSrc = sqliteSrcListDup(p->pSrc);
++  pNew->pWhere = sqliteExprDup(p->pWhere);
++  pNew->pGroupBy = sqliteExprListDup(p->pGroupBy);
++  pNew->pHaving = sqliteExprDup(p->pHaving);
++  pNew->pOrderBy = sqliteExprListDup(p->pOrderBy);
++  pNew->op = p->op;
++  pNew->pPrior = sqliteSelectDup(p->pPrior);
++  pNew->nLimit = p->nLimit;
++  pNew->nOffset = p->nOffset;
++  pNew->zSelect = 0;
++  pNew->iLimit = -1;
++  pNew->iOffset = -1;
++  return pNew;
++}
++
++
++/*
++** Add a new element to the end of an expression list.  If pList is
++** initially NULL, then create a new expression list.
++*/
++ExprList *sqliteExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){
++  if( pList==0 ){
++    pList = sqliteMalloc( sizeof(ExprList) );
++    if( pList==0 ){
++      /* sqliteExprDelete(pExpr); // Leak memory if malloc fails */
++      return 0;
++    }
++    assert( pList->nAlloc==0 );
++  }
++  if( pList->nAlloc<=pList->nExpr ){
++    pList->nAlloc = pList->nAlloc*2 + 4;
++    pList->a = sqliteRealloc(pList->a, pList->nAlloc*sizeof(pList->a[0]));
++    if( pList->a==0 ){
++      /* sqliteExprDelete(pExpr); // Leak memory if malloc fails */
++      pList->nExpr = pList->nAlloc = 0;
++      return pList;
++    }
++  }
++  assert( pList->a!=0 );
++  if( pExpr || pName ){
++    struct ExprList_item *pItem = &pList->a[pList->nExpr++];
++    memset(pItem, 0, sizeof(*pItem));
++    pItem->pExpr = pExpr;
++    if( pName ){
++      sqliteSetNString(&pItem->zName, pName->z, pName->n, 0);
++      sqliteDequote(pItem->zName);
++    }
++  }
++  return pList;
++}
++
++/*
++** Delete an entire expression list.
++*/
++void sqliteExprListDelete(ExprList *pList){
++  int i;
++  if( pList==0 ) return;
++  assert( pList->a!=0 || (pList->nExpr==0 && pList->nAlloc==0) );
++  assert( pList->nExpr<=pList->nAlloc );
++  for(i=0; i<pList->nExpr; i++){
++    sqliteExprDelete(pList->a[i].pExpr);
++    sqliteFree(pList->a[i].zName);
++  }
++  sqliteFree(pList->a);
++  sqliteFree(pList);
++}
++
++/*
++** Walk an expression tree.  Return 1 if the expression is constant
++** and 0 if it involves variables.
++**
++** For the purposes of this function, a double-quoted string (ex: "abc")
++** is considered a variable but a single-quoted string (ex: 'abc') is
++** a constant.
++*/
++int sqliteExprIsConstant(Expr *p){
++  switch( p->op ){
++    case TK_ID:
++    case TK_COLUMN:
++    case TK_DOT:
++    case TK_FUNCTION:
++      return 0;
++    case TK_NULL:
++    case TK_STRING:
++    case TK_INTEGER:
++    case TK_FLOAT:
++    case TK_VARIABLE:
++      return 1;
++    default: {
++      if( p->pLeft && !sqliteExprIsConstant(p->pLeft) ) return 0;
++      if( p->pRight && !sqliteExprIsConstant(p->pRight) ) return 0;
++      if( p->pList ){
++        int i;
++        for(i=0; i<p->pList->nExpr; i++){
++          if( !sqliteExprIsConstant(p->pList->a[i].pExpr) ) return 0;
++        }
++      }
++      return p->pLeft!=0 || p->pRight!=0 || (p->pList && p->pList->nExpr>0);
++    }
++  }
++  return 0;
++}
++
++/*
++** If the given expression codes a constant integer that is small enough
++** to fit in a 32-bit integer, return 1 and put the value of the integer
++** in *pValue.  If the expression is not an integer or if it is too big
++** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged.
++*/
++int sqliteExprIsInteger(Expr *p, int *pValue){
++  switch( p->op ){
++    case TK_INTEGER: {
++      if( sqliteFitsIn32Bits(p->token.z) ){
++        *pValue = atoi(p->token.z);
++        return 1;
++      }
++      break;
++    }
++    case TK_STRING: {
++      const char *z = p->token.z;
++      int n = p->token.n;
++      if( n>0 && z[0]=='-' ){ z++; n--; }
++      while( n>0 && *z && isdigit(*z) ){ z++; n--; }
++      if( n==0 && sqliteFitsIn32Bits(p->token.z) ){
++        *pValue = atoi(p->token.z);
++        return 1;
++      }
++      break;
++    }
++    case TK_UPLUS: {
++      return sqliteExprIsInteger(p->pLeft, pValue);
++    }
++    case TK_UMINUS: {
++      int v;
++      if( sqliteExprIsInteger(p->pLeft, &v) ){
++        *pValue = -v;
++        return 1;
++      }
++      break;
++    }
++    default: break;
++  }
++  return 0;
++}
++
++/*
++** Return TRUE if the given string is a row-id column name.
++*/
++int sqliteIsRowid(const char *z){
++  if( sqliteStrICmp(z, "_ROWID_")==0 ) return 1;
++  if( sqliteStrICmp(z, "ROWID")==0 ) return 1;
++  if( sqliteStrICmp(z, "OID")==0 ) return 1;
++  return 0;
++}
++
++/*
++** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
++** that name in the set of source tables in pSrcList and make the pExpr 
++** expression node refer back to that source column.  The following changes
++** are made to pExpr:
++**
++**    pExpr->iDb           Set the index in db->aDb[] of the database holding
++**                         the table.
++**    pExpr->iTable        Set to the cursor number for the table obtained
++**                         from pSrcList.
++**    pExpr->iColumn       Set to the column number within the table.
++**    pExpr->dataType      Set to the appropriate data type for the column.
++**    pExpr->op            Set to TK_COLUMN.
++**    pExpr->pLeft         Any expression this points to is deleted
++**    pExpr->pRight        Any expression this points to is deleted.
++**
++** The pDbToken is the name of the database (the "X").  This value may be
++** NULL meaning that name is of the form Y.Z or Z.  Any available database
++** can be used.  The pTableToken is the name of the table (the "Y").  This
++** value can be NULL if pDbToken is also NULL.  If pTableToken is NULL it
++** means that the form of the name is Z and that columns from any table
++** can be used.
++**
++** If the name cannot be resolved unambiguously, leave an error message
++** in pParse and return non-zero.  Return zero on success.
++*/
++static int lookupName(
++  Parse *pParse,      /* The parsing context */
++  Token *pDbToken,     /* Name of the database containing table, or NULL */
++  Token *pTableToken,  /* Name of table containing column, or NULL */
++  Token *pColumnToken, /* Name of the column. */
++  SrcList *pSrcList,   /* List of tables used to resolve column names */
++  ExprList *pEList,    /* List of expressions used to resolve "AS" */
++  Expr *pExpr          /* Make this EXPR node point to the selected column */
++){
++  char *zDb = 0;       /* Name of the database.  The "X" in X.Y.Z */
++  char *zTab = 0;      /* Name of the table.  The "Y" in X.Y.Z or Y.Z */
++  char *zCol = 0;      /* Name of the column.  The "Z" */
++  int i, j;            /* Loop counters */
++  int cnt = 0;         /* Number of matching column names */
++  int cntTab = 0;      /* Number of matching table names */
++  sqlite *db = pParse->db;  /* The database */
++
++  assert( pColumnToken && pColumnToken->z ); /* The Z in X.Y.Z cannot be NULL */
++  if( pDbToken && pDbToken->z ){
++    zDb = sqliteStrNDup(pDbToken->z, pDbToken->n);
++    sqliteDequote(zDb);
++  }else{
++    zDb = 0;
++  }
++  if( pTableToken && pTableToken->z ){
++    zTab = sqliteStrNDup(pTableToken->z, pTableToken->n);
++    sqliteDequote(zTab);
++  }else{
++    assert( zDb==0 );
++    zTab = 0;
++  }
++  zCol = sqliteStrNDup(pColumnToken->z, pColumnToken->n);
++  sqliteDequote(zCol);
++  if( sqlite_malloc_failed ){
++    return 1;  /* Leak memory (zDb and zTab) if malloc fails */
++  }
++  assert( zTab==0 || pEList==0 );
++
++  pExpr->iTable = -1;
++  for(i=0; i<pSrcList->nSrc; i++){
++    struct SrcList_item *pItem = &pSrcList->a[i];
++    Table *pTab = pItem->pTab;
++    Column *pCol;
++
++    if( pTab==0 ) continue;
++    assert( pTab->nCol>0 );
++    if( zTab ){
++      if( pItem->zAlias ){
++        char *zTabName = pItem->zAlias;
++        if( sqliteStrICmp(zTabName, zTab)!=0 ) continue;
++      }else{
++        char *zTabName = pTab->zName;
++        if( zTabName==0 || sqliteStrICmp(zTabName, zTab)!=0 ) continue;
++        if( zDb!=0 && sqliteStrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){
++          continue;
++        }
++      }
++    }
++    if( 0==(cntTab++) ){
++      pExpr->iTable = pItem->iCursor;
++      pExpr->iDb = pTab->iDb;
++    }
++    for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
++      if( sqliteStrICmp(pCol->zName, zCol)==0 ){
++        cnt++;
++        pExpr->iTable = pItem->iCursor;
++        pExpr->iDb = pTab->iDb;
++        /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
++        pExpr->iColumn = j==pTab->iPKey ? -1 : j;
++        pExpr->dataType = pCol->sortOrder & SQLITE_SO_TYPEMASK;
++        break;
++      }
++    }
++  }
++
++  /* If we have not already resolved the name, then maybe 
++  ** it is a new.* or old.* trigger argument reference
++  */
++  if( zDb==0 && zTab!=0 && cnt==0 && pParse->trigStack!=0 ){
++    TriggerStack *pTriggerStack = pParse->trigStack;
++    Table *pTab = 0;
++    if( pTriggerStack->newIdx != -1 && sqliteStrICmp("new", zTab) == 0 ){
++      pExpr->iTable = pTriggerStack->newIdx;
++      assert( pTriggerStack->pTab );
++      pTab = pTriggerStack->pTab;
++    }else if( pTriggerStack->oldIdx != -1 && sqliteStrICmp("old", zTab) == 0 ){
++      pExpr->iTable = pTriggerStack->oldIdx;
++      assert( pTriggerStack->pTab );
++      pTab = pTriggerStack->pTab;
++    }
++
++    if( pTab ){ 
++      int j;
++      Column *pCol = pTab->aCol;
++      
++      pExpr->iDb = pTab->iDb;
++      cntTab++;
++      for(j=0; j < pTab->nCol; j++, pCol++) {
++        if( sqliteStrICmp(pCol->zName, zCol)==0 ){
++          cnt++;
++          pExpr->iColumn = j==pTab->iPKey ? -1 : j;
++          pExpr->dataType = pCol->sortOrder & SQLITE_SO_TYPEMASK;
++          break;
++        }
++      }
++    }
++  }
++
++  /*
++  ** Perhaps the name is a reference to the ROWID
++  */
++  if( cnt==0 && cntTab==1 && sqliteIsRowid(zCol) ){
++    cnt = 1;
++    pExpr->iColumn = -1;
++    pExpr->dataType = SQLITE_SO_NUM;
++  }
++
++  /*
++  ** If the input is of the form Z (not Y.Z or X.Y.Z) then the name Z
++  ** might refer to an result-set alias.  This happens, for example, when
++  ** we are resolving names in the WHERE clause of the following command:
++  **
++  **     SELECT a+b AS x FROM table WHERE x<10;
++  **
++  ** In cases like this, replace pExpr with a copy of the expression that
++  ** forms the result set entry ("a+b" in the example) and return immediately.
++  ** Note that the expression in the result set should have already been
++  ** resolved by the time the WHERE clause is resolved.
++  */
++  if( cnt==0 && pEList!=0 ){
++    for(j=0; j<pEList->nExpr; j++){
++      char *zAs = pEList->a[j].zName;
++      if( zAs!=0 && sqliteStrICmp(zAs, zCol)==0 ){
++        assert( pExpr->pLeft==0 && pExpr->pRight==0 );
++        pExpr->op = TK_AS;
++        pExpr->iColumn = j;
++        pExpr->pLeft = sqliteExprDup(pEList->a[j].pExpr);
++        sqliteFree(zCol);
++        assert( zTab==0 && zDb==0 );
++        return 0;
++      }
++    } 
++  }
++
++  /*
++  ** If X and Y are NULL (in other words if only the column name Z is
++  ** supplied) and the value of Z is enclosed in double-quotes, then
++  ** Z is a string literal if it doesn't match any column names.  In that
++  ** case, we need to return right away and not make any changes to
++  ** pExpr.
++  */
++  if( cnt==0 && zTab==0 && pColumnToken->z[0]=='"' ){
++    sqliteFree(zCol);
++    return 0;
++  }
++
++  /*
++  ** cnt==0 means there was not match.  cnt>1 means there were two or
++  ** 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";
++    if( zDb ){
++      sqliteSetString(&z, zDb, ".", zTab, ".", zCol, 0);
++    }else if( zTab ){
++      sqliteSetString(&z, zTab, ".", zCol, 0);
++    }else{
++      z = sqliteStrDup(zCol);
++    }
++    sqliteErrorMsg(pParse, zErr, z);
++    sqliteFree(z);
++  }
++
++  /* Clean up and return
++  */
++  sqliteFree(zDb);
++  sqliteFree(zTab);
++  sqliteFree(zCol);
++  sqliteExprDelete(pExpr->pLeft);
++  pExpr->pLeft = 0;
++  sqliteExprDelete(pExpr->pRight);
++  pExpr->pRight = 0;
++  pExpr->op = TK_COLUMN;
++  sqliteAuthRead(pParse, pExpr, pSrcList);
++  return cnt!=1;
++}
++
++/*
++** This routine walks an expression tree and resolves references to
++** table columns.  Nodes of the form ID.ID or ID resolve into an
++** index to the table in the table list and a column offset.  The 
++** Expr.opcode for such nodes is changed to TK_COLUMN.  The Expr.iTable
++** value is changed to the index of the referenced table in pTabList
++** plus the "base" value.  The base value will ultimately become the
++** VDBE cursor number for a cursor that is pointing into the referenced
++** table.  The Expr.iColumn value is changed to the index of the column 
++** of the referenced table.  The Expr.iColumn value for the special
++** ROWID column is -1.  Any INTEGER PRIMARY KEY column is tried as an
++** alias for ROWID.
++**
++** We also check for instances of the IN operator.  IN comes in two
++** forms:
++**
++**           expr IN (exprlist)
++** and
++**           expr IN (SELECT ...)
++**
++** The first form is handled by creating a set holding the list
++** of allowed values.  The second form causes the SELECT to generate 
++** a temporary table.
++**
++** This routine also looks for scalar SELECTs that are part of an expression.
++** If it finds any, it generates code to write the value of that select
++** into a memory cell.
++**
++** Unknown columns or tables provoke an error.  The function returns
++** the number of errors seen and leaves an error message on pParse->zErrMsg.
++*/
++int sqliteExprResolveIds(
++  Parse *pParse,     /* The parser context */
++  SrcList *pSrcList, /* List of tables used to resolve column names */
++  ExprList *pEList,  /* List of expressions used to resolve "AS" */
++  Expr *pExpr        /* The expression to be analyzed. */
++){
++  int i;
++
++  if( pExpr==0 || pSrcList==0 ) return 0;
++  for(i=0; i<pSrcList->nSrc; i++){
++    assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab );
++  }
++  switch( pExpr->op ){
++    /* Double-quoted strings (ex: "abc") are used as identifiers if
++    ** possible.  Otherwise they remain as strings.  Single-quoted
++    ** strings (ex: 'abc') are always string literals.
++    */
++    case TK_STRING: {
++      if( pExpr->token.z[0]=='\'' ) break;
++      /* Fall thru into the TK_ID case if this is a double-quoted string */
++    }
++    /* A lone identifier is the name of a columnd.
++    */
++    case TK_ID: {
++      if( lookupName(pParse, 0, 0, &pExpr->token, pSrcList, pEList, pExpr) ){
++        return 1;
++      }
++      break; 
++    }
++  
++    /* A table name and column name:     ID.ID
++    ** Or a database, table and column:  ID.ID.ID
++    */
++    case TK_DOT: {
++      Token *pColumn;
++      Token *pTable;
++      Token *pDb;
++      Expr *pRight;
++
++      pRight = pExpr->pRight;
++      if( pRight->op==TK_ID ){
++        pDb = 0;
++        pTable = &pExpr->pLeft->token;
++        pColumn = &pRight->token;
++      }else{
++        assert( pRight->op==TK_DOT );
++        pDb = &pExpr->pLeft->token;
++        pTable = &pRight->pLeft->token;
++        pColumn = &pRight->pRight->token;
++      }
++      if( lookupName(pParse, pDb, pTable, pColumn, pSrcList, 0, pExpr) ){
++        return 1;
++      }
++      break;
++    }
++
++    case TK_IN: {
++      Vdbe *v = sqliteGetVdbe(pParse);
++      if( v==0 ) return 1;
++      if( sqliteExprResolveIds(pParse, pSrcList, pEList, pExpr->pLeft) ){
++        return 1;
++      }
++      if( pExpr->pSelect ){
++        /* Case 1:     expr IN (SELECT ...)
++        **
++        ** Generate code to write the results of the select into a temporary
++        ** table.  The cursor number of the temporary table has already
++        ** been put in iTable by sqliteExprResolveInSelect().
++        */
++        pExpr->iTable = pParse->nTab++;
++        sqliteVdbeAddOp(v, OP_OpenTemp, pExpr->iTable, 1);
++        sqliteSelect(pParse, pExpr->pSelect, SRT_Set, pExpr->iTable, 0,0,0);
++      }else if( pExpr->pList ){
++        /* Case 2:     expr IN (exprlist)
++        **
++        ** Create a set to put the exprlist values in.  The Set id is stored
++        ** in iTable.
++        */
++        int i, iSet;
++        for(i=0; i<pExpr->pList->nExpr; i++){
++          Expr *pE2 = pExpr->pList->a[i].pExpr;
++          if( !sqliteExprIsConstant(pE2) ){
++            sqliteErrorMsg(pParse,
++              "right-hand side of IN operator must be constant");
++            return 1;
++          }
++          if( sqliteExprCheck(pParse, pE2, 0, 0) ){
++            return 1;
++          }
++        }
++        iSet = pExpr->iTable = pParse->nSet++;
++        for(i=0; i<pExpr->pList->nExpr; i++){
++          Expr *pE2 = pExpr->pList->a[i].pExpr;
++          switch( pE2->op ){
++            case TK_FLOAT:
++            case TK_INTEGER:
++            case TK_STRING: {
++              int addr;
++              assert( pE2->token.z );
++              addr = sqliteVdbeOp3(v, OP_SetInsert, iSet, 0,
++                                  pE2->token.z, pE2->token.n);
++              sqliteVdbeDequoteP3(v, addr);
++              break;
++            }
++            default: {
++              sqliteExprCode(pParse, pE2);
++              sqliteVdbeAddOp(v, OP_SetInsert, iSet, 0);
++              break;
++            }
++          }
++        }
++      }
++      break;
++    }
++
++    case TK_SELECT: {
++      /* This has to be a scalar SELECT.  Generate code to put the
++      ** value of this select in a memory cell and record the number
++      ** of the memory cell in iColumn.
++      */
++      pExpr->iColumn = pParse->nMem++;
++      if( sqliteSelect(pParse, pExpr->pSelect, SRT_Mem, pExpr->iColumn,0,0,0) ){
++        return 1;
++      }
++      break;
++    }
++
++    /* For all else, just recursively walk the tree */
++    default: {
++      if( pExpr->pLeft
++      && sqliteExprResolveIds(pParse, pSrcList, pEList, pExpr->pLeft) ){
++        return 1;
++      }
++      if( pExpr->pRight 
++      && sqliteExprResolveIds(pParse, pSrcList, pEList, pExpr->pRight) ){
++        return 1;
++      }
++      if( pExpr->pList ){
++        int i;
++        ExprList *pList = pExpr->pList;
++        for(i=0; i<pList->nExpr; i++){
++          Expr *pArg = pList->a[i].pExpr;
++          if( sqliteExprResolveIds(pParse, pSrcList, pEList, pArg) ){
++            return 1;
++          }
++        }
++      }
++    }
++  }
++  return 0;
++}
++
++/*
++** pExpr is a node that defines a function of some kind.  It might
++** be a syntactic function like "count(x)" or it might be a function
++** that implements an operator, like "a LIKE b".  
++**
++** This routine makes *pzName point to the name of the function and 
++** *pnName hold the number of characters in the function name.
++*/
++static void getFunctionName(Expr *pExpr, const char **pzName, int *pnName){
++  switch( pExpr->op ){
++    case TK_FUNCTION: {
++      *pzName = pExpr->token.z;
++      *pnName = pExpr->token.n;
++      break;
++    }
++    case TK_LIKE: {
++      *pzName = "like";
++      *pnName = 4;
++      break;
++    }
++    case TK_GLOB: {
++      *pzName = "glob";
++      *pnName = 4;
++      break;
++    }
++    default: {
++      *pzName = "can't happen";
++      *pnName = 12;
++      break;
++    }
++  }
++}
++
++/*
++** Error check the functions in an expression.  Make sure all
++** function names are recognized and all functions have the correct
++** number of arguments.  Leave an error message in pParse->zErrMsg
++** if anything is amiss.  Return the number of errors.
++**
++** if pIsAgg is not null and this expression is an aggregate function
++** (like count(*) or max(value)) then write a 1 into *pIsAgg.
++*/
++int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
++  int nErr = 0;
++  if( pExpr==0 ) return 0;
++  switch( pExpr->op ){
++    case TK_GLOB:
++    case TK_LIKE:
++    case TK_FUNCTION: {
++      int n = pExpr->pList ? pExpr->pList->nExpr : 0;  /* Number of arguments */
++      int no_such_func = 0;       /* True if no such function exists */
++      int wrong_num_args = 0;     /* True if wrong number of arguments */
++      int is_agg = 0;             /* True if is an aggregate function */
++      int i;
++      int nId;                    /* Number of characters in function name */
++      const char *zId;            /* The function name. */
++      FuncDef *pDef;
++
++      getFunctionName(pExpr, &zId, &nId);
++      pDef = sqliteFindFunction(pParse->db, zId, nId, n, 0);
++      if( pDef==0 ){
++        pDef = sqliteFindFunction(pParse->db, zId, nId, -1, 0);
++        if( pDef==0 ){
++          no_such_func = 1;
++        }else{
++          wrong_num_args = 1;
++        }
++      }else{
++        is_agg = pDef->xFunc==0;
++      }
++      if( is_agg && !allowAgg ){
++        sqliteErrorMsg(pParse, "misuse of aggregate function %.*s()", nId, zId);
++        nErr++;
++        is_agg = 0;
++      }else if( no_such_func ){
++        sqliteErrorMsg(pParse, "no such function: %.*s", nId, zId);
++        nErr++;
++      }else if( wrong_num_args ){
++        sqliteErrorMsg(pParse,"wrong number of arguments to function %.*s()",
++             nId, zId);
++        nErr++;
++      }
++      if( is_agg ){
++        pExpr->op = TK_AGG_FUNCTION;
++        if( pIsAgg ) *pIsAgg = 1;
++      }
++      for(i=0; nErr==0 && i<n; i++){
++        nErr = sqliteExprCheck(pParse, pExpr->pList->a[i].pExpr,
++                               allowAgg && !is_agg, pIsAgg);
++      }
++      if( pDef==0 ){
++        /* Already reported an error */
++      }else if( pDef->dataType>=0 ){
++        if( pDef->dataType<n ){
++          pExpr->dataType = 
++             sqliteExprType(pExpr->pList->a[pDef->dataType].pExpr);
++        }else{
++          pExpr->dataType = SQLITE_SO_NUM;
++        }
++      }else if( pDef->dataType==SQLITE_ARGS ){
++        pDef->dataType = SQLITE_SO_TEXT;
++        for(i=0; i<n; i++){
++          if( sqliteExprType(pExpr->pList->a[i].pExpr)==SQLITE_SO_NUM ){
++            pExpr->dataType = SQLITE_SO_NUM;
++            break;
++          }
++        }
++      }else if( pDef->dataType==SQLITE_NUMERIC ){
++        pExpr->dataType = SQLITE_SO_NUM;
++      }else{
++        pExpr->dataType = SQLITE_SO_TEXT;
++      }
++    }
++    default: {
++      if( pExpr->pLeft ){
++        nErr = sqliteExprCheck(pParse, pExpr->pLeft, allowAgg, pIsAgg);
++      }
++      if( nErr==0 && pExpr->pRight ){
++        nErr = sqliteExprCheck(pParse, pExpr->pRight, allowAgg, pIsAgg);
++      }
++      if( nErr==0 && pExpr->pList ){
++        int n = pExpr->pList->nExpr;
++        int i;
++        for(i=0; nErr==0 && i<n; i++){
++          Expr *pE2 = pExpr->pList->a[i].pExpr;
++          nErr = sqliteExprCheck(pParse, pE2, allowAgg, pIsAgg);
++        }
++      }
++      break;
++    }
++  }
++  return nErr;
++}
++
++/*
++** Return either SQLITE_SO_NUM or SQLITE_SO_TEXT to indicate whether the
++** given expression should sort as numeric values or as text.
++**
++** The sqliteExprResolveIds() and sqliteExprCheck() routines must have
++** both been called on the expression before it is passed to this routine.
++*/
++int sqliteExprType(Expr *p){
++  if( p==0 ) return SQLITE_SO_NUM;
++  while( p ) switch( p->op ){
++    case TK_PLUS:
++    case TK_MINUS:
++    case TK_STAR:
++    case TK_SLASH:
++    case TK_AND:
++    case TK_OR:
++    case TK_ISNULL:
++    case TK_NOTNULL:
++    case TK_NOT:
++    case TK_UMINUS:
++    case TK_UPLUS:
++    case TK_BITAND:
++    case TK_BITOR:
++    case TK_BITNOT:
++    case TK_LSHIFT:
++    case TK_RSHIFT:
++    case TK_REM:
++    case TK_INTEGER:
++    case TK_FLOAT:
++    case TK_IN:
++    case TK_BETWEEN:
++    case TK_GLOB:
++    case TK_LIKE:
++      return SQLITE_SO_NUM;
++
++    case TK_STRING:
++    case TK_NULL:
++    case TK_CONCAT:
++    case TK_VARIABLE:
++      return SQLITE_SO_TEXT;
++
++    case TK_LT:
++    case TK_LE:
++    case TK_GT:
++    case TK_GE:
++    case TK_NE:
++    case TK_EQ:
++      if( sqliteExprType(p->pLeft)==SQLITE_SO_NUM ){
++        return SQLITE_SO_NUM;
++      }
++      p = p->pRight;
++      break;
++
++    case TK_AS:
++      p = p->pLeft;
++      break;
++
++    case TK_COLUMN:
++    case TK_FUNCTION:
++    case TK_AGG_FUNCTION:
++      return p->dataType;
++
++    case TK_SELECT:
++      assert( p->pSelect );
++      assert( p->pSelect->pEList );
++      assert( p->pSelect->pEList->nExpr>0 );
++      p = p->pSelect->pEList->a[0].pExpr;
++      break;
++
++    case TK_CASE: {
++      if( p->pRight && sqliteExprType(p->pRight)==SQLITE_SO_NUM ){
++        return SQLITE_SO_NUM;
++      }
++      if( p->pList ){
++        int i;
++        ExprList *pList = p->pList;
++        for(i=1; i<pList->nExpr; i+=2){
++          if( sqliteExprType(pList->a[i].pExpr)==SQLITE_SO_NUM ){
++            return SQLITE_SO_NUM;
++          }
++        }
++      }
++      return SQLITE_SO_TEXT;
++    }
++
++    default:
++      assert( p->op==TK_ABORT );  /* Can't Happen */
++      break;
++  }
++  return SQLITE_SO_NUM;
++}
++
++/*
++** Generate code into the current Vdbe to evaluate the given
++** expression and leave the result on the top of stack.
++*/
++void sqliteExprCode(Parse *pParse, Expr *pExpr){
++  Vdbe *v = pParse->pVdbe;
++  int op;
++  if( v==0 || pExpr==0 ) return;
++  switch( pExpr->op ){
++    case TK_PLUS:     op = OP_Add;      break;
++    case TK_MINUS:    op = OP_Subtract; break;
++    case TK_STAR:     op = OP_Multiply; break;
++    case TK_SLASH:    op = OP_Divide;   break;
++    case TK_AND:      op = OP_And;      break;
++    case TK_OR:       op = OP_Or;       break;
++    case TK_LT:       op = OP_Lt;       break;
++    case TK_LE:       op = OP_Le;       break;
++    case TK_GT:       op = OP_Gt;       break;
++    case TK_GE:       op = OP_Ge;       break;
++    case TK_NE:       op = OP_Ne;       break;
++    case TK_EQ:       op = OP_Eq;       break;
++    case TK_ISNULL:   op = OP_IsNull;   break;
++    case TK_NOTNULL:  op = OP_NotNull;  break;
++    case TK_NOT:      op = OP_Not;      break;
++    case TK_UMINUS:   op = OP_Negative; break;
++    case TK_BITAND:   op = OP_BitAnd;   break;
++    case TK_BITOR:    op = OP_BitOr;    break;
++    case TK_BITNOT:   op = OP_BitNot;   break;
++    case TK_LSHIFT:   op = OP_ShiftLeft;  break;
++    case TK_RSHIFT:   op = OP_ShiftRight; break;
++    case TK_REM:      op = OP_Remainder;  break;
++    default: break;
++  }
++  switch( pExpr->op ){
++    case TK_COLUMN: {
++      if( pParse->useAgg ){
++        sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg);
++      }else if( pExpr->iColumn>=0 ){
++        sqliteVdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn);
++      }else{
++        sqliteVdbeAddOp(v, OP_Recno, pExpr->iTable, 0);
++      }
++      break;
++    }
++    case TK_STRING:
++    case TK_FLOAT:
++    case TK_INTEGER: {
++      if( pExpr->op==TK_INTEGER && sqliteFitsIn32Bits(pExpr->token.z) ){
++        sqliteVdbeAddOp(v, OP_Integer, atoi(pExpr->token.z), 0);
++      }else{
++        sqliteVdbeAddOp(v, OP_String, 0, 0);
++      }
++      assert( pExpr->token.z );
++      sqliteVdbeChangeP3(v, -1, pExpr->token.z, pExpr->token.n);
++      sqliteVdbeDequoteP3(v, -1);
++      break;
++    }
++    case TK_NULL: {
++      sqliteVdbeAddOp(v, OP_String, 0, 0);
++      break;
++    }
++    case TK_VARIABLE: {
++      sqliteVdbeAddOp(v, OP_Variable, pExpr->iTable, 0);
++      break;
++    }
++    case TK_LT:
++    case TK_LE:
++    case TK_GT:
++    case TK_GE:
++    case TK_NE:
++    case TK_EQ: {
++      if( pParse->db->file_format>=4 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){
++        op += 6;  /* Convert numeric opcodes to text opcodes */
++      }
++      /* Fall through into the next case */
++    }
++    case TK_AND:
++    case TK_OR:
++    case TK_PLUS:
++    case TK_STAR:
++    case TK_MINUS:
++    case TK_REM:
++    case TK_BITAND:
++    case TK_BITOR:
++    case TK_SLASH: {
++      sqliteExprCode(pParse, pExpr->pLeft);
++      sqliteExprCode(pParse, pExpr->pRight);
++      sqliteVdbeAddOp(v, op, 0, 0);
++      break;
++    }
++    case TK_LSHIFT:
++    case TK_RSHIFT: {
++      sqliteExprCode(pParse, pExpr->pRight);
++      sqliteExprCode(pParse, pExpr->pLeft);
++      sqliteVdbeAddOp(v, op, 0, 0);
++      break;
++    }
++    case TK_CONCAT: {
++      sqliteExprCode(pParse, pExpr->pLeft);
++      sqliteExprCode(pParse, pExpr->pRight);
++      sqliteVdbeAddOp(v, OP_Concat, 2, 0);
++      break;
++    }
++    case TK_UMINUS: {
++      assert( pExpr->pLeft );
++      if( pExpr->pLeft->op==TK_FLOAT || pExpr->pLeft->op==TK_INTEGER ){
++        Token *p = &pExpr->pLeft->token;
++        char *z = sqliteMalloc( p->n + 2 );
++        sprintf(z, "-%.*s", p->n, p->z);
++        if( pExpr->pLeft->op==TK_INTEGER && sqliteFitsIn32Bits(z) ){
++          sqliteVdbeAddOp(v, OP_Integer, atoi(z), 0);
++        }else{
++          sqliteVdbeAddOp(v, OP_String, 0, 0);
++        }
++        sqliteVdbeChangeP3(v, -1, z, p->n+1);
++        sqliteFree(z);
++        break;
++      }
++      /* Fall through into TK_NOT */
++    }
++    case TK_BITNOT:
++    case TK_NOT: {
++      sqliteExprCode(pParse, pExpr->pLeft);
++      sqliteVdbeAddOp(v, op, 0, 0);
++      break;
++    }
++    case TK_ISNULL:
++    case TK_NOTNULL: {
++      int dest;
++      sqliteVdbeAddOp(v, OP_Integer, 1, 0);
++      sqliteExprCode(pParse, pExpr->pLeft);
++      dest = sqliteVdbeCurrentAddr(v) + 2;
++      sqliteVdbeAddOp(v, op, 1, dest);
++      sqliteVdbeAddOp(v, OP_AddImm, -1, 0);
++      break;
++    }
++    case TK_AGG_FUNCTION: {
++      sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg);
++      break;
++    }
++    case TK_GLOB:
++    case TK_LIKE:
++    case TK_FUNCTION: {
++      ExprList *pList = pExpr->pList;
++      int nExpr = pList ? pList->nExpr : 0;
++      FuncDef *pDef;
++      int nId;
++      const char *zId;
++      getFunctionName(pExpr, &zId, &nId);
++      pDef = sqliteFindFunction(pParse->db, zId, nId, nExpr, 0);
++      assert( pDef!=0 );
++      nExpr = sqliteExprCodeExprList(pParse, pList, pDef->includeTypes);
++      sqliteVdbeOp3(v, OP_Function, nExpr, 0, (char*)pDef, P3_POINTER);
++      break;
++    }
++    case TK_SELECT: {
++      sqliteVdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0);
++      break;
++    }
++    case TK_IN: {
++      int addr;
++      sqliteVdbeAddOp(v, OP_Integer, 1, 0);
++      sqliteExprCode(pParse, pExpr->pLeft);
++      addr = sqliteVdbeCurrentAddr(v);
++      sqliteVdbeAddOp(v, OP_NotNull, -1, addr+4);
++      sqliteVdbeAddOp(v, OP_Pop, 2, 0);
++      sqliteVdbeAddOp(v, OP_String, 0, 0);
++      sqliteVdbeAddOp(v, OP_Goto, 0, addr+6);
++      if( pExpr->pSelect ){
++        sqliteVdbeAddOp(v, OP_Found, pExpr->iTable, addr+6);
++      }else{
++        sqliteVdbeAddOp(v, OP_SetFound, pExpr->iTable, addr+6);
++      }
++      sqliteVdbeAddOp(v, OP_AddImm, -1, 0);
++      break;
++    }
++    case TK_BETWEEN: {
++      sqliteExprCode(pParse, pExpr->pLeft);
++      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
++      sqliteExprCode(pParse, pExpr->pList->a[0].pExpr);
++      sqliteVdbeAddOp(v, OP_Ge, 0, 0);
++      sqliteVdbeAddOp(v, OP_Pull, 1, 0);
++      sqliteExprCode(pParse, pExpr->pList->a[1].pExpr);
++      sqliteVdbeAddOp(v, OP_Le, 0, 0);
++      sqliteVdbeAddOp(v, OP_And, 0, 0);
++      break;
++    }
++    case TK_UPLUS:
++    case TK_AS: {
++      sqliteExprCode(pParse, pExpr->pLeft);
++      break;
++    }
++    case TK_CASE: {
++      int expr_end_label;
++      int jumpInst;
++      int addr;
++      int nExpr;
++      int i;
++
++      assert(pExpr->pList);
++      assert((pExpr->pList->nExpr % 2) == 0);
++      assert(pExpr->pList->nExpr > 0);
++      nExpr = pExpr->pList->nExpr;
++      expr_end_label = sqliteVdbeMakeLabel(v);
++      if( pExpr->pLeft ){
++        sqliteExprCode(pParse, pExpr->pLeft);
++      }
++      for(i=0; i<nExpr; i=i+2){
++        sqliteExprCode(pParse, pExpr->pList->a[i].pExpr);
++        if( pExpr->pLeft ){
++          sqliteVdbeAddOp(v, OP_Dup, 1, 1);
++          jumpInst = sqliteVdbeAddOp(v, OP_Ne, 1, 0);
++          sqliteVdbeAddOp(v, OP_Pop, 1, 0);
++        }else{
++          jumpInst = sqliteVdbeAddOp(v, OP_IfNot, 1, 0);
++        }
++        sqliteExprCode(pParse, pExpr->pList->a[i+1].pExpr);
++        sqliteVdbeAddOp(v, OP_Goto, 0, expr_end_label);
++        addr = sqliteVdbeCurrentAddr(v);
++        sqliteVdbeChangeP2(v, jumpInst, addr);
++      }
++      if( pExpr->pLeft ){
++        sqliteVdbeAddOp(v, OP_Pop, 1, 0);
++      }
++      if( pExpr->pRight ){
++        sqliteExprCode(pParse, pExpr->pRight);
++      }else{
++        sqliteVdbeAddOp(v, OP_String, 0, 0);
++      }
++      sqliteVdbeResolveLabel(v, expr_end_label);
++      break;
++    }
++    case TK_RAISE: {
++      if( !pParse->trigStack ){
++        sqliteErrorMsg(pParse,
++                       "RAISE() may only be used within a trigger-program");
++        pParse->nErr++;
++      return;
++      }
++      if( pExpr->iColumn == OE_Rollback ||
++        pExpr->iColumn == OE_Abort ||
++        pExpr->iColumn == OE_Fail ){
++        sqliteVdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn,
++                           pExpr->token.z, pExpr->token.n);
++        sqliteVdbeDequoteP3(v, -1);
++      } else {
++        assert( pExpr->iColumn == OE_Ignore );
++        sqliteVdbeOp3(v, OP_Goto, 0, pParse->trigStack->ignoreJump,
++                           "(IGNORE jump)", 0);
++      }
++    }
++    break;
++  }
++}
++
++/*
++** Generate code that pushes the value of every element of the given
++** expression list onto the stack.  If the includeTypes flag is true,
++** then also push a string that is the datatype of each element onto
++** the stack after the value.
++**
++** Return the number of elements pushed onto the stack.
++*/
++int sqliteExprCodeExprList(
++  Parse *pParse,     /* Parsing context */
++  ExprList *pList,   /* The expression list to be coded */
++  int includeTypes   /* TRUE to put datatypes on the stack too */
++){
++  struct ExprList_item *pItem;
++  int i, n;
++  Vdbe *v;
++  if( pList==0 ) return 0;
++  v = sqliteGetVdbe(pParse);
++  n = pList->nExpr;
++  for(pItem=pList->a, i=0; i<n; i++, pItem++){
++    sqliteExprCode(pParse, pItem->pExpr);
++    if( includeTypes ){
++      sqliteVdbeOp3(v, OP_String, 0, 0, 
++         sqliteExprType(pItem->pExpr)==SQLITE_SO_NUM ? "numeric" : "text",
++         P3_STATIC);
++    }
++  }
++  return includeTypes ? n*2 : n;
++}
++
++/*
++** Generate code for a boolean expression such that a jump is made
++** to the label "dest" if the expression is true but execution
++** 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.
++*/
++void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
++  Vdbe *v = pParse->pVdbe;
++  int op = 0;
++  if( v==0 || pExpr==0 ) return;
++  switch( pExpr->op ){
++    case TK_LT:       op = OP_Lt;       break;
++    case TK_LE:       op = OP_Le;       break;
++    case TK_GT:       op = OP_Gt;       break;
++    case TK_GE:       op = OP_Ge;       break;
++    case TK_NE:       op = OP_Ne;       break;
++    case TK_EQ:       op = OP_Eq;       break;
++    case TK_ISNULL:   op = OP_IsNull;   break;
++    case TK_NOTNULL:  op = OP_NotNull;  break;
++    default:  break;
++  }
++  switch( pExpr->op ){
++    case TK_AND: {
++      int d2 = sqliteVdbeMakeLabel(v);
++      sqliteExprIfFalse(pParse, pExpr->pLeft, d2, !jumpIfNull);
++      sqliteExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
++      sqliteVdbeResolveLabel(v, d2);
++      break;
++    }
++    case TK_OR: {
++      sqliteExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
++      sqliteExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
++      break;
++    }
++    case TK_NOT: {
++      sqliteExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
++      break;
++    }
++    case TK_LT:
++    case TK_LE:
++    case TK_GT:
++    case TK_GE:
++    case TK_NE:
++    case TK_EQ: {
++      sqliteExprCode(pParse, pExpr->pLeft);
++      sqliteExprCode(pParse, pExpr->pRight);
++      if( pParse->db->file_format>=4 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){
++        op += 6;  /* Convert numeric opcodes to text opcodes */
++      }
++      sqliteVdbeAddOp(v, op, jumpIfNull, dest);
++      break;
++    }
++    case TK_ISNULL:
++    case TK_NOTNULL: {
++      sqliteExprCode(pParse, pExpr->pLeft);
++      sqliteVdbeAddOp(v, op, 1, dest);
++      break;
++    }
++    case TK_IN: {
++      int addr;
++      sqliteExprCode(pParse, pExpr->pLeft);
++      addr = sqliteVdbeCurrentAddr(v);
++      sqliteVdbeAddOp(v, OP_NotNull, -1, addr+3);
++      sqliteVdbeAddOp(v, OP_Pop, 1, 0);
++      sqliteVdbeAddOp(v, OP_Goto, 0, jumpIfNull ? dest : addr+4);
++      if( pExpr->pSelect ){
++        sqliteVdbeAddOp(v, OP_Found, pExpr->iTable, dest);
++      }else{
++        sqliteVdbeAddOp(v, OP_SetFound, pExpr->iTable, dest);
++      }
++      break;
++    }
++    case TK_BETWEEN: {
++      int addr;
++      sqliteExprCode(pParse, pExpr->pLeft);
++      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
++      sqliteExprCode(pParse, pExpr->pList->a[0].pExpr);
++      addr = sqliteVdbeAddOp(v, OP_Lt, !jumpIfNull, 0);
++      sqliteExprCode(pParse, pExpr->pList->a[1].pExpr);
++      sqliteVdbeAddOp(v, OP_Le, jumpIfNull, dest);
++      sqliteVdbeAddOp(v, OP_Integer, 0, 0);
++      sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
++      sqliteVdbeAddOp(v, OP_Pop, 1, 0);
++      break;
++    }
++    default: {
++      sqliteExprCode(pParse, pExpr);
++      sqliteVdbeAddOp(v, OP_If, jumpIfNull, dest);
++      break;
++    }
++  }
++}
++
++/*
++** Generate code for a boolean expression such that a jump is made
++** to the label "dest" if the expression is false but execution
++** 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.
++*/
++void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
++  Vdbe *v = pParse->pVdbe;
++  int op = 0;
++  if( v==0 || pExpr==0 ) return;
++  switch( pExpr->op ){
++    case TK_LT:       op = OP_Ge;       break;
++    case TK_LE:       op = OP_Gt;       break;
++    case TK_GT:       op = OP_Le;       break;
++    case TK_GE:       op = OP_Lt;       break;
++    case TK_NE:       op = OP_Eq;       break;
++    case TK_EQ:       op = OP_Ne;       break;
++    case TK_ISNULL:   op = OP_NotNull;  break;
++    case TK_NOTNULL:  op = OP_IsNull;   break;
++    default:  break;
++  }
++  switch( pExpr->op ){
++    case TK_AND: {
++      sqliteExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
++      sqliteExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
++      break;
++    }
++    case TK_OR: {
++      int d2 = sqliteVdbeMakeLabel(v);
++      sqliteExprIfTrue(pParse, pExpr->pLeft, d2, !jumpIfNull);
++      sqliteExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
++      sqliteVdbeResolveLabel(v, d2);
++      break;
++    }
++    case TK_NOT: {
++      sqliteExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
++      break;
++    }
++    case TK_LT:
++    case TK_LE:
++    case TK_GT:
++    case TK_GE:
++    case TK_NE:
++    case TK_EQ: {
++      if( pParse->db->file_format>=4 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){
++        /* Convert numeric comparison opcodes into text comparison opcodes.
++        ** This step depends on the fact that the text comparision opcodes are
++        ** always 6 greater than their corresponding numeric comparison
++        ** opcodes.
++        */
++        assert( OP_Eq+6 == OP_StrEq );
++        op += 6;
++      }
++      sqliteExprCode(pParse, pExpr->pLeft);
++      sqliteExprCode(pParse, pExpr->pRight);
++      sqliteVdbeAddOp(v, op, jumpIfNull, dest);
++      break;
++    }
++    case TK_ISNULL:
++    case TK_NOTNULL: {
++      sqliteExprCode(pParse, pExpr->pLeft);
++      sqliteVdbeAddOp(v, op, 1, dest);
++      break;
++    }
++    case TK_IN: {
++      int addr;
++      sqliteExprCode(pParse, pExpr->pLeft);
++      addr = sqliteVdbeCurrentAddr(v);
++      sqliteVdbeAddOp(v, OP_NotNull, -1, addr+3);
++      sqliteVdbeAddOp(v, OP_Pop, 1, 0);
++      sqliteVdbeAddOp(v, OP_Goto, 0, jumpIfNull ? dest : addr+4);
++      if( pExpr->pSelect ){
++        sqliteVdbeAddOp(v, OP_NotFound, pExpr->iTable, dest);
++      }else{
++        sqliteVdbeAddOp(v, OP_SetNotFound, pExpr->iTable, dest);
++      }
++      break;
++    }
++    case TK_BETWEEN: {
++      int addr;
++      sqliteExprCode(pParse, pExpr->pLeft);
++      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
++      sqliteExprCode(pParse, pExpr->pList->a[0].pExpr);
++      addr = sqliteVdbeCurrentAddr(v);
++      sqliteVdbeAddOp(v, OP_Ge, !jumpIfNull, addr+3);
++      sqliteVdbeAddOp(v, OP_Pop, 1, 0);
++      sqliteVdbeAddOp(v, OP_Goto, 0, dest);
++      sqliteExprCode(pParse, pExpr->pList->a[1].pExpr);
++      sqliteVdbeAddOp(v, OP_Gt, jumpIfNull, dest);
++      break;
++    }
++    default: {
++      sqliteExprCode(pParse, pExpr);
++      sqliteVdbeAddOp(v, OP_IfNot, jumpIfNull, dest);
++      break;
++    }
++  }
++}
++
++/*
++** 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.
++*/
++int sqliteExprCompare(Expr *pA, Expr *pB){
++  int i;
++  if( pA==0 ){
++    return pB==0;
++  }else if( pB==0 ){
++    return 0;
++  }
++  if( pA->op!=pB->op ) return 0;
++  if( !sqliteExprCompare(pA->pLeft, pB->pLeft) ) return 0;
++  if( !sqliteExprCompare(pA->pRight, pB->pRight) ) return 0;
++  if( pA->pList ){
++    if( pB->pList==0 ) return 0;
++    if( pA->pList->nExpr!=pB->pList->nExpr ) return 0;
++    for(i=0; i<pA->pList->nExpr; i++){
++      if( !sqliteExprCompare(pA->pList->a[i].pExpr, pB->pList->a[i].pExpr) ){
++        return 0;
++      }
++    }
++  }else if( pB->pList ){
++    return 0;
++  }
++  if( pA->pSelect || pB->pSelect ) return 0;
++  if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0;
++  if( pA->token.z ){
++    if( pB->token.z==0 ) return 0;
++    if( pB->token.n!=pA->token.n ) return 0;
++    if( sqliteStrNICmp(pA->token.z, pB->token.z, pB->token.n)!=0 ) return 0;
++  }
++  return 1;
++}
++
++/*
++** Add a new element to the pParse->aAgg[] array and return its index.
++*/
++static int appendAggInfo(Parse *pParse){
++  if( (pParse->nAgg & 0x7)==0 ){
++    int amt = pParse->nAgg + 8;
++    AggExpr *aAgg = sqliteRealloc(pParse->aAgg, amt*sizeof(pParse->aAgg[0]));
++    if( aAgg==0 ){
++      return -1;
++    }
++    pParse->aAgg = aAgg;
++  }
++  memset(&pParse->aAgg[pParse->nAgg], 0, sizeof(pParse->aAgg[0]));
++  return pParse->nAgg++;
++}
++
++/*
++** Analyze the given expression looking for aggregate functions and
++** for variables that need to be added to the pParse->aAgg[] array.
++** Make additional entries to the pParse->aAgg[] array as necessary.
++**
++** This routine should only be called after the expression has been
++** analyzed by sqliteExprResolveIds() and sqliteExprCheck().
++**
++** If errors are seen, leave an error message in zErrMsg and return
++** the number of errors.
++*/
++int sqliteExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){
++  int i;
++  AggExpr *aAgg;
++  int nErr = 0;
++
++  if( pExpr==0 ) return 0;
++  switch( pExpr->op ){
++    case TK_COLUMN: {
++      aAgg = pParse->aAgg;
++      for(i=0; i<pParse->nAgg; i++){
++        if( aAgg[i].isAgg ) continue;
++        if( aAgg[i].pExpr->iTable==pExpr->iTable
++         && aAgg[i].pExpr->iColumn==pExpr->iColumn ){
++          break;
++        }
++      }
++      if( i>=pParse->nAgg ){
++        i = appendAggInfo(pParse);
++        if( i<0 ) return 1;
++        pParse->aAgg[i].isAgg = 0;
++        pParse->aAgg[i].pExpr = pExpr;
++      }
++      pExpr->iAgg = i;
++      break;
++    }
++    case TK_AGG_FUNCTION: {
++      aAgg = pParse->aAgg;
++      for(i=0; i<pParse->nAgg; i++){
++        if( !aAgg[i].isAgg ) continue;
++        if( sqliteExprCompare(aAgg[i].pExpr, pExpr) ){
++          break;
++        }
++      }
++      if( i>=pParse->nAgg ){
++        i = appendAggInfo(pParse);
++        if( i<0 ) return 1;
++        pParse->aAgg[i].isAgg = 1;
++        pParse->aAgg[i].pExpr = pExpr;
++        pParse->aAgg[i].pFunc = sqliteFindFunction(pParse->db,
++             pExpr->token.z, pExpr->token.n,
++             pExpr->pList ? pExpr->pList->nExpr : 0, 0);
++      }
++      pExpr->iAgg = i;
++      break;
++    }
++    default: {
++      if( pExpr->pLeft ){
++        nErr = sqliteExprAnalyzeAggregates(pParse, pExpr->pLeft);
++      }
++      if( nErr==0 && pExpr->pRight ){
++        nErr = sqliteExprAnalyzeAggregates(pParse, pExpr->pRight);
++      }
++      if( nErr==0 && pExpr->pList ){
++        int n = pExpr->pList->nExpr;
++        int i;
++        for(i=0; nErr==0 && i<n; i++){
++          nErr = sqliteExprAnalyzeAggregates(pParse, pExpr->pList->a[i].pExpr);
++        }
++      }
++      break;
++    }
++  }
++  return nErr;
++}
++
++/*
++** Locate a user function given a name and a number of arguments.
++** Return a pointer to the FuncDef structure that defines that
++** function, or return NULL if the function does not exist.
++**
++** If the createFlag argument is true, then a new (blank) FuncDef
++** structure is created and liked into the "db" structure if a
++** no matching function previously existed.  When createFlag is true
++** and the nArg parameter is -1, then only a function that accepts
++** any number of arguments will be returned.
++**
++** If createFlag is false and nArg is -1, then the first valid
++** function found is returned.  A function is valid if either xFunc
++** or xStep is non-zero.
++*/
++FuncDef *sqliteFindFunction(
++  sqlite *db,        /* An open database */
++  const char *zName, /* Name of the function.  Not null-terminated */
++  int nName,         /* Number of characters in the name */
++  int nArg,          /* Number of arguments.  -1 means any number */
++  int createFlag     /* Create new entry if true and does not otherwise exist */
++){
++  FuncDef *pFirst, *p, *pMaybe;
++  pFirst = p = (FuncDef*)sqliteHashFind(&db->aFunc, zName, nName);
++  if( p && !createFlag && nArg<0 ){
++    while( p && p->xFunc==0 && p->xStep==0 ){ p = p->pNext; }
++    return p;
++  }
++  pMaybe = 0;
++  while( p && p->nArg!=nArg ){
++    if( p->nArg<0 && !createFlag && (p->xFunc || p->xStep) ) pMaybe = p;
++    p = p->pNext;
++  }
++  if( p && !createFlag && p->xFunc==0 && p->xStep==0 ){
++    return 0;
++  }
++  if( p==0 && pMaybe ){
++    assert( createFlag==0 );
++    return pMaybe;
++  }
++  if( p==0 && createFlag && (p = sqliteMalloc(sizeof(*p)))!=0 ){
++    p->nArg = nArg;
++    p->pNext = pFirst;
++    p->dataType = pFirst ? pFirst->dataType : SQLITE_NUMERIC;
++    sqliteHashInsert(&db->aFunc, zName, nName, (void*)p);
++  }
++  return p;
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/func.c
+@@ -0,0 +1,658 @@
++/*
++** 2002 February 23
++**
++** 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 various SQL
++** functions of SQLite.  
++**
++** There is only one exported symbol in this file - the function
++** sqliteRegisterBuildinFunctions() found at the bottom of the file.
++** All other code has file scope.
++**
++** $Id$
++*/
++#include <ctype.h>
++#include <math.h>
++#include <stdlib.h>
++#include <assert.h>
++#include "sqliteInt.h"
++#include "os.h"
++
++/*
++** Implementation of the non-aggregate min() and max() functions
++*/
++static void minmaxFunc(sqlite_func *context, int argc, const char **argv){
++  const char *zBest; 
++  int i;
++  int (*xCompare)(const char*, const char*);
++  int mask;    /* 0 for min() or 0xffffffff for max() */
++
++  if( argc==0 ) return;
++  mask = (int)sqlite_user_data(context);
++  zBest = argv[0];
++  if( zBest==0 ) return;
++  if( argv[1][0]=='n' ){
++    xCompare = sqliteCompare;
++  }else{
++    xCompare = strcmp;
++  }
++  for(i=2; i<argc; i+=2){
++    if( argv[i]==0 ) return;
++    if( (xCompare(argv[i], zBest)^mask)<0 ){
++      zBest = argv[i];
++    }
++  }
++  sqlite_set_result_string(context, zBest, -1);
++}
++
++/*
++** Return the type of the argument.
++*/
++static void typeofFunc(sqlite_func *context, int argc, const char **argv){
++  assert( argc==2 );
++  sqlite_set_result_string(context, argv[1], -1);
++}
++
++/*
++** Implementation of the length() function
++*/
++static void lengthFunc(sqlite_func *context, int argc, const char **argv){
++  const char *z;
++  int len;
++
++  assert( argc==1 );
++  z = argv[0];
++  if( z==0 ) return;
++#ifdef SQLITE_UTF8
++  for(len=0; *z; z++){ if( (0xc0&*z)!=0x80 ) len++; }
++#else
++  len = strlen(z);
++#endif
++  sqlite_set_result_int(context, len);
++}
++
++/*
++** Implementation of the abs() function
++*/
++static void absFunc(sqlite_func *context, int argc, const char **argv){
++  const char *z;
++  assert( argc==1 );
++  z = argv[0];
++  if( z==0 ) return;
++  if( z[0]=='-' && isdigit(z[1]) ) z++;
++  sqlite_set_result_string(context, z, -1);
++}
++
++/*
++** Implementation of the substr() function
++*/
++static void substrFunc(sqlite_func *context, int argc, const char **argv){
++  const char *z;
++#ifdef SQLITE_UTF8
++  const char *z2;
++  int i;
++#endif
++  int p1, p2, len;
++  assert( argc==3 );
++  z = argv[0];
++  if( z==0 ) return;
++  p1 = atoi(argv[1]?argv[1]:0);
++  p2 = atoi(argv[2]?argv[2]:0);
++#ifdef SQLITE_UTF8
++  for(len=0, z2=z; *z2; z2++){ if( (0xc0&*z2)!=0x80 ) len++; }
++#else
++  len = strlen(z);
++#endif
++  if( p1<0 ){
++    p1 += len;
++    if( p1<0 ){
++      p2 += p1;
++      p1 = 0;
++    }
++  }else if( p1>0 ){
++    p1--;
++  }
++  if( p1+p2>len ){
++    p2 = len-p1;
++  }
++#ifdef SQLITE_UTF8
++  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++;
++  }
++  while( z[i] && (z[i]&0xc0)==0x80 ){ i++; p2++; }
++#endif
++  if( p2<0 ) p2 = 0;
++  sqlite_set_result_string(context, &z[p1], p2);
++}
++
++/*
++** Implementation of the round() function
++*/
++static void roundFunc(sqlite_func *context, int argc, const char **argv){
++  int n;
++  double r;
++  char zBuf[100];
++  assert( argc==1 || argc==2 );
++  if( argv[0]==0 || (argc==2 && argv[1]==0) ) return;
++  n = argc==2 ? atoi(argv[1]) : 0;
++  if( n>30 ) n = 30;
++  if( n<0 ) n = 0;
++  r = sqliteAtoF(argv[0], 0);
++  sprintf(zBuf,"%.*f",n,r);
++  sqlite_set_result_string(context, zBuf, -1);
++}
++
++/*
++** Implementation of the upper() and lower() SQL functions.
++*/
++static void upperFunc(sqlite_func *context, int argc, const char **argv){
++  unsigned char *z;
++  int i;
++  if( argc<1 || argv[0]==0 ) return;
++  z = (unsigned char*)sqlite_set_result_string(context, argv[0], -1);
++  if( z==0 ) return;
++  for(i=0; z[i]; i++){
++    if( islower(z[i]) ) z[i] = toupper(z[i]);
++  }
++}
++static void lowerFunc(sqlite_func *context, int argc, const char **argv){
++  unsigned char *z;
++  int i;
++  if( argc<1 || argv[0]==0 ) return;
++  z = (unsigned char*)sqlite_set_result_string(context, argv[0], -1);
++  if( z==0 ) return;
++  for(i=0; z[i]; i++){
++    if( isupper(z[i]) ) z[i] = tolower(z[i]);
++  }
++}
++
++/*
++** Implementation of the IFNULL(), NVL(), and COALESCE() functions.  
++** All three do the same thing.  They return the first non-NULL
++** argument.
++*/
++static void ifnullFunc(sqlite_func *context, int argc, const char **argv){
++  int i;
++  for(i=0; i<argc; i++){
++    if( argv[i] ){
++      sqlite_set_result_string(context, argv[i], -1);
++      break;
++    }
++  }
++}
++
++/*
++** Implementation of random().  Return a random integer.  
++*/
++static void randomFunc(sqlite_func *context, int argc, const char **argv){
++  int r;
++  sqliteRandomness(sizeof(r), &r);
++  sqlite_set_result_int(context, r);
++}
++
++/*
++** Implementation of the last_insert_rowid() SQL function.  The return
++** value is the same as the sqlite_last_insert_rowid() API function.
++*/
++static void last_insert_rowid(sqlite_func *context, int arg, const char **argv){
++  sqlite *db = sqlite_user_data(context);
++  sqlite_set_result_int(context, sqlite_last_insert_rowid(db));
++}
++
++/*
++** Implementation of the change_count() SQL function.  The return
++** value is the same as the sqlite_changes() API function.
++*/
++static void change_count(sqlite_func *context, int arg, const char **argv){
++  sqlite *db = sqlite_user_data(context);
++  sqlite_set_result_int(context, sqlite_changes(db));
++}
++
++/*
++** Implementation of the last_statement_change_count() SQL function.  The
++** return value is the same as the sqlite_last_statement_changes() API function.
++*/
++static void last_statement_change_count(sqlite_func *context, int arg,
++                                        const char **argv){
++  sqlite *db = sqlite_user_data(context);
++  sqlite_set_result_int(context, sqlite_last_statement_changes(db));
++}
++
++/*
++** Implementation of the like() SQL function.  This function implements
++** the build-in LIKE operator.  The first argument to the function is the
++** string and the second argument is the pattern.  So, the SQL statements:
++**
++**       A LIKE B
++**
++** is implemented as like(A,B).
++*/
++static void likeFunc(sqlite_func *context, int arg, const char **argv){
++  if( argv[0]==0 || argv[1]==0 ) return;
++  sqlite_set_result_int(context, 
++    sqliteLikeCompare((const unsigned char*)argv[0],
++                      (const unsigned char*)argv[1]));
++}
++
++/*
++** Implementation of the glob() SQL function.  This function implements
++** the build-in GLOB operator.  The first argument to the function is the
++** string and the second argument is the pattern.  So, the SQL statements:
++**
++**       A GLOB B
++**
++** is implemented as glob(A,B).
++*/
++static void globFunc(sqlite_func *context, int arg, const char **argv){
++  if( argv[0]==0 || argv[1]==0 ) return;
++  sqlite_set_result_int(context,
++    sqliteGlobCompare((const unsigned char*)argv[0],
++                      (const unsigned char*)argv[1]));
++}
++
++/*
++** Implementation of the NULLIF(x,y) function.  The result is the first
++** argument if the arguments are different.  The result is NULL if the
++** arguments are equal to each other.
++*/
++static void nullifFunc(sqlite_func *context, int argc, const char **argv){
++  if( argv[0]!=0 && sqliteCompare(argv[0],argv[1])!=0 ){
++    sqlite_set_result_string(context, argv[0], -1);
++  }
++}
++
++/*
++** Implementation of the VERSION(*) function.  The result is the version
++** of the SQLite library that is running.
++*/
++static void versionFunc(sqlite_func *context, int argc, const char **argv){
++  sqlite_set_result_string(context, sqlite_version, -1);
++}
++
++/*
++** EXPERIMENTAL - This is not an official function.  The interface may
++** change.  This function may disappear.  Do not write code that depends
++** on this function.
++**
++** Implementation of the QUOTE() function.  This function takes a single
++** argument.  If the argument is numeric, the return value is the same as
++** the argument.  If the argument is NULL, the return value is the string
++** "NULL".  Otherwise, the argument is enclosed in single quotes with
++** single-quote escapes.
++*/
++static void quoteFunc(sqlite_func *context, int argc, const char **argv){
++  if( argc<1 ) return;
++  if( argv[0]==0 ){
++    sqlite_set_result_string(context, "NULL", 4);
++  }else if( sqliteIsNumber(argv[0]) ){
++    sqlite_set_result_string(context, argv[0], -1);
++  }else{
++    int i,j,n;
++    char *z;
++    for(i=n=0; argv[0][i]; i++){ if( argv[0][i]=='\'' ) n++; }
++    z = sqliteMalloc( i+n+3 );
++    if( z==0 ) return;
++    z[0] = '\'';
++    for(i=0, j=1; argv[0][i]; i++){
++      z[j++] = argv[0][i];
++      if( argv[0][i]=='\'' ){
++        z[j++] = '\'';
++      }
++    }
++    z[j++] = '\'';
++    z[j] = 0;
++    sqlite_set_result_string(context, z, j);
++    sqliteFree(z);
++  }
++}
++
++#ifdef SQLITE_SOUNDEX
++/*
++** Compute the soundex encoding of a word.
++*/
++static void soundexFunc(sqlite_func *context, int argc, const char **argv){
++  char zResult[8];
++  const char *zIn;
++  int i, j;
++  static const unsigned char iCode[] = {
++    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, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0,
++    1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
++    0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0,
++    1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
++  };
++  assert( argc==1 );
++  zIn = argv[0];
++  for(i=0; zIn[i] && !isalpha(zIn[i]); i++){}
++  if( zIn[i] ){
++    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';
++      }
++    }
++    while( j<4 ){
++      zResult[j++] = '0';
++    }
++    zResult[j] = 0;
++    sqlite_set_result_string(context, zResult, 4);
++  }else{
++    sqlite_set_result_string(context, "?000", 4);
++  }
++}
++#endif
++
++#ifdef SQLITE_TEST
++/*
++** This function generates a string of random characters.  Used for
++** generating test data.
++*/
++static void randStr(sqlite_func *context, int argc, const char **argv){
++  static const unsigned char zSrc[] = 
++     "abcdefghijklmnopqrstuvwxyz"
++     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
++     "0123456789"
++     ".-!,:*^+=_|?/<> ";
++  int iMin, iMax, n, r, i;
++  unsigned char zBuf[1000];
++  if( argc>=1 ){
++    iMin = atoi(argv[0]);
++    if( iMin<0 ) iMin = 0;
++    if( iMin>=sizeof(zBuf) ) iMin = sizeof(zBuf)-1;
++  }else{
++    iMin = 1;
++  }
++  if( argc>=2 ){
++    iMax = atoi(argv[1]);
++    if( iMax<iMin ) iMax = iMin;
++    if( iMax>=sizeof(zBuf) ) iMax = sizeof(zBuf)-1;
++  }else{
++    iMax = 50;
++  }
++  n = iMin;
++  if( iMax>iMin ){
++    sqliteRandomness(sizeof(r), &r);
++    r &= 0x7fffffff;
++    n += r%(iMax + 1 - iMin);
++  }
++  assert( n<sizeof(zBuf) );
++  sqliteRandomness(n, zBuf);
++  for(i=0; i<n; i++){
++    zBuf[i] = zSrc[zBuf[i]%(sizeof(zSrc)-1)];
++  }
++  zBuf[n] = 0;
++  sqlite_set_result_string(context, zBuf, n);
++}
++#endif
++
++/*
++** An instance of the following structure holds the context of a
++** sum() or avg() aggregate computation.
++*/
++typedef struct SumCtx SumCtx;
++struct SumCtx {
++  double sum;     /* Sum of terms */
++  int cnt;        /* Number of elements summed */
++};
++
++/*
++** Routines used to compute the sum or average.
++*/
++static void sumStep(sqlite_func *context, int argc, const char **argv){
++  SumCtx *p;
++  if( argc<1 ) return;
++  p = sqlite_aggregate_context(context, sizeof(*p));
++  if( p && argv[0] ){
++    p->sum += sqliteAtoF(argv[0], 0);
++    p->cnt++;
++  }
++}
++static void sumFinalize(sqlite_func *context){
++  SumCtx *p;
++  p = sqlite_aggregate_context(context, sizeof(*p));
++  sqlite_set_result_double(context, p ? p->sum : 0.0);
++}
++static void avgFinalize(sqlite_func *context){
++  SumCtx *p;
++  p = sqlite_aggregate_context(context, sizeof(*p));
++  if( p && p->cnt>0 ){
++    sqlite_set_result_double(context, p->sum/(double)p->cnt);
++  }
++}
++
++/*
++** An instance of the following structure holds the context of a
++** variance or standard deviation computation.
++*/
++typedef struct StdDevCtx StdDevCtx;
++struct StdDevCtx {
++  double sum;     /* Sum of terms */
++  double sum2;    /* Sum of the squares of terms */
++  int cnt;        /* Number of terms counted */
++};
++
++#if 0   /* Omit because math library is required */
++/*
++** Routines used to compute the standard deviation as an aggregate.
++*/
++static void stdDevStep(sqlite_func *context, int argc, const char **argv){
++  StdDevCtx *p;
++  double x;
++  if( argc<1 ) return;
++  p = sqlite_aggregate_context(context, sizeof(*p));
++  if( p && argv[0] ){
++    x = sqliteAtoF(argv[0], 0);
++    p->sum += x;
++    p->sum2 += x*x;
++    p->cnt++;
++  }
++}
++static void stdDevFinalize(sqlite_func *context){
++  double rN = sqlite_aggregate_count(context);
++  StdDevCtx *p = sqlite_aggregate_context(context, sizeof(*p));
++  if( p && p->cnt>1 ){
++    double rCnt = cnt;
++    sqlite_set_result_double(context, 
++       sqrt((p->sum2 - p->sum*p->sum/rCnt)/(rCnt-1.0)));
++  }
++}
++#endif
++
++/*
++** The following structure keeps track of state information for the
++** count() aggregate function.
++*/
++typedef struct CountCtx CountCtx;
++struct CountCtx {
++  int n;
++};
++
++/*
++** Routines to implement the count() aggregate function.
++*/
++static void countStep(sqlite_func *context, int argc, const char **argv){
++  CountCtx *p;
++  p = sqlite_aggregate_context(context, sizeof(*p));
++  if( (argc==0 || argv[0]) && p ){
++    p->n++;
++  }
++}   
++static void countFinalize(sqlite_func *context){
++  CountCtx *p;
++  p = sqlite_aggregate_context(context, sizeof(*p));
++  sqlite_set_result_int(context, p ? p->n : 0);
++}
++
++/*
++** This function tracks state information for the min() and max()
++** aggregate functions.
++*/
++typedef struct MinMaxCtx MinMaxCtx;
++struct MinMaxCtx {
++  char *z;         /* The best so far */
++  char zBuf[28];   /* Space that can be used for storage */
++};
++
++/*
++** Routines to implement min() and max() aggregate functions.
++*/
++static void minmaxStep(sqlite_func *context, int argc, const char **argv){
++  MinMaxCtx *p;
++  int (*xCompare)(const char*, const char*);
++  int mask;    /* 0 for min() or 0xffffffff for max() */
++
++  assert( argc==2 );
++  if( argv[0]==0 ) return;  /* Ignore NULL values */
++  if( argv[1][0]=='n' ){
++    xCompare = sqliteCompare;
++  }else{
++    xCompare = strcmp;
++  }
++  mask = (int)sqlite_user_data(context);
++  assert( mask==0 || mask==-1 );
++  p = sqlite_aggregate_context(context, sizeof(*p));
++  if( p==0 || argc<1 ) return;
++  if( p->z==0 || (xCompare(argv[0],p->z)^mask)<0 ){
++    int len;
++    if( p->zBuf[0] ){
++      sqliteFree(p->z);
++    }
++    len = strlen(argv[0]);
++    if( len < sizeof(p->zBuf)-1 ){
++      p->z = &p->zBuf[1];
++      p->zBuf[0] = 0;
++    }else{
++      p->z = sqliteMalloc( len+1 );
++      p->zBuf[0] = 1;
++      if( p->z==0 ) return;
++    }
++    strcpy(p->z, argv[0]);
++  }
++}
++static void minMaxFinalize(sqlite_func *context){
++  MinMaxCtx *p;
++  p = sqlite_aggregate_context(context, sizeof(*p));
++  if( p && p->z && p->zBuf[0]<2 ){
++    sqlite_set_result_string(context, p->z, strlen(p->z));
++  }
++  if( p && p->zBuf[0] ){
++    sqliteFree(p->z);
++  }
++}
++
++/*
++** This function registered all of the above C functions as SQL
++** functions.  This should be the only routine in this file with
++** external linkage.
++*/
++void sqliteRegisterBuiltinFunctions(sqlite *db){
++  static struct {
++     char *zName;
++     signed char nArg;
++     signed char dataType;
++     u8 argType;               /* 0: none.  1: db  2: (-1) */
++     void (*xFunc)(sqlite_func*,int,const char**);
++  } aFuncs[] = {
++    { "min",       -1, SQLITE_ARGS,    0, minmaxFunc },
++    { "min",        0, 0,              0, 0          },
++    { "max",       -1, SQLITE_ARGS,    2, minmaxFunc },
++    { "max",        0, 0,              2, 0          },
++    { "typeof",     1, SQLITE_TEXT,    0, typeofFunc },
++    { "length",     1, SQLITE_NUMERIC, 0, lengthFunc },
++    { "substr",     3, SQLITE_TEXT,    0, substrFunc },
++    { "abs",        1, SQLITE_NUMERIC, 0, absFunc    },
++    { "round",      1, SQLITE_NUMERIC, 0, roundFunc  },
++    { "round",      2, SQLITE_NUMERIC, 0, roundFunc  },
++    { "upper",      1, SQLITE_TEXT,    0, upperFunc  },
++    { "lower",      1, SQLITE_TEXT,    0, lowerFunc  },
++    { "coalesce",  -1, SQLITE_ARGS,    0, ifnullFunc },
++    { "coalesce",   0, 0,              0, 0          },
++    { "coalesce",   1, 0,              0, 0          },
++    { "ifnull",     2, SQLITE_ARGS,    0, ifnullFunc },
++    { "random",    -1, SQLITE_NUMERIC, 0, randomFunc },
++    { "like",       2, SQLITE_NUMERIC, 0, likeFunc   },
++    { "glob",       2, SQLITE_NUMERIC, 0, globFunc   },
++    { "nullif",     2, SQLITE_ARGS,    0, nullifFunc },
++    { "sqlite_version",0,SQLITE_TEXT,  0, versionFunc},
++    { "quote",      1, SQLITE_ARGS,    0, quoteFunc  },
++    { "last_insert_rowid", 0, SQLITE_NUMERIC, 1, last_insert_rowid },
++    { "change_count",      0, SQLITE_NUMERIC, 1, change_count      },
++    { "last_statement_change_count",
++                           0, SQLITE_NUMERIC, 1, last_statement_change_count },
++#ifdef SQLITE_SOUNDEX
++    { "soundex",    1, SQLITE_TEXT,    0, soundexFunc},
++#endif
++#ifdef SQLITE_TEST
++    { "randstr",    2, SQLITE_TEXT,    0, randStr    },
++#endif
++  };
++  static struct {
++    char *zName;
++    signed char nArg;
++    signed char dataType;
++    u8 argType;
++    void (*xStep)(sqlite_func*,int,const char**);
++    void (*xFinalize)(sqlite_func*);
++  } aAggs[] = {
++    { "min",    1, 0,              0, minmaxStep,   minMaxFinalize },
++    { "max",    1, 0,              2, minmaxStep,   minMaxFinalize },
++    { "sum",    1, SQLITE_NUMERIC, 0, sumStep,      sumFinalize    },
++    { "avg",    1, SQLITE_NUMERIC, 0, sumStep,      avgFinalize    },
++    { "count",  0, SQLITE_NUMERIC, 0, countStep,    countFinalize  },
++    { "count",  1, SQLITE_NUMERIC, 0, countStep,    countFinalize  },
++#if 0
++    { "stddev", 1, SQLITE_NUMERIC, 0, stdDevStep,   stdDevFinalize },
++#endif
++  };
++  static const char *azTypeFuncs[] = { "min", "max", "typeof" };
++  int i;
++
++  for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
++    void *pArg;
++    switch( aFuncs[i].argType ){
++      case 0:  pArg = 0;           break;
++      case 1:  pArg = db;          break;
++      case 2:  pArg = (void*)(-1); break;
++    }
++    sqlite_create_function(db, aFuncs[i].zName,
++           aFuncs[i].nArg, aFuncs[i].xFunc, pArg);
++    if( aFuncs[i].xFunc ){
++      sqlite_function_type(db, aFuncs[i].zName, aFuncs[i].dataType);
++    }
++  }
++  for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
++    void *pArg;
++    switch( aAggs[i].argType ){
++      case 0:  pArg = 0;           break;
++      case 1:  pArg = db;          break;
++      case 2:  pArg = (void*)(-1); break;
++    }
++    sqlite_create_aggregate(db, aAggs[i].zName,
++           aAggs[i].nArg, aAggs[i].xStep, aAggs[i].xFinalize, pArg);
++    sqlite_function_type(db, aAggs[i].zName, aAggs[i].dataType);
++  }
++  for(i=0; i<sizeof(azTypeFuncs)/sizeof(azTypeFuncs[0]); i++){
++    int n = strlen(azTypeFuncs[i]);
++    FuncDef *p = sqliteHashFind(&db->aFunc, azTypeFuncs[i], n);
++    while( p ){
++      p->includeTypes = 1;
++      p = p->pNext;
++    }
++  }
++  sqliteRegisterDateTimeFunctions(db);
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/hash.c
+@@ -0,0 +1,356 @@
++/*
++** 2001 September 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 is the implementation of generic hash-tables
++** used in SQLite.
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++#include <assert.h>
++
++/* Turn bulk memory into a hash table object by initializing the
++** fields of the Hash structure.
++**
++** "new" is a pointer to the hash table that is to be initialized.
++** keyClass is one of the constants SQLITE_HASH_INT, SQLITE_HASH_POINTER,
++** SQLITE_HASH_BINARY, or SQLITE_HASH_STRING.  The value of keyClass 
++** determines what kind of key the hash table will use.  "copyKey" is
++** true if the hash table should make its own private copy of keys and
++** false if it should just use the supplied pointer.  CopyKey only makes
++** sense for SQLITE_HASH_STRING and SQLITE_HASH_BINARY and is ignored
++** for other key classes.
++*/
++void sqliteHashInit(Hash *new, int keyClass, int copyKey){
++  assert( new!=0 );
++  assert( keyClass>=SQLITE_HASH_INT && keyClass<=SQLITE_HASH_BINARY );
++  new->keyClass = keyClass;
++  new->copyKey = copyKey &&
++                (keyClass==SQLITE_HASH_STRING || keyClass==SQLITE_HASH_BINARY);
++  new->first = 0;
++  new->count = 0;
++  new->htsize = 0;
++  new->ht = 0;
++}
++
++/* Remove all entries from a hash table.  Reclaim all memory.
++** Call this routine to delete a hash table or to reset a hash table
++** to the empty state.
++*/
++void sqliteHashClear(Hash *pH){
++  HashElem *elem;         /* For looping over all elements of the table */
++
++  assert( pH!=0 );
++  elem = pH->first;
++  pH->first = 0;
++  if( pH->ht ) sqliteFree(pH->ht);
++  pH->ht = 0;
++  pH->htsize = 0;
++  while( elem ){
++    HashElem *next_elem = elem->next;
++    if( pH->copyKey && elem->pKey ){
++      sqliteFree(elem->pKey);
++    }
++    sqliteFree(elem);
++    elem = next_elem;
++  }
++  pH->count = 0;
++}
++
++/*
++** Hash and comparison functions when the mode is SQLITE_HASH_INT
++*/
++static int intHash(const void *pKey, int nKey){
++  return nKey ^ (nKey<<8) ^ (nKey>>8);
++}
++static int intCompare(const void *pKey1, int n1, const void *pKey2, int n2){
++  return n2 - n1;
++}
++
++#if 0 /* NOT USED */
++/*
++** Hash and comparison functions when the mode is SQLITE_HASH_POINTER
++*/
++static int ptrHash(const void *pKey, int nKey){
++  uptr x = Addr(pKey);
++  return x ^ (x<<8) ^ (x>>8);
++}
++static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){
++  if( pKey1==pKey2 ) return 0;
++  if( pKey1<pKey2 ) return -1;
++  return 1;
++}
++#endif
++
++/*
++** Hash and comparison functions when the mode is SQLITE_HASH_STRING
++*/
++static int strHash(const void *pKey, int nKey){
++  return sqliteHashNoCase((const char*)pKey, nKey); 
++}
++static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){
++  if( n1!=n2 ) return n2-n1;
++  return sqliteStrNICmp((const char*)pKey1,(const char*)pKey2,n1);
++}
++
++/*
++** Hash and comparison functions when the mode is SQLITE_HASH_BINARY
++*/
++static int binHash(const void *pKey, int nKey){
++  int h = 0;
++  const char *z = (const char *)pKey;
++  while( nKey-- > 0 ){
++    h = (h<<3) ^ h ^ *(z++);
++  }
++  return h & 0x7fffffff;
++}
++static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){
++  if( n1!=n2 ) return n2-n1;
++  return memcmp(pKey1,pKey2,n1);
++}
++
++/*
++** Return a pointer to the appropriate hash function given the key class.
++**
++** The C syntax in this function definition may be unfamilar to some 
++** programmers, so we provide the following additional explanation:
++**
++** The name of the function is "hashFunction".  The function takes a
++** single parameter "keyClass".  The return value of hashFunction()
++** is a pointer to another function.  Specifically, the return value
++** of hashFunction() is a pointer to a function that takes two parameters
++** with types "const void*" and "int" and returns an "int".
++*/
++static int (*hashFunction(int keyClass))(const void*,int){
++  switch( keyClass ){
++    case SQLITE_HASH_INT:     return &intHash;
++    /* case SQLITE_HASH_POINTER: return &ptrHash; // NOT USED */
++    case SQLITE_HASH_STRING:  return &strHash;
++    case SQLITE_HASH_BINARY:  return &binHash;;
++    default: break;
++  }
++  return 0;
++}
++
++/*
++** Return a pointer to the appropriate hash function given the key class.
++**
++** For help in interpreted the obscure C code in the function definition,
++** see the header comment on the previous function.
++*/
++static int (*compareFunction(int keyClass))(const void*,int,const void*,int){
++  switch( keyClass ){
++    case SQLITE_HASH_INT:     return &intCompare;
++    /* case SQLITE_HASH_POINTER: return &ptrCompare; // NOT USED */
++    case SQLITE_HASH_STRING:  return &strCompare;
++    case SQLITE_HASH_BINARY:  return &binCompare;
++    default: break;
++  }
++  return 0;
++}
++
++
++/* 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.
++*/
++static void rehash(Hash *pH, int new_size){
++  struct _ht *new_ht;            /* The new hash table */
++  HashElem *elem, *next_elem;    /* For looping over existing elements */
++  HashElem *x;                   /* Element being copied to new hash table */
++  int (*xHash)(const void*,int); /* The hash function */
++
++  assert( (new_size & (new_size-1))==0 );
++  new_ht = (struct _ht *)sqliteMalloc( new_size*sizeof(struct _ht) );
++  if( new_ht==0 ) return;
++  if( pH->ht ) sqliteFree(pH->ht);
++  pH->ht = new_ht;
++  pH->htsize = new_size;
++  xHash = hashFunction(pH->keyClass);
++  for(elem=pH->first, pH->first=0; elem; elem = next_elem){
++    int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1);
++    next_elem = elem->next;
++    x = new_ht[h].chain;
++    if( x ){
++      elem->next = x;
++      elem->prev = x->prev;
++      if( x->prev ) x->prev->next = elem;
++      else          pH->first = elem;
++      x->prev = elem;
++    }else{
++      elem->next = pH->first;
++      if( pH->first ) pH->first->prev = elem;
++      elem->prev = 0;
++      pH->first = elem;
++    }
++    new_ht[h].chain = elem;
++    new_ht[h].count++;
++  }
++}
++
++/* This function (for internal use only) locates an element in an
++** hash table that matches the given key.  The hash for this key has
++** already been computed and is passed as the 4th parameter.
++*/
++static HashElem *findElementGivenHash(
++  const Hash *pH,     /* The pH to be searched */
++  const void *pKey,   /* The key we are searching for */
++  int nKey,
++  int h               /* The hash for this key. */
++){
++  HashElem *elem;                /* Used to loop thru the element list */
++  int count;                     /* Number of elements left to test */
++  int (*xCompare)(const void*,int,const void*,int);  /* comparison function */
++
++  if( pH->ht ){
++    elem = pH->ht[h].chain;
++    count = pH->ht[h].count;
++    xCompare = compareFunction(pH->keyClass);
++    while( count-- && elem ){
++      if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){ 
++        return elem;
++      }
++      elem = elem->next;
++    }
++  }
++  return 0;
++}
++
++/* Remove a single entry from the hash table given a pointer to that
++** element and a hash on the element's key.
++*/
++static void removeElementGivenHash(
++  Hash *pH,         /* The pH containing "elem" */
++  HashElem* elem,   /* The element to be removed from the pH */
++  int h             /* Hash value for the element */
++){
++  if( elem->prev ){
++    elem->prev->next = elem->next; 
++  }else{
++    pH->first = elem->next;
++  }
++  if( elem->next ){
++    elem->next->prev = elem->prev;
++  }
++  if( pH->ht[h].chain==elem ){
++    pH->ht[h].chain = elem->next;
++  }
++  pH->ht[h].count--;
++  if( pH->ht[h].count<=0 ){
++    pH->ht[h].chain = 0;
++  }
++  if( pH->copyKey && elem->pKey ){
++    sqliteFree(elem->pKey);
++  }
++  sqliteFree( elem );
++  pH->count--;
++}
++
++/* 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 *sqliteHashFind(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 */
++
++  if( pH==0 || pH->ht==0 ) return 0;
++  xHash = hashFunction(pH->keyClass);
++  assert( xHash!=0 );
++  h = (*xHash)(pKey,nKey);
++  assert( (pH->htsize & (pH->htsize-1))==0 );
++  elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1));
++  return elem ? elem->data : 0;
++}
++
++/* Insert an element into the hash table pH.  The key is pKey,nKey
++** and the data is "data".
++**
++** If no element exists with a matching key, then a new
++** element is created.  A copy of the key is made if the copyKey
++** flag is set.  NULL is returned.
++**
++** If another element already exists with the same key, then the
++** new data replaces the old data and the old data is returned.
++** The key is not copied in this instance.  If a malloc fails, then
++** the new data is returned and the hash table is unchanged.
++**
++** If the "data" parameter to this function is NULL, then the
++** element corresponding to "key" is removed from the hash table.
++*/
++void *sqliteHashInsert(Hash *pH, const void *pKey, int nKey, void *data){
++  int hraw;             /* Raw hash value of the key */
++  int h;                /* the hash of the key modulo hash table size */
++  HashElem *elem;       /* Used to loop thru the element list */
++  HashElem *new_elem;   /* New element added to the pH */
++  int (*xHash)(const void*,int);  /* The hash function */
++
++  assert( pH!=0 );
++  xHash = hashFunction(pH->keyClass);
++  assert( xHash!=0 );
++  hraw = (*xHash)(pKey, nKey);
++  assert( (pH->htsize & (pH->htsize-1))==0 );
++  h = hraw & (pH->htsize-1);
++  elem = findElementGivenHash(pH,pKey,nKey,h);
++  if( elem ){
++    void *old_data = elem->data;
++    if( data==0 ){
++      removeElementGivenHash(pH,elem,h);
++    }else{
++      elem->data = data;
++    }
++    return old_data;
++  }
++  if( data==0 ) return 0;
++  new_elem = (HashElem*)sqliteMalloc( sizeof(HashElem) );
++  if( new_elem==0 ) return data;
++  if( pH->copyKey && pKey!=0 ){
++    new_elem->pKey = sqliteMallocRaw( nKey );
++    if( new_elem->pKey==0 ){
++      sqliteFree(new_elem);
++      return data;
++    }
++    memcpy((void*)new_elem->pKey, pKey, nKey);
++  }else{
++    new_elem->pKey = (void*)pKey;
++  }
++  new_elem->nKey = nKey;
++  pH->count++;
++  if( pH->htsize==0 ) rehash(pH,8);
++  if( pH->htsize==0 ){
++    pH->count = 0;
++    sqliteFree(new_elem);
++    return data;
++  }
++  if( pH->count > pH->htsize ){
++    rehash(pH,pH->htsize*2);
++  }
++  assert( (pH->htsize & (pH->htsize-1))==0 );
++  h = hraw & (pH->htsize-1);
++  elem = pH->ht[h].chain;
++  if( elem ){
++    new_elem->next = elem;
++    new_elem->prev = elem->prev;
++    if( elem->prev ){ elem->prev->next = new_elem; }
++    else            { pH->first = new_elem; }
++    elem->prev = new_elem;
++  }else{
++    new_elem->next = pH->first;
++    new_elem->prev = 0;
++    if( pH->first ){ pH->first->prev = new_elem; }
++    pH->first = new_elem;
++  }
++  pH->ht[h].count++;
++  pH->ht[h].chain = new_elem;
++  new_elem->data = data;
++  return 0;
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/hash.h
+@@ -0,0 +1,109 @@
++/*
++** 2001 September 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 is the header file for the generic hash-table implemenation
++** used in SQLite.
++**
++** $Id$
++*/
++#ifndef _SQLITE_HASH_H_
++#define _SQLITE_HASH_H_
++
++/* Forward declarations of structures. */
++typedef struct Hash Hash;
++typedef struct HashElem HashElem;
++
++/* A complete hash table is an instance of the following structure.
++** The internals of this structure are intended to be opaque -- client
++** code should not attempt to access or modify the fields of this structure
++** directly.  Change this structure only by using the routines below.
++** However, many of the "procedures" and "functions" for modifying and
++** accessing this structure are really macros, so we can't really make
++** this structure opaque.
++*/
++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 */
++  int htsize;             /* Number of buckets in the hash table */
++  struct _ht {            /* the hash table */
++    int count;               /* Number of entries with this hash */
++    HashElem *chain;         /* Pointer to first entry with this hash */
++  } *ht;
++};
++
++/* Each element in the hash table is an instance of the following 
++** structure.  All elements are stored on a single doubly-linked list.
++**
++** Again, this structure is intended to be opaque, but it can't really
++** be opaque because it is used by macros.
++*/
++struct HashElem {
++  HashElem *next, *prev;   /* Next and previous elements in the table */
++  void *data;              /* Data associated with this element */
++  void *pKey; int nKey;    /* Key associated with this element */
++};
++
++/*
++** There are 4 different modes of operation for a hash table:
++**
++**   SQLITE_HASH_INT         nKey is used as the key and pKey is ignored.
++**
++**   SQLITE_HASH_POINTER     pKey is used as the key and nKey is ignored.
++**
++**   SQLITE_HASH_STRING      pKey points to a string that is nKey bytes long
++**                           (including the null-terminator, if any).  Case
++**                           is ignored in comparisons.
++**
++**   SQLITE_HASH_BINARY      pKey points to binary data nKey bytes long. 
++**                           memcmp() is used to compare keys.
++**
++** A copy of the key is made for SQLITE_HASH_STRING and SQLITE_HASH_BINARY
++** if the copyKey parameter to HashInit is 1.  
++*/
++#define SQLITE_HASH_INT       1
++/* #define SQLITE_HASH_POINTER   2 // NOT USED */
++#define SQLITE_HASH_STRING    3
++#define SQLITE_HASH_BINARY    4
++
++/*
++** Access routines.  To delete, insert a NULL pointer.
++*/
++void sqliteHashInit(Hash*, int keytype, int copyKey);
++void *sqliteHashInsert(Hash*, const void *pKey, int nKey, void *pData);
++void *sqliteHashFind(const Hash*, const void *pKey, int nKey);
++void sqliteHashClear(Hash*);
++
++/*
++** Macros for looping over all elements of a hash table.  The idiom is
++** like this:
++**
++**   Hash h;
++**   HashElem *p;
++**   ...
++**   for(p=sqliteHashFirst(&h); p; p=sqliteHashNext(p)){
++**     SomeStructure *pData = sqliteHashData(p);
++**     // do something with pData
++**   }
++*/
++#define sqliteHashFirst(H)  ((H)->first)
++#define sqliteHashNext(E)   ((E)->next)
++#define sqliteHashData(E)   ((E)->data)
++#define sqliteHashKey(E)    ((E)->pKey)
++#define sqliteHashKeysize(E) ((E)->nKey)
++
++/*
++** Number of entries in a hash table
++*/
++#define sqliteHashCount(H)  ((H)->count)
++
++#endif /* _SQLITE_HASH_H_ */
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/insert.c
+@@ -0,0 +1,919 @@
++/*
++** 2001 September 15
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This file contains C code routines that are called by the parser
++** to handle INSERT statements in SQLite.
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++
++/*
++** This routine is call to handle SQL of the following forms:
++**
++**    insert into TABLE (IDLIST) values(EXPRLIST)
++**    insert into TABLE (IDLIST) select
++**
++** The IDLIST following the table name is always optional.  If omitted,
++** then a list of all columns for the table is substituted.  The IDLIST
++** appears in the pColumn parameter.  pColumn is NULL if IDLIST is omitted.
++**
++** The pList parameter holds EXPRLIST in the first form of the INSERT
++** statement above, and pSelect is NULL.  For the second form, pList is
++** 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
++** select with data coming from a VALUES clause, the code executes
++** once straight down through.  The template looks like this:
++**
++**         open write cursor to <table> and its indices
++**         puts VALUES clause expressions onto the stack
++**         write the resulting record into <table>
++**         cleanup
++**
++** If 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:
++**
++**         goto B
++**      A: setup for the SELECT
++**         loop over the tables in the SELECT
++**           gosub C
++**         end loop
++**         cleanup after the SELECT
++**         goto D
++**      B: open write cursor to <table> and its indices
++**         goto A
++**      C: insert the select result into <table>
++**         return
++**      D: cleanup
++**
++** The third 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
++** the select.  The template is like this:
++**
++**         goto B
++**      A: setup for the SELECT
++**         loop over the tables in the SELECT
++**           gosub C
++**         end loop
++**         cleanup after the SELECT
++**         goto D
++**      C: insert the select result into the intermediate table
++**         return
++**      B: open a cursor to an intermediate table
++**         goto A
++**      D: open write cursor to <table> and its indices
++**         loop over the intermediate table
++**           transfer values form intermediate table into <table>
++**         end the loop
++**         cleanup
++*/
++void sqliteInsert(
++  Parse *pParse,        /* Parser context */
++  SrcList *pTabList,    /* Name of table into which we are inserting */
++  ExprList *pList,      /* List of values to be inserted */
++  Select *pSelect,      /* A SELECT statement to use as the data source */
++  IdList *pColumn,      /* Column names corresponding to IDLIST. */
++  int onError           /* How to handle constraint errors */
++){
++  Table *pTab;          /* The table to insert into */
++  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;             /* VDBE Cursor number for pTab */
++  int iCont, iBreak;    /* Beginning and end of the loop over srcTab */
++  sqlite *db;           /* The main database structure */
++  int keyColumn = -1;   /* Column that is the INTEGER PRIMARY KEY */
++  int endOfLoop;        /* Label for the end of the insertion loop */
++  int useTempTable;     /* Store SELECT results in intermediate table */
++  int srcTab;           /* Data comes from this temporary cursor if >=0 */
++  int iSelectLoop;      /* Address of code that implements the SELECT */
++  int iCleanup;         /* Address of the cleanup code */
++  int iInsertBlock;     /* Address of the subroutine used to insert data */
++  int iCntMem;          /* Memory cell used for the row counter */
++  int isView;           /* True if attempting to insert into a view */
++
++  int row_triggers_exist = 0; /* True if there are FOR EACH ROW triggers */
++  int before_triggers;        /* True if there are BEFORE triggers */
++  int after_triggers;         /* True if there are AFTER triggers */
++  int newIdx = -1;            /* Cursor for the NEW table */
++
++  if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
++  db = pParse->db;
++
++  /* Locate the table into which we will be inserting new information.
++  */
++  assert( pTabList->nSrc==1 );
++  zTab = pTabList->a[0].zName;
++  if( zTab==0 ) goto insert_cleanup;
++  pTab = sqliteSrcListLookup(pParse, pTabList);
++  if( pTab==0 ){
++    goto insert_cleanup;
++  }
++  assert( pTab->iDb<db->nDb );
++  zDb = db->aDb[pTab->iDb].zName;
++  if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){
++    goto insert_cleanup;
++  }
++
++  /* Ensure that:
++  *  (a) the table is not read-only, 
++  *  (b) that if it is a view then ON INSERT triggers exist
++  */
++  before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_INSERT, 
++                                       TK_BEFORE, TK_ROW, 0);
++  after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_INSERT,
++                                       TK_AFTER, TK_ROW, 0);
++  row_triggers_exist = before_triggers || after_triggers;
++  isView = pTab->pSelect!=0;
++  if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){
++    goto insert_cleanup;
++  }
++  if( pTab==0 ) goto insert_cleanup;
++
++  /* If pTab is really a view, make sure it has been initialized.
++  */
++  if( isView && sqliteViewGetColumnNames(pParse, pTab) ){
++    goto insert_cleanup;
++  }
++
++  /* Allocate a VDBE
++  */
++  v = sqliteGetVdbe(pParse);
++  if( v==0 ) goto insert_cleanup;
++  sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist, pTab->iDb);
++
++  /* if there are row triggers, allocate a temp table for new.* references. */
++  if( row_triggers_exist ){
++    newIdx = pParse->nTab++;
++  }
++
++  /* Figure out how many columns of data are supplied.  If the data
++  ** is coming from a SELECT statement, then this step also generates
++  ** all the code to implement the SELECT statement and invoke a subroutine
++  ** to process each row of the result. (Template 2.) If the SELECT
++  ** statement uses the the table that is being inserted into, then the
++  ** subroutine is also coded here.  That subroutine stores the SELECT
++  ** results in a temporary table. (Template 3.)
++  */
++  if( pSelect ){
++    /* Data is coming from a SELECT.  Generate code to implement that SELECT
++    */
++    int rc, iInitCode;
++    iInitCode = sqliteVdbeAddOp(v, OP_Goto, 0, 0);
++    iSelectLoop = sqliteVdbeCurrentAddr(v);
++    iInsertBlock = sqliteVdbeMakeLabel(v);
++    rc = sqliteSelect(pParse, pSelect, SRT_Subroutine, iInsertBlock, 0,0,0);
++    if( rc || pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
++    iCleanup = sqliteVdbeMakeLabel(v);
++    sqliteVdbeAddOp(v, OP_Goto, 0, iCleanup);
++    assert( pSelect->pEList );
++    nColumn = pSelect->pEList->nExpr;
++
++    /* Set useTempTable to TRUE if the result of the SELECT statement
++    ** should be written into a temporary table.  Set to FALSE if each
++    ** row of the SELECT can be written directly into the result table.
++    **
++    ** A temp table must be used if the table being updated is also one
++    ** of the tables being read by the SELECT statement.  Also use a 
++    ** temp table in the case of row triggers.
++    */
++    if( row_triggers_exist ){
++      useTempTable = 1;
++    }else{
++      int addr = sqliteVdbeFindOp(v, OP_OpenRead, pTab->tnum);
++      useTempTable = 0;
++      if( addr>0 ){
++        VdbeOp *pOp = sqliteVdbeGetOp(v, addr-2);
++        if( pOp->opcode==OP_Integer && pOp->p1==pTab->iDb ){
++          useTempTable = 1;
++        }
++      }
++    }
++
++    if( useTempTable ){
++      /* Generate the subroutine that SELECT calls to process each row of
++      ** the result.  Store the result in a temporary table
++      */
++      srcTab = pParse->nTab++;
++      sqliteVdbeResolveLabel(v, iInsertBlock);
++      sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0);
++      sqliteVdbeAddOp(v, OP_NewRecno, srcTab, 0);
++      sqliteVdbeAddOp(v, OP_Pull, 1, 0);
++      sqliteVdbeAddOp(v, OP_PutIntKey, srcTab, 0);
++      sqliteVdbeAddOp(v, OP_Return, 0, 0);
++
++      /* 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.
++      */
++      sqliteVdbeChangeP2(v, iInitCode, sqliteVdbeCurrentAddr(v));
++      sqliteVdbeAddOp(v, OP_OpenTemp, srcTab, 0);
++      sqliteVdbeAddOp(v, OP_Goto, 0, iSelectLoop);
++      sqliteVdbeResolveLabel(v, iCleanup);
++    }else{
++      sqliteVdbeChangeP2(v, iInitCode, sqliteVdbeCurrentAddr(v));
++    }
++  }else{
++    /* This is the case if the data for the INSERT is coming from a VALUES
++    ** clause
++    */
++    SrcList dummy;
++    assert( pList!=0 );
++    srcTab = -1;
++    useTempTable = 0;
++    assert( pList );
++    nColumn = pList->nExpr;
++    dummy.nSrc = 0;
++    for(i=0; i<nColumn; i++){
++      if( sqliteExprResolveIds(pParse, &dummy, 0, pList->a[i].pExpr) ){
++        goto insert_cleanup;
++      }
++      if( sqliteExprCheck(pParse, pList->a[i].pExpr, 0, 0) ){
++        goto insert_cleanup;
++      }
++    }
++  }
++
++  /* 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 ){
++    sqliteErrorMsg(pParse, 
++       "table %S has %d columns but %d values were supplied",
++       pTabList, 0, pTab->nCol, nColumn);
++    goto insert_cleanup;
++  }
++  if( pColumn!=0 && nColumn!=pColumn->nId ){
++    sqliteErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId);
++    goto insert_cleanup;
++  }
++
++  /* If the INSERT statement included an IDLIST term, then make sure
++  ** all elements of the IDLIST really are columns of the table and 
++  ** remember the column indices.
++  **
++  ** If the table has an INTEGER PRIMARY KEY column and that column
++  ** is named in the IDLIST, then record in the keyColumn variable
++  ** the index into IDLIST of the primary key column.  keyColumn is
++  ** the index of the primary key as it appears in IDLIST, not as
++  ** is appears in the original table.  (The index of the primary
++  ** key in the original table is pTab->iPKey.)
++  */
++  if( pColumn ){
++    for(i=0; i<pColumn->nId; i++){
++      pColumn->a[i].idx = -1;
++    }
++    for(i=0; i<pColumn->nId; i++){
++      for(j=0; j<pTab->nCol; j++){
++        if( sqliteStrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){
++          pColumn->a[i].idx = j;
++          if( j==pTab->iPKey ){
++            keyColumn = i;
++          }
++          break;
++        }
++      }
++      if( j>=pTab->nCol ){
++        if( sqliteIsRowid(pColumn->a[i].zName) ){
++          keyColumn = i;
++        }else{
++          sqliteErrorMsg(pParse, "table %S has no column named %s",
++              pTabList, 0, pColumn->a[i].zName);
++          pParse->nErr++;
++          goto insert_cleanup;
++        }
++      }
++    }
++  }
++
++  /* If there is no IDLIST term but the table has an integer primary
++  ** key, the set the keyColumn variable to the primary key column index
++  ** in the original table definition.
++  */
++  if( pColumn==0 ){
++    keyColumn = pTab->iPKey;
++  }
++
++  /* Open the temp table for FOR EACH ROW triggers
++  */
++  if( row_triggers_exist ){
++    sqliteVdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
++  }
++    
++  /* Initialize the count of rows to be inserted
++  */
++  if( db->flags & SQLITE_CountRows ){
++    iCntMem = pParse->nMem++;
++    sqliteVdbeAddOp(v, OP_Integer, 0, 0);
++    sqliteVdbeAddOp(v, OP_MemStore, iCntMem, 1);
++  }
++
++  /* Open tables and indices if there are no row triggers */
++  if( !row_triggers_exist ){
++    base = pParse->nTab;
++    idx = sqliteOpenTableAndIndices(pParse, pTab, base);
++    pParse->nTab += idx;
++  }
++
++  /* If the data source is a temporary table, then we have to create
++  ** a loop because there might be multiple rows of data.  If the data
++  ** source is a subroutine call from the SELECT statement, then we need
++  ** to launch the SELECT statement processing.
++  */
++  if( useTempTable ){
++    iBreak = sqliteVdbeMakeLabel(v);
++    sqliteVdbeAddOp(v, OP_Rewind, srcTab, iBreak);
++    iCont = sqliteVdbeCurrentAddr(v);
++  }else if( pSelect ){
++    sqliteVdbeAddOp(v, OP_Goto, 0, iSelectLoop);
++    sqliteVdbeResolveLabel(v, iInsertBlock);
++  }
++
++  /* Run the BEFORE and INSTEAD OF triggers, if there are any
++  */
++  endOfLoop = sqliteVdbeMakeLabel(v);
++  if( before_triggers ){
++
++    /* 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
++    ** translated into a unique ID for the row.  But on a BEFORE trigger,
++    ** we do not know what the unique ID will be (because the insert has
++    ** not happened yet) so we substitute a rowid of -1
++    */
++    if( keyColumn<0 ){
++      sqliteVdbeAddOp(v, OP_Integer, -1, 0);
++    }else if( useTempTable ){
++      sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn);
++    }else if( pSelect ){
++      sqliteVdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1);
++    }else{
++      sqliteExprCode(pParse, pList->a[keyColumn].pExpr);
++      sqliteVdbeAddOp(v, OP_NotNull, -1, sqliteVdbeCurrentAddr(v)+3);
++      sqliteVdbeAddOp(v, OP_Pop, 1, 0);
++      sqliteVdbeAddOp(v, OP_Integer, -1, 0);
++      sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
++    }
++
++    /* Create the new column data
++    */
++    for(i=0; i<pTab->nCol; i++){
++      if( pColumn==0 ){
++        j = i;
++      }else{
++        for(j=0; j<pColumn->nId; j++){
++          if( pColumn->a[j].idx==i ) break;
++        }
++      }
++      if( pColumn && j>=pColumn->nId ){
++        sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
++      }else if( useTempTable ){
++        sqliteVdbeAddOp(v, OP_Column, srcTab, j); 
++      }else if( pSelect ){
++        sqliteVdbeAddOp(v, OP_Dup, nColumn-j-1, 1);
++      }else{
++        sqliteExprCode(pParse, pList->a[j].pExpr);
++      }
++    }
++    sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
++    sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
++
++    /* Fire BEFORE or INSTEAD OF triggers */
++    if( sqliteCodeRowTrigger(pParse, TK_INSERT, 0, TK_BEFORE, pTab, 
++        newIdx, -1, onError, endOfLoop) ){
++      goto insert_cleanup;
++    }
++  }
++
++  /* If any triggers exists, the opening of tables and indices is deferred
++  ** until now.
++  */
++  if( row_triggers_exist && !isView ){
++    base = pParse->nTab;
++    idx = sqliteOpenTableAndIndices(pParse, pTab, base);
++    pParse->nTab += idx;
++  }
++
++  /* Push the record number for the new entry onto the stack.  The
++  ** record number is a randomly generate integer created by NewRecno
++  ** except when the table has an INTEGER PRIMARY KEY column, in which
++  ** case the record number is the same as that column. 
++  */
++  if( !isView ){
++    if( keyColumn>=0 ){
++      if( useTempTable ){
++        sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn);
++      }else if( pSelect ){
++        sqliteVdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1);
++      }else{
++        sqliteExprCode(pParse, pList->a[keyColumn].pExpr);
++      }
++      /* If the PRIMARY KEY expression is NULL, then use OP_NewRecno
++      ** to generate a unique primary key value.
++      */
++      sqliteVdbeAddOp(v, OP_NotNull, -1, sqliteVdbeCurrentAddr(v)+3);
++      sqliteVdbeAddOp(v, OP_Pop, 1, 0);
++      sqliteVdbeAddOp(v, OP_NewRecno, base, 0);
++      sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
++    }else{
++      sqliteVdbeAddOp(v, OP_NewRecno, base, 0);
++    }
++
++    /* Push onto the stack, data for all columns of the new entry, beginning
++    ** with the first column.
++    */
++    for(i=0; i<pTab->nCol; 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. */
++        sqliteVdbeAddOp(v, OP_String, 0, 0);
++        continue;
++      }
++      if( pColumn==0 ){
++        j = i;
++      }else{
++        for(j=0; j<pColumn->nId; j++){
++          if( pColumn->a[j].idx==i ) break;
++        }
++      }
++      if( pColumn && j>=pColumn->nId ){
++        sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
++      }else if( useTempTable ){
++        sqliteVdbeAddOp(v, OP_Column, srcTab, j); 
++      }else if( pSelect ){
++        sqliteVdbeAddOp(v, OP_Dup, i+nColumn-j, 1);
++      }else{
++        sqliteExprCode(pParse, pList->a[j].pExpr);
++      }
++    }
++
++    /* Generate code to check constraints and generate index keys and
++    ** do the insertion.
++    */
++    sqliteGenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0,
++                                   0, onError, endOfLoop);
++    sqliteCompleteInsertion(pParse, pTab, base, 0,0,0,
++                            after_triggers ? newIdx : -1);
++  }
++
++  /* Update the count of rows that are inserted
++  */
++  if( (db->flags & SQLITE_CountRows)!=0 ){
++    sqliteVdbeAddOp(v, OP_MemIncr, iCntMem, 0);
++  }
++
++  if( row_triggers_exist ){
++    /* Close all tables opened */
++    if( !isView ){
++      sqliteVdbeAddOp(v, OP_Close, base, 0);
++      for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
++        sqliteVdbeAddOp(v, OP_Close, idx+base, 0);
++      }
++    }
++
++    /* Code AFTER triggers */
++    if( sqliteCodeRowTrigger(pParse, TK_INSERT, 0, TK_AFTER, pTab, newIdx, -1, 
++          onError, endOfLoop) ){
++      goto insert_cleanup;
++    }
++  }
++
++  /* The bottom of the loop, if the data source is a SELECT statement
++  */
++  sqliteVdbeResolveLabel(v, endOfLoop);
++  if( useTempTable ){
++    sqliteVdbeAddOp(v, OP_Next, srcTab, iCont);
++    sqliteVdbeResolveLabel(v, iBreak);
++    sqliteVdbeAddOp(v, OP_Close, srcTab, 0);
++  }else if( pSelect ){
++    sqliteVdbeAddOp(v, OP_Pop, nColumn, 0);
++    sqliteVdbeAddOp(v, OP_Return, 0, 0);
++    sqliteVdbeResolveLabel(v, iCleanup);
++  }
++
++  if( !row_triggers_exist ){
++    /* Close all tables opened */
++    sqliteVdbeAddOp(v, OP_Close, base, 0);
++    for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
++      sqliteVdbeAddOp(v, OP_Close, idx+base, 0);
++    }
++  }
++
++  sqliteVdbeAddOp(v, OP_SetCounts, 0, 0);
++  sqliteEndWriteOperation(pParse);
++
++  /*
++  ** Return the number of rows inserted.
++  */
++  if( db->flags & SQLITE_CountRows ){
++    sqliteVdbeOp3(v, OP_ColumnName, 0, 1, "rows inserted", P3_STATIC);
++    sqliteVdbeAddOp(v, OP_MemLoad, iCntMem, 0);
++    sqliteVdbeAddOp(v, OP_Callback, 1, 0);
++  }
++
++insert_cleanup:
++  sqliteSrcListDelete(pTabList);
++  if( pList ) sqliteExprListDelete(pList);
++  if( pSelect ) sqliteSelectDelete(pSelect);
++  sqliteIdListDelete(pColumn);
++}
++
++/*
++** Generate code to do a constraint check prior to an INSERT or an UPDATE.
++**
++** When this routine is called, the stack contains (from bottom to top)
++** the following values:
++**
++**    1.  The recno 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.
++**
++**    2.  The recno of the row after the update.
++**
++**    3.  The data in the first column of the entry after the update.
++**
++**    i.  Data from middle columns...
++**
++**    N.  The data in the last column of the entry after the update.
++**
++** The old recno shown as entry (1) above is omitted unless both isUpdate
++** and recnoChng are 1.  isUpdate is true for UPDATEs and false for
++** INSERTs and recnoChng is true if the record number is being changed.
++**
++** 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.
++**
++** This routine also generates code to check constraints.  NOT NULL,
++** CHECK, and UNIQUE constraints are all checked.  If a constraint fails,
++** then the appropriate action is performed.  There are five possible
++** actions: ROLLBACK, ABORT, FAIL, REPLACE, and IGNORE.
++**
++**  Constraint type  Action       What Happens
++**  ---------------  ----------   ----------------------------------------
++**  any              ROLLBACK     The current transaction is rolled back and
++**                                sqlite_exec() returns immediately with a
++**                                return code of SQLITE_CONSTRAINT.
++**
++**  any              ABORT        Back out changes from the current command
++**                                only (do not do a complete rollback) then
++**                                cause sqlite_exec() to return immediately
++**                                with SQLITE_CONSTRAINT.
++**
++**  any              FAIL         Sqlite_exec() returns immediately with a
++**                                return code of SQLITE_CONSTRAINT.  The
++**                                transaction is not rolled back and any
++**                                prior changes are retained.
++**
++**  any              IGNORE       The record number and data is popped from
++**                                the stack and there is an immediate jump
++**                                to label ignoreDest.
++**
++**  NOT NULL         REPLACE      The NULL value is replace by the default
++**                                value for that column.  If the default value
++**                                is NULL, the action is the same as ABORT.
++**
++**  UNIQUE           REPLACE      The other row that conflicts with the row
++**                                being inserted is removed.
++**
++**  CHECK            REPLACE      Illegal.  The results in an exception.
++**
++** Which action to take is determined by the overrideError parameter.
++** Or if overrideError==OE_Default, then the pParse->onError parameter
++** is used.  Or if pParse->onError==OE_Default then the onError value
++** 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.
++** 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.
++*/
++void sqliteGenerateConstraintChecks(
++  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 recnoChng,      /* True if the record number will change */
++  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 */
++){
++  int i;
++  Vdbe *v;
++  int nCol;
++  int onError;
++  int addr;
++  int extra;
++  int iCur;
++  Index *pIdx;
++  int seenReplace = 0;
++  int jumpInst1, jumpInst2;
++  int contAddr;
++  int hasTwoRecnos = (isUpdate && recnoChng);
++
++  v = sqliteGetVdbe(pParse);
++  assert( v!=0 );
++  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
++  nCol = pTab->nCol;
++
++  /* Test all NOT NULL constraints.
++  */
++  for(i=0; i<nCol; i++){
++    if( i==pTab->iPKey ){
++      continue;
++    }
++    onError = pTab->aCol[i].notNull;
++    if( onError==OE_None ) continue;
++    if( overrideError!=OE_Default ){
++      onError = overrideError;
++    }else if( pParse->db->onError!=OE_Default ){
++      onError = pParse->db->onError;
++    }else if( onError==OE_Default ){
++      onError = OE_Abort;
++    }
++    if( onError==OE_Replace && pTab->aCol[i].zDflt==0 ){
++      onError = OE_Abort;
++    }
++    sqliteVdbeAddOp(v, OP_Dup, nCol-1-i, 1);
++    addr = sqliteVdbeAddOp(v, OP_NotNull, 1, 0);
++    switch( onError ){
++      case OE_Rollback:
++      case OE_Abort:
++      case OE_Fail: {
++        char *zMsg = 0;
++        sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError);
++        sqliteSetString(&zMsg, pTab->zName, ".", pTab->aCol[i].zName,
++                        " may not be NULL", (char*)0);
++        sqliteVdbeChangeP3(v, -1, zMsg, P3_DYNAMIC);
++        break;
++      }
++      case OE_Ignore: {
++        sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0);
++        sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
++        break;
++      }
++      case OE_Replace: {
++        sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
++        sqliteVdbeAddOp(v, OP_Push, nCol-i, 0);
++        break;
++      }
++      default: assert(0);
++    }
++    sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
++  }
++
++  /* Test all CHECK constraints
++  */
++  /**** TBD ****/
++
++  /* If we have an INTEGER PRIMARY KEY, make sure the primary key
++  ** of the new record does not previously exist.  Except, if this
++  ** is an UPDATE and the primary key is not changing, that is OK.
++  */
++  if( recnoChng ){
++    onError = pTab->keyConf;
++    if( overrideError!=OE_Default ){
++      onError = overrideError;
++    }else if( pParse->db->onError!=OE_Default ){
++      onError = pParse->db->onError;
++    }else if( onError==OE_Default ){
++      onError = OE_Abort;
++    }
++    
++    if( isUpdate ){
++      sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1);
++      sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1);
++      jumpInst1 = sqliteVdbeAddOp(v, OP_Eq, 0, 0);
++    }
++    sqliteVdbeAddOp(v, OP_Dup, nCol, 1);
++    jumpInst2 = sqliteVdbeAddOp(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: {
++        sqliteVdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError,
++                         "PRIMARY KEY must be unique", P3_STATIC);
++        break;
++      }
++      case OE_Replace: {
++        sqliteGenerateRowIndexDelete(pParse->db, v, pTab, base, 0);
++        if( isUpdate ){
++          sqliteVdbeAddOp(v, OP_Dup, nCol+hasTwoRecnos, 1);
++          sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
++        }
++        seenReplace = 1;
++        break;
++      }
++      case OE_Ignore: {
++        assert( seenReplace==0 );
++        sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0);
++        sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
++        break;
++      }
++    }
++    contAddr = sqliteVdbeCurrentAddr(v);
++    sqliteVdbeChangeP2(v, jumpInst2, contAddr);
++    if( isUpdate ){
++      sqliteVdbeChangeP2(v, jumpInst1, contAddr);
++      sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1);
++      sqliteVdbeAddOp(v, OP_MoveTo, 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++;
++
++    /* Create a key for accessing the index entry */
++    sqliteVdbeAddOp(v, OP_Dup, nCol+extra, 1);
++    for(i=0; i<pIdx->nColumn; i++){
++      int idx = pIdx->aiColumn[i];
++      if( idx==pTab->iPKey ){
++        sqliteVdbeAddOp(v, OP_Dup, i+extra+nCol+1, 1);
++      }else{
++        sqliteVdbeAddOp(v, OP_Dup, i+extra+nCol-idx, 1);
++      }
++    }
++    jumpInst1 = sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
++    if( pParse->db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx);
++
++    /* Find out what action to take in case there is an indexing conflict */
++    onError = pIdx->onError;
++    if( onError==OE_None ) continue;  /* pIdx is not a UNIQUE index */
++    if( overrideError!=OE_Default ){
++      onError = overrideError;
++    }else if( pParse->db->onError!=OE_Default ){
++      onError = pParse->db->onError;
++    }else if( onError==OE_Default ){
++      onError = OE_Abort;
++    }
++    if( seenReplace ){
++      if( onError==OE_Ignore ) onError = OE_Replace;
++      else if( onError==OE_Fail ) onError = OE_Abort;
++    }
++    
++
++    /* Check to see if the new index entry will be unique */
++    sqliteVdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRecnos, 1);
++    jumpInst2 = sqliteVdbeAddOp(v, OP_IsUnique, base+iCur+1, 0);
++
++    /* Generate code that executes if the new index entry is not unique */
++    switch( onError ){
++      case OE_Rollback:
++      case OE_Abort:
++      case OE_Fail: {
++        int j, n1, n2;
++        char zErrMsg[200];
++        strcpy(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], ", ");
++            n1 += 2;
++          }
++          if( n1+n2>sizeof(zErrMsg)-30 ){
++            strcpy(&zErrMsg[n1], "...");
++            n1 += 3;
++            break;
++          }else{
++            strcpy(&zErrMsg[n1], zCol);
++            n1 += n2;
++          }
++        }
++        strcpy(&zErrMsg[n1], 
++            pIdx->nColumn>1 ? " are not unique" : " is not unique");
++        sqliteVdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, zErrMsg, 0);
++        break;
++      }
++      case OE_Ignore: {
++        assert( seenReplace==0 );
++        sqliteVdbeAddOp(v, OP_Pop, nCol+extra+3+hasTwoRecnos, 0);
++        sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
++        break;
++      }
++      case OE_Replace: {
++        sqliteGenerateRowDelete(pParse->db, v, pTab, base, 0);
++        if( isUpdate ){
++          sqliteVdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRecnos, 1);
++          sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
++        }
++        seenReplace = 1;
++        break;
++      }
++      default: assert(0);
++    }
++    contAddr = sqliteVdbeCurrentAddr(v);
++#if NULL_DISTINCT_FOR_UNIQUE
++    sqliteVdbeChangeP2(v, jumpInst1, contAddr);
++#endif
++    sqliteVdbeChangeP2(v, jumpInst2, contAddr);
++  }
++}
++
++/*
++** This routine generates code to finish the INSERT or UPDATE operation
++** that was started by a prior call to sqliteGenerateConstraintChecks.
++** The stack must contain keys for all active indices followed by data
++** and the recno for the new entry.  This routine creates the new
++** entries in all indices and in the main table.
++**
++** The arguments to this routine should be the same as the first six
++** arguments to sqliteGenerateConstraintChecks.
++*/
++void sqliteCompleteInsertion(
++  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 recnoChng,      /* 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 i;
++  Vdbe *v;
++  int nIdx;
++  Index *pIdx;
++
++  v = sqliteGetVdbe(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;
++    sqliteVdbeAddOp(v, OP_IdxPut, base+i+1, 0);
++  }
++  sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
++  if( newIdx>=0 ){
++    sqliteVdbeAddOp(v, OP_Dup, 1, 0);
++    sqliteVdbeAddOp(v, OP_Dup, 1, 0);
++    sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
++  }
++  sqliteVdbeAddOp(v, OP_PutIntKey, base,
++    (pParse->trigStack?0:OPFLAG_NCHANGE) |
++    (isUpdate?0:OPFLAG_LASTROWID) | OPFLAG_CSCHANGE);
++  if( isUpdate && recnoChng ){
++    sqliteVdbeAddOp(v, OP_Pop, 1, 0);
++  }
++}
++
++/*
++** Generate code that will open write cursors for a table and for all
++** indices of that table.  The "base" parameter is the cursor number used
++** for the table.  Indices are opened on subsequent cursors.
++**
++** Return the total number of cursors opened.  This is always at least
++** 1 (for the main table) plus more for each cursor.
++*/
++int sqliteOpenTableAndIndices(Parse *pParse, Table *pTab, int base){
++  int i;
++  Index *pIdx;
++  Vdbe *v = sqliteGetVdbe(pParse);
++  assert( v!=0 );
++  sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
++  sqliteVdbeOp3(v, OP_OpenWrite, base, pTab->tnum, pTab->zName, P3_STATIC);
++  for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
++    sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
++    sqliteVdbeOp3(v, OP_OpenWrite, i+base, pIdx->tnum, pIdx->zName, P3_STATIC);
++  }
++  return i;
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/libsqlite.dsp
+@@ -0,0 +1,353 @@
++# Microsoft Developer Studio Project File - Name="libsqlite" - Package Owner=<4>\r
++# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
++# ** DO NOT EDIT **\r
++\r
++# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
++\r
++CFG=libsqlite - Win32 Debug_TS\r
++!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
++!MESSAGE use the Export Makefile command and run\r
++!MESSAGE \r
++!MESSAGE NMAKE /f "libsqlite.mak".\r
++!MESSAGE \r
++!MESSAGE You can specify a configuration when running NMAKE\r
++!MESSAGE by defining the macro CFG on the command line. For example:\r
++!MESSAGE \r
++!MESSAGE NMAKE /f "libsqlite.mak" CFG="libsqlite - Win32 Debug_TS"\r
++!MESSAGE \r
++!MESSAGE Possible choices for configuration are:\r
++!MESSAGE \r
++!MESSAGE "libsqlite - Win32 Debug_TS" (based on "Win32 (x86) Static Library")\r
++!MESSAGE "libsqlite - Win32 Release_TS" (based on "Win32 (x86) Static Library")\r
++!MESSAGE "libsqlite - Win32 Release_TSDbg" (based on "Win32 (x86) Static Library")\r
++!MESSAGE \r
++\r
++# Begin Project\r
++# PROP AllowPerConfigDependencies 0\r
++# PROP Scc_ProjName ""\r
++# PROP Scc_LocalPath ""\r
++CPP=cl.exe\r
++RSC=rc.exe\r
++\r
++!IF  "$(CFG)" == "libsqlite - Win32 Debug_TS"\r
++\r
++# PROP BASE Use_MFC 0\r
++# PROP BASE Use_Debug_Libraries 1\r
++# PROP BASE Output_Dir "Debug_TS"\r
++# PROP BASE Intermediate_Dir "Debug_TS"\r
++# PROP BASE Target_Dir ""\r
++# PROP Use_MFC 0\r
++# PROP Use_Debug_Libraries 1\r
++# PROP Output_Dir "..\..\Debug_TS"\r
++# PROP Intermediate_Dir "..\..\Debug_TS"\r
++# PROP Target_Dir ""\r
++# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
++# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D THREADSAFE=1 /YX /FD /GZ /c\r
++# ADD BASE RSC /l 0x406 /d "_DEBUG"\r
++# ADD RSC /l 0x406 /d "_DEBUG"\r
++BSC32=bscmake.exe\r
++# ADD BASE BSC32 /nologo\r
++# ADD BSC32 /nologo\r
++LIB32=link.exe -lib\r
++# ADD BASE LIB32 /nologo\r
++# ADD LIB32 /nologo\r
++\r
++!ELSEIF  "$(CFG)" == "libsqlite - Win32 Release_TS"\r
++\r
++# PROP BASE Use_MFC 0\r
++# PROP BASE Use_Debug_Libraries 0\r
++# PROP BASE Output_Dir "Release_TS"\r
++# PROP BASE Intermediate_Dir "Release_TS"\r
++# PROP BASE Target_Dir ""\r
++# PROP Use_MFC 0\r
++# PROP Use_Debug_Libraries 0\r
++# PROP Output_Dir "..\..\Release_TS"\r
++# PROP Intermediate_Dir "..\..\Release_TS"\r
++# PROP Target_Dir ""\r
++# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
++# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D THREADSAFE=1 /YX /FD /c\r
++# ADD BASE RSC /l 0x406 /d "NDEBUG"\r
++# ADD RSC /l 0x406 /d "NDEBUG"\r
++BSC32=bscmake.exe\r
++# ADD BASE BSC32 /nologo\r
++# ADD BSC32 /nologo\r
++LIB32=link.exe -lib\r
++# ADD BASE LIB32 /nologo\r
++# ADD LIB32 /nologo\r
++\r
++!ELSEIF  "$(CFG)" == "libsqlite - Win32 Release_TSDbg"\r
++\r
++# PROP BASE Use_MFC 0\r
++# PROP BASE Use_Debug_Libraries 0\r
++# PROP BASE Output_Dir "libsqlite___Win32_Release_TSDbg"\r
++# PROP BASE Intermediate_Dir "libsqlite___Win32_Release_TSDbg"\r
++# PROP BASE Target_Dir ""\r
++# PROP Use_MFC 0\r
++# PROP Use_Debug_Libraries 0\r
++# PROP Output_Dir "..\..\Release_TSDbg"\r
++# PROP Intermediate_Dir "..\..\Release_TSDbg"\r
++# PROP Target_Dir ""\r
++# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D THREADSAFE=1 /YX /FD /c\r
++# ADD CPP /nologo /MD /W3 /GX /Zi /Od /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D THREADSAFE=1 /YX /FD /c\r
++# ADD BASE RSC /l 0x406 /d "NDEBUG"\r
++# ADD RSC /l 0x406 /d "NDEBUG"\r
++BSC32=bscmake.exe\r
++# ADD BASE BSC32 /nologo\r
++# ADD BSC32 /nologo\r
++LIB32=link.exe -lib\r
++# ADD BASE LIB32 /nologo /out:"Release_TS\libsqlite.lib"\r
++# ADD LIB32 /nologo\r
++\r
++!ENDIF \r
++\r
++# Begin Target\r
++\r
++# Name "libsqlite - Win32 Debug_TS"\r
++# Name "libsqlite - Win32 Release_TS"\r
++# Name "libsqlite - Win32 Release_TSDbg"\r
++# Begin Group "Source Files"\r
++\r
++# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
++# Begin Source File\r
++\r
++SOURCE=attach.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=auth.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=btree.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=btree_rb.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=build.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=copy.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\date.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=delete.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=encode.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=expr.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=func.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=hash.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=insert.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=main.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=opcodes.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=os.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=pager.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=parse.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=pragma.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=printf.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=random.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=select.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=table.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=tokenize.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=trigger.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=update.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=util.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=vacuum.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=vdbe.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\vdbeaux.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=where.c\r
++# End Source File\r
++# End Group\r
++# Begin Group "Header Files"\r
++\r
++# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
++# Begin Source File\r
++\r
++SOURCE=btree.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=config_static.w32.h\r
++\r
++!IF  "$(CFG)" == "libsqlite - Win32 Debug_TS"\r
++\r
++# Begin Custom Build\r
++InputDir=.\r
++InputPath=config_static.w32.h\r
++\r
++"$(InputDir)\config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
++      copy $(InputPath) $(InputDir)\config.h\r
++\r
++# End Custom Build\r
++\r
++!ELSEIF  "$(CFG)" == "libsqlite - Win32 Release_TS"\r
++\r
++# Begin Custom Build\r
++InputDir=.\r
++InputPath=config_static.w32.h\r
++\r
++"$(InputDir)\config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
++      copy $(InputPath) $(InputDir)\config.h\r
++\r
++# End Custom Build\r
++\r
++!ELSEIF  "$(CFG)" == "libsqlite - Win32 Release_TSDbg"\r
++\r
++# Begin Custom Build\r
++InputDir=.\r
++InputPath=config_static.w32.h\r
++\r
++"$(InputDir)\config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
++      copy $(InputPath) $(InputDir)\config.h\r
++\r
++# End Custom Build\r
++\r
++!ENDIF \r
++\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=hash.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=opcodes.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=os.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=pager.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=parse.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=sqlite.w32.h\r
++\r
++!IF  "$(CFG)" == "libsqlite - Win32 Debug_TS"\r
++\r
++# Begin Custom Build\r
++InputDir=.\r
++InputPath=sqlite.w32.h\r
++\r
++"$(InputDir)\sqlite.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
++      copy $(InputPath) $(InputDir)\sqlite.h\r
++\r
++# End Custom Build\r
++\r
++!ELSEIF  "$(CFG)" == "libsqlite - Win32 Release_TS"\r
++\r
++# Begin Custom Build\r
++InputDir=.\r
++InputPath=sqlite.w32.h\r
++\r
++"$(InputDir)\sqlite.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
++      copy $(InputPath) $(InputDir)\sqlite.h\r
++\r
++# End Custom Build\r
++\r
++!ELSEIF  "$(CFG)" == "libsqlite - Win32 Release_TSDbg"\r
++\r
++# Begin Custom Build\r
++InputDir=.\r
++InputPath=sqlite.w32.h\r
++\r
++"$(InputDir)\sqlite.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
++      copy $(InputPath) $(InputDir)\sqlite.h\r
++\r
++# End Custom Build\r
++\r
++!ENDIF \r
++\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=sqliteInt.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=vdbe.h\r
++# End Source File\r
++# End Group\r
++# End Target\r
++# End Project\r
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/main.c
+@@ -0,0 +1,1143 @@
++/*
++** 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.
++**
++*************************************************************************
++** Main file for the SQLite library.  The routines in this file
++** implement the programmer interface to the library.  Routines in
++** other files are for internal use by SQLite and should not be
++** accessed by users of the library.
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++#include "os.h"
++#include <ctype.h>
++
++/*
++** A pointer to this structure is used to communicate information
++** from sqliteInit into the sqliteInitCallback.
++*/
++typedef struct {
++  sqlite *db;         /* The database being initialized */
++  char **pzErrMsg;    /* Error message stored here */
++} InitData;
++
++/*
++** Fill the InitData structure with an error message that indicates
++** that the database is corrupt.
++*/
++static void corruptSchema(InitData *pData, const char *zExtra){
++  sqliteSetString(pData->pzErrMsg, "malformed database schema",
++     zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0);
++}
++
++/*
++** This is the callback routine for the code that initializes the
++** database.  See sqliteInit() below for additional information.
++**
++** Each callback contains the following information:
++**
++**     argv[0] = "file-format" or "schema-cookie" or "table" or "index"
++**     argv[1] = table or index name or meta statement type.
++**     argv[2] = root page number for table or index.  NULL for meta.
++**     argv[3] = SQL text for a CREATE TABLE or CREATE INDEX statement.
++**     argv[4] = "1" for temporary files, "0" for main database, "2" or more
++**               for auxiliary database files.
++**
++*/
++static
++int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
++  InitData *pData = (InitData*)pInit;
++  int nErr = 0;
++
++  assert( argc==5 );
++  if( argv==0 ) return 0;   /* Might happen if EMPTY_RESULT_CALLBACKS are on */
++  if( argv[0]==0 ){
++    corruptSchema(pData, 0);
++    return 1;
++  }
++  switch( argv[0][0] ){
++    case 'v':
++    case 'i':
++    case 't': {  /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */
++      sqlite *db = pData->db;
++      if( argv[2]==0 || argv[4]==0 ){
++        corruptSchema(pData, 0);
++        return 1;
++      }
++      if( argv[3] && argv[3][0] ){
++        /* Call the parser to process a CREATE TABLE, INDEX or VIEW.
++        ** But because db->init.busy is set to 1, no VDBE code is generated
++        ** or executed.  All the parser does is build the internal data
++        ** structures that describe the table, index, or view.
++        */
++        char *zErr;
++        assert( db->init.busy );
++        db->init.iDb = atoi(argv[4]);
++        assert( db->init.iDb>=0 && db->init.iDb<db->nDb );
++        db->init.newTnum = atoi(argv[2]);
++        if( sqlite_exec(db, argv[3], 0, 0, &zErr) ){
++          corruptSchema(pData, zErr);
++          sqlite_freemem(zErr);
++        }
++        db->init.iDb = 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
++        ** constraint for a CREATE TABLE.  The index should have already
++        ** been created when we processed the CREATE TABLE.  All we have
++        ** to do here is record the root page number for that index.
++        */
++        int iDb;
++        Index *pIndex;
++
++        iDb = atoi(argv[4]);
++        assert( iDb>=0 && iDb<db->nDb );
++        pIndex = sqliteFindIndex(db, argv[1], db->aDb[iDb].zName);
++        if( pIndex==0 || pIndex->tnum!=0 ){
++          /* This can occur if there exists an index on a TEMP table which
++          ** has the same name as another index on a permanent index.  Since
++          ** the permanent table is hidden by the TEMP table, we can also
++          ** safely ignore the index on the permanent table.
++          */
++          /* Do Nothing */;
++        }else{
++          pIndex->tnum = atoi(argv[2]);
++        }
++      }
++      break;
++    }
++    default: {
++      /* This can not happen! */
++      nErr = 1;
++      assert( nErr==0 );
++    }
++  }
++  return nErr;
++}
++
++/*
++** This is a callback procedure used to reconstruct a table.  The
++** name of the table to be reconstructed is passed in as argv[0].
++**
++** This routine is used to automatically upgrade a database from
++** format version 1 or 2 to version 3.  The correct operation of
++** this routine relys on the fact that no indices are used when
++** copying a table out to a temporary file.
++**
++** The change from version 2 to version 3 occurred between SQLite
++** version 2.5.6 and 2.6.0 on 2002-July-18.  
++*/
++static
++int upgrade_3_callback(void *pInit, int argc, char **argv, char **NotUsed){
++  InitData *pData = (InitData*)pInit;
++  int rc;
++  Table *pTab;
++  Trigger *pTrig;
++  char *zErr = 0;
++
++  pTab = sqliteFindTable(pData->db, argv[0], 0);
++  assert( pTab!=0 );
++  assert( sqliteStrICmp(pTab->zName, argv[0])==0 );
++  if( pTab ){
++    pTrig = pTab->pTrigger;
++    pTab->pTrigger = 0;  /* Disable all triggers before rebuilding the table */
++  }
++  rc = sqlite_exec_printf(pData->db,
++    "CREATE TEMP TABLE sqlite_x AS SELECT * FROM '%q'; "
++    "DELETE FROM '%q'; "
++    "INSERT INTO '%q' SELECT * FROM sqlite_x; "
++    "DROP TABLE sqlite_x;",
++    0, 0, &zErr, argv[0], argv[0], argv[0]);
++  if( zErr ){
++    if( *pData->pzErrMsg ) sqlite_freemem(*pData->pzErrMsg);
++    *pData->pzErrMsg = zErr;
++  }
++
++  /* If an error occurred in the SQL above, then the transaction will
++  ** rollback which will delete the internal symbol tables.  This will
++  ** cause the structure that pTab points to be deleted.  In case that
++  ** happened, we need to refetch pTab.
++  */
++  pTab = sqliteFindTable(pData->db, argv[0], 0);
++  if( pTab ){
++    assert( sqliteStrICmp(pTab->zName, argv[0])==0 );
++    pTab->pTrigger = pTrig;  /* Re-enable triggers */
++  }
++  return rc!=SQLITE_OK;
++}
++
++
++
++/*
++** Attempt to read the database schema and initialize internal
++** data structures for a single database file.  The index of the
++** database file is given by iDb.  iDb==0 is used for the main
++** database.  iDb==1 should never be used.  iDb>=2 is used for
++** auxiliary databases.  Return one of the SQLITE_ error codes to
++** indicate success or failure.
++*/
++static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
++  int rc;
++  BtCursor *curMain;
++  int size;
++  Table *pTab;
++  char const *azArg[6];
++  char zDbNum[30];
++  int meta[SQLITE_N_BTREE_META];
++  InitData initData;
++  char const *zMasterSchema;
++  char const *zMasterName;
++  char *zSql = 0;
++
++  /*
++  ** The master database table has a structure like this
++  */
++  static char master_schema[] = 
++     "CREATE TABLE sqlite_master(\n"
++     "  type text,\n"
++     "  name text,\n"
++     "  tbl_name text,\n"
++     "  rootpage integer,\n"
++     "  sql text\n"
++     ")"
++  ;
++  static char temp_master_schema[] = 
++     "CREATE TEMP TABLE sqlite_temp_master(\n"
++     "  type text,\n"
++     "  name text,\n"
++     "  tbl_name text,\n"
++     "  rootpage integer,\n"
++     "  sql text\n"
++     ")"
++  ;
++
++  assert( iDb>=0 && iDb<db->nDb );
++
++  /* zMasterSchema and zInitScript are set to point at the master schema
++  ** and initialisation script appropriate for the database being
++  ** initialised. zMasterName is the name of the master table.
++  */
++  if( iDb==1 ){
++    zMasterSchema = temp_master_schema;
++    zMasterName = TEMP_MASTER_NAME;
++  }else{
++    zMasterSchema = master_schema;
++    zMasterName = MASTER_NAME;
++  }
++
++  /* Construct the schema table.
++  */
++  sqliteSafetyOff(db);
++  azArg[0] = "table";
++  azArg[1] = zMasterName;
++  azArg[2] = "2";
++  azArg[3] = zMasterSchema;
++  sprintf(zDbNum, "%d", iDb);
++  azArg[4] = zDbNum;
++  azArg[5] = 0;
++  initData.db = db;
++  initData.pzErrMsg = pzErrMsg;
++  sqliteInitCallback(&initData, 5, (char **)azArg, 0);
++  pTab = sqliteFindTable(db, zMasterName, db->aDb[iDb].zName);
++  if( pTab ){
++    pTab->readOnly = 1;
++  }else{
++    return SQLITE_NOMEM;
++  }
++  sqliteSafetyOn(db);
++
++  /* Create a cursor to hold the database open
++  */
++  if( db->aDb[iDb].pBt==0 ) return SQLITE_OK;
++  rc = sqliteBtreeCursor(db->aDb[iDb].pBt, 2, 0, &curMain);
++  if( rc ){
++    sqliteSetString(pzErrMsg, sqlite_error_string(rc), (char*)0);
++    return rc;
++  }
++
++  /* Get the database meta information
++  */
++  rc = sqliteBtreeGetMeta(db->aDb[iDb].pBt, meta);
++  if( rc ){
++    sqliteSetString(pzErrMsg, sqlite_error_string(rc), (char*)0);
++    sqliteBtreeCloseCursor(curMain);
++    return rc;
++  }
++  db->aDb[iDb].schema_cookie = meta[1];
++  if( iDb==0 ){
++    db->next_cookie = meta[1];
++    db->file_format = meta[2];
++    size = meta[3];
++    if( size==0 ){ size = MAX_PAGES; }
++    db->cache_size = size;
++    db->safety_level = meta[4];
++    if( meta[6]>0 && meta[6]<=2 && db->temp_store==0 ){
++      db->temp_store = meta[6];
++    }
++    if( db->safety_level==0 ) db->safety_level = 2;
++
++    /*
++    **  file_format==1    Version 2.1.0.
++    **  file_format==2    Version 2.2.0. Add support for INTEGER PRIMARY KEY.
++    **  file_format==3    Version 2.6.0. Fix empty-string index bug.
++    **  file_format==4    Version 2.7.0. Add support for separate numeric and
++    **                    text datatypes.
++    */
++    if( db->file_format==0 ){
++      /* This happens if the database was initially empty */
++      db->file_format = 4;
++    }else if( db->file_format>4 ){
++      sqliteBtreeCloseCursor(curMain);
++      sqliteSetString(pzErrMsg, "unsupported file format", (char*)0);
++      return SQLITE_ERROR;
++    }
++  }else if( iDb!=1 && (db->file_format!=meta[2] || db->file_format<4) ){
++    assert( db->file_format>=4 );
++    if( meta[2]==0 ){
++      sqliteSetString(pzErrMsg, "cannot attach empty database: ",
++         db->aDb[iDb].zName, (char*)0);
++    }else{
++      sqliteSetString(pzErrMsg, "incompatible file format in auxiliary "
++         "database: ", db->aDb[iDb].zName, (char*)0);
++    }
++    sqliteBtreeClose(db->aDb[iDb].pBt);
++    db->aDb[iDb].pBt = 0;
++    return SQLITE_FORMAT;
++  }
++  sqliteBtreeSetCacheSize(db->aDb[iDb].pBt, db->cache_size);
++  sqliteBtreeSetSafetyLevel(db->aDb[iDb].pBt, meta[4]==0 ? 2 : meta[4]);
++
++  /* Read the schema information out of the schema tables
++  */
++  assert( db->init.busy );
++  sqliteSafetyOff(db);
++
++  /* The following SQL will read the schema from the master tables.
++  ** The first version works with SQLite file formats 2 or greater.
++  ** The second version is for format 1 files.
++  **
++  ** Beginning with file format 2, the rowid for new table entries
++  ** (including entries in sqlite_master) is an increasing integer.
++  ** So for file format 2 and later, we can play back sqlite_master
++  ** and all the CREATE statements will appear in the right order.
++  ** But with file format 1, table entries were random and so we
++  ** have to make sure the CREATE TABLEs occur before their corresponding
++  ** CREATE INDEXs.  (We don't have to deal with CREATE VIEW or
++  ** CREATE TRIGGER in file format 1 because those constructs did
++  ** not exist then.) 
++  */
++  if( db->file_format>=2 ){
++    sqliteSetString(&zSql, 
++        "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"",
++       db->aDb[iDb].zName, "\".", zMasterName, (char*)0);
++  }else{
++    sqliteSetString(&zSql, 
++        "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"",
++       db->aDb[iDb].zName, "\".", zMasterName, 
++       " WHERE type IN ('table', 'index')"
++       " ORDER BY CASE type WHEN 'table' THEN 0 ELSE 1 END", (char*)0);
++  }
++  rc = sqlite_exec(db, zSql, sqliteInitCallback, &initData, 0);
++
++  sqliteFree(zSql);
++  sqliteSafetyOn(db);
++  sqliteBtreeCloseCursor(curMain);
++  if( sqlite_malloc_failed ){
++    sqliteSetString(pzErrMsg, "out of memory", (char*)0);
++    rc = SQLITE_NOMEM;
++    sqliteResetInternalSchema(db, 0);
++  }
++  if( rc==SQLITE_OK ){
++    DbSetProperty(db, iDb, DB_SchemaLoaded);
++  }else{
++    sqliteResetInternalSchema(db, iDb);
++  }
++  return rc;
++}
++
++/*
++** Initialize all database files - the main database file, the file
++** used to store temporary tables, and any additional database files
++** created using ATTACH statements.  Return a success code.  If an
++** error occurs, write an error message into *pzErrMsg.
++**
++** After the database is initialized, the SQLITE_Initialized
++** bit is set in the flags field of the sqlite structure.  An
++** attempt is made to initialize the database as soon as it
++** is opened.  If that fails (perhaps because another process
++** has the sqlite_master table locked) than another attempt
++** is made the first time the database is accessed.
++*/
++int sqliteInit(sqlite *db, char **pzErrMsg){
++  int i, rc;
++  
++  if( db->init.busy ) return SQLITE_OK;
++  assert( (db->flags & SQLITE_Initialized)==0 );
++  rc = SQLITE_OK;
++  db->init.busy = 1;
++  for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
++    if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
++    rc = sqliteInitOne(db, i, pzErrMsg);
++    if( rc ){
++      sqliteResetInternalSchema(db, i);
++    }
++  }
++
++  /* Once all the other databases have been initialised, load the schema
++  ** for the TEMP database. This is loaded last, as the TEMP database
++  ** schema may contain references to objects in other databases.
++  */
++  if( rc==SQLITE_OK && db->nDb>1 && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
++    rc = sqliteInitOne(db, 1, pzErrMsg);
++    if( rc ){
++      sqliteResetInternalSchema(db, 1);
++    }
++  }
++
++  db->init.busy = 0;
++  if( rc==SQLITE_OK ){
++    db->flags |= SQLITE_Initialized;
++    sqliteCommitInternalChanges(db);
++  }
++
++  /* If the database is in formats 1 or 2, then upgrade it to
++  ** version 3.  This will reconstruct all indices.  If the
++  ** upgrade fails for any reason (ex: out of disk space, database
++  ** is read only, interrupt received, etc.) then fail the init.
++  */
++  if( rc==SQLITE_OK && db->file_format<3 ){
++    char *zErr = 0;
++    InitData initData;
++    int meta[SQLITE_N_BTREE_META];
++
++    db->magic = SQLITE_MAGIC_OPEN;
++    initData.db = db;
++    initData.pzErrMsg = &zErr;
++    db->file_format = 3;
++    rc = sqlite_exec(db,
++      "BEGIN; SELECT name FROM sqlite_master WHERE type='table';",
++      upgrade_3_callback,
++      &initData,
++      &zErr);
++    if( rc==SQLITE_OK ){
++      sqliteBtreeGetMeta(db->aDb[0].pBt, meta);
++      meta[2] = 4;
++      sqliteBtreeUpdateMeta(db->aDb[0].pBt, meta);
++      sqlite_exec(db, "COMMIT", 0, 0, 0);
++    }
++    if( rc!=SQLITE_OK ){
++      sqliteSetString(pzErrMsg, 
++        "unable to upgrade database to the version 2.6 format",
++        zErr ? ": " : 0, zErr, (char*)0);
++    }
++    sqlite_freemem(zErr);
++  }
++
++  if( rc!=SQLITE_OK ){
++    db->flags &= ~SQLITE_Initialized;
++  }
++  return rc;
++}
++
++/*
++** The version of the library
++*/
++const char rcsid[] = "@(#) \044Id: SQLite version " SQLITE_VERSION " $";
++const char sqlite_version[] = SQLITE_VERSION;
++
++/*
++** Does the library expect data to be encoded as UTF-8 or iso8859?  The
++** following global constant always lets us know.
++*/
++#ifdef SQLITE_UTF8
++const char sqlite_encoding[] = "UTF-8";
++#else
++const char sqlite_encoding[] = "iso8859";
++#endif
++
++/*
++** Open a new SQLite database.  Construct an "sqlite" structure to define
++** the state of this database and return a pointer to that structure.
++**
++** An attempt is made to initialize the in-memory data structures that
++** hold the database schema.  But if this fails (because the schema file
++** is locked) then that step is deferred until the first call to
++** sqlite_exec().
++*/
++sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
++  sqlite *db;
++  int rc, i;
++
++  /* Allocate the sqlite data structure */
++  db = sqliteMalloc( sizeof(sqlite) );
++  if( pzErrMsg ) *pzErrMsg = 0;
++  if( db==0 ) goto no_mem_on_open;
++  db->onError = OE_Default;
++  db->priorNewRowid = 0;
++  db->magic = SQLITE_MAGIC_BUSY;
++  db->nDb = 2;
++  db->aDb = db->aDbStatic;
++  /* db->flags |= SQLITE_ShortColNames; */
++  sqliteHashInit(&db->aFunc, SQLITE_HASH_STRING, 1);
++  for(i=0; i<db->nDb; i++){
++    sqliteHashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0);
++    sqliteHashInit(&db->aDb[i].idxHash, SQLITE_HASH_STRING, 0);
++    sqliteHashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0);
++    sqliteHashInit(&db->aDb[i].aFKey, SQLITE_HASH_STRING, 1);
++  }
++  
++  /* Open the backend database driver */
++  if( zFilename[0]==':' && strcmp(zFilename,":memory:")==0 ){
++    db->temp_store = 2;
++  }
++  rc = sqliteBtreeFactory(db, zFilename, 0, MAX_PAGES, &db->aDb[0].pBt);
++  if( rc!=SQLITE_OK ){
++    switch( rc ){
++      default: {
++        sqliteSetString(pzErrMsg, "unable to open database: ",
++           zFilename, (char*)0);
++      }
++    }
++    sqliteFree(db);
++    sqliteStrRealloc(pzErrMsg);
++    return 0;
++  }
++  db->aDb[0].zName = "main";
++  db->aDb[1].zName = "temp";
++
++  /* Attempt to read the schema */
++  sqliteRegisterBuiltinFunctions(db);
++  rc = sqliteInit(db, pzErrMsg);
++  db->magic = SQLITE_MAGIC_OPEN;
++  if( sqlite_malloc_failed ){
++    sqlite_close(db);
++    goto no_mem_on_open;
++  }else if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
++    sqlite_close(db);
++    sqliteStrRealloc(pzErrMsg);
++    return 0;
++  }else if( pzErrMsg ){
++    sqliteFree(*pzErrMsg);
++    *pzErrMsg = 0;
++  }
++
++  /* Return a pointer to the newly opened database structure */
++  return db;
++
++no_mem_on_open:
++  sqliteSetString(pzErrMsg, "out of memory", (char*)0);
++  sqliteStrRealloc(pzErrMsg);
++  return 0;
++}
++
++/*
++** Return the ROWID of the most recent insert
++*/
++int sqlite_last_insert_rowid(sqlite *db){
++  return db->lastRowid;
++}
++
++/*
++** Return the number of changes in the most recent call to sqlite_exec().
++*/
++int sqlite_changes(sqlite *db){
++  return db->nChange;
++}
++
++/*
++** Return the number of changes produced by the last INSERT, UPDATE, or
++** DELETE statement to complete execution. The count does not include
++** changes due to SQL statements executed in trigger programs that were
++** triggered by that statement
++*/
++int sqlite_last_statement_changes(sqlite *db){
++  return db->lsChange;
++}
++
++/*
++** Close an existing SQLite database
++*/
++void sqlite_close(sqlite *db){
++  HashElem *i;
++  int j;
++  db->want_to_close = 1;
++  if( sqliteSafetyCheck(db) || sqliteSafetyOn(db) ){
++    /* printf("DID NOT CLOSE\n"); fflush(stdout); */
++    return;
++  }
++  db->magic = SQLITE_MAGIC_CLOSED;
++  for(j=0; j<db->nDb; j++){
++    struct Db *pDb = &db->aDb[j];
++    if( pDb->pBt ){
++      sqliteBtreeClose(pDb->pBt);
++      pDb->pBt = 0;
++    }
++  }
++  sqliteResetInternalSchema(db, 0);
++  assert( db->nDb<=2 );
++  assert( db->aDb==db->aDbStatic );
++  for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){
++    FuncDef *pFunc, *pNext;
++    for(pFunc = (FuncDef*)sqliteHashData(i); pFunc; pFunc=pNext){
++      pNext = pFunc->pNext;
++      sqliteFree(pFunc);
++    }
++  }
++  sqliteHashClear(&db->aFunc);
++  sqliteFree(db);
++}
++
++/*
++** Rollback all database files.
++*/
++void sqliteRollbackAll(sqlite *db){
++  int i;
++  for(i=0; i<db->nDb; i++){
++    if( db->aDb[i].pBt ){
++      sqliteBtreeRollback(db->aDb[i].pBt);
++      db->aDb[i].inTrans = 0;
++    }
++  }
++  sqliteResetInternalSchema(db, 0);
++  /* sqliteRollbackInternalChanges(db); */
++}
++
++/*
++** Execute SQL code.  Return one of the SQLITE_ success/failure
++** codes.  Also write an error message into memory obtained from
++** malloc() and make *pzErrMsg point to that message.
++**
++** If the SQL is a query, then for each row in the query result
++** the xCallback() function is called.  pArg becomes the first
++** argument to xCallback().  If xCallback=NULL then no callback
++** is invoked, even for queries.
++*/
++int sqlite_exec(
++  sqlite *db,                 /* The database on which the SQL executes */
++  const char *zSql,           /* The SQL to be executed */
++  sqlite_callback xCallback,  /* Invoke this callback routine */
++  void *pArg,                 /* First argument to xCallback() */
++  char **pzErrMsg             /* Write error messages here */
++){
++  int rc = SQLITE_OK;
++  const char *zLeftover;
++  sqlite_vm *pVm;
++  int nRetry = 0;
++  int nChange = 0;
++  int nCallback;
++
++  if( zSql==0 ) return SQLITE_OK;
++  while( rc==SQLITE_OK && zSql[0] ){
++    pVm = 0;
++    rc = sqlite_compile(db, zSql, &zLeftover, &pVm, pzErrMsg);
++    if( rc!=SQLITE_OK ){
++      assert( pVm==0 || sqlite_malloc_failed );
++      return rc;
++    }
++    if( pVm==0 ){
++      /* This happens if the zSql input contained only whitespace */
++      break;
++    }
++    db->nChange += nChange;
++    nCallback = 0;
++    while(1){
++      int nArg;
++      char **azArg, **azCol;
++      rc = sqlite_step(pVm, &nArg, (const char***)&azArg,(const char***)&azCol);
++      if( rc==SQLITE_ROW ){
++        if( xCallback!=0 && xCallback(pArg, nArg, azArg, azCol) ){
++          sqlite_finalize(pVm, 0);
++          return SQLITE_ABORT;
++        }
++        nCallback++;
++      }else{
++        if( rc==SQLITE_DONE && nCallback==0
++          && (db->flags & SQLITE_NullCallback)!=0 && xCallback!=0 ){
++          xCallback(pArg, nArg, azArg, azCol);
++        }
++        rc = sqlite_finalize(pVm, pzErrMsg);
++        if( rc==SQLITE_SCHEMA && nRetry<2 ){
++          nRetry++;
++          rc = SQLITE_OK;
++          break;
++        }
++        if( db->pVdbe==0 ){
++          nChange = db->nChange;
++        }
++        nRetry = 0;
++        zSql = zLeftover;
++        while( isspace(zSql[0]) ) zSql++;
++        break;
++      }
++    }
++  }
++  return rc;
++}
++
++
++/*
++** Compile a single statement of SQL into a virtual machine.  Return one
++** of the SQLITE_ success/failure codes.  Also write an error message into
++** memory obtained from malloc() and make *pzErrMsg point to that message.
++*/
++int sqlite_compile(
++  sqlite *db,                 /* The database on which the SQL executes */
++  const char *zSql,           /* The SQL to be executed */
++  const char **pzTail,        /* OUT: Next statement after the first */
++  sqlite_vm **ppVm,           /* OUT: The virtual machine */
++  char **pzErrMsg             /* OUT: Write error messages here */
++){
++  Parse sParse;
++
++  if( pzErrMsg ) *pzErrMsg = 0;
++  if( sqliteSafetyOn(db) ) goto exec_misuse;
++  if( !db->init.busy ){
++    if( (db->flags & SQLITE_Initialized)==0 ){
++      int rc, cnt = 1;
++      while( (rc = sqliteInit(db, pzErrMsg))==SQLITE_BUSY
++         && db->xBusyCallback
++         && db->xBusyCallback(db->pBusyArg, "", cnt++)!=0 ){}
++      if( rc!=SQLITE_OK ){
++        sqliteStrRealloc(pzErrMsg);
++        sqliteSafetyOff(db);
++        return rc;
++      }
++      if( pzErrMsg ){
++        sqliteFree(*pzErrMsg);
++        *pzErrMsg = 0;
++      }
++    }
++    if( db->file_format<3 ){
++      sqliteSafetyOff(db);
++      sqliteSetString(pzErrMsg, "obsolete database file format", (char*)0);
++      return SQLITE_ERROR;
++    }
++  }
++  assert( (db->flags & SQLITE_Initialized)!=0 || db->init.busy );
++  if( db->pVdbe==0 ){ db->nChange = 0; }
++  memset(&sParse, 0, sizeof(sParse));
++  sParse.db = db;
++  sqliteRunParser(&sParse, zSql, pzErrMsg);
++  if( db->xTrace && !db->init.busy ){
++    /* Trace only the statment that was compiled.
++    ** Make a copy of that part of the SQL string since zSQL is const
++    ** and we must pass a zero terminated string to the trace function
++    ** The copy is unnecessary if the tail pointer is pointing at the
++    ** beginnig or end of the SQL string.
++    */
++    if( sParse.zTail && sParse.zTail!=zSql && *sParse.zTail ){
++      char *tmpSql = sqliteStrNDup(zSql, sParse.zTail - zSql);
++      if( tmpSql ){
++        db->xTrace(db->pTraceArg, tmpSql);
++        free(tmpSql);
++      }else{
++        /* If a memory error occurred during the copy,
++        ** trace entire SQL string and fall through to the
++        ** sqlite_malloc_failed test to report the error.
++        */
++        db->xTrace(db->pTraceArg, zSql); 
++      }
++    }else{
++      db->xTrace(db->pTraceArg, zSql); 
++    }
++  }
++  if( sqlite_malloc_failed ){
++    sqliteSetString(pzErrMsg, "out of memory", (char*)0);
++    sParse.rc = SQLITE_NOMEM;
++    sqliteRollbackAll(db);
++    sqliteResetInternalSchema(db, 0);
++    db->flags &= ~SQLITE_InTrans;
++  }
++  if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
++  if( sParse.rc!=SQLITE_OK && pzErrMsg && *pzErrMsg==0 ){
++    sqliteSetString(pzErrMsg, sqlite_error_string(sParse.rc), (char*)0);
++  }
++  sqliteStrRealloc(pzErrMsg);
++  if( sParse.rc==SQLITE_SCHEMA ){
++    sqliteResetInternalSchema(db, 0);
++  }
++  assert( ppVm );
++  *ppVm = (sqlite_vm*)sParse.pVdbe;
++  if( pzTail ) *pzTail = sParse.zTail;
++  if( sqliteSafetyOff(db) ) goto exec_misuse;
++  return sParse.rc;
++
++exec_misuse:
++  if( pzErrMsg ){
++    *pzErrMsg = 0;
++    sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), (char*)0);
++    sqliteStrRealloc(pzErrMsg);
++  }
++  return SQLITE_MISUSE;
++}
++
++
++/*
++** The following routine destroys a virtual machine that is created by
++** the sqlite_compile() routine.
++**
++** The integer returned is an SQLITE_ success/failure code that describes
++** the result of executing the virtual machine.  An error message is
++** written into memory obtained from malloc and *pzErrMsg is made to
++** point to that error if pzErrMsg is not NULL.  The calling routine
++** should use sqlite_freemem() to delete the message when it has finished
++** with it.
++*/
++int sqlite_finalize(
++  sqlite_vm *pVm,            /* The virtual machine to be destroyed */
++  char **pzErrMsg            /* OUT: Write error messages here */
++){
++  int rc = sqliteVdbeFinalize((Vdbe*)pVm, pzErrMsg);
++  sqliteStrRealloc(pzErrMsg);
++  return rc;
++}
++
++/*
++** Terminate the current execution of a virtual machine then
++** reset the virtual machine back to its starting state so that it
++** can be reused.  Any error message resulting from the prior execution
++** is written into *pzErrMsg.  A success code from the prior execution
++** is returned.
++*/
++int sqlite_reset(
++  sqlite_vm *pVm,            /* The virtual machine to be destroyed */
++  char **pzErrMsg            /* OUT: Write error messages here */
++){
++  int rc = sqliteVdbeReset((Vdbe*)pVm, pzErrMsg);
++  sqliteVdbeMakeReady((Vdbe*)pVm, -1, 0);
++  sqliteStrRealloc(pzErrMsg);
++  return rc;
++}
++
++/*
++** Return a static string that describes the kind of error specified in the
++** argument.
++*/
++const char *sqlite_error_string(int rc){
++  const char *z;
++  switch( rc ){
++    case SQLITE_OK:         z = "not an error";                          break;
++    case SQLITE_ERROR:      z = "SQL logic error or missing database";   break;
++    case SQLITE_INTERNAL:   z = "internal SQLite implementation flaw";   break;
++    case SQLITE_PERM:       z = "access permission denied";              break;
++    case SQLITE_ABORT:      z = "callback requested query abort";        break;
++    case SQLITE_BUSY:       z = "database is locked";                    break;
++    case SQLITE_LOCKED:     z = "database table is locked";              break;
++    case SQLITE_NOMEM:      z = "out of memory";                         break;
++    case SQLITE_READONLY:   z = "attempt to write a readonly database";  break;
++    case SQLITE_INTERRUPT:  z = "interrupted";                           break;
++    case SQLITE_IOERR:      z = "disk I/O error";                        break;
++    case SQLITE_CORRUPT:    z = "database disk image is malformed";      break;
++    case SQLITE_NOTFOUND:   z = "table or record not found";             break;
++    case SQLITE_FULL:       z = "database 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 = "too much data for one table row";       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;
++    case SQLITE_NOLFS:      z = "kernel lacks large file support";       break;
++    case SQLITE_AUTH:       z = "authorization denied";                  break;
++    case SQLITE_FORMAT:     z = "auxiliary database format error";       break;
++    case SQLITE_RANGE:      z = "bind index out of range";               break;
++    case SQLITE_NOTADB:     z = "file is encrypted or is not a database";break;
++    default:                z = "unknown error";                         break;
++  }
++  return z;
++}
++
++/*
++** This routine implements a busy callback that sleeps and tries
++** again until a timeout value is reached.  The timeout value is
++** an integer number of milliseconds passed in as the first
++** argument.
++*/
++static int sqliteDefaultBusyCallback(
++ void *Timeout,           /* Maximum amount of time to wait */
++ const char *NotUsed,     /* The name of the table that is busy */
++ int count                /* Number of times table has been busy */
++){
++#if SQLITE_MIN_SLEEP_MS==1
++  static const char delays[] =
++     { 1, 2, 5, 10, 15, 20, 25, 25,  25,  50,  50,  50, 100};
++  static const short int totals[] =
++     { 0, 1, 3,  8, 18, 33, 53, 78, 103, 128, 178, 228, 287};
++# define NDELAY (sizeof(delays)/sizeof(delays[0]))
++  int timeout = (int)(long)Timeout;
++  int delay, prior;
++
++  if( count <= NDELAY ){
++    delay = delays[count-1];
++    prior = totals[count-1];
++  }else{
++    delay = delays[NDELAY-1];
++    prior = totals[NDELAY-1] + delay*(count-NDELAY-1);
++  }
++  if( prior + delay > timeout ){
++    delay = timeout - prior;
++    if( delay<=0 ) return 0;
++  }
++  sqliteOsSleep(delay);
++  return 1;
++#else
++  int timeout = (int)(long)Timeout;
++  if( (count+1)*1000 > timeout ){
++    return 0;
++  }
++  sqliteOsSleep(1000);
++  return 1;
++#endif
++}
++
++/*
++** This routine sets the busy callback for an Sqlite database to the
++** given callback function with the given argument.
++*/
++void sqlite_busy_handler(
++  sqlite *db,
++  int (*xBusy)(void*,const char*,int),
++  void *pArg
++){
++  db->xBusyCallback = xBusy;
++  db->pBusyArg = pArg;
++}
++
++#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
++/*
++** This routine sets the progress callback for an Sqlite database to the
++** given callback function with the given argument. The progress callback will
++** be invoked every nOps opcodes.
++*/
++void sqlite_progress_handler(
++  sqlite *db, 
++  int nOps,
++  int (*xProgress)(void*), 
++  void *pArg
++){
++  if( nOps>0 ){
++    db->xProgress = xProgress;
++    db->nProgressOps = nOps;
++    db->pProgressArg = pArg;
++  }else{
++    db->xProgress = 0;
++    db->nProgressOps = 0;
++    db->pProgressArg = 0;
++  }
++}
++#endif
++
++
++/*
++** This routine installs a default busy handler that waits for the
++** specified number of milliseconds before returning 0.
++*/
++void sqlite_busy_timeout(sqlite *db, int ms){
++  if( ms>0 ){
++    sqlite_busy_handler(db, sqliteDefaultBusyCallback, (void*)(long)ms);
++  }else{
++    sqlite_busy_handler(db, 0, 0);
++  }
++}
++
++/*
++** Cause any pending operation to stop at its earliest opportunity.
++*/
++void sqlite_interrupt(sqlite *db){
++  db->flags |= SQLITE_Interrupt;
++}
++
++/*
++** Windows systems should call this routine to free memory that
++** is returned in the in the errmsg parameter of sqlite_open() when
++** SQLite is a DLL.  For some reason, it does not work to call free()
++** directly.
++**
++** Note that we need to call free() not sqliteFree() here, since every
++** string that is exported from SQLite should have already passed through
++** sqliteStrRealloc().
++*/
++void sqlite_freemem(void *p){ free(p); }
++
++/*
++** Windows systems need functions to call to return the sqlite_version
++** and sqlite_encoding strings since they are unable to access constants
++** within DLLs.
++*/
++const char *sqlite_libversion(void){ return sqlite_version; }
++const char *sqlite_libencoding(void){ return sqlite_encoding; }
++
++/*
++** Create new user-defined functions.  The sqlite_create_function()
++** routine creates a regular function and sqlite_create_aggregate()
++** creates an aggregate function.
++**
++** Passing a NULL xFunc argument or NULL xStep and xFinalize arguments
++** disables the function.  Calling sqlite_create_function() with the
++** same name and number of arguments as a prior call to
++** sqlite_create_aggregate() disables the prior call to
++** sqlite_create_aggregate(), and vice versa.
++**
++** If nArg is -1 it means that this function will accept any number
++** of arguments, including 0.  The maximum allowed value of nArg is 127.
++*/
++int sqlite_create_function(
++  sqlite *db,          /* Add the function to this database connection */
++  const char *zName,   /* Name of the function to add */
++  int nArg,            /* Number of arguments */
++  void (*xFunc)(sqlite_func*,int,const char**),  /* The implementation */
++  void *pUserData      /* User data */
++){
++  FuncDef *p;
++  int nName;
++  if( db==0 || zName==0 || sqliteSafetyCheck(db) ) return 1;
++  if( nArg<-1 || nArg>127 ) return 1;
++  nName = strlen(zName);
++  if( nName>255 ) return 1;
++  p = sqliteFindFunction(db, zName, nName, nArg, 1);
++  if( p==0 ) return 1;
++  p->xFunc = xFunc;
++  p->xStep = 0;
++  p->xFinalize = 0;
++  p->pUserData = pUserData;
++  return 0;
++}
++int sqlite_create_aggregate(
++  sqlite *db,          /* Add the function to this database connection */
++  const char *zName,   /* Name of the function to add */
++  int nArg,            /* Number of arguments */
++  void (*xStep)(sqlite_func*,int,const char**), /* The step function */
++  void (*xFinalize)(sqlite_func*),              /* The finalizer */
++  void *pUserData      /* User data */
++){
++  FuncDef *p;
++  int nName;
++  if( db==0 || zName==0 || sqliteSafetyCheck(db) ) return 1;
++  if( nArg<-1 || nArg>127 ) return 1;
++  nName = strlen(zName);
++  if( nName>255 ) return 1;
++  p = sqliteFindFunction(db, zName, nName, nArg, 1);
++  if( p==0 ) return 1;
++  p->xFunc = 0;
++  p->xStep = xStep;
++  p->xFinalize = xFinalize;
++  p->pUserData = pUserData;
++  return 0;
++}
++
++/*
++** Change the datatype for all functions with a given name.  See the
++** header comment for the prototype of this function in sqlite.h for
++** additional information.
++*/
++int sqlite_function_type(sqlite *db, const char *zName, int dataType){
++  FuncDef *p = (FuncDef*)sqliteHashFind(&db->aFunc, zName, strlen(zName));
++  while( p ){
++    p->dataType = dataType; 
++    p = p->pNext;
++  }
++  return SQLITE_OK;
++}
++
++/*
++** Register a trace function.  The pArg from the previously registered trace
++** is returned.  
++**
++** A NULL trace function means that no tracing is executes.  A non-NULL
++** trace is a pointer to a function that is invoked at the start of each
++** sqlite_exec().
++*/
++void *sqlite_trace(sqlite *db, void (*xTrace)(void*,const char*), void *pArg){
++  void *pOld = db->pTraceArg;
++  db->xTrace = xTrace;
++  db->pTraceArg = pArg;
++  return pOld;
++}
++
++/*** EXPERIMENTAL ***
++**
++** Register a function to be invoked when a transaction comments.
++** If either function returns non-zero, then the commit becomes a
++** rollback.
++*/
++void *sqlite_commit_hook(
++  sqlite *db,               /* Attach the hook to this database */
++  int (*xCallback)(void*),  /* Function to invoke on each commit */
++  void *pArg                /* Argument to the function */
++){
++  void *pOld = db->pCommitArg;
++  db->xCommitCallback = xCallback;
++  db->pCommitArg = pArg;
++  return pOld;
++}
++
++
++/*
++** This routine is called to create a connection to a database BTree
++** driver.  If zFilename is the name of a file, then that file is
++** opened and used.  If zFilename is the magic name ":memory:" then
++** the database is stored in memory (and is thus forgotten as soon as
++** the connection is closed.)  If zFilename is NULL then the database
++** is for temporary use only and is deleted as soon as the connection
++** is closed.
++**
++** A temporary database can be either a disk file (that is automatically
++** deleted when the file is closed) or a set of red-black trees held in memory,
++** depending on the values of the TEMP_STORE compile-time macro and the
++** db->temp_store variable, according to the following chart:
++**
++**       TEMP_STORE     db->temp_store     Location of temporary database
++**       ----------     --------------     ------------------------------
++**           0               any             file
++**           1                1              file
++**           1                2              memory
++**           1                0              file
++**           2                1              file
++**           2                2              memory
++**           2                0              memory
++**           3               any             memory
++*/
++int sqliteBtreeFactory(
++  const sqlite *db,       /* Main database when opening aux otherwise 0 */
++  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 */
++  Btree **ppBtree){         /* Pointer to new Btree object written here */
++
++  assert( ppBtree != 0);
++
++#ifndef SQLITE_OMIT_INMEMORYDB
++  if( zFilename==0 ){
++    if (TEMP_STORE == 0) {
++      /* Always use file based temporary DB */
++      return sqliteBtreeOpen(0, omitJournal, nCache, ppBtree);
++    } else if (TEMP_STORE == 1 || TEMP_STORE == 2) {
++      /* Switch depending on compile-time and/or runtime settings. */
++      int location = db->temp_store==0 ? TEMP_STORE : db->temp_store;
++
++      if (location == 1) {
++        return sqliteBtreeOpen(zFilename, omitJournal, nCache, ppBtree);
++      } else {
++        return sqliteRbtreeOpen(0, 0, 0, ppBtree);
++      }
++    } else {
++      /* Always use in-core DB */
++      return sqliteRbtreeOpen(0, 0, 0, ppBtree);
++    }
++  }else if( zFilename[0]==':' && strcmp(zFilename,":memory:")==0 ){
++    return sqliteRbtreeOpen(0, 0, 0, ppBtree);
++  }else
++#endif
++  {
++    return sqliteBtreeOpen(zFilename, omitJournal, nCache, ppBtree);
++  }
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/opcodes.c
+@@ -0,0 +1,140 @@
++/* Automatically generated file.  Do not edit */
++char *sqliteOpcodeNames[] = { "???", 
++  "Goto", 
++  "Gosub", 
++  "Return", 
++  "Halt", 
++  "Integer", 
++  "String", 
++  "Variable", 
++  "Pop", 
++  "Dup", 
++  "Pull", 
++  "Push", 
++  "ColumnName", 
++  "Callback", 
++  "Concat", 
++  "Add", 
++  "Subtract", 
++  "Multiply", 
++  "Divide", 
++  "Remainder", 
++  "Function", 
++  "BitAnd", 
++  "BitOr", 
++  "ShiftLeft", 
++  "ShiftRight", 
++  "AddImm", 
++  "ForceInt", 
++  "MustBeInt", 
++  "Eq", 
++  "Ne", 
++  "Lt", 
++  "Le", 
++  "Gt", 
++  "Ge", 
++  "StrEq", 
++  "StrNe", 
++  "StrLt", 
++  "StrLe", 
++  "StrGt", 
++  "StrGe", 
++  "And", 
++  "Or", 
++  "Negative", 
++  "AbsValue", 
++  "Not", 
++  "BitNot", 
++  "Noop", 
++  "If", 
++  "IfNot", 
++  "IsNull", 
++  "NotNull", 
++  "MakeRecord", 
++  "MakeIdxKey", 
++  "MakeKey", 
++  "IncrKey", 
++  "Checkpoint", 
++  "Transaction", 
++  "Commit", 
++  "Rollback", 
++  "ReadCookie", 
++  "SetCookie", 
++  "VerifyCookie", 
++  "OpenRead", 
++  "OpenWrite", 
++  "OpenTemp", 
++  "OpenPseudo", 
++  "Close", 
++  "MoveLt", 
++  "MoveTo", 
++  "Distinct", 
++  "NotFound", 
++  "Found", 
++  "IsUnique", 
++  "NotExists", 
++  "NewRecno", 
++  "PutIntKey", 
++  "PutStrKey", 
++  "Delete", 
++  "SetCounts", 
++  "KeyAsData", 
++  "RowKey", 
++  "RowData", 
++  "Column", 
++  "Recno", 
++  "FullKey", 
++  "NullRow", 
++  "Last", 
++  "Rewind", 
++  "Prev", 
++  "Next", 
++  "IdxPut", 
++  "IdxDelete", 
++  "IdxRecno", 
++  "IdxLT", 
++  "IdxGT", 
++  "IdxGE", 
++  "IdxIsNull", 
++  "Destroy", 
++  "Clear", 
++  "CreateIndex", 
++  "CreateTable", 
++  "IntegrityCk", 
++  "ListWrite", 
++  "ListRewind", 
++  "ListRead", 
++  "ListReset", 
++  "ListPush", 
++  "ListPop", 
++  "ContextPush", 
++  "ContextPop", 
++  "SortPut", 
++  "SortMakeRec", 
++  "SortMakeKey", 
++  "Sort", 
++  "SortNext", 
++  "SortCallback", 
++  "SortReset", 
++  "FileOpen", 
++  "FileRead", 
++  "FileColumn", 
++  "MemStore", 
++  "MemLoad", 
++  "MemIncr", 
++  "AggReset", 
++  "AggInit", 
++  "AggFunc", 
++  "AggFocus", 
++  "AggSet", 
++  "AggGet", 
++  "AggNext", 
++  "SetInsert", 
++  "SetFound", 
++  "SetNotFound", 
++  "SetFirst", 
++  "SetNext", 
++  "Vacuum", 
++  "StackDepth", 
++  "StackReset", 
++};
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/opcodes.h
+@@ -0,0 +1,138 @@
++/* Automatically generated file.  Do not edit */
++#define OP_Goto                          1
++#define OP_Gosub                         2
++#define OP_Return                        3
++#define OP_Halt                          4
++#define OP_Integer                       5
++#define OP_String                        6
++#define OP_Variable                      7
++#define OP_Pop                           8
++#define OP_Dup                           9
++#define OP_Pull                         10
++#define OP_Push                         11
++#define OP_ColumnName                   12
++#define OP_Callback                     13
++#define OP_Concat                       14
++#define OP_Add                          15
++#define OP_Subtract                     16
++#define OP_Multiply                     17
++#define OP_Divide                       18
++#define OP_Remainder                    19
++#define OP_Function                     20
++#define OP_BitAnd                       21
++#define OP_BitOr                        22
++#define OP_ShiftLeft                    23
++#define OP_ShiftRight                   24
++#define OP_AddImm                       25
++#define OP_ForceInt                     26
++#define OP_MustBeInt                    27
++#define OP_Eq                           28
++#define OP_Ne                           29
++#define OP_Lt                           30
++#define OP_Le                           31
++#define OP_Gt                           32
++#define OP_Ge                           33
++#define OP_StrEq                        34
++#define OP_StrNe                        35
++#define OP_StrLt                        36
++#define OP_StrLe                        37
++#define OP_StrGt                        38
++#define OP_StrGe                        39
++#define OP_And                          40
++#define OP_Or                           41
++#define OP_Negative                     42
++#define OP_AbsValue                     43
++#define OP_Not                          44
++#define OP_BitNot                       45
++#define OP_Noop                         46
++#define OP_If                           47
++#define OP_IfNot                        48
++#define OP_IsNull                       49
++#define OP_NotNull                      50
++#define OP_MakeRecord                   51
++#define OP_MakeIdxKey                   52
++#define OP_MakeKey                      53
++#define OP_IncrKey                      54
++#define OP_Checkpoint                   55
++#define OP_Transaction                  56
++#define OP_Commit                       57
++#define OP_Rollback                     58
++#define OP_ReadCookie                   59
++#define OP_SetCookie                    60
++#define OP_VerifyCookie                 61
++#define OP_OpenRead                     62
++#define OP_OpenWrite                    63
++#define OP_OpenTemp                     64
++#define OP_OpenPseudo                   65
++#define OP_Close                        66
++#define OP_MoveLt                       67
++#define OP_MoveTo                       68
++#define OP_Distinct                     69
++#define OP_NotFound                     70
++#define OP_Found                        71
++#define OP_IsUnique                     72
++#define OP_NotExists                    73
++#define OP_NewRecno                     74
++#define OP_PutIntKey                    75
++#define OP_PutStrKey                    76
++#define OP_Delete                       77
++#define OP_SetCounts                    78
++#define OP_KeyAsData                    79
++#define OP_RowKey                       80
++#define OP_RowData                      81
++#define OP_Column                       82
++#define OP_Recno                        83
++#define OP_FullKey                      84
++#define OP_NullRow                      85
++#define OP_Last                         86
++#define OP_Rewind                       87
++#define OP_Prev                         88
++#define OP_Next                         89
++#define OP_IdxPut                       90
++#define OP_IdxDelete                    91
++#define OP_IdxRecno                     92
++#define OP_IdxLT                        93
++#define OP_IdxGT                        94
++#define OP_IdxGE                        95
++#define OP_IdxIsNull                    96
++#define OP_Destroy                      97
++#define OP_Clear                        98
++#define OP_CreateIndex                  99
++#define OP_CreateTable                 100
++#define OP_IntegrityCk                 101
++#define OP_ListWrite                   102
++#define OP_ListRewind                  103
++#define OP_ListRead                    104
++#define OP_ListReset                   105
++#define OP_ListPush                    106
++#define OP_ListPop                     107
++#define OP_ContextPush                 108
++#define OP_ContextPop                  109
++#define OP_SortPut                     110
++#define OP_SortMakeRec                 111
++#define OP_SortMakeKey                 112
++#define OP_Sort                        113
++#define OP_SortNext                    114
++#define OP_SortCallback                115
++#define OP_SortReset                   116
++#define OP_FileOpen                    117
++#define OP_FileRead                    118
++#define OP_FileColumn                  119
++#define OP_MemStore                    120
++#define OP_MemLoad                     121
++#define OP_MemIncr                     122
++#define OP_AggReset                    123
++#define OP_AggInit                     124
++#define OP_AggFunc                     125
++#define OP_AggFocus                    126
++#define OP_AggSet                      127
++#define OP_AggGet                      128
++#define OP_AggNext                     129
++#define OP_SetInsert                   130
++#define OP_SetFound                    131
++#define OP_SetNotFound                 132
++#define OP_SetFirst                    133
++#define OP_SetNext                     134
++#define OP_Vacuum                      135
++#define OP_StackDepth                  136
++#define OP_StackReset                  137
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/os.c
+@@ -0,0 +1,1850 @@
++/*
++** 2001 September 16
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++******************************************************************************
++**
++** This file contains code that is specific to particular operating
++** systems.  The purpose of this file is to provide a uniform abstraction
++** on which the rest of SQLite can operate.
++*/
++#include "os.h"          /* Must be first to enable large file support */
++#include "sqliteInt.h"
++
++#if OS_UNIX
++# include <time.h>
++# include <errno.h>
++# include <unistd.h>
++# ifndef O_LARGEFILE
++#  define O_LARGEFILE 0
++# endif
++# ifdef SQLITE_DISABLE_LFS
++#  undef O_LARGEFILE
++#  define O_LARGEFILE 0
++# endif
++# ifndef O_NOFOLLOW
++#  define O_NOFOLLOW 0
++# endif
++# ifndef O_BINARY
++#  define O_BINARY 0
++# endif
++#endif
++
++
++#if OS_WIN
++# include <winbase.h>
++#endif
++
++#if OS_MAC
++# include <extras.h>
++# include <path2fss.h>
++# include <TextUtils.h>
++# include <FinderRegistry.h>
++# include <Folders.h>
++# include <Timer.h>
++# include <OSUtils.h>
++#endif
++
++/*
++** The DJGPP compiler environment looks mostly like Unix, but it
++** lacks the fcntl() system call.  So redefine fcntl() to be something
++** that always succeeds.  This means that locking does not occur under
++** DJGPP.  But its DOS - what did you expect?
++*/
++#ifdef __DJGPP__
++# define fcntl(A,B,C) 0
++#endif
++
++/*
++** Macros used to determine whether or not to use threads.  The
++** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for
++** Posix threads and SQLITE_W32_THREADS is defined if we are
++** synchronizing using Win32 threads.
++*/
++#if OS_UNIX && defined(THREADSAFE) && THREADSAFE
++# include <pthread.h>
++# define SQLITE_UNIX_THREADS 1
++#endif
++#if OS_WIN && defined(THREADSAFE) && THREADSAFE
++# define SQLITE_W32_THREADS 1
++#endif
++#if OS_MAC && defined(THREADSAFE) && THREADSAFE
++# include <Multiprocessing.h>
++# define SQLITE_MACOS_MULTITASKING 1
++#endif
++
++/*
++** Macros for performance tracing.  Normally turned off
++*/
++#if 0
++static int last_page = 0;
++__inline__ unsigned long long int hwtime(void){
++  unsigned long long int x;
++  __asm__("rdtsc\n\t"
++          "mov %%edx, %%ecx\n\t"
++          :"=A" (x));
++  return x;
++}
++static unsigned long long int g_start;
++static unsigned int elapse;
++#define TIMER_START       g_start=hwtime()
++#define TIMER_END         elapse=hwtime()-g_start
++#define SEEK(X)           last_page=(X)
++#define TRACE1(X)         fprintf(stderr,X)
++#define TRACE2(X,Y)       fprintf(stderr,X,Y)
++#define TRACE3(X,Y,Z)     fprintf(stderr,X,Y,Z)
++#define TRACE4(X,Y,Z,A)   fprintf(stderr,X,Y,Z,A)
++#define TRACE5(X,Y,Z,A,B) fprintf(stderr,X,Y,Z,A,B)
++#else
++#define TIMER_START
++#define TIMER_END
++#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)
++#endif
++
++
++#if OS_UNIX
++/*
++** Here is the dirt on POSIX advisory locks:  ANSI STD 1003.1 (1996)
++** section 6.5.2.2 lines 483 through 490 specify that when a process
++** sets or clears a lock, that operation overrides any prior locks set
++** by the same process.  It does not explicitly say so, but this implies
++** that it overrides locks set by the same process using a different
++** file descriptor.  Consider this test case:
++**
++**       int fd1 = open("./file1", O_RDWR|O_CREAT, 0644);
++**       int fd2 = open("./file2", O_RDWR|O_CREAT, 0644);
++**
++** Suppose ./file1 and ./file2 are really the same file (because
++** one is a hard or symbolic link to the other) then if you set
++** an exclusive lock on fd1, then try to get an exclusive lock
++** on fd2, it works.  I would have expected the second lock to
++** fail since there was already a lock on the file due to fd1.
++** But not so.  Since both locks came from the same process, the
++** second overrides the first, even though they were on different
++** file descriptors opened on different file names.
++**
++** Bummer.  If you ask me, this is broken.  Badly broken.  It means
++** that we cannot use POSIX locks to synchronize file access among
++** competing threads of the same process.  POSIX locks will work fine
++** to synchronize access for threads in separate processes, but not
++** threads within the same process.
++**
++** To work around the problem, SQLite has to manage file locks internally
++** on its own.  Whenever a new database is opened, we have to find the
++** specific inode of the database file (the inode is determined by the
++** st_dev and st_ino fields of the stat structure that fstat() fills in)
++** and check for locks already existing on that inode.  When locks are
++** created or removed, we have to look at our own internal record of the
++** 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
++** 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
++** 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
++** file is unlocked.  cnt==-1 means the file has an exclusive lock.
++** cnt>0 means there are cnt shared locks on the file.
++**
++** Any attempt to lock or unlock a file first checks the locking
++** structure.  The fcntl() system call is only invoked to set a 
++** POSIX lock if the internal lock structure transitions between
++** a locked and an unlocked state.
++**
++** 2004-Jan-11:
++** More recent discoveries about POSIX advisory locks.  (The more
++** I discover, the more I realize the a POSIX advisory locks are
++** an abomination.)
++**
++** 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
++** 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
++** 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
++** clears.
++**
++** First, under Linux threads, because each thread has a separate
++** process ID, lock operations in one thread do not override locks
++** to the same file in other threads.  Linux threads behave like
++** separate processes in this respect.  But, if you close a file
++** descriptor in linux threads, all locks are cleared, even locks
++** on other threads and even though the other threads have different
++** process IDs.  Linux threads is inconsistent in this respect.
++** (I'm beginning to think that linux threads is an abomination too.)
++** The consequence of this all is that the hash table for the lockInfo
++** structure has to include the process id as part of its key because
++** locks in different threads are treated as distinct.  But the 
++** openCnt structure should not include the process id in its
++** key because close() clears lock on all threads, not just the current
++** thread.  Were it not for this goofiness in linux threads, we could
++** combine the lockInfo and openCnt structures into a single structure.
++*/
++
++/*
++** An instance of the following structure serves as the key used
++** to locate a particular lockInfo structure given its inode.  Note
++** that we have to include the process ID as part of the key.  On some
++** threading implementations (ex: linux), each thread has a separate
++** process ID.
++*/
++struct lockKey {
++  dev_t dev;   /* Device number */
++  ino_t ino;   /* Inode number */
++  pid_t pid;   /* Process ID */
++};
++
++/*
++** An instance of the following structure is allocated for each open
++** 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
++** structure contains a pointer to an instance of this object and this
++** object keeps a count of the number of OsFiles pointing to it.
++*/
++struct lockInfo {
++  struct lockKey key;  /* The lookup key */
++  int cnt;             /* 0: unlocked.  -1: write lock.  1...: read lock. */
++  int nRef;            /* Number of pointers to this structure */
++};
++
++/*
++** An instance of the following structure serves as the key used
++** to locate a particular openCnt structure given its inode.  This
++** is the same as the lockKey except that the process ID is omitted.
++*/
++struct openKey {
++  dev_t dev;   /* Device number */
++  ino_t ino;   /* Inode number */
++};
++
++/*
++** An instance of the following structure is allocated for each open
++** inode.  This structure keeps track of the number of locks on that
++** inode.  If a close is attempted against an inode that is holding
++** locks, the close is deferred until all locks clear by adding the
++** file descriptor to be closed to the pending list.
++*/
++struct openCnt {
++  struct openKey key;   /* The lookup key */
++  int nRef;             /* Number of pointers to this structure */
++  int nLock;            /* Number of outstanding locks */
++  int nPending;         /* Number of pending close() operations */
++  int *aPending;        /* Malloced space holding fd's awaiting a close() */
++};
++
++/* 
++** These hash table maps inodes and process IDs into lockInfo and openCnt
++** structures.  Access to these hash tables must be protected by a mutex.
++*/
++static Hash lockHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
++static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
++
++/*
++** Release a lockInfo structure previously allocated by findLockInfo().
++*/
++static void releaseLockInfo(struct lockInfo *pLock){
++  pLock->nRef--;
++  if( pLock->nRef==0 ){
++    sqliteHashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0);
++    sqliteFree(pLock);
++  }
++}
++
++/*
++** Release a openCnt structure previously allocated by findLockInfo().
++*/
++static void releaseOpenCnt(struct openCnt *pOpen){
++  pOpen->nRef--;
++  if( pOpen->nRef==0 ){
++    sqliteHashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0);
++    sqliteFree(pOpen->aPending);
++    sqliteFree(pOpen);
++  }
++}
++
++/*
++** Given a file descriptor, locate lockInfo and openCnt structures that
++** describes that file descriptor.  Create a new ones if necessary.  The
++** return values might be unset if an error occurs.
++**
++** Return the number of errors.
++*/
++int findLockInfo(
++  int fd,                      /* The file descriptor used in the key */
++  struct lockInfo **ppLock,    /* Return the lockInfo structure here */
++  struct openCnt **ppOpen   /* Return the openCnt structure here */
++){
++  int rc;
++  struct lockKey key1;
++  struct openKey key2;
++  struct stat statbuf;
++  struct lockInfo *pLock;
++  struct openCnt *pOpen;
++  rc = fstat(fd, &statbuf);
++  if( rc!=0 ) return 1;
++  memset(&key1, 0, sizeof(key1));
++  key1.dev = statbuf.st_dev;
++  key1.ino = statbuf.st_ino;
++  key1.pid = getpid();
++  memset(&key2, 0, sizeof(key2));
++  key2.dev = statbuf.st_dev;
++  key2.ino = statbuf.st_ino;
++  pLock = (struct lockInfo*)sqliteHashFind(&lockHash, &key1, sizeof(key1));
++  if( pLock==0 ){
++    struct lockInfo *pOld;
++    pLock = sqliteMallocRaw( sizeof(*pLock) );
++    if( pLock==0 ) return 1;
++    pLock->key = key1;
++    pLock->nRef = 1;
++    pLock->cnt = 0;
++    pOld = sqliteHashInsert(&lockHash, &pLock->key, sizeof(key1), pLock);
++    if( pOld!=0 ){
++      assert( pOld==pLock );
++      sqliteFree(pLock);
++      return 1;
++    }
++  }else{
++    pLock->nRef++;
++  }
++  *ppLock = pLock;
++  pOpen = (struct openCnt*)sqliteHashFind(&openHash, &key2, sizeof(key2));
++  if( pOpen==0 ){
++    struct openCnt *pOld;
++    pOpen = sqliteMallocRaw( sizeof(*pOpen) );
++    if( pOpen==0 ){
++      releaseLockInfo(pLock);
++      return 1;
++    }
++    pOpen->key = key2;
++    pOpen->nRef = 1;
++    pOpen->nLock = 0;
++    pOpen->nPending = 0;
++    pOpen->aPending = 0;
++    pOld = sqliteHashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen);
++    if( pOld!=0 ){
++      assert( pOld==pOpen );
++      sqliteFree(pOpen);
++      releaseLockInfo(pLock);
++      return 1;
++    }
++  }else{
++    pOpen->nRef++;
++  }
++  *ppOpen = pOpen;
++  return 0;
++}
++
++#endif  /** POSIX advisory lock work-around **/
++
++/*
++** If we compile with the SQLITE_TEST macro set, then the following block
++** of code will give us the ability to simulate a disk I/O error.  This
++** is used for testing the I/O recovery logic.
++*/
++#ifdef SQLITE_TEST
++int sqlite_io_error_pending = 0;
++#define SimulateIOError(A)  \
++   if( sqlite_io_error_pending ) \
++     if( sqlite_io_error_pending-- == 1 ){ local_ioerr(); return A; }
++static void local_ioerr(){
++  sqlite_io_error_pending = 0;  /* Really just a place to set a breakpoint */
++}
++#else
++#define SimulateIOError(A)
++#endif
++
++/*
++** When testing, keep a count of the number of open files.
++*/
++#ifdef SQLITE_TEST
++int sqlite_open_file_count = 0;
++#define OpenCounter(X)  sqlite_open_file_count+=(X)
++#else
++#define OpenCounter(X)
++#endif
++
++
++/*
++** Delete the named file
++*/
++int sqliteOsDelete(const char *zFilename){
++#if OS_UNIX
++  unlink(zFilename);
++#endif
++#if OS_WIN
++  DeleteFile(zFilename);
++#endif
++#if OS_MAC
++  unlink(zFilename);
++#endif
++  return SQLITE_OK;
++}
++
++/*
++** Return TRUE if the named file exists.
++*/
++int sqliteOsFileExists(const char *zFilename){
++#if OS_UNIX
++  return access(zFilename, 0)==0;
++#endif
++#if OS_WIN
++  return GetFileAttributes(zFilename) != 0xffffffff;
++#endif
++#if OS_MAC
++  return access(zFilename, 0)==0;
++#endif
++}
++
++
++#if 0 /* NOT USED */
++/*
++** Change the name of an existing file.
++*/
++int sqliteOsFileRename(const char *zOldName, const char *zNewName){
++#if OS_UNIX
++  if( link(zOldName, zNewName) ){
++    return SQLITE_ERROR;
++  }
++  unlink(zOldName);
++  return SQLITE_OK;
++#endif
++#if OS_WIN
++  if( !MoveFile(zOldName, zNewName) ){
++    return SQLITE_ERROR;
++  }
++  return SQLITE_OK;
++#endif
++#if OS_MAC
++  /**** FIX ME ***/
++  return SQLITE_ERROR;
++#endif
++}
++#endif /* NOT USED */
++
++/*
++** 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 sqliteOsOpenReadWrite(
++  const char *zFilename,
++  OsFile *id,
++  int *pReadonly
++){
++#if OS_UNIX
++  int rc;
++  id->dirfd = -1;
++  id->fd = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, 0644);
++  if( id->fd<0 ){
++#ifdef EISDIR
++    if( errno==EISDIR ){
++      return SQLITE_CANTOPEN;
++    }
++#endif
++    id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
++    if( id->fd<0 ){
++      return SQLITE_CANTOPEN; 
++    }
++    *pReadonly = 1;
++  }else{
++    *pReadonly = 0;
++  }
++  sqliteOsEnterMutex();
++  rc = findLockInfo(id->fd, &id->pLock, &id->pOpen);
++  sqliteOsLeaveMutex();
++  if( rc ){
++    close(id->fd);
++    return SQLITE_NOMEM;
++  }
++  id->locked = 0;
++  TRACE3("OPEN    %-3d %s\n", id->fd, zFilename);
++  OpenCounter(+1);
++  return SQLITE_OK;
++#endif
++#if OS_WIN
++  HANDLE h = CreateFile(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 = CreateFile(zFilename,
++       GENERIC_READ,
++       FILE_SHARE_READ,
++       NULL,
++       OPEN_ALWAYS,
++       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
++       NULL
++    );
++    if( h==INVALID_HANDLE_VALUE ){
++      return SQLITE_CANTOPEN;
++    }
++    *pReadonly = 1;
++  }else{
++    *pReadonly = 0;
++  }
++  id->h = h;
++  id->locked = 0;
++  OpenCounter(+1);
++  return SQLITE_OK;
++#endif
++#if OS_MAC
++  FSSpec fsSpec;
++# ifdef _LARGE_FILE
++  HFSUniStr255 dfName;
++  FSRef fsRef;
++  if( __path2fss(zFilename, &fsSpec) != noErr ){
++    if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
++      return SQLITE_CANTOPEN;
++  }
++  if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
++    return SQLITE_CANTOPEN;
++  FSGetDataForkName(&dfName);
++  if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
++                 fsRdWrShPerm, &(id->refNum)) != noErr ){
++    if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
++                   fsRdWrPerm, &(id->refNum)) != noErr ){
++      if (FSOpenFork(&fsRef, dfName.length, dfName.unicode,
++                   fsRdPerm, &(id->refNum)) != noErr )
++        return SQLITE_CANTOPEN;
++      else
++        *pReadonly = 1;
++    } else
++      *pReadonly = 0;
++  } else
++    *pReadonly = 0;
++# else
++  __path2fss(zFilename, &fsSpec);
++  if( !sqliteOsFileExists(zFilename) ){
++    if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
++      return SQLITE_CANTOPEN;
++  }
++  if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNum)) != noErr ){
++    if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr ){
++      if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr )
++        return SQLITE_CANTOPEN;
++      else
++        *pReadonly = 1;
++    } else
++      *pReadonly = 0;
++  } else
++    *pReadonly = 0;
++# endif
++  if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){
++    id->refNumRF = -1;
++  }
++  id->locked = 0;
++  id->delOnClose = 0;
++  OpenCounter(+1);
++  return SQLITE_OK;
++#endif
++}
++
++
++/*
++** 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 sqliteOsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
++#if OS_UNIX
++  int rc;
++  if( access(zFilename, 0)==0 ){
++    return SQLITE_CANTOPEN;
++  }
++  id->dirfd = -1;
++  id->fd = open(zFilename,
++                O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, 0600);
++  if( id->fd<0 ){
++    return SQLITE_CANTOPEN;
++  }
++  sqliteOsEnterMutex();
++  rc = findLockInfo(id->fd, &id->pLock, &id->pOpen);
++  sqliteOsLeaveMutex();
++  if( rc ){
++    close(id->fd);
++    unlink(zFilename);
++    return SQLITE_NOMEM;
++  }
++  id->locked = 0;
++  if( delFlag ){
++    unlink(zFilename);
++  }
++  TRACE3("OPEN-EX %-3d %s\n", id->fd, zFilename);
++  OpenCounter(+1);
++  return SQLITE_OK;
++#endif
++#if OS_WIN
++  HANDLE h;
++  int fileflags;
++  if( delFlag ){
++    fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS 
++                     | FILE_FLAG_DELETE_ON_CLOSE;
++  }else{
++    fileflags = FILE_FLAG_RANDOM_ACCESS;
++  }
++  h = CreateFile(zFilename,
++     GENERIC_READ | GENERIC_WRITE,
++     0,
++     NULL,
++     CREATE_ALWAYS,
++     fileflags,
++     NULL
++  );
++  if( h==INVALID_HANDLE_VALUE ){
++    return SQLITE_CANTOPEN;
++  }
++  id->h = h;
++  id->locked = 0;
++  OpenCounter(+1);
++  return SQLITE_OK;
++#endif
++#if OS_MAC
++  FSSpec fsSpec;
++# ifdef _LARGE_FILE
++  HFSUniStr255 dfName;
++  FSRef fsRef;
++  __path2fss(zFilename, &fsSpec);
++  if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
++    return SQLITE_CANTOPEN;
++  if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
++    return SQLITE_CANTOPEN;
++  FSGetDataForkName(&dfName);
++  if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
++                 fsRdWrPerm, &(id->refNum)) != noErr )
++    return SQLITE_CANTOPEN;
++# else
++  __path2fss(zFilename, &fsSpec);
++  if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
++    return SQLITE_CANTOPEN;
++  if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr )
++    return SQLITE_CANTOPEN;
++# endif
++  id->refNumRF = -1;
++  id->locked = 0;
++  id->delOnClose = delFlag;
++  if (delFlag)
++    id->pathToDel = sqliteOsFullPathname(zFilename);
++  OpenCounter(+1);
++  return SQLITE_OK;
++#endif
++}
++
++/*
++** 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 sqliteOsOpenReadOnly(const char *zFilename, OsFile *id){
++#if OS_UNIX
++  int rc;
++  id->dirfd = -1;
++  id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
++  if( id->fd<0 ){
++    return SQLITE_CANTOPEN;
++  }
++  sqliteOsEnterMutex();
++  rc = findLockInfo(id->fd, &id->pLock, &id->pOpen);
++  sqliteOsLeaveMutex();
++  if( rc ){
++    close(id->fd);
++    return SQLITE_NOMEM;
++  }
++  id->locked = 0;
++  TRACE3("OPEN-RO %-3d %s\n", id->fd, zFilename);
++  OpenCounter(+1);
++  return SQLITE_OK;
++#endif
++#if OS_WIN
++  HANDLE h = CreateFile(zFilename,
++     GENERIC_READ,
++     0,
++     NULL,
++     OPEN_EXISTING,
++     FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
++     NULL
++  );
++  if( h==INVALID_HANDLE_VALUE ){
++    return SQLITE_CANTOPEN;
++  }
++  id->h = h;
++  id->locked = 0;
++  OpenCounter(+1);
++  return SQLITE_OK;
++#endif
++#if OS_MAC
++  FSSpec fsSpec;
++# ifdef _LARGE_FILE
++  HFSUniStr255 dfName;
++  FSRef fsRef;
++  if( __path2fss(zFilename, &fsSpec) != noErr )
++    return SQLITE_CANTOPEN;
++  if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
++    return SQLITE_CANTOPEN;
++  FSGetDataForkName(&dfName);
++  if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
++                 fsRdPerm, &(id->refNum)) != noErr )
++    return SQLITE_CANTOPEN;
++# else
++  __path2fss(zFilename, &fsSpec);
++  if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr )
++    return SQLITE_CANTOPEN;
++# endif
++  if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){
++    id->refNumRF = -1;
++  }
++  id->locked = 0;
++  id->delOnClose = 0;
++  OpenCounter(+1);
++  return SQLITE_OK;
++#endif
++}
++
++/*
++** Attempt to open a file descriptor for the directory that contains a
++** file.  This file descriptor can be used to fsync() the directory
++** in order to make sure the creation of a new file is actually written
++** to disk.
++**
++** This routine is only meaningful for Unix.  It is a no-op under
++** windows since windows does not support hard links.
++**
++** On success, a handle for a previously open file is at *id is
++** updated with the new directory file descriptor and SQLITE_OK is
++** returned.
++**
++** On failure, the function returns SQLITE_CANTOPEN and leaves
++** *id unchanged.
++*/
++int sqliteOsOpenDirectory(
++  const char *zDirname,
++  OsFile *id
++){
++#if OS_UNIX
++  if( id->fd<0 ){
++    /* Do not open the directory if the corresponding file is not already
++    ** open. */
++    return SQLITE_CANTOPEN;
++  }
++  assert( id->dirfd<0 );
++  id->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0644);
++  if( id->dirfd<0 ){
++    return SQLITE_CANTOPEN; 
++  }
++  TRACE3("OPENDIR %-3d %s\n", id->dirfd, zDirname);
++#endif
++  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.
++*/
++const char *sqlite_temp_directory = 0;
++
++/*
++** Create a temporary file name in zBuf.  zBuf must be big enough to
++** hold at least SQLITE_TEMPNAME_SIZE characters.
++*/
++int sqliteOsTempFileName(char *zBuf){
++#if OS_UNIX
++  static const char *azDirs[] = {
++     0,
++     "/var/tmp",
++     "/usr/tmp",
++     "/tmp",
++     ".",
++  };
++  static unsigned char zChars[] =
++    "abcdefghijklmnopqrstuvwxyz"
++    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
++    "0123456789";
++  int i, j;
++  struct stat buf;
++  const char *zDir = ".";
++  azDirs[0] = sqlite_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);
++    sqliteRandomness(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 );
++#endif
++#if OS_WIN
++  static char zChars[] =
++    "abcdefghijklmnopqrstuvwxyz"
++    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
++    "0123456789";
++  int i, j;
++  const char *zDir;
++  char zTempPath[SQLITE_TEMPNAME_SIZE];
++  if( sqlite_temp_directory==0 ){
++    GetTempPath(SQLITE_TEMPNAME_SIZE-30, zTempPath);
++    for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
++    zTempPath[i] = 0;
++    zDir = zTempPath;
++  }else{
++    zDir = sqlite_temp_directory;
++  }
++  for(;;){
++    sprintf(zBuf, "%s\\"TEMP_FILE_PREFIX, zDir);
++    j = strlen(zBuf);
++    sqliteRandomness(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( !sqliteOsFileExists(zBuf) ) break;
++  }
++#endif
++#if OS_MAC
++  static char zChars[] =
++    "abcdefghijklmnopqrstuvwxyz"
++    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
++    "0123456789";
++  int i, j;
++  char *zDir;
++  char zTempPath[SQLITE_TEMPNAME_SIZE];
++  char zdirName[32];
++  CInfoPBRec infoRec;
++  Str31 dirName;
++  memset(&infoRec, 0, sizeof(infoRec));
++  memset(zTempPath, 0, SQLITE_TEMPNAME_SIZE);
++  if( sqlite_temp_directory!=0 ){
++    zDir = sqlite_temp_directory;
++  }else if( FindFolder(kOnSystemDisk, kTemporaryFolderType,  kCreateFolder,
++       &(infoRec.dirInfo.ioVRefNum), &(infoRec.dirInfo.ioDrParID)) == noErr ){
++    infoRec.dirInfo.ioNamePtr = dirName;
++    do{
++      infoRec.dirInfo.ioFDirIndex = -1;
++      infoRec.dirInfo.ioDrDirID = infoRec.dirInfo.ioDrParID;
++      if( PBGetCatInfoSync(&infoRec) == noErr ){
++        CopyPascalStringToC(dirName, zdirName);
++        i = strlen(zdirName);
++        memmove(&(zTempPath[i+1]), zTempPath, strlen(zTempPath));
++        strcpy(zTempPath, zdirName);
++        zTempPath[i] = ':';
++      }else{
++        *zTempPath = 0;
++        break;
++      }
++    } while( infoRec.dirInfo.ioDrDirID != fsRtDirID );
++    zDir = zTempPath;
++  }
++  if( zDir[0]==0 ){
++    getcwd(zTempPath, SQLITE_TEMPNAME_SIZE-24);
++    zDir = zTempPath;
++  }
++  for(;;){
++    sprintf(zBuf, "%s"TEMP_FILE_PREFIX, zDir);
++    j = strlen(zBuf);
++    sqliteRandomness(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( !sqliteOsFileExists(zBuf) ) break;
++  }
++#endif
++  return SQLITE_OK; 
++}
++
++/*
++** Close a file.
++*/
++int sqliteOsClose(OsFile *id){
++#if OS_UNIX
++  sqliteOsUnlock(id);
++  if( id->dirfd>=0 ) close(id->dirfd);
++  id->dirfd = -1;
++  sqliteOsEnterMutex();
++  if( id->pOpen->nLock ){
++    /* If there are outstanding locks, do not actually close the file just
++    ** yet because that would clear those locks.  Instead, add the file
++    ** descriptor to pOpen->aPending.  It will be automatically closed when
++    ** the last lock is cleared.
++    */
++    int *aNew;
++    struct openCnt *pOpen = id->pOpen;
++    pOpen->nPending++;
++    aNew = sqliteRealloc( pOpen->aPending, pOpen->nPending*sizeof(int) );
++    if( aNew==0 ){
++      /* If a malloc fails, just leak the file descriptor */
++    }else{
++      pOpen->aPending = aNew;
++      pOpen->aPending[pOpen->nPending-1] = id->fd;
++    }
++  }else{
++    /* There are no outstanding locks so we can close the file immediately */
++    close(id->fd);
++  }
++  releaseLockInfo(id->pLock);
++  releaseOpenCnt(id->pOpen);
++  sqliteOsLeaveMutex();
++  TRACE2("CLOSE   %-3d\n", id->fd);
++  OpenCounter(-1);
++  return SQLITE_OK;
++#endif
++#if OS_WIN
++  CloseHandle(id->h);
++  OpenCounter(-1);
++  return SQLITE_OK;
++#endif
++#if OS_MAC
++  if( id->refNumRF!=-1 )
++    FSClose(id->refNumRF);
++# ifdef _LARGE_FILE
++  FSCloseFork(id->refNum);
++# else
++  FSClose(id->refNum);
++# endif
++  if( id->delOnClose ){
++    unlink(id->pathToDel);
++    sqliteFree(id->pathToDel);
++  }
++  OpenCounter(-1);
++  return SQLITE_OK;
++#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.
++*/
++int sqliteOsRead(OsFile *id, void *pBuf, int amt){
++#if OS_UNIX
++  int got;
++  SimulateIOError(SQLITE_IOERR);
++  TIMER_START;
++  got = read(id->fd, pBuf, amt);
++  TIMER_END;
++  TRACE4("READ    %-3d %7d %d\n", id->fd, last_page, elapse);
++  SEEK(0);
++  /* if( got<0 ) got = 0; */
++  if( got==amt ){
++    return SQLITE_OK;
++  }else{
++    return SQLITE_IOERR;
++  }
++#endif
++#if OS_WIN
++  DWORD got;
++  SimulateIOError(SQLITE_IOERR);
++  TRACE2("READ %d\n", last_page);
++  if( !ReadFile(id->h, pBuf, amt, &got, 0) ){
++    got = 0;
++  }
++  if( got==(DWORD)amt ){
++    return SQLITE_OK;
++  }else{
++    return SQLITE_IOERR;
++  }
++#endif
++#if OS_MAC
++  int got;
++  SimulateIOError(SQLITE_IOERR);
++  TRACE2("READ %d\n", last_page);
++# ifdef _LARGE_FILE
++  FSReadFork(id->refNum, fsAtMark, 0, (ByteCount)amt, pBuf, (ByteCount*)&got);
++# else
++  got = amt;
++  FSRead(id->refNum, &got, pBuf);
++# endif
++  if( got==amt ){
++    return SQLITE_OK;
++  }else{
++    return SQLITE_IOERR;
++  }
++#endif
++}
++
++/*
++** Write data from a buffer into a file.  Return SQLITE_OK on success
++** or some other error code on failure.
++*/
++int sqliteOsWrite(OsFile *id, const void *pBuf, int amt){
++#if OS_UNIX
++  int wrote = 0;
++  SimulateIOError(SQLITE_IOERR);
++  TIMER_START;
++  while( amt>0 && (wrote = write(id->fd, pBuf, amt))>0 ){
++    amt -= wrote;
++    pBuf = &((char*)pBuf)[wrote];
++  }
++  TIMER_END;
++  TRACE4("WRITE   %-3d %7d %d\n", id->fd, last_page, elapse);
++  SEEK(0);
++  if( amt>0 ){
++    return SQLITE_FULL;
++  }
++  return SQLITE_OK;
++#endif
++#if OS_WIN
++  int rc;
++  DWORD wrote;
++  SimulateIOError(SQLITE_IOERR);
++  TRACE2("WRITE %d\n", last_page);
++  while( amt>0 && (rc = WriteFile(id->h, pBuf, amt, &wrote, 0))!=0 && wrote>0 ){
++    amt -= wrote;
++    pBuf = &((char*)pBuf)[wrote];
++  }
++  if( !rc || amt>(int)wrote ){
++    return SQLITE_FULL;
++  }
++  return SQLITE_OK;
++#endif
++#if OS_MAC
++  OSErr oserr;
++  int wrote = 0;
++  SimulateIOError(SQLITE_IOERR);
++  TRACE2("WRITE %d\n", last_page);
++  while( amt>0 ){
++# ifdef _LARGE_FILE
++    oserr = FSWriteFork(id->refNum, fsAtMark, 0,
++                        (ByteCount)amt, pBuf, (ByteCount*)&wrote);
++# else
++    wrote = amt;
++    oserr = FSWrite(id->refNum, &wrote, pBuf);
++# endif
++    if( wrote == 0 || oserr != noErr)
++      break;
++    amt -= wrote;
++    pBuf = &((char*)pBuf)[wrote];
++  }
++  if( oserr != noErr || amt>wrote ){
++    return SQLITE_FULL;
++  }
++  return SQLITE_OK;
++#endif
++}
++
++/*
++** Move the read/write pointer in a file.
++*/
++int sqliteOsSeek(OsFile *id, off_t offset){
++  SEEK(offset/1024 + 1);
++#if OS_UNIX
++  lseek(id->fd, offset, SEEK_SET);
++  return SQLITE_OK;
++#endif
++#if OS_WIN
++  {
++    LONG upperBits = offset>>32;
++    LONG lowerBits = offset & 0xffffffff;
++    DWORD rc;
++    rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN);
++    /* TRACE3("SEEK rc=0x%x upper=0x%x\n", rc, upperBits); */
++  }
++  return SQLITE_OK;
++#endif
++#if OS_MAC
++  {
++    off_t curSize;
++    if( sqliteOsFileSize(id, &curSize) != SQLITE_OK ){
++      return SQLITE_IOERR;
++    }
++    if( offset >= curSize ){
++      if( sqliteOsTruncate(id, offset+1) != SQLITE_OK ){
++        return SQLITE_IOERR;
++      }
++    }
++# ifdef _LARGE_FILE
++    if( FSSetForkPosition(id->refNum, fsFromStart, offset) != noErr ){
++# else
++    if( SetFPos(id->refNum, fsFromStart, offset) != noErr ){
++# endif
++      return SQLITE_IOERR;
++    }else{
++      return SQLITE_OK;
++    }
++  }
++#endif
++}
++
++#ifdef SQLITE_NOSYNC
++# define fsync(X) 0
++#endif
++
++/*
++** Make sure all writes to a particular file are committed to disk.
++**
++** Under Unix, also make sure that the directory entry for the file
++** has been created by fsync-ing the directory that contains the file.
++** If we do not do this and we encounter a power failure, the directory
++** entry for the journal might not exist after we reboot.  The next
++** SQLite to access the file will not know that the journal exists (because
++** the directory entry for the journal was never created) and the transaction
++** will not roll back - possibly leading to database corruption.
++*/
++int sqliteOsSync(OsFile *id){
++#if OS_UNIX
++  SimulateIOError(SQLITE_IOERR);
++  TRACE2("SYNC    %-3d\n", id->fd);
++  if( fsync(id->fd) ){
++    return SQLITE_IOERR;
++  }else{
++    if( id->dirfd>=0 ){
++      TRACE2("DIRSYNC %-3d\n", id->dirfd);
++      fsync(id->dirfd);
++      close(id->dirfd);  /* Only need to sync once, so close the directory */
++      id->dirfd = -1;    /* when we are done. */
++    }
++    return SQLITE_OK;
++  }
++#endif
++#if OS_WIN
++  if( FlushFileBuffers(id->h) ){
++    return SQLITE_OK;
++  }else{
++    return SQLITE_IOERR;
++  }
++#endif
++#if OS_MAC
++# ifdef _LARGE_FILE
++  if( FSFlushFork(id->refNum) != noErr ){
++# else
++  ParamBlockRec params;
++  memset(&params, 0, sizeof(ParamBlockRec));
++  params.ioParam.ioRefNum = id->refNum;
++  if( PBFlushFileSync(&params) != noErr ){
++# endif
++    return SQLITE_IOERR;
++  }else{
++    return SQLITE_OK;
++  }
++#endif
++}
++
++/*
++** Truncate an open file to a specified size
++*/
++int sqliteOsTruncate(OsFile *id, off_t nByte){
++  SimulateIOError(SQLITE_IOERR);
++#if OS_UNIX
++  return ftruncate(id->fd, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
++#endif
++#if OS_WIN
++  {
++    LONG upperBits = nByte>>32;
++    SetFilePointer(id->h, nByte, &upperBits, FILE_BEGIN);
++    SetEndOfFile(id->h);
++  }
++  return SQLITE_OK;
++#endif
++#if OS_MAC
++# ifdef _LARGE_FILE
++  if( FSSetForkSize(id->refNum, fsFromStart, nByte) != noErr){
++# else
++  if( SetEOF(id->refNum, nByte) != noErr ){
++# endif
++    return SQLITE_IOERR;
++  }else{
++    return SQLITE_OK;
++  }
++#endif
++}
++
++/*
++** Determine the current size of a file in bytes
++*/
++int sqliteOsFileSize(OsFile *id, off_t *pSize){
++#if OS_UNIX
++  struct stat buf;
++  SimulateIOError(SQLITE_IOERR);
++  if( fstat(id->fd, &buf)!=0 ){
++    return SQLITE_IOERR;
++  }
++  *pSize = buf.st_size;
++  return SQLITE_OK;
++#endif
++#if OS_WIN
++  DWORD upperBits, lowerBits;
++  SimulateIOError(SQLITE_IOERR);
++  lowerBits = GetFileSize(id->h, &upperBits);
++  *pSize = (((off_t)upperBits)<<32) + lowerBits;
++  return SQLITE_OK;
++#endif
++#if OS_MAC
++# ifdef _LARGE_FILE
++  if( FSGetForkSize(id->refNum, pSize) != noErr){
++# else
++  if( GetEOF(id->refNum, pSize) != noErr ){
++# endif
++    return SQLITE_IOERR;
++  }else{
++    return SQLITE_OK;
++  }
++#endif
++}
++
++#if OS_WIN
++/*
++** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.
++** 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.
++*/
++int isNT(void){
++  static int osType = 0;   /* 0=unknown 1=win95 2=winNT */
++  if( osType==0 ){
++    OSVERSIONINFO sInfo;
++    sInfo.dwOSVersionInfoSize = sizeof(sInfo);
++    GetVersionEx(&sInfo);
++    osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
++  }
++  return osType==2;
++}
++#endif
++
++/*
++** Windows file locking notes:  [similar issues apply to MacOS]
++**
++** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
++** those functions are not available.  So we use only LockFile() and
++** UnlockFile().
++**
++** LockFile() prevents not just writing but also reading by other processes.
++** (This is a design error on the part of Windows, but there is nothing
++** we can do about that.)  So the region used for locking is at the
++** end of the file where it is unlikely to ever interfere with an
++** actual read attempt.
++**
++** A database read lock is obtained by locking a single randomly-chosen 
++** byte out of a specific range of bytes. The lock byte is obtained at 
++** random so two separate readers can probably access the file at the 
++** same time, unless they are unlucky and choose the same lock byte.
++** A database write lock is obtained by locking all bytes in the range.
++** There can only be one writer.
++**
++** A lock is obtained on the first byte of the lock range before acquiring
++** either a read lock or a write lock.  This prevents two processes from
++** attempting to get a lock at a same time.  The semantics of 
++** sqliteOsReadLock() require that if there is already a write lock, that
++** lock is converted into a read lock atomically.  The lock on the first
++** byte allows us to drop the old write lock and get the read lock without
++** another process jumping into the middle and messing us up.  The same
++** argument applies to sqliteOsWriteLock().
++**
++** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
++** which means we can use reader/writer locks.  When reader writer locks
++** are used, the lock is placed on the same range of bytes that is used
++** for probabilistic locking in Win95/98/ME.  Hence, the locking scheme
++** will support two or more Win95 readers or two or more WinNT readers.
++** But a single Win95 reader will lock out all WinNT readers and a single
++** WinNT reader will lock out all other Win95 readers.
++**
++** Note: On MacOS we use the resource fork for locking.
++**
++** The following #defines specify the range of bytes used for locking.
++** N_LOCKBYTE is the number of bytes available for doing the locking.
++** The first byte used to hold the lock while the lock is changing does
++** not count toward this number.  FIRST_LOCKBYTE is the address of
++** the first byte in the range of bytes used for locking.
++*/
++#define N_LOCKBYTE       10239
++#if OS_MAC
++# define FIRST_LOCKBYTE   (0x000fffff - N_LOCKBYTE)
++#else
++# define FIRST_LOCKBYTE   (0xffffffff - N_LOCKBYTE)
++#endif
++
++/*
++** Change the status of the lock on the file "id" to be a readlock.
++** If the file was write locked, then this reduces the lock to a read.
++** If the file was read locked, then this acquires a new read lock.
++**
++** Return SQLITE_OK on success and SQLITE_BUSY on failure.  If this
++** library was compiled with large file support (LFS) but LFS is not
++** available on the host, then an SQLITE_NOLFS is returned.
++*/
++int sqliteOsReadLock(OsFile *id){
++#if OS_UNIX
++  int rc;
++  sqliteOsEnterMutex();
++  if( id->pLock->cnt>0 ){
++    if( !id->locked ){
++      id->pLock->cnt++;
++      id->locked = 1;
++      id->pOpen->nLock++;
++    }
++    rc = SQLITE_OK;
++  }else if( id->locked || id->pLock->cnt==0 ){
++    struct flock lock;
++    int s;
++    lock.l_type = F_RDLCK;
++    lock.l_whence = SEEK_SET;
++    lock.l_start = lock.l_len = 0L;
++    s = fcntl(id->fd, F_SETLK, &lock);
++    if( s!=0 ){
++      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
++    }else{
++      rc = SQLITE_OK;
++      if( !id->locked ){
++        id->pOpen->nLock++;
++        id->locked = 1;
++      }
++      id->pLock->cnt = 1;
++    }
++  }else{
++    rc = SQLITE_BUSY;
++  }
++  sqliteOsLeaveMutex();
++  return rc;
++#endif
++#if OS_WIN
++  int rc;
++  if( id->locked>0 ){
++    rc = SQLITE_OK;
++  }else{
++    int lk;
++    int res;
++    int cnt = 100;
++    sqliteRandomness(sizeof(lk), &lk);
++    lk = (lk & 0x7fffffff)%N_LOCKBYTE + 1;
++    while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0))==0 ){
++      Sleep(1);
++    }
++    if( res ){
++      UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
++      if( isNT() ){
++        OVERLAPPED ovlp;
++        ovlp.Offset = FIRST_LOCKBYTE+1;
++        ovlp.OffsetHigh = 0;
++        ovlp.hEvent = 0;
++        res = LockFileEx(id->h, LOCKFILE_FAIL_IMMEDIATELY, 
++                          0, N_LOCKBYTE, 0, &ovlp);
++      }else{
++        res = LockFile(id->h, FIRST_LOCKBYTE+lk, 0, 1, 0);
++      }
++      UnlockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0);
++    }
++    if( res ){
++      id->locked = lk;
++      rc = SQLITE_OK;
++    }else{
++      rc = SQLITE_BUSY;
++    }
++  }
++  return rc;
++#endif
++#if OS_MAC
++  int rc;
++  if( id->locked>0 || id->refNumRF == -1 ){
++    rc = SQLITE_OK;
++  }else{
++    int lk;
++    OSErr res;
++    int cnt = 5;
++    ParamBlockRec params;
++    sqliteRandomness(sizeof(lk), &lk);
++    lk = (lk & 0x7fffffff)%N_LOCKBYTE + 1;
++    memset(&params, 0, sizeof(params));
++    params.ioParam.ioRefNum = id->refNumRF;
++    params.ioParam.ioPosMode = fsFromStart;
++    params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
++    params.ioParam.ioReqCount = 1;
++    while( cnt-->0 && (res = PBLockRangeSync(&params))!=noErr ){
++      UInt32 finalTicks;
++      Delay(1, &finalTicks); /* 1/60 sec */
++    }
++    if( res == noErr ){
++      params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
++      params.ioParam.ioReqCount = N_LOCKBYTE;
++      PBUnlockRangeSync(&params);
++      params.ioParam.ioPosOffset = FIRST_LOCKBYTE+lk;
++      params.ioParam.ioReqCount = 1;
++      res = PBLockRangeSync(&params);
++      params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
++      params.ioParam.ioReqCount = 1;
++      PBUnlockRangeSync(&params);
++    }
++    if( res == noErr ){
++      id->locked = lk;
++      rc = SQLITE_OK;
++    }else{
++      rc = SQLITE_BUSY;
++    }
++  }
++  return rc;
++#endif
++}
++
++/*
++** Change the lock status to be an exclusive or write lock.  Return
++** SQLITE_OK on success and SQLITE_BUSY on a failure.  If this
++** library was compiled with large file support (LFS) but LFS is not
++** available on the host, then an SQLITE_NOLFS is returned.
++*/
++int sqliteOsWriteLock(OsFile *id){
++#if OS_UNIX
++  int rc;
++  sqliteOsEnterMutex();
++  if( id->pLock->cnt==0 || (id->pLock->cnt==1 && id->locked==1) ){
++    struct flock lock;
++    int s;
++    lock.l_type = F_WRLCK;
++    lock.l_whence = SEEK_SET;
++    lock.l_start = lock.l_len = 0L;
++    s = fcntl(id->fd, F_SETLK, &lock);
++    if( s!=0 ){
++      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
++    }else{
++      rc = SQLITE_OK;
++      if( !id->locked ){
++        id->pOpen->nLock++;
++        id->locked = 1;
++      }
++      id->pLock->cnt = -1;
++    }
++  }else{
++    rc = SQLITE_BUSY;
++  }
++  sqliteOsLeaveMutex();
++  return rc;
++#endif
++#if OS_WIN
++  int rc;
++  if( id->locked<0 ){
++    rc = SQLITE_OK;
++  }else{
++    int res;
++    int cnt = 100;
++    while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0))==0 ){
++      Sleep(1);
++    }
++    if( res ){
++      if( id->locked>0 ){
++        if( isNT() ){
++          UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
++        }else{
++          res = UnlockFile(id->h, FIRST_LOCKBYTE + id->locked, 0, 1, 0);
++        }
++      }
++      if( res ){
++        res = LockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
++      }else{
++        res = 0;
++      }
++      UnlockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0);
++    }
++    if( res ){
++      id->locked = -1;
++      rc = SQLITE_OK;
++    }else{
++      rc = SQLITE_BUSY;
++    }
++  }
++  return rc;
++#endif
++#if OS_MAC
++  int rc;
++  if( id->locked<0 || id->refNumRF == -1 ){
++    rc = SQLITE_OK;
++  }else{
++    OSErr res;
++    int cnt = 5;
++    ParamBlockRec params;
++    memset(&params, 0, sizeof(params));
++    params.ioParam.ioRefNum = id->refNumRF;
++    params.ioParam.ioPosMode = fsFromStart;
++    params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
++    params.ioParam.ioReqCount = 1;
++    while( cnt-->0 && (res = PBLockRangeSync(&params))!=noErr ){
++      UInt32 finalTicks;
++      Delay(1, &finalTicks); /* 1/60 sec */
++    }
++    if( res == noErr ){
++      params.ioParam.ioPosOffset = FIRST_LOCKBYTE + id->locked;
++      params.ioParam.ioReqCount = 1;
++      if( id->locked==0 
++            || PBUnlockRangeSync(&params)==noErr ){
++        params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
++        params.ioParam.ioReqCount = N_LOCKBYTE;
++        res = PBLockRangeSync(&params);
++      }else{
++        res = afpRangeNotLocked;
++      }
++      params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
++      params.ioParam.ioReqCount = 1;
++      PBUnlockRangeSync(&params);
++    }
++    if( res == noErr ){
++      id->locked = -1;
++      rc = SQLITE_OK;
++    }else{
++      rc = SQLITE_BUSY;
++    }
++  }
++  return rc;
++#endif
++}
++
++/*
++** Unlock the given file descriptor.  If the file descriptor was
++** not previously locked, then this routine is a no-op.  If this
++** library was compiled with large file support (LFS) but LFS is not
++** available on the host, then an SQLITE_NOLFS is returned.
++*/
++int sqliteOsUnlock(OsFile *id){
++#if OS_UNIX
++  int rc;
++  if( !id->locked ) return SQLITE_OK;
++  sqliteOsEnterMutex();
++  assert( id->pLock->cnt!=0 );
++  if( id->pLock->cnt>1 ){
++    id->pLock->cnt--;
++    rc = SQLITE_OK;
++  }else{
++    struct flock lock;
++    int s;
++    lock.l_type = F_UNLCK;
++    lock.l_whence = SEEK_SET;
++    lock.l_start = lock.l_len = 0L;
++    s = fcntl(id->fd, F_SETLK, &lock);
++    if( s!=0 ){
++      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
++    }else{
++      rc = SQLITE_OK;
++      id->pLock->cnt = 0;
++    }
++  }
++  if( rc==SQLITE_OK ){
++    /* Decrement the count of locks against this same file.  When the
++    ** count reaches zero, close any other file descriptors whose close
++    ** was deferred because of outstanding locks.
++    */
++    struct openCnt *pOpen = id->pOpen;
++    pOpen->nLock--;
++    assert( pOpen->nLock>=0 );
++    if( pOpen->nLock==0 && pOpen->nPending>0 ){
++      int i;
++      for(i=0; i<pOpen->nPending; i++){
++        close(pOpen->aPending[i]);
++      }
++      sqliteFree(pOpen->aPending);
++      pOpen->nPending = 0;
++      pOpen->aPending = 0;
++    }
++  }
++  sqliteOsLeaveMutex();
++  id->locked = 0;
++  return rc;
++#endif
++#if OS_WIN
++  int rc;
++  if( id->locked==0 ){
++    rc = SQLITE_OK;
++  }else if( isNT() || id->locked<0 ){
++    UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
++    rc = SQLITE_OK;
++    id->locked = 0;
++  }else{
++    UnlockFile(id->h, FIRST_LOCKBYTE+id->locked, 0, 1, 0);
++    rc = SQLITE_OK;
++    id->locked = 0;
++  }
++  return rc;
++#endif
++#if OS_MAC
++  int rc;
++  ParamBlockRec params;
++  memset(&params, 0, sizeof(params));
++  params.ioParam.ioRefNum = id->refNumRF;
++  params.ioParam.ioPosMode = fsFromStart;
++  if( id->locked==0 || id->refNumRF == -1 ){
++    rc = SQLITE_OK;
++  }else if( id->locked<0 ){
++    params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
++    params.ioParam.ioReqCount = N_LOCKBYTE;
++    PBUnlockRangeSync(&params);
++    rc = SQLITE_OK;
++    id->locked = 0;
++  }else{
++    params.ioParam.ioPosOffset = FIRST_LOCKBYTE+id->locked;
++    params.ioParam.ioReqCount = 1;
++    PBUnlockRangeSync(&params);
++    rc = SQLITE_OK;
++    id->locked = 0;
++  }
++  return rc;
++#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.
++*/
++int sqliteOsRandomSeed(char *zBuf){
++  /* We have to initialize zBuf to prevent valgrind from reporting
++  ** errors.  The reports issued by valgrind are incorrect - we would
++  ** prefer that the randomness be increased by making use of the
++  ** uninitialized space in zBuf - but valgrind errors tend to worry
++  ** some users.  Rather than argue, it seems easier just to initialize
++  ** the whole array and silence valgrind, even if that means less randomness
++  ** in the random seed.
++  **
++  ** When testing, initializing zBuf[] to zero is all we do.  That means
++  ** that we always use the same random number sequence.* This makes the
++  ** tests repeatable.
++  */
++  memset(zBuf, 0, 256);
++#if OS_UNIX && !defined(SQLITE_TEST)
++  {
++    int pid;
++    time((time_t*)zBuf);
++    pid = getpid();
++    memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid));
++  }
++#endif
++#if OS_WIN && !defined(SQLITE_TEST)
++  GetSystemTime((LPSYSTEMTIME)zBuf);
++#endif
++#if OS_MAC
++  {
++    int pid;
++    Microseconds((UnsignedWide*)zBuf);
++    pid = getpid();
++    memcpy(&zBuf[sizeof(UnsignedWide)], &pid, sizeof(pid));
++  }
++#endif
++  return SQLITE_OK;
++}
++
++/*
++** Sleep for a little while.  Return the amount of time slept.
++*/
++int sqliteOsSleep(int ms){
++#if OS_UNIX
++#if defined(HAVE_USLEEP) && HAVE_USLEEP
++  usleep(ms*1000);
++  return ms;
++#else
++  sleep((ms+999)/1000);
++  return 1000*((ms+999)/1000);
++#endif
++#endif
++#if OS_WIN
++  Sleep(ms);
++  return ms;
++#endif
++#if OS_MAC
++  UInt32 finalTicks;
++  UInt32 ticks = (((UInt32)ms+16)*3)/50;  /* 1/60 sec per tick */
++  Delay(ticks, &finalTicks);
++  return (int)((ticks*50)/3);
++#endif
++}
++
++/*
++** Static variables used for thread synchronization
++*/
++static int inMutex = 0;
++#ifdef SQLITE_UNIX_THREADS
++  static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
++#endif
++#ifdef SQLITE_W32_THREADS
++  static CRITICAL_SECTION cs;
++#endif
++#ifdef SQLITE_MACOS_MULTITASKING
++  static MPCriticalRegionID criticalRegion;
++#endif
++
++/*
++** The following pair of routine implement mutual exclusion for
++** multi-threaded processes.  Only a single thread is allowed to
++** executed code that is surrounded by EnterMutex() and LeaveMutex().
++**
++** SQLite uses only a single Mutex.  There is not much critical
++** code and what little there is executes quickly and without blocking.
++*/
++void sqliteOsEnterMutex(){
++#ifdef SQLITE_UNIX_THREADS
++  pthread_mutex_lock(&mutex);
++#endif
++#ifdef SQLITE_W32_THREADS
++  static int isInit = 0;
++  while( !isInit ){
++    static long lock = 0;
++    if( InterlockedIncrement(&lock)==1 ){
++      InitializeCriticalSection(&cs);
++      isInit = 1;
++    }else{
++      Sleep(1);
++    }
++  }
++  EnterCriticalSection(&cs);
++#endif
++#ifdef SQLITE_MACOS_MULTITASKING
++  static volatile int notInit = 1;
++  if( notInit ){
++    if( notInit == 2 ) /* as close as you can get to thread safe init */
++      MPYield();
++    else{
++      notInit = 2;
++      MPCreateCriticalRegion(&criticalRegion);
++      notInit = 0;
++    }
++  }
++  MPEnterCriticalRegion(criticalRegion, kDurationForever);
++#endif
++  assert( !inMutex );
++  inMutex = 1;
++}
++void sqliteOsLeaveMutex(){
++  assert( inMutex );
++  inMutex = 0;
++#ifdef SQLITE_UNIX_THREADS
++  pthread_mutex_unlock(&mutex);
++#endif
++#ifdef SQLITE_W32_THREADS
++  LeaveCriticalSection(&cs);
++#endif
++#ifdef SQLITE_MACOS_MULTITASKING
++  MPExitCriticalRegion(criticalRegion);
++#endif
++}
++
++/*
++** Turn a relative pathname into a full pathname.  Return a pointer
++** to the full pathname stored in space obtained from sqliteMalloc().
++** The calling function is responsible for freeing this space once it
++** is no longer needed.
++*/
++char *sqliteOsFullPathname(const char *zRelative){
++#if OS_UNIX
++  char *zFull = 0;
++  if( zRelative[0]=='/' ){
++    sqliteSetString(&zFull, zRelative, (char*)0);
++  }else{
++    char zBuf[5000];
++    zBuf[0] = 0;
++    sqliteSetString(&zFull, getcwd(zBuf, sizeof(zBuf)), "/", zRelative,
++                    (char*)0);
++  }
++  return zFull;
++#endif
++#if OS_WIN
++  char *zNotUsed;
++  char *zFull;
++  int nByte;
++  nByte = GetFullPathName(zRelative, 0, 0, &zNotUsed) + 1;
++  zFull = sqliteMalloc( nByte );
++  if( zFull==0 ) return 0;
++  GetFullPathName(zRelative, nByte, zFull, &zNotUsed);
++  return zFull;
++#endif
++#if OS_MAC
++  char *zFull = 0;
++  if( zRelative[0]==':' ){
++    char zBuf[_MAX_PATH+1];
++    sqliteSetString(&zFull, getcwd(zBuf, sizeof(zBuf)), &(zRelative[1]),
++                    (char*)0);
++  }else{
++    if( strchr(zRelative, ':') ){
++      sqliteSetString(&zFull, zRelative, (char*)0);
++    }else{
++    char zBuf[_MAX_PATH+1];
++      sqliteSetString(&zFull, getcwd(zBuf, sizeof(zBuf)), zRelative, (char*)0);
++    }
++  }
++  return zFull;
++#endif
++}
++
++/*
++** The following variable, if set to a non-zero value, becomes the result
++** returned from sqliteOsCurrentTime().  This is used for testing.
++*/
++#ifdef SQLITE_TEST
++int sqlite_current_time = 0;
++#endif
++
++/*
++** Find the current time (in Universal Coordinated Time).  Write the
++** current time and date as a Julian Day number into *prNow and
++** return 0.  Return 1 if the time and date cannot be found.
++*/
++int sqliteOsCurrentTime(double *prNow){
++#if OS_UNIX
++  time_t t;
++  time(&t);
++  *prNow = t/86400.0 + 2440587.5;
++#endif
++#if OS_WIN
++  FILETIME ft;
++  /* FILETIME structure is a 64-bit value representing the number of 
++     100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). 
++  */
++  double now;
++  GetSystemTimeAsFileTime( &ft );
++  now = ((double)ft.dwHighDateTime) * 4294967296.0; 
++  *prNow = (now + ft.dwLowDateTime)/864000000000.0 + 2305813.5;
++#endif
++#ifdef SQLITE_TEST
++  if( sqlite_current_time ){
++    *prNow = sqlite_current_time/86400.0 + 2440587.5;
++  }
++#endif
++  return 0;
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/os.h
+@@ -0,0 +1,191 @@
++/*
++** 2001 September 16
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++******************************************************************************
++**
++** This header file (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.
++*/
++#ifndef _SQLITE_OS_H_
++#define _SQLITE_OS_H_
++
++/*
++** Helpful hint:  To get this to compile on HP/UX, add -D_INCLUDE_POSIX_SOURCE
++** to the compiler command line.
++*/
++
++/*
++** 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.
++**
++** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
++** on the compiler command line.  This is necessary if you are compiling
++** on a recent machine (ex: RedHat 7.2) but you want your code to work
++** on an older machine (ex: RedHat 6.0).  If you compile on RedHat 7.2
++** without this option, LFS is enable.  But LFS does not exist in the kernel
++** in RedHat 6.0, so the code won't work.  Hence, for maximum binary
++** portability you should omit LFS.
++**
++** Similar is true for MacOS.  LFS is only supported on MacOS 9 and later.
++*/
++#ifndef SQLITE_DISABLE_LFS
++# define _LARGE_FILE       1
++# ifndef _FILE_OFFSET_BITS
++#   define _FILE_OFFSET_BITS 64
++# endif
++# define _LARGEFILE_SOURCE 1
++#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
++
++/*
++** Figure out if we are dealing with Unix, Windows or MacOS.
++**
++** N.B. MacOS means Mac Classic (or Carbon). Treat Darwin (OS X) as Unix.
++**      The MacOS build is designed to use CodeWarrior (tested with v8)
++*/
++#ifndef OS_UNIX
++# ifndef OS_WIN
++#  ifndef OS_MAC
++#    if defined(__MACOS__)
++#      define OS_MAC 1
++#      define OS_WIN 0
++#      define OS_UNIX 0
++#    elif defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
++#      define OS_MAC 0
++#      define OS_WIN 1
++#      define OS_UNIX 0
++#    else
++#      define OS_MAC 0
++#      define OS_WIN 0
++#      define OS_UNIX 1
++#    endif
++#  else
++#    define OS_WIN 0
++#    define OS_UNIX 0
++#  endif
++# else
++#  define OS_MAC 0
++#  define OS_UNIX 0
++# endif
++#else
++# define OS_MAC 0
++# ifndef OS_WIN
++#  define OS_WIN 0
++# endif
++#endif
++
++/*
++** A handle for an open file is stored in an OsFile object.
++*/
++#if OS_UNIX
++# include <sys/types.h>
++# include <sys/stat.h>
++# include <fcntl.h>
++# include <unistd.h>
++  typedef struct OsFile OsFile;
++  struct OsFile {
++    struct openCnt *pOpen;    /* Info about all open fd's on this inode */
++    struct lockInfo *pLock;   /* Info about locks on this inode */
++    int fd;                   /* The file descriptor */
++    int locked;               /* True if this instance holds the lock */
++    int dirfd;                /* File descriptor for the directory */
++  };
++# define SQLITE_TEMPNAME_SIZE 200
++# if defined(HAVE_USLEEP) && HAVE_USLEEP
++#  define SQLITE_MIN_SLEEP_MS 1
++# else
++#  define SQLITE_MIN_SLEEP_MS 1000
++# endif
++#endif
++
++#if OS_WIN
++#include <windows.h>
++#include <winbase.h>
++  typedef struct OsFile OsFile;
++  struct OsFile {
++    HANDLE h;               /* Handle for accessing the file */
++    int locked;             /* 0: unlocked, <0: write lock, >0: read lock */
++  };
++# if defined(_MSC_VER) || defined(__BORLANDC__)
++    typedef __int64 off_t;
++# else
++#  if !defined(_CYGWIN_TYPES_H)
++     typedef long long off_t;
++#    if defined(__MINGW32__)
++#      define _OFF_T_
++#    endif
++#  endif
++# endif
++# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
++# define SQLITE_MIN_SLEEP_MS 1
++#endif
++
++#if OS_MAC
++# include <unistd.h>
++# include <Files.h>
++  typedef struct OsFile OsFile;
++  struct OsFile {
++    SInt16 refNum;           /* Data fork/file reference number */
++    SInt16 refNumRF;         /* Resource fork reference number (for locking) */
++    int locked;              /* 0: unlocked, <0: write lock, >0: read lock */
++    int delOnClose;          /* True if file is to be deleted on close */
++    char *pathToDel;         /* Name of file to delete on close */
++  };
++# ifdef _LARGE_FILE
++    typedef SInt64 off_t;
++# else
++    typedef SInt32 off_t;
++# endif
++# define SQLITE_TEMPNAME_SIZE _MAX_PATH
++# define SQLITE_MIN_SLEEP_MS 17
++#endif
++
++int sqliteOsDelete(const char*);
++int sqliteOsFileExists(const char*);
++int sqliteOsFileRename(const char*, const char*);
++int sqliteOsOpenReadWrite(const char*, OsFile*, int*);
++int sqliteOsOpenExclusive(const char*, OsFile*, int);
++int sqliteOsOpenReadOnly(const char*, OsFile*);
++int sqliteOsOpenDirectory(const char*, OsFile*);
++int sqliteOsTempFileName(char*);
++int sqliteOsClose(OsFile*);
++int sqliteOsRead(OsFile*, void*, int amt);
++int sqliteOsWrite(OsFile*, const void*, int amt);
++int sqliteOsSeek(OsFile*, off_t offset);
++int sqliteOsSync(OsFile*);
++int sqliteOsTruncate(OsFile*, off_t size);
++int sqliteOsFileSize(OsFile*, off_t *pSize);
++int sqliteOsReadLock(OsFile*);
++int sqliteOsWriteLock(OsFile*);
++int sqliteOsUnlock(OsFile*);
++int sqliteOsRandomSeed(char*);
++int sqliteOsSleep(int ms);
++int sqliteOsCurrentTime(double*);
++void sqliteOsEnterMutex(void);
++void sqliteOsLeaveMutex(void);
++char *sqliteOsFullPathname(const char*);
++
++
++
++#endif /* _SQLITE_OS_H_ */
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/pager.c
+@@ -0,0 +1,2220 @@
++/*
++** 2001 September 15
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This is the implementation of the page cache subsystem or "pager".
++** 
++** The pager is used to access a database disk file.  It implements
++** atomic commit and rollback through the use of a journal file that
++** is separate from the database file.  The pager also implements file
++** locking to prevent two processes from writing the same database
++** file simultaneously, or one process from reading the database while
++** another is writing.
++**
++** @(#) $Id$
++*/
++#include "os.h"         /* Must be first to enable large file support */
++#include "sqliteInt.h"
++#include "pager.h"
++#include <assert.h>
++#include <string.h>
++
++/*
++** Macros for troubleshooting.  Normally turned off
++*/
++#if 0
++static Pager *mainPager = 0;
++#define SET_PAGER(X)  if( mainPager==0 ) mainPager = (X)
++#define CLR_PAGER(X)  if( mainPager==(X) ) mainPager = 0
++#define TRACE1(X)     if( pPager==mainPager ) fprintf(stderr,X)
++#define TRACE2(X,Y)   if( pPager==mainPager ) fprintf(stderr,X,Y)
++#define TRACE3(X,Y,Z) if( pPager==mainPager ) fprintf(stderr,X,Y,Z)
++#else
++#define SET_PAGER(X)
++#define CLR_PAGER(X)
++#define TRACE1(X)
++#define TRACE2(X,Y)
++#define TRACE3(X,Y,Z)
++#endif
++
++
++/*
++** The page cache as a whole is always in one of the following
++** states:
++**
++**   SQLITE_UNLOCK       The page cache is not currently reading or 
++**                       writing the database file.  There is no
++**                       data held in memory.  This is the initial
++**                       state.
++**
++**   SQLITE_READLOCK     The page cache is reading the database.
++**                       Writing is not permitted.  There can be
++**                       multiple readers accessing the same database
++**                       file at the same time.
++**
++**   SQLITE_WRITELOCK    The page cache is writing the database.
++**                       Access is exclusive.  No other processes or
++**                       threads can be reading or writing while one
++**                       process is writing.
++**
++** The page cache comes up in SQLITE_UNLOCK.  The first time a
++** sqlite_page_get() occurs, the state transitions to SQLITE_READLOCK.
++** After all pages have been released using sqlite_page_unref(),
++** the state transitions back to SQLITE_UNLOCK.  The first time
++** that sqlite_page_write() is called, the state transitions to
++** SQLITE_WRITELOCK.  (Note that sqlite_page_write() can only be
++** called on an outstanding page which means that the pager must
++** be in SQLITE_READLOCK before it transitions to SQLITE_WRITELOCK.)
++** The sqlite_page_rollback() and sqlite_page_commit() functions 
++** transition the state from SQLITE_WRITELOCK back to SQLITE_READLOCK.
++*/
++#define SQLITE_UNLOCK      0
++#define SQLITE_READLOCK    1
++#define SQLITE_WRITELOCK   2
++
++
++/*
++** 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 sqlitepager_write() on a page prior to making
++** any modifications to that page.  The first time sqlitepager_write()
++** 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
++** is cleared.  The modified page cannot be written back into the original
++** 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 sqlitepager_write() is called and
++** is cleared again when the page content is written back to 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 */
++  int nRef;                      /* Number of users of this page */
++  PgHdr *pNextFree, *pPrevFree;  /* Freelist of pages where nRef==0 */
++  PgHdr *pNextAll, *pPrevAll;    /* A list of all pages */
++  PgHdr *pNextCkpt, *pPrevCkpt;  /* List of pages in the checkpoint journal */
++  u8 inJournal;                  /* TRUE if has been written to journal */
++  u8 inCkpt;                     /* TRUE if written to the checkpoint journal */
++  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 */
++  PgHdr *pDirty;                 /* Dirty pages sorted by PgHdr.pgno */
++  /* SQLITE_PAGE_SIZE bytes of page data follow this header */
++  /* Pager.nExtra bytes of local data follow the page data */
++};
++
++
++/*
++** A macro used for invoking the codec if there is one
++*/
++#ifdef SQLITE_HAS_CODEC
++# define CODEC(P,D,N,X) if( P->xCodec ){ P->xCodec(P->pCodecArg,D,N,X); }
++#else
++# define CODEC(P,D,N,X)
++#endif
++
++/*
++** 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(P) ((void*)&((char*)(&(P)[1]))[SQLITE_PAGE_SIZE])
++
++/*
++** How big to make the hash table used for locating in-memory pages
++** by page number.
++*/
++#define N_PG_HASH 2048
++
++/*
++** Hash a page number
++*/
++#define pager_hash(PN)  ((PN)&(N_PG_HASH-1))
++
++/*
++** A open page cache is an instance of the following structure.
++*/
++struct Pager {
++  char *zFilename;            /* Name of the database file */
++  char *zJournal;             /* Name of the journal file */
++  char *zDirectory;           /* Directory hold database and journal files */
++  OsFile fd, jfd;             /* File descriptors for database and journal */
++  OsFile cpfd;                /* File descriptor for the checkpoint journal */
++  int dbSize;                 /* Number of pages in the file */
++  int origDbSize;             /* dbSize before the current change */
++  int ckptSize;               /* Size of database (in pages) at ckpt_begin() */
++  off_t ckptJSize;            /* Size of journal at ckpt_begin() */
++  int nRec;                   /* Number of pages written to the journal */
++  u32 cksumInit;              /* Quasi-random value added to every checksum */
++  int ckptNRec;               /* Number of records in the checkpoint journal */
++  int nExtra;                 /* Add this many bytes to each in-memory page */
++  void (*xDestructor)(void*); /* Call this routine when freeing pages */
++  int nPage;                  /* Total number of in-memory pages */
++  int nRef;                   /* Number of in-memory pages with PgHdr.nRef>0 */
++  int mxPage;                 /* Maximum number of pages to hold in cache */
++  int nHit, nMiss, nOvfl;     /* Cache hits, missing, and LRU overflows */
++  void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
++  void *pCodecArg;            /* First argument to xCodec() */
++  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 */
++  u8 ckptOpen;                /* True if the checkpoint journal is open */
++  u8 ckptInUse;               /* True we are in a checkpoint */
++  u8 ckptAutoopen;            /* Open ckpt 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 state;                   /* SQLITE_UNLOCK, _READLOCK or _WRITELOCK */
++  u8 errMask;                 /* 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 dirtyFile;               /* True if database file has changed in any way */
++  u8 alwaysRollback;          /* Disable dont_rollback() for all pages */
++  u8 *aInJournal;             /* One bit for each page in the database file */
++  u8 *aInCkpt;                /* One bit for each page in the database */
++  PgHdr *pFirst, *pLast;      /* List of free pages */
++  PgHdr *pFirstSynced;        /* First free page with PgHdr.needSync==0 */
++  PgHdr *pAll;                /* List of all pages */
++  PgHdr *pCkpt;               /* List of pages in the checkpoint journal */
++  PgHdr *aHash[N_PG_HASH];    /* Hash table to map page number of PgHdr */
++};
++
++/*
++** These are bits that can be set in Pager.errMask.
++*/
++#define PAGER_ERR_FULL     0x01  /* a write() failed */
++#define PAGER_ERR_MEM      0x02  /* malloc() failed */
++#define PAGER_ERR_LOCK     0x04  /* error in the locking protocol */
++#define PAGER_ERR_CORRUPT  0x08  /* database or journal corruption */
++#define PAGER_ERR_DISK     0x10  /* general disk I/O error - bad hard drive? */
++
++/*
++** The journal file contains page records in the following
++** format.
++**
++** Actually, this structure is the complete page record for pager
++** formats less than 3.  Beginning with format 3, this record is surrounded
++** by two checksums.
++*/
++typedef struct PageRecord PageRecord;
++struct PageRecord {
++  Pgno pgno;                      /* The page number */
++  char aData[SQLITE_PAGE_SIZE];   /* Original data for page pgno */
++};
++
++/*
++** Journal files begin with the following magic string.  The data
++** was obtained from /dev/random.  It is used only as a sanity check.
++**
++** There are three journal formats (so far). The 1st journal format writes
++** 32-bit integers in the byte-order of the host machine.  New
++** formats writes integers as big-endian.  All new journals use the
++** new format, but we have to be able to read an older journal in order
++** to rollback journals created by older versions of the library.
++**
++** The 3rd journal format (added for 2.8.0) adds additional sanity
++** checking information to the journal.  If the power fails while the
++** journal is being written, semi-random garbage data might appear in
++** the journal file after power is restored.  If an attempt is then made
++** to roll the journal back, the database could be corrupted.  The additional
++** sanity checking data is an attempt to discover the garbage in the
++** journal and ignore it.
++**
++** The sanity checking information for the 3rd journal format consists
++** of a 32-bit checksum on each page of data.  The checksum covers both
++** the page number and the SQLITE_PAGE_SIZE bytes of data for the page.
++** This cksum is initialized to a 32-bit random value that appears in the
++** journal file right after the header.  The random initializer is important,
++** because garbage data that appears at the end of a journal is likely
++** data that was once in other files that have now been deleted.  If the
++** garbage data came from an obsolete journal file, the checksums might
++** be correct.  But by initializing the checksum to random value which
++** is different for every journal, we minimize that risk.
++*/
++static const unsigned char aJournalMagic1[] = {
++  0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd4,
++};
++static const unsigned char aJournalMagic2[] = {
++  0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd5,
++};
++static const unsigned char aJournalMagic3[] = {
++  0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd6,
++};
++#define JOURNAL_FORMAT_1 1
++#define JOURNAL_FORMAT_2 2
++#define JOURNAL_FORMAT_3 3
++
++/*
++** The following integer determines what format to use when creating
++** new primary journal files.  By default we always use format 3.
++** When testing, we can set this value to older journal formats in order to
++** make sure that newer versions of the library are able to rollback older
++** journal files.
++**
++** Note that checkpoint journals always use format 2 and omit the header.
++*/
++#ifdef SQLITE_TEST
++int journal_format = 3;
++#else
++# define journal_format 3
++#endif
++
++/*
++** The size of the header and of each page in the journal varies according
++** to which journal format is being used.  The following macros figure out
++** the sizes based on format numbers.
++*/
++#define JOURNAL_HDR_SZ(X) \
++   (sizeof(aJournalMagic1) + sizeof(Pgno) + ((X)>=3)*2*sizeof(u32))
++#define JOURNAL_PG_SZ(X) \
++   (SQLITE_PAGE_SIZE + sizeof(Pgno) + ((X)>=3)*sizeof(u32))
++
++/*
++** Enable reference count tracking here:
++*/
++#ifdef SQLITE_TEST
++  int pager_refinfo_enable = 0;
++  static void pager_refinfo(PgHdr *p){
++    static int cnt = 0;
++    if( !pager_refinfo_enable ) return;
++    printf(
++       "REFCNT: %4d addr=0x%08x nRef=%d\n",
++       p->pgno, (int)PGHDR_TO_DATA(p), p->nRef
++    );
++    cnt++;   /* Something to set a breakpoint on */
++  }
++# define REFINFO(X)  pager_refinfo(X)
++#else
++# define REFINFO(X)
++#endif
++
++/*
++** Read a 32-bit integer from the given file descriptor.  Store the integer
++** that is read in *pRes.  Return SQLITE_OK if everything worked, or an
++** error code is something goes wrong.
++**
++** If the journal format is 2 or 3, read a big-endian integer.  If the
++** journal format is 1, read an integer in the native byte-order of the
++** host machine.
++*/
++static int read32bits(int format, OsFile *fd, u32 *pRes){
++  u32 res;
++  int rc;
++  rc = sqliteOsRead(fd, &res, sizeof(res));
++  if( rc==SQLITE_OK && format>JOURNAL_FORMAT_1 ){
++    unsigned char ac[4];
++    memcpy(ac, &res, 4);
++    res = (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3];
++  }
++  *pRes = res;
++  return rc;
++}
++
++/*
++** Write a 32-bit integer into the given file descriptor.  Return SQLITE_OK
++** on success or an error code is something goes wrong.
++**
++** If the journal format is 2 or 3, write the integer as 4 big-endian
++** bytes.  If the journal format is 1, write the integer in the native
++** byte order.  In normal operation, only formats 2 and 3 are used.
++** Journal format 1 is only used for testing.
++*/
++static int write32bits(OsFile *fd, u32 val){
++  unsigned char ac[4];
++  if( journal_format<=1 ){
++    return sqliteOsWrite(fd, &val, 4);
++  }
++  ac[0] = (val>>24) & 0xff;
++  ac[1] = (val>>16) & 0xff;
++  ac[2] = (val>>8) & 0xff;
++  ac[3] = val & 0xff;
++  return sqliteOsWrite(fd, ac, 4);
++}
++
++/*
++** Write a 32-bit integer into a page header right before the
++** page data.  This will overwrite the PgHdr.pDirty pointer.
++**
++** The integer is big-endian for formats 2 and 3 and native byte order
++** for journal format 1.
++*/
++static void store32bits(u32 val, PgHdr *p, int offset){
++  unsigned char *ac;
++  ac = &((unsigned char*)PGHDR_TO_DATA(p))[offset];
++  if( journal_format<=1 ){
++    memcpy(ac, &val, 4);
++  }else{
++    ac[0] = (val>>24) & 0xff;
++    ac[1] = (val>>16) & 0xff;
++    ac[2] = (val>>8) & 0xff;
++    ac[3] = val & 0xff;
++  }
++}
++
++
++/*
++** Convert the bits in the pPager->errMask into an approprate
++** return code.
++*/
++static int pager_errcode(Pager *pPager){
++  int rc = SQLITE_OK;
++  if( pPager->errMask & PAGER_ERR_LOCK )    rc = SQLITE_PROTOCOL;
++  if( pPager->errMask & PAGER_ERR_DISK )    rc = SQLITE_IOERR;
++  if( pPager->errMask & PAGER_ERR_FULL )    rc = SQLITE_FULL;
++  if( pPager->errMask & PAGER_ERR_MEM )     rc = SQLITE_NOMEM;
++  if( pPager->errMask & PAGER_ERR_CORRUPT ) rc = SQLITE_CORRUPT;
++  return rc;
++}
++
++/*
++** Add or remove a page from the list of all pages that are in the
++** checkpoint journal.
++**
++** The Pager keeps a separate list of pages that are currently in
++** the checkpoint journal.  This helps the sqlitepager_ckpt_commit()
++** routine run MUCH faster for the common case where there are many
++** pages in memory but only a few are in the checkpoint journal.
++*/
++static void page_add_to_ckpt_list(PgHdr *pPg){
++  Pager *pPager = pPg->pPager;
++  if( pPg->inCkpt ) return;
++  assert( pPg->pPrevCkpt==0 && pPg->pNextCkpt==0 );
++  pPg->pPrevCkpt = 0;
++  if( pPager->pCkpt ){
++    pPager->pCkpt->pPrevCkpt = pPg;
++  }
++  pPg->pNextCkpt = pPager->pCkpt;
++  pPager->pCkpt = pPg;
++  pPg->inCkpt = 1;
++}
++static void page_remove_from_ckpt_list(PgHdr *pPg){
++  if( !pPg->inCkpt ) return;
++  if( pPg->pPrevCkpt ){
++    assert( pPg->pPrevCkpt->pNextCkpt==pPg );
++    pPg->pPrevCkpt->pNextCkpt = pPg->pNextCkpt;
++  }else{
++    assert( pPg->pPager->pCkpt==pPg );
++    pPg->pPager->pCkpt = pPg->pNextCkpt;
++  }
++  if( pPg->pNextCkpt ){
++    assert( pPg->pNextCkpt->pPrevCkpt==pPg );
++    pPg->pNextCkpt->pPrevCkpt = pPg->pPrevCkpt;
++  }
++  pPg->pNextCkpt = 0;
++  pPg->pPrevCkpt = 0;
++  pPg->inCkpt = 0;
++}
++
++/*
++** Find a page in the hash table given its page number.  Return
++** a pointer to the page or NULL if not found.
++*/
++static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
++  PgHdr *p = pPager->aHash[pager_hash(pgno)];
++  while( p && p->pgno!=pgno ){
++    p = p->pNextHash;
++  }
++  return p;
++}
++
++/*
++** Unlock the database and 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.
++*/
++static void pager_reset(Pager *pPager){
++  PgHdr *pPg, *pNext;
++  for(pPg=pPager->pAll; pPg; pPg=pNext){
++    pNext = pPg->pNextAll;
++    sqliteFree(pPg);
++  }
++  pPager->pFirst = 0;
++  pPager->pFirstSynced = 0;
++  pPager->pLast = 0;
++  pPager->pAll = 0;
++  memset(pPager->aHash, 0, sizeof(pPager->aHash));
++  pPager->nPage = 0;
++  if( pPager->state>=SQLITE_WRITELOCK ){
++    sqlitepager_rollback(pPager);
++  }
++  sqliteOsUnlock(&pPager->fd);
++  pPager->state = SQLITE_UNLOCK;
++  pPager->dbSize = -1;
++  pPager->nRef = 0;
++  assert( pPager->journalOpen==0 );
++}
++
++/*
++** When this routine is called, the pager has the journal file open and
++** a write lock on the database.  This routine releases the database
++** write lock and acquires a read lock in its place.  The journal file
++** is deleted and closed.
++**
++** 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){
++  int rc;
++  PgHdr *pPg;
++  if( pPager->state<SQLITE_WRITELOCK ) return SQLITE_OK;
++  sqlitepager_ckpt_commit(pPager);
++  if( pPager->ckptOpen ){
++    sqliteOsClose(&pPager->cpfd);
++    pPager->ckptOpen = 0;
++  }
++  if( pPager->journalOpen ){
++    sqliteOsClose(&pPager->jfd);
++    pPager->journalOpen = 0;
++    sqliteOsDelete(pPager->zJournal);
++    sqliteFree( pPager->aInJournal );
++    pPager->aInJournal = 0;
++    for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
++      pPg->inJournal = 0;
++      pPg->dirty = 0;
++      pPg->needSync = 0;
++    }
++  }else{
++    assert( pPager->dirtyFile==0 || pPager->useJournal==0 );
++  }
++  rc = sqliteOsReadLock(&pPager->fd);
++  if( rc==SQLITE_OK ){
++    pPager->state = SQLITE_READLOCK;
++  }else{
++    /* This can only happen if a process does a BEGIN, then forks and the
++    ** child process does the COMMIT.  Because of the semantics of unix
++    ** file locking, the unlock will fail.
++    */
++    pPager->state = SQLITE_UNLOCK;
++  }
++  return rc;
++}
++
++/*
++** Compute and return a checksum for the page of data.
++**
++** This is not a real checksum.  It is really just the sum of the 
++** random initial value and the page number.  We considered do a checksum
++** of the database, but that was found to be too slow.
++*/
++static u32 pager_cksum(Pager *pPager, Pgno pgno, const char *aData){
++  u32 cksum = pPager->cksumInit + pgno;
++  return cksum;
++}
++
++/*
++** Read a single page from the journal file opened on file descriptor
++** jfd.  Playback this one page.
++**
++** There are three different journal formats.  The format parameter determines
++** which format is used by the journal that is played back.
++*/
++static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int format){
++  int rc;
++  PgHdr *pPg;              /* An existing page in the cache */
++  PageRecord pgRec;
++  u32 cksum;
++
++  rc = read32bits(format, jfd, &pgRec.pgno);
++  if( rc!=SQLITE_OK ) return rc;
++  rc = sqliteOsRead(jfd, &pgRec.aData, sizeof(pgRec.aData));
++  if( rc!=SQLITE_OK ) return rc;
++
++  /* Sanity checking on the page.  This is more important that I originally
++  ** thought.  If a power failure occurs while the journal is being written,
++  ** it could cause invalid data to be written into the journal.  We need to
++  ** detect this invalid data (with high probability) and ignore it.
++  */
++  if( pgRec.pgno==0 ){
++    return SQLITE_DONE;
++  }
++  if( pgRec.pgno>(unsigned)pPager->dbSize ){
++    return SQLITE_OK;
++  }
++  if( format>=JOURNAL_FORMAT_3 ){
++    rc = read32bits(format, jfd, &cksum);
++    if( rc ) return rc;
++    if( pager_cksum(pPager, pgRec.pgno, pgRec.aData)!=cksum ){
++      return SQLITE_DONE;
++    }
++  }
++
++  /* Playback the page.  Update the in-memory copy of the page
++  ** at the same time, if there is one.
++  */
++  pPg = pager_lookup(pPager, pgRec.pgno);
++  TRACE2("PLAYBACK %d\n", pgRec.pgno);
++  sqliteOsSeek(&pPager->fd, (pgRec.pgno-1)*(off_t)SQLITE_PAGE_SIZE);
++  rc = sqliteOsWrite(&pPager->fd, pgRec.aData, SQLITE_PAGE_SIZE);
++  if( pPg ){
++    /* No page should ever be rolled back that is in use, except for page
++    ** 1 which is held in use in order to keep the lock on the database
++    ** active.
++    */
++    assert( pPg->nRef==0 || pPg->pgno==1 );
++    memcpy(PGHDR_TO_DATA(pPg), pgRec.aData, SQLITE_PAGE_SIZE);
++    memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra);
++    pPg->dirty = 0;
++    pPg->needSync = 0;
++    CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
++  }
++  return rc;
++}
++
++/*
++** Playback the journal and thus restore the database file to
++** the state it was in before we started making changes.  
++**
++** The journal file format is as follows: 
++**
++**    *  8 byte prefix.  One of the aJournalMagic123 vectors defined
++**       above.  The format of the journal file is determined by which
++**       of the three prefix vectors is seen.
++**    *  4 byte big-endian integer which is the number of valid page records
++**       in the journal.  If this value is 0xffffffff, then compute the
++**       number of page records from the journal size.  This field appears
++**       in format 3 only.
++**    *  4 byte big-endian integer which is the initial value for the 
++**       sanity checksum.  This field appears in format 3 only.
++**    *  4 byte integer which is the number of pages to truncate the
++**       database to during a rollback.
++**    *  Zero or more pages instances, each as follows:
++**        +  4 byte page number.
++**        +  SQLITE_PAGE_SIZE bytes of data.
++**        +  4 byte checksum (format 3 only)
++**
++** When we speak of the journal header, we mean the first 4 bullets above.
++** Each entry in the journal is an instance of the 5th bullet.  Note that
++** bullets 2 and 3 only appear in format-3 journals.
++**
++** Call the value from the second bullet "nRec".  nRec is the number of
++** valid page entries in the journal.  In most cases, you can compute the
++** value of nRec from the size of the journal file.  But if a power
++** failure occurred while the journal was being written, it could be the
++** case that the size of the journal file had already been increased but
++** the extra entries had not yet made it safely to disk.  In such a case,
++** the value of nRec computed from the file size would be too large.  For
++** that reason, we always use the nRec value in the header.
++**
++** If the nRec value is 0xffffffff it means that nRec should be computed
++** from the file size.  This value is used when the user selects the
++** no-sync option for the journal.  A power failure could lead to corruption
++** in this case.  But for things like temporary table (which will be
++** deleted when the power is restored) we don't care.  
++**
++** Journal formats 1 and 2 do not have an nRec value in the header so we
++** have to compute nRec from the file size.  This has risks (as described
++** above) which is why all persistent tables have been changed to use
++** format 3.
++**
++** If the file opened as the journal file is not a well-formed
++** journal file then the database will likely already be
++** corrupted, so the PAGER_ERR_CORRUPT bit is set in pPager->errMask
++** and SQLITE_CORRUPT is returned.  If it all works, then this routine
++** returns SQLITE_OK.
++*/
++static int pager_playback(Pager *pPager, int useJournalSize){
++  off_t szJ;               /* Size of the journal file in bytes */
++  int nRec;                /* Number of Records in the journal */
++  int i;                   /* Loop counter */
++  Pgno mxPg = 0;           /* Size of the original file in pages */
++  int format;              /* Format of the journal file. */
++  unsigned char aMagic[sizeof(aJournalMagic1)];
++  int rc;
++
++  /* Figure out how many records are in the journal.  Abort early if
++  ** the journal is empty.
++  */
++  assert( pPager->journalOpen );
++  sqliteOsSeek(&pPager->jfd, 0);
++  rc = sqliteOsFileSize(&pPager->jfd, &szJ);
++  if( rc!=SQLITE_OK ){
++    goto end_playback;
++  }
++
++  /* If the journal file is too small to contain a complete header,
++  ** it must mean that the process that created the journal was just
++  ** beginning to write the journal file when it died.  In that case,
++  ** the database file should have still been completely unchanged.
++  ** Nothing needs to be rolled back.  We can safely ignore this journal.
++  */
++  if( szJ < sizeof(aMagic)+sizeof(Pgno) ){
++    goto end_playback;
++  }
++
++  /* Read the beginning of the journal and truncate the
++  ** database file back to its original size.
++  */
++  rc = sqliteOsRead(&pPager->jfd, aMagic, sizeof(aMagic));
++  if( rc!=SQLITE_OK ){
++    rc = SQLITE_PROTOCOL;
++    goto end_playback;
++  }
++  if( memcmp(aMagic, aJournalMagic3, sizeof(aMagic))==0 ){
++    format = JOURNAL_FORMAT_3;
++  }else if( memcmp(aMagic, aJournalMagic2, sizeof(aMagic))==0 ){
++    format = JOURNAL_FORMAT_2;
++  }else if( memcmp(aMagic, aJournalMagic1, sizeof(aMagic))==0 ){
++    format = JOURNAL_FORMAT_1;
++  }else{
++    rc = SQLITE_PROTOCOL;
++    goto end_playback;
++  }
++  if( format>=JOURNAL_FORMAT_3 ){
++    if( szJ < sizeof(aMagic) + 3*sizeof(u32) ){
++      /* Ignore the journal if it is too small to contain a complete
++      ** header.  We already did this test once above, but at the prior
++      ** test, we did not know the journal format and so we had to assume
++      ** the smallest possible header.  Now we know the header is bigger
++      ** than the minimum so we test again.
++      */
++      goto end_playback;
++    }
++    rc = read32bits(format, &pPager->jfd, (u32*)&nRec);
++    if( rc ) goto end_playback;
++    rc = read32bits(format, &pPager->jfd, &pPager->cksumInit);
++    if( rc ) goto end_playback;
++    if( nRec==0xffffffff || useJournalSize ){
++      nRec = (szJ - JOURNAL_HDR_SZ(3))/JOURNAL_PG_SZ(3);
++    }
++  }else{
++    nRec = (szJ - JOURNAL_HDR_SZ(2))/JOURNAL_PG_SZ(2);
++    assert( nRec*JOURNAL_PG_SZ(2)+JOURNAL_HDR_SZ(2)==szJ );
++  }
++  rc = read32bits(format, &pPager->jfd, &mxPg);
++  if( rc!=SQLITE_OK ){
++    goto end_playback;
++  }
++  assert( pPager->origDbSize==0 || pPager->origDbSize==mxPg );
++  rc = sqliteOsTruncate(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)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, format);
++    if( rc!=SQLITE_OK ){
++      if( rc==SQLITE_DONE ){
++        rc = SQLITE_OK;
++      }
++      break;
++    }
++  }
++
++  /* Pages that have been written to the journal but never synced
++  ** where not restored by the loop above.  We have to restore those
++  ** pages by reading them back from the original database.
++  */
++  if( rc==SQLITE_OK ){
++    PgHdr *pPg;
++    for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
++      char zBuf[SQLITE_PAGE_SIZE];
++      if( !pPg->dirty ) continue;
++      if( (int)pPg->pgno <= pPager->origDbSize ){
++        sqliteOsSeek(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)(pPg->pgno-1));
++        rc = sqliteOsRead(&pPager->fd, zBuf, SQLITE_PAGE_SIZE);
++        TRACE2("REFETCH %d\n", pPg->pgno);
++        CODEC(pPager, zBuf, pPg->pgno, 2);
++        if( rc ) break;
++      }else{
++        memset(zBuf, 0, SQLITE_PAGE_SIZE);
++      }
++      if( pPg->nRef==0 || memcmp(zBuf, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE) ){
++        memcpy(PGHDR_TO_DATA(pPg), zBuf, SQLITE_PAGE_SIZE);
++        memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra);
++      }
++      pPg->needSync = 0;
++      pPg->dirty = 0;
++    }
++  }
++
++end_playback:
++  if( rc!=SQLITE_OK ){
++    pager_unwritelock(pPager);
++    pPager->errMask |= PAGER_ERR_CORRUPT;
++    rc = SQLITE_CORRUPT;
++  }else{
++    rc = pager_unwritelock(pPager);
++  }
++  return rc;
++}
++
++/*
++** Playback the checkpoint journal.
++**
++** This is similar to playing back the transaction journal but with
++** a few extra twists.
++**
++**    (1)  The number of pages in the database file at the start of
++**         the checkpoint is stored in pPager->ckptSize, not in the
++**         journal file itself.
++**
++**    (2)  In addition to playing back the checkpoint journal, also
++**         playback all pages of the transaction journal beginning
++**         at offset pPager->ckptJSize.
++*/
++static int pager_ckpt_playback(Pager *pPager){
++  off_t szJ;               /* Size of the full journal */
++  int nRec;                /* Number of Records */
++  int i;                   /* Loop counter */
++  int rc;
++
++  /* Truncate the database back to its original size.
++  */
++  rc = sqliteOsTruncate(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)pPager->ckptSize);
++  pPager->dbSize = pPager->ckptSize;
++
++  /* Figure out how many records are in the checkpoint journal.
++  */
++  assert( pPager->ckptInUse && pPager->journalOpen );
++  sqliteOsSeek(&pPager->cpfd, 0);
++  nRec = pPager->ckptNRec;
++  
++  /* Copy original pages out of the checkpoint journal and back into the
++  ** database file.  Note that the checkpoint journal always uses format
++  ** 2 instead of format 3 since it does not need to be concerned with
++  ** power failures corrupting the journal and can thus omit the checksums.
++  */
++  for(i=nRec-1; i>=0; i--){
++    rc = pager_playback_one_page(pPager, &pPager->cpfd, 2);
++    assert( rc!=SQLITE_DONE );
++    if( rc!=SQLITE_OK ) goto end_ckpt_playback;
++  }
++
++  /* Figure out how many pages need to be copied out of the transaction
++  ** journal.
++  */
++  rc = sqliteOsSeek(&pPager->jfd, pPager->ckptJSize);
++  if( rc!=SQLITE_OK ){
++    goto end_ckpt_playback;
++  }
++  rc = sqliteOsFileSize(&pPager->jfd, &szJ);
++  if( rc!=SQLITE_OK ){
++    goto end_ckpt_playback;
++  }
++  nRec = (szJ - pPager->ckptJSize)/JOURNAL_PG_SZ(journal_format);
++  for(i=nRec-1; i>=0; i--){
++    rc = pager_playback_one_page(pPager, &pPager->jfd, journal_format);
++    if( rc!=SQLITE_OK ){
++      assert( rc!=SQLITE_DONE );
++      goto end_ckpt_playback;
++    }
++  }
++  
++end_ckpt_playback:
++  if( rc!=SQLITE_OK ){
++    pPager->errMask |= PAGER_ERR_CORRUPT;
++    rc = SQLITE_CORRUPT;
++  }
++  return rc;
++}
++
++/*
++** Change the maximum number of in-memory pages that are allowed.
++**
++** The maximum number is the absolute value of the mxPage parameter.
++** If mxPage is negative, the noSync flag is also set.  noSync bypasses
++** calls to sqliteOsSync().  The pager runs much faster with noSync on,
++** but if the operating system crashes or there is an abrupt power 
++** failure, the database file might be left in an inconsistent and
++** unrepairable state.  
++*/
++void sqlitepager_set_cachesize(Pager *pPager, int mxPage){
++  if( mxPage>=0 ){
++    pPager->noSync = pPager->tempFile;
++    if( pPager->noSync==0 ) pPager->needSync = 0;
++  }else{
++    pPager->noSync = 1;
++    mxPage = -mxPage;
++  }
++  if( mxPage>10 ){
++    pPager->mxPage = mxPage;
++  }
++}
++
++/*
++** Adjust the robustness of the database to damage due to OS crashes
++** or power failures by changing the number of syncs()s when writing
++** the rollback journal.  There are three levels:
++**
++**    OFF       sqliteOsSync() is never called.  This is the default
++**              for temporary and transient files.
++**
++**    NORMAL    The journal is synced once before writes begin on the
++**              database.  This is normally adequate protection, but
++**              it is theoretically possible, though very unlikely,
++**              that an inopertune power failure could leave the journal
++**              in a state which would cause damage to the database
++**              when it is rolled back.
++**
++**    FULL      The journal is synced twice before writes begin on the
++**              database (with some additional information - the nRec field
++**              of the journal header - being written in between the two
++**              syncs).  If we assume that writing a
++**              single disk sector is atomic, then this mode provides
++**              assurance that the journal will not be corrupted to the
++**              point of causing damage to the database during rollback.
++**
++** Numeric values associated with these states are OFF==1, NORMAL=2,
++** and FULL=3.
++*/
++void sqlitepager_set_safety_level(Pager *pPager, int level){
++  pPager->noSync =  level==1 || pPager->tempFile;
++  pPager->fullSync = level==3 && !pPager->tempFile;
++  if( pPager->noSync==0 ) pPager->needSync = 0;
++}
++
++/*
++** Open a temporary file.  Write the name of the file into zName
++** (zName 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.
++**
++** The OS will automatically delete the temporary file when it is
++** closed.
++*/
++static int sqlitepager_opentemp(char *zFile, OsFile *fd){
++  int cnt = 8;
++  int rc;
++  do{
++    cnt--;
++    sqliteOsTempFileName(zFile);
++    rc = sqliteOsOpenExclusive(zFile, fd, 1);
++  }while( cnt>0 && rc!=SQLITE_OK );
++  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 sqlitepager_get() and is only held open until the
++** last page is released using sqlitepager_unref().
++**
++** 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
++** automatically when it is closed.
++*/
++int sqlitepager_open(
++  Pager **ppPager,         /* Return the Pager structure here */
++  const char *zFilename,   /* Name of the database file to open */
++  int mxPage,              /* Max number of in-memory cache pages */
++  int nExtra,              /* Extra bytes append to each in-memory page */
++  int useJournal           /* TRUE to use a rollback journal on this file */
++){
++  Pager *pPager;
++  char *zFullPathname;
++  int nameLen;
++  OsFile fd;
++  int rc, i;
++  int tempFile;
++  int readOnly = 0;
++  char zTemp[SQLITE_TEMPNAME_SIZE];
++
++  *ppPager = 0;
++  if( sqlite_malloc_failed ){
++    return SQLITE_NOMEM;
++  }
++  if( zFilename && zFilename[0] ){
++    zFullPathname = sqliteOsFullPathname(zFilename);
++    rc = sqliteOsOpenReadWrite(zFullPathname, &fd, &readOnly);
++    tempFile = 0;
++  }else{
++    rc = sqlitepager_opentemp(zTemp, &fd);
++    zFilename = zTemp;
++    zFullPathname = sqliteOsFullPathname(zFilename);
++    tempFile = 1;
++  }
++  if( sqlite_malloc_failed ){
++    return SQLITE_NOMEM;
++  }
++  if( rc!=SQLITE_OK ){
++    sqliteFree(zFullPathname);
++    return SQLITE_CANTOPEN;
++  }
++  nameLen = strlen(zFullPathname);
++  pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
++  if( pPager==0 ){
++    sqliteOsClose(&fd);
++    sqliteFree(zFullPathname);
++    return SQLITE_NOMEM;
++  }
++  SET_PAGER(pPager);
++  pPager->zFilename = (char*)&pPager[1];
++  pPager->zDirectory = &pPager->zFilename[nameLen+1];
++  pPager->zJournal = &pPager->zDirectory[nameLen+1];
++  strcpy(pPager->zFilename, zFullPathname);
++  strcpy(pPager->zDirectory, zFullPathname);
++  for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){}
++  if( i>0 ) pPager->zDirectory[i-1] = 0;
++  strcpy(pPager->zJournal, zFullPathname);
++  sqliteFree(zFullPathname);
++  strcpy(&pPager->zJournal[nameLen], "-journal");
++  pPager->fd = fd;
++  pPager->journalOpen = 0;
++  pPager->useJournal = useJournal;
++  pPager->ckptOpen = 0;
++  pPager->ckptInUse = 0;
++  pPager->nRef = 0;
++  pPager->dbSize = -1;
++  pPager->ckptSize = 0;
++  pPager->ckptJSize = 0;
++  pPager->nPage = 0;
++  pPager->mxPage = mxPage>5 ? mxPage : 10;
++  pPager->state = SQLITE_UNLOCK;
++  pPager->errMask = 0;
++  pPager->tempFile = tempFile;
++  pPager->readOnly = readOnly;
++  pPager->needSync = 0;
++  pPager->noSync = pPager->tempFile || !useJournal;
++  pPager->pFirst = 0;
++  pPager->pFirstSynced = 0;
++  pPager->pLast = 0;
++  pPager->nExtra = nExtra;
++  memset(pPager->aHash, 0, sizeof(pPager->aHash));
++  *ppPager = pPager;
++  return SQLITE_OK;
++}
++
++/*
++** Set the destructor for this pager.  If not NULL, the destructor is called
++** 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 sqlitepager_close().  
++** Destructors are only called by sqlitepager_unref().
++*/
++void sqlitepager_set_destructor(Pager *pPager, void (*xDesc)(void*)){
++  pPager->xDestructor = xDesc;
++}
++
++/*
++** Return the total number of pages in the disk file associated with
++** pPager.
++*/
++int sqlitepager_pagecount(Pager *pPager){
++  off_t n;
++  assert( pPager!=0 );
++  if( pPager->dbSize>=0 ){
++    return pPager->dbSize;
++  }
++  if( sqliteOsFileSize(&pPager->fd, &n)!=SQLITE_OK ){
++    pPager->errMask |= PAGER_ERR_DISK;
++    return 0;
++  }
++  n /= SQLITE_PAGE_SIZE;
++  if( pPager->state!=SQLITE_UNLOCK ){
++    pPager->dbSize = n;
++  }
++  return n;
++}
++
++/*
++** Forward declaration
++*/
++static int syncJournal(Pager*);
++
++/*
++** Truncate the file to the number of pages specified.
++*/
++int sqlitepager_truncate(Pager *pPager, Pgno nPage){
++  int rc;
++  if( pPager->dbSize<0 ){
++    sqlitepager_pagecount(pPager);
++  }
++  if( pPager->errMask!=0 ){
++    rc = pager_errcode(pPager);
++    return rc;
++  }
++  if( nPage>=(unsigned)pPager->dbSize ){
++    return SQLITE_OK;
++  }
++  syncJournal(pPager);
++  rc = sqliteOsTruncate(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)nPage);
++  if( rc==SQLITE_OK ){
++    pPager->dbSize = nPage;
++  }
++  return rc;
++}
++
++/*
++** Shutdown the page cache.  Free all memory and close all files.
++**
++** If a transaction was in progress when this routine is called, that
++** transaction is rolled back.  All outstanding pages are invalidated
++** and their memory is freed.  Any attempt to use a page associated
++** with this page cache after this function returns will likely
++** result in a coredump.
++*/
++int sqlitepager_close(Pager *pPager){
++  PgHdr *pPg, *pNext;
++  switch( pPager->state ){
++    case SQLITE_WRITELOCK: {
++      sqlitepager_rollback(pPager);
++      sqliteOsUnlock(&pPager->fd);
++      assert( pPager->journalOpen==0 );
++      break;
++    }
++    case SQLITE_READLOCK: {
++      sqliteOsUnlock(&pPager->fd);
++      break;
++    }
++    default: {
++      /* Do nothing */
++      break;
++    }
++  }
++  for(pPg=pPager->pAll; pPg; pPg=pNext){
++    pNext = pPg->pNextAll;
++    sqliteFree(pPg);
++  }
++  sqliteOsClose(&pPager->fd);
++  assert( pPager->journalOpen==0 );
++  /* Temp files are automatically deleted by the OS
++  ** if( pPager->tempFile ){
++  **   sqliteOsDelete(pPager->zFilename);
++  ** }
++  */
++  CLR_PAGER(pPager);
++  if( pPager->zFilename!=(char*)&pPager[1] ){
++    assert( 0 );  /* Cannot happen */
++    sqliteFree(pPager->zFilename);
++    sqliteFree(pPager->zJournal);
++    sqliteFree(pPager->zDirectory);
++  }
++  sqliteFree(pPager);
++  return SQLITE_OK;
++}
++
++/*
++** Return the page number for the given page data.
++*/
++Pgno sqlitepager_pagenumber(void *pData){
++  PgHdr *p = DATA_TO_PGHDR(pData);
++  return p->pgno;
++}
++
++/*
++** Increment the reference count for a page.  If the page is
++** currently on the freelist (the reference count is zero) then
++** remove it from the freelist.
++*/
++#define page_ref(P)   ((P)->nRef==0?_page_ref(P):(void)(P)->nRef++)
++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;
++    }
++    pPg->pPager->nRef++;
++  }
++  pPg->nRef++;
++  REFINFO(pPg);
++}
++
++/*
++** Increment the reference count for a page.  The input pointer is
++** a reference to the page data.
++*/
++int sqlitepager_ref(void *pData){
++  PgHdr *pPg = DATA_TO_PGHDR(pData);
++  page_ref(pPg);
++  return SQLITE_OK;
++}
++
++/*
++** Sync the journal.  In other words, make sure all the pages that have
++** been written to the journal have actually reached the surface of the
++** disk.  It is not safe to modify the original database file until after
++** the journal has been synced.  If the original database is modified before
++** the journal is synced and a power failure occurs, the unsynced journal
++** data would be lost and we would be unable to completely rollback the
++** database changes.  Database corruption would occur.
++** 
++** This routine also updates the nRec field in the header of the journal.
++** (See comments on the pager_playback() routine for additional information.)
++** If the sync mode is FULL, two syncs will occur.  First the whole journal
++** 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.
++**
++** This routine clears the needSync field of every page current held in
++** memory.
++*/
++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 ){
++      assert( pPager->journalOpen );
++      /* assert( !pPager->noSync ); // noSync might be set if synchronous
++      ** was turned off after the transaction was started.  Ticket #615 */
++#ifndef NDEBUG
++      {
++        /* Make sure the pPager->nRec counter we are keeping agrees
++        ** with the nRec computed from the size of the journal file.
++        */
++        off_t hdrSz, pgSz, jSz;
++        hdrSz = JOURNAL_HDR_SZ(journal_format);
++        pgSz = JOURNAL_PG_SZ(journal_format);
++        rc = sqliteOsFileSize(&pPager->jfd, &jSz);
++        if( rc!=0 ) return rc;
++        assert( pPager->nRec*pgSz+hdrSz==jSz );
++      }
++#endif
++      if( journal_format>=3 ){
++        /* Write the nRec value into the journal file header */
++        off_t szJ;
++        if( pPager->fullSync ){
++          TRACE1("SYNC\n");
++          rc = sqliteOsSync(&pPager->jfd);
++          if( rc!=0 ) return rc;
++        }
++        sqliteOsSeek(&pPager->jfd, sizeof(aJournalMagic1));
++        rc = write32bits(&pPager->jfd, pPager->nRec);
++        if( rc ) return rc;
++        szJ = JOURNAL_HDR_SZ(journal_format) +
++                 pPager->nRec*JOURNAL_PG_SZ(journal_format);
++        sqliteOsSeek(&pPager->jfd, szJ);
++      }
++      TRACE1("SYNC\n");
++      rc = sqliteOsSync(&pPager->jfd);
++      if( rc!=0 ) return rc;
++      pPager->journalStarted = 1;
++    }
++    pPager->needSync = 0;
++
++    /* Erase the needSync flag from every page.
++    */
++    for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
++      pPg->needSync = 0;
++    }
++    pPager->pFirstSynced = pPager->pFirst;
++  }
++
++#ifndef NDEBUG
++  /* If the Pager.needSync flag is clear then the PgHdr.needSync
++  ** flag must also be clear for all pages.  Verify that this
++  ** invariant is true.
++  */
++  else{
++    for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
++      assert( pPg->needSync==0 );
++    }
++    assert( pPager->pFirstSynced==pPager->pFirst );
++  }
++#endif
++
++  return rc;
++}
++
++/*
++** Given a list of pages (connected by the PgHdr.pDirty pointer) write
++** every one of those pages out to the database file and mark them all
++** as clean.
++*/
++static int pager_write_pagelist(PgHdr *pList){
++  Pager *pPager;
++  int rc;
++
++  if( pList==0 ) return SQLITE_OK;
++  pPager = pList->pPager;
++  while( pList ){
++    assert( pList->dirty );
++    sqliteOsSeek(&pPager->fd, (pList->pgno-1)*(off_t)SQLITE_PAGE_SIZE);
++    CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
++    TRACE2("STORE %d\n", pList->pgno);
++    rc = sqliteOsWrite(&pPager->fd, PGHDR_TO_DATA(pList), SQLITE_PAGE_SIZE);
++    CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0);
++    if( rc ) return rc;
++    pList->dirty = 0;
++    pList = pList->pDirty;
++  }
++  return SQLITE_OK;
++}
++
++/*
++** Collect every dirty page into a dirty list and
++** return a pointer to the head of that list.  All pages are
++** collected even if they are still in use.
++*/
++static PgHdr *pager_get_all_dirty_pages(Pager *pPager){
++  PgHdr *p, *pList;
++  pList = 0;
++  for(p=pPager->pAll; p; p=p->pNextAll){
++    if( p->dirty ){
++      p->pDirty = pList;
++      pList = p;
++    }
++  }
++  return pList;
++}
++
++/*
++** Acquire a page.
++**
++** 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
++** 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
++** to zeros the first time a page is loaded into memory.
++**
++** The acquisition might fail for several reasons.  In all cases,
++** an appropriate error code is returned and *ppPage is set to NULL.
++**
++** See also sqlitepager_lookup().  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()
++** 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
++** or journal files.
++*/
++int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){
++  PgHdr *pPg;
++  int rc;
++
++  /* Make sure we have not hit any critical errors.
++  */ 
++  assert( pPager!=0 );
++  assert( pgno!=0 );
++  *ppPage = 0;
++  if( pPager->errMask & ~(PAGER_ERR_FULL) ){
++    return pager_errcode(pPager);
++  }
++
++  /* If this is the first page accessed, then get a read lock
++  ** on the database file.
++  */
++  if( pPager->nRef==0 ){
++    rc = sqliteOsReadLock(&pPager->fd);
++    if( rc!=SQLITE_OK ){
++      return rc;
++    }
++    pPager->state = SQLITE_READLOCK;
++
++    /* If a journal file exists, try to play it back.
++    */
++    if( pPager->useJournal && sqliteOsFileExists(pPager->zJournal) ){
++       int rc;
++
++       /* Get a write lock on the database
++       */
++       rc = sqliteOsWriteLock(&pPager->fd);
++       if( rc!=SQLITE_OK ){
++         if( sqliteOsUnlock(&pPager->fd)!=SQLITE_OK ){
++           /* This should never happen! */
++           rc = SQLITE_INTERNAL;
++         }
++         return rc;
++       }
++       pPager->state = SQLITE_WRITELOCK;
++
++       /* 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 = sqliteOsOpenReadOnly(pPager->zJournal, &pPager->jfd);
++       if( rc!=SQLITE_OK ){
++         rc = sqliteOsUnlock(&pPager->fd);
++         assert( rc==SQLITE_OK );
++         return SQLITE_BUSY;
++       }
++       pPager->journalOpen = 1;
++       pPager->journalStarted = 0;
++
++       /* Playback and delete the journal.  Drop the database write
++       ** lock and reacquire the read lock.
++       */
++       rc = pager_playback(pPager, 0);
++       if( rc!=SQLITE_OK ){
++         return rc;
++       }
++    }
++    pPg = 0;
++  }else{
++    /* Search for page in cache */
++    pPg = pager_lookup(pPager, pgno);
++  }
++  if( pPg==0 ){
++    /* The requested page is not in the page cache. */
++    int h;
++    pPager->nMiss++;
++    if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 ){
++      /* Create a new page */
++      pPg = sqliteMallocRaw( sizeof(*pPg) + SQLITE_PAGE_SIZE 
++                              + sizeof(u32) + pPager->nExtra );
++      if( pPg==0 ){
++        pager_unwritelock(pPager);
++        pPager->errMask |= PAGER_ERR_MEM;
++        return SQLITE_NOMEM;
++      }
++      memset(pPg, 0, sizeof(*pPg));
++      pPg->pPager = pPager;
++      pPg->pNextAll = pPager->pAll;
++      if( pPager->pAll ){
++        pPager->pAll->pPrevAll = pPg;
++      }
++      pPg->pPrevAll = 0;
++      pPager->pAll = pPg;
++      pPager->nPage++;
++    }else{
++      /* Find a page to recycle.  Try to locate a page that does not
++      ** require us to do an fsync() on the journal.
++      */
++      pPg = pPager->pFirstSynced;
++
++      /* If we could not find a page that does not require an fsync()
++      ** on the journal file then fsync the journal file.  This is a
++      ** very slow operation, so we work hard to avoid it.  But sometimes
++      ** it can't be helped.
++      */
++      if( pPg==0 ){
++        int rc = syncJournal(pPager);
++        if( rc!=0 ){
++          sqlitepager_rollback(pPager);
++          return SQLITE_IOERR;
++        }
++        pPg = pPager->pFirst;
++      }
++      assert( pPg->nRef==0 );
++
++      /* Write the page to the database file if it is dirty.
++      */
++      if( pPg->dirty ){
++        assert( pPg->needSync==0 );
++        pPg->pDirty = 0;
++        rc = pager_write_pagelist( pPg );
++        if( rc!=SQLITE_OK ){
++          sqlitepager_rollback(pPager);
++          return SQLITE_IOERR;
++        }
++      }
++      assert( pPg->dirty==0 );
++
++      /* If the page we are recycling is marked as alwaysRollback, then
++      ** set the global alwaysRollback flag, thus disabling the
++      ** sqlite_dont_rollback() optimization for the rest of this transaction.
++      ** It is necessary to do this because the page marked alwaysRollback
++      ** might be reloaded at a later time but at that point we won't remember
++      ** that is was marked alwaysRollback.  This means that all pages must
++      ** be marked as alwaysRollback from here on out.
++      */
++      if( pPg->alwaysRollback ){
++        pPager->alwaysRollback = 1;
++      }
++
++      /* Unlink the old page from the free list and the hash table
++      */
++      if( pPg==pPager->pFirstSynced ){
++        PgHdr *p = pPg->pNextFree;
++        while( p && p->needSync ){ p = p->pNextFree; }
++        pPager->pFirstSynced = p;
++      }
++      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;
++      if( pPg->pNextHash ){
++        pPg->pNextHash->pPrevHash = pPg->pPrevHash;
++      }
++      if( pPg->pPrevHash ){
++        pPg->pPrevHash->pNextHash = pPg->pNextHash;
++      }else{
++        h = pager_hash(pPg->pgno);
++        assert( pPager->aHash[h]==pPg );
++        pPager->aHash[h] = pPg->pNextHash;
++      }
++      pPg->pNextHash = pPg->pPrevHash = 0;
++      pPager->nOvfl++;
++    }
++    pPg->pgno = pgno;
++    if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){
++      sqliteCheckMemory(pPager->aInJournal, pgno/8);
++      assert( pPager->journalOpen );
++      pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0;
++      pPg->needSync = 0;
++    }else{
++      pPg->inJournal = 0;
++      pPg->needSync = 0;
++    }
++    if( pPager->aInCkpt && (int)pgno<=pPager->ckptSize
++             && (pPager->aInCkpt[pgno/8] & (1<<(pgno&7)))!=0 ){
++      page_add_to_ckpt_list(pPg);
++    }else{
++      page_remove_from_ckpt_list(pPg);
++    }
++    pPg->dirty = 0;
++    pPg->nRef = 1;
++    REFINFO(pPg);
++    pPager->nRef++;
++    h = pager_hash(pgno);
++    pPg->pNextHash = pPager->aHash[h];
++    pPager->aHash[h] = pPg;
++    if( pPg->pNextHash ){
++      assert( pPg->pNextHash->pPrevHash==0 );
++      pPg->pNextHash->pPrevHash = pPg;
++    }
++    if( pPager->nExtra>0 ){
++      memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra);
++    }
++    if( pPager->dbSize<0 ) sqlitepager_pagecount(pPager);
++    if( pPager->errMask!=0 ){
++      sqlitepager_unref(PGHDR_TO_DATA(pPg));
++      rc = pager_errcode(pPager);
++      return rc;
++    }
++    if( pPager->dbSize<(int)pgno ){
++      memset(PGHDR_TO_DATA(pPg), 0, SQLITE_PAGE_SIZE);
++    }else{
++      int rc;
++      sqliteOsSeek(&pPager->fd, (pgno-1)*(off_t)SQLITE_PAGE_SIZE);
++      rc = sqliteOsRead(&pPager->fd, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE);
++      TRACE2("FETCH %d\n", pPg->pgno);
++      CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
++      if( rc!=SQLITE_OK ){
++        off_t fileSize;
++        if( sqliteOsFileSize(&pPager->fd,&fileSize)!=SQLITE_OK
++               || fileSize>=pgno*SQLITE_PAGE_SIZE ){
++          sqlitepager_unref(PGHDR_TO_DATA(pPg));
++          return rc;
++        }else{
++          memset(PGHDR_TO_DATA(pPg), 0, SQLITE_PAGE_SIZE);
++        }
++      }
++    }
++  }else{
++    /* The requested page is in the page cache. */
++    pPager->nHit++;
++    page_ref(pPg);
++  }
++  *ppPage = PGHDR_TO_DATA(pPg);
++  return SQLITE_OK;
++}
++
++/*
++** 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 sqlitepager_get().  The difference between this routine
++** and sqlitepager_get() 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 *sqlitepager_lookup(Pager *pPager, Pgno pgno){
++  PgHdr *pPg;
++
++  assert( pPager!=0 );
++  assert( pgno!=0 );
++  if( pPager->errMask & ~(PAGER_ERR_FULL) ){
++    return 0;
++  }
++  /* if( pPager->nRef==0 ){
++  **  return 0;
++  ** }
++  */
++  pPg = pager_lookup(pPager, pgno);
++  if( pPg==0 ) return 0;
++  page_ref(pPg);
++  return PGHDR_TO_DATA(pPg);
++}
++
++/*
++** Release a page.
++**
++** If the number of references to the page drop to zero, then the
++** page is added to the LRU list.  When all references to all pages
++** are released, a rollback occurs and the lock on the database is
++** removed.
++*/
++int sqlitepager_unref(void *pData){
++  PgHdr *pPg;
++
++  /* Decrement the reference count for this page
++  */
++  pPg = DATA_TO_PGHDR(pData);
++  assert( pPg->nRef>0 );
++  pPg->nRef--;
++  REFINFO(pPg);
++
++  /* When the number of references to a page reach 0, call the
++  ** 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;
++    }
++    if( pPager->xDestructor ){
++      pPager->xDestructor(pData);
++    }
++  
++    /* When all pages reach the freelist, drop the read lock from
++    ** the database file.
++    */
++    pPager->nRef--;
++    assert( pPager->nRef>=0 );
++    if( pPager->nRef==0 ){
++      pager_reset(pPager);
++    }
++  }
++  return SQLITE_OK;
++}
++
++/*
++** Create a journal file for pPager.  There should already be a write
++** lock on the database file when this routine is called.
++**
++** Return SQLITE_OK if everything.  Return an error code and release the
++** write lock if anything goes wrong.
++*/
++static int pager_open_journal(Pager *pPager){
++  int rc;
++  assert( pPager->state==SQLITE_WRITELOCK );
++  assert( pPager->journalOpen==0 );
++  assert( pPager->useJournal );
++  sqlitepager_pagecount(pPager);
++  pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 );
++  if( pPager->aInJournal==0 ){
++    sqliteOsReadLock(&pPager->fd);
++    pPager->state = SQLITE_READLOCK;
++    return SQLITE_NOMEM;
++  }
++  rc = sqliteOsOpenExclusive(pPager->zJournal, &pPager->jfd,pPager->tempFile);
++  if( rc!=SQLITE_OK ){
++    sqliteFree(pPager->aInJournal);
++    pPager->aInJournal = 0;
++    sqliteOsReadLock(&pPager->fd);
++    pPager->state = SQLITE_READLOCK;
++    return SQLITE_CANTOPEN;
++  }
++  sqliteOsOpenDirectory(pPager->zDirectory, &pPager->jfd);
++  pPager->journalOpen = 1;
++  pPager->journalStarted = 0;
++  pPager->needSync = 0;
++  pPager->alwaysRollback = 0;
++  pPager->nRec = 0;
++  if( pPager->errMask!=0 ){
++    rc = pager_errcode(pPager);
++    return rc;
++  }
++  pPager->origDbSize = pPager->dbSize;
++  if( journal_format==JOURNAL_FORMAT_3 ){
++    rc = sqliteOsWrite(&pPager->jfd, aJournalMagic3, sizeof(aJournalMagic3));
++    if( rc==SQLITE_OK ){
++      rc = write32bits(&pPager->jfd, pPager->noSync ? 0xffffffff : 0);
++    }
++    if( rc==SQLITE_OK ){
++      sqliteRandomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
++      rc = write32bits(&pPager->jfd, pPager->cksumInit);
++    }
++  }else if( journal_format==JOURNAL_FORMAT_2 ){
++    rc = sqliteOsWrite(&pPager->jfd, aJournalMagic2, sizeof(aJournalMagic2));
++  }else{
++    assert( journal_format==JOURNAL_FORMAT_1 );
++    rc = sqliteOsWrite(&pPager->jfd, aJournalMagic1, sizeof(aJournalMagic1));
++  }
++  if( rc==SQLITE_OK ){
++    rc = write32bits(&pPager->jfd, pPager->dbSize);
++  }
++  if( pPager->ckptAutoopen && rc==SQLITE_OK ){
++    rc = sqlitepager_ckpt_begin(pPager);
++  }
++  if( rc!=SQLITE_OK ){
++    rc = pager_unwritelock(pPager);
++    if( rc==SQLITE_OK ){
++      rc = SQLITE_FULL;
++    }
++  }
++  return rc;  
++}
++
++/*
++** Acquire a write-lock on the database.  The lock is removed when
++** the any of the following happen:
++**
++**   *  sqlitepager_commit() is called.
++**   *  sqlitepager_rollback() is called.
++**   *  sqlitepager_close() is called.
++**   *  sqlitepager_unref() is called to on every outstanding page.
++**
++** The 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 acquire a pointer to the Pager structure and as proof that there
++** is already a read-lock on the database.
++**
++** A journal file is opened if this is not a temporary file.  For
++** temporary files, the opening of the journal file is deferred until
++** there is an actual need to write to the journal.
++**
++** If the database is already write-locked, this routine is a no-op.
++*/
++int sqlitepager_begin(void *pData){
++  PgHdr *pPg = DATA_TO_PGHDR(pData);
++  Pager *pPager = pPg->pPager;
++  int rc = SQLITE_OK;
++  assert( pPg->nRef>0 );
++  assert( pPager->state!=SQLITE_UNLOCK );
++  if( pPager->state==SQLITE_READLOCK ){
++    assert( pPager->aInJournal==0 );
++    rc = sqliteOsWriteLock(&pPager->fd);
++    if( rc!=SQLITE_OK ){
++      return rc;
++    }
++    pPager->state = SQLITE_WRITELOCK;
++    pPager->dirtyFile = 0;
++    TRACE1("TRANSACTION\n");
++    if( pPager->useJournal && !pPager->tempFile ){
++      rc = pager_open_journal(pPager);
++    }
++  }
++  return rc;
++}
++
++/*
++** Mark a data page as writeable.  The page is written into the journal 
++** if it is not there already.  This routine must be called before making
++** changes to a page.
++**
++** The first time this routine is called, the pager creates a new
++** journal and acquires a write lock on the database.  If the write
++** lock could not be acquired, this routine returns SQLITE_BUSY.  The
++** calling routine must check for that return value and be careful not to
++** change any page data until this routine returns SQLITE_OK.
++**
++** 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 sqlitepager_commit() or sqlitepager_rollback() to
++** reset.
++*/
++int sqlitepager_write(void *pData){
++  PgHdr *pPg = DATA_TO_PGHDR(pData);
++  Pager *pPager = pPg->pPager;
++  int rc = SQLITE_OK;
++
++  /* Check for errors
++  */
++  if( pPager->errMask ){ 
++    return pager_errcode(pPager);
++  }
++  if( pPager->readOnly ){
++    return SQLITE_PERM;
++  }
++
++  /* Mark the page as dirty.  If the page has already been written
++  ** to the journal then we can return right away.
++  */
++  pPg->dirty = 1;
++  if( pPg->inJournal && (pPg->inCkpt || pPager->ckptInUse==0) ){
++    pPager->dirtyFile = 1;
++    return SQLITE_OK;
++  }
++
++  /* If we get this far, it means that the page needs to be
++  ** written to the transaction journal or the ckeckpoint journal
++  ** or both.
++  **
++  ** First check to see that the transaction journal exists and
++  ** create it if it does not.
++  */
++  assert( pPager->state!=SQLITE_UNLOCK );
++  rc = sqlitepager_begin(pData);
++  if( rc!=SQLITE_OK ){
++    return rc;
++  }
++  assert( pPager->state==SQLITE_WRITELOCK );
++  if( !pPager->journalOpen && pPager->useJournal ){
++    rc = pager_open_journal(pPager);
++    if( rc!=SQLITE_OK ) return rc;
++  }
++  assert( pPager->journalOpen || !pPager->useJournal );
++  pPager->dirtyFile = 1;
++
++  /* The transaction journal now exists and we have a write lock on the
++  ** main database file.  Write the current page to the transaction 
++  ** journal if it is not there already.
++  */
++  if( !pPg->inJournal && pPager->useJournal ){
++    if( (int)pPg->pgno <= pPager->origDbSize ){
++      int szPg;
++      u32 saved;
++      if( journal_format>=JOURNAL_FORMAT_3 ){
++        u32 cksum = pager_cksum(pPager, pPg->pgno, pData);
++        saved = *(u32*)PGHDR_TO_EXTRA(pPg);
++        store32bits(cksum, pPg, SQLITE_PAGE_SIZE);
++        szPg = SQLITE_PAGE_SIZE+8;
++      }else{
++        szPg = SQLITE_PAGE_SIZE+4;
++      }
++      store32bits(pPg->pgno, pPg, -4);
++      CODEC(pPager, pData, pPg->pgno, 7);
++      rc = sqliteOsWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
++      TRACE3("JOURNAL %d %d\n", pPg->pgno, pPg->needSync);
++      CODEC(pPager, pData, pPg->pgno, 0);
++      if( journal_format>=JOURNAL_FORMAT_3 ){
++        *(u32*)PGHDR_TO_EXTRA(pPg) = saved;
++      }
++      if( rc!=SQLITE_OK ){
++        sqlitepager_rollback(pPager);
++        pPager->errMask |= PAGER_ERR_FULL;
++        return rc;
++      }
++      pPager->nRec++;
++      assert( pPager->aInJournal!=0 );
++      pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
++      pPg->needSync = !pPager->noSync;
++      pPg->inJournal = 1;
++      if( pPager->ckptInUse ){
++        pPager->aInCkpt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
++        page_add_to_ckpt_list(pPg);
++      }
++    }else{
++      pPg->needSync = !pPager->journalStarted && !pPager->noSync;
++      TRACE3("APPEND %d %d\n", pPg->pgno, pPg->needSync);
++    }
++    if( pPg->needSync ){
++      pPager->needSync = 1;
++    }
++  }
++
++  /* If the checkpoint journal is open and the page is not in it,
++  ** then write the current page to the checkpoint journal.  Note that
++  ** the checkpoint journal always uses the simplier format 2 that lacks
++  ** checksums.  The header is also omitted from the checkpoint journal.
++  */
++  if( pPager->ckptInUse && !pPg->inCkpt && (int)pPg->pgno<=pPager->ckptSize ){
++    assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
++    store32bits(pPg->pgno, pPg, -4);
++    CODEC(pPager, pData, pPg->pgno, 7);
++    rc = sqliteOsWrite(&pPager->cpfd, &((char*)pData)[-4], SQLITE_PAGE_SIZE+4);
++    TRACE2("CKPT-JOURNAL %d\n", pPg->pgno);
++    CODEC(pPager, pData, pPg->pgno, 0);
++    if( rc!=SQLITE_OK ){
++      sqlitepager_rollback(pPager);
++      pPager->errMask |= PAGER_ERR_FULL;
++      return rc;
++    }
++    pPager->ckptNRec++;
++    assert( pPager->aInCkpt!=0 );
++    pPager->aInCkpt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
++    page_add_to_ckpt_list(pPg);
++  }
++
++  /* Update the database size and return.
++  */
++  if( pPager->dbSize<(int)pPg->pgno ){
++    pPager->dbSize = pPg->pgno;
++  }
++  return rc;
++}
++
++/*
++** Return TRUE if the page given in the argument was previously passed
++** to sqlitepager_write().  In other words, return TRUE if it is ok
++** to change the content of the page.
++*/
++int sqlitepager_iswriteable(void *pData){
++  PgHdr *pPg = DATA_TO_PGHDR(pData);
++  return pPg->dirty;
++}
++
++/*
++** Replace the content of a single page with the information in the third
++** argument.
++*/
++int sqlitepager_overwrite(Pager *pPager, Pgno pgno, void *pData){
++  void *pPage;
++  int rc;
++
++  rc = sqlitepager_get(pPager, pgno, &pPage);
++  if( rc==SQLITE_OK ){
++    rc = sqlitepager_write(pPage);
++    if( rc==SQLITE_OK ){
++      memcpy(pPage, pData, SQLITE_PAGE_SIZE);
++    }
++    sqlitepager_unref(pPage);
++  }
++  return rc;
++}
++
++/*
++** 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
++** that page might be marked as dirty.
++**
++** The overlying software layer calls this routine when all of the data
++** on the given page is unused.  The pager marks the page as clean so
++** that it does not get written to disk.
++**
++** Tests show that this optimization, together with the
++** sqlitepager_dont_rollback() 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 sqlitepager_dont_rollback() 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.
++*/
++void sqlitepager_dont_write(Pager *pPager, Pgno pgno){
++  PgHdr *pPg;
++
++  pPg = pager_lookup(pPager, pgno);
++  pPg->alwaysRollback = 1;
++  if( pPg && pPg->dirty && !pPager->ckptInUse ){
++    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.
++      ** When the database file grows, we must make sure that the last page
++      ** gets written at least once so that the disk file will be the correct
++      ** size. If you do not write this page and the size of the file
++      ** on the disk ends up being too small, that can lead to database
++      ** corruption during the next transaction.
++      */
++    }else{
++      TRACE2("DONT_WRITE %d\n", pgno);
++      pPg->dirty = 0;
++    }
++  }
++}
++
++/*
++** A call to this routine tells the pager that if a rollback occurs,
++** 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.
++*/
++void sqlitepager_dont_rollback(void *pData){
++  PgHdr *pPg = DATA_TO_PGHDR(pData);
++  Pager *pPager = pPg->pPager;
++
++  if( pPager->state!=SQLITE_WRITELOCK || pPager->journalOpen==0 ) return;
++  if( pPg->alwaysRollback || pPager->alwaysRollback ) 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->ckptInUse ){
++      pPager->aInCkpt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
++      page_add_to_ckpt_list(pPg);
++    }
++    TRACE2("DONT_ROLLBACK %d\n", pPg->pgno);
++  }
++  if( pPager->ckptInUse && !pPg->inCkpt && (int)pPg->pgno<=pPager->ckptSize ){
++    assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
++    assert( pPager->aInCkpt!=0 );
++    pPager->aInCkpt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
++    page_add_to_ckpt_list(pPg);
++  }
++}
++
++/*
++** Commit all changes to the database and release the write lock.
++**
++** If the commit fails for any reason, a rollback attempt is made
++** and an error code is returned.  If the commit worked, SQLITE_OK
++** is returned.
++*/
++int sqlitepager_commit(Pager *pPager){
++  int rc;
++  PgHdr *pPg;
++
++  if( pPager->errMask==PAGER_ERR_FULL ){
++    rc = sqlitepager_rollback(pPager);
++    if( rc==SQLITE_OK ){
++      rc = SQLITE_FULL;
++    }
++    return rc;
++  }
++  if( pPager->errMask!=0 ){
++    rc = pager_errcode(pPager);
++    return rc;
++  }
++  if( pPager->state!=SQLITE_WRITELOCK ){
++    return SQLITE_ERROR;
++  }
++  TRACE1("COMMIT\n");
++  if( pPager->dirtyFile==0 ){
++    /* Exit early (without doing the time-consuming sqliteOsSync() 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 = syncJournal(pPager);
++  if( rc!=SQLITE_OK ){
++    goto commit_abort;
++  }
++  pPg = pager_get_all_dirty_pages(pPager);
++  if( pPg ){
++    rc = pager_write_pagelist(pPg);
++    if( rc || (!pPager->noSync && sqliteOsSync(&pPager->fd)!=SQLITE_OK) ){
++      goto commit_abort;
++    }
++  }
++  rc = pager_unwritelock(pPager);
++  pPager->dbSize = -1;
++  return rc;
++
++  /* Jump here if anything goes wrong during the commit process.
++  */
++commit_abort:
++  rc = sqlitepager_rollback(pPager);
++  if( rc==SQLITE_OK ){
++    rc = SQLITE_FULL;
++  }
++  return rc;
++}
++
++/*
++** Rollback all changes.  The database falls back to read-only mode.
++** All in-memory cache pages revert to their original data contents.
++** 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
++** 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 sqlitepager_rollback(Pager *pPager){
++  int rc;
++  TRACE1("ROLLBACK\n");
++  if( !pPager->dirtyFile || !pPager->journalOpen ){
++    rc = pager_unwritelock(pPager);
++    pPager->dbSize = -1;
++    return rc;
++  }
++
++  if( pPager->errMask!=0 && pPager->errMask!=PAGER_ERR_FULL ){
++    if( pPager->state>=SQLITE_WRITELOCK ){
++      pager_playback(pPager, 1);
++    }
++    return pager_errcode(pPager);
++  }
++  if( pPager->state!=SQLITE_WRITELOCK ){
++    return SQLITE_OK;
++  }
++  rc = pager_playback(pPager, 1);
++  if( rc!=SQLITE_OK ){
++    rc = SQLITE_CORRUPT;
++    pPager->errMask |= PAGER_ERR_CORRUPT;
++  }
++  pPager->dbSize = -1;
++  return rc;
++}
++
++/*
++** Return TRUE if the database file is opened read-only.  Return FALSE
++** if the database is (in theory) writable.
++*/
++int sqlitepager_isreadonly(Pager *pPager){
++  return pPager->readOnly;
++}
++
++/*
++** This routine is used for testing and analysis only.
++*/
++int *sqlitepager_stats(Pager *pPager){
++  static int a[9];
++  a[0] = pPager->nRef;
++  a[1] = pPager->nPage;
++  a[2] = pPager->mxPage;
++  a[3] = pPager->dbSize;
++  a[4] = pPager->state;
++  a[5] = pPager->errMask;
++  a[6] = pPager->nHit;
++  a[7] = pPager->nMiss;
++  a[8] = pPager->nOvfl;
++  return a;
++}
++
++/*
++** Set the checkpoint.
++**
++** This routine should be called with the transaction journal already
++** open.  A new checkpoint journal is created that can be used to rollback
++** changes of a single SQL command within a larger transaction.
++*/
++int sqlitepager_ckpt_begin(Pager *pPager){
++  int rc;
++  char zTemp[SQLITE_TEMPNAME_SIZE];
++  if( !pPager->journalOpen ){
++    pPager->ckptAutoopen = 1;
++    return SQLITE_OK;
++  }
++  assert( pPager->journalOpen );
++  assert( !pPager->ckptInUse );
++  pPager->aInCkpt = sqliteMalloc( pPager->dbSize/8 + 1 );
++  if( pPager->aInCkpt==0 ){
++    sqliteOsReadLock(&pPager->fd);
++    return SQLITE_NOMEM;
++  }
++#ifndef NDEBUG
++  rc = sqliteOsFileSize(&pPager->jfd, &pPager->ckptJSize);
++  if( rc ) goto ckpt_begin_failed;
++  assert( pPager->ckptJSize == 
++    pPager->nRec*JOURNAL_PG_SZ(journal_format)+JOURNAL_HDR_SZ(journal_format) );
++#endif
++  pPager->ckptJSize = pPager->nRec*JOURNAL_PG_SZ(journal_format)
++                         + JOURNAL_HDR_SZ(journal_format);
++  pPager->ckptSize = pPager->dbSize;
++  if( !pPager->ckptOpen ){
++    rc = sqlitepager_opentemp(zTemp, &pPager->cpfd);
++    if( rc ) goto ckpt_begin_failed;
++    pPager->ckptOpen = 1;
++    pPager->ckptNRec = 0;
++  }
++  pPager->ckptInUse = 1;
++  return SQLITE_OK;
++ 
++ckpt_begin_failed:
++  if( pPager->aInCkpt ){
++    sqliteFree(pPager->aInCkpt);
++    pPager->aInCkpt = 0;
++  }
++  return rc;
++}
++
++/*
++** Commit a checkpoint.
++*/
++int sqlitepager_ckpt_commit(Pager *pPager){
++  if( pPager->ckptInUse ){
++    PgHdr *pPg, *pNext;
++    sqliteOsSeek(&pPager->cpfd, 0);
++    /* sqliteOsTruncate(&pPager->cpfd, 0); */
++    pPager->ckptNRec = 0;
++    pPager->ckptInUse = 0;
++    sqliteFree( pPager->aInCkpt );
++    pPager->aInCkpt = 0;
++    for(pPg=pPager->pCkpt; pPg; pPg=pNext){
++      pNext = pPg->pNextCkpt;
++      assert( pPg->inCkpt );
++      pPg->inCkpt = 0;
++      pPg->pPrevCkpt = pPg->pNextCkpt = 0;
++    }
++    pPager->pCkpt = 0;
++  }
++  pPager->ckptAutoopen = 0;
++  return SQLITE_OK;
++}
++
++/*
++** Rollback a checkpoint.
++*/
++int sqlitepager_ckpt_rollback(Pager *pPager){
++  int rc;
++  if( pPager->ckptInUse ){
++    rc = pager_ckpt_playback(pPager);
++    sqlitepager_ckpt_commit(pPager);
++  }else{
++    rc = SQLITE_OK;
++  }
++  pPager->ckptAutoopen = 0;
++  return rc;
++}
++
++/*
++** Return the full pathname of the database file.
++*/
++const char *sqlitepager_filename(Pager *pPager){
++  return pPager->zFilename;
++}
++
++/*
++** Set the codec for this pager
++*/
++void sqlitepager_set_codec(
++  Pager *pPager,
++  void (*xCodec)(void*,void*,Pgno,int),
++  void *pCodecArg
++){
++  pPager->xCodec = xCodec;
++  pPager->pCodecArg = pCodecArg;
++}
++
++#ifdef SQLITE_TEST
++/*
++** Print a listing of all referenced pages and their ref count.
++*/
++void sqlitepager_refdump(Pager *pPager){
++  PgHdr *pPg;
++  for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
++    if( pPg->nRef<=0 ) continue;
++    printf("PAGE %3d addr=0x%08x nRef=%d\n", 
++       pPg->pgno, (int)PGHDR_TO_DATA(pPg), pPg->nRef);
++  }
++}
++#endif
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/pager.h
+@@ -0,0 +1,107 @@
++/*
++** 2001 September 15
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This header file defines the interface that the sqlite page cache
++** subsystem.  The page cache subsystem reads and writes a file a page
++** at a time and provides a journal for rollback.
++**
++** @(#) $Id$
++*/
++
++/*
++** The size of one page
++**
++** You can change this value to another (reasonable) value you want.
++** It need not be a power of two, though the interface to the disk
++** will likely be faster if it is.
++**
++** Experiments show that a page size of 1024 gives the best speed
++** for common usages.  The speed differences for different sizes
++** such as 512, 2048, 4096, an so forth, is minimal.  Note, however,
++** that changing the page size results in a completely imcompatible
++** file format.
++*/
++#ifndef SQLITE_PAGE_SIZE
++#define SQLITE_PAGE_SIZE 1024
++#endif
++
++/*
++** Number of extra bytes of data allocated at the end of each page and
++** stored on disk but not used by the higher level btree layer.  Changing
++** this value results in a completely incompatible file format.
++*/
++#ifndef SQLITE_PAGE_RESERVE
++#define SQLITE_PAGE_RESERVE 0
++#endif
++
++/*
++** The total number of usable bytes stored on disk for each page.
++** The usable bytes come at the beginning of the page and the reserve
++** bytes come at the end.
++*/
++#define SQLITE_USABLE_SIZE (SQLITE_PAGE_SIZE-SQLITE_PAGE_RESERVE)
++
++/*
++** Maximum number of pages in one database.  (This is a limitation of
++** imposed by 4GB files size limits.)
++*/
++#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".
++*/
++typedef unsigned int Pgno;
++
++/*
++** Each open file is managed by a separate instance of the "Pager" structure.
++*/
++typedef struct Pager Pager;
++
++/*
++** See source code comments for a detailed description of the following
++** routines:
++*/
++int sqlitepager_open(Pager **ppPager, const char *zFilename,
++                     int nPage, int nExtra, int useJournal);
++void sqlitepager_set_destructor(Pager*, void(*)(void*));
++void sqlitepager_set_cachesize(Pager*, int);
++int sqlitepager_close(Pager *pPager);
++int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage);
++void *sqlitepager_lookup(Pager *pPager, Pgno pgno);
++int sqlitepager_ref(void*);
++int sqlitepager_unref(void*);
++Pgno sqlitepager_pagenumber(void*);
++int sqlitepager_write(void*);
++int sqlitepager_iswriteable(void*);
++int sqlitepager_overwrite(Pager *pPager, Pgno pgno, void*);
++int sqlitepager_pagecount(Pager*);
++int sqlitepager_truncate(Pager*,Pgno);
++int sqlitepager_begin(void*);
++int sqlitepager_commit(Pager*);
++int sqlitepager_rollback(Pager*);
++int sqlitepager_isreadonly(Pager*);
++int sqlitepager_ckpt_begin(Pager*);
++int sqlitepager_ckpt_commit(Pager*);
++int sqlitepager_ckpt_rollback(Pager*);
++void sqlitepager_dont_rollback(void*);
++void sqlitepager_dont_write(Pager*, Pgno);
++int *sqlitepager_stats(Pager*);
++void sqlitepager_set_safety_level(Pager*,int);
++const char *sqlitepager_filename(Pager*);
++int sqlitepager_rename(Pager*, const char *zNewName);
++void sqlitepager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*);
++
++#ifdef SQLITE_TEST
++void sqlitepager_refdump(Pager*);
++int pager_refinfo_enable;
++int journal_format;
++#endif
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/parse.c
+@@ -0,0 +1,3355 @@
++/* Driver template for the LEMON parser generator.
++** The author disclaims copyright to this source code.
++*/
++/* First off, code is included that follows the "include" declaration
++** in the input grammar file. */
++#include <stdio.h>
++#line 33 "ext/sqlite/libsqlite/src/parse.y"
++
++#include "sqliteInt.h"
++#include "parse.h"
++
++/*
++** An instance of this structure holds information about the
++** LIMIT clause of a SELECT statement.
++*/
++struct LimitVal {
++  int limit;    /* The LIMIT value.  -1 if there is no limit */
++  int offset;   /* The OFFSET.  0 if there is none */
++};
++
++/*
++** An instance of the following structure describes the event of a
++** TRIGGER.  "a" is the event type, one of TK_UPDATE, TK_INSERT,
++** TK_DELETE, or TK_INSTEAD.  If the event is of the form
++**
++**      UPDATE ON (a,b,c)
++**
++** Then the "b" IdList records the list "a,b,c".
++*/
++struct TrigEvent { int a; IdList * b; };
++
++#line 33 "ext/sqlite/libsqlite/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.
++*/
++/* 
++** These constants (all generated automatically by the parser generator)
++** specify the various kinds of tokens (terminals) that the parser
++** understands. 
++**
++** Each symbol here is a terminal symbol in the grammar.
++*/
++/* Make sure the INTERFACE macro is defined.
++*/
++#ifndef INTERFACE
++# define INTERFACE 1
++#endif
++/* The next thing included is series of defines which control
++** various aspects of the generated parser.
++**    YYCODETYPE         is the data type used for storing terminal
++**                       and nonterminal numbers.  "unsigned char" is
++**                       used if there are fewer than 250 terminals
++**                       and nonterminals.  "int" is used otherwise.
++**    YYNOCODE           is a number of type YYCODETYPE which corresponds
++**                       to no legal terminal or nonterminal number.  This
++**                       number is used to fill in empty slots of the hash 
++**                       table.
++**    YYFALLBACK         If defined, this indicates that one or more tokens
++**                       have fall-back values which should be used if the
++**                       original value of the token will not parse.
++**    YYACTIONTYPE       is the data type used for storing terminal
++**                       and nonterminal numbers.  "unsigned char" is
++**                       used if there are fewer than 250 rules and
++**                       states combined.  "int" is used otherwise.
++**    sqliteParserTOKENTYPE     is the data type used for minor tokens given 
++**                       directly to the parser from the tokenizer.
++**    YYMINORTYPE        is the data type used for all minor tokens.
++**                       This is typically a union of many types, one of
++**                       which is sqliteParserTOKENTYPE.  The entry in the union
++**                       for base tokens is called "yy0".
++**    YYSTACKDEPTH       is the maximum depth of the parser's stack.  If
++**                       zero the stack is dynamically sized using realloc()
++**    sqliteParserARG_SDECL     A static variable declaration for the %extra_argument
++**    sqliteParserARG_PDECL     A parameter declaration for the %extra_argument
++**    sqliteParserARG_STORE     Code to store %extra_argument into yypParser
++**    sqliteParserARG_FETCH     Code to extract %extra_argument from yypParser
++**    YYNSTATE           the combined number of states.
++**    YYNRULE            the number of rules in the grammar
++**    YYERRORSYMBOL      is the code number of the error symbol.  If not
++**                       defined, then do no error processing.
++*/
++#define YYCODETYPE unsigned char
++#define YYNOCODE 221
++#define YYACTIONTYPE unsigned short int
++#define sqliteParserTOKENTYPE Token
++typedef union {
++  int yyinit;
++  sqliteParserTOKENTYPE yy0;
++  TriggerStep * yy19;
++  struct LimitVal yy124;
++  Select* yy179;
++  Expr * yy182;
++  Expr* yy242;
++  struct TrigEvent yy290;
++  SrcList* yy307;
++  IdList* yy320;
++  ExprList* yy322;
++  int yy372;
++  struct {int value; int mask;} yy407;
++} YYMINORTYPE;
++#ifndef YYSTACKDEPTH
++#define YYSTACKDEPTH 100
++#endif
++#define sqliteParserARG_SDECL Parse *pParse;
++#define sqliteParserARG_PDECL ,Parse *pParse
++#define sqliteParserARG_FETCH Parse *pParse = yypParser->pParse
++#define sqliteParserARG_STORE yypParser->pParse = pParse
++#define YYNSTATE 563
++#define YYNRULE 293
++#define YYFALLBACK 1
++#define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
++#define YY_ACCEPT_ACTION  (YYNSTATE+YYNRULE+1)
++#define YY_ERROR_ACTION   (YYNSTATE+YYNRULE)
++
++/* The yyzerominor constant is used to initialize instances of
++** YYMINORTYPE objects to zero. */
++static const YYMINORTYPE yyzerominor = { 0 };
++
++/* Define the yytestcase() macro to be a no-op if is not already defined
++** otherwise.
++**
++** Applications can choose to define yytestcase() in the %include section
++** to a macro that can assist in verifying code coverage.  For production
++** code the yytestcase() macro should be turned off.  But it is useful
++** for testing.
++*/
++#ifndef yytestcase
++# define yytestcase(X)
++#endif
++
++
++/* Next are the tables used to determine what action to take based on the
++** current state and lookahead token.  These tables are used to implement
++** functions that take a state number and lookahead value and return an
++** action integer.  
++**
++** Suppose the action integer is N.  Then the action is determined as
++** follows
++**
++**   0 <= N < YYNSTATE                  Shift N.  That is, push the lookahead
++**                                      token onto the stack and goto state N.
++**
++**   YYNSTATE <= N < YYNSTATE+YYNRULE   Reduce by rule N-YYNSTATE.
++**
++**   N == YYNSTATE+YYNRULE              A syntax error has occurred.
++**
++**   N == YYNSTATE+YYNRULE+1            The parser accepts its input.
++**
++**   N == YYNSTATE+YYNRULE+2            No such action.  Denotes unused
++**                                      slots in the yy_action[] table.
++**
++** The action table is constructed as a single large table named yy_action[].
++** Given state S and lookahead X, the action is computed as
++**
++**      yy_action[ yy_shift_ofst[S] + X ]
++**
++** If the index value yy_shift_ofst[S]+X is out of range or if the value
++** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
++** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
++** and that yy_default[S] should be used instead.  
++**
++** The formula above is for computing the action when the lookahead is
++** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
++** a reduce action) then the yy_reduce_ofst[] array is used in place of
++** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
++** YY_SHIFT_USE_DFLT.
++**
++** The following are the tables generated in this section:
++**
++**  yy_action[]        A single table containing all actions.
++**  yy_lookahead[]     A table containing the lookahead for each entry in
++**                     yy_action.  Used to detect hash collisions.
++**  yy_shift_ofst[]    For each state, the offset into yy_action for
++**                     shifting terminals.
++**  yy_reduce_ofst[]   For each state, the offset into yy_action for
++**                     shifting non-terminals after a reduce.
++**  yy_default[]       Default action for each state.
++*/
++#define YY_ACTTAB_COUNT (1090)
++static const YYACTIONTYPE yy_action[] = {
++ /*     0 */   186,  561,  483,   69,   67,   70,   68,   64,   63,   62,
++ /*    10 */    61,   58,   57,   56,   55,   54,   53,  181,  180,  179,
++ /*    20 */   514,  421,  334,  420,  468,  515,   64,   63,   62,   61,
++ /*    30 */    58,   57,   56,   55,   54,   53,    9,  423,  422,   71,
++ /*    40 */    72,  129,   65,   66,  513,  510,  305,   52,  138,   69,
++ /*    50 */    67,   70,   68,   64,   63,   62,   61,   58,   57,   56,
++ /*    60 */    55,   54,   53,  448,  469,  175,  482,  514,  470,  344,
++ /*    70 */   342,   36,  515,   58,   57,   56,   55,   54,   53,    8,
++ /*    80 */   341,  281,  285,  307,  437,  178,   71,   72,  129,   65,
++ /*    90 */    66,  513,  510,  305,   52,  138,   69,   67,   70,   68,
++ /*   100 */    64,   63,   62,   61,   58,   57,   56,   55,   54,   53,
++ /*   110 */   130,  362,  360,  508,  507,  267,  551,  436,  298,  297,
++ /*   120 */   369,  368,   50,  128,  543,   29,  266,  449,  537,  447,
++ /*   130 */   591,  528,  442,  441,  187,  132,  514,  536,   47,   48,
++ /*   140 */   472,  515,  122,  427,  331,  409,   49,  371,  370,  518,
++ /*   150 */   328,  363,  517,  520,   45,   71,   72,  129,   65,   66,
++ /*   160 */   513,  510,  305,   52,  138,   69,   67,   70,   68,   64,
++ /*   170 */    63,   62,   61,   58,   57,   56,   55,   54,   53,  185,
++ /*   180 */   550,  549,  512,  175,  467,  516,   18,  344,  342,   36,
++ /*   190 */   544,  175,  320,  230,  231,  344,  342,   36,  341,   56,
++ /*   200 */    55,   54,   53,  212,  531,  514,  341,  551,    3,  213,
++ /*   210 */   515,    2,  551,   73,    7,  551,  184,  132,  551,  172,
++ /*   220 */   551,  309,  348,   42,   71,   72,  129,   65,   66,  513,
++ /*   230 */   510,  305,   52,  138,   69,   67,   70,   68,   64,   63,
++ /*   240 */    62,   61,   58,   57,   56,   55,   54,   53,  243,  197,
++ /*   250 */   282,  358,  268,  373,  264,  372,  183,  241,  436,  169,
++ /*   260 */   356,  171,  269,  240,  471,  426,   29,  446,  506,  514,
++ /*   270 */   445,  550,  549,  494,  515,  354,  550,  549,  359,  550,
++ /*   280 */   549,  144,  550,  549,  550,  549,  592,  309,   71,   72,
++ /*   290 */   129,   65,   66,  513,  510,  305,   52,  138,   69,   67,
++ /*   300 */    70,   68,   64,   63,   62,   61,   58,   57,   56,   55,
++ /*   310 */    54,   53,  514,  857,   82,  377,    1,  515,  268,  373,
++ /*   320 */   264,  372,  183,  241,  362,   12,  508,  507,  500,  240,
++ /*   330 */    17,   71,   72,  129,   65,   66,  513,  510,  305,   52,
++ /*   340 */   138,   69,   67,   70,   68,   64,   63,   62,   61,   58,
++ /*   350 */    57,   56,   55,   54,   53,  362,  182,  508,  507,  514,
++ /*   360 */   362,  527,  508,  507,  515,  563,  429,  463,  182,  444,
++ /*   370 */   375,  338,  443,  430,  379,  378,  593,  156,   71,   72,
++ /*   380 */   129,   65,   66,  513,  510,  305,   52,  138,   69,   67,
++ /*   390 */    70,   68,   64,   63,   62,   61,   58,   57,   56,   55,
++ /*   400 */    54,   53,  514,  526,  542,  450,  534,  515,  286,  493,
++ /*   410 */   453,   17,  478,  240,   80,   11,  533,  153,  194,  155,
++ /*   420 */   286,   71,   51,  129,   65,   66,  513,  510,  305,   52,
++ /*   430 */   138,   69,   67,   70,   68,   64,   63,   62,   61,   58,
++ /*   440 */    57,   56,   55,   54,   53,  514,  195,  466,  160,   17,
++ /*   450 */   515,  454,  490,   80,  459,  440,  460,  176,  239,  238,
++ /*   460 */    80,   80,  562,    1,   71,   40,  129,   65,   66,  513,
++ /*   470 */   510,  305,   52,  138,   69,   67,   70,   68,   64,   63,
++ /*   480 */    62,   61,   58,   57,   56,   55,   54,   53,  514,  365,
++ /*   490 */   154,   19,  339,  515,   80,  232,  405,   80,  165,  404,
++ /*   500 */   193,   32,  396,   13,   32,   86,  414,  108,   72,  129,
++ /*   510 */    65,   66,  513,  510,  305,   52,  138,   69,   67,   70,
++ /*   520 */    68,   64,   63,   62,   61,   58,   57,   56,   55,   54,
++ /*   530 */    53,  514,  551,  365,  483,  192,  515,  488,  323,  207,
++ /*   540 */   366,  249,  177,  186,   87,  483,  483,   46,   38,   44,
++ /*   550 */   458,  108,  129,   65,   66,  513,  510,  305,   52,  138,
++ /*   560 */    69,   67,   70,   68,   64,   63,   62,   61,   58,   57,
++ /*   570 */    56,   55,   54,   53,  274,  457,  272,  271,  270,   23,
++ /*   580 */     8,  551,  211,  412,  307,  257,  365,  385,  201,   31,
++ /*   590 */   217,  388,  141,  205,  387,  219,  550,  549,  482,  511,
++ /*   600 */   215,  376,  560,  134,   90,  477,  214,  514,  392,  482,
++ /*   610 */   482,  152,  515,  360,  203,  212,  409,  531,  800,  284,
++ /*   620 */   365,  145,  505,   50,  300,  365,  365,  173,  321,  212,
++ /*   630 */   487,  137,  135,    8,   41,  136,  531,  307,   93,   47,
++ /*   640 */    48,  346,  316,  106,  106,  550,  549,   49,  371,  370,
++ /*   650 */   518,  509,  531,  517,  520,  504,  531,  531,  162,  495,
++ /*   660 */   170,  317,  503,  319,  223,  231,  360,  551,  502,  283,
++ /*   670 */   162,  207,  557,  486,  212,  191,   50,   10,  289,  304,
++ /*   680 */   303,  556,  207,  531,    8,  531,  516,   18,  307,  498,
++ /*   690 */   498,  189,   47,   48,  393,  531,  555,   28,  302,  554,
++ /*   700 */    49,  371,  370,  518,  484,  480,  517,  520,  322,  299,
++ /*   710 */   553,  418,  365,  323,   17,  365,  365,  360,  416,  207,
++ /*   720 */   322,  417,  207,  418,  327,  212,  480,   50,  207,  326,
++ /*   730 */   106,  550,  549,  106,  105,  247,  407,  475,  332,  516,
++ /*   740 */    18,  326,  365,   47,   48,  207,  295,  365,  475,  294,
++ /*   750 */   158,   49,  371,  370,  518,  293,  473,  517,  520,  485,
++ /*   760 */   106,  391,  390,  202,  148,   93,  351,  480,  204,  301,
++ /*   770 */   333,  190,  291,  541,   60,  531,  498,  252,  453,  498,
++ /*   780 */   365,  365,  290,  365,  501,  475,  365,   79,  475,  531,
++ /*   790 */   516,   18,  379,  378,  475,  365,  465,  245,   89,  112,
++ /*   800 */   365,  109,  365,  131,  121,  288,  499,  365,  365,  439,
++ /*   810 */   365,  475,  365,  120,  365,  365,  343,  365,  119,  365,
++ /*   820 */   118,  365,  365,  365,  365,  117,  116,  365,  126,  365,
++ /*   830 */   125,  365,  124,  123,  365,  115,  365,  114,  431,  140,
++ /*   840 */   139,  255,  254,  365,  365,  253,  365,  280,  365,  107,
++ /*   850 */   365,  365,  113,  365,  111,   26,  365,  365,  365,  365,
++ /*   860 */   365,  279,  278,  365,  277,  365,   92,  365,  104,  103,
++ /*   870 */   365,   91,  365,  365,  102,  101,  110,  100,   99,  347,
++ /*   880 */    25,   98,  340,   30,   24,   97,  266,  174,   96,   85,
++ /*   890 */    95,   94,  166,  292,   78,  165,  415,   14,  163,   60,
++ /*   900 */   164,   22,    6,  408,    5,   77,   34,   33,  159,   16,
++ /*   910 */   157,  151,   75,  149,   15,  146,  313,  312,  395,  384,
++ /*   920 */   143,   20,   60,  206,   21,  273,  198,  559,  375,  548,
++ /*   930 */   547,  546,  374,    4,  540,  539,  538,  308,  535,  532,
++ /*   940 */   530,  212,  261,   38,  260,  352,  259,   39,  258,  367,
++ /*   950 */   529,  196,  210,  256,  521,  522,   53,   53,  209,   43,
++ /*   960 */   496,  188,  492,  208,  256,   81,  246,   37,  479,  349,
++ /*   970 */   244,   37,  474,  464,  276,   27,  452,  451,  433,  432,
++ /*   980 */   275,  235,  234,  335,  424,   35,  329,  413,  410,  127,
++ /*   990 */   161,   84,   76,  403,   38,  400,  188,  399,  224,  398,
++ /*  1000 */    38,  150,  318,  220,   83,  147,  315,  200,  381,  383,
++ /*  1010 */   199,  142,  545,  265,   88,  262,  523,  361,  491,  476,
++ /*  1020 */   463,  406,  397,  287,  389,  386,  310,  382,  552,   74,
++ /*  1030 */   306,  525,  524,  364,  519,  357,  355,  353,  497,  489,
++ /*  1040 */   481,  263,  242,  462,  461,  456,  455,  438,  296,  345,
++ /*  1050 */   434,  237,  425,  337,  168,  167,  336,  236,  419,  330,
++ /*  1060 */   233,  325,  324,  229,  228,  402,  401,  227,  226,  225,
++ /*  1070 */   222,  221,  218,  314,  394,  311,  216,  380,  251,  250,
++ /*  1080 */   133,  350,  248,  364,  558,   59,  435,  411,  428,  212,
++};
++static const YYCODETYPE yy_lookahead[] = {
++ /*     0 */    21,    9,   23,   70,   71,   72,   73,   74,   75,   76,
++ /*    10 */    77,   78,   79,   80,   81,   82,   83,  100,  101,  102,
++ /*    20 */    41,  100,  101,  102,   20,   46,   74,   75,   76,   77,
++ /*    30 */    78,   79,   80,   81,   82,   83,   19,   55,   56,   60,
++ /*    40 */    61,   62,   63,   64,   65,   66,   67,   68,   69,   70,
++ /*    50 */    71,   72,   73,   74,   75,   76,   77,   78,   79,   80,
++ /*    60 */    81,   82,   83,   23,  108,   90,   87,   41,  112,   94,
++ /*    70 */    95,   96,   46,   78,   79,   80,   81,   82,   83,   19,
++ /*    80 */   105,  149,  143,   23,  152,  153,   60,   61,   62,   63,
++ /*    90 */    64,   65,   66,   67,   68,   69,   70,   71,   72,   73,
++ /*   100 */    74,   75,   76,   77,   78,   79,   80,   81,   82,   83,
++ /*   110 */    31,  107,   52,  109,  110,   93,   23,  140,   78,   79,
++ /*   120 */    78,   79,   62,   22,  147,  148,  104,   87,   34,   89,
++ /*   130 */   113,   89,   92,   93,  183,  184,   41,   43,   78,   79,
++ /*   140 */    80,   46,  165,  166,  205,   53,   86,   87,   88,   89,
++ /*   150 */   211,   62,   92,   93,  128,   60,   61,   62,   63,   64,
++ /*   160 */    65,   66,   67,   68,   69,   70,   71,   72,   73,   74,
++ /*   170 */    75,   76,   77,   78,   79,   80,   81,   82,   83,  146,
++ /*   180 */    87,   88,   93,   90,   20,  125,  126,   94,   95,   96,
++ /*   190 */    20,   90,  100,  101,  102,   94,   95,   96,  105,   80,
++ /*   200 */    81,   82,   83,  111,  171,   41,  105,   23,   19,   48,
++ /*   210 */    46,   19,   23,   19,   19,   23,  183,  184,   23,   17,
++ /*   220 */    23,   62,  189,  128,   60,   61,   62,   63,   64,   65,
++ /*   230 */    66,   67,   68,   69,   70,   71,   72,   73,   74,   75,
++ /*   240 */    76,   77,   78,   79,   80,   81,   82,   83,   20,   90,
++ /*   250 */    91,   15,   93,   94,   95,   96,   97,   98,  140,   57,
++ /*   260 */    24,   59,  144,  104,   80,  147,  148,   89,   20,   41,
++ /*   270 */    92,   87,   88,   20,   46,   39,   87,   88,   42,   87,
++ /*   280 */    88,   19,   87,   88,   87,   88,  113,   62,   60,   61,
++ /*   290 */    62,   63,   64,   65,   66,   67,   68,   69,   70,   71,
++ /*   300 */    72,   73,   74,   75,   76,   77,   78,   79,   80,   81,
++ /*   310 */    82,   83,   41,  132,  133,  134,  135,   46,   93,   94,
++ /*   320 */    95,   96,   97,   98,  107,   63,  109,  110,   20,  104,
++ /*   330 */    22,   60,   61,   62,   63,   64,   65,   66,   67,   68,
++ /*   340 */    69,   70,   71,   72,   73,   74,   75,   76,   77,   78,
++ /*   350 */    79,   80,   81,   82,   83,  107,   47,  109,  110,   41,
++ /*   360 */   107,   89,  109,  110,   46,    0,  161,  162,   47,   89,
++ /*   370 */    99,   62,   92,  168,    9,   10,  113,   17,   60,   61,
++ /*   380 */    62,   63,   64,   65,   66,   67,   68,   69,   70,   71,
++ /*   390 */    72,   73,   74,   75,   76,   77,   78,   79,   80,   81,
++ /*   400 */    82,   83,   41,   89,  155,  156,   26,   46,   99,   20,
++ /*   410 */   161,   22,   20,  104,   22,  118,   36,   57,   22,   59,
++ /*   420 */    99,   60,   61,   62,   63,   64,   65,   66,   67,   68,
++ /*   430 */    69,   70,   71,   72,   73,   74,   75,   76,   77,   78,
++ /*   440 */    79,   80,   81,   82,   83,   41,   50,   20,   22,   22,
++ /*   450 */    46,   20,   22,   22,   91,   20,   93,   22,   20,   20,
++ /*   460 */    22,   22,  134,  135,   60,   61,   62,   63,   64,   65,
++ /*   470 */    66,   67,   68,   69,   70,   71,   72,   73,   74,   75,
++ /*   480 */    76,   77,   78,   79,   80,   81,   82,   83,   41,  140,
++ /*   490 */   130,   22,   20,   46,   22,   20,   20,   22,   22,   20,
++ /*   500 */   113,   22,   20,   19,   22,   21,   18,  158,   61,   62,
++ /*   510 */    63,   64,   65,   66,   67,   68,   69,   70,   71,   72,
++ /*   520 */    73,   74,   75,   76,   77,   78,   79,   80,   81,   82,
++ /*   530 */    83,   41,   23,  140,   23,  113,   46,   22,  140,  140,
++ /*   540 */   191,  192,   19,   21,  114,   23,   23,  127,  122,  129,
++ /*   550 */    29,  158,   62,   63,   64,   65,   66,   67,   68,   69,
++ /*   560 */    70,   71,   72,   73,   74,   75,   76,   77,   78,   79,
++ /*   570 */    80,   81,   82,   83,   11,   54,   13,   14,   15,   16,
++ /*   580 */    19,   23,  174,   95,   23,  192,  140,   78,   79,  181,
++ /*   590 */    27,   89,  146,  195,   92,   32,   87,   88,   87,   93,
++ /*   600 */    37,  136,  137,   88,  158,  206,  141,   41,   99,   87,
++ /*   610 */    87,  146,   46,   52,   51,  111,   53,  171,  130,   19,
++ /*   620 */   140,   58,   14,   62,  103,  140,  140,  146,  124,  111,
++ /*   630 */   115,  146,  146,   19,   68,   69,  171,   23,  158,   78,
++ /*   640 */    79,   80,  124,  158,  158,   87,   88,   86,   87,   88,
++ /*   650 */    89,  108,  171,   92,   93,   20,  171,  171,  146,   93,
++ /*   660 */   146,  196,   20,  100,  101,  102,   52,   23,   20,  106,
++ /*   670 */   146,  140,   15,  115,  111,   22,   62,  118,  198,  194,
++ /*   680 */   194,   24,  140,  171,   19,  171,  125,  126,   23,  204,
++ /*   690 */   204,   22,   78,   79,  140,  171,   39,   19,  167,   42,
++ /*   700 */    86,   87,   88,   89,  115,  152,   92,   93,  196,  167,
++ /*   710 */    53,  140,  140,  140,   22,  140,  140,   52,   25,  140,
++ /*   720 */   196,   28,  140,  140,  212,  111,  152,   62,  140,  217,
++ /*   730 */   158,   87,   88,  158,  158,  182,  212,  206,   45,  125,
++ /*   740 */   126,  217,  140,   78,   79,  140,  167,  140,  206,  167,
++ /*   750 */   146,   86,   87,   88,   89,  167,  182,   92,   93,  115,
++ /*   760 */   158,  207,  208,  209,  146,  158,  194,  152,  195,  194,
++ /*   770 */   199,   22,  167,  156,  200,  171,  204,  201,  161,  204,
++ /*   780 */   140,  140,  199,  140,   20,  206,  140,   20,  206,  171,
++ /*   790 */   125,  126,    9,   10,  206,  140,   20,  182,  158,  158,
++ /*   800 */   140,  158,  140,  113,  158,  198,  204,  140,  140,   20,
++ /*   810 */   140,  206,  140,  158,  140,  140,   48,  140,  158,  140,
++ /*   820 */   158,  140,  140,  140,  140,  158,  158,  140,  158,  140,
++ /*   830 */   158,  140,  158,  158,  140,  158,  140,  158,  139,  158,
++ /*   840 */   158,  158,  158,  140,  140,  158,  140,  158,  140,  158,
++ /*   850 */   140,  140,  158,  140,  158,   19,  140,  140,  140,  140,
++ /*   860 */   140,  158,  158,  140,  158,  140,  158,  140,  158,  158,
++ /*   870 */   140,  158,  140,  140,  158,  158,  158,  158,  158,  140,
++ /*   880 */    19,  158,   48,  158,   19,  158,  104,   97,  158,   21,
++ /*   890 */   158,  158,   99,   38,   49,   22,   49,  158,   99,  200,
++ /*   900 */   130,   19,   11,   14,    9,  103,   63,   63,  123,   19,
++ /*   910 */   114,  114,  103,  123,   19,  114,  116,   35,   87,   20,
++ /*   920 */    21,  150,  200,  160,  160,  138,   12,  139,   99,  138,
++ /*   930 */   138,  138,  145,   22,  139,  139,  164,   44,  139,  139,
++ /*   940 */   171,  111,  176,  122,  177,  119,  178,  120,  179,  117,
++ /*   950 */   180,  121,  193,   98,  151,   23,   83,   83,  202,  127,
++ /*   960 */   186,  113,  186,  193,   98,  186,  187,   99,  188,  116,
++ /*   970 */   187,   99,  188,  139,  159,   19,  151,  164,  139,  139,
++ /*   980 */   159,  186,  215,   40,  216,  127,  186,  139,  169,   60,
++ /*   990 */   169,  197,   19,  176,  122,  186,  113,  186,  186,  176,
++ /*  1000 */   122,  169,  186,  186,  197,  169,  186,  218,   33,  219,
++ /*  1010 */   116,  218,  142,  157,  173,  175,  157,  203,  157,  157,
++ /*  1020 */   162,  176,  176,  152,  210,  210,  152,  152,  140,  140,
++ /*  1030 */   154,  154,  154,  140,  140,  140,  140,  140,  140,  185,
++ /*  1040 */   140,  172,  140,  140,  163,  163,  163,  152,  154,  154,
++ /*  1050 */   140,  140,  140,  140,  140,  213,  214,  140,  140,  140,
++ /*  1060 */   140,  140,  140,  140,  140,  140,  140,  140,  140,  140,
++ /*  1070 */   140,  140,  140,  140,  140,  140,  140,  140,  140,  140,
++ /*  1080 */   140,  140,  140,  140,  170,  200,  166,  170,  166,  111,
++};
++#define YY_SHIFT_USE_DFLT (-84)
++#define YY_SHIFT_COUNT (376)
++#define YY_SHIFT_MIN   (-83)
++#define YY_SHIFT_MAX   (978)
++static const short yy_shift_ofst[] = {
++ /*     0 */   783,  563,  614,  614,   93,   92,   92,  978,  614,  561,
++ /*    10 */   665,  665,  509,  197,  -21,  665,  665,  665,  665,  665,
++ /*    20 */   159,  309,  197,  488,  197,  197,  197,  197,  197,  511,
++ /*    30 */   271,   60,  665,  665,  665,  665,  665,  665,  665,  665,
++ /*    40 */   665,  665,  665,  665,  665,  665,  665,  665,  665,  665,
++ /*    50 */   665,  665,  665,  665,  665,  665,  665,  665,  665,  665,
++ /*    60 */   665,  665,  665,  665,  665,  665,  665,  665,  665,  665,
++ /*    70 */   665,  665,  665,  665,  225,  197,  197,  197,  197,  522,
++ /*    80 */   197,  522,  365,  518,  504,  978,  978,  -84,  -84,  228,
++ /*    90 */   164,   95,   26,  318,  318,  318,  318,  318,  318,  318,
++ /*   100 */   318,  404,  318,  318,  318,  318,  318,  361,  318,  447,
++ /*   110 */   490,  490,  490,  -67,  -67,  -67,  -67,  -67,  -48,  -48,
++ /*   120 */   -48,  -48,  101,   -5,   -5,   -5,   -5,  657,  -25,  566,
++ /*   130 */   657,  184,  195,  644,  558,  253,  192,  248,  189,  119,
++ /*   140 */   119,    4,  197,  197,  197,  197,  197,  197,  217,  197,
++ /*   150 */   197,  197,  217,  197,  197,  197,  197,  197,  217,  197,
++ /*   160 */   197,  197,  217,  197,  197,  197,  197,  -79,  693,  197,
++ /*   170 */   217,  197,  197,  217,  197,  197,   42,   42,  523,  521,
++ /*   180 */   521,  521,  197,  197,  515,  217,  197,  515,  197,  197,
++ /*   190 */   197,  197,  197,  197,   42,   42,   42,  197,  197,  511,
++ /*   200 */   511,  502,  502,  511,  426,  426,  321,  380,  380,  420,
++ /*   210 */   380,  430,  -44,  380,  484,  975,  894,  975,  883,  929,
++ /*   220 */   973,  883,  883,  929,  878,  883,  883,  883,  872,  973,
++ /*   230 */   929,  929,  829,  848,  858,  943,  848,  956,  829,  829,
++ /*   240 */   893,  932,  956,  829,  853,  872,  853,  868,  848,  866,
++ /*   250 */   848,  848,  832,  874,  874,  873,  932,  855,  830,  832,
++ /*   260 */   827,  826,  821,  830,  829,  829,  893,  829,  829,  911,
++ /*   270 */   914,  914,  914,  829,  914,  -84,  -84,  -84,  -84,  -84,
++ /*   280 */   -84,  -84,   40,  360,  236,  202,  -83,  262,  482,  479,
++ /*   290 */   476,  475,  -18,  472,  439,  438,  435,  280,  178,  431,
++ /*   300 */   363,  427,  392,  389,  308,   89,  396,   17,   94,   22,
++ /*   310 */   899,  899,  831,  882,  800,  801,  895,  790,  809,  797,
++ /*   320 */   796,  890,  785,  844,  843,  802,  895,  889,  891,  882,
++ /*   330 */   799,  770,  847,  873,  845,  855,  793,  868,  782,  790,
++ /*   340 */   865,  834,  861,  836,  768,  789,  776,  690,  767,  678,
++ /*   350 */   589,  692,  559,  764,  669,  648,  749,  642,  653,  635,
++ /*   360 */   600,  608,  543,  506,  422,  387,  469,  297,  314,  272,
++ /*   370 */   263,  173,  194,  161,  170,   79,   -8,
++};
++#define YY_REDUCE_USE_DFLT (-69)
++#define YY_REDUCE_COUNT (281)
++#define YY_REDUCE_MIN   (-68)
++#define YY_REDUCE_MAX   (943)
++static const short yy_reduce_ofst[] = {
++ /*     0 */   181,  465,  486,  485,  -23,  524,  512,   33,  446,  575,
++ /*    10 */   572,  349,  554,  118,  574,  607,  480,  602,  576,  393,
++ /*    20 */   249,  205,  605,  -61,  588,  582,  579,  542,  531,  -68,
++ /*    30 */   699,  739,  733,  732,  730,  727,  725,  723,  720,  719,
++ /*    40 */   718,  717,  716,  713,  711,  710,  708,  706,  704,  703,
++ /*    50 */   696,  694,  691,  689,  687,  684,  683,  682,  681,  679,
++ /*    60 */   677,  675,  674,  672,  670,  668,  667,  662,  660,  655,
++ /*    70 */   646,  643,  641,  640,  617,  573,  583,  398,  571,  615,
++ /*    80 */   399,  553,  328,  618,  604,  514,  481,  -49,  408,  722,
++ /*    90 */   722,  722,  722,  722,  722,  722,  722,  722,  722,  722,
++ /*   100 */   722,  722,  722,  722,  722,  722,  722,  722,  722,  722,
++ /*   110 */   722,  722,  722,  722,  722,  722,  722,  722,  722,  722,
++ /*   120 */   722,  722,  922,  722,  722,  722,  722,  917,  920,  885,
++ /*   130 */   914,  943,  942,  941,  940,  869,  939,  869,  938,  722,
++ /*   140 */   722,  869,  937,  936,  935,  934,  933,  932,  869,  931,
++ /*   150 */   930,  929,  869,  928,  927,  926,  925,  924,  869,  923,
++ /*   160 */   922,  921,  869,  920,  919,  918,  917,  842,  842,  914,
++ /*   170 */   869,  913,  912,  869,  911,  910,  895,  894,  895,  883,
++ /*   180 */   882,  881,  903,  902,  854,  869,  900,  854,  898,  897,
++ /*   190 */   896,  895,  894,  893,  878,  877,  876,  889,  888,  875,
++ /*   200 */   874,  815,  814,  871,  846,  845,  858,  862,  861,  814,
++ /*   210 */   859,  840,  841,  856,  870,  793,  790,  789,  820,  836,
++ /*   220 */   807,  817,  816,  832,  823,  812,  811,  809,  817,  794,
++ /*   230 */   821,  819,  848,  800,  768,  767,  795,  821,  840,  839,
++ /*   240 */   813,  825,  815,  834,  784,  783,  780,  779,  779,  770,
++ /*   250 */   776,  774,  756,  722,  722,  722,  803,  759,  770,  769,
++ /*   260 */   768,  767,  766,  769,  800,  799,  772,  796,  795,  787,
++ /*   270 */   793,  792,  791,  788,  787,  764,  763,  722,  722,  722,
++ /*   280 */   722,  771,
++};
++static const YYACTIONTYPE yy_default[] = {
++ /*     0 */   570,  856,  797,  797,  856,  839,  839,  685,  856,  797,
++ /*    10 */   797,  856,  822,  856,  681,  856,  856,  797,  793,  856,
++ /*    20 */   586,  649,  856,  581,  856,  856,  856,  856,  856,  594,
++ /*    30 */   651,  856,  856,  856,  856,  856,  856,  856,  856,  856,
++ /*    40 */   856,  856,  856,  856,  856,  856,  856,  856,  856,  856,
++ /*    50 */   856,  856,  856,  856,  856,  856,  856,  856,  856,  856,
++ /*    60 */   856,  856,  856,  856,  856,  856,  856,  856,  856,  856,
++ /*    70 */   856,  856,  856,  856,  856,  856,  856,  856,  856,  681,
++ /*    80 */   856,  681,  570,  856,  856,  856,  856,  685,  675,  856,
++ /*    90 */   856,  856,  856,  730,  729,  724,  723,  837,  697,  721,
++ /*   100 */   714,  856,  789,  790,  788,  792,  796,  856,  705,  748,
++ /*   110 */   780,  774,  747,  779,  760,  759,  754,  753,  752,  751,
++ /*   120 */   750,  749,  640,  758,  757,  756,  755,  856,  856,  856,
++ /*   130 */   856,  856,  856,  856,  856,  856,  856,  856,  856,  764,
++ /*   140 */   763,  856,  856,  856,  856,  809,  856,  856,  726,  856,
++ /*   150 */   856,  856,  663,  856,  856,  856,  856,  856,  842,  856,
++ /*   160 */   856,  856,  844,  856,  856,  856,  856,  856,  828,  856,
++ /*   170 */   661,  856,  856,  583,  856,  856,  856,  856,  595,  856,
++ /*   180 */   856,  856,  856,  856,  689,  688,  856,  683,  856,  856,
++ /*   190 */   856,  856,  856,  856,  856,  856,  856,  856,  573,  856,
++ /*   200 */   856,  856,  856,  856,  720,  720,  621,  708,  708,  791,
++ /*   210 */   708,  682,  673,  708,  856,  854,  852,  854,  690,  653,
++ /*   220 */   731,  690,  690,  653,  720,  690,  690,  690,  720,  731,
++ /*   230 */   653,  653,  651,  690,  836,  833,  690,  801,  651,  651,
++ /*   240 */   636,  856,  801,  651,  700,  698,  700,  698,  690,  709,
++ /*   250 */   690,  690,  856,  767,  766,  765,  856,  709,  715,  701,
++ /*   260 */   713,  711,  720,  856,  651,  651,  636,  651,  651,  639,
++ /*   270 */   572,  572,  572,  651,  572,  624,  624,  777,  776,  775,
++ /*   280 */   768,  604,  856,  856,  856,  856,  856,  816,  856,  856,
++ /*   290 */   856,  856,  856,  856,  856,  856,  856,  856,  856,  856,
++ /*   300 */   856,  856,  856,  856,  856,  856,  716,  737,  856,  856,
++ /*   310 */   856,  856,  856,  856,  808,  856,  856,  856,  856,  856,
++ /*   320 */   856,  856,  856,  856,  856,  856,  856,  856,  856,  856,
++ /*   330 */   856,  856,  856,  832,  831,  856,  856,  856,  856,  856,
++ /*   340 */   856,  856,  856,  856,  856,  856,  856,  856,  856,  856,
++ /*   350 */   856,  712,  856,  856,  856,  856,  856,  856,  856,  856,
++ /*   360 */   856,  856,  666,  856,  739,  856,  702,  856,  856,  856,
++ /*   370 */   738,  743,  856,  856,  856,  856,  856,  565,  569,  567,
++ /*   380 */   855,  853,  851,  850,  815,  821,  818,  820,  819,  817,
++ /*   390 */   814,  813,  812,  811,  810,  807,  725,  722,  719,  849,
++ /*   400 */   806,  662,  660,  843,  841,  732,  840,  838,  823,  728,
++ /*   410 */   727,  654,  799,  798,  580,  827,  826,  825,  734,  733,
++ /*   420 */   830,  829,  835,  834,  824,  579,  585,  643,  642,  650,
++ /*   430 */   648,  647,  646,  645,  644,  641,  587,  598,  599,  597,
++ /*   440 */   596,  615,  612,  614,  611,  613,  610,  609,  608,  607,
++ /*   450 */   606,  635,  623,  622,  802,  629,  628,  633,  632,  631,
++ /*   460 */   630,  627,  626,  625,  620,  746,  745,  735,  778,  672,
++ /*   470 */   671,  678,  677,  676,  687,  804,  805,  803,  699,  686,
++ /*   480 */   680,  679,  590,  589,  696,  695,  694,  693,  692,  684,
++ /*   490 */   674,  704,  786,  783,  784,  772,  785,  691,  795,  794,
++ /*   500 */   781,  848,  847,  846,  845,  787,  782,  669,  668,  667,
++ /*   510 */   771,  773,  770,  769,  762,  761,  744,  742,  741,  740,
++ /*   520 */   736,  710,  588,  703,  718,  717,  602,  601,  600,  670,
++ /*   530 */   665,  664,  619,  707,  706,  618,  638,  637,  634,  617,
++ /*   540 */   616,  605,  603,  584,  582,  578,  577,  576,  575,  593,
++ /*   550 */   592,  591,  574,  659,  658,  657,  656,  655,  652,  571,
++ /*   560 */   568,  566,  564,
++};
++
++/* The next table maps tokens into fallback tokens.  If a construct
++** like the following:
++** 
++**      %fallback ID X Y Z.
++**
++** appears in the grammar, then ID becomes a fallback token for X, Y,
++** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
++** but it does not parse, the type of the token is changed to ID and
++** the parse is retried before an error is thrown.
++*/
++#ifdef YYFALLBACK
++static const YYCODETYPE yyFallback[] = {
++    0,  /*          $ => nothing */
++    0,  /* END_OF_FILE => nothing */
++    0,  /*    ILLEGAL => nothing */
++    0,  /*      SPACE => nothing */
++    0,  /* UNCLOSED_STRING => nothing */
++    0,  /*    COMMENT => nothing */
++    0,  /*   FUNCTION => nothing */
++    0,  /*     COLUMN => nothing */
++    0,  /* AGG_FUNCTION => nothing */
++    0,  /*       SEMI => nothing */
++   23,  /*    EXPLAIN => ID */
++   23,  /*      BEGIN => ID */
++    0,  /* TRANSACTION => nothing */
++    0,  /*     COMMIT => nothing */
++   23,  /*        END => ID */
++    0,  /*   ROLLBACK => nothing */
++    0,  /*     CREATE => nothing */
++    0,  /*      TABLE => nothing */
++   23,  /*       TEMP => ID */
++    0,  /*         LP => nothing */
++    0,  /*         RP => nothing */
++    0,  /*         AS => nothing */
++    0,  /*      COMMA => nothing */
++    0,  /*         ID => nothing */
++   23,  /*      ABORT => ID */
++   23,  /*      AFTER => ID */
++   23,  /*        ASC => ID */
++   23,  /*     ATTACH => ID */
++   23,  /*     BEFORE => ID */
++   23,  /*    CASCADE => ID */
++   23,  /*    CLUSTER => ID */
++   23,  /*   CONFLICT => ID */
++   23,  /*       COPY => ID */
++   23,  /*   DATABASE => ID */
++   23,  /*   DEFERRED => ID */
++   23,  /* DELIMITERS => ID */
++   23,  /*       DESC => ID */
++   23,  /*     DETACH => ID */
++   23,  /*       EACH => ID */
++   23,  /*       FAIL => ID */
++   23,  /*        FOR => ID */
++   23,  /*       GLOB => ID */
++   23,  /*     IGNORE => ID */
++   23,  /*  IMMEDIATE => ID */
++   23,  /*  INITIALLY => ID */
++   23,  /*    INSTEAD => ID */
++   23,  /*       LIKE => ID */
++   23,  /*      MATCH => ID */
++   23,  /*        KEY => ID */
++   23,  /*         OF => ID */
++   23,  /*     OFFSET => ID */
++   23,  /*     PRAGMA => ID */
++   23,  /*      RAISE => ID */
++   23,  /*    REPLACE => ID */
++   23,  /*   RESTRICT => ID */
++   23,  /*        ROW => ID */
++   23,  /*  STATEMENT => ID */
++   23,  /*    TRIGGER => ID */
++   23,  /*     VACUUM => ID */
++   23,  /*       VIEW => ID */
++};
++#endif /* YYFALLBACK */
++
++/* The following structure represents a single element of the
++** parser's stack.  Information stored includes:
++**
++**   +  The state number for the parser at this level of the stack.
++**
++**   +  The value of the token stored at this level of the stack.
++**      (In other words, the "major" token.)
++**
++**   +  The semantic value stored at this level of the stack.  This is
++**      the information used by the action routines in the grammar.
++**      It is sometimes called the "minor" token.
++*/
++struct yyStackEntry {
++  YYACTIONTYPE stateno;  /* The state-number */
++  YYCODETYPE major;      /* The major token value.  This is the code
++                         ** number for the token at this stack level */
++  YYMINORTYPE minor;     /* The user-supplied minor token value.  This
++                         ** is the value of the token  */
++};
++typedef struct yyStackEntry yyStackEntry;
++
++/* The state of the parser is completely contained in an instance of
++** the following structure */
++struct yyParser {
++  int yyidx;                    /* Index of top element in stack */
++#ifdef YYTRACKMAXSTACKDEPTH
++  int yyidxMax;                 /* Maximum value of yyidx */
++#endif
++  int yyerrcnt;                 /* Shifts left before out of the error */
++  sqliteParserARG_SDECL                /* A place to hold %extra_argument */
++#if YYSTACKDEPTH<=0
++  int yystksz;                  /* Current side of the stack */
++  yyStackEntry *yystack;        /* The parser's stack */
++#else
++  yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
++#endif
++};
++typedef struct yyParser yyParser;
++
++#ifndef NDEBUG
++#include <stdio.h>
++static FILE *yyTraceFILE = 0;
++static char *yyTracePrompt = 0;
++#endif /* NDEBUG */
++
++#ifndef NDEBUG
++/* 
++** Turn parser tracing on by giving a stream to which to write the trace
++** and a prompt to preface each trace message.  Tracing is turned off
++** by making either argument NULL 
++**
++** Inputs:
++** <ul>
++** <li> A FILE* to which trace output should be written.
++**      If NULL, then tracing is turned off.
++** <li> A prefix string written at the beginning of every
++**      line of trace output.  If NULL, then tracing is
++**      turned off.
++** </ul>
++**
++** Outputs:
++** None.
++*/
++void sqliteParserTrace(FILE *TraceFILE, char *zTracePrompt){
++  yyTraceFILE = TraceFILE;
++  yyTracePrompt = zTracePrompt;
++  if( yyTraceFILE==0 ) yyTracePrompt = 0;
++  else if( yyTracePrompt==0 ) yyTraceFILE = 0;
++}
++#endif /* NDEBUG */
++
++#ifndef NDEBUG
++/* For tracing shifts, the names of all terminals and nonterminals
++** are required.  The following table supplies these names */
++static const char *const yyTokenName[] = { 
++  "$",             "END_OF_FILE",   "ILLEGAL",       "SPACE",       
++  "UNCLOSED_STRING",  "COMMENT",       "FUNCTION",      "COLUMN",      
++  "AGG_FUNCTION",  "SEMI",          "EXPLAIN",       "BEGIN",       
++  "TRANSACTION",   "COMMIT",        "END",           "ROLLBACK",    
++  "CREATE",        "TABLE",         "TEMP",          "LP",          
++  "RP",            "AS",            "COMMA",         "ID",          
++  "ABORT",         "AFTER",         "ASC",           "ATTACH",      
++  "BEFORE",        "CASCADE",       "CLUSTER",       "CONFLICT",    
++  "COPY",          "DATABASE",      "DEFERRED",      "DELIMITERS",  
++  "DESC",          "DETACH",        "EACH",          "FAIL",        
++  "FOR",           "GLOB",          "IGNORE",        "IMMEDIATE",   
++  "INITIALLY",     "INSTEAD",       "LIKE",          "MATCH",       
++  "KEY",           "OF",            "OFFSET",        "PRAGMA",      
++  "RAISE",         "REPLACE",       "RESTRICT",      "ROW",         
++  "STATEMENT",     "TRIGGER",       "VACUUM",        "VIEW",        
++  "OR",            "AND",           "NOT",           "EQ",          
++  "NE",            "ISNULL",        "NOTNULL",       "IS",          
++  "BETWEEN",       "IN",            "GT",            "GE",          
++  "LT",            "LE",            "BITAND",        "BITOR",       
++  "LSHIFT",        "RSHIFT",        "PLUS",          "MINUS",       
++  "STAR",          "SLASH",         "REM",           "CONCAT",      
++  "UMINUS",        "UPLUS",         "BITNOT",        "STRING",      
++  "JOIN_KW",       "INTEGER",       "CONSTRAINT",    "DEFAULT",     
++  "FLOAT",         "NULL",          "PRIMARY",       "UNIQUE",      
++  "CHECK",         "REFERENCES",    "COLLATE",       "ON",          
++  "DELETE",        "UPDATE",        "INSERT",        "SET",         
++  "DEFERRABLE",    "FOREIGN",       "DROP",          "UNION",       
++  "ALL",           "INTERSECT",     "EXCEPT",        "SELECT",      
++  "DISTINCT",      "DOT",           "FROM",          "JOIN",        
++  "USING",         "ORDER",         "BY",            "GROUP",       
++  "HAVING",        "LIMIT",         "WHERE",         "INTO",        
++  "VALUES",        "VARIABLE",      "CASE",          "WHEN",        
++  "THEN",          "ELSE",          "INDEX",         "error",       
++  "input",         "cmdlist",       "ecmd",          "explain",     
++  "cmdx",          "cmd",           "trans_opt",     "onconf",      
++  "nm",            "create_table",  "create_table_args",  "temp",        
++  "columnlist",    "conslist_opt",  "select",        "column",      
++  "columnid",      "type",          "carglist",      "id",          
++  "ids",           "typename",      "signed",        "carg",        
++  "ccons",         "sortorder",     "expr",          "idxlist_opt", 
++  "refargs",       "defer_subclause",  "refarg",        "refact",      
++  "init_deferred_pred_opt",  "conslist",      "tcons",         "idxlist",     
++  "defer_subclause_opt",  "orconf",        "resolvetype",   "oneselect",   
++  "multiselect_op",  "distinct",      "selcollist",    "from",        
++  "where_opt",     "groupby_opt",   "having_opt",    "orderby_opt", 
++  "limit_opt",     "sclp",          "as",            "seltablist",  
++  "stl_prefix",    "joinop",        "dbnm",          "on_opt",      
++  "using_opt",     "seltablist_paren",  "joinop2",       "sortlist",    
++  "sortitem",      "collate",       "exprlist",      "setlist",     
++  "insert_cmd",    "inscollist_opt",  "itemlist",      "inscollist",  
++  "likeop",        "case_operand",  "case_exprlist",  "case_else",   
++  "expritem",      "uniqueflag",    "idxitem",       "plus_num",    
++  "minus_num",     "plus_opt",      "number",        "trigger_decl",
++  "trigger_cmd_list",  "trigger_time",  "trigger_event",  "foreach_clause",
++  "when_clause",   "trigger_cmd",   "database_kw_opt",  "key_opt",     
++};
++#endif /* NDEBUG */
++
++#ifndef NDEBUG
++/* For tracing reduce actions, the names of all rules are required.
++*/
++static const char *const yyRuleName[] = {
++ /*   0 */ "input ::= cmdlist",
++ /*   1 */ "cmdlist ::= cmdlist ecmd",
++ /*   2 */ "cmdlist ::= ecmd",
++ /*   3 */ "ecmd ::= explain cmdx SEMI",
++ /*   4 */ "ecmd ::= SEMI",
++ /*   5 */ "cmdx ::= cmd",
++ /*   6 */ "explain ::= EXPLAIN",
++ /*   7 */ "explain ::=",
++ /*   8 */ "cmd ::= BEGIN trans_opt onconf",
++ /*   9 */ "trans_opt ::=",
++ /*  10 */ "trans_opt ::= TRANSACTION",
++ /*  11 */ "trans_opt ::= TRANSACTION nm",
++ /*  12 */ "cmd ::= COMMIT trans_opt",
++ /*  13 */ "cmd ::= END trans_opt",
++ /*  14 */ "cmd ::= ROLLBACK trans_opt",
++ /*  15 */ "cmd ::= create_table create_table_args",
++ /*  16 */ "create_table ::= CREATE temp TABLE nm",
++ /*  17 */ "temp ::= TEMP",
++ /*  18 */ "temp ::=",
++ /*  19 */ "create_table_args ::= LP columnlist conslist_opt RP",
++ /*  20 */ "create_table_args ::= AS select",
++ /*  21 */ "columnlist ::= columnlist COMMA column",
++ /*  22 */ "columnlist ::= column",
++ /*  23 */ "column ::= columnid type carglist",
++ /*  24 */ "columnid ::= nm",
++ /*  25 */ "id ::= ID",
++ /*  26 */ "ids ::= ID",
++ /*  27 */ "ids ::= STRING",
++ /*  28 */ "nm ::= ID",
++ /*  29 */ "nm ::= STRING",
++ /*  30 */ "nm ::= JOIN_KW",
++ /*  31 */ "type ::=",
++ /*  32 */ "type ::= typename",
++ /*  33 */ "type ::= typename LP signed RP",
++ /*  34 */ "type ::= typename LP signed COMMA signed RP",
++ /*  35 */ "typename ::= ids",
++ /*  36 */ "typename ::= typename ids",
++ /*  37 */ "signed ::= INTEGER",
++ /*  38 */ "signed ::= PLUS INTEGER",
++ /*  39 */ "signed ::= MINUS INTEGER",
++ /*  40 */ "carglist ::= carglist carg",
++ /*  41 */ "carglist ::=",
++ /*  42 */ "carg ::= CONSTRAINT nm ccons",
++ /*  43 */ "carg ::= ccons",
++ /*  44 */ "carg ::= DEFAULT STRING",
++ /*  45 */ "carg ::= DEFAULT ID",
++ /*  46 */ "carg ::= DEFAULT INTEGER",
++ /*  47 */ "carg ::= DEFAULT PLUS INTEGER",
++ /*  48 */ "carg ::= DEFAULT MINUS INTEGER",
++ /*  49 */ "carg ::= DEFAULT FLOAT",
++ /*  50 */ "carg ::= DEFAULT PLUS FLOAT",
++ /*  51 */ "carg ::= DEFAULT MINUS FLOAT",
++ /*  52 */ "carg ::= DEFAULT NULL",
++ /*  53 */ "ccons ::= NULL onconf",
++ /*  54 */ "ccons ::= NOT NULL onconf",
++ /*  55 */ "ccons ::= PRIMARY KEY sortorder onconf",
++ /*  56 */ "ccons ::= UNIQUE onconf",
++ /*  57 */ "ccons ::= CHECK LP expr RP onconf",
++ /*  58 */ "ccons ::= REFERENCES nm idxlist_opt refargs",
++ /*  59 */ "ccons ::= defer_subclause",
++ /*  60 */ "ccons ::= COLLATE id",
++ /*  61 */ "refargs ::=",
++ /*  62 */ "refargs ::= refargs refarg",
++ /*  63 */ "refarg ::= MATCH nm",
++ /*  64 */ "refarg ::= ON DELETE refact",
++ /*  65 */ "refarg ::= ON UPDATE refact",
++ /*  66 */ "refarg ::= ON INSERT refact",
++ /*  67 */ "refact ::= SET NULL",
++ /*  68 */ "refact ::= SET DEFAULT",
++ /*  69 */ "refact ::= CASCADE",
++ /*  70 */ "refact ::= RESTRICT",
++ /*  71 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
++ /*  72 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
++ /*  73 */ "init_deferred_pred_opt ::=",
++ /*  74 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
++ /*  75 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
++ /*  76 */ "conslist_opt ::=",
++ /*  77 */ "conslist_opt ::= COMMA conslist",
++ /*  78 */ "conslist ::= conslist COMMA tcons",
++ /*  79 */ "conslist ::= conslist tcons",
++ /*  80 */ "conslist ::= tcons",
++ /*  81 */ "tcons ::= CONSTRAINT nm",
++ /*  82 */ "tcons ::= PRIMARY KEY LP idxlist RP onconf",
++ /*  83 */ "tcons ::= UNIQUE LP idxlist RP onconf",
++ /*  84 */ "tcons ::= CHECK expr onconf",
++ /*  85 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt",
++ /*  86 */ "defer_subclause_opt ::=",
++ /*  87 */ "defer_subclause_opt ::= defer_subclause",
++ /*  88 */ "onconf ::=",
++ /*  89 */ "onconf ::= ON CONFLICT resolvetype",
++ /*  90 */ "orconf ::=",
++ /*  91 */ "orconf ::= OR resolvetype",
++ /*  92 */ "resolvetype ::= ROLLBACK",
++ /*  93 */ "resolvetype ::= ABORT",
++ /*  94 */ "resolvetype ::= FAIL",
++ /*  95 */ "resolvetype ::= IGNORE",
++ /*  96 */ "resolvetype ::= REPLACE",
++ /*  97 */ "cmd ::= DROP TABLE nm",
++ /*  98 */ "cmd ::= CREATE temp VIEW nm AS select",
++ /*  99 */ "cmd ::= DROP VIEW nm",
++ /* 100 */ "cmd ::= select",
++ /* 101 */ "select ::= oneselect",
++ /* 102 */ "select ::= select multiselect_op oneselect",
++ /* 103 */ "multiselect_op ::= UNION",
++ /* 104 */ "multiselect_op ::= UNION ALL",
++ /* 105 */ "multiselect_op ::= INTERSECT",
++ /* 106 */ "multiselect_op ::= EXCEPT",
++ /* 107 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
++ /* 108 */ "distinct ::= DISTINCT",
++ /* 109 */ "distinct ::= ALL",
++ /* 110 */ "distinct ::=",
++ /* 111 */ "sclp ::= selcollist COMMA",
++ /* 112 */ "sclp ::=",
++ /* 113 */ "selcollist ::= sclp expr as",
++ /* 114 */ "selcollist ::= sclp STAR",
++ /* 115 */ "selcollist ::= sclp nm DOT STAR",
++ /* 116 */ "as ::= AS nm",
++ /* 117 */ "as ::= ids",
++ /* 118 */ "as ::=",
++ /* 119 */ "from ::=",
++ /* 120 */ "from ::= FROM seltablist",
++ /* 121 */ "stl_prefix ::= seltablist joinop",
++ /* 122 */ "stl_prefix ::=",
++ /* 123 */ "seltablist ::= stl_prefix nm dbnm as on_opt using_opt",
++ /* 124 */ "seltablist ::= stl_prefix LP seltablist_paren RP as on_opt using_opt",
++ /* 125 */ "seltablist_paren ::= select",
++ /* 126 */ "seltablist_paren ::= seltablist",
++ /* 127 */ "dbnm ::=",
++ /* 128 */ "dbnm ::= DOT nm",
++ /* 129 */ "joinop ::= COMMA",
++ /* 130 */ "joinop ::= JOIN",
++ /* 131 */ "joinop ::= JOIN_KW JOIN",
++ /* 132 */ "joinop ::= JOIN_KW nm JOIN",
++ /* 133 */ "joinop ::= JOIN_KW nm nm JOIN",
++ /* 134 */ "on_opt ::= ON expr",
++ /* 135 */ "on_opt ::=",
++ /* 136 */ "using_opt ::= USING LP idxlist RP",
++ /* 137 */ "using_opt ::=",
++ /* 138 */ "orderby_opt ::=",
++ /* 139 */ "orderby_opt ::= ORDER BY sortlist",
++ /* 140 */ "sortlist ::= sortlist COMMA sortitem collate sortorder",
++ /* 141 */ "sortlist ::= sortitem collate sortorder",
++ /* 142 */ "sortitem ::= expr",
++ /* 143 */ "sortorder ::= ASC",
++ /* 144 */ "sortorder ::= DESC",
++ /* 145 */ "sortorder ::=",
++ /* 146 */ "collate ::=",
++ /* 147 */ "collate ::= COLLATE id",
++ /* 148 */ "groupby_opt ::=",
++ /* 149 */ "groupby_opt ::= GROUP BY exprlist",
++ /* 150 */ "having_opt ::=",
++ /* 151 */ "having_opt ::= HAVING expr",
++ /* 152 */ "limit_opt ::=",
++ /* 153 */ "limit_opt ::= LIMIT signed",
++ /* 154 */ "limit_opt ::= LIMIT signed OFFSET signed",
++ /* 155 */ "limit_opt ::= LIMIT signed COMMA signed",
++ /* 156 */ "cmd ::= DELETE FROM nm dbnm where_opt",
++ /* 157 */ "where_opt ::=",
++ /* 158 */ "where_opt ::= WHERE expr",
++ /* 159 */ "cmd ::= UPDATE orconf nm dbnm SET setlist where_opt",
++ /* 160 */ "setlist ::= setlist COMMA nm EQ expr",
++ /* 161 */ "setlist ::= nm EQ expr",
++ /* 162 */ "cmd ::= insert_cmd INTO nm dbnm inscollist_opt VALUES LP itemlist RP",
++ /* 163 */ "cmd ::= insert_cmd INTO nm dbnm inscollist_opt select",
++ /* 164 */ "insert_cmd ::= INSERT orconf",
++ /* 165 */ "insert_cmd ::= REPLACE",
++ /* 166 */ "itemlist ::= itemlist COMMA expr",
++ /* 167 */ "itemlist ::= expr",
++ /* 168 */ "inscollist_opt ::=",
++ /* 169 */ "inscollist_opt ::= LP inscollist RP",
++ /* 170 */ "inscollist ::= inscollist COMMA nm",
++ /* 171 */ "inscollist ::= nm",
++ /* 172 */ "expr ::= LP expr RP",
++ /* 173 */ "expr ::= NULL",
++ /* 174 */ "expr ::= ID",
++ /* 175 */ "expr ::= JOIN_KW",
++ /* 176 */ "expr ::= nm DOT nm",
++ /* 177 */ "expr ::= nm DOT nm DOT nm",
++ /* 178 */ "expr ::= INTEGER",
++ /* 179 */ "expr ::= FLOAT",
++ /* 180 */ "expr ::= STRING",
++ /* 181 */ "expr ::= VARIABLE",
++ /* 182 */ "expr ::= ID LP exprlist RP",
++ /* 183 */ "expr ::= ID LP STAR RP",
++ /* 184 */ "expr ::= expr AND expr",
++ /* 185 */ "expr ::= expr OR expr",
++ /* 186 */ "expr ::= expr LT expr",
++ /* 187 */ "expr ::= expr GT expr",
++ /* 188 */ "expr ::= expr LE expr",
++ /* 189 */ "expr ::= expr GE expr",
++ /* 190 */ "expr ::= expr NE expr",
++ /* 191 */ "expr ::= expr EQ expr",
++ /* 192 */ "expr ::= expr BITAND expr",
++ /* 193 */ "expr ::= expr BITOR expr",
++ /* 194 */ "expr ::= expr LSHIFT expr",
++ /* 195 */ "expr ::= expr RSHIFT expr",
++ /* 196 */ "expr ::= expr likeop expr",
++ /* 197 */ "expr ::= expr NOT likeop expr",
++ /* 198 */ "likeop ::= LIKE",
++ /* 199 */ "likeop ::= GLOB",
++ /* 200 */ "expr ::= expr PLUS expr",
++ /* 201 */ "expr ::= expr MINUS expr",
++ /* 202 */ "expr ::= expr STAR expr",
++ /* 203 */ "expr ::= expr SLASH expr",
++ /* 204 */ "expr ::= expr REM expr",
++ /* 205 */ "expr ::= expr CONCAT expr",
++ /* 206 */ "expr ::= expr ISNULL",
++ /* 207 */ "expr ::= expr IS NULL",
++ /* 208 */ "expr ::= expr NOTNULL",
++ /* 209 */ "expr ::= expr NOT NULL",
++ /* 210 */ "expr ::= expr IS NOT NULL",
++ /* 211 */ "expr ::= NOT expr",
++ /* 212 */ "expr ::= BITNOT expr",
++ /* 213 */ "expr ::= MINUS expr",
++ /* 214 */ "expr ::= PLUS expr",
++ /* 215 */ "expr ::= LP select RP",
++ /* 216 */ "expr ::= expr BETWEEN expr AND expr",
++ /* 217 */ "expr ::= expr NOT BETWEEN expr AND expr",
++ /* 218 */ "expr ::= expr IN LP exprlist RP",
++ /* 219 */ "expr ::= expr IN LP select RP",
++ /* 220 */ "expr ::= expr NOT IN LP exprlist RP",
++ /* 221 */ "expr ::= expr NOT IN LP select RP",
++ /* 222 */ "expr ::= expr IN nm dbnm",
++ /* 223 */ "expr ::= expr NOT IN nm dbnm",
++ /* 224 */ "expr ::= CASE case_operand case_exprlist case_else END",
++ /* 225 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
++ /* 226 */ "case_exprlist ::= WHEN expr THEN expr",
++ /* 227 */ "case_else ::= ELSE expr",
++ /* 228 */ "case_else ::=",
++ /* 229 */ "case_operand ::= expr",
++ /* 230 */ "case_operand ::=",
++ /* 231 */ "exprlist ::= exprlist COMMA expritem",
++ /* 232 */ "exprlist ::= expritem",
++ /* 233 */ "expritem ::= expr",
++ /* 234 */ "expritem ::=",
++ /* 235 */ "cmd ::= CREATE uniqueflag INDEX nm ON nm dbnm LP idxlist RP onconf",
++ /* 236 */ "uniqueflag ::= UNIQUE",
++ /* 237 */ "uniqueflag ::=",
++ /* 238 */ "idxlist_opt ::=",
++ /* 239 */ "idxlist_opt ::= LP idxlist RP",
++ /* 240 */ "idxlist ::= idxlist COMMA idxitem",
++ /* 241 */ "idxlist ::= idxitem",
++ /* 242 */ "idxitem ::= nm sortorder",
++ /* 243 */ "cmd ::= DROP INDEX nm dbnm",
++ /* 244 */ "cmd ::= COPY orconf nm dbnm FROM nm USING DELIMITERS STRING",
++ /* 245 */ "cmd ::= COPY orconf nm dbnm FROM nm",
++ /* 246 */ "cmd ::= VACUUM",
++ /* 247 */ "cmd ::= VACUUM nm",
++ /* 248 */ "cmd ::= PRAGMA ids EQ nm",
++ /* 249 */ "cmd ::= PRAGMA ids EQ ON",
++ /* 250 */ "cmd ::= PRAGMA ids EQ plus_num",
++ /* 251 */ "cmd ::= PRAGMA ids EQ minus_num",
++ /* 252 */ "cmd ::= PRAGMA ids LP nm RP",
++ /* 253 */ "cmd ::= PRAGMA ids",
++ /* 254 */ "plus_num ::= plus_opt number",
++ /* 255 */ "minus_num ::= MINUS number",
++ /* 256 */ "number ::= INTEGER",
++ /* 257 */ "number ::= FLOAT",
++ /* 258 */ "plus_opt ::= PLUS",
++ /* 259 */ "plus_opt ::=",
++ /* 260 */ "cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END",
++ /* 261 */ "trigger_decl ::= temp TRIGGER nm trigger_time trigger_event ON nm dbnm foreach_clause when_clause",
++ /* 262 */ "trigger_time ::= BEFORE",
++ /* 263 */ "trigger_time ::= AFTER",
++ /* 264 */ "trigger_time ::= INSTEAD OF",
++ /* 265 */ "trigger_time ::=",
++ /* 266 */ "trigger_event ::= DELETE",
++ /* 267 */ "trigger_event ::= INSERT",
++ /* 268 */ "trigger_event ::= UPDATE",
++ /* 269 */ "trigger_event ::= UPDATE OF inscollist",
++ /* 270 */ "foreach_clause ::=",
++ /* 271 */ "foreach_clause ::= FOR EACH ROW",
++ /* 272 */ "foreach_clause ::= FOR EACH STATEMENT",
++ /* 273 */ "when_clause ::=",
++ /* 274 */ "when_clause ::= WHEN expr",
++ /* 275 */ "trigger_cmd_list ::= trigger_cmd SEMI trigger_cmd_list",
++ /* 276 */ "trigger_cmd_list ::=",
++ /* 277 */ "trigger_cmd ::= UPDATE orconf nm SET setlist where_opt",
++ /* 278 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt VALUES LP itemlist RP",
++ /* 279 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt select",
++ /* 280 */ "trigger_cmd ::= DELETE FROM nm where_opt",
++ /* 281 */ "trigger_cmd ::= select",
++ /* 282 */ "expr ::= RAISE LP IGNORE RP",
++ /* 283 */ "expr ::= RAISE LP ROLLBACK COMMA nm RP",
++ /* 284 */ "expr ::= RAISE LP ABORT COMMA nm RP",
++ /* 285 */ "expr ::= RAISE LP FAIL COMMA nm RP",
++ /* 286 */ "cmd ::= DROP TRIGGER nm dbnm",
++ /* 287 */ "cmd ::= ATTACH database_kw_opt ids AS nm key_opt",
++ /* 288 */ "key_opt ::= USING ids",
++ /* 289 */ "key_opt ::=",
++ /* 290 */ "database_kw_opt ::= DATABASE",
++ /* 291 */ "database_kw_opt ::=",
++ /* 292 */ "cmd ::= DETACH database_kw_opt nm",
++};
++#endif /* NDEBUG */
++
++
++#if YYSTACKDEPTH<=0
++/*
++** Try to increase the size of the parser stack.
++*/
++static void yyGrowStack(yyParser *p){
++  int newSize;
++  yyStackEntry *pNew;
++
++  newSize = p->yystksz*2 + 100;
++  pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
++  if( pNew ){
++    p->yystack = pNew;
++    p->yystksz = newSize;
++#ifndef NDEBUG
++    if( yyTraceFILE ){
++      fprintf(yyTraceFILE,"%sStack grows to %d entries!\n",
++              yyTracePrompt, p->yystksz);
++    }
++#endif
++  }
++}
++#endif
++
++/* 
++** This function allocates a new parser.
++** The only argument is a pointer to a function which works like
++** malloc.
++**
++** Inputs:
++** A pointer to the function used to allocate memory.
++**
++** Outputs:
++** A pointer to a parser.  This pointer is used in subsequent calls
++** to sqliteParser and sqliteParserFree.
++*/
++void *sqliteParserAlloc(void *(*mallocProc)(size_t)){
++  yyParser *pParser;
++  pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
++  if( pParser ){
++    pParser->yyidx = -1;
++#ifdef YYTRACKMAXSTACKDEPTH
++    pParser->yyidxMax = 0;
++#endif
++#if YYSTACKDEPTH<=0
++    pParser->yystack = NULL;
++    pParser->yystksz = 0;
++    yyGrowStack(pParser);
++#endif
++  }
++  return pParser;
++}
++
++/* The following function deletes the value associated with a
++** symbol.  The symbol can be either a terminal or nonterminal.
++** "yymajor" is the symbol code, and "yypminor" is a pointer to
++** the value.
++*/
++static void yy_destructor(
++  yyParser *yypParser,    /* The parser */
++  YYCODETYPE yymajor,     /* Type code for object to destroy */
++  YYMINORTYPE *yypminor   /* The object to be destroyed */
++){
++  sqliteParserARG_FETCH;
++  switch( yymajor ){
++    /* Here is inserted the actions which take place when a
++    ** terminal or non-terminal is destroyed.  This can happen
++    ** when the symbol is popped from the stack during a
++    ** reduce or during error processing or when a parser is 
++    ** being destroyed before it is finished parsing.
++    **
++    ** Note: during a reduce, the only symbols destroyed are those
++    ** which appear on the RHS of the rule, but which are not used
++    ** inside the C code.
++    */
++    case 146: /* select */
++    case 171: /* oneselect */
++    case 189: /* seltablist_paren */
++{
++#line 286 "ext/sqlite/libsqlite/src/parse.y"
++sqliteSelectDelete((yypminor->yy179));
++#line 1131 "ext/sqlite/libsqlite/src/parse.c"
++}
++      break;
++    case 158: /* expr */
++    case 176: /* where_opt */
++    case 178: /* having_opt */
++    case 187: /* on_opt */
++    case 192: /* sortitem */
++    case 204: /* expritem */
++{
++#line 533 "ext/sqlite/libsqlite/src/parse.y"
++sqliteExprDelete((yypminor->yy242));
++#line 1143 "ext/sqlite/libsqlite/src/parse.c"
++}
++      break;
++    case 159: /* idxlist_opt */
++    case 167: /* idxlist */
++    case 188: /* using_opt */
++    case 197: /* inscollist_opt */
++    case 199: /* inscollist */
++{
++#line 746 "ext/sqlite/libsqlite/src/parse.y"
++sqliteIdListDelete((yypminor->yy320));
++#line 1154 "ext/sqlite/libsqlite/src/parse.c"
++}
++      break;
++    case 174: /* selcollist */
++    case 177: /* groupby_opt */
++    case 179: /* orderby_opt */
++    case 181: /* sclp */
++    case 191: /* sortlist */
++    case 194: /* exprlist */
++    case 195: /* setlist */
++    case 198: /* itemlist */
++    case 202: /* case_exprlist */
++{
++#line 322 "ext/sqlite/libsqlite/src/parse.y"
++sqliteExprListDelete((yypminor->yy322));
++#line 1169 "ext/sqlite/libsqlite/src/parse.c"
++}
++      break;
++    case 175: /* from */
++    case 183: /* seltablist */
++    case 184: /* stl_prefix */
++{
++#line 353 "ext/sqlite/libsqlite/src/parse.y"
++sqliteSrcListDelete((yypminor->yy307));
++#line 1178 "ext/sqlite/libsqlite/src/parse.c"
++}
++      break;
++    case 212: /* trigger_cmd_list */
++    case 217: /* trigger_cmd */
++{
++#line 828 "ext/sqlite/libsqlite/src/parse.y"
++sqliteDeleteTriggerStep((yypminor->yy19));
++#line 1186 "ext/sqlite/libsqlite/src/parse.c"
++}
++      break;
++    case 214: /* trigger_event */
++{
++#line 812 "ext/sqlite/libsqlite/src/parse.y"
++sqliteIdListDelete((yypminor->yy290).b);
++#line 1193 "ext/sqlite/libsqlite/src/parse.c"
++}
++      break;
++    default:  break;   /* If no destructor action specified: do nothing */
++  }
++}
++
++/*
++** Pop the parser's stack once.
++**
++** If there is a destructor routine associated with the token which
++** is popped from the stack, then call it.
++**
++** Return the major token number for the symbol popped.
++*/
++static int yy_pop_parser_stack(yyParser *pParser){
++  YYCODETYPE yymajor;
++  yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
++
++  if( pParser->yyidx<0 ) return 0;
++#ifndef NDEBUG
++  if( yyTraceFILE && pParser->yyidx>=0 ){
++    fprintf(yyTraceFILE,"%sPopping %s\n",
++      yyTracePrompt,
++      yyTokenName[yytos->major]);
++  }
++#endif
++  yymajor = yytos->major;
++  yy_destructor(pParser, yymajor, &yytos->minor);
++  pParser->yyidx--;
++  return yymajor;
++}
++
++/* 
++** Deallocate and destroy a parser.  Destructors are all called for
++** all stack elements before shutting the parser down.
++**
++** Inputs:
++** <ul>
++** <li>  A pointer to the parser.  This should be a pointer
++**       obtained from sqliteParserAlloc.
++** <li>  A pointer to a function used to reclaim memory obtained
++**       from malloc.
++** </ul>
++*/
++void sqliteParserFree(
++  void *p,                    /* The parser to be deleted */
++  void (*freeProc)(void*)     /* Function used to reclaim memory */
++){
++  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);
++}
++
++/*
++** Return the peak depth of the stack for a parser.
++*/
++#ifdef YYTRACKMAXSTACKDEPTH
++int sqliteParserStackPeak(void *p){
++  yyParser *pParser = (yyParser*)p;
++  return pParser->yyidxMax;
++}
++#endif
++
++/*
++** Find the appropriate action for a parser given the terminal
++** look-ahead token iLookAhead.
++**
++** If the look-ahead token is YYNOCODE, then check to see if the action is
++** independent of the look-ahead.  If it is, return the action, otherwise
++** return YY_NO_ACTION.
++*/
++static int yy_find_shift_action(
++  yyParser *pParser,        /* The parser */
++  YYCODETYPE iLookAhead     /* The look-ahead token */
++){
++  int i;
++  int stateno = pParser->yystack[pParser->yyidx].stateno;
++ 
++  if( stateno>YY_SHIFT_COUNT
++   || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
++    return yy_default[stateno];
++  }
++  assert( iLookAhead!=YYNOCODE );
++  i += iLookAhead;
++  if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
++    if( iLookAhead>0 ){
++#ifdef YYFALLBACK
++      YYCODETYPE iFallback;            /* Fallback token */
++      if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
++             && (iFallback = yyFallback[iLookAhead])!=0 ){
++#ifndef NDEBUG
++        if( yyTraceFILE ){
++          fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
++             yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
++        }
++#endif
++        return yy_find_shift_action(pParser, iFallback);
++      }
++#endif
++#ifdef YYWILDCARD
++      {
++        int j = i - iLookAhead + YYWILDCARD;
++        if( 
++#if YY_SHIFT_MIN+YYWILDCARD<0
++          j>=0 &&
++#endif
++#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
++          j<YY_ACTTAB_COUNT &&
++#endif
++          yy_lookahead[j]==YYWILDCARD
++        ){
++#ifndef NDEBUG
++          if( yyTraceFILE ){
++            fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
++               yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]);
++          }
++#endif /* NDEBUG */
++          return yy_action[j];
++        }
++      }
++#endif /* YYWILDCARD */
++    }
++    return yy_default[stateno];
++  }else{
++    return yy_action[i];
++  }
++}
++
++/*
++** Find the appropriate action for a parser given the non-terminal
++** look-ahead token iLookAhead.
++**
++** If the look-ahead token is YYNOCODE, then check to see if the action is
++** independent of the look-ahead.  If it is, return the action, otherwise
++** return YY_NO_ACTION.
++*/
++static int yy_find_reduce_action(
++  int stateno,              /* Current state number */
++  YYCODETYPE iLookAhead     /* The look-ahead token */
++){
++  int i;
++#ifdef YYERRORSYMBOL
++  if( stateno>YY_REDUCE_COUNT ){
++    return yy_default[stateno];
++  }
++#else
++  assert( stateno<=YY_REDUCE_COUNT );
++#endif
++  i = yy_reduce_ofst[stateno];
++  assert( i!=YY_REDUCE_USE_DFLT );
++  assert( iLookAhead!=YYNOCODE );
++  i += iLookAhead;
++#ifdef YYERRORSYMBOL
++  if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
++    return yy_default[stateno];
++  }
++#else
++  assert( i>=0 && i<YY_ACTTAB_COUNT );
++  assert( yy_lookahead[i]==iLookAhead );
++#endif
++  return yy_action[i];
++}
++
++/*
++** The following routine is called if the stack overflows.
++*/
++static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
++   sqliteParserARG_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 */
++   sqliteParserARG_STORE; /* Suppress warning about unused %extra_argument var */
++}
++
++/*
++** Perform a shift action.
++*/
++static void yy_shift(
++  yyParser *yypParser,          /* The parser to be shifted */
++  int yyNewState,               /* The new state to shift in */
++  int yyMajor,                  /* The major token to shift in */
++  YYMINORTYPE *yypMinor         /* Pointer to the minor token to shift in */
++){
++  yyStackEntry *yytos;
++  yypParser->yyidx++;
++#ifdef YYTRACKMAXSTACKDEPTH
++  if( yypParser->yyidx>yypParser->yyidxMax ){
++    yypParser->yyidxMax = yypParser->yyidx;
++  }
++#endif
++#if YYSTACKDEPTH>0 
++  if( yypParser->yyidx>=YYSTACKDEPTH ){
++    yyStackOverflow(yypParser, yypMinor);
++    return;
++  }
++#else
++  if( yypParser->yyidx>=yypParser->yystksz ){
++    yyGrowStack(yypParser);
++    if( yypParser->yyidx>=yypParser->yystksz ){
++      yyStackOverflow(yypParser, yypMinor);
++      return;
++    }
++  }
++#endif
++  yytos = &yypParser->yystack[yypParser->yyidx];
++  yytos->stateno = (YYACTIONTYPE)yyNewState;
++  yytos->major = (YYCODETYPE)yyMajor;
++  yytos->minor = *yypMinor;
++#ifndef NDEBUG
++  if( yyTraceFILE && yypParser->yyidx>0 ){
++    int i;
++    fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
++    fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
++    for(i=1; i<=yypParser->yyidx; i++)
++      fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
++    fprintf(yyTraceFILE,"\n");
++  }
++#endif
++}
++
++/* The following table contains information about every rule that
++** is used during the reduce.
++*/
++static const struct {
++  YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
++  unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
++} yyRuleInfo[] = {
++  { 132, 1 },
++  { 133, 2 },
++  { 133, 1 },
++  { 134, 3 },
++  { 134, 1 },
++  { 136, 1 },
++  { 135, 1 },
++  { 135, 0 },
++  { 137, 3 },
++  { 138, 0 },
++  { 138, 1 },
++  { 138, 2 },
++  { 137, 2 },
++  { 137, 2 },
++  { 137, 2 },
++  { 137, 2 },
++  { 141, 4 },
++  { 143, 1 },
++  { 143, 0 },
++  { 142, 4 },
++  { 142, 2 },
++  { 144, 3 },
++  { 144, 1 },
++  { 147, 3 },
++  { 148, 1 },
++  { 151, 1 },
++  { 152, 1 },
++  { 152, 1 },
++  { 140, 1 },
++  { 140, 1 },
++  { 140, 1 },
++  { 149, 0 },
++  { 149, 1 },
++  { 149, 4 },
++  { 149, 6 },
++  { 153, 1 },
++  { 153, 2 },
++  { 154, 1 },
++  { 154, 2 },
++  { 154, 2 },
++  { 150, 2 },
++  { 150, 0 },
++  { 155, 3 },
++  { 155, 1 },
++  { 155, 2 },
++  { 155, 2 },
++  { 155, 2 },
++  { 155, 3 },
++  { 155, 3 },
++  { 155, 2 },
++  { 155, 3 },
++  { 155, 3 },
++  { 155, 2 },
++  { 156, 2 },
++  { 156, 3 },
++  { 156, 4 },
++  { 156, 2 },
++  { 156, 5 },
++  { 156, 4 },
++  { 156, 1 },
++  { 156, 2 },
++  { 160, 0 },
++  { 160, 2 },
++  { 162, 2 },
++  { 162, 3 },
++  { 162, 3 },
++  { 162, 3 },
++  { 163, 2 },
++  { 163, 2 },
++  { 163, 1 },
++  { 163, 1 },
++  { 161, 3 },
++  { 161, 2 },
++  { 164, 0 },
++  { 164, 2 },
++  { 164, 2 },
++  { 145, 0 },
++  { 145, 2 },
++  { 165, 3 },
++  { 165, 2 },
++  { 165, 1 },
++  { 166, 2 },
++  { 166, 6 },
++  { 166, 5 },
++  { 166, 3 },
++  { 166, 10 },
++  { 168, 0 },
++  { 168, 1 },
++  { 139, 0 },
++  { 139, 3 },
++  { 169, 0 },
++  { 169, 2 },
++  { 170, 1 },
++  { 170, 1 },
++  { 170, 1 },
++  { 170, 1 },
++  { 170, 1 },
++  { 137, 3 },
++  { 137, 6 },
++  { 137, 3 },
++  { 137, 1 },
++  { 146, 1 },
++  { 146, 3 },
++  { 172, 1 },
++  { 172, 2 },
++  { 172, 1 },
++  { 172, 1 },
++  { 171, 9 },
++  { 173, 1 },
++  { 173, 1 },
++  { 173, 0 },
++  { 181, 2 },
++  { 181, 0 },
++  { 174, 3 },
++  { 174, 2 },
++  { 174, 4 },
++  { 182, 2 },
++  { 182, 1 },
++  { 182, 0 },
++  { 175, 0 },
++  { 175, 2 },
++  { 184, 2 },
++  { 184, 0 },
++  { 183, 6 },
++  { 183, 7 },
++  { 189, 1 },
++  { 189, 1 },
++  { 186, 0 },
++  { 186, 2 },
++  { 185, 1 },
++  { 185, 1 },
++  { 185, 2 },
++  { 185, 3 },
++  { 185, 4 },
++  { 187, 2 },
++  { 187, 0 },
++  { 188, 4 },
++  { 188, 0 },
++  { 179, 0 },
++  { 179, 3 },
++  { 191, 5 },
++  { 191, 3 },
++  { 192, 1 },
++  { 157, 1 },
++  { 157, 1 },
++  { 157, 0 },
++  { 193, 0 },
++  { 193, 2 },
++  { 177, 0 },
++  { 177, 3 },
++  { 178, 0 },
++  { 178, 2 },
++  { 180, 0 },
++  { 180, 2 },
++  { 180, 4 },
++  { 180, 4 },
++  { 137, 5 },
++  { 176, 0 },
++  { 176, 2 },
++  { 137, 7 },
++  { 195, 5 },
++  { 195, 3 },
++  { 137, 9 },
++  { 137, 6 },
++  { 196, 2 },
++  { 196, 1 },
++  { 198, 3 },
++  { 198, 1 },
++  { 197, 0 },
++  { 197, 3 },
++  { 199, 3 },
++  { 199, 1 },
++  { 158, 3 },
++  { 158, 1 },
++  { 158, 1 },
++  { 158, 1 },
++  { 158, 3 },
++  { 158, 5 },
++  { 158, 1 },
++  { 158, 1 },
++  { 158, 1 },
++  { 158, 1 },
++  { 158, 4 },
++  { 158, 4 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 4 },
++  { 200, 1 },
++  { 200, 1 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 3 },
++  { 158, 2 },
++  { 158, 3 },
++  { 158, 2 },
++  { 158, 3 },
++  { 158, 4 },
++  { 158, 2 },
++  { 158, 2 },
++  { 158, 2 },
++  { 158, 2 },
++  { 158, 3 },
++  { 158, 5 },
++  { 158, 6 },
++  { 158, 5 },
++  { 158, 5 },
++  { 158, 6 },
++  { 158, 6 },
++  { 158, 4 },
++  { 158, 5 },
++  { 158, 5 },
++  { 202, 5 },
++  { 202, 4 },
++  { 203, 2 },
++  { 203, 0 },
++  { 201, 1 },
++  { 201, 0 },
++  { 194, 3 },
++  { 194, 1 },
++  { 204, 1 },
++  { 204, 0 },
++  { 137, 11 },
++  { 205, 1 },
++  { 205, 0 },
++  { 159, 0 },
++  { 159, 3 },
++  { 167, 3 },
++  { 167, 1 },
++  { 206, 2 },
++  { 137, 4 },
++  { 137, 9 },
++  { 137, 6 },
++  { 137, 1 },
++  { 137, 2 },
++  { 137, 4 },
++  { 137, 4 },
++  { 137, 4 },
++  { 137, 4 },
++  { 137, 5 },
++  { 137, 2 },
++  { 207, 2 },
++  { 208, 2 },
++  { 210, 1 },
++  { 210, 1 },
++  { 209, 1 },
++  { 209, 0 },
++  { 137, 5 },
++  { 211, 10 },
++  { 213, 1 },
++  { 213, 1 },
++  { 213, 2 },
++  { 213, 0 },
++  { 214, 1 },
++  { 214, 1 },
++  { 214, 1 },
++  { 214, 3 },
++  { 215, 0 },
++  { 215, 3 },
++  { 215, 3 },
++  { 216, 0 },
++  { 216, 2 },
++  { 212, 3 },
++  { 212, 0 },
++  { 217, 6 },
++  { 217, 8 },
++  { 217, 5 },
++  { 217, 4 },
++  { 217, 1 },
++  { 158, 4 },
++  { 158, 6 },
++  { 158, 6 },
++  { 158, 6 },
++  { 137, 4 },
++  { 137, 6 },
++  { 219, 2 },
++  { 219, 0 },
++  { 218, 1 },
++  { 218, 0 },
++  { 137, 3 },
++};
++
++static void yy_accept(yyParser*);  /* Forward Declaration */
++
++/*
++** Perform a reduce action and the shift that must immediately
++** follow the reduce.
++*/
++static void yy_reduce(
++  yyParser *yypParser,         /* The parser */
++  int yyruleno                 /* Number of the rule by which to reduce */
++){
++  int yygoto;                     /* The next state */
++  int yyact;                      /* The next action */
++  YYMINORTYPE yygotominor;        /* The LHS of the rule reduced */
++  yyStackEntry *yymsp;            /* The top of the parser's stack */
++  int yysize;                     /* Amount to pop the stack */
++  sqliteParserARG_FETCH;
++  yymsp = &yypParser->yystack[yypParser->yyidx];
++#ifndef NDEBUG
++  if( yyTraceFILE && yyruleno>=0 
++        && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
++    fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
++      yyRuleName[yyruleno]);
++  }
++#endif /* NDEBUG */
++
++  /* Silence complaints from purify about yygotominor being uninitialized
++  ** in some cases when it is copied into the stack after the following
++  ** switch.  yygotominor is uninitialized when a rule reduces that does
++  ** not set the value of its left-hand side nonterminal.  Leaving the
++  ** value of the nonterminal uninitialized is utterly harmless as long
++  ** as the value is never used.  So really the only thing this code
++  ** accomplishes is to quieten purify.  
++  **
++  ** 2007-01-16:  The wireshark project (www.wireshark.org) reports that
++  ** without this code, their parser segfaults.  I'm not sure what there
++  ** parser is doing to make this happen.  This is the second bug report
++  ** from wireshark this week.  Clearly they are stressing Lemon in ways
++  ** that it has not been previously stressed...  (SQLite ticket #2172)
++  */
++  /*memset(&yygotominor, 0, sizeof(yygotominor));*/
++  yygotominor = yyzerominor;
++
++
++  switch( yyruleno ){
++  /* Beginning here are the reduction cases.  A typical example
++  ** follows:
++  **   case 0:
++  **  #line <lineno> <grammarfile>
++  **     { ... }           // User supplied code
++  **  #line <lineno> <thisfile>
++  **     break;
++  */
++      case 5: /* cmdx ::= cmd */
++#line 72 "ext/sqlite/libsqlite/src/parse.y"
++{ sqliteExec(pParse); }
++#line 1781 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 6: /* explain ::= EXPLAIN */
++#line 73 "ext/sqlite/libsqlite/src/parse.y"
++{ sqliteBeginParse(pParse, 1); }
++#line 1786 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 7: /* explain ::= */
++#line 74 "ext/sqlite/libsqlite/src/parse.y"
++{ sqliteBeginParse(pParse, 0); }
++#line 1791 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 8: /* cmd ::= BEGIN trans_opt onconf */
++#line 79 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteBeginTransaction(pParse,yymsp[0].minor.yy372);}
++#line 1796 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 12: /* cmd ::= COMMIT trans_opt */
++      case 13: /* cmd ::= END trans_opt */ yytestcase(yyruleno==13);
++#line 83 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteCommitTransaction(pParse);}
++#line 1802 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 14: /* cmd ::= ROLLBACK trans_opt */
++#line 85 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteRollbackTransaction(pParse);}
++#line 1807 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 16: /* create_table ::= CREATE temp TABLE nm */
++#line 90 "ext/sqlite/libsqlite/src/parse.y"
++{
++   sqliteStartTable(pParse,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0,yymsp[-2].minor.yy372,0);
++}
++#line 1814 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 17: /* temp ::= TEMP */
++      case 74: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ yytestcase(yyruleno==74);
++      case 108: /* distinct ::= DISTINCT */ yytestcase(yyruleno==108);
++#line 94 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy372 = 1;}
++#line 1821 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 18: /* temp ::= */
++      case 73: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==73);
++      case 75: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ yytestcase(yyruleno==75);
++      case 86: /* defer_subclause_opt ::= */ yytestcase(yyruleno==86);
++      case 109: /* distinct ::= ALL */ yytestcase(yyruleno==109);
++      case 110: /* distinct ::= */ yytestcase(yyruleno==110);
++#line 95 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy372 = 0;}
++#line 1831 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 19: /* create_table_args ::= LP columnlist conslist_opt RP */
++#line 96 "ext/sqlite/libsqlite/src/parse.y"
++{
++  sqliteEndTable(pParse,&yymsp[0].minor.yy0,0);
++}
++#line 1838 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 20: /* create_table_args ::= AS select */
++#line 99 "ext/sqlite/libsqlite/src/parse.y"
++{
++  sqliteEndTable(pParse,0,yymsp[0].minor.yy179);
++  sqliteSelectDelete(yymsp[0].minor.yy179);
++}
++#line 1846 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 24: /* columnid ::= nm */
++#line 111 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteAddColumn(pParse,&yymsp[0].minor.yy0);}
++#line 1851 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 25: /* id ::= ID */
++      case 26: /* ids ::= ID */ yytestcase(yyruleno==26);
++      case 27: /* ids ::= STRING */ yytestcase(yyruleno==27);
++      case 28: /* nm ::= ID */ yytestcase(yyruleno==28);
++      case 29: /* nm ::= STRING */ yytestcase(yyruleno==29);
++      case 30: /* nm ::= JOIN_KW */ yytestcase(yyruleno==30);
++      case 35: /* typename ::= ids */ yytestcase(yyruleno==35);
++      case 128: /* dbnm ::= DOT nm */ yytestcase(yyruleno==128);
++      case 254: /* plus_num ::= plus_opt number */ yytestcase(yyruleno==254);
++      case 255: /* minus_num ::= MINUS number */ yytestcase(yyruleno==255);
++      case 256: /* number ::= INTEGER */ yytestcase(yyruleno==256);
++      case 257: /* number ::= FLOAT */ yytestcase(yyruleno==257);
++#line 117 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy0 = yymsp[0].minor.yy0;}
++#line 1867 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 32: /* type ::= typename */
++#line 160 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteAddColumnType(pParse,&yymsp[0].minor.yy0,&yymsp[0].minor.yy0);}
++#line 1872 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 33: /* type ::= typename LP signed RP */
++#line 161 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteAddColumnType(pParse,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);}
++#line 1877 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 34: /* type ::= typename LP signed COMMA signed RP */
++#line 163 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteAddColumnType(pParse,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);}
++#line 1882 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 36: /* typename ::= typename ids */
++      case 242: /* idxitem ::= nm sortorder */ yytestcase(yyruleno==242);
++#line 166 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy0 = yymsp[-1].minor.yy0;}
++#line 1888 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 37: /* signed ::= INTEGER */
++      case 38: /* signed ::= PLUS INTEGER */ yytestcase(yyruleno==38);
++#line 168 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = atoi(yymsp[0].minor.yy0.z); }
++#line 1894 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 39: /* signed ::= MINUS INTEGER */
++#line 170 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = -atoi(yymsp[0].minor.yy0.z); }
++#line 1899 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 44: /* carg ::= DEFAULT STRING */
++      case 45: /* carg ::= DEFAULT ID */ yytestcase(yyruleno==45);
++      case 46: /* carg ::= DEFAULT INTEGER */ yytestcase(yyruleno==46);
++      case 47: /* carg ::= DEFAULT PLUS INTEGER */ yytestcase(yyruleno==47);
++      case 49: /* carg ::= DEFAULT FLOAT */ yytestcase(yyruleno==49);
++      case 50: /* carg ::= DEFAULT PLUS FLOAT */ yytestcase(yyruleno==50);
++#line 175 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteAddDefaultValue(pParse,&yymsp[0].minor.yy0,0);}
++#line 1909 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 48: /* carg ::= DEFAULT MINUS INTEGER */
++      case 51: /* carg ::= DEFAULT MINUS FLOAT */ yytestcase(yyruleno==51);
++#line 179 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteAddDefaultValue(pParse,&yymsp[0].minor.yy0,1);}
++#line 1915 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 54: /* ccons ::= NOT NULL onconf */
++#line 189 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteAddNotNull(pParse, yymsp[0].minor.yy372);}
++#line 1920 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 55: /* ccons ::= PRIMARY KEY sortorder onconf */
++#line 190 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteAddPrimaryKey(pParse,0,yymsp[0].minor.yy372);}
++#line 1925 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 56: /* ccons ::= UNIQUE onconf */
++#line 191 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteCreateIndex(pParse,0,0,0,yymsp[0].minor.yy372,0,0);}
++#line 1930 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 57: /* ccons ::= CHECK LP expr RP onconf */
++#line 192 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yy_destructor(yypParser,158,&yymsp[-2].minor);
++}
++#line 1937 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 58: /* ccons ::= REFERENCES nm idxlist_opt refargs */
++#line 194 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteCreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy320,yymsp[0].minor.yy372);}
++#line 1942 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 59: /* ccons ::= defer_subclause */
++#line 195 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteDeferForeignKey(pParse,yymsp[0].minor.yy372);}
++#line 1947 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 60: /* ccons ::= COLLATE id */
++#line 196 "ext/sqlite/libsqlite/src/parse.y"
++{
++   sqliteAddCollateType(pParse, sqliteCollateType(yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n));
++}
++#line 1954 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 61: /* refargs ::= */
++#line 206 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = OE_Restrict * 0x010101; }
++#line 1959 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 62: /* refargs ::= refargs refarg */
++#line 207 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = (yymsp[-1].minor.yy372 & yymsp[0].minor.yy407.mask) | yymsp[0].minor.yy407.value; }
++#line 1964 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 63: /* refarg ::= MATCH nm */
++#line 209 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy407.value = 0;     yygotominor.yy407.mask = 0x000000; }
++#line 1969 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 64: /* refarg ::= ON DELETE refact */
++#line 210 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy407.value = yymsp[0].minor.yy372;     yygotominor.yy407.mask = 0x0000ff; }
++#line 1974 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 65: /* refarg ::= ON UPDATE refact */
++#line 211 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy407.value = yymsp[0].minor.yy372<<8;  yygotominor.yy407.mask = 0x00ff00; }
++#line 1979 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 66: /* refarg ::= ON INSERT refact */
++#line 212 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy407.value = yymsp[0].minor.yy372<<16; yygotominor.yy407.mask = 0xff0000; }
++#line 1984 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 67: /* refact ::= SET NULL */
++#line 214 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = OE_SetNull; }
++#line 1989 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 68: /* refact ::= SET DEFAULT */
++#line 215 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = OE_SetDflt; }
++#line 1994 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 69: /* refact ::= CASCADE */
++#line 216 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = OE_Cascade; }
++#line 1999 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 70: /* refact ::= RESTRICT */
++#line 217 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = OE_Restrict; }
++#line 2004 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 71: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
++      case 72: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ yytestcase(yyruleno==72);
++      case 87: /* defer_subclause_opt ::= defer_subclause */ yytestcase(yyruleno==87);
++      case 164: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==164);
++#line 219 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy372 = yymsp[0].minor.yy372;}
++#line 2012 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 82: /* tcons ::= PRIMARY KEY LP idxlist RP onconf */
++#line 236 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteAddPrimaryKey(pParse,yymsp[-2].minor.yy320,yymsp[0].minor.yy372);}
++#line 2017 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 83: /* tcons ::= UNIQUE LP idxlist RP onconf */
++#line 238 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteCreateIndex(pParse,0,0,yymsp[-2].minor.yy320,yymsp[0].minor.yy372,0,0);}
++#line 2022 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 84: /* tcons ::= CHECK expr onconf */
++#line 239 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yy_destructor(yypParser,158,&yymsp[-1].minor);
++}
++#line 2029 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 85: /* tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt */
++#line 241 "ext/sqlite/libsqlite/src/parse.y"
++{
++    sqliteCreateForeignKey(pParse, yymsp[-6].minor.yy320, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy320, yymsp[-1].minor.yy372);
++    sqliteDeferForeignKey(pParse, yymsp[0].minor.yy372);
++}
++#line 2037 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 88: /* onconf ::= */
++      case 90: /* orconf ::= */ yytestcase(yyruleno==90);
++#line 255 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = OE_Default; }
++#line 2043 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 89: /* onconf ::= ON CONFLICT resolvetype */
++      case 91: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==91);
++#line 256 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = yymsp[0].minor.yy372; }
++#line 2049 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 92: /* resolvetype ::= ROLLBACK */
++#line 259 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = OE_Rollback; }
++#line 2054 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 93: /* resolvetype ::= ABORT */
++      case 236: /* uniqueflag ::= UNIQUE */ yytestcase(yyruleno==236);
++#line 260 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = OE_Abort; }
++#line 2060 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 94: /* resolvetype ::= FAIL */
++#line 261 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = OE_Fail; }
++#line 2065 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 95: /* resolvetype ::= IGNORE */
++#line 262 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = OE_Ignore; }
++#line 2070 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 96: /* resolvetype ::= REPLACE */
++#line 263 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = OE_Replace; }
++#line 2075 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 97: /* cmd ::= DROP TABLE nm */
++#line 267 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteDropTable(pParse,&yymsp[0].minor.yy0,0);}
++#line 2080 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 98: /* cmd ::= CREATE temp VIEW nm AS select */
++#line 271 "ext/sqlite/libsqlite/src/parse.y"
++{
++  sqliteCreateView(pParse, &yymsp[-5].minor.yy0, &yymsp[-2].minor.yy0, yymsp[0].minor.yy179, yymsp[-4].minor.yy372);
++}
++#line 2087 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 99: /* cmd ::= DROP VIEW nm */
++#line 274 "ext/sqlite/libsqlite/src/parse.y"
++{
++  sqliteDropTable(pParse, &yymsp[0].minor.yy0, 1);
++}
++#line 2094 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 100: /* cmd ::= select */
++#line 280 "ext/sqlite/libsqlite/src/parse.y"
++{
++  sqliteSelect(pParse, yymsp[0].minor.yy179, SRT_Callback, 0, 0, 0, 0);
++  sqliteSelectDelete(yymsp[0].minor.yy179);
++}
++#line 2102 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 101: /* select ::= oneselect */
++      case 125: /* seltablist_paren ::= select */ yytestcase(yyruleno==125);
++#line 290 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy179 = yymsp[0].minor.yy179;}
++#line 2108 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 102: /* select ::= select multiselect_op oneselect */
++#line 291 "ext/sqlite/libsqlite/src/parse.y"
++{
++  if( yymsp[0].minor.yy179 ){
++    yymsp[0].minor.yy179->op = yymsp[-1].minor.yy372;
++    yymsp[0].minor.yy179->pPrior = yymsp[-2].minor.yy179;
++  }
++  yygotominor.yy179 = yymsp[0].minor.yy179;
++}
++#line 2119 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 103: /* multiselect_op ::= UNION */
++#line 299 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy372 = TK_UNION;}
++#line 2124 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 104: /* multiselect_op ::= UNION ALL */
++#line 300 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy372 = TK_ALL;}
++#line 2129 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 105: /* multiselect_op ::= INTERSECT */
++#line 301 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy372 = TK_INTERSECT;}
++#line 2134 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 106: /* multiselect_op ::= EXCEPT */
++#line 302 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy372 = TK_EXCEPT;}
++#line 2139 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 107: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
++#line 304 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy179 = sqliteSelectNew(yymsp[-6].minor.yy322,yymsp[-5].minor.yy307,yymsp[-4].minor.yy242,yymsp[-3].minor.yy322,yymsp[-2].minor.yy242,yymsp[-1].minor.yy322,yymsp[-7].minor.yy372,yymsp[0].minor.yy124.limit,yymsp[0].minor.yy124.offset);
++}
++#line 2146 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 111: /* sclp ::= selcollist COMMA */
++#line 325 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy322 = yymsp[-1].minor.yy322;}
++#line 2151 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 112: /* sclp ::= */
++      case 138: /* orderby_opt ::= */ yytestcase(yyruleno==138);
++      case 148: /* groupby_opt ::= */ yytestcase(yyruleno==148);
++#line 326 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy322 = 0;}
++#line 2158 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 113: /* selcollist ::= sclp expr as */
++#line 327 "ext/sqlite/libsqlite/src/parse.y"
++{
++   yygotominor.yy322 = sqliteExprListAppend(yymsp[-2].minor.yy322,yymsp[-1].minor.yy242,yymsp[0].minor.yy0.n?&yymsp[0].minor.yy0:0);
++}
++#line 2165 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 114: /* selcollist ::= sclp STAR */
++#line 330 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy322 = sqliteExprListAppend(yymsp[-1].minor.yy322, sqliteExpr(TK_ALL, 0, 0, 0), 0);
++}
++#line 2172 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 115: /* selcollist ::= sclp nm DOT STAR */
++#line 333 "ext/sqlite/libsqlite/src/parse.y"
++{
++  Expr *pRight = sqliteExpr(TK_ALL, 0, 0, 0);
++  Expr *pLeft = sqliteExpr(TK_ID, 0, 0, &yymsp[-2].minor.yy0);
++  yygotominor.yy322 = sqliteExprListAppend(yymsp[-3].minor.yy322, sqliteExpr(TK_DOT, pLeft, pRight, 0), 0);
++}
++#line 2181 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 116: /* as ::= AS nm */
++      case 117: /* as ::= ids */ yytestcase(yyruleno==117);
++      case 288: /* key_opt ::= USING ids */ yytestcase(yyruleno==288);
++#line 343 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy0 = yymsp[0].minor.yy0; }
++#line 2188 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 118: /* as ::= */
++#line 345 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy0.n = 0; }
++#line 2193 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 119: /* from ::= */
++#line 357 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy307 = sqliteMalloc(sizeof(*yygotominor.yy307));}
++#line 2198 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 120: /* from ::= FROM seltablist */
++#line 358 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy307 = yymsp[0].minor.yy307;}
++#line 2203 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 121: /* stl_prefix ::= seltablist joinop */
++#line 363 "ext/sqlite/libsqlite/src/parse.y"
++{
++   yygotominor.yy307 = yymsp[-1].minor.yy307;
++   if( yygotominor.yy307 && yygotominor.yy307->nSrc>0 ) yygotominor.yy307->a[yygotominor.yy307->nSrc-1].jointype = yymsp[0].minor.yy372;
++}
++#line 2211 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 122: /* stl_prefix ::= */
++#line 367 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy307 = 0;}
++#line 2216 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 123: /* seltablist ::= stl_prefix nm dbnm as on_opt using_opt */
++#line 368 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy307 = sqliteSrcListAppend(yymsp[-5].minor.yy307,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0);
++  if( yymsp[-2].minor.yy0.n ) sqliteSrcListAddAlias(yygotominor.yy307,&yymsp[-2].minor.yy0);
++  if( yymsp[-1].minor.yy242 ){
++    if( yygotominor.yy307 && yygotominor.yy307->nSrc>1 ){ yygotominor.yy307->a[yygotominor.yy307->nSrc-2].pOn = yymsp[-1].minor.yy242; }
++    else { sqliteExprDelete(yymsp[-1].minor.yy242); }
++  }
++  if( yymsp[0].minor.yy320 ){
++    if( yygotominor.yy307 && yygotominor.yy307->nSrc>1 ){ yygotominor.yy307->a[yygotominor.yy307->nSrc-2].pUsing = yymsp[0].minor.yy320; }
++    else { sqliteIdListDelete(yymsp[0].minor.yy320); }
++  }
++}
++#line 2232 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 124: /* seltablist ::= stl_prefix LP seltablist_paren RP as on_opt using_opt */
++#line 381 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy307 = sqliteSrcListAppend(yymsp[-6].minor.yy307,0,0);
++  yygotominor.yy307->a[yygotominor.yy307->nSrc-1].pSelect = yymsp[-4].minor.yy179;
++  if( yymsp[-2].minor.yy0.n ) sqliteSrcListAddAlias(yygotominor.yy307,&yymsp[-2].minor.yy0);
++  if( yymsp[-1].minor.yy242 ){
++    if( yygotominor.yy307 && yygotominor.yy307->nSrc>1 ){ yygotominor.yy307->a[yygotominor.yy307->nSrc-2].pOn = yymsp[-1].minor.yy242; }
++    else { sqliteExprDelete(yymsp[-1].minor.yy242); }
++  }
++  if( yymsp[0].minor.yy320 ){
++    if( yygotominor.yy307 && yygotominor.yy307->nSrc>1 ){ yygotominor.yy307->a[yygotominor.yy307->nSrc-2].pUsing = yymsp[0].minor.yy320; }
++    else { sqliteIdListDelete(yymsp[0].minor.yy320); }
++  }
++}
++#line 2249 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 126: /* seltablist_paren ::= seltablist */
++#line 402 "ext/sqlite/libsqlite/src/parse.y"
++{
++   yygotominor.yy179 = sqliteSelectNew(0,yymsp[0].minor.yy307,0,0,0,0,0,-1,0);
++}
++#line 2256 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 127: /* dbnm ::= */
++#line 407 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy0.z=0; yygotominor.yy0.n=0;}
++#line 2261 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 129: /* joinop ::= COMMA */
++      case 130: /* joinop ::= JOIN */ yytestcase(yyruleno==130);
++#line 412 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = JT_INNER; }
++#line 2267 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 131: /* joinop ::= JOIN_KW JOIN */
++#line 414 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = sqliteJoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
++#line 2272 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 132: /* joinop ::= JOIN_KW nm JOIN */
++#line 415 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = sqliteJoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); }
++#line 2277 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 133: /* joinop ::= JOIN_KW nm nm JOIN */
++#line 417 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = sqliteJoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); }
++#line 2282 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 134: /* on_opt ::= ON expr */
++      case 142: /* sortitem ::= expr */ yytestcase(yyruleno==142);
++      case 151: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==151);
++      case 158: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==158);
++      case 227: /* case_else ::= ELSE expr */ yytestcase(yyruleno==227);
++      case 229: /* case_operand ::= expr */ yytestcase(yyruleno==229);
++      case 233: /* expritem ::= expr */ yytestcase(yyruleno==233);
++#line 421 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = yymsp[0].minor.yy242;}
++#line 2293 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 135: /* on_opt ::= */
++      case 150: /* having_opt ::= */ yytestcase(yyruleno==150);
++      case 157: /* where_opt ::= */ yytestcase(yyruleno==157);
++      case 228: /* case_else ::= */ yytestcase(yyruleno==228);
++      case 230: /* case_operand ::= */ yytestcase(yyruleno==230);
++      case 234: /* expritem ::= */ yytestcase(yyruleno==234);
++#line 422 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = 0;}
++#line 2303 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 136: /* using_opt ::= USING LP idxlist RP */
++      case 169: /* inscollist_opt ::= LP inscollist RP */ yytestcase(yyruleno==169);
++      case 239: /* idxlist_opt ::= LP idxlist RP */ yytestcase(yyruleno==239);
++#line 426 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy320 = yymsp[-1].minor.yy320;}
++#line 2310 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 137: /* using_opt ::= */
++      case 168: /* inscollist_opt ::= */ yytestcase(yyruleno==168);
++      case 238: /* idxlist_opt ::= */ yytestcase(yyruleno==238);
++#line 427 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy320 = 0;}
++#line 2317 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 139: /* orderby_opt ::= ORDER BY sortlist */
++      case 149: /* groupby_opt ::= GROUP BY exprlist */ yytestcase(yyruleno==149);
++#line 438 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy322 = yymsp[0].minor.yy322;}
++#line 2323 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 140: /* sortlist ::= sortlist COMMA sortitem collate sortorder */
++#line 439 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy322 = sqliteExprListAppend(yymsp[-4].minor.yy322,yymsp[-2].minor.yy242,0);
++  if( yygotominor.yy322 ) yygotominor.yy322->a[yygotominor.yy322->nExpr-1].sortOrder = yymsp[-1].minor.yy372+yymsp[0].minor.yy372;
++}
++#line 2331 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 141: /* sortlist ::= sortitem collate sortorder */
++#line 443 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy322 = sqliteExprListAppend(0,yymsp[-2].minor.yy242,0);
++  if( yygotominor.yy322 ) yygotominor.yy322->a[0].sortOrder = yymsp[-1].minor.yy372+yymsp[0].minor.yy372;
++}
++#line 2339 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 143: /* sortorder ::= ASC */
++      case 145: /* sortorder ::= */ yytestcase(yyruleno==145);
++#line 452 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy372 = SQLITE_SO_ASC;}
++#line 2345 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 144: /* sortorder ::= DESC */
++#line 453 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy372 = SQLITE_SO_DESC;}
++#line 2350 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 146: /* collate ::= */
++#line 455 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy372 = SQLITE_SO_UNK;}
++#line 2355 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 147: /* collate ::= COLLATE id */
++#line 456 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy372 = sqliteCollateType(yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n);}
++#line 2360 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 152: /* limit_opt ::= */
++#line 469 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy124.limit = -1; yygotominor.yy124.offset = 0;}
++#line 2365 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 153: /* limit_opt ::= LIMIT signed */
++#line 470 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy124.limit = yymsp[0].minor.yy372; yygotominor.yy124.offset = 0;}
++#line 2370 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 154: /* limit_opt ::= LIMIT signed OFFSET signed */
++#line 472 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy124.limit = yymsp[-2].minor.yy372; yygotominor.yy124.offset = yymsp[0].minor.yy372;}
++#line 2375 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 155: /* limit_opt ::= LIMIT signed COMMA signed */
++#line 474 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy124.limit = yymsp[0].minor.yy372; yygotominor.yy124.offset = yymsp[-2].minor.yy372;}
++#line 2380 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 156: /* cmd ::= DELETE FROM nm dbnm where_opt */
++#line 478 "ext/sqlite/libsqlite/src/parse.y"
++{
++   sqliteDeleteFrom(pParse, sqliteSrcListAppend(0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0), yymsp[0].minor.yy242);
++}
++#line 2387 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 159: /* cmd ::= UPDATE orconf nm dbnm SET setlist where_opt */
++#line 494 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteUpdate(pParse,sqliteSrcListAppend(0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0),yymsp[-1].minor.yy322,yymsp[0].minor.yy242,yymsp[-5].minor.yy372);}
++#line 2392 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 160: /* setlist ::= setlist COMMA nm EQ expr */
++#line 497 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy322 = sqliteExprListAppend(yymsp[-4].minor.yy322,yymsp[0].minor.yy242,&yymsp[-2].minor.yy0);}
++#line 2397 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 161: /* setlist ::= nm EQ expr */
++#line 498 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy322 = sqliteExprListAppend(0,yymsp[0].minor.yy242,&yymsp[-2].minor.yy0);}
++#line 2402 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 162: /* cmd ::= insert_cmd INTO nm dbnm inscollist_opt VALUES LP itemlist RP */
++#line 504 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteInsert(pParse, sqliteSrcListAppend(0,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0), yymsp[-1].minor.yy322, 0, yymsp[-4].minor.yy320, yymsp[-8].minor.yy372);}
++#line 2407 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 163: /* cmd ::= insert_cmd INTO nm dbnm inscollist_opt select */
++#line 506 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteInsert(pParse, sqliteSrcListAppend(0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0), 0, yymsp[0].minor.yy179, yymsp[-1].minor.yy320, yymsp[-5].minor.yy372);}
++#line 2412 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 165: /* insert_cmd ::= REPLACE */
++#line 510 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy372 = OE_Replace;}
++#line 2417 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 166: /* itemlist ::= itemlist COMMA expr */
++      case 231: /* exprlist ::= exprlist COMMA expritem */ yytestcase(yyruleno==231);
++#line 516 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy322 = sqliteExprListAppend(yymsp[-2].minor.yy322,yymsp[0].minor.yy242,0);}
++#line 2423 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 167: /* itemlist ::= expr */
++      case 232: /* exprlist ::= expritem */ yytestcase(yyruleno==232);
++#line 517 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy322 = sqliteExprListAppend(0,yymsp[0].minor.yy242,0);}
++#line 2429 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 170: /* inscollist ::= inscollist COMMA nm */
++      case 240: /* idxlist ::= idxlist COMMA idxitem */ yytestcase(yyruleno==240);
++#line 526 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy320 = sqliteIdListAppend(yymsp[-2].minor.yy320,&yymsp[0].minor.yy0);}
++#line 2435 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 171: /* inscollist ::= nm */
++      case 241: /* idxlist ::= idxitem */ yytestcase(yyruleno==241);
++#line 527 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy320 = sqliteIdListAppend(0,&yymsp[0].minor.yy0);}
++#line 2441 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 172: /* expr ::= LP expr RP */
++#line 535 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = yymsp[-1].minor.yy242; sqliteExprSpan(yygotominor.yy242,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); }
++#line 2446 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 173: /* expr ::= NULL */
++#line 536 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_NULL, 0, 0, &yymsp[0].minor.yy0);}
++#line 2451 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 174: /* expr ::= ID */
++      case 175: /* expr ::= JOIN_KW */ yytestcase(yyruleno==175);
++#line 537 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_ID, 0, 0, &yymsp[0].minor.yy0);}
++#line 2457 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 176: /* expr ::= nm DOT nm */
++#line 539 "ext/sqlite/libsqlite/src/parse.y"
++{
++  Expr *temp1 = sqliteExpr(TK_ID, 0, 0, &yymsp[-2].minor.yy0);
++  Expr *temp2 = sqliteExpr(TK_ID, 0, 0, &yymsp[0].minor.yy0);
++  yygotominor.yy242 = sqliteExpr(TK_DOT, temp1, temp2, 0);
++}
++#line 2466 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 177: /* expr ::= nm DOT nm DOT nm */
++#line 544 "ext/sqlite/libsqlite/src/parse.y"
++{
++  Expr *temp1 = sqliteExpr(TK_ID, 0, 0, &yymsp[-4].minor.yy0);
++  Expr *temp2 = sqliteExpr(TK_ID, 0, 0, &yymsp[-2].minor.yy0);
++  Expr *temp3 = sqliteExpr(TK_ID, 0, 0, &yymsp[0].minor.yy0);
++  Expr *temp4 = sqliteExpr(TK_DOT, temp2, temp3, 0);
++  yygotominor.yy242 = sqliteExpr(TK_DOT, temp1, temp4, 0);
++}
++#line 2477 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 178: /* expr ::= INTEGER */
++#line 551 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_INTEGER, 0, 0, &yymsp[0].minor.yy0);}
++#line 2482 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 179: /* expr ::= FLOAT */
++#line 552 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_FLOAT, 0, 0, &yymsp[0].minor.yy0);}
++#line 2487 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 180: /* expr ::= STRING */
++#line 553 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_STRING, 0, 0, &yymsp[0].minor.yy0);}
++#line 2492 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 181: /* expr ::= VARIABLE */
++#line 554 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_VARIABLE, 0, 0, &yymsp[0].minor.yy0);
++  if( yygotominor.yy242 ) yygotominor.yy242->iTable = ++pParse->nVar;
++}
++#line 2500 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 182: /* expr ::= ID LP exprlist RP */
++#line 558 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExprFunction(yymsp[-1].minor.yy322, &yymsp[-3].minor.yy0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
++}
++#line 2508 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 183: /* expr ::= ID LP STAR RP */
++#line 562 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExprFunction(0, &yymsp[-3].minor.yy0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
++}
++#line 2516 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 184: /* expr ::= expr AND expr */
++#line 566 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_AND, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2521 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 185: /* expr ::= expr OR expr */
++#line 567 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_OR, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2526 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 186: /* expr ::= expr LT expr */
++#line 568 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_LT, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2531 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 187: /* expr ::= expr GT expr */
++#line 569 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_GT, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2536 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 188: /* expr ::= expr LE expr */
++#line 570 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_LE, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2541 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 189: /* expr ::= expr GE expr */
++#line 571 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_GE, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2546 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 190: /* expr ::= expr NE expr */
++#line 572 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_NE, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2551 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 191: /* expr ::= expr EQ expr */
++#line 573 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_EQ, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2556 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 192: /* expr ::= expr BITAND expr */
++#line 574 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_BITAND, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2561 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 193: /* expr ::= expr BITOR expr */
++#line 575 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_BITOR, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2566 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 194: /* expr ::= expr LSHIFT expr */
++#line 576 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_LSHIFT, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2571 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 195: /* expr ::= expr RSHIFT expr */
++#line 577 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_RSHIFT, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2576 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 196: /* expr ::= expr likeop expr */
++#line 578 "ext/sqlite/libsqlite/src/parse.y"
++{
++  ExprList *pList = sqliteExprListAppend(0, yymsp[0].minor.yy242, 0);
++  pList = sqliteExprListAppend(pList, yymsp[-2].minor.yy242, 0);
++  yygotominor.yy242 = sqliteExprFunction(pList, 0);
++  if( yygotominor.yy242 ) yygotominor.yy242->op = yymsp[-1].minor.yy372;
++  sqliteExprSpan(yygotominor.yy242, &yymsp[-2].minor.yy242->span, &yymsp[0].minor.yy242->span);
++}
++#line 2587 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 197: /* expr ::= expr NOT likeop expr */
++#line 585 "ext/sqlite/libsqlite/src/parse.y"
++{
++  ExprList *pList = sqliteExprListAppend(0, yymsp[0].minor.yy242, 0);
++  pList = sqliteExprListAppend(pList, yymsp[-3].minor.yy242, 0);
++  yygotominor.yy242 = sqliteExprFunction(pList, 0);
++  if( yygotominor.yy242 ) yygotominor.yy242->op = yymsp[-1].minor.yy372;
++  yygotominor.yy242 = sqliteExpr(TK_NOT, yygotominor.yy242, 0, 0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-3].minor.yy242->span,&yymsp[0].minor.yy242->span);
++}
++#line 2599 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 198: /* likeop ::= LIKE */
++#line 594 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy372 = TK_LIKE;}
++#line 2604 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 199: /* likeop ::= GLOB */
++#line 595 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy372 = TK_GLOB;}
++#line 2609 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 200: /* expr ::= expr PLUS expr */
++#line 596 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_PLUS, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2614 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 201: /* expr ::= expr MINUS expr */
++#line 597 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_MINUS, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2619 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 202: /* expr ::= expr STAR expr */
++#line 598 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_STAR, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2624 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 203: /* expr ::= expr SLASH expr */
++#line 599 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_SLASH, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2629 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 204: /* expr ::= expr REM expr */
++#line 600 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_REM, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2634 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 205: /* expr ::= expr CONCAT expr */
++#line 601 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy242 = sqliteExpr(TK_CONCAT, yymsp[-2].minor.yy242, yymsp[0].minor.yy242, 0);}
++#line 2639 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 206: /* expr ::= expr ISNULL */
++#line 602 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_ISNULL, yymsp[-1].minor.yy242, 0, 0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-1].minor.yy242->span,&yymsp[0].minor.yy0);
++}
++#line 2647 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 207: /* expr ::= expr IS NULL */
++#line 606 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_ISNULL, yymsp[-2].minor.yy242, 0, 0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-2].minor.yy242->span,&yymsp[0].minor.yy0);
++}
++#line 2655 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 208: /* expr ::= expr NOTNULL */
++#line 610 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_NOTNULL, yymsp[-1].minor.yy242, 0, 0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-1].minor.yy242->span,&yymsp[0].minor.yy0);
++}
++#line 2663 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 209: /* expr ::= expr NOT NULL */
++#line 614 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_NOTNULL, yymsp[-2].minor.yy242, 0, 0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-2].minor.yy242->span,&yymsp[0].minor.yy0);
++}
++#line 2671 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 210: /* expr ::= expr IS NOT NULL */
++#line 618 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_NOTNULL, yymsp[-3].minor.yy242, 0, 0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-3].minor.yy242->span,&yymsp[0].minor.yy0);
++}
++#line 2679 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 211: /* expr ::= NOT expr */
++#line 622 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_NOT, yymsp[0].minor.yy242, 0, 0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy242->span);
++}
++#line 2687 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 212: /* expr ::= BITNOT expr */
++#line 626 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_BITNOT, yymsp[0].minor.yy242, 0, 0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy242->span);
++}
++#line 2695 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 213: /* expr ::= MINUS expr */
++#line 630 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_UMINUS, yymsp[0].minor.yy242, 0, 0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy242->span);
++}
++#line 2703 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 214: /* expr ::= PLUS expr */
++#line 634 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_UPLUS, yymsp[0].minor.yy242, 0, 0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy242->span);
++}
++#line 2711 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 215: /* expr ::= LP select RP */
++#line 638 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_SELECT, 0, 0, 0);
++  if( yygotominor.yy242 ) yygotominor.yy242->pSelect = yymsp[-1].minor.yy179;
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
++}
++#line 2720 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 216: /* expr ::= expr BETWEEN expr AND expr */
++#line 643 "ext/sqlite/libsqlite/src/parse.y"
++{
++  ExprList *pList = sqliteExprListAppend(0, yymsp[-2].minor.yy242, 0);
++  pList = sqliteExprListAppend(pList, yymsp[0].minor.yy242, 0);
++  yygotominor.yy242 = sqliteExpr(TK_BETWEEN, yymsp[-4].minor.yy242, 0, 0);
++  if( yygotominor.yy242 ) yygotominor.yy242->pList = pList;
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-4].minor.yy242->span,&yymsp[0].minor.yy242->span);
++}
++#line 2731 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 217: /* expr ::= expr NOT BETWEEN expr AND expr */
++#line 650 "ext/sqlite/libsqlite/src/parse.y"
++{
++  ExprList *pList = sqliteExprListAppend(0, yymsp[-2].minor.yy242, 0);
++  pList = sqliteExprListAppend(pList, yymsp[0].minor.yy242, 0);
++  yygotominor.yy242 = sqliteExpr(TK_BETWEEN, yymsp[-5].minor.yy242, 0, 0);
++  if( yygotominor.yy242 ) yygotominor.yy242->pList = pList;
++  yygotominor.yy242 = sqliteExpr(TK_NOT, yygotominor.yy242, 0, 0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-5].minor.yy242->span,&yymsp[0].minor.yy242->span);
++}
++#line 2743 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 218: /* expr ::= expr IN LP exprlist RP */
++#line 658 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_IN, yymsp[-4].minor.yy242, 0, 0);
++  if( yygotominor.yy242 ) yygotominor.yy242->pList = yymsp[-1].minor.yy322;
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-4].minor.yy242->span,&yymsp[0].minor.yy0);
++}
++#line 2752 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 219: /* expr ::= expr IN LP select RP */
++#line 663 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_IN, yymsp[-4].minor.yy242, 0, 0);
++  if( yygotominor.yy242 ) yygotominor.yy242->pSelect = yymsp[-1].minor.yy179;
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-4].minor.yy242->span,&yymsp[0].minor.yy0);
++}
++#line 2761 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 220: /* expr ::= expr NOT IN LP exprlist RP */
++#line 668 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_IN, yymsp[-5].minor.yy242, 0, 0);
++  if( yygotominor.yy242 ) yygotominor.yy242->pList = yymsp[-1].minor.yy322;
++  yygotominor.yy242 = sqliteExpr(TK_NOT, yygotominor.yy242, 0, 0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-5].minor.yy242->span,&yymsp[0].minor.yy0);
++}
++#line 2771 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 221: /* expr ::= expr NOT IN LP select RP */
++#line 674 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_IN, yymsp[-5].minor.yy242, 0, 0);
++  if( yygotominor.yy242 ) yygotominor.yy242->pSelect = yymsp[-1].minor.yy179;
++  yygotominor.yy242 = sqliteExpr(TK_NOT, yygotominor.yy242, 0, 0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-5].minor.yy242->span,&yymsp[0].minor.yy0);
++}
++#line 2781 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 222: /* expr ::= expr IN nm dbnm */
++#line 680 "ext/sqlite/libsqlite/src/parse.y"
++{
++  SrcList *pSrc = sqliteSrcListAppend(0, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);
++  yygotominor.yy242 = sqliteExpr(TK_IN, yymsp[-3].minor.yy242, 0, 0);
++  if( yygotominor.yy242 ) yygotominor.yy242->pSelect = sqliteSelectNew(0,pSrc,0,0,0,0,0,-1,0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-3].minor.yy242->span,yymsp[0].minor.yy0.z?&yymsp[0].minor.yy0:&yymsp[-1].minor.yy0);
++}
++#line 2791 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 223: /* expr ::= expr NOT IN nm dbnm */
++#line 686 "ext/sqlite/libsqlite/src/parse.y"
++{
++  SrcList *pSrc = sqliteSrcListAppend(0, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);
++  yygotominor.yy242 = sqliteExpr(TK_IN, yymsp[-4].minor.yy242, 0, 0);
++  if( yygotominor.yy242 ) yygotominor.yy242->pSelect = sqliteSelectNew(0,pSrc,0,0,0,0,0,-1,0);
++  yygotominor.yy242 = sqliteExpr(TK_NOT, yygotominor.yy242, 0, 0);
++  sqliteExprSpan(yygotominor.yy242,&yymsp[-4].minor.yy242->span,yymsp[0].minor.yy0.z?&yymsp[0].minor.yy0:&yymsp[-1].minor.yy0);
++}
++#line 2802 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 224: /* expr ::= CASE case_operand case_exprlist case_else END */
++#line 696 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_CASE, yymsp[-3].minor.yy242, yymsp[-1].minor.yy242, 0);
++  if( yygotominor.yy242 ) yygotominor.yy242->pList = yymsp[-2].minor.yy322;
++  sqliteExprSpan(yygotominor.yy242, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0);
++}
++#line 2811 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 225: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
++#line 703 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy322 = sqliteExprListAppend(yymsp[-4].minor.yy322, yymsp[-2].minor.yy242, 0);
++  yygotominor.yy322 = sqliteExprListAppend(yygotominor.yy322, yymsp[0].minor.yy242, 0);
++}
++#line 2819 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 226: /* case_exprlist ::= WHEN expr THEN expr */
++#line 707 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy322 = sqliteExprListAppend(0, yymsp[-2].minor.yy242, 0);
++  yygotominor.yy322 = sqliteExprListAppend(yygotominor.yy322, yymsp[0].minor.yy242, 0);
++}
++#line 2827 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 235: /* cmd ::= CREATE uniqueflag INDEX nm ON nm dbnm LP idxlist RP onconf */
++#line 732 "ext/sqlite/libsqlite/src/parse.y"
++{
++  SrcList *pSrc = sqliteSrcListAppend(0, &yymsp[-5].minor.yy0, &yymsp[-4].minor.yy0);
++  if( yymsp[-9].minor.yy372!=OE_None ) yymsp[-9].minor.yy372 = yymsp[0].minor.yy372;
++  if( yymsp[-9].minor.yy372==OE_Default) yymsp[-9].minor.yy372 = OE_Abort;
++  sqliteCreateIndex(pParse, &yymsp[-7].minor.yy0, pSrc, yymsp[-2].minor.yy320, yymsp[-9].minor.yy372, &yymsp[-10].minor.yy0, &yymsp[-1].minor.yy0);
++}
++#line 2837 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 237: /* uniqueflag ::= */
++#line 741 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = OE_None; }
++#line 2842 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 243: /* cmd ::= DROP INDEX nm dbnm */
++#line 758 "ext/sqlite/libsqlite/src/parse.y"
++{
++  sqliteDropIndex(pParse, sqliteSrcListAppend(0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0));
++}
++#line 2849 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 244: /* cmd ::= COPY orconf nm dbnm FROM nm USING DELIMITERS STRING */
++#line 766 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteCopy(pParse,sqliteSrcListAppend(0,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0),&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0,yymsp[-7].minor.yy372);}
++#line 2854 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 245: /* cmd ::= COPY orconf nm dbnm FROM nm */
++#line 768 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteCopy(pParse,sqliteSrcListAppend(0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0),&yymsp[0].minor.yy0,0,yymsp[-4].minor.yy372);}
++#line 2859 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 246: /* cmd ::= VACUUM */
++#line 772 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteVacuum(pParse,0);}
++#line 2864 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 247: /* cmd ::= VACUUM nm */
++#line 773 "ext/sqlite/libsqlite/src/parse.y"
++{sqliteVacuum(pParse,&yymsp[0].minor.yy0);}
++#line 2869 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 248: /* cmd ::= PRAGMA ids EQ nm */
++      case 249: /* cmd ::= PRAGMA ids EQ ON */ yytestcase(yyruleno==249);
++      case 250: /* cmd ::= PRAGMA ids EQ plus_num */ yytestcase(yyruleno==250);
++#line 777 "ext/sqlite/libsqlite/src/parse.y"
++{sqlitePragma(pParse,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
++#line 2876 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 251: /* cmd ::= PRAGMA ids EQ minus_num */
++#line 780 "ext/sqlite/libsqlite/src/parse.y"
++{sqlitePragma(pParse,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
++#line 2881 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 252: /* cmd ::= PRAGMA ids LP nm RP */
++#line 781 "ext/sqlite/libsqlite/src/parse.y"
++{sqlitePragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
++#line 2886 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 253: /* cmd ::= PRAGMA ids */
++#line 782 "ext/sqlite/libsqlite/src/parse.y"
++{sqlitePragma(pParse,&yymsp[0].minor.yy0,&yymsp[0].minor.yy0,0);}
++#line 2891 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 260: /* cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END */
++#line 792 "ext/sqlite/libsqlite/src/parse.y"
++{
++  Token all;
++  all.z = yymsp[-4].minor.yy0.z;
++  all.n = (yymsp[0].minor.yy0.z - yymsp[-4].minor.yy0.z) + yymsp[0].minor.yy0.n;
++  sqliteFinishTrigger(pParse, yymsp[-1].minor.yy19, &all);
++}
++#line 2901 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 261: /* trigger_decl ::= temp TRIGGER nm trigger_time trigger_event ON nm dbnm foreach_clause when_clause */
++#line 800 "ext/sqlite/libsqlite/src/parse.y"
++{
++  SrcList *pTab = sqliteSrcListAppend(0, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0);
++  sqliteBeginTrigger(pParse, &yymsp[-7].minor.yy0, yymsp[-6].minor.yy372, yymsp[-5].minor.yy290.a, yymsp[-5].minor.yy290.b, pTab, yymsp[-1].minor.yy372, yymsp[0].minor.yy182, yymsp[-9].minor.yy372);
++}
++#line 2909 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 262: /* trigger_time ::= BEFORE */
++      case 265: /* trigger_time ::= */ yytestcase(yyruleno==265);
++#line 806 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = TK_BEFORE; }
++#line 2915 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 263: /* trigger_time ::= AFTER */
++#line 807 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = TK_AFTER;  }
++#line 2920 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 264: /* trigger_time ::= INSTEAD OF */
++#line 808 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = TK_INSTEAD;}
++#line 2925 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 266: /* trigger_event ::= DELETE */
++#line 813 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy290.a = TK_DELETE; yygotominor.yy290.b = 0; }
++#line 2930 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 267: /* trigger_event ::= INSERT */
++#line 814 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy290.a = TK_INSERT; yygotominor.yy290.b = 0; }
++#line 2935 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 268: /* trigger_event ::= UPDATE */
++#line 815 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy290.a = TK_UPDATE; yygotominor.yy290.b = 0;}
++#line 2940 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 269: /* trigger_event ::= UPDATE OF inscollist */
++#line 816 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy290.a = TK_UPDATE; yygotominor.yy290.b = yymsp[0].minor.yy320; }
++#line 2945 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 270: /* foreach_clause ::= */
++      case 271: /* foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==271);
++#line 819 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = TK_ROW; }
++#line 2951 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 272: /* foreach_clause ::= FOR EACH STATEMENT */
++#line 821 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy372 = TK_STATEMENT; }
++#line 2956 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 273: /* when_clause ::= */
++#line 824 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy182 = 0; }
++#line 2961 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 274: /* when_clause ::= WHEN expr */
++#line 825 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy182 = yymsp[0].minor.yy242; }
++#line 2966 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 275: /* trigger_cmd_list ::= trigger_cmd SEMI trigger_cmd_list */
++#line 829 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yymsp[-2].minor.yy19->pNext = yymsp[0].minor.yy19;
++  yygotominor.yy19 = yymsp[-2].minor.yy19;
++}
++#line 2974 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 276: /* trigger_cmd_list ::= */
++#line 833 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy19 = 0; }
++#line 2979 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 277: /* trigger_cmd ::= UPDATE orconf nm SET setlist where_opt */
++#line 839 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy19 = sqliteTriggerUpdateStep(&yymsp[-3].minor.yy0, yymsp[-1].minor.yy322, yymsp[0].minor.yy242, yymsp[-4].minor.yy372); }
++#line 2984 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 278: /* trigger_cmd ::= insert_cmd INTO nm inscollist_opt VALUES LP itemlist RP */
++#line 844 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy19 = sqliteTriggerInsertStep(&yymsp[-5].minor.yy0, yymsp[-4].minor.yy320, yymsp[-1].minor.yy322, 0, yymsp[-7].minor.yy372);}
++#line 2989 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 279: /* trigger_cmd ::= insert_cmd INTO nm inscollist_opt select */
++#line 847 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy19 = sqliteTriggerInsertStep(&yymsp[-2].minor.yy0, yymsp[-1].minor.yy320, 0, yymsp[0].minor.yy179, yymsp[-4].minor.yy372);}
++#line 2994 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 280: /* trigger_cmd ::= DELETE FROM nm where_opt */
++#line 851 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy19 = sqliteTriggerDeleteStep(&yymsp[-1].minor.yy0, yymsp[0].minor.yy242);}
++#line 2999 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 281: /* trigger_cmd ::= select */
++#line 854 "ext/sqlite/libsqlite/src/parse.y"
++{yygotominor.yy19 = sqliteTriggerSelectStep(yymsp[0].minor.yy179); }
++#line 3004 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 282: /* expr ::= RAISE LP IGNORE RP */
++#line 857 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_RAISE, 0, 0, 0); 
++  yygotominor.yy242->iColumn = OE_Ignore;
++  sqliteExprSpan(yygotominor.yy242, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0);
++}
++#line 3013 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 283: /* expr ::= RAISE LP ROLLBACK COMMA nm RP */
++#line 862 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy0); 
++  yygotominor.yy242->iColumn = OE_Rollback;
++  sqliteExprSpan(yygotominor.yy242, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0);
++}
++#line 3022 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 284: /* expr ::= RAISE LP ABORT COMMA nm RP */
++#line 867 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy0); 
++  yygotominor.yy242->iColumn = OE_Abort;
++  sqliteExprSpan(yygotominor.yy242, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0);
++}
++#line 3031 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 285: /* expr ::= RAISE LP FAIL COMMA nm RP */
++#line 872 "ext/sqlite/libsqlite/src/parse.y"
++{
++  yygotominor.yy242 = sqliteExpr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy0); 
++  yygotominor.yy242->iColumn = OE_Fail;
++  sqliteExprSpan(yygotominor.yy242, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0);
++}
++#line 3040 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 286: /* cmd ::= DROP TRIGGER nm dbnm */
++#line 879 "ext/sqlite/libsqlite/src/parse.y"
++{
++  sqliteDropTrigger(pParse,sqliteSrcListAppend(0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0));
++}
++#line 3047 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 287: /* cmd ::= ATTACH database_kw_opt ids AS nm key_opt */
++#line 884 "ext/sqlite/libsqlite/src/parse.y"
++{
++  sqliteAttach(pParse, &yymsp[-3].minor.yy0, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);
++}
++#line 3054 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 289: /* key_opt ::= */
++#line 889 "ext/sqlite/libsqlite/src/parse.y"
++{ yygotominor.yy0.z = 0; yygotominor.yy0.n = 0; }
++#line 3059 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      case 292: /* cmd ::= DETACH database_kw_opt nm */
++#line 895 "ext/sqlite/libsqlite/src/parse.y"
++{
++  sqliteDetach(pParse, &yymsp[0].minor.yy0);
++}
++#line 3066 "ext/sqlite/libsqlite/src/parse.c"
++        break;
++      default:
++      /* (0) input ::= cmdlist */ yytestcase(yyruleno==0);
++      /* (1) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==1);
++      /* (2) cmdlist ::= ecmd */ yytestcase(yyruleno==2);
++      /* (3) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==3);
++      /* (4) ecmd ::= SEMI */ yytestcase(yyruleno==4);
++      /* (9) trans_opt ::= */ yytestcase(yyruleno==9);
++      /* (10) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==10);
++      /* (11) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==11);
++      /* (15) cmd ::= create_table create_table_args */ yytestcase(yyruleno==15);
++      /* (21) columnlist ::= columnlist COMMA column */ yytestcase(yyruleno==21);
++      /* (22) columnlist ::= column */ yytestcase(yyruleno==22);
++      /* (23) column ::= columnid type carglist */ yytestcase(yyruleno==23);
++      /* (31) type ::= */ yytestcase(yyruleno==31);
++      /* (40) carglist ::= carglist carg */ yytestcase(yyruleno==40);
++      /* (41) carglist ::= */ yytestcase(yyruleno==41);
++      /* (42) carg ::= CONSTRAINT nm ccons */ yytestcase(yyruleno==42);
++      /* (43) carg ::= ccons */ yytestcase(yyruleno==43);
++      /* (52) carg ::= DEFAULT NULL */ yytestcase(yyruleno==52);
++      /* (53) ccons ::= NULL onconf */ yytestcase(yyruleno==53);
++      /* (76) conslist_opt ::= */ yytestcase(yyruleno==76);
++      /* (77) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==77);
++      /* (78) conslist ::= conslist COMMA tcons */ yytestcase(yyruleno==78);
++      /* (79) conslist ::= conslist tcons */ yytestcase(yyruleno==79);
++      /* (80) conslist ::= tcons */ yytestcase(yyruleno==80);
++      /* (81) tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==81);
++      /* (258) plus_opt ::= PLUS */ yytestcase(yyruleno==258);
++      /* (259) plus_opt ::= */ yytestcase(yyruleno==259);
++      /* (290) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==290);
++      /* (291) database_kw_opt ::= */ yytestcase(yyruleno==291);
++        break;
++  };
++  yygoto = yyRuleInfo[yyruleno].lhs;
++  yysize = yyRuleInfo[yyruleno].nrhs;
++  yypParser->yyidx -= yysize;
++  yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
++  if( yyact < YYNSTATE ){
++#ifdef NDEBUG
++    /* If we are not debugging and the reduce action popped at least
++    ** one element off the stack, then we can push the new element back
++    ** onto the stack here, and skip the stack overflow test in yy_shift().
++    ** That gives a significant speed improvement. */
++    if( yysize ){
++      yypParser->yyidx++;
++      yymsp -= yysize-1;
++      yymsp->stateno = (YYACTIONTYPE)yyact;
++      yymsp->major = (YYCODETYPE)yygoto;
++      yymsp->minor = yygotominor;
++    }else
++#endif
++    {
++      yy_shift(yypParser,yyact,yygoto,&yygotominor);
++    }
++  }else{
++    assert( yyact == YYNSTATE + YYNRULE + 1 );
++    yy_accept(yypParser);
++  }
++}
++
++/*
++** The following code executes when the parse fails
++*/
++#ifndef YYNOERRORRECOVERY
++static void yy_parse_failed(
++  yyParser *yypParser           /* The parser */
++){
++  sqliteParserARG_FETCH;
++#ifndef NDEBUG
++  if( yyTraceFILE ){
++    fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
++  }
++#endif
++  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
++  /* Here code is inserted which will be executed whenever the
++  ** parser fails */
++  sqliteParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
++}
++#endif /* YYNOERRORRECOVERY */
++
++/*
++** The following code executes when a syntax error first occurs.
++*/
++static void yy_syntax_error(
++  yyParser *yypParser,           /* The parser */
++  int yymajor,                   /* The major type of the error token */
++  YYMINORTYPE yyminor            /* The minor type of the error token */
++){
++  sqliteParserARG_FETCH;
++#define TOKEN (yyminor.yy0)
++#line 23 "ext/sqlite/libsqlite/src/parse.y"
++
++  if( pParse->zErrMsg==0 ){
++    if( TOKEN.z[0] ){
++      sqliteErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
++    }else{
++      sqliteErrorMsg(pParse, "incomplete SQL statement");
++    }
++  }
++#line 3166 "ext/sqlite/libsqlite/src/parse.c"
++  sqliteParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
++}
++
++/*
++** The following is executed when the parser accepts
++*/
++static void yy_accept(
++  yyParser *yypParser           /* The parser */
++){
++  sqliteParserARG_FETCH;
++#ifndef NDEBUG
++  if( yyTraceFILE ){
++    fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
++  }
++#endif
++  while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
++  /* Here code is inserted which will be executed whenever the
++  ** parser accepts */
++  sqliteParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
++}
++
++/* The main parser program.
++** The first argument is a pointer to a structure obtained from
++** "sqliteParserAlloc" which describes the current state of the parser.
++** The second argument is the major token number.  The third is
++** the minor token.  The fourth optional argument is whatever the
++** user wants (and specified in the grammar) and is available for
++** use by the action routines.
++**
++** Inputs:
++** <ul>
++** <li> A pointer to the parser (an opaque structure.)
++** <li> The major token number.
++** <li> The minor token number.
++** <li> An option argument of a grammar-specified type.
++** </ul>
++**
++** Outputs:
++** None.
++*/
++void sqliteParser(
++  void *yyp,                   /* The parser */
++  int yymajor,                 /* The major token code number */
++  sqliteParserTOKENTYPE yyminor       /* The value for the token */
++  sqliteParserARG_PDECL               /* Optional %extra_argument parameter */
++){
++  YYMINORTYPE yyminorunion;
++  int yyact;            /* The parser action. */
++  int yyendofinput;     /* True if we are at the end of input */
++#ifdef YYERRORSYMBOL
++  int yyerrorhit = 0;   /* True if yymajor has invoked an error */
++#endif
++  yyParser *yypParser;  /* The parser */
++
++  /* (re)initialize the parser, if necessary */
++  yypParser = (yyParser*)yyp;
++  if( yypParser->yyidx<0 ){
++#if YYSTACKDEPTH<=0
++    if( yypParser->yystksz <=0 ){
++      /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/
++      yyminorunion = yyzerominor;
++      yyStackOverflow(yypParser, &yyminorunion);
++      return;
++    }
++#endif
++    yypParser->yyidx = 0;
++    yypParser->yyerrcnt = -1;
++    yypParser->yystack[0].stateno = 0;
++    yypParser->yystack[0].major = 0;
++  }
++  yyminorunion.yy0 = yyminor;
++  yyendofinput = (yymajor==0);
++  sqliteParserARG_STORE;
++
++#ifndef NDEBUG
++  if( yyTraceFILE ){
++    fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
++  }
++#endif
++
++  do{
++    yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
++    if( yyact<YYNSTATE ){
++      assert( !yyendofinput );  /* Impossible to shift the $ token */
++      yy_shift(yypParser,yyact,yymajor,&yyminorunion);
++      yypParser->yyerrcnt--;
++      yymajor = YYNOCODE;
++    }else if( yyact < YYNSTATE + YYNRULE ){
++      yy_reduce(yypParser,yyact-YYNSTATE);
++    }else{
++      assert( yyact == YY_ERROR_ACTION );
++#ifdef YYERRORSYMBOL
++      int yymx;
++#endif
++#ifndef NDEBUG
++      if( yyTraceFILE ){
++        fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
++      }
++#endif
++#ifdef YYERRORSYMBOL
++      /* A syntax error has occurred.
++      ** The response to an error depends upon whether or not the
++      ** grammar defines an error token "ERROR".  
++      **
++      ** This is what we do if the grammar does define ERROR:
++      **
++      **  * Call the %syntax_error function.
++      **
++      **  * Begin popping the stack until we enter a state where
++      **    it is legal to shift the error symbol, then shift
++      **    the error symbol.
++      **
++      **  * Set the error count to three.
++      **
++      **  * Begin accepting and shifting new tokens.  No new error
++      **    processing will occur until three tokens have been
++      **    shifted successfully.
++      **
++      */
++      if( yypParser->yyerrcnt<0 ){
++        yy_syntax_error(yypParser,yymajor,yyminorunion);
++      }
++      yymx = yypParser->yystack[yypParser->yyidx].major;
++      if( yymx==YYERRORSYMBOL || yyerrorhit ){
++#ifndef NDEBUG
++        if( yyTraceFILE ){
++          fprintf(yyTraceFILE,"%sDiscard input token %s\n",
++             yyTracePrompt,yyTokenName[yymajor]);
++        }
++#endif
++        yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion);
++        yymajor = YYNOCODE;
++      }else{
++         while(
++          yypParser->yyidx >= 0 &&
++          yymx != YYERRORSYMBOL &&
++          (yyact = yy_find_reduce_action(
++                        yypParser->yystack[yypParser->yyidx].stateno,
++                        YYERRORSYMBOL)) >= YYNSTATE
++        ){
++          yy_pop_parser_stack(yypParser);
++        }
++        if( yypParser->yyidx < 0 || yymajor==0 ){
++          yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
++          yy_parse_failed(yypParser);
++          yymajor = YYNOCODE;
++        }else if( yymx!=YYERRORSYMBOL ){
++          YYMINORTYPE u2;
++          u2.YYERRSYMDT = 0;
++          yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
++        }
++      }
++      yypParser->yyerrcnt = 3;
++      yyerrorhit = 1;
++#elif defined(YYNOERRORRECOVERY)
++      /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to
++      ** do any kind of error recovery.  Instead, simply invoke the syntax
++      ** error routine and continue going as if nothing had happened.
++      **
++      ** Applications can set this macro (for example inside %include) if
++      ** they intend to abandon the parse upon the first syntax error seen.
++      */
++      yy_syntax_error(yypParser,yymajor,yyminorunion);
++      yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
++      yymajor = YYNOCODE;
++      
++#else  /* YYERRORSYMBOL is not defined */
++      /* This is what we do if the grammar does not define ERROR:
++      **
++      **  * Report an error message, and throw away the input token.
++      **
++      **  * If the input token is $, then fail the parse.
++      **
++      ** As before, subsequent error messages are suppressed until
++      ** three input tokens have been successfully shifted.
++      */
++      if( yypParser->yyerrcnt<=0 ){
++        yy_syntax_error(yypParser,yymajor,yyminorunion);
++      }
++      yypParser->yyerrcnt = 3;
++      yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
++      if( yyendofinput ){
++        yy_parse_failed(yypParser);
++      }
++      yymajor = YYNOCODE;
++#endif
++    }
++  }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
++  return;
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/parse.h
+@@ -0,0 +1,130 @@
++#define TK_END_OF_FILE                     1
++#define TK_ILLEGAL                         2
++#define TK_SPACE                           3
++#define TK_UNCLOSED_STRING                 4
++#define TK_COMMENT                         5
++#define TK_FUNCTION                        6
++#define TK_COLUMN                          7
++#define TK_AGG_FUNCTION                    8
++#define TK_SEMI                            9
++#define TK_EXPLAIN                        10
++#define TK_BEGIN                          11
++#define TK_TRANSACTION                    12
++#define TK_COMMIT                         13
++#define TK_END                            14
++#define TK_ROLLBACK                       15
++#define TK_CREATE                         16
++#define TK_TABLE                          17
++#define TK_TEMP                           18
++#define TK_LP                             19
++#define TK_RP                             20
++#define TK_AS                             21
++#define TK_COMMA                          22
++#define TK_ID                             23
++#define TK_ABORT                          24
++#define TK_AFTER                          25
++#define TK_ASC                            26
++#define TK_ATTACH                         27
++#define TK_BEFORE                         28
++#define TK_CASCADE                        29
++#define TK_CLUSTER                        30
++#define TK_CONFLICT                       31
++#define TK_COPY                           32
++#define TK_DATABASE                       33
++#define TK_DEFERRED                       34
++#define TK_DELIMITERS                     35
++#define TK_DESC                           36
++#define TK_DETACH                         37
++#define TK_EACH                           38
++#define TK_FAIL                           39
++#define TK_FOR                            40
++#define TK_GLOB                           41
++#define TK_IGNORE                         42
++#define TK_IMMEDIATE                      43
++#define TK_INITIALLY                      44
++#define TK_INSTEAD                        45
++#define TK_LIKE                           46
++#define TK_MATCH                          47
++#define TK_KEY                            48
++#define TK_OF                             49
++#define TK_OFFSET                         50
++#define TK_PRAGMA                         51
++#define TK_RAISE                          52
++#define TK_REPLACE                        53
++#define TK_RESTRICT                       54
++#define TK_ROW                            55
++#define TK_STATEMENT                      56
++#define TK_TRIGGER                        57
++#define TK_VACUUM                         58
++#define TK_VIEW                           59
++#define TK_OR                             60
++#define TK_AND                            61
++#define TK_NOT                            62
++#define TK_EQ                             63
++#define TK_NE                             64
++#define TK_ISNULL                         65
++#define TK_NOTNULL                        66
++#define TK_IS                             67
++#define TK_BETWEEN                        68
++#define TK_IN                             69
++#define TK_GT                             70
++#define TK_GE                             71
++#define TK_LT                             72
++#define TK_LE                             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_UMINUS                         84
++#define TK_UPLUS                          85
++#define TK_BITNOT                         86
++#define TK_STRING                         87
++#define TK_JOIN_KW                        88
++#define TK_INTEGER                        89
++#define TK_CONSTRAINT                     90
++#define TK_DEFAULT                        91
++#define TK_FLOAT                          92
++#define TK_NULL                           93
++#define TK_PRIMARY                        94
++#define TK_UNIQUE                         95
++#define TK_CHECK                          96
++#define TK_REFERENCES                     97
++#define TK_COLLATE                        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_INTERSECT                      109
++#define TK_EXCEPT                         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_VARIABLE                       125
++#define TK_CASE                           126
++#define TK_WHEN                           127
++#define TK_THEN                           128
++#define TK_ELSE                           129
++#define TK_INDEX                          130
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/parse.y
+@@ -0,0 +1,897 @@
++/*
++** 2001 September 15
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This file contains SQLite's grammar for SQL.  Process this file
++** using the lemon parser generator to generate C code that runs
++** the parser.  Lemon will also generate a header file containing
++** numeric codes for all of the tokens.
++**
++** @(#) $Id$
++*/
++%token_prefix TK_
++%token_type {Token}
++%default_type {Token}
++%extra_argument {Parse *pParse}
++%syntax_error {
++  if( pParse->zErrMsg==0 ){
++    if( TOKEN.z[0] ){
++      sqliteErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
++    }else{
++      sqliteErrorMsg(pParse, "incomplete SQL statement");
++    }
++  }
++}
++%name sqliteParser
++%include {
++#include "sqliteInt.h"
++#include "parse.h"
++
++/*
++** An instance of this structure holds information about the
++** LIMIT clause of a SELECT statement.
++*/
++struct LimitVal {
++  int limit;    /* The LIMIT value.  -1 if there is no limit */
++  int offset;   /* The OFFSET.  0 if there is none */
++};
++
++/*
++** An instance of the following structure describes the event of a
++** TRIGGER.  "a" is the event type, one of TK_UPDATE, TK_INSERT,
++** TK_DELETE, or TK_INSTEAD.  If the event is of the form
++**
++**      UPDATE ON (a,b,c)
++**
++** Then the "b" IdList records the list "a,b,c".
++*/
++struct TrigEvent { int a; IdList * b; };
++
++} // end %include
++
++// These are extra tokens used by the lexer but never seen by the
++// parser.  We put them in a rule so that the parser generator will
++// add them to the parse.h output file.
++//
++%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
++          COLUMN AGG_FUNCTION.
++
++// Input is a single SQL command
++input ::= cmdlist.
++cmdlist ::= cmdlist ecmd.
++cmdlist ::= ecmd.
++ecmd ::= explain cmdx SEMI.
++ecmd ::= SEMI.
++cmdx ::= cmd.           { sqliteExec(pParse); }
++explain ::= EXPLAIN.    { sqliteBeginParse(pParse, 1); }
++explain ::= .           { sqliteBeginParse(pParse, 0); }
++
++///////////////////// Begin and end transactions. ////////////////////////////
++//
++
++cmd ::= BEGIN trans_opt onconf(R).  {sqliteBeginTransaction(pParse,R);}
++trans_opt ::= .
++trans_opt ::= TRANSACTION.
++trans_opt ::= TRANSACTION nm.
++cmd ::= COMMIT trans_opt.      {sqliteCommitTransaction(pParse);}
++cmd ::= END trans_opt.         {sqliteCommitTransaction(pParse);}
++cmd ::= ROLLBACK trans_opt.    {sqliteRollbackTransaction(pParse);}
++
++///////////////////// The CREATE TABLE statement ////////////////////////////
++//
++cmd ::= create_table create_table_args.
++create_table ::= CREATE(X) temp(T) TABLE nm(Y). {
++   sqliteStartTable(pParse,&X,&Y,T,0);
++}
++%type temp {int}
++temp(A) ::= TEMP.  {A = 1;}
++temp(A) ::= .      {A = 0;}
++create_table_args ::= LP columnlist conslist_opt RP(X). {
++  sqliteEndTable(pParse,&X,0);
++}
++create_table_args ::= AS select(S). {
++  sqliteEndTable(pParse,0,S);
++  sqliteSelectDelete(S);
++}
++columnlist ::= columnlist COMMA column.
++columnlist ::= column.
++
++// About the only information used for a column is the name of the
++// column.  The type is always just "text".  But the code will accept
++// an elaborate typename.  Perhaps someday we'll do something with it.
++//
++column ::= columnid type carglist. 
++columnid ::= nm(X).                {sqliteAddColumn(pParse,&X);}
++
++// An IDENTIFIER can be a generic identifier, or one of several
++// keywords.  Any non-standard keyword can also be an identifier.
++//
++%type id {Token}
++id(A) ::= ID(X).         {A = X;}
++
++// The following directive causes tokens ABORT, AFTER, ASC, etc. to
++// fallback to ID if they will not parse as their original value.
++// This obviates the need for the "id" nonterminal.
++//
++%fallback ID
++  ABORT AFTER ASC ATTACH BEFORE BEGIN CASCADE CLUSTER CONFLICT
++  COPY DATABASE DEFERRED DELIMITERS DESC DETACH EACH END EXPLAIN FAIL FOR
++  GLOB IGNORE IMMEDIATE INITIALLY INSTEAD LIKE MATCH KEY
++  OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
++  TEMP TRIGGER VACUUM VIEW.
++
++// Define operator precedence early so that this is the first occurance
++// of the operator tokens in the grammer.  Keeping the operators together
++// causes them to be assigned integer values that are close together,
++// which keeps parser tables smaller.
++//
++%left OR.
++%left AND.
++%right NOT.
++%left EQ NE ISNULL NOTNULL IS LIKE GLOB BETWEEN IN.
++%left GT GE LT LE.
++%left BITAND BITOR LSHIFT RSHIFT.
++%left PLUS MINUS.
++%left STAR SLASH REM.
++%left CONCAT.
++%right UMINUS UPLUS BITNOT.
++
++// And "ids" is an identifer-or-string.
++//
++%type ids {Token}
++ids(A) ::= ID(X).        {A = X;}
++ids(A) ::= STRING(X).    {A = X;}
++
++// The name of a column or table can be any of the following:
++//
++%type nm {Token}
++nm(A) ::= ID(X).         {A = X;}
++nm(A) ::= STRING(X).     {A = X;}
++nm(A) ::= JOIN_KW(X).    {A = X;}
++
++type ::= .
++type ::= typename(X).                    {sqliteAddColumnType(pParse,&X,&X);}
++type ::= typename(X) LP signed RP(Y).    {sqliteAddColumnType(pParse,&X,&Y);}
++type ::= typename(X) LP signed COMMA signed RP(Y).
++                                         {sqliteAddColumnType(pParse,&X,&Y);}
++%type typename {Token}
++typename(A) ::= ids(X).           {A = X;}
++typename(A) ::= typename(X) ids.  {A = X;}
++%type signed {int}
++signed(A) ::= INTEGER(X).         { A = atoi(X.z); }
++signed(A) ::= PLUS INTEGER(X).    { A = atoi(X.z); }
++signed(A) ::= MINUS INTEGER(X).   { A = -atoi(X.z); }
++carglist ::= carglist carg.
++carglist ::= .
++carg ::= CONSTRAINT nm ccons.
++carg ::= ccons.
++carg ::= DEFAULT STRING(X).          {sqliteAddDefaultValue(pParse,&X,0);}
++carg ::= DEFAULT ID(X).              {sqliteAddDefaultValue(pParse,&X,0);}
++carg ::= DEFAULT INTEGER(X).         {sqliteAddDefaultValue(pParse,&X,0);}
++carg ::= DEFAULT PLUS INTEGER(X).    {sqliteAddDefaultValue(pParse,&X,0);}
++carg ::= DEFAULT MINUS INTEGER(X).   {sqliteAddDefaultValue(pParse,&X,1);}
++carg ::= DEFAULT FLOAT(X).           {sqliteAddDefaultValue(pParse,&X,0);}
++carg ::= DEFAULT PLUS FLOAT(X).      {sqliteAddDefaultValue(pParse,&X,0);}
++carg ::= DEFAULT MINUS FLOAT(X).     {sqliteAddDefaultValue(pParse,&X,1);}
++carg ::= DEFAULT NULL. 
++
++// In addition to the type name, we also care about the primary key and
++// UNIQUE constraints.
++//
++ccons ::= NULL onconf.
++ccons ::= NOT NULL onconf(R).               {sqliteAddNotNull(pParse, R);}
++ccons ::= PRIMARY KEY sortorder onconf(R).  {sqliteAddPrimaryKey(pParse,0,R);}
++ccons ::= UNIQUE onconf(R).           {sqliteCreateIndex(pParse,0,0,0,R,0,0);}
++ccons ::= CHECK LP expr RP onconf.
++ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
++                                {sqliteCreateForeignKey(pParse,0,&T,TA,R);}
++ccons ::= defer_subclause(D).   {sqliteDeferForeignKey(pParse,D);}
++ccons ::= COLLATE id(C).  {
++   sqliteAddCollateType(pParse, sqliteCollateType(C.z, C.n));
++}
++
++// The next group of rules parses the arguments to a REFERENCES clause
++// that determine if the referential integrity checking is deferred or
++// or immediate and which determine what action to take if a ref-integ
++// check fails.
++//
++%type refargs {int}
++refargs(A) ::= .                     { A = OE_Restrict * 0x010101; }
++refargs(A) ::= refargs(X) refarg(Y). { A = (X & Y.mask) | Y.value; }
++%type refarg {struct {int value; int mask;}}
++refarg(A) ::= MATCH nm.              { A.value = 0;     A.mask = 0x000000; }
++refarg(A) ::= ON DELETE refact(X).   { A.value = X;     A.mask = 0x0000ff; }
++refarg(A) ::= ON UPDATE refact(X).   { A.value = X<<8;  A.mask = 0x00ff00; }
++refarg(A) ::= ON INSERT refact(X).   { A.value = X<<16; A.mask = 0xff0000; }
++%type refact {int}
++refact(A) ::= SET NULL.              { A = OE_SetNull; }
++refact(A) ::= SET DEFAULT.           { A = OE_SetDflt; }
++refact(A) ::= CASCADE.               { A = OE_Cascade; }
++refact(A) ::= RESTRICT.              { A = OE_Restrict; }
++%type defer_subclause {int}
++defer_subclause(A) ::= NOT DEFERRABLE init_deferred_pred_opt(X).  {A = X;}
++defer_subclause(A) ::= DEFERRABLE init_deferred_pred_opt(X).      {A = X;}
++%type init_deferred_pred_opt {int}
++init_deferred_pred_opt(A) ::= .                       {A = 0;}
++init_deferred_pred_opt(A) ::= INITIALLY DEFERRED.     {A = 1;}
++init_deferred_pred_opt(A) ::= INITIALLY IMMEDIATE.    {A = 0;}
++
++// For the time being, the only constraint we care about is the primary
++// key and UNIQUE.  Both create indices.
++//
++conslist_opt ::= .
++conslist_opt ::= COMMA conslist.
++conslist ::= conslist COMMA tcons.
++conslist ::= conslist tcons.
++conslist ::= tcons.
++tcons ::= CONSTRAINT nm.
++tcons ::= PRIMARY KEY LP idxlist(X) RP onconf(R).
++                                             {sqliteAddPrimaryKey(pParse,X,R);}
++tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
++                                       {sqliteCreateIndex(pParse,0,0,X,R,0,0);}
++tcons ::= CHECK expr onconf.
++tcons ::= FOREIGN KEY LP idxlist(FA) RP
++          REFERENCES nm(T) idxlist_opt(TA) refargs(R) defer_subclause_opt(D). {
++    sqliteCreateForeignKey(pParse, FA, &T, TA, R);
++    sqliteDeferForeignKey(pParse, D);
++}
++%type defer_subclause_opt {int}
++defer_subclause_opt(A) ::= .                    {A = 0;}
++defer_subclause_opt(A) ::= defer_subclause(X).  {A = X;}
++
++// The following is a non-standard extension that allows us to declare the
++// default behavior when there is a constraint conflict.
++//
++%type onconf {int}
++%type orconf {int}
++%type resolvetype {int}
++onconf(A) ::= .                              { A = OE_Default; }
++onconf(A) ::= ON CONFLICT resolvetype(X).    { A = X; }
++orconf(A) ::= .                              { A = OE_Default; }
++orconf(A) ::= OR resolvetype(X).             { A = X; }
++resolvetype(A) ::= ROLLBACK.                 { A = OE_Rollback; }
++resolvetype(A) ::= ABORT.                    { A = OE_Abort; }
++resolvetype(A) ::= FAIL.                     { A = OE_Fail; }
++resolvetype(A) ::= IGNORE.                   { A = OE_Ignore; }
++resolvetype(A) ::= REPLACE.                  { A = OE_Replace; }
++
++////////////////////////// The DROP TABLE /////////////////////////////////////
++//
++cmd ::= DROP TABLE nm(X).          {sqliteDropTable(pParse,&X,0);}
++
++///////////////////// The CREATE VIEW statement /////////////////////////////
++//
++cmd ::= CREATE(X) temp(T) VIEW nm(Y) AS select(S). {
++  sqliteCreateView(pParse, &X, &Y, S, T);
++}
++cmd ::= DROP VIEW nm(X). {
++  sqliteDropTable(pParse, &X, 1);
++}
++
++//////////////////////// The SELECT statement /////////////////////////////////
++//
++cmd ::= select(X).  {
++  sqliteSelect(pParse, X, SRT_Callback, 0, 0, 0, 0);
++  sqliteSelectDelete(X);
++}
++
++%type select {Select*}
++%destructor select {sqliteSelectDelete($$);}
++%type oneselect {Select*}
++%destructor oneselect {sqliteSelectDelete($$);}
++
++select(A) ::= oneselect(X).                      {A = X;}
++select(A) ::= select(X) multiselect_op(Y) oneselect(Z).  {
++  if( Z ){
++    Z->op = Y;
++    Z->pPrior = X;
++  }
++  A = Z;
++}
++%type multiselect_op {int}
++multiselect_op(A) ::= UNION.      {A = TK_UNION;}
++multiselect_op(A) ::= UNION ALL.  {A = TK_ALL;}
++multiselect_op(A) ::= INTERSECT.  {A = TK_INTERSECT;}
++multiselect_op(A) ::= EXCEPT.     {A = TK_EXCEPT;}
++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 = sqliteSelectNew(W,X,Y,P,Q,Z,D,L.limit,L.offset);
++}
++
++// The "distinct" nonterminal is true (1) if the DISTINCT keyword is
++// present and false (0) if it is not.
++//
++%type distinct {int}
++distinct(A) ::= DISTINCT.   {A = 1;}
++distinct(A) ::= ALL.        {A = 0;}
++distinct(A) ::= .           {A = 0;}
++
++// selcollist is a list of expressions that are to become the return
++// values of the SELECT statement.  The "*" in statements like
++// "SELECT * FROM ..." is encoded as a special expression with an
++// opcode of TK_ALL.
++//
++%type selcollist {ExprList*}
++%destructor selcollist {sqliteExprListDelete($$);}
++%type sclp {ExprList*}
++%destructor sclp {sqliteExprListDelete($$);}
++sclp(A) ::= selcollist(X) COMMA.             {A = X;}
++sclp(A) ::= .                                {A = 0;}
++selcollist(A) ::= sclp(P) expr(X) as(Y).     {
++   A = sqliteExprListAppend(P,X,Y.n?&Y:0);
++}
++selcollist(A) ::= sclp(P) STAR. {
++  A = sqliteExprListAppend(P, sqliteExpr(TK_ALL, 0, 0, 0), 0);
++}
++selcollist(A) ::= sclp(P) nm(X) DOT STAR. {
++  Expr *pRight = sqliteExpr(TK_ALL, 0, 0, 0);
++  Expr *pLeft = sqliteExpr(TK_ID, 0, 0, &X);
++  A = sqliteExprListAppend(P, sqliteExpr(TK_DOT, pLeft, pRight, 0), 0);
++}
++
++// An option "AS <id>" phrase that can follow one of the expressions that
++// define the result set, or one of the tables in the FROM clause.
++//
++%type as {Token}
++as(X) ::= AS nm(Y).    { X = Y; }
++as(X) ::= ids(Y).      { X = Y; }
++as(X) ::= .            { X.n = 0; }
++
++
++%type seltablist {SrcList*}
++%destructor seltablist {sqliteSrcListDelete($$);}
++%type stl_prefix {SrcList*}
++%destructor stl_prefix {sqliteSrcListDelete($$);}
++%type from {SrcList*}
++%destructor from {sqliteSrcListDelete($$);}
++
++// A complete FROM clause.
++//
++from(A) ::= .                                 {A = sqliteMalloc(sizeof(*A));}
++from(A) ::= FROM seltablist(X).               {A = X;}
++
++// "seltablist" is a "Select Table List" - the content of the FROM clause
++// in a SELECT statement.  "stl_prefix" is a prefix of this list.
++//
++stl_prefix(A) ::= seltablist(X) joinop(Y).    {
++   A = X;
++   if( A && A->nSrc>0 ) A->a[A->nSrc-1].jointype = Y;
++}
++stl_prefix(A) ::= .                           {A = 0;}
++seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
++  A = sqliteSrcListAppend(X,&Y,&D);
++  if( Z.n ) sqliteSrcListAddAlias(A,&Z);
++  if( N ){
++    if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; }
++    else { sqliteExprDelete(N); }
++  }
++  if( U ){
++    if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; }
++    else { sqliteIdListDelete(U); }
++  }
++}
++seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP
++                  as(Z) on_opt(N) using_opt(U). {
++  A = sqliteSrcListAppend(X,0,0);
++  A->a[A->nSrc-1].pSelect = S;
++  if( Z.n ) sqliteSrcListAddAlias(A,&Z);
++  if( N ){
++    if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; }
++    else { sqliteExprDelete(N); }
++  }
++  if( U ){
++    if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; }
++    else { sqliteIdListDelete(U); }
++  }
++}
++
++// A seltablist_paren nonterminal represents anything in a FROM that
++// is contained inside parentheses.  This can be either a subquery or
++// a grouping of table and subqueries.
++//
++%type seltablist_paren {Select*}
++%destructor seltablist_paren {sqliteSelectDelete($$);}
++seltablist_paren(A) ::= select(S).      {A = S;}
++seltablist_paren(A) ::= seltablist(F).  {
++   A = sqliteSelectNew(0,F,0,0,0,0,0,-1,0);
++}
++
++%type dbnm {Token}
++dbnm(A) ::= .          {A.z=0; A.n=0;}
++dbnm(A) ::= DOT nm(X). {A = X;}
++
++%type joinop {int}
++%type joinop2 {int}
++joinop(X) ::= COMMA.                   { X = JT_INNER; }
++joinop(X) ::= JOIN.                    { X = JT_INNER; }
++joinop(X) ::= JOIN_KW(A) JOIN.         { X = sqliteJoinType(pParse,&A,0,0); }
++joinop(X) ::= JOIN_KW(A) nm(B) JOIN.   { X = sqliteJoinType(pParse,&A,&B,0); }
++joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN.
++                                       { X = sqliteJoinType(pParse,&A,&B,&C); }
++
++%type on_opt {Expr*}
++%destructor on_opt {sqliteExprDelete($$);}
++on_opt(N) ::= ON expr(E).   {N = E;}
++on_opt(N) ::= .             {N = 0;}
++
++%type using_opt {IdList*}
++%destructor using_opt {sqliteIdListDelete($$);}
++using_opt(U) ::= USING LP idxlist(L) RP.  {U = L;}
++using_opt(U) ::= .                        {U = 0;}
++
++
++%type orderby_opt {ExprList*}
++%destructor orderby_opt {sqliteExprListDelete($$);}
++%type sortlist {ExprList*}
++%destructor sortlist {sqliteExprListDelete($$);}
++%type sortitem {Expr*}
++%destructor sortitem {sqliteExprDelete($$);}
++
++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 = sqliteExprListAppend(X,Y,0);
++  if( A ) A->a[A->nExpr-1].sortOrder = C+Z;
++}
++sortlist(A) ::= sortitem(Y) collate(C) sortorder(Z). {
++  A = sqliteExprListAppend(0,Y,0);
++  if( A ) A->a[0].sortOrder = C+Z;
++}
++sortitem(A) ::= expr(X).   {A = X;}
++
++%type sortorder {int}
++%type collate {int}
++
++sortorder(A) ::= ASC.           {A = SQLITE_SO_ASC;}
++sortorder(A) ::= DESC.          {A = SQLITE_SO_DESC;}
++sortorder(A) ::= .              {A = SQLITE_SO_ASC;}
++collate(C) ::= .                {C = SQLITE_SO_UNK;}
++collate(C) ::= COLLATE id(X).   {C = sqliteCollateType(X.z, X.n);}
++
++%type groupby_opt {ExprList*}
++%destructor groupby_opt {sqliteExprListDelete($$);}
++groupby_opt(A) ::= .                      {A = 0;}
++groupby_opt(A) ::= GROUP BY exprlist(X).  {A = X;}
++
++%type having_opt {Expr*}
++%destructor having_opt {sqliteExprDelete($$);}
++having_opt(A) ::= .                {A = 0;}
++having_opt(A) ::= HAVING expr(X).  {A = X;}
++
++%type limit_opt {struct LimitVal}
++limit_opt(A) ::= .                     {A.limit = -1; A.offset = 0;}
++limit_opt(A) ::= LIMIT signed(X).      {A.limit = X; A.offset = 0;}
++limit_opt(A) ::= LIMIT signed(X) OFFSET signed(Y). 
++                                       {A.limit = X; A.offset = Y;}
++limit_opt(A) ::= LIMIT signed(X) COMMA signed(Y). 
++                                       {A.limit = Y; A.offset = X;}
++
++/////////////////////////// The DELETE statement /////////////////////////////
++//
++cmd ::= DELETE FROM nm(X) dbnm(D) where_opt(Y). {
++   sqliteDeleteFrom(pParse, sqliteSrcListAppend(0,&X,&D), Y);
++}
++
++%type where_opt {Expr*}
++%destructor where_opt {sqliteExprDelete($$);}
++
++where_opt(A) ::= .                    {A = 0;}
++where_opt(A) ::= WHERE expr(X).       {A = X;}
++
++%type setlist {ExprList*}
++%destructor setlist {sqliteExprListDelete($$);}
++
++////////////////////////// The UPDATE command ////////////////////////////////
++//
++cmd ::= UPDATE orconf(R) nm(X) dbnm(D) SET setlist(Y) where_opt(Z).
++    {sqliteUpdate(pParse,sqliteSrcListAppend(0,&X,&D),Y,Z,R);}
++
++setlist(A) ::= setlist(Z) COMMA nm(X) EQ expr(Y).
++    {A = sqliteExprListAppend(Z,Y,&X);}
++setlist(A) ::= nm(X) EQ expr(Y).   {A = sqliteExprListAppend(0,Y,&X);}
++
++////////////////////////// The INSERT command /////////////////////////////////
++//
++cmd ::= insert_cmd(R) INTO nm(X) dbnm(D) inscollist_opt(F) 
++        VALUES LP itemlist(Y) RP.
++            {sqliteInsert(pParse, sqliteSrcListAppend(0,&X,&D), Y, 0, F, R);}
++cmd ::= insert_cmd(R) INTO nm(X) dbnm(D) inscollist_opt(F) select(S).
++            {sqliteInsert(pParse, sqliteSrcListAppend(0,&X,&D), 0, S, F, R);}
++
++%type insert_cmd {int}
++insert_cmd(A) ::= INSERT orconf(R).   {A = R;}
++insert_cmd(A) ::= REPLACE.            {A = OE_Replace;}
++
++
++%type itemlist {ExprList*}
++%destructor itemlist {sqliteExprListDelete($$);}
++
++itemlist(A) ::= itemlist(X) COMMA expr(Y).  {A = sqliteExprListAppend(X,Y,0);}
++itemlist(A) ::= expr(X).                    {A = sqliteExprListAppend(0,X,0);}
++
++%type inscollist_opt {IdList*}
++%destructor inscollist_opt {sqliteIdListDelete($$);}
++%type inscollist {IdList*}
++%destructor inscollist {sqliteIdListDelete($$);}
++
++inscollist_opt(A) ::= .                       {A = 0;}
++inscollist_opt(A) ::= LP inscollist(X) RP.    {A = X;}
++inscollist(A) ::= inscollist(X) COMMA nm(Y).  {A = sqliteIdListAppend(X,&Y);}
++inscollist(A) ::= nm(Y).                      {A = sqliteIdListAppend(0,&Y);}
++
++/////////////////////////// Expression Processing /////////////////////////////
++//
++
++%type expr {Expr*}
++%destructor expr {sqliteExprDelete($$);}
++
++expr(A) ::= LP(B) expr(X) RP(E). {A = X; sqliteExprSpan(A,&B,&E); }
++expr(A) ::= NULL(X).             {A = sqliteExpr(TK_NULL, 0, 0, &X);}
++expr(A) ::= ID(X).               {A = sqliteExpr(TK_ID, 0, 0, &X);}
++expr(A) ::= JOIN_KW(X).          {A = sqliteExpr(TK_ID, 0, 0, &X);}
++expr(A) ::= nm(X) DOT nm(Y). {
++  Expr *temp1 = sqliteExpr(TK_ID, 0, 0, &X);
++  Expr *temp2 = sqliteExpr(TK_ID, 0, 0, &Y);
++  A = sqliteExpr(TK_DOT, temp1, temp2, 0);
++}
++expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
++  Expr *temp1 = sqliteExpr(TK_ID, 0, 0, &X);
++  Expr *temp2 = sqliteExpr(TK_ID, 0, 0, &Y);
++  Expr *temp3 = sqliteExpr(TK_ID, 0, 0, &Z);
++  Expr *temp4 = sqliteExpr(TK_DOT, temp2, temp3, 0);
++  A = sqliteExpr(TK_DOT, temp1, temp4, 0);
++}
++expr(A) ::= INTEGER(X).      {A = sqliteExpr(TK_INTEGER, 0, 0, &X);}
++expr(A) ::= FLOAT(X).        {A = sqliteExpr(TK_FLOAT, 0, 0, &X);}
++expr(A) ::= STRING(X).       {A = sqliteExpr(TK_STRING, 0, 0, &X);}
++expr(A) ::= VARIABLE(X).     {
++  A = sqliteExpr(TK_VARIABLE, 0, 0, &X);
++  if( A ) A->iTable = ++pParse->nVar;
++}
++expr(A) ::= ID(X) LP exprlist(Y) RP(E). {
++  A = sqliteExprFunction(Y, &X);
++  sqliteExprSpan(A,&X,&E);
++}
++expr(A) ::= ID(X) LP STAR RP(E). {
++  A = sqliteExprFunction(0, &X);
++  sqliteExprSpan(A,&X,&E);
++}
++expr(A) ::= expr(X) AND expr(Y).   {A = sqliteExpr(TK_AND, X, Y, 0);}
++expr(A) ::= expr(X) OR expr(Y).    {A = sqliteExpr(TK_OR, X, Y, 0);}
++expr(A) ::= expr(X) LT expr(Y).    {A = sqliteExpr(TK_LT, X, Y, 0);}
++expr(A) ::= expr(X) GT expr(Y).    {A = sqliteExpr(TK_GT, X, Y, 0);}
++expr(A) ::= expr(X) LE expr(Y).    {A = sqliteExpr(TK_LE, X, Y, 0);}
++expr(A) ::= expr(X) GE expr(Y).    {A = sqliteExpr(TK_GE, X, Y, 0);}
++expr(A) ::= expr(X) NE expr(Y).    {A = sqliteExpr(TK_NE, X, Y, 0);}
++expr(A) ::= expr(X) EQ expr(Y).    {A = sqliteExpr(TK_EQ, X, Y, 0);}
++expr(A) ::= expr(X) BITAND expr(Y). {A = sqliteExpr(TK_BITAND, X, Y, 0);}
++expr(A) ::= expr(X) BITOR expr(Y).  {A = sqliteExpr(TK_BITOR, X, Y, 0);}
++expr(A) ::= expr(X) LSHIFT expr(Y). {A = sqliteExpr(TK_LSHIFT, X, Y, 0);}
++expr(A) ::= expr(X) RSHIFT expr(Y). {A = sqliteExpr(TK_RSHIFT, X, Y, 0);}
++expr(A) ::= expr(X) likeop(OP) expr(Y).  [LIKE]  {
++  ExprList *pList = sqliteExprListAppend(0, Y, 0);
++  pList = sqliteExprListAppend(pList, X, 0);
++  A = sqliteExprFunction(pList, 0);
++  if( A ) A->op = OP;
++  sqliteExprSpan(A, &X->span, &Y->span);
++}
++expr(A) ::= expr(X) NOT likeop(OP) expr(Y). [LIKE] {
++  ExprList *pList = sqliteExprListAppend(0, Y, 0);
++  pList = sqliteExprListAppend(pList, X, 0);
++  A = sqliteExprFunction(pList, 0);
++  if( A ) A->op = OP;
++  A = sqliteExpr(TK_NOT, A, 0, 0);
++  sqliteExprSpan(A,&X->span,&Y->span);
++}
++%type likeop {int}
++likeop(A) ::= LIKE. {A = TK_LIKE;}
++likeop(A) ::= GLOB. {A = TK_GLOB;}
++expr(A) ::= expr(X) PLUS expr(Y).  {A = sqliteExpr(TK_PLUS, X, Y, 0);}
++expr(A) ::= expr(X) MINUS expr(Y). {A = sqliteExpr(TK_MINUS, X, Y, 0);}
++expr(A) ::= expr(X) STAR expr(Y).  {A = sqliteExpr(TK_STAR, X, Y, 0);}
++expr(A) ::= expr(X) SLASH expr(Y). {A = sqliteExpr(TK_SLASH, X, Y, 0);}
++expr(A) ::= expr(X) REM expr(Y).   {A = sqliteExpr(TK_REM, X, Y, 0);}
++expr(A) ::= expr(X) CONCAT expr(Y). {A = sqliteExpr(TK_CONCAT, X, Y, 0);}
++expr(A) ::= expr(X) ISNULL(E). {
++  A = sqliteExpr(TK_ISNULL, X, 0, 0);
++  sqliteExprSpan(A,&X->span,&E);
++}
++expr(A) ::= expr(X) IS NULL(E). {
++  A = sqliteExpr(TK_ISNULL, X, 0, 0);
++  sqliteExprSpan(A,&X->span,&E);
++}
++expr(A) ::= expr(X) NOTNULL(E). {
++  A = sqliteExpr(TK_NOTNULL, X, 0, 0);
++  sqliteExprSpan(A,&X->span,&E);
++}
++expr(A) ::= expr(X) NOT NULL(E). {
++  A = sqliteExpr(TK_NOTNULL, X, 0, 0);
++  sqliteExprSpan(A,&X->span,&E);
++}
++expr(A) ::= expr(X) IS NOT NULL(E). {
++  A = sqliteExpr(TK_NOTNULL, X, 0, 0);
++  sqliteExprSpan(A,&X->span,&E);
++}
++expr(A) ::= NOT(B) expr(X). {
++  A = sqliteExpr(TK_NOT, X, 0, 0);
++  sqliteExprSpan(A,&B,&X->span);
++}
++expr(A) ::= BITNOT(B) expr(X). {
++  A = sqliteExpr(TK_BITNOT, X, 0, 0);
++  sqliteExprSpan(A,&B,&X->span);
++}
++expr(A) ::= MINUS(B) expr(X). [UMINUS] {
++  A = sqliteExpr(TK_UMINUS, X, 0, 0);
++  sqliteExprSpan(A,&B,&X->span);
++}
++expr(A) ::= PLUS(B) expr(X). [UPLUS] {
++  A = sqliteExpr(TK_UPLUS, X, 0, 0);
++  sqliteExprSpan(A,&B,&X->span);
++}
++expr(A) ::= LP(B) select(X) RP(E). {
++  A = sqliteExpr(TK_SELECT, 0, 0, 0);
++  if( A ) A->pSelect = X;
++  sqliteExprSpan(A,&B,&E);
++}
++expr(A) ::= expr(W) BETWEEN expr(X) AND expr(Y). {
++  ExprList *pList = sqliteExprListAppend(0, X, 0);
++  pList = sqliteExprListAppend(pList, Y, 0);
++  A = sqliteExpr(TK_BETWEEN, W, 0, 0);
++  if( A ) A->pList = pList;
++  sqliteExprSpan(A,&W->span,&Y->span);
++}
++expr(A) ::= expr(W) NOT BETWEEN expr(X) AND expr(Y). {
++  ExprList *pList = sqliteExprListAppend(0, X, 0);
++  pList = sqliteExprListAppend(pList, Y, 0);
++  A = sqliteExpr(TK_BETWEEN, W, 0, 0);
++  if( A ) A->pList = pList;
++  A = sqliteExpr(TK_NOT, A, 0, 0);
++  sqliteExprSpan(A,&W->span,&Y->span);
++}
++expr(A) ::= expr(X) IN LP exprlist(Y) RP(E).  {
++  A = sqliteExpr(TK_IN, X, 0, 0);
++  if( A ) A->pList = Y;
++  sqliteExprSpan(A,&X->span,&E);
++}
++expr(A) ::= expr(X) IN LP select(Y) RP(E).  {
++  A = sqliteExpr(TK_IN, X, 0, 0);
++  if( A ) A->pSelect = Y;
++  sqliteExprSpan(A,&X->span,&E);
++}
++expr(A) ::= expr(X) NOT IN LP exprlist(Y) RP(E).  {
++  A = sqliteExpr(TK_IN, X, 0, 0);
++  if( A ) A->pList = Y;
++  A = sqliteExpr(TK_NOT, A, 0, 0);
++  sqliteExprSpan(A,&X->span,&E);
++}
++expr(A) ::= expr(X) NOT IN LP select(Y) RP(E).  {
++  A = sqliteExpr(TK_IN, X, 0, 0);
++  if( A ) A->pSelect = Y;
++  A = sqliteExpr(TK_NOT, A, 0, 0);
++  sqliteExprSpan(A,&X->span,&E);
++}
++expr(A) ::= expr(X) IN nm(Y) dbnm(D). {
++  SrcList *pSrc = sqliteSrcListAppend(0, &Y, &D);
++  A = sqliteExpr(TK_IN, X, 0, 0);
++  if( A ) A->pSelect = sqliteSelectNew(0,pSrc,0,0,0,0,0,-1,0);
++  sqliteExprSpan(A,&X->span,D.z?&D:&Y);
++}
++expr(A) ::= expr(X) NOT IN nm(Y) dbnm(D). {
++  SrcList *pSrc = sqliteSrcListAppend(0, &Y, &D);
++  A = sqliteExpr(TK_IN, X, 0, 0);
++  if( A ) A->pSelect = sqliteSelectNew(0,pSrc,0,0,0,0,0,-1,0);
++  A = sqliteExpr(TK_NOT, A, 0, 0);
++  sqliteExprSpan(A,&X->span,D.z?&D:&Y);
++}
++
++
++/* CASE expressions */
++expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
++  A = sqliteExpr(TK_CASE, X, Z, 0);
++  if( A ) A->pList = Y;
++  sqliteExprSpan(A, &C, &E);
++}
++%type case_exprlist {ExprList*}
++%destructor case_exprlist {sqliteExprListDelete($$);}
++case_exprlist(A) ::= case_exprlist(X) WHEN expr(Y) THEN expr(Z). {
++  A = sqliteExprListAppend(X, Y, 0);
++  A = sqliteExprListAppend(A, Z, 0);
++}
++case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). {
++  A = sqliteExprListAppend(0, Y, 0);
++  A = sqliteExprListAppend(A, Z, 0);
++}
++%type case_else {Expr*}
++case_else(A) ::=  ELSE expr(X).         {A = X;}
++case_else(A) ::=  .                     {A = 0;} 
++%type case_operand {Expr*}
++case_operand(A) ::= expr(X).            {A = X;} 
++case_operand(A) ::= .                   {A = 0;} 
++
++%type exprlist {ExprList*}
++%destructor exprlist {sqliteExprListDelete($$);}
++%type expritem {Expr*}
++%destructor expritem {sqliteExprDelete($$);}
++
++exprlist(A) ::= exprlist(X) COMMA expritem(Y). 
++   {A = sqliteExprListAppend(X,Y,0);}
++exprlist(A) ::= expritem(X).            {A = sqliteExprListAppend(0,X,0);}
++expritem(A) ::= expr(X).                {A = X;}
++expritem(A) ::= .                       {A = 0;}
++
++///////////////////////////// The CREATE INDEX command ///////////////////////
++//
++cmd ::= CREATE(S) uniqueflag(U) INDEX nm(X)
++        ON nm(Y) dbnm(D) LP idxlist(Z) RP(E) onconf(R). {
++  SrcList *pSrc = sqliteSrcListAppend(0, &Y, &D);
++  if( U!=OE_None ) U = R;
++  if( U==OE_Default) U = OE_Abort;
++  sqliteCreateIndex(pParse, &X, pSrc, Z, U, &S, &E);
++}
++
++%type uniqueflag {int}
++uniqueflag(A) ::= UNIQUE.  { A = OE_Abort; }
++uniqueflag(A) ::= .        { A = OE_None; }
++
++%type idxlist {IdList*}
++%destructor idxlist {sqliteIdListDelete($$);}
++%type idxlist_opt {IdList*}
++%destructor idxlist_opt {sqliteIdListDelete($$);}
++%type idxitem {Token}
++
++idxlist_opt(A) ::= .                         {A = 0;}
++idxlist_opt(A) ::= LP idxlist(X) RP.         {A = X;}
++idxlist(A) ::= idxlist(X) COMMA idxitem(Y).  {A = sqliteIdListAppend(X,&Y);}
++idxlist(A) ::= idxitem(Y).                   {A = sqliteIdListAppend(0,&Y);}
++idxitem(A) ::= nm(X) sortorder.              {A = X;}
++
++///////////////////////////// The DROP INDEX command /////////////////////////
++//
++
++cmd ::= DROP INDEX nm(X) dbnm(Y).   {
++  sqliteDropIndex(pParse, sqliteSrcListAppend(0,&X,&Y));
++}
++
++
++///////////////////////////// The COPY command ///////////////////////////////
++//
++cmd ::= COPY orconf(R) nm(X) dbnm(D) FROM nm(Y) USING DELIMITERS STRING(Z).
++    {sqliteCopy(pParse,sqliteSrcListAppend(0,&X,&D),&Y,&Z,R);}
++cmd ::= COPY orconf(R) nm(X) dbnm(D) FROM nm(Y).
++    {sqliteCopy(pParse,sqliteSrcListAppend(0,&X,&D),&Y,0,R);}
++
++///////////////////////////// The VACUUM command /////////////////////////////
++//
++cmd ::= VACUUM.                {sqliteVacuum(pParse,0);}
++cmd ::= VACUUM nm(X).         {sqliteVacuum(pParse,&X);}
++
++///////////////////////////// The PRAGMA command /////////////////////////////
++//
++cmd ::= PRAGMA ids(X) EQ nm(Y).         {sqlitePragma(pParse,&X,&Y,0);}
++cmd ::= PRAGMA ids(X) EQ ON(Y).          {sqlitePragma(pParse,&X,&Y,0);}
++cmd ::= PRAGMA ids(X) EQ plus_num(Y).    {sqlitePragma(pParse,&X,&Y,0);}
++cmd ::= PRAGMA ids(X) EQ minus_num(Y).   {sqlitePragma(pParse,&X,&Y,1);}
++cmd ::= PRAGMA ids(X) LP nm(Y) RP.      {sqlitePragma(pParse,&X,&Y,0);}
++cmd ::= PRAGMA ids(X).                   {sqlitePragma(pParse,&X,&X,0);}
++plus_num(A) ::= plus_opt number(X).   {A = X;}
++minus_num(A) ::= MINUS number(X).     {A = X;}
++number(A) ::= INTEGER(X).  {A = X;}
++number(A) ::= FLOAT(X).    {A = X;}
++plus_opt ::= PLUS.
++plus_opt ::= .
++
++//////////////////////////// The CREATE TRIGGER command /////////////////////
++
++cmd ::= CREATE(A) trigger_decl BEGIN trigger_cmd_list(S) END(Z). {
++  Token all;
++  all.z = A.z;
++  all.n = (Z.z - A.z) + Z.n;
++  sqliteFinishTrigger(pParse, S, &all);
++}
++
++trigger_decl ::= temp(T) TRIGGER nm(B) trigger_time(C) trigger_event(D)
++                 ON nm(E) dbnm(DB) foreach_clause(F) when_clause(G). {
++  SrcList *pTab = sqliteSrcListAppend(0, &E, &DB);
++  sqliteBeginTrigger(pParse, &B, C, D.a, D.b, pTab, F, G, T);
++}
++
++%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;}
++trigger_time(A) ::= .            { A = TK_BEFORE; }
++
++%type trigger_event {struct TrigEvent}
++%destructor trigger_event {sqliteIdListDelete($$.b);}
++trigger_event(A) ::= DELETE. { A.a = TK_DELETE; A.b = 0; }
++trigger_event(A) ::= INSERT. { A.a = TK_INSERT; A.b = 0; }
++trigger_event(A) ::= UPDATE. { A.a = TK_UPDATE; 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; }
++
++%type when_clause {Expr *}
++when_clause(A) ::= .             { A = 0; }
++when_clause(A) ::= WHEN expr(X). { A = X; }
++
++%type trigger_cmd_list {TriggerStep *}
++%destructor trigger_cmd_list {sqliteDeleteTriggerStep($$);}
++trigger_cmd_list(A) ::= trigger_cmd(X) SEMI trigger_cmd_list(Y). {
++  X->pNext = Y;
++  A = X;
++}
++trigger_cmd_list(A) ::= . { A = 0; }
++
++%type trigger_cmd {TriggerStep *}
++%destructor trigger_cmd {sqliteDeleteTriggerStep($$);}
++// UPDATE 
++trigger_cmd(A) ::= UPDATE orconf(R) nm(X) SET setlist(Y) where_opt(Z).  
++               { A = sqliteTriggerUpdateStep(&X, Y, Z, R); }
++
++// INSERT
++trigger_cmd(A) ::= insert_cmd(R) INTO nm(X) inscollist_opt(F) 
++  VALUES LP itemlist(Y) RP.  
++{A = sqliteTriggerInsertStep(&X, F, Y, 0, R);}
++
++trigger_cmd(A) ::= insert_cmd(R) INTO nm(X) inscollist_opt(F) select(S).
++               {A = sqliteTriggerInsertStep(&X, F, 0, S, R);}
++
++// DELETE
++trigger_cmd(A) ::= DELETE FROM nm(X) where_opt(Y).
++               {A = sqliteTriggerDeleteStep(&X, Y);}
++
++// SELECT
++trigger_cmd(A) ::= select(X).  {A = sqliteTriggerSelectStep(X); }
++
++// The special RAISE expression that may occur in trigger programs
++expr(A) ::= RAISE(X) LP IGNORE RP(Y).  {
++  A = sqliteExpr(TK_RAISE, 0, 0, 0); 
++  A->iColumn = OE_Ignore;
++  sqliteExprSpan(A, &X, &Y);
++}
++expr(A) ::= RAISE(X) LP ROLLBACK COMMA nm(Z) RP(Y).  {
++  A = sqliteExpr(TK_RAISE, 0, 0, &Z); 
++  A->iColumn = OE_Rollback;
++  sqliteExprSpan(A, &X, &Y);
++}
++expr(A) ::= RAISE(X) LP ABORT COMMA nm(Z) RP(Y).  {
++  A = sqliteExpr(TK_RAISE, 0, 0, &Z); 
++  A->iColumn = OE_Abort;
++  sqliteExprSpan(A, &X, &Y);
++}
++expr(A) ::= RAISE(X) LP FAIL COMMA nm(Z) RP(Y).  {
++  A = sqliteExpr(TK_RAISE, 0, 0, &Z); 
++  A->iColumn = OE_Fail;
++  sqliteExprSpan(A, &X, &Y);
++}
++
++////////////////////////  DROP TRIGGER statement //////////////////////////////
++cmd ::= DROP TRIGGER nm(X) dbnm(D). {
++  sqliteDropTrigger(pParse,sqliteSrcListAppend(0,&X,&D));
++}
++
++//////////////////////// ATTACH DATABASE file AS name /////////////////////////
++cmd ::= ATTACH database_kw_opt ids(F) AS nm(D) key_opt(K). {
++  sqliteAttach(pParse, &F, &D, &K);
++}
++%type key_opt {Token}
++key_opt(A) ::= USING ids(X).  { A = X; }
++key_opt(A) ::= .              { A.z = 0; A.n = 0; }
++
++database_kw_opt ::= DATABASE.
++database_kw_opt ::= .
++
++//////////////////////// DETACH DATABASE name /////////////////////////////////
++cmd ::= DETACH database_kw_opt nm(D). {
++  sqliteDetach(pParse, &D);
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/pragma.c
+@@ -0,0 +1,712 @@
++/*
++** 2003 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.
++**
++*************************************************************************
++** This file contains code used to implement the PRAGMA command.
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++#include <ctype.h>
++
++/*
++** Interpret the given string as a boolean value.
++*/
++static int getBoolean(const char *z){
++  static char *azTrue[] = { "yes", "on", "true" };
++  int i;
++  if( z[0]==0 ) return 0;
++  if( isdigit(z[0]) || (z[0]=='-' && isdigit(z[1])) ){
++    return atoi(z);
++  }
++  for(i=0; i<sizeof(azTrue)/sizeof(azTrue[0]); i++){
++    if( sqliteStrICmp(z,azTrue[i])==0 ) return 1;
++  }
++  return 0;
++}
++
++/*
++** Interpret the given string as a safety level.  Return 0 for OFF,
++** 1 for ON or NORMAL and 2 for FULL.  Return 1 for an empty or 
++** unrecognized string argument.
++**
++** Note that the values returned are one less that the values that
++** should be passed into sqliteBtreeSetSafetyLevel().  The is done
++** to support legacy SQL code.  The safety level used to be boolean
++** and older scripts may have used numbers 0 for OFF and 1 for ON.
++*/
++static int getSafetyLevel(char *z){
++  static const struct {
++    const char *zWord;
++    int val;
++  } aKey[] = {
++    { "no",    0 },
++    { "off",   0 },
++    { "false", 0 },
++    { "yes",   1 },
++    { "on",    1 },
++    { "true",  1 },
++    { "full",  2 },
++  };
++  int i;
++  if( z[0]==0 ) return 1;
++  if( isdigit(z[0]) || (z[0]=='-' && isdigit(z[1])) ){
++    return atoi(z);
++  }
++  for(i=0; i<sizeof(aKey)/sizeof(aKey[0]); i++){
++    if( sqliteStrICmp(z,aKey[i].zWord)==0 ) return aKey[i].val;
++  }
++  return 1;
++}
++
++/*
++** Interpret the given string as a temp db location. Return 1 for file
++** backed temporary databases, 2 for the Red-Black tree in memory database
++** and 0 to use the compile-time default.
++*/
++static int getTempStore(const char *z){
++  if( z[0]>='0' && z[0]<='2' ){
++    return z[0] - '0';
++  }else if( sqliteStrICmp(z, "file")==0 ){
++    return 1;
++  }else if( sqliteStrICmp(z, "memory")==0 ){
++    return 2;
++  }else{
++    return 0;
++  }
++}
++
++/*
++** If the TEMP database is open, close it and mark the database schema
++** as needing reloading.  This must be done when using the TEMP_STORE
++** or DEFAULT_TEMP_STORE pragmas.
++*/
++static int changeTempStorage(Parse *pParse, const char *zStorageType){
++  int ts = getTempStore(zStorageType);
++  sqlite *db = pParse->db;
++  if( db->temp_store==ts ) return SQLITE_OK;
++  if( db->aDb[1].pBt!=0 ){
++    if( db->flags & SQLITE_InTrans ){
++      sqliteErrorMsg(pParse, "temporary storage cannot be changed "
++        "from within a transaction");
++      return SQLITE_ERROR;
++    }
++    sqliteBtreeClose(db->aDb[1].pBt);
++    db->aDb[1].pBt = 0;
++    sqliteResetInternalSchema(db, 0);
++  }
++  db->temp_store = ts;
++  return SQLITE_OK;
++}
++
++/*
++** Check to see if zRight and zLeft refer to a pragma that queries
++** or changes one of the flags in db->flags.  Return 1 if so and 0 if not.
++** Also, implement the pragma.
++*/
++static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
++  static const struct {
++    const char *zName;  /* Name of the pragma */
++    int mask;           /* Mask for the db->flags value */
++  } aPragma[] = {
++    { "vdbe_trace",               SQLITE_VdbeTrace     },
++    { "full_column_names",        SQLITE_FullColNames  },
++    { "short_column_names",       SQLITE_ShortColNames },
++    { "show_datatypes",           SQLITE_ReportTypes   },
++    { "count_changes",            SQLITE_CountRows     },
++    { "empty_result_callbacks",   SQLITE_NullCallback  },
++  };
++  int i;
++  for(i=0; i<sizeof(aPragma)/sizeof(aPragma[0]); i++){
++    if( sqliteStrICmp(zLeft, aPragma[i].zName)==0 ){
++      sqlite *db = pParse->db;
++      Vdbe *v;
++      if( strcmp(zLeft,zRight)==0 && (v = sqliteGetVdbe(pParse))!=0 ){
++        sqliteVdbeOp3(v, OP_ColumnName, 0, 1, aPragma[i].zName, P3_STATIC);
++        sqliteVdbeOp3(v, OP_ColumnName, 1, 0, "boolean", P3_STATIC);
++        sqliteVdbeCode(v, OP_Integer, (db->flags & aPragma[i].mask)!=0, 0,
++                          OP_Callback, 1, 0,
++                          0);
++      }else if( getBoolean(zRight) ){
++        db->flags |= aPragma[i].mask;
++      }else{
++        db->flags &= ~aPragma[i].mask;
++      }
++      return 1;
++    }
++  }
++  return 0;
++}
++
++/*
++** Process a pragma statement.  
++**
++** Pragmas are of this form:
++**
++**      PRAGMA id = value
++**
++** The identifier might also be a string.  The value is a string, and
++** identifier, or a number.  If minusFlag is true, then the value is
++** a number that was preceded by a minus sign.
++*/
++void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
++  char *zLeft = 0;
++  char *zRight = 0;
++  sqlite *db = pParse->db;
++  Vdbe *v = sqliteGetVdbe(pParse);
++  if( v==0 ) return;
++
++  zLeft = sqliteStrNDup(pLeft->z, pLeft->n);
++  sqliteDequote(zLeft);
++  if( minusFlag ){
++    zRight = 0;
++    sqliteSetNString(&zRight, "-", 1, pRight->z, pRight->n, 0);
++  }else{
++    zRight = sqliteStrNDup(pRight->z, pRight->n);
++    sqliteDequote(zRight);
++  }
++  if( sqliteAuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, 0) ){
++    sqliteFree(zLeft);
++    sqliteFree(zRight);
++    return;
++  }
++ 
++  /*
++  **  PRAGMA default_cache_size
++  **  PRAGMA default_cache_size=N
++  **
++  ** The first form reports the current persistent setting for the
++  ** page cache size.  The value returned is the maximum number of
++  ** pages in the page cache.  The second form sets both the current
++  ** page cache size value and the persistent page cache size value
++  ** stored in the database file.
++  **
++  ** The default cache size is stored in meta-value 2 of page 1 of the
++  ** database file.  The cache size is actually the absolute value of
++  ** this memory location.  The sign of meta-value 2 determines the
++  ** synchronous setting.  A negative value means synchronous is off
++  ** and a positive value means synchronous is on.
++  */
++  if( sqliteStrICmp(zLeft,"default_cache_size")==0 ){
++    static VdbeOpList getCacheSize[] = {
++      { OP_ReadCookie,  0, 2,        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_ColumnName,  0, 1,        "cache_size"},
++      { OP_Callback,    1, 0,        0},
++    };
++    int addr;
++    if( pRight->z==pLeft->z ){
++      addr = sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
++      sqliteVdbeChangeP1(v, addr+5, MAX_PAGES);
++    }else{
++      int size = atoi(zRight);
++      if( size<0 ) size = -size;
++      sqliteBeginWriteOperation(pParse, 0, 0);
++      sqliteVdbeAddOp(v, OP_Integer, size, 0);
++      sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
++      addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
++      sqliteVdbeAddOp(v, OP_Ge, 0, addr+3);
++      sqliteVdbeAddOp(v, OP_Negative, 0, 0);
++      sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
++      sqliteEndWriteOperation(pParse);
++      db->cache_size = db->cache_size<0 ? -size : size;
++      sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
++    }
++  }else
++
++  /*
++  **  PRAGMA cache_size
++  **  PRAGMA cache_size=N
++  **
++  ** The first form reports the current local setting for the
++  ** page cache size.  The local setting can be different from
++  ** the persistent cache size value that is stored in the database
++  ** file itself.  The value returned is the maximum number of
++  ** pages in the page cache.  The second form sets the local
++  ** page cache size value.  It does not change the persistent
++  ** cache size stored on the disk so the cache size will revert
++  ** to its default value when the database is closed and reopened.
++  ** N should be a positive integer.
++  */
++  if( sqliteStrICmp(zLeft,"cache_size")==0 ){
++    static VdbeOpList getCacheSize[] = {
++      { OP_ColumnName,  0, 1,        "cache_size"},
++      { OP_Callback,    1, 0,        0},
++    };
++    if( pRight->z==pLeft->z ){
++      int size = db->cache_size;;
++      if( size<0 ) size = -size;
++      sqliteVdbeAddOp(v, OP_Integer, size, 0);
++      sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
++    }else{
++      int size = atoi(zRight);
++      if( size<0 ) size = -size;
++      if( db->cache_size<0 ) size = -size;
++      db->cache_size = size;
++      sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
++    }
++  }else
++
++  /*
++  **  PRAGMA default_synchronous
++  **  PRAGMA default_synchronous=ON|OFF|NORMAL|FULL
++  **
++  ** The first form returns the persistent value of the "synchronous" setting
++  ** that is stored in the database.  This is the synchronous setting that
++  ** is used whenever the database is opened unless overridden by a separate
++  ** "synchronous" pragma.  The second form changes the persistent and the
++  ** local synchronous setting to the value given.
++  **
++  ** If synchronous is OFF, SQLite does not attempt any fsync() systems calls
++  ** to make sure data is committed to disk.  Write operations are very fast,
++  ** but a power failure can leave the database in an inconsistent state.
++  ** If synchronous is ON or NORMAL, SQLite will do an fsync() system call to
++  ** make sure data is being written to disk.  The risk of corruption due to
++  ** a power loss in this mode is negligible but non-zero.  If synchronous
++  ** is FULL, extra fsync()s occur to reduce the risk of corruption to near
++  ** zero, but with a write performance penalty.  The default mode is NORMAL.
++  */
++  if( sqliteStrICmp(zLeft,"default_synchronous")==0 ){
++    static VdbeOpList getSync[] = {
++      { OP_ColumnName,  0, 1,        "synchronous"},
++      { OP_ReadCookie,  0, 3,        0},
++      { OP_Dup,         0, 0,        0},
++      { OP_If,          0, 0,        0},  /* 3 */
++      { OP_ReadCookie,  0, 2,        0},
++      { OP_Integer,     0, 0,        0},
++      { OP_Lt,          0, 5,        0},
++      { OP_AddImm,      1, 0,        0},
++      { OP_Callback,    1, 0,        0},
++      { OP_Halt,        0, 0,        0},
++      { OP_AddImm,     -1, 0,        0},  /* 10 */
++      { OP_Callback,    1, 0,        0}
++    };
++    if( pRight->z==pLeft->z ){
++      int addr = sqliteVdbeAddOpList(v, ArraySize(getSync), getSync);
++      sqliteVdbeChangeP2(v, addr+3, addr+10);
++    }else{
++      int addr;
++      int size = db->cache_size;
++      if( size<0 ) size = -size;
++      sqliteBeginWriteOperation(pParse, 0, 0);
++      sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
++      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
++      addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
++      sqliteVdbeAddOp(v, OP_Ne, 0, addr+3);
++      sqliteVdbeAddOp(v, OP_AddImm, MAX_PAGES, 0);
++      sqliteVdbeAddOp(v, OP_AbsValue, 0, 0);
++      db->safety_level = getSafetyLevel(zRight)+1;
++      if( db->safety_level==1 ){
++        sqliteVdbeAddOp(v, OP_Negative, 0, 0);
++        size = -size;
++      }
++      sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
++      sqliteVdbeAddOp(v, OP_Integer, db->safety_level, 0);
++      sqliteVdbeAddOp(v, OP_SetCookie, 0, 3);
++      sqliteEndWriteOperation(pParse);
++      db->cache_size = size;
++      sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
++      sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
++    }
++  }else
++
++  /*
++  **   PRAGMA synchronous
++  **   PRAGMA synchronous=OFF|ON|NORMAL|FULL
++  **
++  ** Return or set the local value of the synchronous flag.  Changing
++  ** the local value does not make changes to the disk file and the
++  ** default value will be restored the next time the database is
++  ** opened.
++  */
++  if( sqliteStrICmp(zLeft,"synchronous")==0 ){
++    static VdbeOpList getSync[] = {
++      { OP_ColumnName,  0, 1,        "synchronous"},
++      { OP_Callback,    1, 0,        0},
++    };
++    if( pRight->z==pLeft->z ){
++      sqliteVdbeAddOp(v, OP_Integer, db->safety_level-1, 0);
++      sqliteVdbeAddOpList(v, ArraySize(getSync), getSync);
++    }else{
++      int size = db->cache_size;
++      if( size<0 ) size = -size;
++      db->safety_level = getSafetyLevel(zRight)+1;
++      if( db->safety_level==1 ) size = -size;
++      db->cache_size = size;
++      sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
++      sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
++    }
++  }else
++
++#ifndef NDEBUG
++  if( sqliteStrICmp(zLeft, "trigger_overhead_test")==0 ){
++    if( getBoolean(zRight) ){
++      always_code_trigger_setup = 1;
++    }else{
++      always_code_trigger_setup = 0;
++    }
++  }else
++#endif
++
++  if( flagPragma(pParse, zLeft, zRight) ){
++    /* The flagPragma() call also generates any necessary code */
++  }else
++
++  if( sqliteStrICmp(zLeft, "table_info")==0 ){
++    Table *pTab;
++    pTab = sqliteFindTable(db, zRight, 0);
++    if( pTab ){
++      static VdbeOpList tableInfoPreface[] = {
++        { OP_ColumnName,  0, 0,       "cid"},
++        { OP_ColumnName,  1, 0,       "name"},
++        { OP_ColumnName,  2, 0,       "type"},
++        { OP_ColumnName,  3, 0,       "notnull"},
++        { OP_ColumnName,  4, 0,       "dflt_value"},
++        { OP_ColumnName,  5, 1,       "pk"},
++      };
++      int i;
++      sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
++      sqliteViewGetColumnNames(pParse, pTab);
++      for(i=0; i<pTab->nCol; i++){
++        sqliteVdbeAddOp(v, OP_Integer, i, 0);
++        sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zName, 0);
++        sqliteVdbeOp3(v, OP_String, 0, 0,
++           pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", 0);
++        sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0);
++        sqliteVdbeOp3(v, OP_String, 0, 0,
++           pTab->aCol[i].zDflt, P3_STATIC);
++        sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].isPrimKey, 0);
++        sqliteVdbeAddOp(v, OP_Callback, 6, 0);
++      }
++    }
++  }else
++
++  if( sqliteStrICmp(zLeft, "index_info")==0 ){
++    Index *pIdx;
++    Table *pTab;
++    pIdx = sqliteFindIndex(db, zRight, 0);
++    if( pIdx ){
++      static VdbeOpList tableInfoPreface[] = {
++        { OP_ColumnName,  0, 0,       "seqno"},
++        { OP_ColumnName,  1, 0,       "cid"},
++        { OP_ColumnName,  2, 1,       "name"},
++      };
++      int i;
++      pTab = pIdx->pTable;
++      sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
++      for(i=0; i<pIdx->nColumn; i++){
++        int cnum = pIdx->aiColumn[i];
++        sqliteVdbeAddOp(v, OP_Integer, i, 0);
++        sqliteVdbeAddOp(v, OP_Integer, cnum, 0);
++        assert( pTab->nCol>cnum );
++        sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[cnum].zName, 0);
++        sqliteVdbeAddOp(v, OP_Callback, 3, 0);
++      }
++    }
++  }else
++
++  if( sqliteStrICmp(zLeft, "index_list")==0 ){
++    Index *pIdx;
++    Table *pTab;
++    pTab = sqliteFindTable(db, zRight, 0);
++    if( pTab ){
++      v = sqliteGetVdbe(pParse);
++      pIdx = pTab->pIndex;
++    }
++    if( pTab && pIdx ){
++      int i = 0; 
++      static VdbeOpList indexListPreface[] = {
++        { OP_ColumnName,  0, 0,       "seq"},
++        { OP_ColumnName,  1, 0,       "name"},
++        { OP_ColumnName,  2, 1,       "unique"},
++      };
++
++      sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
++      while(pIdx){
++        sqliteVdbeAddOp(v, OP_Integer, i, 0);
++        sqliteVdbeOp3(v, OP_String, 0, 0, pIdx->zName, 0);
++        sqliteVdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
++        sqliteVdbeAddOp(v, OP_Callback, 3, 0);
++        ++i;
++        pIdx = pIdx->pNext;
++      }
++    }
++  }else
++
++  if( sqliteStrICmp(zLeft, "foreign_key_list")==0 ){
++    FKey *pFK;
++    Table *pTab;
++    pTab = sqliteFindTable(db, zRight, 0);
++    if( pTab ){
++      v = sqliteGetVdbe(pParse);
++      pFK = pTab->pFKey;
++    }
++    if( pTab && pFK ){
++      int i = 0; 
++      static VdbeOpList indexListPreface[] = {
++        { OP_ColumnName,  0, 0,       "id"},
++        { OP_ColumnName,  1, 0,       "seq"},
++        { OP_ColumnName,  2, 0,       "table"},
++        { OP_ColumnName,  3, 0,       "from"},
++        { OP_ColumnName,  4, 1,       "to"},
++      };
++
++      sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
++      while(pFK){
++        int j;
++        for(j=0; j<pFK->nCol; j++){
++          sqliteVdbeAddOp(v, OP_Integer, i, 0);
++          sqliteVdbeAddOp(v, OP_Integer, j, 0);
++          sqliteVdbeOp3(v, OP_String, 0, 0, pFK->zTo, 0);
++          sqliteVdbeOp3(v, OP_String, 0, 0,
++                           pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
++          sqliteVdbeOp3(v, OP_String, 0, 0, pFK->aCol[j].zCol, 0);
++          sqliteVdbeAddOp(v, OP_Callback, 5, 0);
++        }
++        ++i;
++        pFK = pFK->pNextFrom;
++      }
++    }
++  }else
++
++  if( sqliteStrICmp(zLeft, "database_list")==0 ){
++    int i;
++    static VdbeOpList indexListPreface[] = {
++      { OP_ColumnName,  0, 0,       "seq"},
++      { OP_ColumnName,  1, 0,       "name"},
++      { OP_ColumnName,  2, 1,       "file"},
++    };
++
++    sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
++    for(i=0; i<db->nDb; i++){
++      if( db->aDb[i].pBt==0 ) continue;
++      assert( db->aDb[i].zName!=0 );
++      sqliteVdbeAddOp(v, OP_Integer, i, 0);
++      sqliteVdbeOp3(v, OP_String, 0, 0, db->aDb[i].zName, 0);
++      sqliteVdbeOp3(v, OP_String, 0, 0,
++           sqliteBtreeGetFilename(db->aDb[i].pBt), 0);
++      sqliteVdbeAddOp(v, OP_Callback, 3, 0);
++    }
++  }else
++
++
++  /*
++  **   PRAGMA temp_store
++  **   PRAGMA temp_store = "default"|"memory"|"file"
++  **
++  ** Return or set the local value of the temp_store flag.  Changing
++  ** the local value does not make changes to the disk file and the default
++  ** value will be restored the next time the database is opened.
++  **
++  ** Note that it is possible for the library compile-time options to
++  ** override this setting
++  */
++  if( sqliteStrICmp(zLeft, "temp_store")==0 ){
++    static VdbeOpList getTmpDbLoc[] = {
++      { OP_ColumnName,  0, 1,        "temp_store"},
++      { OP_Callback,    1, 0,        0},
++    };
++    if( pRight->z==pLeft->z ){
++      sqliteVdbeAddOp(v, OP_Integer, db->temp_store, 0);
++      sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc);
++    }else{
++      changeTempStorage(pParse, zRight);
++    }
++  }else
++
++  /*
++  **   PRAGMA default_temp_store
++  **   PRAGMA default_temp_store = "default"|"memory"|"file"
++  **
++  ** Return or set the value of the persistent temp_store flag.  Any
++  ** change does not take effect until the next time the database is
++  ** opened.
++  **
++  ** Note that it is possible for the library compile-time options to
++  ** override this setting
++  */
++  if( sqliteStrICmp(zLeft, "default_temp_store")==0 ){
++    static VdbeOpList getTmpDbLoc[] = {
++      { OP_ColumnName,  0, 1,        "temp_store"},
++      { OP_ReadCookie,  0, 5,        0},
++      { OP_Callback,    1, 0,        0}};
++    if( pRight->z==pLeft->z ){
++      sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc);
++    }else{
++      sqliteBeginWriteOperation(pParse, 0, 0);
++      sqliteVdbeAddOp(v, OP_Integer, getTempStore(zRight), 0);
++      sqliteVdbeAddOp(v, OP_SetCookie, 0, 5);
++      sqliteEndWriteOperation(pParse);
++    }
++  }else
++
++#ifndef NDEBUG
++  if( sqliteStrICmp(zLeft, "parser_trace")==0 ){
++    extern void sqliteParserTrace(FILE*, char *);
++    if( getBoolean(zRight) ){
++      sqliteParserTrace(stdout, "parser: ");
++    }else{
++      sqliteParserTrace(0, 0);
++    }
++  }else
++#endif
++
++  if( sqliteStrICmp(zLeft, "integrity_check")==0 ){
++    int i, j, addr;
++
++    /* Code that initializes the integrity check program.  Set the
++    ** error count 0
++    */
++    static VdbeOpList initCode[] = {
++      { OP_Integer,     0, 0,        0},
++      { OP_MemStore,    0, 1,        0},
++      { OP_ColumnName,  0, 1,        "integrity_check"},
++    };
++
++    /* Code to do an BTree integrity check on a single database file.
++    */
++    static VdbeOpList checkDb[] = {
++      { OP_SetInsert,   0, 0,        "2"},
++      { OP_Integer,     0, 0,        0},    /* 1 */
++      { OP_OpenRead,    0, 2,        0},
++      { OP_Rewind,      0, 7,        0},    /* 3 */
++      { OP_Column,      0, 3,        0},    /* 4 */
++      { OP_SetInsert,   0, 0,        0},
++      { OP_Next,        0, 4,        0},    /* 6 */
++      { OP_IntegrityCk, 0, 0,        0},    /* 7 */
++      { OP_Dup,         0, 1,        0},
++      { OP_String,      0, 0,        "ok"},
++      { OP_StrEq,       0, 12,       0},    /* 10 */
++      { OP_MemIncr,     0, 0,        0},
++      { OP_String,      0, 0,        "*** in database "},
++      { OP_String,      0, 0,        0},    /* 13 */
++      { OP_String,      0, 0,        " ***\n"},
++      { OP_Pull,        3, 0,        0},
++      { OP_Concat,      4, 1,        0},
++      { OP_Callback,    1, 0,        0},
++    };
++
++    /* 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 VdbeOpList endCode[] = {
++      { OP_MemLoad,     0, 0,        0},
++      { OP_Integer,     0, 0,        0},
++      { OP_Ne,          0, 0,        0},    /* 2 */
++      { OP_String,      0, 0,        "ok"},
++      { OP_Callback,    1, 0,        0},
++    };
++
++    /* Initialize the VDBE program */
++    sqliteVdbeAddOpList(v, ArraySize(initCode), initCode);
++
++    /* Do an integrity check on each database file */
++    for(i=0; i<db->nDb; i++){
++      HashElem *x;
++
++      /* Do an integrity check of the B-Tree
++      */
++      addr = sqliteVdbeAddOpList(v, ArraySize(checkDb), checkDb);
++      sqliteVdbeChangeP1(v, addr+1, i);
++      sqliteVdbeChangeP2(v, addr+3, addr+7);
++      sqliteVdbeChangeP2(v, addr+6, addr+4);
++      sqliteVdbeChangeP2(v, addr+7, i);
++      sqliteVdbeChangeP2(v, addr+10, addr+ArraySize(checkDb));
++      sqliteVdbeChangeP3(v, addr+13, db->aDb[i].zName, P3_STATIC);
++
++      /* Make sure all the indices are constructed correctly.
++      */
++      sqliteCodeVerifySchema(pParse, i);
++      for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
++        Table *pTab = sqliteHashData(x);
++        Index *pIdx;
++        int loopTop;
++
++        if( pTab->pIndex==0 ) continue;
++        sqliteVdbeAddOp(v, OP_Integer, i, 0);
++        sqliteVdbeOp3(v, OP_OpenRead, 1, pTab->tnum, pTab->zName, 0);
++        for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
++          if( pIdx->tnum==0 ) continue;
++          sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
++          sqliteVdbeOp3(v, OP_OpenRead, j+2, pIdx->tnum, pIdx->zName, 0);
++        }
++        sqliteVdbeAddOp(v, OP_Integer, 0, 0);
++        sqliteVdbeAddOp(v, OP_MemStore, 1, 1);
++        loopTop = sqliteVdbeAddOp(v, OP_Rewind, 1, 0);
++        sqliteVdbeAddOp(v, OP_MemIncr, 1, 0);
++        for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
++          int k, jmp2;
++          static VdbeOpList idxErr[] = {
++            { OP_MemIncr,     0,  0,  0},
++            { OP_String,      0,  0,  "rowid "},
++            { OP_Recno,       1,  0,  0},
++            { OP_String,      0,  0,  " missing from index "},
++            { OP_String,      0,  0,  0},    /* 4 */
++            { OP_Concat,      4,  0,  0},
++            { OP_Callback,    1,  0,  0},
++          };
++          sqliteVdbeAddOp(v, OP_Recno, 1, 0);
++          for(k=0; k<pIdx->nColumn; k++){
++            int idx = pIdx->aiColumn[k];
++            if( idx==pTab->iPKey ){
++              sqliteVdbeAddOp(v, OP_Recno, 1, 0);
++            }else{
++              sqliteVdbeAddOp(v, OP_Column, 1, idx);
++            }
++          }
++          sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
++          if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx);
++          jmp2 = sqliteVdbeAddOp(v, OP_Found, j+2, 0);
++          addr = sqliteVdbeAddOpList(v, ArraySize(idxErr), idxErr);
++          sqliteVdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
++          sqliteVdbeChangeP2(v, jmp2, sqliteVdbeCurrentAddr(v));
++        }
++        sqliteVdbeAddOp(v, OP_Next, 1, loopTop+1);
++        sqliteVdbeChangeP2(v, loopTop, sqliteVdbeCurrentAddr(v));
++        for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
++          static VdbeOpList cntIdx[] = {
++             { OP_Integer,      0,  0,  0},
++             { OP_MemStore,     2,  1,  0},
++             { OP_Rewind,       0,  0,  0},  /* 2 */
++             { OP_MemIncr,      2,  0,  0},
++             { OP_Next,         0,  0,  0},  /* 4 */
++             { OP_MemLoad,      1,  0,  0},
++             { OP_MemLoad,      2,  0,  0},
++             { OP_Eq,           0,  0,  0},  /* 7 */
++             { OP_MemIncr,      0,  0,  0},
++             { OP_String,       0,  0,  "wrong # of entries in index "},
++             { OP_String,       0,  0,  0},  /* 10 */
++             { OP_Concat,       2,  0,  0},
++             { OP_Callback,     1,  0,  0},
++          };
++          if( pIdx->tnum==0 ) continue;
++          addr = sqliteVdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
++          sqliteVdbeChangeP1(v, addr+2, j+2);
++          sqliteVdbeChangeP2(v, addr+2, addr+5);
++          sqliteVdbeChangeP1(v, addr+4, j+2);
++          sqliteVdbeChangeP2(v, addr+4, addr+3);
++          sqliteVdbeChangeP2(v, addr+7, addr+ArraySize(cntIdx));
++          sqliteVdbeChangeP3(v, addr+10, pIdx->zName, P3_STATIC);
++        }
++      } 
++    }
++    addr = sqliteVdbeAddOpList(v, ArraySize(endCode), endCode);
++    sqliteVdbeChangeP2(v, addr+2, addr+ArraySize(endCode));
++  }else
++
++  {}
++  sqliteFree(zLeft);
++  sqliteFree(zRight);
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/printf.c
+@@ -0,0 +1,858 @@
++/*
++** The "printf" code that follows dates from the 1980's.  It is in
++** the public domain.  The original comments are included here for
++** completeness.  They are very out-of-date but might be useful as
++** an historical reference.  Most of the "enhancements" have been backed
++** out so that the functionality is now the same as standard printf().
++**
++**************************************************************************
++**
++** The following modules is an enhanced replacement for the "printf" subroutines
++** found in the standard C library.  The following enhancements are
++** supported:
++**
++**      +  Additional functions.  The standard set of "printf" functions
++**         includes printf, fprintf, sprintf, vprintf, vfprintf, and
++**         vsprintf.  This module adds the following:
++**
++**           *  snprintf -- Works like sprintf, but has an extra argument
++**                          which is the size of the buffer written to.
++**
++**           *  mprintf --  Similar to sprintf.  Writes output to memory
++**                          obtained from malloc.
++**
++**           *  xprintf --  Calls a function to dispose of output.
++**
++**           *  nprintf --  No output, but returns the number of characters
++**                          that would have been output by printf.
++**
++**           *  A v- version (ex: vsnprintf) of every function is also
++**              supplied.
++**
++**      +  A few extensions to the formatting notation are supported:
++**
++**           *  The "=" flag (similar to "-") causes the output to be
++**              be centered in the appropriately sized field.
++**
++**           *  The %b field outputs an integer in binary notation.
++**
++**           *  The %c field now accepts a precision.  The character output
++**              is repeated by the number of times the precision specifies.
++**
++**           *  The %' field works like %c, but takes as its character the
++**              next character of the format string, instead of the next
++**              argument.  For example,  printf("%.78'-")  prints 78 minus
++**              signs, the same as  printf("%.78c",'-').
++**
++**      +  When compiled using GCC on a SPARC, this version of printf is
++**         faster than the library printf for SUN OS 4.1.
++**
++**      +  All functions are fully reentrant.
++**
++*/
++#include "sqliteInt.h"
++
++/*
++** Conversion types fall into various categories as defined by the
++** following enumeration.
++*/
++#define etRADIX       1 /* Integer types.  %d, %x, %o, and so forth */
++#define etFLOAT       2 /* Floating point.  %f */
++#define etEXP         3 /* Exponentional notation. %e and %E */
++#define etGENERIC     4 /* Floating or exponential, depending on exponent. %g */
++#define etSIZE        5 /* Return number of characters processed so far. %n */
++#define etSTRING      6 /* Strings. %s */
++#define etDYNSTRING   7 /* Dynamically allocated strings. %z */
++#define etPERCENT     8 /* Percent symbol. %% */
++#define etCHARX       9 /* Characters. %c */
++#define etERROR      10 /* Used to indicate no such conversion type */
++/* The rest are extensions, not normally found in printf() */
++#define etCHARLIT    11 /* Literal characters.  %' */
++#define etSQLESCAPE  12 /* Strings with '\'' doubled.  %q */
++#define etSQLESCAPE2 13 /* Strings with '\'' doubled and enclosed in '',
++                          NULL pointers replaced by SQL NULL.  %Q */
++#define etTOKEN      14 /* a pointer to a Token structure */
++#define etSRCLIST    15 /* a pointer to a SrcList */
++
++
++/*
++** An "etByte" is an 8-bit unsigned value.
++*/
++typedef unsigned char etByte;
++
++/*
++** Each builtin conversion character (ex: the 'd' in "%d") is described
++** by an instance of the following structure
++*/
++typedef struct et_info {   /* Information about each format field */
++  char fmttype;            /* The format field code letter */
++  etByte base;             /* The base for radix conversion */
++  etByte flags;            /* One or more of FLAG_ constants below */
++  etByte type;             /* Conversion paradigm */
++  char *charset;           /* The character set for conversion */
++  char *prefix;            /* Prefix on non-zero values in alt format */
++} et_info;
++
++/*
++** Allowed values for et_info.flags
++*/
++#define FLAG_SIGNED  1     /* True if the value to convert is signed */
++#define FLAG_INTERN  2     /* True if for internal use only */
++
++
++/*
++** The following table is searched linearly, so it is good to put the
++** most frequently used conversion types first.
++*/
++static et_info fmtinfo[] = {
++  {  'd', 10, 1, etRADIX,      "0123456789",       0    },
++  {  's',  0, 0, etSTRING,     0,                  0    },
++  {  'z',  0, 2, etDYNSTRING,  0,                  0    },
++  {  'q',  0, 0, etSQLESCAPE,  0,                  0    },
++  {  'Q',  0, 0, etSQLESCAPE2, 0,                  0    },
++  {  'c',  0, 0, etCHARX,      0,                  0    },
++  {  'o',  8, 0, etRADIX,      "01234567",         "0"  },
++  {  'u', 10, 0, etRADIX,      "0123456789",       0    },
++  {  'x', 16, 0, etRADIX,      "0123456789abcdef", "x0" },
++  {  'X', 16, 0, etRADIX,      "0123456789ABCDEF", "X0" },
++  {  'f',  0, 1, etFLOAT,      0,                  0    },
++  {  'e',  0, 1, etEXP,        "e",                0    },
++  {  'E',  0, 1, etEXP,        "E",                0    },
++  {  'g',  0, 1, etGENERIC,    "e",                0    },
++  {  'G',  0, 1, etGENERIC,    "E",                0    },
++  {  'i', 10, 1, etRADIX,      "0123456789",       0    },
++  {  'n',  0, 0, etSIZE,       0,                  0    },
++  {  '%',  0, 0, etPERCENT,    0,                  0    },
++  {  'p', 10, 0, etRADIX,      "0123456789",       0    },
++  {  'T',  0, 2, etTOKEN,      0,                  0    },
++  {  'S',  0, 2, etSRCLIST,    0,                  0    },
++};
++#define etNINFO  (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
++
++/*
++** If NOFLOATINGPOINT is defined, then none of the floating point
++** conversions will work.
++*/
++#ifndef etNOFLOATINGPOINT
++/*
++** "*val" is a double such that 0.1 <= *val < 10.0
++** Return the ascii code for the leading digit of *val, then
++** multiply "*val" by 10.0 to renormalize.
++**
++** Example:
++**     input:     *val = 3.14159
++**     output:    *val = 1.4159    function return = '3'
++**
++** The counter *cnt is incremented each time.  After counter exceeds
++** 16 (the number of significant digits in a 64-bit float) '0' is
++** always returned.
++*/
++static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
++  int digit;
++  LONGDOUBLE_TYPE d;
++  if( (*cnt)++ >= 16 ) return '0';
++  digit = (int)*val;
++  d = digit;
++  digit += '0';
++  *val = (*val - d)*10.0;
++  return digit;
++}
++#endif
++
++#define etBUFSIZE 1000  /* Size of the output buffer */
++
++/*
++** The root program.  All variations call this core.
++**
++** INPUTS:
++**   func   This is a pointer to a function taking three arguments
++**            1. A pointer to anything.  Same as the "arg" parameter.
++**            2. A pointer to the list of characters to be output
++**               (Note, this list is NOT null terminated.)
++**            3. An integer number of characters to be output.
++**               (Note: This number might be zero.)
++**
++**   arg    This is the pointer to anything which will be passed as the
++**          first argument to "func".  Use it for whatever you like.
++**
++**   fmt    This is the format string, as in the usual print.
++**
++**   ap     This is a pointer to a list of arguments.  Same as in
++**          vfprint.
++**
++** OUTPUTS:
++**          The return value is the total number of characters sent to
++**          the function "func".  Returns -1 on a error.
++**
++** Note that the order in which automatic variables are declared below
++** 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 */
++  int useExtended,                   /* Allow extended %-conversions */
++  const char *fmt,                   /* Format string */
++  va_list ap                         /* arguments */
++){
++  int c;                     /* Next character in the format string */
++  char *bufpt;               /* Pointer to the conversion buffer */
++  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 */
++  etByte flag_blanksign;     /* True if " " flag is present */
++  etByte flag_alternateform; /* True if "#" flag is present */
++  etByte flag_zeropad;       /* True if field width constant starts with zero */
++  etByte flag_long;          /* True if "l" flag is present */
++  unsigned long longvalue;   /* Value for integer types */
++  LONGDOUBLE_TYPE realvalue; /* Value for real types */
++  et_info *infop;            /* Pointer to the appropriate info structure */
++  char buf[etBUFSIZE];       /* Conversion buffer */
++  char prefix;               /* Prefix character.  "+" or "-" or " " or '\0'. */
++  etByte errorflag = 0;      /* True if an error is encountered */
++  etByte xtype;              /* Conversion paradigm */
++  char *zExtra;              /* Extra memory used for etTCLESCAPE conversions */
++  static char spaces[] = "                                                  ";
++#define etSPACESIZE (sizeof(spaces)-1)
++#ifndef etNOFLOATINGPOINT
++  int  exp;                  /* exponent of real numbers */
++  double rounder;            /* Used for rounding floating point values */
++  etByte flag_dp;            /* True if decimal point should be shown */
++  etByte flag_rtz;           /* True if trailing zeros should be removed */
++  etByte flag_exp;           /* True to force display of the exponent */
++  int nsd;                   /* Number of significant digits returned */
++#endif
++
++  func(arg,"",0);
++  count = length = 0;
++  bufpt = 0;
++  for(; (c=(*fmt))!=0; ++fmt){
++    if( c!='%' ){
++      int amt;
++      bufpt = (char *)fmt;
++      amt = 1;
++      while( (c=(*++fmt))!='%' && c!=0 ) amt++;
++      (*func)(arg,bufpt,amt);
++      count += amt;
++      if( c==0 ) break;
++    }
++    if( (c=(*++fmt))==0 ){
++      errorflag = 1;
++      (*func)(arg,"%",1);
++      count++;
++      break;
++    }
++    /* Find out what flags are present */
++    flag_leftjustify = flag_plussign = flag_blanksign = 
++     flag_alternateform = flag_zeropad = 0;
++    do{
++      switch( c ){
++        case '-':   flag_leftjustify = 1;     c = 0;   break;
++        case '+':   flag_plussign = 1;        c = 0;   break;
++        case ' ':   flag_blanksign = 1;       c = 0;   break;
++        case '#':   flag_alternateform = 1;   c = 0;   break;
++        case '0':   flag_zeropad = 1;         c = 0;   break;
++        default:                                       break;
++      }
++    }while( c==0 && (c=(*++fmt))!=0 );
++    /* Get the field width */
++    width = 0;
++    if( c=='*' ){
++      width = va_arg(ap,int);
++      if( width<0 ){
++        flag_leftjustify = 1;
++        width = -width;
++      }
++      c = *++fmt;
++    }else{
++      while( c>='0' && c<='9' ){
++        width = width*10 + c - '0';
++        c = *++fmt;
++      }
++    }
++    if( width > etBUFSIZE-10 ){
++      width = etBUFSIZE-10;
++    }
++    /* Get the precision */
++    if( c=='.' ){
++      precision = 0;
++      c = *++fmt;
++      if( c=='*' ){
++        precision = va_arg(ap,int);
++        if( precision<0 ) precision = -precision;
++        c = *++fmt;
++      }else{
++        while( c>='0' && c<='9' ){
++          precision = precision*10 + c - '0';
++          c = *++fmt;
++        }
++      }
++      /* Limit the precision to prevent overflowing buf[] during conversion */
++      if( precision>etBUFSIZE-40 ) precision = etBUFSIZE-40;
++    }else{
++      precision = -1;
++    }
++    /* Get the conversion type modifier */
++    if( c=='l' ){
++      flag_long = 1;
++      c = *++fmt;
++    }else{
++      flag_long = 0;
++    }
++    /* Fetch the info entry for the field */
++    infop = 0;
++    xtype = etERROR;
++    for(idx=0; idx<etNINFO; idx++){
++      if( c==fmtinfo[idx].fmttype ){
++        infop = &fmtinfo[idx];
++        if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
++          xtype = infop->type;
++        }
++        break;
++      }
++    }
++    zExtra = 0;
++
++    /*
++    ** At this point, variables are initialized as follows:
++    **
++    **   flag_alternateform          TRUE if a '#' is present.
++    **   flag_plussign               TRUE if a '+' is present.
++    **   flag_leftjustify            TRUE if a '-' is present or if the
++    **                               field width was negative.
++    **   flag_zeropad                TRUE if the width began with 0.
++    **   flag_long                   TRUE if the letter 'l' (ell) prefixed
++    **                               the conversion character.
++    **   flag_blanksign              TRUE if a ' ' is present.
++    **   width                       The specified field width.  This is
++    **                               always non-negative.  Zero is the default.
++    **   precision                   The specified precision.  The default
++    **                               is -1.
++    **   xtype                       The class of the conversion.
++    **   infop                       Pointer to the appropriate info struct.
++    */
++    switch( xtype ){
++      case etRADIX:
++        if( flag_long )  longvalue = va_arg(ap,long);
++        else             longvalue = va_arg(ap,int);
++#if 1
++        /* For the format %#x, the value zero is printed "0" not "0x0".
++        ** I think this is stupid. */
++        if( longvalue==0 ) flag_alternateform = 0;
++#else
++        /* More sensible: turn off the prefix for octal (to prevent "00"),
++        ** but leave the prefix for hex. */
++        if( longvalue==0 && infop->base==8 ) flag_alternateform = 0;
++#endif
++        if( infop->flags & FLAG_SIGNED ){
++          if( *(long*)&longvalue<0 ){
++            longvalue = -*(long*)&longvalue;
++            prefix = '-';
++          }else if( flag_plussign )  prefix = '+';
++          else if( flag_blanksign )  prefix = ' ';
++          else                       prefix = 0;
++        }else                        prefix = 0;
++        if( flag_zeropad && precision<width-(prefix!=0) ){
++          precision = width-(prefix!=0);
++        }
++        bufpt = &buf[etBUFSIZE-1];
++        {
++          register char *cset;      /* Use registers for speed */
++          register int base;
++          cset = infop->charset;
++          base = infop->base;
++          do{                                           /* Convert to ascii */
++            *(--bufpt) = cset[longvalue%base];
++            longvalue = longvalue/base;
++          }while( longvalue>0 );
++        }
++        length = &buf[etBUFSIZE-1]-bufpt;
++        for(idx=precision-length; idx>0; idx--){
++          *(--bufpt) = '0';                             /* Zero pad */
++        }
++        if( prefix ) *(--bufpt) = prefix;               /* Add sign */
++        if( flag_alternateform && infop->prefix ){      /* Add "0" or "0x" */
++          char *pre, x;
++          pre = infop->prefix;
++          if( *bufpt!=pre[0] ){
++            for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x;
++          }
++        }
++        length = &buf[etBUFSIZE-1]-bufpt;
++        break;
++      case etFLOAT:
++      case etEXP:
++      case etGENERIC:
++        realvalue = va_arg(ap,double);
++#ifndef etNOFLOATINGPOINT
++        if( precision<0 ) precision = 6;         /* Set default precision */
++        if( precision>etBUFSIZE-10 ) precision = etBUFSIZE-10;
++        if( realvalue<0.0 ){
++          realvalue = -realvalue;
++          prefix = '-';
++        }else{
++          if( flag_plussign )          prefix = '+';
++          else if( flag_blanksign )    prefix = ' ';
++          else                         prefix = 0;
++        }
++        if( infop->type==etGENERIC && precision>0 ) precision--;
++        rounder = 0.0;
++#if 0
++        /* Rounding works like BSD when the constant 0.4999 is used.  Wierd! */
++        for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
++#else
++        /* It makes more sense to use 0.5 */
++        for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1);
++#endif
++        if( infop->type==etFLOAT ) realvalue += rounder;
++        /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
++        exp = 0;
++        if( realvalue>0.0 ){
++          while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
++          while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
++          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;
++            break;
++          }
++        }
++        bufpt = buf;
++        /*
++        ** If the field type is etGENERIC, then convert to either etEXP
++        ** or etFLOAT, as appropriate.
++        */
++        flag_exp = xtype==etEXP;
++        if( xtype!=etFLOAT ){
++          realvalue += rounder;
++          if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
++        }
++        if( xtype==etGENERIC ){
++          flag_rtz = !flag_alternateform;
++          if( exp<-4 || exp>precision ){
++            xtype = etEXP;
++          }else{
++            precision = precision - exp;
++            xtype = etFLOAT;
++          }
++        }else{
++          flag_rtz = 0;
++        }
++        /*
++        ** The "exp+precision" test causes output to be of type etEXP if
++        ** the precision is too large to fit in buf[].
++        */
++        nsd = 0;
++        if( xtype==etFLOAT && exp+precision<etBUFSIZE-30 ){
++          flag_dp = (precision>0 || flag_alternateform);
++          if( prefix ) *(bufpt++) = prefix;         /* Sign */
++          if( exp<0 )  *(bufpt++) = '0';            /* Digits before "." */
++          else for(; exp>=0; exp--) *(bufpt++) = et_getdigit(&realvalue,&nsd);
++          if( flag_dp ) *(bufpt++) = '.';           /* The decimal point */
++          for(exp++; exp<0 && precision>0; precision--, exp++){
++            *(bufpt++) = '0';
++          }
++          while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);
++          *(bufpt--) = 0;                           /* Null terminate */
++          if( flag_rtz && flag_dp ){     /* Remove trailing zeros and "." */
++            while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
++            if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
++          }
++          bufpt++;                            /* point to next free slot */
++        }else{    /* etEXP or etGENERIC */
++          flag_dp = (precision>0 || flag_alternateform);
++          if( prefix ) *(bufpt++) = prefix;   /* Sign */
++          *(bufpt++) = et_getdigit(&realvalue,&nsd);  /* First digit */
++          if( flag_dp ) *(bufpt++) = '.';     /* Decimal point */
++          while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);
++          bufpt--;                            /* point to last digit */
++          if( flag_rtz && flag_dp ){          /* Remove tail zeros */
++            while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
++            if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
++          }
++          bufpt++;                            /* point to next free slot */
++          if( exp || flag_exp ){
++            *(bufpt++) = infop->charset[0];
++            if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */
++            else       { *(bufpt++) = '+'; }
++            if( exp>=100 ){
++              *(bufpt++) = (exp/100)+'0';                /* 100's digit */
++              exp %= 100;
++            }
++            *(bufpt++) = exp/10+'0';                     /* 10's digit */
++            *(bufpt++) = exp%10+'0';                     /* 1's digit */
++          }
++        }
++        /* The converted number is in buf[] and zero terminated. Output it.
++        ** Note that the number is in the usual order, not reversed as with
++        ** integer conversions. */
++        length = bufpt-buf;
++        bufpt = buf;
++
++        /* Special case:  Add leading zeros if the flag_zeropad flag is
++        ** set and we are not left justified */
++        if( flag_zeropad && !flag_leftjustify && length < width){
++          int i;
++          int nPad = width - length;
++          for(i=width; i>=nPad; i--){
++            bufpt[i] = bufpt[i-nPad];
++          }
++          i = prefix!=0;
++          while( nPad-- ) bufpt[i++] = '0';
++          length = width;
++        }
++#endif
++        break;
++      case etSIZE:
++        *(va_arg(ap,int*)) = count;
++        length = width = 0;
++        break;
++      case etPERCENT:
++        buf[0] = '%';
++        bufpt = buf;
++        length = 1;
++        break;
++      case etCHARLIT:
++      case etCHARX:
++        c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt);
++        if( precision>=0 ){
++          for(idx=1; idx<precision; idx++) buf[idx] = c;
++          length = precision;
++        }else{
++          length =1;
++        }
++        bufpt = buf;
++        break;
++      case etSTRING:
++      case etDYNSTRING:
++        bufpt = va_arg(ap,char*);
++        if( bufpt==0 ){
++          bufpt = "";
++        }else if( xtype==etDYNSTRING ){
++          zExtra = bufpt;
++        }
++        length = strlen(bufpt);
++        if( precision>=0 && precision<length ) length = precision;
++        break;
++      case etSQLESCAPE:
++      case etSQLESCAPE2:
++        {
++          int i, j, n, c, isnull;
++          char *arg = va_arg(ap,char*);
++          isnull = arg==0;
++          if( isnull ) arg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
++          for(i=n=0; (c=arg[i])!=0; i++){
++            if( c=='\'' )  n++;
++          }
++          n += i + 1 + ((!isnull && xtype==etSQLESCAPE2) ? 2 : 0);
++          if( n>etBUFSIZE ){
++            bufpt = zExtra = sqliteMalloc( n );
++            if( bufpt==0 ) return -1;
++          }else{
++            bufpt = buf;
++          }
++          j = 0;
++          if( !isnull && xtype==etSQLESCAPE2 ) bufpt[j++] = '\'';
++          for(i=0; (c=arg[i])!=0; i++){
++            bufpt[j++] = c;
++            if( c=='\'' ) bufpt[j++] = c;
++          }
++          if( !isnull && xtype==etSQLESCAPE2 ) bufpt[j++] = '\'';
++          bufpt[j] = 0;
++          length = j;
++          if( precision>=0 && precision<length ) length = precision;
++        }
++        break;
++      case etTOKEN: {
++        Token *pToken = va_arg(ap, Token*);
++        (*func)(arg, pToken->z, pToken->n);
++        length = width = 0;
++        break;
++      }
++      case etSRCLIST: {
++        SrcList *pSrc = va_arg(ap, SrcList*);
++        int k = va_arg(ap, int);
++        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);
++        }
++        (*func)(arg, pItem->zName, strlen(pItem->zName));
++        length = width = 0;
++        break;
++      }
++      case etERROR:
++        buf[0] = '%';
++        buf[1] = c;
++        errorflag = 0;
++        idx = 1+(c!=0);
++        (*func)(arg,"%",idx);
++        count += idx;
++        if( c==0 ) fmt--;
++        break;
++    }/* End switch over the format type */
++    /*
++    ** The text of the conversion is pointed to by "bufpt" and is
++    ** "length" characters long.  The field width is "width".  Do
++    ** the output.
++    */
++    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);
++      }
++    }
++    if( length>0 ){
++      (*func)(arg,bufpt,length);
++      count += 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);
++      }
++    }
++    if( zExtra ){
++      sqliteFree(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".
++*/
++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;
++    }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);
++        }
++      }else{
++        pM->zText = pM->xRealloc(pM->zText, pM->nAlloc);
++      }
++    }
++  }
++  if( pM->zText ){
++    if( nNewChar>0 ){
++      memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
++      pM->nChar += nNewChar;
++    }
++    pM->zText[pM->nChar] = 0;
++  }
++}
++
++/*
++** This routine is a wrapper around xprintf() that invokes mout() as
++** the consumer.  
++*/
++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);
++      memcpy(sM.zText, sM.zBase, sM.nChar+1);
++    }else if( sM.nAlloc>sM.nChar+10 ){
++      sM.zText = xRealloc(sM.zText, sM.nChar+1);
++    }
++  }
++  return sM.zText;
++}
++
++/*
++** Realloc that is a real function, not a macro.
++*/
++static void *printf_realloc(void *old, int size){
++  return sqliteRealloc(old,size);
++}
++
++/*
++** Print into memory obtained from sqliteMalloc().  Use the internal
++** %-conversion extensions.
++*/
++char *sqliteVMPrintf(const char *zFormat, va_list ap){
++  char zBase[1000];
++  return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
++}
++
++/*
++** Print into memory obtained from sqliteMalloc().  Use the internal
++** %-conversion extensions.
++*/
++char *sqliteMPrintf(const char *zFormat, ...){
++  va_list ap;
++  char *z;
++  char zBase[1000];
++  va_start(ap, zFormat);
++  z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
++  va_end(ap);
++  return z;
++}
++
++/*
++** Print into memory obtained from malloc().  Do not use the internal
++** %-conversion extensions.  This routine is for use by external users.
++*/
++char *sqlite_mprintf(const char *zFormat, ...){
++  va_list ap;
++  char *z;
++  char zBuf[200];
++
++  va_start(ap,zFormat);
++  z = base_vprintf((void*(*)(void*,int))realloc, 0, 
++                   zBuf, sizeof(zBuf), zFormat, ap);
++  va_end(ap);
++  return z;
++}
++
++/* This is the varargs version of sqlite_mprintf.  
++*/
++char *sqlite_vmprintf(const char *zFormat, va_list ap){
++  char zBuf[200];
++  return base_vprintf((void*(*)(void*,int))realloc, 0,
++                      zBuf, sizeof(zBuf), zFormat, ap);
++}
++
++/*
++** sqlite_snprintf() works like snprintf() except that it ignores the
++** current locale settings.  This is important for SQLite because we
++** are not able to use a "," as the decimal point in place of "." as
++** specified by some locales.
++*/
++char *sqlite_snprintf(int n, char *zBuf, const char *zFormat, ...){
++  char *z;
++  va_list ap;
++
++  va_start(ap,zFormat);
++  z = base_vprintf(0, 0, zBuf, n, zFormat, ap);
++  va_end(ap);
++  return z;
++}
++
++/*
++** The following four routines implement the varargs versions of the
++** sqlite_exec() and sqlite_get_table() interfaces.  See the sqlite.h
++** header files for a more detailed description of how these interfaces
++** work.
++**
++** These routines are all just simple wrappers.
++*/
++int sqlite_exec_printf(
++  sqlite *db,                   /* An open database */
++  const char *sqlFormat,        /* printf-style format string for the SQL */
++  sqlite_callback xCallback,    /* Callback function */
++  void *pArg,                   /* 1st argument to callback function */
++  char **errmsg,                /* Error msg written here */
++  ...                           /* Arguments to the format string. */
++){
++  va_list ap;
++  int rc;
++
++  va_start(ap, errmsg);
++  rc = sqlite_exec_vprintf(db, sqlFormat, xCallback, pArg, errmsg, ap);
++  va_end(ap);
++  return rc;
++}
++int sqlite_exec_vprintf(
++  sqlite *db,                   /* An open database */
++  const char *sqlFormat,        /* printf-style format string for the SQL */
++  sqlite_callback xCallback,    /* Callback function */
++  void *pArg,                   /* 1st argument to callback function */
++  char **errmsg,                /* Error msg written here */
++  va_list ap                    /* Arguments to the format string. */
++){
++  char *zSql;
++  int rc;
++
++  zSql = sqlite_vmprintf(sqlFormat, ap);
++  rc = sqlite_exec(db, zSql, xCallback, pArg, errmsg);
++  free(zSql);
++  return rc;
++}
++int sqlite_get_table_printf(
++  sqlite *db,            /* An open database */
++  const char *sqlFormat, /* printf-style format string for the SQL */
++  char ***resultp,       /* Result written to a char *[]  that this points to */
++  int *nrow,             /* Number of result rows written here */
++  int *ncol,             /* Number of result columns written here */
++  char **errmsg,         /* Error msg written here */
++  ...                    /* Arguments to the format string */
++){
++  va_list ap;
++  int rc;
++
++  va_start(ap, errmsg);
++  rc = sqlite_get_table_vprintf(db, sqlFormat, resultp, nrow, ncol, errmsg, ap);
++  va_end(ap);
++  return rc;
++}
++int sqlite_get_table_vprintf(
++  sqlite *db,            /* An open database */
++  const char *sqlFormat, /* printf-style format string for the SQL */
++  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 */
++  va_list ap             /* Arguments to the format string */
++){
++  char *zSql;
++  int rc;
++
++  zSql = sqlite_vmprintf(sqlFormat, ap);
++  rc = sqlite_get_table(db, zSql, resultp, nrow, ncolumn, errmsg);
++  free(zSql);
++  return rc;
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/random.c
+@@ -0,0 +1,97 @@
++/*
++** 2001 September 15
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This file contains code to implement a pseudo-random number
++** generator (PRNG) for SQLite.
++**
++** Random numbers are used by some of the database backends in order
++** to generate random integer keys for tables or random filenames.
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++#include "os.h"
++
++
++/*
++** Get a single 8-bit random value from the RC4 PRNG.  The Mutex
++** must be held while executing this routine.
++**
++** Why not just use a library random generator like lrand48() for this?
++** Because the OP_NewRecno opcode in the VDBE depends on having a very
++** good source of random numbers.  The lrand48() library function may
++** well be good enough.  But maybe not.  Or maybe lrand48() has some
++** subtle problems on some systems that could cause problems.  It is hard
++** to know.  To minimize the risk of problems due to bad lrand48()
++** implementations, SQLite uses this random number generator based
++** on RC4, which we know works very well.
++*/
++static int randomByte(){
++  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
++  ** not need to contain a lot of randomness since we are not
++  ** trying to do secure encryption or anything like that...
++  **
++  ** Nothing in this file or anywhere else in SQLite does any kind of
++  ** encryption.  The RC4 algorithm is being used as a PRNG (pseudo-random
++  ** number generator) not as an encryption device.
++  */
++  if( !prng.isInit ){
++    int i;
++    char k[256];
++    prng.j = 0;
++    prng.i = 0;
++    sqliteOsRandomSeed(k);
++    for(i=0; i<256; i++){
++      prng.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;
++    }
++    prng.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];
++}
++
++/*
++** Return N random bytes.
++*/
++void sqliteRandomness(int N, void *pBuf){
++  unsigned char *zBuf = pBuf;
++  sqliteOsEnterMutex();
++  while( N-- ){
++    *(zBuf++) = randomByte();
++  }
++  sqliteOsLeaveMutex();
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/select.c
+@@ -0,0 +1,2434 @@
++/*
++** 2001 September 15
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This file contains C code routines that are called by the parser
++** to handle SELECT statements in SQLite.
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++
++
++/*
++** Allocate a new Select structure and return a pointer to that
++** structure.
++*/
++Select *sqliteSelectNew(
++  ExprList *pEList,     /* which columns to include in the result */
++  SrcList *pSrc,        /* the FROM clause -- which tables to scan */
++  Expr *pWhere,         /* the WHERE clause */
++  ExprList *pGroupBy,   /* the GROUP BY clause */
++  Expr *pHaving,        /* the HAVING clause */
++  ExprList *pOrderBy,   /* the ORDER BY clause */
++  int isDistinct,       /* true if the DISTINCT keyword is present */
++  int nLimit,           /* LIMIT value.  -1 means not used */
++  int nOffset           /* OFFSET value.  0 means no offset */
++){
++  Select *pNew;
++  pNew = sqliteMalloc( sizeof(*pNew) );
++  if( pNew==0 ){
++    sqliteExprListDelete(pEList);
++    sqliteSrcListDelete(pSrc);
++    sqliteExprDelete(pWhere);
++    sqliteExprListDelete(pGroupBy);
++    sqliteExprDelete(pHaving);
++    sqliteExprListDelete(pOrderBy);
++  }else{
++    if( pEList==0 ){
++      pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL,0,0,0), 0);
++    }
++    pNew->pEList = pEList;
++    pNew->pSrc = pSrc;
++    pNew->pWhere = pWhere;
++    pNew->pGroupBy = pGroupBy;
++    pNew->pHaving = pHaving;
++    pNew->pOrderBy = pOrderBy;
++    pNew->isDistinct = isDistinct;
++    pNew->op = TK_SELECT;
++    pNew->nLimit = nLimit;
++    pNew->nOffset = nOffset;
++    pNew->iLimit = -1;
++    pNew->iOffset = -1;
++  }
++  return pNew;
++}
++
++/*
++** Given 1 to 3 identifiers preceeding the JOIN keyword, determine the
++** type of join.  Return an integer constant that expresses that type
++** in terms of the following bit values:
++**
++**     JT_INNER
++**     JT_OUTER
++**     JT_NATURAL
++**     JT_LEFT
++**     JT_RIGHT
++**
++** A full outer join is the combination of JT_LEFT and JT_RIGHT.
++**
++** If an illegal or unsupported join type is seen, then still return
++** a join type, but put an error in the pParse structure.
++*/
++int sqliteJoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
++  int jointype = 0;
++  Token *apAll[3];
++  Token *p;
++  static struct {
++    const char *zKeyword;
++    int nChar;
++    int code;
++  } keywords[] = {
++    { "natural", 7, JT_NATURAL },
++    { "left",    4, JT_LEFT|JT_OUTER },
++    { "right",   5, JT_RIGHT|JT_OUTER },
++    { "full",    4, JT_LEFT|JT_RIGHT|JT_OUTER },
++    { "outer",   5, JT_OUTER },
++    { "inner",   5, JT_INNER },
++    { "cross",   5, JT_INNER },
++  };
++  int i, j;
++  apAll[0] = pA;
++  apAll[1] = pB;
++  apAll[2] = pC;
++  for(i=0; i<3 && apAll[i]; i++){
++    p = apAll[i];
++    for(j=0; j<sizeof(keywords)/sizeof(keywords[0]); j++){
++      if( p->n==keywords[j].nChar 
++          && sqliteStrNICmp(p->z, keywords[j].zKeyword, p->n)==0 ){
++        jointype |= keywords[j].code;
++        break;
++      }
++    }
++    if( j>=sizeof(keywords)/sizeof(keywords[0]) ){
++      jointype |= JT_ERROR;
++      break;
++    }
++  }
++  if(
++     (jointype & (JT_INNER|JT_OUTER))==(JT_INNER|JT_OUTER) ||
++     (jointype & JT_ERROR)!=0
++  ){
++    static Token dummy = { 0, 0 };
++    char *zSp1 = " ", *zSp2 = " ";
++    if( pB==0 ){ pB = &dummy; zSp1 = 0; }
++    if( pC==0 ){ pC = &dummy; zSp2 = 0; }
++    sqliteSetNString(&pParse->zErrMsg, "unknown or unsupported join type: ", 0,
++       pA->z, pA->n, zSp1, 1, pB->z, pB->n, zSp2, 1, pC->z, pC->n, 0);
++    pParse->nErr++;
++    jointype = JT_INNER;
++  }else if( jointype & JT_RIGHT ){
++    sqliteErrorMsg(pParse, 
++      "RIGHT and FULL OUTER JOINs are not currently supported");
++    jointype = JT_INNER;
++  }
++  return jointype;
++}
++
++/*
++** Return the index of a column in a table.  Return -1 if the column
++** is not contained in the table.
++*/
++static int columnIndex(Table *pTab, const char *zCol){
++  int i;
++  for(i=0; i<pTab->nCol; i++){
++    if( sqliteStrICmp(pTab->aCol[i].zName, zCol)==0 ) return i;
++  }
++  return -1;
++}
++
++/*
++** Add a term to the WHERE expression in *ppExpr that requires the
++** zCol column to be equal in the two tables pTab1 and pTab2.
++*/
++static void addWhereTerm(
++  const char *zCol,        /* Name of the column */
++  const Table *pTab1,      /* First table */
++  const Table *pTab2,      /* Second table */
++  Expr **ppExpr            /* Add the equality term to this expression */
++){
++  Token dummy;
++  Expr *pE1a, *pE1b, *pE1c;
++  Expr *pE2a, *pE2b, *pE2c;
++  Expr *pE;
++
++  dummy.z = zCol;
++  dummy.n = strlen(zCol);
++  dummy.dyn = 0;
++  pE1a = sqliteExpr(TK_ID, 0, 0, &dummy);
++  pE2a = sqliteExpr(TK_ID, 0, 0, &dummy);
++  dummy.z = pTab1->zName;
++  dummy.n = strlen(dummy.z);
++  pE1b = sqliteExpr(TK_ID, 0, 0, &dummy);
++  dummy.z = pTab2->zName;
++  dummy.n = strlen(dummy.z);
++  pE2b = sqliteExpr(TK_ID, 0, 0, &dummy);
++  pE1c = sqliteExpr(TK_DOT, pE1b, pE1a, 0);
++  pE2c = sqliteExpr(TK_DOT, pE2b, pE2a, 0);
++  pE = sqliteExpr(TK_EQ, pE1c, pE2c, 0);
++  ExprSetProperty(pE, EP_FromJoin);
++  if( *ppExpr ){
++    *ppExpr = sqliteExpr(TK_AND, *ppExpr, pE, 0);
++  }else{
++    *ppExpr = pE;
++  }
++}
++
++/*
++** Set the EP_FromJoin property on all terms of the given expression.
++**
++** The EP_FromJoin property is used on terms of an expression to tell
++** the LEFT OUTER JOIN processing logic that this term is part of the
++** join restriction specified in the ON or USING clause and not a part
++** of the more general WHERE clause.  These terms are moved over to the
++** WHERE clause during join processing but we need to remember that they
++** originated in the ON or USING clause.
++*/
++static void setJoinExpr(Expr *p){
++  while( p ){
++    ExprSetProperty(p, EP_FromJoin);
++    setJoinExpr(p->pLeft);
++    p = p->pRight;
++  } 
++}
++
++/*
++** This routine processes the join information for a SELECT statement.
++** ON and USING clauses are converted into extra terms of the WHERE clause.
++** NATURAL joins also create extra WHERE clause terms.
++**
++** This routine returns the number of errors encountered.
++*/
++static int sqliteProcessJoin(Parse *pParse, Select *p){
++  SrcList *pSrc;
++  int i, j;
++  pSrc = p->pSrc;
++  for(i=0; i<pSrc->nSrc-1; i++){
++    struct SrcList_item *pTerm = &pSrc->a[i];
++    struct SrcList_item *pOther = &pSrc->a[i+1];
++
++    if( pTerm->pTab==0 || pOther->pTab==0 ) continue;
++
++    /* When the NATURAL keyword is present, add WHERE clause terms for
++    ** every column that the two tables have in common.
++    */
++    if( pTerm->jointype & JT_NATURAL ){
++      Table *pTab;
++      if( pTerm->pOn || pTerm->pUsing ){
++        sqliteErrorMsg(pParse, "a NATURAL join may not have "
++           "an ON or USING clause", 0);
++        return 1;
++      }
++      pTab = pTerm->pTab;
++      for(j=0; j<pTab->nCol; j++){
++        if( columnIndex(pOther->pTab, pTab->aCol[j].zName)>=0 ){
++          addWhereTerm(pTab->aCol[j].zName, pTab, pOther->pTab, &p->pWhere);
++        }
++      }
++    }
++
++    /* Disallow both ON and USING clauses in the same join
++    */
++    if( pTerm->pOn && pTerm->pUsing ){
++      sqliteErrorMsg(pParse, "cannot have both ON and USING "
++        "clauses in the same join");
++      return 1;
++    }
++
++    /* Add the ON clause to the end of the WHERE clause, connected by
++    ** and AND operator.
++    */
++    if( pTerm->pOn ){
++      setJoinExpr(pTerm->pOn);
++      if( p->pWhere==0 ){
++        p->pWhere = pTerm->pOn;
++      }else{
++        p->pWhere = sqliteExpr(TK_AND, p->pWhere, pTerm->pOn, 0);
++      }
++      pTerm->pOn = 0;
++    }
++
++    /* Create extra terms on the WHERE clause for each column named
++    ** in the USING clause.  Example: If the two tables to be joined are 
++    ** A and B and the USING clause names X, Y, and Z, then add this
++    ** to the WHERE clause:    A.X=B.X AND A.Y=B.Y AND A.Z=B.Z
++    ** Report an error if any column mentioned in the USING clause is
++    ** not contained in both tables to be joined.
++    */
++    if( pTerm->pUsing ){
++      IdList *pList;
++      int j;
++      assert( i<pSrc->nSrc-1 );
++      pList = pTerm->pUsing;
++      for(j=0; j<pList->nId; j++){
++        if( columnIndex(pTerm->pTab, pList->a[j].zName)<0 ||
++            columnIndex(pOther->pTab, pList->a[j].zName)<0 ){
++          sqliteErrorMsg(pParse, "cannot join using column %s - column "
++            "not present in both tables", pList->a[j].zName);
++          return 1;
++        }
++        addWhereTerm(pList->a[j].zName, pTerm->pTab, pOther->pTab, &p->pWhere);
++      }
++    }
++  }
++  return 0;
++}
++
++/*
++** Delete the given Select structure and all of its substructures.
++*/
++void sqliteSelectDelete(Select *p){
++  if( p==0 ) return;
++  sqliteExprListDelete(p->pEList);
++  sqliteSrcListDelete(p->pSrc);
++  sqliteExprDelete(p->pWhere);
++  sqliteExprListDelete(p->pGroupBy);
++  sqliteExprDelete(p->pHaving);
++  sqliteExprListDelete(p->pOrderBy);
++  sqliteSelectDelete(p->pPrior);
++  sqliteFree(p->zSelect);
++  sqliteFree(p);
++}
++
++/*
++** Delete the aggregate information from the parse structure.
++*/
++static void sqliteAggregateInfoReset(Parse *pParse){
++  sqliteFree(pParse->aAgg);
++  pParse->aAgg = 0;
++  pParse->nAgg = 0;
++  pParse->useAgg = 0;
++}
++
++/*
++** Insert code into "v" that will push the record on the top of the
++** stack into the sorter.
++*/
++static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){
++  char *zSortOrder;
++  int i;
++  zSortOrder = sqliteMalloc( pOrderBy->nExpr + 1 );
++  if( zSortOrder==0 ) return;
++  for(i=0; i<pOrderBy->nExpr; i++){
++    int order = pOrderBy->a[i].sortOrder;
++    int type;
++    int c;
++    if( (order & SQLITE_SO_TYPEMASK)==SQLITE_SO_TEXT ){
++      type = SQLITE_SO_TEXT;
++    }else if( (order & SQLITE_SO_TYPEMASK)==SQLITE_SO_NUM ){
++      type = SQLITE_SO_NUM;
++    }else if( pParse->db->file_format>=4 ){
++      type = sqliteExprType(pOrderBy->a[i].pExpr);
++    }else{
++      type = SQLITE_SO_NUM;
++    }
++    if( (order & SQLITE_SO_DIRMASK)==SQLITE_SO_ASC ){
++      c = type==SQLITE_SO_TEXT ? 'A' : '+';
++    }else{
++      c = type==SQLITE_SO_TEXT ? 'D' : '-';
++    }
++    zSortOrder[i] = c;
++    sqliteExprCode(pParse, pOrderBy->a[i].pExpr);
++  }
++  zSortOrder[pOrderBy->nExpr] = 0;
++  sqliteVdbeOp3(v, OP_SortMakeKey, pOrderBy->nExpr, 0, zSortOrder, P3_DYNAMIC);
++  sqliteVdbeAddOp(v, OP_SortPut, 0, 0);
++}
++
++/*
++** This routine adds a P3 argument to the last VDBE opcode that was
++** inserted. The P3 argument added is a string suitable for the 
++** OP_MakeKey or OP_MakeIdxKey opcodes.  The string consists of
++** characters 't' or 'n' depending on whether or not the various
++** fields of the key to be generated should be treated as numeric
++** or as text.  See the OP_MakeKey and OP_MakeIdxKey opcode
++** documentation for additional information about the P3 string.
++** See also the sqliteAddIdxKeyType() routine.
++*/
++void sqliteAddKeyType(Vdbe *v, ExprList *pEList){
++  int nColumn = pEList->nExpr;
++  char *zType = sqliteMalloc( nColumn+1 );
++  int i;
++  if( zType==0 ) return;
++  for(i=0; i<nColumn; i++){
++    zType[i] = sqliteExprType(pEList->a[i].pExpr)==SQLITE_SO_NUM ? 'n' : 't';
++  }
++  zType[i] = 0;
++  sqliteVdbeChangeP3(v, -1, zType, P3_DYNAMIC);
++}
++
++/*
++** Add code to implement the OFFSET and LIMIT
++*/
++static void codeLimiter(
++  Vdbe *v,          /* Generate code into this VM */
++  Select *p,        /* The SELECT statement being coded */
++  int iContinue,    /* Jump here to skip the current record */
++  int iBreak,       /* Jump here to end the loop */
++  int nPop          /* Number of times to pop stack when jumping */
++){
++  if( p->iOffset>=0 ){
++    int addr = sqliteVdbeCurrentAddr(v) + 2;
++    if( nPop>0 ) addr++;
++    sqliteVdbeAddOp(v, OP_MemIncr, p->iOffset, addr);
++    if( nPop>0 ){
++      sqliteVdbeAddOp(v, OP_Pop, nPop, 0);
++    }
++    sqliteVdbeAddOp(v, OP_Goto, 0, iContinue);
++  }
++  if( p->iLimit>=0 ){
++    sqliteVdbeAddOp(v, OP_MemIncr, p->iLimit, iBreak);
++  }
++}
++
++/*
++** This routine generates the code for the inside of the inner loop
++** of a SELECT.
++**
++** If srcTab and nColumn are both zero, then the pEList expressions
++** are evaluated in order to get the data for this row.  If nColumn>0
++** then data is pulled from srcTab and pEList is used only to get the
++** datatypes for each column.
++*/
++static int selectInnerLoop(
++  Parse *pParse,          /* The parser context */
++  Select *p,              /* The complete select statement being coded */
++  ExprList *pEList,       /* List of values being extracted */
++  int srcTab,             /* Pull data from this table */
++  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 */
++  int iContinue,          /* Jump here to continue with next row */
++  int iBreak              /* Jump here to break out of the inner loop */
++){
++  Vdbe *v = pParse->pVdbe;
++  int i;
++  int hasDistinct;        /* True if the DISTINCT keyword is present */
++
++  if( v==0 ) return 0;
++  assert( pEList!=0 );
++
++  /* If there was a LIMIT clause on the SELECT statement, then do the check
++  ** to see if this row should be output.
++  */
++  hasDistinct = distinct>=0 && pEList && pEList->nExpr>0;
++  if( pOrderBy==0 && !hasDistinct ){
++    codeLimiter(v, p, iContinue, iBreak, 0);
++  }
++
++  /* Pull the requested columns.
++  */
++  if( nColumn>0 ){
++    for(i=0; i<nColumn; i++){
++      sqliteVdbeAddOp(v, OP_Column, srcTab, i);
++    }
++  }else{
++    nColumn = pEList->nExpr;
++    for(i=0; i<pEList->nExpr; i++){
++      sqliteExprCode(pParse, pEList->a[i].pExpr);
++    }
++  }
++
++  /* If the DISTINCT keyword was present on the SELECT statement
++  ** and this row has been seen before, then do not make this row
++  ** part of the result.
++  */
++  if( hasDistinct ){
++#if NULL_ALWAYS_DISTINCT
++    sqliteVdbeAddOp(v, OP_IsNull, -pEList->nExpr, sqliteVdbeCurrentAddr(v)+7);
++#endif
++    sqliteVdbeAddOp(v, OP_MakeKey, pEList->nExpr, 1);
++    if( pParse->db->file_format>=4 ) sqliteAddKeyType(v, pEList);
++    sqliteVdbeAddOp(v, OP_Distinct, distinct, sqliteVdbeCurrentAddr(v)+3);
++    sqliteVdbeAddOp(v, OP_Pop, pEList->nExpr+1, 0);
++    sqliteVdbeAddOp(v, OP_Goto, 0, iContinue);
++    sqliteVdbeAddOp(v, OP_String, 0, 0);
++    sqliteVdbeAddOp(v, OP_PutStrKey, distinct, 0);
++    if( pOrderBy==0 ){
++      codeLimiter(v, p, iContinue, iBreak, nColumn);
++    }
++  }
++
++  switch( eDest ){
++    /* In this mode, write each query result to the key of the temporary
++    ** table iParm.
++    */
++    case SRT_Union: {
++      sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT);
++      sqliteVdbeAddOp(v, OP_String, 0, 0);
++      sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0);
++      break;
++    }
++
++    /* Store the result as data using a unique key.
++    */
++    case SRT_Table:
++    case SRT_TempTable: {
++      sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0);
++      if( pOrderBy ){
++        pushOntoSorter(pParse, v, pOrderBy);
++      }else{
++        sqliteVdbeAddOp(v, OP_NewRecno, iParm, 0);
++        sqliteVdbeAddOp(v, OP_Pull, 1, 0);
++        sqliteVdbeAddOp(v, OP_PutIntKey, iParm, 0);
++      }
++      break;
++    }
++
++    /* Construct a record from the query result, but instead of
++    ** saving that record, use it as a key to delete elements from
++    ** the temporary table iParm.
++    */
++    case SRT_Except: {
++      int addr;
++      addr = sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT);
++      sqliteVdbeAddOp(v, OP_NotFound, iParm, addr+3);
++      sqliteVdbeAddOp(v, OP_Delete, iParm, 0);
++      break;
++    }
++
++    /* If we are creating a set for an "expr IN (SELECT ...)" construct,
++    ** then there should be a single item on the stack.  Write this
++    ** item into the set table with bogus data.
++    */
++    case SRT_Set: {
++      int addr1 = sqliteVdbeCurrentAddr(v);
++      int addr2;
++      assert( nColumn==1 );
++      sqliteVdbeAddOp(v, OP_NotNull, -1, addr1+3);
++      sqliteVdbeAddOp(v, OP_Pop, 1, 0);
++      addr2 = sqliteVdbeAddOp(v, OP_Goto, 0, 0);
++      if( pOrderBy ){
++        pushOntoSorter(pParse, v, pOrderBy);
++      }else{
++        sqliteVdbeAddOp(v, OP_String, 0, 0);
++        sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0);
++      }
++      sqliteVdbeChangeP2(v, addr2, sqliteVdbeCurrentAddr(v));
++      break;
++    }
++
++    /* If this is a scalar select that is part of an expression, then
++    ** store the results in the appropriate memory cell and break out
++    ** of the scan loop.
++    */
++    case SRT_Mem: {
++      assert( nColumn==1 );
++      if( pOrderBy ){
++        pushOntoSorter(pParse, v, pOrderBy);
++      }else{
++        sqliteVdbeAddOp(v, OP_MemStore, iParm, 1);
++        sqliteVdbeAddOp(v, OP_Goto, 0, iBreak);
++      }
++      break;
++    }
++
++    /* Send the data to the callback function.
++    */
++    case SRT_Callback:
++    case SRT_Sorter: {
++      if( pOrderBy ){
++        sqliteVdbeAddOp(v, OP_SortMakeRec, nColumn, 0);
++        pushOntoSorter(pParse, v, pOrderBy);
++      }else{
++        assert( eDest==SRT_Callback );
++        sqliteVdbeAddOp(v, OP_Callback, nColumn, 0);
++      }
++      break;
++    }
++
++    /* Invoke a subroutine to handle the results.  The subroutine itself
++    ** is responsible for popping the results off of the stack.
++    */
++    case SRT_Subroutine: {
++      if( pOrderBy ){
++        sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0);
++        pushOntoSorter(pParse, v, pOrderBy);
++      }else{
++        sqliteVdbeAddOp(v, OP_Gosub, 0, iParm);
++      }
++      break;
++    }
++
++    /* Discard the results.  This is used for SELECT statements inside
++    ** the body of a TRIGGER.  The purpose of such selects is to call
++    ** user-defined functions that have side effects.  We do not care
++    ** about the actual results of the select.
++    */
++    default: {
++      assert( eDest==SRT_Discard );
++      sqliteVdbeAddOp(v, OP_Pop, nColumn, 0);
++      break;
++    }
++  }
++  return 0;
++}
++
++/*
++** If the inner loop was generated using a non-null pOrderBy argument,
++** then the results were placed in a sorter.  After the loop is terminated
++** we need to run the sorter and output the results.  The following
++** routine generates the code needed to do that.
++*/
++static void generateSortTail(
++  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 */
++){
++  int end1 = sqliteVdbeMakeLabel(v);
++  int end2 = sqliteVdbeMakeLabel(v);
++  int addr;
++  if( eDest==SRT_Sorter ) return;
++  sqliteVdbeAddOp(v, OP_Sort, 0, 0);
++  addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end1);
++  codeLimiter(v, p, addr, end2, 1);
++  switch( eDest ){
++    case SRT_Callback: {
++      sqliteVdbeAddOp(v, OP_SortCallback, nColumn, 0);
++      break;
++    }
++    case SRT_Table:
++    case SRT_TempTable: {
++      sqliteVdbeAddOp(v, OP_NewRecno, iParm, 0);
++      sqliteVdbeAddOp(v, OP_Pull, 1, 0);
++      sqliteVdbeAddOp(v, OP_PutIntKey, iParm, 0);
++      break;
++    }
++    case SRT_Set: {
++      assert( nColumn==1 );
++      sqliteVdbeAddOp(v, OP_NotNull, -1, sqliteVdbeCurrentAddr(v)+3);
++      sqliteVdbeAddOp(v, OP_Pop, 1, 0);
++      sqliteVdbeAddOp(v, OP_Goto, 0, sqliteVdbeCurrentAddr(v)+3);
++      sqliteVdbeAddOp(v, OP_String, 0, 0);
++      sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0);
++      break;
++    }
++    case SRT_Mem: {
++      assert( nColumn==1 );
++      sqliteVdbeAddOp(v, OP_MemStore, iParm, 1);
++      sqliteVdbeAddOp(v, OP_Goto, 0, end1);
++      break;
++    }
++    case SRT_Subroutine: {
++      int i;
++      for(i=0; i<nColumn; i++){
++        sqliteVdbeAddOp(v, OP_Column, -1-i, i);
++      }
++      sqliteVdbeAddOp(v, OP_Gosub, 0, iParm);
++      sqliteVdbeAddOp(v, OP_Pop, 1, 0);
++      break;
++    }
++    default: {
++      /* Do nothing */
++      break;
++    }
++  }
++  sqliteVdbeAddOp(v, OP_Goto, 0, addr);
++  sqliteVdbeResolveLabel(v, end2);
++  sqliteVdbeAddOp(v, OP_Pop, 1, 0);
++  sqliteVdbeResolveLabel(v, end1);
++  sqliteVdbeAddOp(v, OP_SortReset, 0, 0);
++}
++
++/*
++** Generate code that will tell the VDBE the datatypes of
++** columns in the result set.
++**
++** This routine only generates code if the "PRAGMA show_datatypes=on"
++** has been executed.  The datatypes are reported out in the azCol
++** parameter to the callback function.  The first N azCol[] entries
++** are the names of the columns, and the second N entries are the
++** datatypes for the columns.
++**
++** The "datatype" for a result that is a column of a type is the
++** datatype definition extracted from the CREATE TABLE statement.
++** The datatype for an expression is either TEXT or NUMERIC.  The
++** datatype for a ROWID field is INTEGER.
++*/
++static void generateColumnTypes(
++  Parse *pParse,      /* Parser context */
++  SrcList *pTabList,  /* List of tables */
++  ExprList *pEList    /* Expressions defining the result set */
++){
++  Vdbe *v = pParse->pVdbe;
++  int i, j;
++  for(i=0; i<pEList->nExpr; i++){
++    Expr *p = pEList->a[i].pExpr;
++    char *zType = 0;
++    if( p==0 ) continue;
++    if( p->op==TK_COLUMN && pTabList ){
++      Table *pTab;
++      int iCol = p->iColumn;
++      for(j=0; j<pTabList->nSrc && pTabList->a[j].iCursor!=p->iTable; j++){}
++      assert( j<pTabList->nSrc );
++      pTab = pTabList->a[j].pTab;
++      if( iCol<0 ) iCol = pTab->iPKey;
++      assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
++      if( iCol<0 ){
++        zType = "INTEGER";
++      }else{
++        zType = pTab->aCol[iCol].zType;
++      }
++    }else{
++      if( sqliteExprType(p)==SQLITE_SO_TEXT ){
++        zType = "TEXT";
++      }else{
++        zType = "NUMERIC";
++      }
++    }
++    sqliteVdbeOp3(v, OP_ColumnName, i + pEList->nExpr, 0, zType, 0);
++  }
++}
++
++/*
++** Generate code that will tell the VDBE the names of columns
++** in the result set.  This information is used to provide the
++** azCol[] values in the callback.
++*/
++static void generateColumnNames(
++  Parse *pParse,      /* Parser context */
++  SrcList *pTabList,  /* List of tables */
++  ExprList *pEList    /* Expressions defining the result set */
++){
++  Vdbe *v = pParse->pVdbe;
++  int i, j;
++  sqlite *db = pParse->db;
++  int fullNames, shortNames;
++
++  assert( v!=0 );
++  if( pParse->colNamesSet || v==0 || sqlite_malloc_failed ) return;
++  pParse->colNamesSet = 1;
++  fullNames = (db->flags & SQLITE_FullColNames)!=0;
++  shortNames = (db->flags & SQLITE_ShortColNames)!=0;
++  for(i=0; i<pEList->nExpr; i++){
++    Expr *p;
++    int p2 = i==pEList->nExpr-1;
++    p = pEList->a[i].pExpr;
++    if( p==0 ) continue;
++    if( pEList->a[i].zName ){
++      char *zName = pEList->a[i].zName;
++      sqliteVdbeOp3(v, OP_ColumnName, i, p2, zName, 0);
++      continue;
++    }
++    if( p->op==TK_COLUMN && pTabList ){
++      Table *pTab;
++      char *zCol;
++      int iCol = p->iColumn;
++      for(j=0; j<pTabList->nSrc && pTabList->a[j].iCursor!=p->iTable; j++){}
++      assert( j<pTabList->nSrc );
++      pTab = pTabList->a[j].pTab;
++      if( iCol<0 ) iCol = pTab->iPKey;
++      assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
++      if( iCol<0 ){
++        zCol = "_ROWID_";
++      }else{
++        zCol = pTab->aCol[iCol].zName;
++      }
++      if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){
++        int addr = sqliteVdbeOp3(v,OP_ColumnName, i, p2, p->span.z, p->span.n);
++        sqliteVdbeCompressSpace(v, addr);
++      }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){
++        char *zName = 0;
++        char *zTab;
++ 
++        zTab = pTabList->a[j].zAlias;
++        if( fullNames || zTab==0 ) zTab = pTab->zName;
++        sqliteSetString(&zName, zTab, ".", zCol, 0);
++        sqliteVdbeOp3(v, OP_ColumnName, i, p2, zName, P3_DYNAMIC);
++      }else{
++        sqliteVdbeOp3(v, OP_ColumnName, i, p2, zCol, 0);
++      }
++    }else if( p->span.z && p->span.z[0] ){
++      int addr = sqliteVdbeOp3(v,OP_ColumnName, i, p2, p->span.z, p->span.n);
++      sqliteVdbeCompressSpace(v, addr);
++    }else{
++      char zName[30];
++      assert( p->op!=TK_COLUMN || pTabList==0 );
++      sprintf(zName, "column%d", i+1);
++      sqliteVdbeOp3(v, OP_ColumnName, i, p2, zName, 0);
++    }
++  }
++}
++
++/*
++** Name of the connection operator, used for error messages.
++*/
++static const char *selectOpName(int id){
++  char *z;
++  switch( id ){
++    case TK_ALL:       z = "UNION ALL";   break;
++    case TK_INTERSECT: z = "INTERSECT";   break;
++    case TK_EXCEPT:    z = "EXCEPT";      break;
++    default:           z = "UNION";       break;
++  }
++  return z;
++}
++
++/*
++** Forward declaration
++*/
++static int fillInColumnList(Parse*, Select*);
++
++/*
++** Given a SELECT statement, generate a Table structure that describes
++** the result set of that SELECT.
++*/
++Table *sqliteResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
++  Table *pTab;
++  int i, j;
++  ExprList *pEList;
++  Column *aCol;
++
++  if( fillInColumnList(pParse, pSelect) ){
++    return 0;
++  }
++  pTab = sqliteMalloc( sizeof(Table) );
++  if( pTab==0 ){
++    return 0;
++  }
++  pTab->zName = zTabName ? sqliteStrDup(zTabName) : 0;
++  pEList = pSelect->pEList;
++  pTab->nCol = pEList->nExpr;
++  assert( pTab->nCol>0 );
++  pTab->aCol = aCol = sqliteMalloc( sizeof(pTab->aCol[0])*pTab->nCol );
++  for(i=0; i<pTab->nCol; i++){
++    Expr *p, *pR;
++    if( pEList->a[i].zName ){
++      aCol[i].zName = sqliteStrDup(pEList->a[i].zName);
++    }else if( (p=pEList->a[i].pExpr)->op==TK_DOT 
++               && (pR=p->pRight)!=0 && pR->token.z && pR->token.z[0] ){
++      int cnt;
++      sqliteSetNString(&aCol[i].zName, pR->token.z, pR->token.n, 0);
++      for(j=cnt=0; j<i; j++){
++        if( sqliteStrICmp(aCol[j].zName, aCol[i].zName)==0 ){
++          int n;
++          char zBuf[30];
++          sprintf(zBuf,"_%d",++cnt);
++          n = strlen(zBuf);
++          sqliteSetNString(&aCol[i].zName, pR->token.z, pR->token.n, zBuf, n,0);
++          j = -1;
++        }
++      }
++    }else if( p->span.z && p->span.z[0] ){
++      sqliteSetNString(&pTab->aCol[i].zName, p->span.z, p->span.n, 0);
++    }else{
++      char zBuf[30];
++      sprintf(zBuf, "column%d", i+1);
++      aCol[i].zName = sqliteStrDup(zBuf);
++    }
++    sqliteDequote(aCol[i].zName);
++  }
++  pTab->iPKey = -1;
++  return pTab;
++}
++
++/*
++** For the given SELECT statement, do three things.
++**
++**    (1)  Fill in the pTabList->a[].pTab fields in the SrcList that 
++**         defines the set of tables that should be scanned.  For views,
++**         fill pTabList->a[].pSelect with a copy of the SELECT statement
++**         that implements the view.  A copy is made of the view's SELECT
++**         statement so that we can freely modify or delete that statement
++**         without worrying about messing up the presistent representation
++**         of the view.
++**
++**    (2)  Add terms to the WHERE clause to accomodate the NATURAL keyword
++**         on joins and the ON and USING clause of joins.
++**
++**    (3)  Scan the list of columns in the result set (pEList) looking
++**         for instances of the "*" operator or the TABLE.* operator.
++**         If found, expand each "*" to be every column in every table
++**         and TABLE.* to be every column in TABLE.
++**
++** Return 0 on success.  If there are problems, leave an error message
++** in pParse and return non-zero.
++*/
++static int fillInColumnList(Parse *pParse, Select *p){
++  int i, j, k, rc;
++  SrcList *pTabList;
++  ExprList *pEList;
++  Table *pTab;
++
++  if( p==0 || p->pSrc==0 ) return 1;
++  pTabList = p->pSrc;
++  pEList = p->pEList;
++
++  /* Look up every table in the table list.
++  */
++  for(i=0; i<pTabList->nSrc; i++){
++    if( pTabList->a[i].pTab ){
++      /* This routine has run before!  No need to continue */
++      return 0;
++    }
++    if( pTabList->a[i].zName==0 ){
++      /* A sub-query in the FROM clause of a SELECT */
++      assert( pTabList->a[i].pSelect!=0 );
++      if( pTabList->a[i].zAlias==0 ){
++        char zFakeName[60];
++        sprintf(zFakeName, "sqlite_subquery_%p_",
++           (void*)pTabList->a[i].pSelect);
++        sqliteSetString(&pTabList->a[i].zAlias, zFakeName, 0);
++      }
++      pTabList->a[i].pTab = pTab = 
++        sqliteResultSetOfSelect(pParse, pTabList->a[i].zAlias,
++                                        pTabList->a[i].pSelect);
++      if( pTab==0 ){
++        return 1;
++      }
++      /* The isTransient flag indicates that the Table structure has been
++      ** dynamically allocated and may be freed at any time.  In other words,
++      ** pTab is not pointing to a persistent table structure that defines
++      ** part of the schema. */
++      pTab->isTransient = 1;
++    }else{
++      /* An ordinary table or view name in the FROM clause */
++      pTabList->a[i].pTab = pTab = 
++        sqliteLocateTable(pParse,pTabList->a[i].zName,pTabList->a[i].zDatabase);
++      if( pTab==0 ){
++        return 1;
++      }
++      if( pTab->pSelect ){
++        /* We reach here if the named table is a really a view */
++        if( sqliteViewGetColumnNames(pParse, pTab) ){
++          return 1;
++        }
++        /* If pTabList->a[i].pSelect!=0 it means we are dealing with a
++        ** view within a view.  The SELECT structure has already been
++        ** copied by the outer view so we can skip the copy step here
++        ** in the inner view.
++        */
++        if( pTabList->a[i].pSelect==0 ){
++          pTabList->a[i].pSelect = sqliteSelectDup(pTab->pSelect);
++        }
++      }
++    }
++  }
++
++  /* Process NATURAL keywords, and ON and USING clauses of joins.
++  */
++  if( sqliteProcessJoin(pParse, p) ) return 1;
++
++  /* For every "*" that occurs in the column list, insert the names of
++  ** all columns in all tables.  And for every TABLE.* insert the names
++  ** of all columns in TABLE.  The parser inserted a special expression
++  ** with the TK_ALL operator for each "*" that it found in the column list.
++  ** The following code just has to locate the TK_ALL expressions and expand
++  ** each one to the list of all columns in all tables.
++  **
++  ** The first loop just checks to see if there are any "*" operators
++  ** that need expanding.
++  */
++  for(k=0; k<pEList->nExpr; k++){
++    Expr *pE = pEList->a[k].pExpr;
++    if( pE->op==TK_ALL ) break;
++    if( pE->op==TK_DOT && pE->pRight && pE->pRight->op==TK_ALL
++         && pE->pLeft && pE->pLeft->op==TK_ID ) break;
++  }
++  rc = 0;
++  if( k<pEList->nExpr ){
++    /*
++    ** If we get here it means the result set contains one or more "*"
++    ** operators that need to be expanded.  Loop through each expression
++    ** in the result set and expand them one by one.
++    */
++    struct ExprList_item *a = pEList->a;
++    ExprList *pNew = 0;
++    for(k=0; k<pEList->nExpr; k++){
++      Expr *pE = a[k].pExpr;
++      if( pE->op!=TK_ALL &&
++           (pE->op!=TK_DOT || pE->pRight==0 || pE->pRight->op!=TK_ALL) ){
++        /* This particular expression does not need to be expanded.
++        */
++        pNew = sqliteExprListAppend(pNew, a[k].pExpr, 0);
++        pNew->a[pNew->nExpr-1].zName = a[k].zName;
++        a[k].pExpr = 0;
++        a[k].zName = 0;
++      }else{
++        /* This expression is a "*" or a "TABLE.*" and needs to be
++        ** expanded. */
++        int tableSeen = 0;      /* Set to 1 when TABLE matches */
++        char *zTName;           /* text of name of TABLE */
++        if( pE->op==TK_DOT && pE->pLeft ){
++          zTName = sqliteTableNameFromToken(&pE->pLeft->token);
++        }else{
++          zTName = 0;
++        }
++        for(i=0; i<pTabList->nSrc; i++){
++          Table *pTab = pTabList->a[i].pTab;
++          char *zTabName = pTabList->a[i].zAlias;
++          if( zTabName==0 || zTabName[0]==0 ){ 
++            zTabName = pTab->zName;
++          }
++          if( zTName && (zTabName==0 || zTabName[0]==0 || 
++                 sqliteStrICmp(zTName, zTabName)!=0) ){
++            continue;
++          }
++          tableSeen = 1;
++          for(j=0; j<pTab->nCol; j++){
++            Expr *pExpr, *pLeft, *pRight;
++            char *zName = pTab->aCol[j].zName;
++
++            if( i>0 && (pTabList->a[i-1].jointype & JT_NATURAL)!=0 &&
++                columnIndex(pTabList->a[i-1].pTab, zName)>=0 ){
++              /* In a NATURAL join, omit the join columns from the 
++              ** table on the right */
++              continue;
++            }
++            if( i>0 && sqliteIdListIndex(pTabList->a[i-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 = sqliteExpr(TK_ID, 0, 0, 0);
++            if( pRight==0 ) break;
++            pRight->token.z = zName;
++            pRight->token.n = strlen(zName);
++            pRight->token.dyn = 0;
++            if( zTabName && pTabList->nSrc>1 ){
++              pLeft = sqliteExpr(TK_ID, 0, 0, 0);
++              pExpr = sqliteExpr(TK_DOT, pLeft, pRight, 0);
++              if( pExpr==0 ) break;
++              pLeft->token.z = zTabName;
++              pLeft->token.n = strlen(zTabName);
++              pLeft->token.dyn = 0;
++              sqliteSetString((char**)&pExpr->span.z, zTabName, ".", zName, 0);
++              pExpr->span.n = strlen(pExpr->span.z);
++              pExpr->span.dyn = 1;
++              pExpr->token.z = 0;
++              pExpr->token.n = 0;
++              pExpr->token.dyn = 0;
++            }else{
++              pExpr = pRight;
++              pExpr->span = pExpr->token;
++            }
++            pNew = sqliteExprListAppend(pNew, pExpr, 0);
++          }
++        }
++        if( !tableSeen ){
++          if( zTName ){
++            sqliteErrorMsg(pParse, "no such table: %s", zTName);
++          }else{
++            sqliteErrorMsg(pParse, "no tables specified");
++          }
++          rc = 1;
++        }
++        sqliteFree(zTName);
++      }
++    }
++    sqliteExprListDelete(pEList);
++    p->pEList = pNew;
++  }
++  return rc;
++}
++
++/*
++** This routine recursively unlinks the Select.pSrc.a[].pTab pointers
++** in a select structure.  It just sets the pointers to NULL.  This
++** routine is recursive in the sense that if the Select.pSrc.a[].pSelect
++** pointer is not NULL, this routine is called recursively on that pointer.
++**
++** This routine is called on the Select structure that defines a
++** VIEW in order to undo any bindings to tables.  This is necessary
++** because those tables might be DROPed by a subsequent SQL command.
++** If the bindings are not removed, then the Select.pSrc->a[].pTab field
++** will be left pointing to a deallocated Table structure after the
++** DROP and a coredump will occur the next time the VIEW is used.
++*/
++void sqliteSelectUnbind(Select *p){
++  int i;
++  SrcList *pSrc = p->pSrc;
++  Table *pTab;
++  if( p==0 ) return;
++  for(i=0; i<pSrc->nSrc; i++){
++    if( (pTab = pSrc->a[i].pTab)!=0 ){
++      if( pTab->isTransient ){
++        sqliteDeleteTable(0, pTab);
++      }
++      pSrc->a[i].pTab = 0;
++      if( pSrc->a[i].pSelect ){
++        sqliteSelectUnbind(pSrc->a[i].pSelect);
++      }
++    }
++  }
++}
++
++/*
++** 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.
++**
++** If there are prior SELECT clauses, they are processed first.  A match
++** in an earlier SELECT takes precedence over a later SELECT.
++**
++** Any entry that does not match is flagged as an error.  The number
++** of errors is returned.
++**
++** This routine does NOT correctly initialize the Expr.dataType  field
++** of the ORDER BY expressions.  The multiSelectSortOrder() routine
++** must be called to do that after the individual select statements
++** have all been analyzed.  This routine is unable to compute Expr.dataType
++** because it must be called before the individual select statements
++** have been analyzed.
++*/
++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 */
++){
++  int nErr = 0;
++  int i, j;
++  ExprList *pEList;
++
++  if( pSelect==0 || pOrderBy==0 ) return 1;
++  if( mustComplete ){
++    for(i=0; i<pOrderBy->nExpr; i++){ pOrderBy->a[i].done = 0; }
++  }
++  if( fillInColumnList(pParse, pSelect) ){
++    return 1;
++  }
++  if( pSelect->pPrior ){
++    if( matchOrderbyToColumn(pParse, pSelect->pPrior, pOrderBy, iTable, 0) ){
++      return 1;
++    }
++  }
++  pEList = pSelect->pEList;
++  for(i=0; i<pOrderBy->nExpr; i++){
++    Expr *pE = pOrderBy->a[i].pExpr;
++    int iCol = -1;
++    if( pOrderBy->a[i].done ) continue;
++    if( sqliteExprIsInteger(pE, &iCol) ){
++      if( iCol<=0 || iCol>pEList->nExpr ){
++        sqliteErrorMsg(pParse,
++          "ORDER BY position %d should be between 1 and %d",
++          iCol, pEList->nExpr);
++        nErr++;
++        break;
++      }
++      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;
++        assert( pE->token.z );
++        zLabel = sqliteStrNDup(pE->token.z, pE->token.n);
++        sqliteDequote(zLabel);
++        if( sqliteStrICmp(zName, zLabel)==0 ){ 
++          iCol = j;
++        }
++        sqliteFree(zLabel);
++      }
++      if( iCol<0 && sqliteExprCompare(pE, pEList->a[j].pExpr) ){
++        iCol = j;
++      }
++    }
++    if( iCol>=0 ){
++      pE->op = TK_COLUMN;
++      pE->iColumn = iCol;
++      pE->iTable = iTable;
++      pOrderBy->a[i].done = 1;
++    }
++    if( iCol<0 && mustComplete ){
++      sqliteErrorMsg(pParse,
++        "ORDER BY term number %d does not match any result column", i+1);
++      nErr++;
++      break;
++    }
++  }
++  return nErr;  
++}
++
++/*
++** Get a VDBE for the given parser context.  Create a new one if necessary.
++** If an error occurs, return NULL and leave a message in pParse.
++*/
++Vdbe *sqliteGetVdbe(Parse *pParse){
++  Vdbe *v = pParse->pVdbe;
++  if( v==0 ){
++    v = pParse->pVdbe = sqliteVdbeCreate(pParse->db);
++  }
++  return v;
++}
++
++/*
++** This routine sets the Expr.dataType field on all elements of
++** the pOrderBy expression list.  The pOrderBy list will have been
++** set up by matchOrderbyToColumn().  Hence each expression has
++** a TK_COLUMN as its root node.  The Expr.iColumn refers to a 
++** column in the result set.   The datatype is set to SQLITE_SO_TEXT
++** if the corresponding column in p and every SELECT to the left of
++** p has a datatype of SQLITE_SO_TEXT.  If the cooressponding column
++** in p or any of the left SELECTs is SQLITE_SO_NUM, then the datatype
++** of the order-by expression is set to SQLITE_SO_NUM.
++**
++** Examples:
++**
++**     CREATE TABLE one(a INTEGER, b TEXT);
++**     CREATE TABLE two(c VARCHAR(5), d FLOAT);
++**
++**     SELECT b, b FROM one UNION SELECT d, c FROM two ORDER BY 1, 2;
++**
++** The primary sort key will use SQLITE_SO_NUM because the "d" in
++** the second SELECT is numeric.  The 1st column of the first SELECT
++** is text but that does not matter because a numeric always overrides
++** a text.
++**
++** The secondary key will use the SQLITE_SO_TEXT sort order because
++** both the (second) "b" in the first SELECT and the "c" in the second
++** SELECT have a datatype of text.
++*/ 
++static void multiSelectSortOrder(Select *p, ExprList *pOrderBy){
++  int i;
++  ExprList *pEList;
++  if( pOrderBy==0 ) return;
++  if( p==0 ){
++    for(i=0; i<pOrderBy->nExpr; i++){
++      pOrderBy->a[i].pExpr->dataType = SQLITE_SO_TEXT;
++    }
++    return;
++  }
++  multiSelectSortOrder(p->pPrior, pOrderBy);
++  pEList = p->pEList;
++  for(i=0; i<pOrderBy->nExpr; i++){
++    Expr *pE = pOrderBy->a[i].pExpr;
++    if( pE->dataType==SQLITE_SO_NUM ) continue;
++    assert( pE->iColumn>=0 );
++    if( pEList->nExpr>pE->iColumn ){
++      pE->dataType = sqliteExprType(pEList->a[pE->iColumn].pExpr);
++    }
++  }
++}
++
++/*
++** Compute the iLimit and iOffset fields of the SELECT based on the
++** nLimit and nOffset fields.  nLimit and nOffset hold the integers
++** that appear in the original SQL statement after the LIMIT and OFFSET
++** keywords.  Or that hold -1 and 0 if those keywords are omitted.
++** iLimit and iOffset are the integer memory register numbers for
++** counters used to compute the limit and offset.  If there is no
++** limit and/or offset, then iLimit and iOffset are negative.
++**
++** This routine changes the values if iLimit and iOffset only if
++** a limit or offset is defined by nLimit and nOffset.  iLimit and
++** iOffset should have been preset to appropriate default values
++** (usually but not always -1) prior to calling this routine.
++** Only if nLimit>=0 or nOffset>0 do the limit registers get
++** redefined.  The UNION ALL operator uses this property to force
++** the reuse of the same limit and offset registers across multiple
++** SELECT statements.
++*/
++static void computeLimitRegisters(Parse *pParse, Select *p){
++  /* 
++  ** If the comparison is p->nLimit>0 then "LIMIT 0" shows
++  ** all rows.  It is the same as no limit. If the comparision is
++  ** p->nLimit>=0 then "LIMIT 0" show no rows at all.
++  ** "LIMIT -1" always shows all rows.  There is some
++  ** contraversy about what the correct behavior should be.
++  ** The current implementation interprets "LIMIT 0" to mean
++  ** no rows.
++  */
++  if( p->nLimit>=0 ){
++    int iMem = pParse->nMem++;
++    Vdbe *v = sqliteGetVdbe(pParse);
++    if( v==0 ) return;
++    sqliteVdbeAddOp(v, OP_Integer, -p->nLimit, 0);
++    sqliteVdbeAddOp(v, OP_MemStore, iMem, 1);
++    p->iLimit = iMem;
++  }
++  if( p->nOffset>0 ){
++    int iMem = pParse->nMem++;
++    Vdbe *v = sqliteGetVdbe(pParse);
++    if( v==0 ) return;
++    sqliteVdbeAddOp(v, OP_Integer, -p->nOffset, 0);
++    sqliteVdbeAddOp(v, OP_MemStore, iMem, 1);
++    p->iOffset = iMem;
++  }
++}
++
++/*
++** This routine is called to process a query that is really the union
++** or intersection of two or more separate queries.
++**
++** "p" points to the right-most of the two queries.  the query on the
++** left is p->pPrior.  The left query could also be a compound query
++** in which case this routine will be called recursively. 
++**
++** The results of the total query are to be written into a destination
++** of type eDest with parameter iParm.
++**
++** Example 1:  Consider a three-way compound SQL statement.
++**
++**     SELECT a FROM t1 UNION SELECT b FROM t2 UNION SELECT c FROM t3
++**
++** This statement is parsed up as follows:
++**
++**     SELECT c FROM t3
++**      |
++**      `----->  SELECT b FROM t2
++**                |
++**                `------>  SELECT a FROM t1
++**
++** The arrows in the diagram above represent the Select.pPrior pointer.
++** So if this routine is called with p equal to the t3 query, then
++** pPrior will be the t2 query.  p->op will be TK_UNION in this case.
++**
++** Notice that because of the way SQLite parses compound SELECTs, the
++** individual selects always group from left to right.
++*/
++static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
++  int rc;             /* Success code from a subroutine */
++  Select *pPrior;     /* Another SELECT immediately to our left */
++  Vdbe *v;            /* Generate code to this VDBE */
++
++  /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs.  Only
++  ** the last SELECT in the series may have an ORDER BY or LIMIT.
++  */
++  if( p==0 || p->pPrior==0 ) return 1;
++  pPrior = p->pPrior;
++  if( pPrior->pOrderBy ){
++    sqliteErrorMsg(pParse,"ORDER BY clause should come after %s not before",
++      selectOpName(p->op));
++    return 1;
++  }
++  if( pPrior->nLimit>=0 || pPrior->nOffset>0 ){
++    sqliteErrorMsg(pParse,"LIMIT clause should come after %s not before",
++      selectOpName(p->op));
++    return 1;
++  }
++
++  /* Make sure we have a valid query engine.  If not, create a new one.
++  */
++  v = sqliteGetVdbe(pParse);
++  if( v==0 ) return 1;
++
++  /* Create the destination temporary table if necessary
++  */
++  if( eDest==SRT_TempTable ){
++    sqliteVdbeAddOp(v, OP_OpenTemp, iParm, 0);
++    eDest = SRT_Table;
++  }
++
++  /* Generate code for the left and right SELECT statements.
++  */
++  switch( p->op ){
++    case TK_ALL: {
++      if( p->pOrderBy==0 ){
++        pPrior->nLimit = p->nLimit;
++        pPrior->nOffset = p->nOffset;
++        rc = sqliteSelect(pParse, pPrior, eDest, iParm, 0, 0, 0);
++        if( rc ) return rc;
++        p->pPrior = 0;
++        p->iLimit = pPrior->iLimit;
++        p->iOffset = pPrior->iOffset;
++        p->nLimit = -1;
++        p->nOffset = 0;
++        rc = sqliteSelect(pParse, p, eDest, iParm, 0, 0, 0);
++        p->pPrior = pPrior;
++        if( rc ) return rc;
++        break;
++      }
++      /* For UNION ALL ... ORDER BY fall through to the next case */
++    }
++    case TK_EXCEPT:
++    case TK_UNION: {
++      int unionTab;    /* Cursor number of the temporary table holding result */
++      int op;          /* One of the SRT_ operations to apply to self */
++      int priorOp;     /* The SRT_ operation to apply to prior selects */
++      int nLimit, nOffset; /* Saved values of p->nLimit and p->nOffset */
++      ExprList *pOrderBy;  /* The ORDER BY clause for the right SELECT */
++
++      priorOp = p->op==TK_ALL ? SRT_Table : SRT_Union;
++      if( eDest==priorOp && p->pOrderBy==0 && p->nLimit<0 && p->nOffset==0 ){
++        /* We can reuse a temporary table generated by a SELECT to our
++        ** right.
++        */
++        unionTab = iParm;
++      }else{
++        /* We will need to create our own temporary table to hold the
++        ** intermediate results.
++        */
++        unionTab = pParse->nTab++;
++        if( p->pOrderBy 
++        && matchOrderbyToColumn(pParse, p, p->pOrderBy, unionTab, 1) ){
++          return 1;
++        }
++        if( p->op!=TK_ALL ){
++          sqliteVdbeAddOp(v, OP_OpenTemp, unionTab, 1);
++          sqliteVdbeAddOp(v, OP_KeyAsData, unionTab, 1);
++        }else{
++          sqliteVdbeAddOp(v, OP_OpenTemp, unionTab, 0);
++        }
++      }
++
++      /* Code the SELECT statements to our left
++      */
++      rc = sqliteSelect(pParse, pPrior, priorOp, unionTab, 0, 0, 0);
++      if( rc ) return rc;
++
++      /* Code the current SELECT statement
++      */
++      switch( p->op ){
++         case TK_EXCEPT:  op = SRT_Except;   break;
++         case TK_UNION:   op = SRT_Union;    break;
++         case TK_ALL:     op = SRT_Table;    break;
++      }
++      p->pPrior = 0;
++      pOrderBy = p->pOrderBy;
++      p->pOrderBy = 0;
++      nLimit = p->nLimit;
++      p->nLimit = -1;
++      nOffset = p->nOffset;
++      p->nOffset = 0;
++      rc = sqliteSelect(pParse, p, op, unionTab, 0, 0, 0);
++      p->pPrior = pPrior;
++      p->pOrderBy = pOrderBy;
++      p->nLimit = nLimit;
++      p->nOffset = nOffset;
++      if( rc ) return rc;
++
++      /* Convert the data in the temporary table into whatever form
++      ** it is that we currently need.
++      */      
++      if( eDest!=priorOp || unionTab!=iParm ){
++        int iCont, iBreak, iStart;
++        assert( p->pEList );
++        if( eDest==SRT_Callback ){
++          generateColumnNames(pParse, 0, p->pEList);
++          generateColumnTypes(pParse, p->pSrc, p->pEList);
++        }
++        iBreak = sqliteVdbeMakeLabel(v);
++        iCont = sqliteVdbeMakeLabel(v);
++        sqliteVdbeAddOp(v, OP_Rewind, unionTab, iBreak);
++        computeLimitRegisters(pParse, p);
++        iStart = sqliteVdbeCurrentAddr(v);
++        multiSelectSortOrder(p, p->pOrderBy);
++        rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,
++                             p->pOrderBy, -1, eDest, iParm, 
++                             iCont, iBreak);
++        if( rc ) return 1;
++        sqliteVdbeResolveLabel(v, iCont);
++        sqliteVdbeAddOp(v, OP_Next, unionTab, iStart);
++        sqliteVdbeResolveLabel(v, iBreak);
++        sqliteVdbeAddOp(v, OP_Close, unionTab, 0);
++        if( p->pOrderBy ){
++          generateSortTail(p, v, p->pEList->nExpr, eDest, iParm);
++        }
++      }
++      break;
++    }
++    case TK_INTERSECT: {
++      int tab1, tab2;
++      int iCont, iBreak, iStart;
++      int nLimit, nOffset;
++
++      /* INTERSECT is different from the others since it requires
++      ** two temporary tables.  Hence it has its own case.  Begin
++      ** by allocating the tables we will need.
++      */
++      tab1 = pParse->nTab++;
++      tab2 = pParse->nTab++;
++      if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){
++        return 1;
++      }
++      sqliteVdbeAddOp(v, OP_OpenTemp, tab1, 1);
++      sqliteVdbeAddOp(v, OP_KeyAsData, tab1, 1);
++
++      /* Code the SELECTs to our left into temporary table "tab1".
++      */
++      rc = sqliteSelect(pParse, pPrior, SRT_Union, tab1, 0, 0, 0);
++      if( rc ) return rc;
++
++      /* Code the current SELECT into temporary table "tab2"
++      */
++      sqliteVdbeAddOp(v, OP_OpenTemp, tab2, 1);
++      sqliteVdbeAddOp(v, OP_KeyAsData, tab2, 1);
++      p->pPrior = 0;
++      nLimit = p->nLimit;
++      p->nLimit = -1;
++      nOffset = p->nOffset;
++      p->nOffset = 0;
++      rc = sqliteSelect(pParse, p, SRT_Union, tab2, 0, 0, 0);
++      p->pPrior = pPrior;
++      p->nLimit = nLimit;
++      p->nOffset = nOffset;
++      if( rc ) return rc;
++
++      /* Generate code to take the intersection of the two temporary
++      ** tables.
++      */
++      assert( p->pEList );
++      if( eDest==SRT_Callback ){
++        generateColumnNames(pParse, 0, p->pEList);
++        generateColumnTypes(pParse, p->pSrc, p->pEList);
++      }
++      iBreak = sqliteVdbeMakeLabel(v);
++      iCont = sqliteVdbeMakeLabel(v);
++      sqliteVdbeAddOp(v, OP_Rewind, tab1, iBreak);
++      computeLimitRegisters(pParse, p);
++      iStart = sqliteVdbeAddOp(v, OP_FullKey, tab1, 0);
++      sqliteVdbeAddOp(v, OP_NotFound, tab2, iCont);
++      multiSelectSortOrder(p, p->pOrderBy);
++      rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
++                             p->pOrderBy, -1, eDest, iParm, 
++                             iCont, iBreak);
++      if( rc ) return 1;
++      sqliteVdbeResolveLabel(v, iCont);
++      sqliteVdbeAddOp(v, OP_Next, tab1, iStart);
++      sqliteVdbeResolveLabel(v, iBreak);
++      sqliteVdbeAddOp(v, OP_Close, tab2, 0);
++      sqliteVdbeAddOp(v, OP_Close, tab1, 0);
++      if( p->pOrderBy ){
++        generateSortTail(p, v, p->pEList->nExpr, eDest, iParm);
++      }
++      break;
++    }
++  }
++  assert( p->pEList && pPrior->pEList );
++  if( p->pEList->nExpr!=pPrior->pEList->nExpr ){
++    sqliteErrorMsg(pParse, "SELECTs to the left and right of %s"
++      " do not have the same number of result columns", selectOpName(p->op));
++    return 1;
++  }
++  return 0;
++}
++
++/*
++** Scan through the expression pExpr.  Replace every reference to
++** a column in table number iTable with a copy of the iColumn-th
++** entry in pEList.  (But leave references to the ROWID column 
++** unchanged.)
++**
++** This routine is part of the flattening procedure.  A subquery
++** whose result set is defined by pEList appears as entry in the
++** FROM clause of a SELECT such that the VDBE cursor assigned to that
++** FORM clause entry is iTable.  This routine make the necessary 
++** 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 substExpr(Expr *pExpr, int iTable, ExprList *pEList){
++  if( pExpr==0 ) return;
++  if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
++    if( pExpr->iColumn<0 ){
++      pExpr->op = TK_NULL;
++    }else{
++      Expr *pNew;
++      assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
++      assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 );
++      pNew = pEList->a[pExpr->iColumn].pExpr;
++      assert( pNew!=0 );
++      pExpr->op = pNew->op;
++      pExpr->dataType = pNew->dataType;
++      assert( pExpr->pLeft==0 );
++      pExpr->pLeft = sqliteExprDup(pNew->pLeft);
++      assert( pExpr->pRight==0 );
++      pExpr->pRight = sqliteExprDup(pNew->pRight);
++      assert( pExpr->pList==0 );
++      pExpr->pList = sqliteExprListDup(pNew->pList);
++      pExpr->iTable = pNew->iTable;
++      pExpr->iColumn = pNew->iColumn;
++      pExpr->iAgg = pNew->iAgg;
++      sqliteTokenCopy(&pExpr->token, &pNew->token);
++      sqliteTokenCopy(&pExpr->span, &pNew->span);
++    }
++  }else{
++    substExpr(pExpr->pLeft, iTable, pEList);
++    substExpr(pExpr->pRight, iTable, pEList);
++    substExprList(pExpr->pList, iTable, pEList);
++  }
++}
++static void 
++substExprList(ExprList *pList, int iTable, ExprList *pEList){
++  int i;
++  if( pList==0 ) return;
++  for(i=0; i<pList->nExpr; i++){
++    substExpr(pList->a[i].pExpr, iTable, pEList);
++  }
++}
++
++/*
++** This routine attempts to flatten subqueries in order to speed
++** execution.  It returns 1 if it makes changes and 0 if no flattening
++** occurs.
++**
++** To understand the concept of flattening, consider the following
++** query:
++**
++**     SELECT a FROM (SELECT x+y AS a FROM t1 WHERE z<100) WHERE a>5
++**
++** The default way of implementing this query is to execute the
++** subquery first and store the results in a temporary table, then
++** run the outer query on that temporary table.  This requires two
++** passes over the data.  Furthermore, because the temporary table
++** has no indices, the WHERE clause on the outer query cannot be
++** optimized.
++**
++** This routine attempts to rewrite queries such as the above into
++** a single flat select, like this:
++**
++**     SELECT x+y AS a FROM t1 WHERE z<100 AND a>5
++**
++** The code generated for this simpification gives the same result
++** but only has to scan the data once.  And because indices might 
++** exist on the table t1, a complete scan of the data might be
++** avoided.
++**
++** Flattening is only attempted if all of the following are true:
++**
++**   (1)  The subquery and the outer query do not both use aggregates.
++**
++**   (2)  The subquery is not an aggregate or the outer query is not a join.
++**
++**   (3)  The subquery is not the right operand of a left outer join, or
++**        the subquery is not itself a join.  (Ticket #306)
++**
++**   (4)  The subquery is not DISTINCT or the outer query is not a join.
++**
++**   (5)  The subquery is not DISTINCT or the outer query does not use
++**        aggregates.
++**
++**   (6)  The subquery does not use aggregates or the outer query is not
++**        DISTINCT.
++**
++**   (7)  The subquery has a FROM clause.
++**
++**   (8)  The subquery does not use LIMIT or the outer query is not a join.
++**
++**   (9)  The subquery does not use LIMIT or the outer query does not use
++**        aggregates.
++**
++**  (10)  The subquery does not use aggregates or the outer query does not
++**        use LIMIT.
++**
++**  (11)  The subquery and the outer query do not both have ORDER BY clauses.
++**
++**  (12)  The subquery is not the right term of a LEFT OUTER JOIN or the
++**        subquery has no WHERE clause.  (added by ticket #350)
++**
++** 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.
++**
++** If flattening is not attempted, this routine is a no-op and returns 0.
++** If flattening is attempted this routine returns 1.
++**
++** All of the expression analysis must occur on both the outer query and
++** the subquery before this routine runs.
++*/
++static int flattenSubquery(
++  Parse *pParse,       /* The parsing context */
++  Select *p,           /* The parent or outer SELECT statement */
++  int iFrom,           /* Index in p->pSrc->a[] of the inner subquery */
++  int isAgg,           /* True if outer SELECT uses aggregate functions */
++  int subqueryIsAgg    /* True if the subquery uses aggregate functions */
++){
++  Select *pSub;       /* The inner query or "subquery" */
++  SrcList *pSrc;      /* The FROM clause of the outer query */
++  SrcList *pSubSrc;   /* The FROM clause of the subquery */
++  ExprList *pList;    /* The result set of the outer query */
++  int iParent;        /* VDBE cursor number of the pSub result set temp table */
++  int i;
++  Expr *pWhere;
++
++  /* Check to see if flattening is permitted.  Return 0 if not.
++  */
++  if( p==0 ) return 0;
++  pSrc = p->pSrc;
++  assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
++  pSub = pSrc->a[iFrom].pSelect;
++  assert( pSub!=0 );
++  if( isAgg && subqueryIsAgg ) return 0;
++  if( subqueryIsAgg && pSrc->nSrc>1 ) return 0;
++  pSubSrc = pSub->pSrc;
++  assert( pSubSrc );
++  if( pSubSrc->nSrc==0 ) return 0;
++  if( (pSub->isDistinct || pSub->nLimit>=0) &&  (pSrc->nSrc>1 || isAgg) ){
++     return 0;
++  }
++  if( (p->isDistinct || p->nLimit>=0) && subqueryIsAgg ) return 0;
++  if( p->pOrderBy && pSub->pOrderBy ) return 0;
++
++  /* Restriction 3:  If the subquery is a join, make sure the subquery is 
++  ** not used as the right operand of an outer join.  Examples of why this
++  ** is not allowed:
++  **
++  **         t1 LEFT OUTER JOIN (t2 JOIN t3)
++  **
++  ** If we flatten the above, we would get
++  **
++  **         (t1 LEFT OUTER JOIN t2) JOIN t3
++  **
++  ** which is not at all the same thing.
++  */
++  if( pSubSrc->nSrc>1 && iFrom>0 && (pSrc->a[iFrom-1].jointype & JT_OUTER)!=0 ){
++    return 0;
++  }
++
++  /* Restriction 12:  If the subquery is the right operand of a left outer
++  ** join, make sure the subquery has no WHERE clause.
++  ** An examples of why this is not allowed:
++  **
++  **         t1 LEFT OUTER JOIN (SELECT * FROM t2 WHERE t2.x>0)
++  **
++  ** If we flatten the above, we would get
++  **
++  **         (t1 LEFT OUTER JOIN t2) WHERE t2.x>0
++  **
++  ** 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 ){
++    return 0;
++  }
++
++  /* If we reach this point, it means flattening is permitted for the
++  ** iFrom-th entry of the FROM clause in the outer query.
++  */
++
++  /* Move all of the FROM elements of the subquery into the
++  ** the FROM clause of the outer query.  Before doing this, remember
++  ** the cursor number for the original outer query FROM element in
++  ** iParent.  The iParent cursor will never be used.  Subsequent code
++  ** will scan expressions looking for iParent references and replace
++  ** those references with expressions that resolve to the subquery FROM
++  ** elements we are now copying in.
++  */
++  iParent = pSrc->a[iFrom].iCursor;
++  {
++    int nSubSrc = pSubSrc->nSrc;
++    int jointype = pSrc->a[iFrom].jointype;
++
++    if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){
++      sqliteDeleteTable(0, pSrc->a[iFrom].pTab);
++    }
++    sqliteFree(pSrc->a[iFrom].zDatabase);
++    sqliteFree(pSrc->a[iFrom].zName);
++    sqliteFree(pSrc->a[iFrom].zAlias);
++    if( nSubSrc>1 ){
++      int extra = nSubSrc - 1;
++      for(i=1; i<nSubSrc; i++){
++        pSrc = sqliteSrcListAppend(pSrc, 0, 0);
++      }
++      p->pSrc = pSrc;
++      for(i=pSrc->nSrc-1; i-extra>=iFrom; i--){
++        pSrc->a[i] = pSrc->a[i-extra];
++      }
++    }
++    for(i=0; i<nSubSrc; i++){
++      pSrc->a[i+iFrom] = pSubSrc->a[i];
++      memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
++    }
++    pSrc->a[iFrom+nSubSrc-1].jointype = jointype;
++  }
++
++  /* Now begin substituting subquery result set expressions for 
++  ** references to the iParent in the outer query.
++  ** 
++  ** Example:
++  **
++  **   SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b;
++  **   \                     \_____________ subquery __________/          /
++  **    \_____________________ outer query ______________________________/
++  **
++  ** We look at every expression in the outer query and every place we see
++  ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
++  */
++  substExprList(p->pEList, iParent, pSub->pEList);
++  pList = p->pEList;
++  for(i=0; i<pList->nExpr; i++){
++    Expr *pExpr;
++    if( pList->a[i].zName==0 && (pExpr = pList->a[i].pExpr)->span.z!=0 ){
++      pList->a[i].zName = sqliteStrNDup(pExpr->span.z, pExpr->span.n);
++    }
++  }
++  if( isAgg ){
++    substExprList(p->pGroupBy, iParent, pSub->pEList);
++    substExpr(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);
++  }
++  if( pSub->pWhere ){
++    pWhere = sqliteExprDup(pSub->pWhere);
++  }else{
++    pWhere = 0;
++  }
++  if( subqueryIsAgg ){
++    assert( p->pHaving==0 );
++    p->pHaving = p->pWhere;
++    p->pWhere = pWhere;
++    substExpr(p->pHaving, iParent, pSub->pEList);
++    if( pSub->pHaving ){
++      Expr *pHaving = sqliteExprDup(pSub->pHaving);
++      if( p->pHaving ){
++        p->pHaving = sqliteExpr(TK_AND, p->pHaving, pHaving, 0);
++      }else{
++        p->pHaving = pHaving;
++      }
++    }
++    assert( p->pGroupBy==0 );
++    p->pGroupBy = sqliteExprListDup(pSub->pGroupBy);
++  }else if( p->pWhere==0 ){
++    p->pWhere = pWhere;
++  }else{
++    substExpr(p->pWhere, iParent, pSub->pEList);
++    if( pWhere ){
++      p->pWhere = sqliteExpr(TK_AND, p->pWhere, pWhere, 0);
++    }
++  }
++
++  /* The flattened query is distinct if either the inner or the
++  ** outer query is distinct. 
++  */
++  p->isDistinct = p->isDistinct || pSub->isDistinct;
++
++  /* Transfer the limit expression from the subquery to the outer
++  ** query.
++  */
++  if( pSub->nLimit>=0 ){
++    if( p->nLimit<0 ){
++      p->nLimit = pSub->nLimit;
++    }else if( p->nLimit+p->nOffset > pSub->nLimit+pSub->nOffset ){
++      p->nLimit = pSub->nLimit + pSub->nOffset - p->nOffset;
++    }
++  }
++  p->nOffset += pSub->nOffset;
++
++  /* Finially, delete what is left of the subquery and return
++  ** success.
++  */
++  sqliteSelectDelete(pSub);
++  return 1;
++}
++
++/*
++** 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:
++**
++**    SELECT min(a) FROM table;
++**    SELECT max(a) FROM table;
++**
++** 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 sqliteSelect().
++** See the header comment on that routine for additional information.
++*/
++static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
++  Expr *pExpr;
++  int iCol;
++  Table *pTab;
++  Index *pIdx;
++  int base;
++  Vdbe *v;
++  int seekOp;
++  int cont;
++  ExprList *pEList, *pList, eList;
++  struct ExprList_item eListItem;
++  SrcList *pSrc;
++  
++
++  /* 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;
++  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;
++  if( sqliteStrNICmp(pExpr->token.z,"min",3)==0 ){
++    seekOp = OP_Rewind;
++  }else if( sqliteStrNICmp(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{
++    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
++      assert( pIdx->nColumn>=1 );
++      if( pIdx->aiColumn[0]==iCol ) 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 = sqliteGetVdbe(pParse);
++  if( v==0 ) return 0;
++  if( eDest==SRT_Callback ){
++    generateColumnTypes(pParse, p->pSrc, p->pEList);
++  }
++
++  /* If the output is destined for a temporary table, open that table.
++  */
++  if( eDest==SRT_TempTable ){
++    sqliteVdbeAddOp(v, OP_OpenTemp, iParm, 0);
++  }
++
++  /* 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.
++  */
++  sqliteCodeVerifySchema(pParse, pTab->iDb);
++  base = pSrc->a[0].iCursor;
++  computeLimitRegisters(pParse, p);
++  if( pSrc->a[0].pSelect==0 ){
++    sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
++    sqliteVdbeOp3(v, OP_OpenRead, base, pTab->tnum, pTab->zName, 0);
++  }
++  cont = sqliteVdbeMakeLabel(v);
++  if( pIdx==0 ){
++    sqliteVdbeAddOp(v, seekOp, base, 0);
++  }else{
++    sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
++    sqliteVdbeOp3(v, OP_OpenRead, base+1, pIdx->tnum, pIdx->zName, P3_STATIC);
++    if( seekOp==OP_Rewind ){
++      sqliteVdbeAddOp(v, OP_String, 0, 0);
++      sqliteVdbeAddOp(v, OP_MakeKey, 1, 0);
++      sqliteVdbeAddOp(v, OP_IncrKey, 0, 0);
++      seekOp = OP_MoveTo;
++    }
++    sqliteVdbeAddOp(v, seekOp, base+1, 0);
++    sqliteVdbeAddOp(v, OP_IdxRecno, base+1, 0);
++    sqliteVdbeAddOp(v, OP_Close, base+1, 0);
++    sqliteVdbeAddOp(v, OP_MoveTo, 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, cont, cont);
++  sqliteVdbeResolveLabel(v, cont);
++  sqliteVdbeAddOp(v, OP_Close, base, 0);
++  
++  return 1;
++}
++
++/*
++** Generate code for the given SELECT statement.
++**
++** The results are distributed in various ways depending on the
++** value of eDest and iParm.
++**
++**     eDest Value       Result
++**     ------------    -------------------------------------------
++**     SRT_Callback    Invoke the callback for each row of the result.
++**
++**     SRT_Mem         Store first result in memory cell iParm
++**
++**     SRT_Set         Store results as keys of a table with cursor iParm
++**
++**     SRT_Union       Store results as a key in a temporary table iParm
++**
++**     SRT_Except      Remove results from the temporary table iParm.
++**
++**     SRT_Table       Store results in temporary table iParm
++**
++** 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.
++**
++** This routine returns the number of errors.  If any errors are
++** encountered, then an appropriate error message is left in
++** pParse->zErrMsg.
++**
++** This routine does NOT free the Select structure passed in.  The
++** calling function needs to do that.
++**
++** The pParent, parentTab, and *pParentAgg fields are filled in if this
++** SELECT is a subquery.  This routine may try to combine this SELECT
++** with its parent to form a single flat query.  In so doing, it might
++** change the parent query from a non-aggregate to an aggregate query.
++** For that reason, the pParentAgg flag is passed as a pointer, so it
++** can be changed.
++**
++** Example 1:   The meaning of the pParent parameter.
++**
++**    SELECT * FROM t1 JOIN (SELECT x, count(*) FROM t2) JOIN t3;
++**    \                      \_______ subquery _______/        /
++**     \                                                      /
++**      \____________________ outer query ___________________/
++**
++** This routine is called for the outer query first.   For that call,
++** pParent will be NULL.  During the processing of the outer query, this 
++** routine is called recursively to handle the subquery.  For the recursive
++** call, pParent will point to the outer query.  Because the subquery is
++** the second element in a three-way join, the parentTab parameter will
++** be 1 (the 2nd value of a 0-indexed array.)
++*/
++int sqliteSelect(
++  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 */
++  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 */
++){
++  int i;
++  WhereInfo *pWInfo;
++  Vdbe *v;
++  int isAgg = 0;         /* True for select lists like "count(*)" */
++  ExprList *pEList;      /* List of columns to extract. */
++  SrcList *pTabList;     /* List of tables to select from */
++  Expr *pWhere;          /* The WHERE clause.  May be NULL */
++  ExprList *pOrderBy;    /* The ORDER BY clause.  May be NULL */
++  ExprList *pGroupBy;    /* The GROUP BY clause.  May be NULL */
++  Expr *pHaving;         /* The HAVING clause.  May be NULL */
++  int isDistinct;        /* True if the DISTINCT keyword is present */
++  int distinct;          /* Table to use for the distinct set */
++  int rc = 1;            /* Value to return from this function */
++
++  if( sqlite_malloc_failed || pParse->nErr || p==0 ) return 1;
++  if( sqliteAuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
++
++  /* If there is are a sequence of queries, do the earlier ones first.
++  */
++  if( p->pPrior ){
++    return multiSelect(pParse, p, eDest, iParm);
++  }
++
++  /* Make local copies of the parameters for this query.
++  */
++  pTabList = p->pSrc;
++  pWhere = p->pWhere;
++  pOrderBy = p->pOrderBy;
++  pGroupBy = p->pGroupBy;
++  pHaving = p->pHaving;
++  isDistinct = p->isDistinct;
++
++  /* Allocate VDBE cursors for each table in the FROM clause
++  */
++  sqliteSrcListAssignCursors(pParse, pTabList);
++
++  /* 
++  ** Do not even attempt to generate any code if we have already seen
++  ** errors before this routine starts.
++  */
++  if( pParse->nErr>0 ) goto select_end;
++
++  /* Expand any "*" terms in the result set.  (For example the "*" in
++  ** "SELECT * FROM t1")  The fillInColumnlist() routine also does some
++  ** other housekeeping - see the header comment for details.
++  */
++  if( fillInColumnList(pParse, p) ){
++    goto select_end;
++  }
++  pWhere = p->pWhere;
++  pEList = p->pEList;
++  if( pEList==0 ) goto select_end;
++
++  /* If writing to memory or generating a set
++  ** only a single column may be output.
++  */
++  if( (eDest==SRT_Mem || eDest==SRT_Set) && pEList->nExpr>1 ){
++    sqliteErrorMsg(pParse, "only a single result allowed for "
++       "a SELECT that is part of an expression");
++    goto select_end;
++  }
++
++  /* ORDER BY is ignored for some destinations.
++  */
++  switch( eDest ){
++    case SRT_Union:
++    case SRT_Except:
++    case SRT_Discard:
++      pOrderBy = 0;
++      break;
++    default:
++      break;
++  }
++
++  /* At this point, we should have allocated all the cursors that we
++  ** need to handle subquerys and temporary tables.  
++  **
++  ** Resolve the column names and do a semantics check on all the expressions.
++  */
++  for(i=0; i<pEList->nExpr; i++){
++    if( sqliteExprResolveIds(pParse, pTabList, 0, pEList->a[i].pExpr) ){
++      goto select_end;
++    }
++    if( sqliteExprCheck(pParse, pEList->a[i].pExpr, 1, &isAgg) ){
++      goto select_end;
++    }
++  }
++  if( pWhere ){
++    if( sqliteExprResolveIds(pParse, pTabList, pEList, pWhere) ){
++      goto select_end;
++    }
++    if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
++      goto select_end;
++    }
++  }
++  if( pHaving ){
++    if( pGroupBy==0 ){
++      sqliteErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
++      goto select_end;
++    }
++    if( sqliteExprResolveIds(pParse, pTabList, pEList, pHaving) ){
++      goto select_end;
++    }
++    if( sqliteExprCheck(pParse, pHaving, 1, &isAgg) ){
++      goto select_end;
++    }
++  }
++  if( pOrderBy ){
++    for(i=0; i<pOrderBy->nExpr; i++){
++      int iCol;
++      Expr *pE = pOrderBy->a[i].pExpr;
++      if( sqliteExprIsInteger(pE, &iCol) && iCol>0 && iCol<=pEList->nExpr ){
++        sqliteExprDelete(pE);
++        pE = pOrderBy->a[i].pExpr = sqliteExprDup(pEList->a[iCol-1].pExpr);
++      }
++      if( sqliteExprResolveIds(pParse, pTabList, pEList, pE) ){
++        goto select_end;
++      }
++      if( sqliteExprCheck(pParse, pE, isAgg, 0) ){
++        goto select_end;
++      }
++      if( sqliteExprIsConstant(pE) ){
++        if( sqliteExprIsInteger(pE, &iCol)==0 ){
++          sqliteErrorMsg(pParse,
++             "ORDER BY terms must not be non-integer constants");
++          goto select_end;
++        }else if( iCol<=0 || iCol>pEList->nExpr ){
++          sqliteErrorMsg(pParse, 
++             "ORDER BY column number %d out of range - should be "
++             "between 1 and %d", iCol, pEList->nExpr);
++          goto select_end;
++        }
++      }
++    }
++  }
++  if( pGroupBy ){
++    for(i=0; i<pGroupBy->nExpr; i++){
++      int iCol;
++      Expr *pE = pGroupBy->a[i].pExpr;
++      if( sqliteExprIsInteger(pE, &iCol) && iCol>0 && iCol<=pEList->nExpr ){
++        sqliteExprDelete(pE);
++        pE = pGroupBy->a[i].pExpr = sqliteExprDup(pEList->a[iCol-1].pExpr);
++      }
++      if( sqliteExprResolveIds(pParse, pTabList, pEList, pE) ){
++        goto select_end;
++      }
++      if( sqliteExprCheck(pParse, pE, isAgg, 0) ){
++        goto select_end;
++      }
++      if( sqliteExprIsConstant(pE) ){
++        if( sqliteExprIsInteger(pE, &iCol)==0 ){
++          sqliteErrorMsg(pParse,
++            "GROUP BY terms must not be non-integer constants");
++          goto select_end;
++        }else if( iCol<=0 || iCol>pEList->nExpr ){
++          sqliteErrorMsg(pParse,
++             "GROUP BY column number %d out of range - should be "
++             "between 1 and %d", iCol, pEList->nExpr);
++          goto select_end;
++        }
++      }
++    }
++  }
++
++  /* Begin generating code.
++  */
++  v = sqliteGetVdbe(pParse);
++  if( v==0 ) goto select_end;
++
++  /* Identify column names if we will be using them in a callback.  This
++  ** step is skipped if the output is going to some other destination.
++  */
++  if( eDest==SRT_Callback ){
++    generateColumnNames(pParse, pTabList, pEList);
++  }
++
++  /* Generate code for all sub-queries in the FROM clause
++  */
++  for(i=0; i<pTabList->nSrc; i++){
++    const char *zSavedAuthContext;
++    int needRestoreContext;
++
++    if( pTabList->a[i].pSelect==0 ) continue;
++    if( pTabList->a[i].zName!=0 ){
++      zSavedAuthContext = pParse->zAuthContext;
++      pParse->zAuthContext = pTabList->a[i].zName;
++      needRestoreContext = 1;
++    }else{
++      needRestoreContext = 0;
++    }
++    sqliteSelect(pParse, pTabList->a[i].pSelect, SRT_TempTable, 
++                 pTabList->a[i].iCursor, p, i, &isAgg);
++    if( needRestoreContext ){
++      pParse->zAuthContext = zSavedAuthContext;
++    }
++    pTabList = p->pSrc;
++    pWhere = p->pWhere;
++    if( eDest!=SRT_Union && eDest!=SRT_Except && eDest!=SRT_Discard ){
++      pOrderBy = p->pOrderBy;
++    }
++    pGroupBy = p->pGroupBy;
++    pHaving = p->pHaving;
++    isDistinct = p->isDistinct;
++  }
++
++  /* Check for the special case of a min() or max() function by itself
++  ** in the result set.
++  */
++  if( simpleMinMaxQuery(pParse, p, eDest, iParm) ){
++    rc = 0;
++    goto select_end;
++  }
++
++  /* 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.  
++  */
++  if( pParent && pParentAgg &&
++      flattenSubquery(pParse, pParent, parentTab, *pParentAgg, isAgg) ){
++    if( isAgg ) *pParentAgg = 1;
++    return rc;
++  }
++
++  /* Set the limiter.
++  */
++  computeLimitRegisters(pParse, p);
++
++  /* Identify column types if we will be using a callback.  This
++  ** step is skipped if the output is going to a destination other
++  ** than a callback.
++  **
++  ** We have to do this separately from the creation of column names
++  ** above because if the pTabList contains views then they will not
++  ** have been resolved and we will not know the column types until
++  ** now.
++  */
++  if( eDest==SRT_Callback ){
++    generateColumnTypes(pParse, pTabList, pEList);
++  }
++
++  /* If the output is destined for a temporary table, open that table.
++  */
++  if( eDest==SRT_TempTable ){
++    sqliteVdbeAddOp(v, OP_OpenTemp, iParm, 0);
++  }
++
++  /* Do an analysis of aggregate expressions.
++  */
++  sqliteAggregateInfoReset(pParse);
++  if( isAgg || pGroupBy ){
++    assert( pParse->nAgg==0 );
++    isAgg = 1;
++    for(i=0; i<pEList->nExpr; i++){
++      if( sqliteExprAnalyzeAggregates(pParse, pEList->a[i].pExpr) ){
++        goto select_end;
++      }
++    }
++    if( pGroupBy ){
++      for(i=0; i<pGroupBy->nExpr; i++){
++        if( sqliteExprAnalyzeAggregates(pParse, pGroupBy->a[i].pExpr) ){
++          goto select_end;
++        }
++      }
++    }
++    if( pHaving && sqliteExprAnalyzeAggregates(pParse, pHaving) ){
++      goto select_end;
++    }
++    if( pOrderBy ){
++      for(i=0; i<pOrderBy->nExpr; i++){
++        if( sqliteExprAnalyzeAggregates(pParse, pOrderBy->a[i].pExpr) ){
++          goto select_end;
++        }
++      }
++    }
++  }
++
++  /* Reset the aggregator
++  */
++  if( isAgg ){
++    sqliteVdbeAddOp(v, OP_AggReset, 0, pParse->nAgg);
++    for(i=0; i<pParse->nAgg; i++){
++      FuncDef *pFunc;
++      if( (pFunc = pParse->aAgg[i].pFunc)!=0 && pFunc->xFinalize!=0 ){
++        sqliteVdbeOp3(v, OP_AggInit, 0, i, (char*)pFunc, P3_POINTER);
++      }
++    }
++    if( pGroupBy==0 ){
++      sqliteVdbeAddOp(v, OP_String, 0, 0);
++      sqliteVdbeAddOp(v, OP_AggFocus, 0, 0);
++    }
++  }
++
++  /* Initialize the memory cell to NULL
++  */
++  if( eDest==SRT_Mem ){
++    sqliteVdbeAddOp(v, OP_String, 0, 0);
++    sqliteVdbeAddOp(v, OP_MemStore, iParm, 1);
++  }
++
++  /* Open a temporary table to use for the distinct set.
++  */
++  if( isDistinct ){
++    distinct = pParse->nTab++;
++    sqliteVdbeAddOp(v, OP_OpenTemp, distinct, 1);
++  }else{
++    distinct = -1;
++  }
++
++  /* Begin the database scan
++  */
++  pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0, 
++                            pGroupBy ? 0 : &pOrderBy);
++  if( pWInfo==0 ) goto select_end;
++
++  /* Use the standard inner loop if we are not dealing with
++  ** aggregates
++  */
++  if( !isAgg ){
++    if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest,
++                    iParm, pWInfo->iContinue, pWInfo->iBreak) ){
++       goto select_end;
++    }
++  }
++
++  /* If we are dealing with aggregates, then do the special aggregate
++  ** processing.  
++  */
++  else{
++    AggExpr *pAgg;
++    if( pGroupBy ){
++      int lbl1;
++      for(i=0; i<pGroupBy->nExpr; i++){
++        sqliteExprCode(pParse, pGroupBy->a[i].pExpr);
++      }
++      sqliteVdbeAddOp(v, OP_MakeKey, pGroupBy->nExpr, 0);
++      if( pParse->db->file_format>=4 ) sqliteAddKeyType(v, pGroupBy);
++      lbl1 = sqliteVdbeMakeLabel(v);
++      sqliteVdbeAddOp(v, OP_AggFocus, 0, lbl1);
++      for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
++        if( pAgg->isAgg ) continue;
++        sqliteExprCode(pParse, pAgg->pExpr);
++        sqliteVdbeAddOp(v, OP_AggSet, 0, i);
++      }
++      sqliteVdbeResolveLabel(v, lbl1);
++    }
++    for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
++      Expr *pE;
++      int nExpr;
++      FuncDef *pDef;
++      if( !pAgg->isAgg ) continue;
++      assert( pAgg->pFunc!=0 );
++      assert( pAgg->pFunc->xStep!=0 );
++      pDef = pAgg->pFunc;
++      pE = pAgg->pExpr;
++      assert( pE!=0 );
++      assert( pE->op==TK_AGG_FUNCTION );
++      nExpr = sqliteExprCodeExprList(pParse, pE->pList, pDef->includeTypes);
++      sqliteVdbeAddOp(v, OP_Integer, i, 0);
++      sqliteVdbeOp3(v, OP_AggFunc, 0, nExpr, (char*)pDef, P3_POINTER);
++    }
++  }
++
++  /* End the database scan loop.
++  */
++  sqliteWhereEnd(pWInfo);
++
++  /* If we are processing aggregates, we need to set up a second loop
++  ** over all of the aggregate values and process them.
++  */
++  if( isAgg ){
++    int endagg = sqliteVdbeMakeLabel(v);
++    int startagg;
++    startagg = sqliteVdbeAddOp(v, OP_AggNext, 0, endagg);
++    pParse->useAgg = 1;
++    if( pHaving ){
++      sqliteExprIfFalse(pParse, pHaving, startagg, 1);
++    }
++    if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest,
++                    iParm, startagg, endagg) ){
++      goto select_end;
++    }
++    sqliteVdbeAddOp(v, OP_Goto, 0, startagg);
++    sqliteVdbeResolveLabel(v, endagg);
++    sqliteVdbeAddOp(v, OP_Noop, 0, 0);
++    pParse->useAgg = 0;
++  }
++
++  /* If there is an ORDER BY clause, then we need to sort the results
++  ** and send them to the callback one by one.
++  */
++  if( pOrderBy ){
++    generateSortTail(p, v, pEList->nExpr, eDest, iParm);
++  }
++
++  /* If this was a subquery, we have now converted the subquery into a
++  ** temporary table.  So delete the subquery structure from the parent
++  ** to prevent this subquery from being evaluated again and to force the
++  ** the use of the temporary table.
++  */
++  if( pParent ){
++    assert( pParent->pSrc->nSrc>parentTab );
++    assert( pParent->pSrc->a[parentTab].pSelect==p );
++    sqliteSelectDelete(p);
++    pParent->pSrc->a[parentTab].pSelect = 0;
++  }
++
++  /* The SELECT was successfully coded.   Set the return code to 0
++  ** to indicate no errors.
++  */
++  rc = 0;
++
++  /* Control jumps to here if an error is encountered above, or upon
++  ** successful coding of the SELECT.
++  */
++select_end:
++  sqliteAggregateInfoReset(pParse);
++  return rc;
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/sqlite_config.w32.h
+@@ -0,0 +1,8 @@
++#include "config.w32.h"
++#if ZTS
++# define THREADSAFE 1
++#endif
++#if !ZEND_DEBUG && !defined(NDEBUG)
++# define NDEBUG
++#endif
++#define SQLITE_PTR_SZ 4
+\ No newline at end of file
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/sqlite.h.in
+@@ -0,0 +1,886 @@
++/*
++** 2001 September 15
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This header file defines the interface that the SQLite library
++** presents to client programs.
++**
++** @(#) $Id$
++*/
++#ifndef _SQLITE_H_
++#define _SQLITE_H_
++#include <stdarg.h>     /* Needed for the definition of va_list */
++
++/*
++** Make sure we can call this stuff from C++.
++*/
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/*
++** The version of the SQLite library.
++*/
++#ifdef SQLITE_VERSION
++# undef SQLITE_VERSION
++#else
++# define SQLITE_VERSION         "--VERS--"
++#endif
++
++/*
++** 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.
++*/
++extern const char sqlite_version[];
++
++/*
++** The SQLITE_UTF8 macro is defined if the library expects to see
++** UTF-8 encoded data.  The SQLITE_ISO8859 macro is defined if the
++** iso8859 encoded should be used.
++*/
++#define SQLITE_--ENCODING-- 1
++
++/*
++** The following constant holds one of two strings, "UTF-8" or "iso8859",
++** depending on which character encoding the SQLite library expects to
++** see.  The character encoding makes a difference for the LIKE and GLOB
++** operators and for the LENGTH() and SUBSTR() functions.
++*/
++extern const char sqlite_encoding[];
++
++/*
++** Each open sqlite database is represented by an instance of the
++** following opaque structure.
++*/
++typedef struct sqlite sqlite;
++
++/*
++** A function to open a new sqlite database.  
++**
++** If the database does not exist and mode indicates write
++** permission, then a new database is created.  If the database
++** does not exist and mode does not indicate write permission,
++** then the open fails, an error message generated (if errmsg!=0)
++** and the function returns 0.
++** 
++** If mode does not indicates user write permission, then the 
++** database is opened read-only.
++**
++** The Truth:  As currently implemented, all databases are opened
++** for writing all the time.  Maybe someday we will provide the
++** ability to open a database readonly.  The mode parameters is
++** provided in anticipation of that enhancement.
++*/
++sqlite *sqlite_open(const char *filename, int mode, char **errmsg);
++
++/*
++** A function to close the database.
++**
++** Call this function with a pointer to a structure that was previously
++** returned from sqlite_open() and the corresponding database will by closed.
++*/
++void sqlite_close(sqlite *);
++
++/*
++** The type for a callback function.
++*/
++typedef int (*sqlite_callback)(void*,int,char**, char**);
++
++/*
++** A function to executes one or more statements of SQL.
++**
++** 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 sqlite_exec() function returns the SQLITE_ABORT.
++**
++** The 4th parameter is an arbitrary pointer that is passed
++** to the callback function as its first parameter.
++**
++** 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.
++**
++** 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.
++**
++** 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 sqlite_freemem() for this.  If errmsg==NULL,
++** then no error message is ever written.
++**
++** 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. 
++**
++** 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 sqlite_busy_handler()
++** and sqlite_busy_timeout() functions below.)
++*/
++int sqlite_exec(
++  sqlite*,                      /* An open database */
++  const char *sql,              /* SQL to be executed */
++  sqlite_callback,              /* Callback function */
++  void *,                       /* 1st argument to callback function */
++  char **errmsg                 /* Error msg written here */
++);
++
++/*
++** Return values for sqlite_exec() and sqlite_step()
++*/
++#define SQLITE_OK           0   /* Successful result */
++#define SQLITE_ERROR        1   /* SQL error or missing database */
++#define SQLITE_INTERNAL     2   /* An 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 */
++#define SQLITE_LOCKED       6   /* A table in the database is locked */
++#define SQLITE_NOMEM        7   /* A malloc() failed */
++#define SQLITE_READONLY     8   /* Attempt to write a readonly database */
++#define SQLITE_INTERRUPT    9   /* Operation terminated by sqlite_interrupt() */
++#define SQLITE_IOERR       10   /* Some kind of disk I/O error occurred */
++#define SQLITE_CORRUPT     11   /* The database disk image is malformed */
++#define SQLITE_NOTFOUND    12   /* (Internal Only) 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_EMPTY       16   /* (Internal Only) Database table is empty */
++#define SQLITE_SCHEMA      17   /* The database schema changed */
++#define SQLITE_TOOBIG      18   /* Too much data for one row of a table */
++#define SQLITE_CONSTRAINT  19   /* Abort due to contraint 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 */
++#define SQLITE_AUTH        23   /* Authorization denied */
++#define SQLITE_FORMAT      24   /* Auxiliary database format error */
++#define SQLITE_RANGE       25   /* 2nd parameter to sqlite_bind out of range */
++#define SQLITE_NOTADB      26   /* File opened that is not a database file */
++#define SQLITE_ROW         100  /* sqlite_step() has another row ready */
++#define SQLITE_DONE        101  /* sqlite_step() has finished executing */
++
++/*
++** 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.
++**
++** This function is similar to the mysql_insert_id() function from MySQL.
++*/
++int sqlite_last_insert_rowid(sqlite*);
++
++/*
++** This function returns the number of database rows that were changed
++** (or inserted or deleted) by the most recent called sqlite_exec().
++**
++** 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.
++**
++** If a callback invokes sqlite_exec() recursively, then the changes
++** in the inner, recursive call are counted together with the changes
++** in the outer call.
++**
++** 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.
++*/
++int sqlite_changes(sqlite*);
++
++/*
++** This function returns the number of database rows that were changed
++** by the last INSERT, UPDATE, or DELETE statment executed by sqlite_exec(),
++** or by the last VM to run to completion. The change count is not updated
++** by SQL statements other than INSERT, UPDATE or DELETE.
++**
++** Changes are counted, even if they are later undone by a ROLLBACK or
++** ABORT. Changes associated with trigger programs that execute as a
++** result of the INSERT, UPDATE, or DELETE statement are not counted.
++**
++** If a callback invokes sqlite_exec() recursively, then the changes
++** in the inner, recursive call are counted together with the changes
++** in the outer call.
++**
++** 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.
++**
++******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
++*/
++int sqlite_last_statement_changes(sqlite*);
++
++/* If the parameter to this routine is one of the return value constants
++** defined above, then this routine returns a constant text string which
++** descripts (in English) the meaning of the return value.
++*/
++const char *sqlite_error_string(int);
++#define sqliteErrStr sqlite_error_string  /* Legacy. Do not use in new code. */
++
++/* 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.
++*/
++void sqlite_interrupt(sqlite*);
++
++
++/* This function returns true if the given input string comprises
++** one or more complete SQL statements.
++**
++** The algorithm is simple.  If the last token other than spaces
++** and comments is a semicolon, then return true.  otherwise return
++** false.
++*/
++int sqlite_complete(const char *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 sqlite_exec() returns SQLITE_BUSY immediately if
++** it finds a locked table.  If the busy callback is not NULL, then
++** sqlite_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 sqlite_exec() immediately returns
++** SQLITE_BUSY.  If the callback returns non-zero, then sqlite_exec()
++** tries to open the table again and the cycle repeats.
++**
++** 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.
++*/
++void sqlite_busy_handler(sqlite*, int(*)(void*,const char*,int), void*);
++
++/*
++** This routine sets a 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 sqlite_exec() to return SQLITE_BUSY.
++**
++** Calling this routine with an argument less than or equal to zero
++** turns off all busy handlers.
++*/
++void sqlite_busy_timeout(sqlite*, int ms);
++
++/*
++** This next routine is really just a wrapper around sqlite_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:
++**
++**        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).
++**
++** After the calling function has finished using the result, it should 
++** pass the result data pointer to sqlite_free_table() in order to 
++** release the memory that was malloc-ed.  Because of the way the 
++** malloc() happens, the calling function must not try to call 
++** malloc() directly.  Only sqlite_free_table() is able to release 
++** the memory properly and safely.
++**
++** The return value of this routine is the same as from sqlite_exec().
++*/
++int sqlite_get_table(
++  sqlite*,               /* 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 */
++);
++
++/*
++** Call this routine to free the memory that sqlite_get_table() allocated.
++*/
++void sqlite_free_table(char **result);
++
++/*
++** The following routines are wrappers around sqlite_exec() and
++** sqlite_get_table().  The only difference between the routines that
++** follow and the originals is that the second argument to the 
++** routines that follow is really a printf()-style format
++** string describing the SQL to be executed.  Arguments to the format
++** string appear at the end of the argument list.
++**
++** 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
++** 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
++** the string.
++**
++** For example, so some string variable contains text as follows:
++**
++**      char *zText = "It's a happy day!";
++**
++** We can use this text in an SQL statement as follows:
++**
++**      sqlite_exec_printf(db, "INSERT INTO table VALUES('%q')",
++**          callback1, 0, 0, zText);
++**
++** 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!')
++**
++** 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!');
++**
++** 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.
++*/
++int sqlite_exec_printf(
++  sqlite*,                      /* An open database */
++  const char *sqlFormat,        /* printf-style format string for the SQL */
++  sqlite_callback,              /* Callback function */
++  void *,                       /* 1st argument to callback function */
++  char **errmsg,                /* Error msg written here */
++  ...                           /* Arguments to the format string. */
++);
++int sqlite_exec_vprintf(
++  sqlite*,                      /* An open database */
++  const char *sqlFormat,        /* printf-style format string for the SQL */
++  sqlite_callback,              /* Callback function */
++  void *,                       /* 1st argument to callback function */
++  char **errmsg,                /* Error msg written here */
++  va_list ap                    /* Arguments to the format string. */
++);
++int sqlite_get_table_printf(
++  sqlite*,               /* An open database */
++  const char *sqlFormat, /* printf-style format string for the SQL */
++  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 */
++  ...                    /* Arguments to the format string */
++);
++int sqlite_get_table_vprintf(
++  sqlite*,               /* An open database */
++  const char *sqlFormat, /* printf-style format string for the SQL */
++  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 */
++  va_list ap             /* Arguments to the format string */
++);
++char *sqlite_mprintf(const char*,...);
++char *sqlite_vmprintf(const char*, va_list);
++
++/*
++** Windows systems should call this routine to free memory that
++** is returned in the in the errmsg parameter of sqlite_open() when
++** SQLite is a DLL.  For some reason, it does not work to call free()
++** directly.
++*/
++void sqlite_freemem(void *p);
++
++/*
++** Windows systems need functions to call to return the sqlite_version
++** and sqlite_encoding strings.
++*/
++const char *sqlite_libversion(void);
++const char *sqlite_libencoding(void);
++
++/*
++** A pointer to the following structure is used to communicate with
++** the implementations of user-defined functions.
++*/
++typedef struct sqlite_func sqlite_func;
++
++/*
++** Use the following routines to create new user-defined functions.  See
++** the documentation for details.
++*/
++int sqlite_create_function(
++  sqlite*,                  /* Database where the new function is registered */
++  const char *zName,        /* Name of the new function */
++  int nArg,                 /* Number of arguments.  -1 means any number */
++  void (*xFunc)(sqlite_func*,int,const char**),  /* C code to implement */
++  void *pUserData           /* Available via the sqlite_user_data() call */
++);
++int sqlite_create_aggregate(
++  sqlite*,                  /* Database where the new function is registered */
++  const char *zName,        /* Name of the function */
++  int nArg,                 /* Number of arguments */
++  void (*xStep)(sqlite_func*,int,const char**), /* Called for each row */
++  void (*xFinalize)(sqlite_func*),       /* Called once to get final result */
++  void *pUserData           /* Available via the sqlite_user_data() call */
++);
++
++/*
++** Use the following routine to define the datatype returned by a
++** user-defined function.  The second argument can be one of the
++** constants SQLITE_NUMERIC, SQLITE_TEXT, or SQLITE_ARGS or it
++** can be an integer greater than or equal to zero.  When the datatype
++** parameter is non-negative, the type of the result will be the
++** same as the datatype-th argument.  If datatype==SQLITE_NUMERIC
++** then the result is always numeric.  If datatype==SQLITE_TEXT then
++** the result is always text.  If datatype==SQLITE_ARGS then the result
++** is numeric if any argument is numeric and is text otherwise.
++*/
++int sqlite_function_type(
++  sqlite *db,               /* The database there the function is registered */
++  const char *zName,        /* Name of the function */
++  int datatype              /* The datatype for this function */
++);
++#define SQLITE_NUMERIC     (-1)
++/* #define SQLITE_TEXT     (-2)  // See below */
++#define SQLITE_ARGS        (-3)
++
++/*
++** SQLite version 3 defines SQLITE_TEXT differently.  To allow both
++** version 2 and version 3 to be included, undefine them both if a
++** conflict is seen.  Define SQLITE2_TEXT to be the version 2 value.
++*/
++#ifdef SQLITE_TEXT
++# undef SQLITE_TEXT
++#else
++# define SQLITE_TEXT     (-2)
++#endif
++#define SQLITE2_TEXT     (-2)
++
++
++
++/*
++** The user function implementations call one of the following four routines
++** in order to return their results.  The first parameter to each of these
++** routines is a copy of the first argument to xFunc() or xFinialize().
++** The second parameter to these routines is the result to be returned.
++** A NULL can be passed as the second parameter to sqlite_set_result_string()
++** in order to return a NULL result.
++**
++** The 3rd argument to _string and _error is the number of characters to
++** take from the string.  If this argument is negative, then all characters
++** up to and including the first '\000' are used.
++**
++** The sqlite_set_result_string() function allocates a buffer to hold the
++** result and returns a pointer to this buffer.  The calling routine
++** (that is, the implmentation of a user function) can alter the content
++** of this buffer if desired.
++*/
++char *sqlite_set_result_string(sqlite_func*,const char*,int);
++void sqlite_set_result_int(sqlite_func*,int);
++void sqlite_set_result_double(sqlite_func*,double);
++void sqlite_set_result_error(sqlite_func*,const char*,int);
++
++/*
++** The pUserData parameter to the sqlite_create_function() and
++** sqlite_create_aggregate() routines used to register user functions
++** is available to the implementation of the function using this
++** call.
++*/
++void *sqlite_user_data(sqlite_func*);
++
++/*
++** 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
++** of the aggregate can use the returned buffer to accumulate data.
++**
++** The buffer allocated is freed automatically be SQLite.
++*/
++void *sqlite_aggregate_context(sqlite_func*, int nBytes);
++
++/*
++** The next routine returns the number of calls to xStep for a particular
++** aggregate function instance.  The current call to xStep counts so this
++** routine always returns at least 1.
++*/
++int sqlite_aggregate_count(sqlite_func*);
++
++/*
++** 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.
++*/
++int sqlite_set_authorizer(
++  sqlite*,
++  int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
++  void *pUserData
++);
++
++/*
++** 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
++** 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.
++**
++**                                          Arg-3           Arg-4
++*/
++#define SQLITE_COPY                  0   /* Table Name      File Name       */
++#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      */
++#define SQLITE_CREATE_TEMP_TABLE     4   /* Table Name      NULL            */
++#define SQLITE_CREATE_TEMP_TRIGGER   5   /* Trigger Name    Table Name      */
++#define SQLITE_CREATE_TEMP_VIEW      6   /* View Name       NULL            */
++#define SQLITE_CREATE_TRIGGER        7   /* Trigger Name    Table Name      */
++#define SQLITE_CREATE_VIEW           8   /* View Name       NULL            */
++#define SQLITE_DELETE                9   /* Table Name      NULL            */
++#define SQLITE_DROP_INDEX           10   /* Index Name      Table Name      */
++#define SQLITE_DROP_TABLE           11   /* Table Name      NULL            */
++#define SQLITE_DROP_TEMP_INDEX      12   /* Index Name      Table Name      */
++#define SQLITE_DROP_TEMP_TABLE      13   /* Table Name      NULL            */
++#define SQLITE_DROP_TEMP_TRIGGER    14   /* Trigger Name    Table Name      */
++#define SQLITE_DROP_TEMP_VIEW       15   /* View Name       NULL            */
++#define SQLITE_DROP_TRIGGER         16   /* Trigger Name    Table Name      */
++#define SQLITE_DROP_VIEW            17   /* View Name       NULL            */
++#define SQLITE_INSERT               18   /* Table Name      NULL            */
++#define SQLITE_PRAGMA               19   /* Pragma Name     1st arg or NULL */
++#define SQLITE_READ                 20   /* Table Name      Column Name     */
++#define SQLITE_SELECT               21   /* NULL            NULL            */
++#define SQLITE_TRANSACTION          22   /* NULL            NULL            */
++#define SQLITE_UPDATE               23   /* Table Name      Column Name     */
++#define SQLITE_ATTACH               24   /* Filename        NULL            */
++#define SQLITE_DETACH               25   /* Database Name   NULL            */
++
++
++/*
++** 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 that is called at every invocation of sqlite_exec()
++** or sqlite_compile().  This function can be used (for example) to generate
++** a log file of all SQL executed against a database.
++*/
++void *sqlite_trace(sqlite*, void(*xTrace)(void*,const char*), void*);
++
++/*** The Callback-Free API
++** 
++** The following routines implement a new way to access SQLite that does not
++** involve the use of callbacks.
++**
++** An sqlite_vm is an opaque object that represents a single SQL statement
++** that is ready to be executed.
++*/
++typedef struct sqlite_vm sqlite_vm;
++
++/*
++** To execute an SQLite query without the use of callbacks, you first have
++** to compile the SQL using this routine.  The 1st parameter "db" is a pointer
++** to an sqlite object obtained from sqlite_open().  The 2nd parameter
++** "zSql" is the text of the SQL to be compiled.   The remaining parameters
++** are all outputs.
++**
++** *pzTail is made to point to the first character 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.
++**
++** *ppVm is left pointing to a "virtual machine" that can be used to execute
++** the compiled statement.  Or if there is an error, *ppVm may be set to NULL.
++** If the input text contained no SQL (if the input is and empty string or
++** a comment) then *ppVm is set to NULL.
++**
++** If any errors are detected during compilation, an error message is written
++** into space obtained from malloc() and *pzErrMsg is made to point to that
++** error message.  The calling routine is responsible for freeing the text
++** of this message when it has finished with it.  Use sqlite_freemem() to
++** free the message.  pzErrMsg may be NULL in which case no error message
++** will be generated.
++**
++** On success, SQLITE_OK is returned.  Otherwise and error code is returned.
++*/
++int sqlite_compile(
++  sqlite *db,                   /* The open database */
++  const char *zSql,             /* SQL statement to be compiled */
++  const char **pzTail,          /* OUT: uncompiled tail of zSql */
++  sqlite_vm **ppVm,             /* OUT: the virtual machine to execute zSql */
++  char **pzErrmsg               /* OUT: Error message. */
++);
++
++/*
++** After an SQL statement has been compiled, it is handed to this routine
++** to be executed.  This routine executes the statement as far as it can
++** go then returns.  The return value will be one of SQLITE_DONE,
++** SQLITE_ERROR, SQLITE_BUSY, SQLITE_ROW, or SQLITE_MISUSE.
++**
++** SQLITE_DONE means that the execute of the SQL statement is complete
++** an no errors have occurred.  sqlite_step() should not be called again
++** for the same virtual machine.  *pN is set to the number of columns in
++** the result set and *pazColName is set to an array of strings that
++** describe the column names and datatypes.  The name of the i-th column
++** is (*pazColName)[i] and the datatype of the i-th column is
++** (*pazColName)[i+*pN].  *pazValue is set to NULL.
++**
++** SQLITE_ERROR means that the virtual machine encountered a run-time
++** error.  sqlite_step() should not be called again for the same
++** virtual machine.  *pN is set to 0 and *pazColName and *pazValue are set
++** to NULL.  Use sqlite_finalize() to obtain the specific error code
++** and the error message text for the error.
++**
++** SQLITE_BUSY means that an attempt to open the database failed because
++** another thread or process is holding a lock.  The calling routine
++** can try again to open the database by calling sqlite_step() again.
++** The return code will only be SQLITE_BUSY if no busy handler is registered
++** using the sqlite_busy_handler() or sqlite_busy_timeout() routines.  If
++** a busy handler callback has been registered but returns 0, then this
++** routine will return SQLITE_ERROR and sqltie_finalize() will return
++** SQLITE_BUSY when it is called.
++**
++** SQLITE_ROW means that a single row of the result is now available.
++** The data is contained in *pazValue.  The value of the i-th column is
++** (*azValue)[i].  *pN and *pazColName are set as described in SQLITE_DONE.
++** Invoke sqlite_step() again to advance to the next row.
++**
++** SQLITE_MISUSE is returned if sqlite_step() is called incorrectly.
++** For example, if you call sqlite_step() after the virtual machine
++** has halted (after a prior call to sqlite_step() has returned SQLITE_DONE)
++** or if you call sqlite_step() with an incorrectly initialized virtual
++** machine or a virtual machine that has been deleted or that is associated
++** with an sqlite structure that has been closed.
++*/
++int sqlite_step(
++  sqlite_vm *pVm,              /* The virtual machine to execute */
++  int *pN,                     /* OUT: Number of columns in result */
++  const char ***pazValue,      /* OUT: Column data */
++  const char ***pazColName     /* OUT: Column names and datatypes */
++);
++
++/*
++** This routine is called to delete a virtual machine after it has finished
++** executing.  The return value is the result code.  SQLITE_OK is returned
++** if the statement executed successfully and some other value is returned if
++** there was any kind of error.  If an error occurred and pzErrMsg is not
++** NULL, then an error message is written into memory obtained from malloc()
++** and *pzErrMsg is made to point to that error message.  The calling routine
++** should use sqlite_freemem() to delete this message when it has finished
++** with it.
++**
++** 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 sqlite_interrupt().)  Incomplete updates may be
++** rolled back and transactions cancelled,  depending on the circumstances,
++** and the result code returned will be SQLITE_ABORT.
++*/
++int sqlite_finalize(sqlite_vm*, char **pzErrMsg);
++
++/*
++** This routine deletes the virtual machine, writes any error message to
++** *pzErrMsg and returns an SQLite return code in the same way as the
++** sqlite_finalize() function.
++**
++** Additionally, if ppVm is not NULL, *ppVm is left pointing to a new virtual
++** machine loaded with the compiled version of the original query ready for
++** execution.
++**
++** If sqlite_reset() returns SQLITE_SCHEMA, then *ppVm is set to NULL.
++**
++******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
++*/
++int sqlite_reset(sqlite_vm*, char **pzErrMsg);
++
++/*
++** If the SQL that was handed to sqlite_compile contains variables that
++** are represeted in the SQL text by a question mark ('?').  This routine
++** is used to assign values to those variables.
++**
++** The first parameter is a virtual machine obtained from sqlite_compile().
++** The 2nd "idx" parameter determines which variable in the SQL statement
++** to bind the value to.  The left most '?' is 1.  The 3rd parameter is
++** the value to assign to that variable.  The 4th parameter is the number
++** of bytes in the value, including the terminating \000 for strings.
++** Finally, the 5th "copy" parameter is TRUE if SQLite should make its
++** own private copy of this value, or false if the space that the 3rd
++** parameter points to will be unchanging and can be used directly by
++** SQLite.
++**
++** Unbound variables are treated as having a value of NULL.  To explicitly
++** set a variable to NULL, call this routine with the 3rd parameter as a
++** NULL pointer.
++**
++** If the 4th "len" parameter is -1, then strlen() is used to find the
++** length.
++**
++** This routine can only be called immediately after sqlite_compile()
++** or sqlite_reset() and before any calls to sqlite_step().
++**
++******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
++*/
++int sqlite_bind(sqlite_vm*, int idx, const char *value, int len, int copy);
++
++/*
++** This routine configures a callback function - the progress callback - that
++** is invoked periodically during long running calls to sqlite_exec(),
++** sqlite_step() and sqlite_get_table(). An example use for this API is to keep
++** a GUI updated during a large query.
++**
++** The progress callback is invoked once for every N virtual machine opcodes,
++** where N is the second argument to this function. The progress callback
++** 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.
++**
++** If a call to sqlite_exec(), sqlite_step() or sqlite_get_table() results 
++** in less than N opcodes being executed, then the progress callback is not
++** invoked.
++** 
++** Calling this routine overwrites any previously installed progress callback.
++** To remove the progress callback altogether, pass NULL as the third
++** argument to this function.
++**
++** 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 sqlite_exec() call returns SQLITE_ABORT. 
++**
++******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
++*/
++void sqlite_progress_handler(sqlite*, 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.
++**
++** If another function was previously registered, its pArg value is returned.
++** Otherwise NULL is returned.
++**
++** Registering a NULL function disables the callback.
++**
++******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
++*/
++void *sqlite_commit_hook(sqlite*, int(*)(void*), void*);
++
++/*
++** Open an encrypted SQLite database.  If pKey==0 or nKey==0, this routine
++** is the same as sqlite_open().
++**
++** The code to implement this API is not available in the public release
++** of SQLite.
++*/
++sqlite *sqlite_open_encrypted(
++  const char *zFilename,   /* Name of the encrypted database */
++  const void *pKey,        /* Pointer to the key */
++  int nKey,                /* Number of bytes in the key */
++  int *pErrcode,           /* Write error code here */
++  char **pzErrmsg          /* Write error message here */
++);
++
++/*
++** Change the key on an open database.  If the current database is not
++** encrypted, this routine will encrypt it.  If pNew==0 or nNew==0, the
++** database is decrypted.
++**
++** The code to implement this API is not available in the public release
++** of SQLite.
++*/
++int sqlite_rekey(
++  sqlite *db,                    /* Database to be rekeyed */
++  const void *pKey, int nKey     /* The new key */
++);
++
++/*
++** Encode a binary buffer "in" of size n bytes so that it contains
++** no instances of characters '\'' or '\000'.  The output is 
++** null-terminated and can be used as a string value in an INSERT
++** or UPDATE statement.  Use sqlite_decode_binary() to convert the
++** string back into its original binary.
++**
++** The result is written into a preallocated output buffer "out".
++** "out" must be able to hold at least 2 +(257*n)/254 bytes.
++** In other words, the output will be expanded by as much as 3
++** bytes for every 254 bytes of input plus 2 bytes of fixed overhead.
++** (This is approximately 2 + 1.0118*n or about a 1.2% size increase.)
++**
++** The return value is the number of characters in the encoded
++** string, excluding the "\000" terminator.
++**
++** If out==NULL then no output is generated but the routine still returns
++** the number of characters that would have been generated if out had
++** not been NULL.
++*/
++int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out);
++
++/*
++** Decode the string "in" into binary data and write it into "out".
++** This routine reverses the encoding created by sqlite_encode_binary().
++** The output will always be a few bytes less than the input.  The number
++** of bytes of output is returned.  If the input is not a well-formed
++** encoding, -1 is returned.
++**
++** The "in" and "out" parameters may point to the same buffer in order
++** to decode a string in place.
++*/
++int sqlite_decode_binary(const unsigned char *in, unsigned char *out);
++
++#ifdef __cplusplus
++}  /* End of the 'extern "C"' block */
++#endif
++
++#endif /* _SQLITE_H_ */
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/sqliteInt.h
+@@ -0,0 +1,1270 @@
++/*
++** 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.
++**
++*************************************************************************
++** Internal interface definitions for SQLite.
++**
++** @(#) $Id$
++*/
++#include "config.h"
++#include "sqlite.h"
++#include "hash.h"
++#include "parse.h"
++#include "btree.h"
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <assert.h>
++
++/*
++** The maximum number of in-memory pages to use for the main database
++** table and for temporary tables.
++*/
++#define MAX_PAGES   2000
++#define TEMP_PAGES   500
++
++/*
++** If the following macro is set to 1, then NULL values are considered
++** distinct for the SELECT DISTINCT statement and for UNION or EXCEPT
++** compound queries.  No other SQL database engine (among those tested) 
++** works this way except for OCELOT.  But the SQL92 spec implies that
++** this is how things should work.
++**
++** If the following macro is set to 0, then NULLs are indistinct for
++** SELECT DISTINCT and for UNION.
++*/
++#define NULL_ALWAYS_DISTINCT 0
++
++/*
++** If the following macro is set to 1, then NULL values are considered
++** distinct when determining whether or not two entries are the same
++** in a UNIQUE index.  This is the way PostgreSQL, Oracle, DB2, MySQL,
++** OCELOT, and Firebird all work.  The SQL92 spec explicitly says this
++** is the way things are suppose to work.
++**
++** If the following macro is set to 0, the NULLs are indistinct for
++** a UNIQUE index.  In this mode, you can only have a single NULL entry
++** for a column declared UNIQUE.  This is the way Informix and SQL Server
++** work.
++*/
++#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 256 because
++** an unsigned character is used to stored the database index.
++*/
++#define MAX_ATTACHED 10
++
++/*
++** The next macro is used to determine where TEMP tables and indices
++** are stored.  Possible values:
++**
++**   0    Always use a temporary files
++**   1    Use a file unless overridden by "PRAGMA temp_store"
++**   2    Use memory unless overridden by "PRAGMA temp_store"
++**   3    Always use memory
++*/
++#ifndef TEMP_STORE
++# define TEMP_STORE 1
++#endif
++
++/*
++** When building SQLite for embedded systems where memory is scarce,
++** you can define one or more of the following macros to omit extra
++** features of the library and thus keep the size of the library to
++** a minimum.
++*/
++/* #define SQLITE_OMIT_AUTHORIZATION  1 */
++/* #define SQLITE_OMIT_INMEMORYDB     1 */
++/* #define SQLITE_OMIT_VACUUM         1 */
++/* #define SQLITE_OMIT_DATETIME_FUNCS 1 */
++/* #define SQLITE_OMIT_PROGRESS_CALLBACK 1 */
++
++/*
++** Integers of known sizes.  These typedefs might change for architectures
++** where the sizes very.  Preprocessor macros are available so that the
++** types can be conveniently redefined at compile-type.  Like this:
++**
++**         cc '-DUINTPTR_TYPE=long long int' ...
++*/
++#ifndef UINT32_TYPE
++# define UINT32_TYPE unsigned int
++#endif
++#ifndef UINT16_TYPE
++# define UINT16_TYPE unsigned short int
++#endif
++#ifndef INT16_TYPE
++# define INT16_TYPE short int
++#endif
++#ifndef UINT8_TYPE
++# define UINT8_TYPE unsigned char
++#endif
++#ifndef INT8_TYPE
++# define INT8_TYPE signed char
++#endif
++#ifndef INTPTR_TYPE
++# if SQLITE_PTR_SZ==4
++#   define INTPTR_TYPE int
++# else
++#   define INTPTR_TYPE long long
++# endif
++#endif
++typedef UINT32_TYPE u32;           /* 4-byte unsigned integer */
++typedef UINT16_TYPE u16;           /* 2-byte unsigned integer */
++typedef INT16_TYPE i16;            /* 2-byte signed integer */
++typedef UINT8_TYPE u8;             /* 1-byte unsigned integer */
++typedef UINT8_TYPE i8;             /* 1-byte signed integer */
++typedef INTPTR_TYPE ptr;           /* Big enough to hold a pointer */
++typedef unsigned INTPTR_TYPE uptr; /* Big enough to hold a pointer */
++
++/*
++** Defer sourcing vdbe.h until after the "u8" typedef is defined.
++*/
++#include "vdbe.h"
++
++/*
++** Most C compilers these days recognize "long double", don't they?
++** Just in case we encounter one that does not, we will create a macro
++** for long double so that it can be easily changed to just "double".
++*/
++#ifndef LONGDOUBLE_TYPE
++# define LONGDOUBLE_TYPE long double
++#endif
++
++/*
++** This macro casts a pointer to an integer.  Useful for doing
++** pointer arithmetic.
++*/
++#define Addr(X)  ((uptr)X)
++
++/*
++** The maximum number of bytes of data that can be put into a single
++** row of a single table.  The upper bound on this limit is 16777215
++** bytes (or 16MB-1).  We have arbitrarily set the limit to just 1MB
++** here because the overflow page chain is inefficient for really big
++** records and we want to discourage people from thinking that 
++** multi-megabyte records are OK.  If your needs are different, you can
++** change this define and recompile to increase or decrease the record
++** size.
++**
++** The 16777198 is computed as follows:  238 bytes of payload on the
++** original pages plus 16448 overflow pages each holding 1020 bytes of
++** data.
++*/
++#define MAX_BYTES_PER_ROW  1048576
++/* #define MAX_BYTES_PER_ROW 16777198 */
++
++/*
++** If memory allocation problems are found, recompile with
++**
++**      -DMEMORY_DEBUG=1
++**
++** to enable some sanity checking on malloc() and free().  To
++** check for memory leaks, recompile with
++**
++**      -DMEMORY_DEBUG=2
++**
++** and a line of text will be written to standard error for
++** each malloc() and free().  This output can be analyzed
++** by an AWK script to determine if there are any leaks.
++*/
++#ifdef MEMORY_DEBUG
++# define sqliteMalloc(X)    sqliteMalloc_(X,1,__FILE__,__LINE__)
++# define sqliteMallocRaw(X) sqliteMalloc_(X,0,__FILE__,__LINE__)
++# define sqliteFree(X)      sqliteFree_(X,__FILE__,__LINE__)
++# define sqliteRealloc(X,Y) sqliteRealloc_(X,Y,__FILE__,__LINE__)
++# define sqliteStrDup(X)    sqliteStrDup_(X,__FILE__,__LINE__)
++# define sqliteStrNDup(X,Y) sqliteStrNDup_(X,Y,__FILE__,__LINE__)
++  void sqliteStrRealloc(char**);
++#else
++# define sqliteRealloc_(X,Y) sqliteRealloc(X,Y)
++# define sqliteStrRealloc(X)
++#endif
++
++/*
++** This variable gets set if malloc() ever fails.  After it gets set,
++** the SQLite library shuts down permanently.
++*/
++extern int sqlite_malloc_failed;
++
++/*
++** The following global variables are used for testing and debugging
++** only.  They only work if MEMORY_DEBUG is defined.
++*/
++#ifdef MEMORY_DEBUG
++extern int sqlite_nMalloc;       /* Number of sqliteMalloc() calls */
++extern int sqlite_nFree;         /* Number of sqliteFree() calls */
++extern int sqlite_iMallocFail;   /* Fail sqliteMalloc() after this many calls */
++#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.
++*/
++#define MASTER_NAME       "sqlite_master"
++#define TEMP_MASTER_NAME  "sqlite_temp_master"
++
++/*
++** The name of the schema table.
++*/
++#define SCHEMA_TABLE(x)  (x?TEMP_MASTER_NAME:MASTER_NAME)
++
++/*
++** A convenience macro that returns the number of elements in
++** an array.
++*/
++#define ArraySize(X)    (sizeof(X)/sizeof(X[0]))
++
++/*
++** Forward references to structures
++*/
++typedef struct Column Column;
++typedef struct Table Table;
++typedef struct Index Index;
++typedef struct Instruction Instruction;
++typedef struct Expr Expr;
++typedef struct ExprList ExprList;
++typedef struct Parse Parse;
++typedef struct Token Token;
++typedef struct IdList IdList;
++typedef struct SrcList SrcList;
++typedef struct WhereInfo WhereInfo;
++typedef struct WhereLevel WhereLevel;
++typedef struct Select Select;
++typedef struct AggExpr AggExpr;
++typedef struct FuncDef FuncDef;
++typedef struct Trigger Trigger;
++typedef struct TriggerStep TriggerStep;
++typedef struct TriggerStack TriggerStack;
++typedef struct FKey FKey;
++typedef struct Db Db;
++typedef struct AuthContext AuthContext;
++
++/*
++** 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
++** aDb[1] is the database file used to hold temporary tables.  Additional
++** databases may be attached.
++*/
++struct Db {
++  char *zName;         /* Name of this database */
++  Btree *pBt;          /* The B*Tree structure for this database file */
++  int schema_cookie;   /* Database schema version number for this file */
++  Hash tblHash;        /* All tables indexed by name */
++  Hash idxHash;        /* All (named) indices indexed by name */
++  Hash trigHash;       /* All triggers indexed by name */
++  Hash aFKey;          /* Foreign keys indexed by to-table */
++  u8 inTrans;          /* 0: not writable.  1: Transaction.  2: Checkpoint */
++  u16 flags;           /* Flags associated with this database */
++  void *pAux;          /* Auxiliary data.  Usually NULL */
++  void (*xFreeAux)(void*);  /* Routine to free pAux */
++};
++
++/*
++** These macros can be used to test, set, or clear bits in the 
++** Db.flags field.
++*/
++#define DbHasProperty(D,I,P)     (((D)->aDb[I].flags&(P))==(P))
++#define DbHasAnyProperty(D,I,P)  (((D)->aDb[I].flags&(P))!=0)
++#define DbSetProperty(D,I,P)     (D)->aDb[I].flags|=(P)
++#define DbClearProperty(D,I,P)   (D)->aDb[I].flags&=~(P)
++
++/*
++** Allowed values for the DB.flags field.
++**
++** The DB_Locked flag is set when the first OP_Transaction or OP_Checkpoint
++** opcode is emitted for a database.  This prevents multiple occurances
++** of those opcodes for the same database in the same program.  Similarly,
++** the DB_Cookie flag is set when the OP_VerifyCookie opcode is emitted,
++** and prevents duplicate OP_VerifyCookies from taking up space and slowing
++** down execution.
++**
++** The DB_SchemaLoaded flag is set after the database schema has been
++** read into internal hash tables.
++**
++** DB_UnresetViews means that one or more views have column names that
++** have been filled out.  If the schema changes, these column names might
++** changes and so the view will need to be reset.
++*/
++#define DB_Locked          0x0001  /* OP_Transaction opcode has been emitted */
++#define DB_Cookie          0x0002  /* OP_VerifyCookie opcode has been emiited */
++#define DB_SchemaLoaded    0x0004  /* The schema has been loaded */
++#define DB_UnresetViews    0x0008  /* Some views have defined column names */
++
++
++/*
++** Each database is an instance of the following structure.
++**
++** The sqlite.file_format is initialized by the database file
++** and helps determines how the data in the database file is
++** represented.  This field allows newer versions of the library
++** to read and write older databases.  The various file formats
++** are as follows:
++**
++**     file_format==1    Version 2.1.0.
++**     file_format==2    Version 2.2.0. Add support for INTEGER PRIMARY KEY.
++**     file_format==3    Version 2.6.0. Fix empty-string index bug.
++**     file_format==4    Version 2.7.0. Add support for separate numeric and
++**                       text datatypes.
++**
++** The sqlite.temp_store determines where temporary database files
++** are stored.  If 1, then a file is created to hold those tables.  If
++** 2, then they are held in memory.  0 means use the default value in
++** the TEMP_STORE macro.
++**
++** The sqlite.lastRowid records the last insert rowid generated by an
++** insert statement.  Inserts on views do not affect its value.  Each
++** trigger has its own context, so that lastRowid can be updated inside
++** triggers as usual.  The previous value will be restored once the trigger
++** exits.  Upon entering a before or instead of trigger, lastRowid is no
++** longer (since after version 2.8.12) reset to -1.
++**
++** The sqlite.nChange does not count changes within triggers and keeps no
++** context.  It is reset at start of sqlite_exec.
++** The sqlite.lsChange represents the number of changes made by the last
++** insert, update, or delete statement.  It remains constant throughout the
++** length of a statement and is then updated by OP_SetCounts.  It keeps a
++** context stack just like lastRowid so that the count of changes
++** within a trigger is not seen outside the trigger.  Changes to views do not
++** affect the value of lsChange.
++** The sqlite.csChange keeps track of the number of current changes (since
++** the last statement) and is used to update sqlite_lsChange.
++*/
++struct sqlite {
++  int nDb;                      /* Number of backends currently in use */
++  Db *aDb;                      /* All backends */
++  Db aDbStatic[2];              /* Static space for the 2 default backends */
++  int flags;                    /* Miscellanous flags. See below */
++  u8 file_format;               /* What file format version is this database? */
++  u8 safety_level;              /* How aggressive at synching data to disk */
++  u8 want_to_close;             /* Close after all VDBEs are deallocated */
++  u8 temp_store;                /* 1=file, 2=memory, 0=compile-time default */
++  u8 onError;                   /* Default conflict algorithm */
++  int next_cookie;              /* Next value of aDb[0].schema_cookie */
++  int cache_size;               /* Number of pages to use in the cache */
++  int nTable;                   /* Number of tables in the database */
++  void *pBusyArg;               /* 1st Argument to the busy callback */
++  int (*xBusyCallback)(void *,const char*,int);  /* The busy callback */
++  void *pCommitArg;             /* Argument to xCommitCallback() */   
++  int (*xCommitCallback)(void*);/* Invoked at every commit. */
++  Hash aFunc;                   /* All functions that can be in SQL exprs */
++  int lastRowid;                /* ROWID of most recent insert (see above) */
++  int priorNewRowid;            /* Last randomly generated ROWID */
++  int magic;                    /* Magic number for detect library misuse */
++  int nChange;                  /* Number of rows changed (see above) */
++  int lsChange;                 /* Last statement change count (see above) */
++  int csChange;                 /* Current statement change count (see above) */
++  struct sqliteInitInfo {       /* 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;
++  struct Vdbe *pVdbe;           /* List of active virtual machines */
++  void (*xTrace)(void*,const char*);     /* Trace function */
++  void *pTraceArg;                       /* Argument to the trace function */
++#ifndef SQLITE_OMIT_AUTHORIZATION
++  int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
++                                /* Access authorization function */
++  void *pAuthArg;               /* 1st argument to the access auth function */
++#endif
++#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
++  int (*xProgress)(void *);     /* The progress callback */
++  void *pProgressArg;           /* Argument to the progress callback */
++  int nProgressOps;             /* Number of opcodes for progress callback */
++#endif
++};
++
++/*
++** Possible values for the sqlite.flags and or Db.flags fields.
++**
++** On sqlite.flags, the SQLITE_InTrans value means that we have
++** executed a BEGIN.  On Db.flags, SQLITE_InTrans means a statement
++** transaction is active on that particular database file.
++*/
++#define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
++#define SQLITE_Initialized    0x00000002  /* True after initialization */
++#define SQLITE_Interrupt      0x00000004  /* Cancel current operation */
++#define SQLITE_InTrans        0x00000008  /* True if in a transaction */
++#define SQLITE_InternChanges  0x00000010  /* Uncommitted Hash table changes */
++#define SQLITE_FullColNames   0x00000020  /* Show full column names on SELECT */
++#define SQLITE_ShortColNames  0x00000040  /* Show short columns names */
++#define SQLITE_CountRows      0x00000080  /* Count rows changed by INSERT, */
++                                          /*   DELETE, or UPDATE and return */
++                                          /*   the count using a callback. */
++#define SQLITE_NullCallback   0x00000100  /* Invoke the callback once if the */
++                                          /*   result set is empty */
++#define SQLITE_ReportTypes    0x00000200  /* Include information on datatypes */
++                                          /*   in 4th argument of callback */
++
++/*
++** Possible values for the sqlite.magic field.
++** The numbers are obtained at random and have no special meaning, other
++** than being distinct from one another.
++*/
++#define SQLITE_MAGIC_OPEN     0xa029a697  /* Database is open */
++#define SQLITE_MAGIC_CLOSED   0x9f3c2d33  /* Database is closed */
++#define SQLITE_MAGIC_BUSY     0xf03b7906  /* Database currently in use */
++#define SQLITE_MAGIC_ERROR    0xb5357930  /* An SQLITE_MISUSE error occurred */
++
++/*
++** Each SQL function is defined by an instance of the following
++** structure.  A pointer to this structure is stored in the sqlite.aFunc
++** hash table.  When multiple functions have the same name, the hash table
++** points to a linked list of these structures.
++*/
++struct FuncDef {
++  void (*xFunc)(sqlite_func*,int,const char**);  /* Regular function */
++  void (*xStep)(sqlite_func*,int,const char**);  /* Aggregate function step */
++  void (*xFinalize)(sqlite_func*);           /* Aggregate function finializer */
++  signed char nArg;         /* Number of arguments.  -1 means unlimited */
++  signed char dataType;     /* Arg that determines datatype.  -1=NUMERIC, */
++                            /* -2=TEXT. -3=SQLITE_ARGS */
++  u8 includeTypes;          /* Add datatypes to args of xFunc and xStep */
++  void *pUserData;          /* User data parameter */
++  FuncDef *pNext;           /* Next function with same name */
++};
++
++/*
++** information about each column of an SQL table is held in an instance
++** of this structure.
++*/
++struct Column {
++  char *zName;     /* Name of this column */
++  char *zDflt;     /* Default value of this column */
++  char *zType;     /* Data type for this column */
++  u8 notNull;      /* True if there is a NOT NULL constraint */
++  u8 isPrimKey;    /* True if this column is part of the PRIMARY KEY */
++  u8 sortOrder;    /* Some combination of SQLITE_SO_... values */
++  u8 dottedName;   /* True if zName contains a "." character */
++};
++
++/*
++** The allowed sort orders.
++**
++** The TEXT and NUM values use bits that do not overlap with DESC and ASC.
++** That way the two can be combined into a single number.
++*/
++#define SQLITE_SO_UNK       0  /* Use the default collating type.  (SCT_NUM) */
++#define SQLITE_SO_TEXT      2  /* Sort using memcmp() */
++#define SQLITE_SO_NUM       4  /* Sort using sqliteCompare() */
++#define SQLITE_SO_TYPEMASK  6  /* Mask to extract the collating sequence */
++#define SQLITE_SO_ASC       0  /* Sort in ascending order */
++#define SQLITE_SO_DESC      1  /* Sort in descending order */
++#define SQLITE_SO_DIRMASK   1  /* Mask to extract the sort direction */
++
++/*
++** Each SQL table is represented in memory by an instance of the
++** following structure.
++**
++** Table.zName is the name of the table.  The case of the original
++** CREATE TABLE statement is stored, but case is not significant for
++** comparisons.
++**
++** Table.nCol is the number of columns in this table.  Table.aCol is a
++** pointer to an array of Column structures, one for each column.
++**
++** If the table has an INTEGER PRIMARY KEY, then Table.iPKey is the index of
++** the column that is that key.   Otherwise Table.iPKey is negative.  Note
++** that the datatype of the PRIMARY KEY must be INTEGER for this field to
++** be set.  An INTEGER PRIMARY KEY is used as the rowid for each row of
++** the table.  If a table has no INTEGER PRIMARY KEY, then a random rowid
++** is generated for each row of the table.  Table.hasPrimKey is true if
++** the table has any PRIMARY KEY, INTEGER or otherwise.
++**
++** Table.tnum is the page number for the root BTree page of the table in the
++** database file.  If Table.iDb is the index of the database table backend
++** in sqlite.aDb[].  0 is for the main database and 1 is for the file that
++** holds temporary tables and indices.  If Table.isTransient
++** is true, then the table is stored in a file that is automatically deleted
++** when the VDBE cursor to the table is closed.  In this case Table.tnum 
++** refers VDBE cursor number that holds the table open, not to the root
++** page number.  Transient tables are used to hold the results of a
++** sub-query that appears instead of a real table name in the FROM clause 
++** of a SELECT statement.
++*/
++struct Table {
++  char *zName;     /* Name of the table */
++  int nCol;        /* Number of columns in this table */
++  Column *aCol;    /* Information about each column */
++  int iPKey;       /* If not less then 0, use aCol[iPKey] as the primary key */
++  Index *pIndex;   /* List of SQL indexes on this table. */
++  int tnum;        /* Root BTree node for this table (see note above) */
++  Select *pSelect; /* NULL for tables.  Points to definition if a view. */
++  u8 readOnly;     /* True if this table should not be written by the user */
++  u8 iDb;          /* Index into sqlite.aDb[] of the backend for this table */
++  u8 isTransient;  /* True if automatically deleted when VDBE finishes */
++  u8 hasPrimKey;   /* True if there exists a primary key */
++  u8 keyConf;      /* What to do in case of uniqueness conflict on iPKey */
++  Trigger *pTrigger; /* List of SQL triggers on this table */
++  FKey *pFKey;       /* Linked list of all foreign keys in this table */
++};
++
++/*
++** Each foreign key constraint is an instance of the following structure.
++**
++** A foreign key is associated with two tables.  The "from" table is
++** the table that contains the REFERENCES clause that creates the foreign
++** key.  The "to" table is the table that is named in the REFERENCES clause.
++** Consider this example:
++**
++**     CREATE TABLE ex1(
++**       a INTEGER PRIMARY KEY,
++**       b INTEGER CONSTRAINT fk1 REFERENCES ex2(x)
++**     );
++**
++** For foreign key "fk1", the from-table is "ex1" and the to-table is "ex2".
++**
++** Each REFERENCES clause generates an instance of the following structure
++** which is attached to the from-table.  The to-table need not exist when
++** the from-table is created.  The existance of the to-table is not checked
++** until an attempt is made to insert data into the from-table.
++**
++** The sqlite.aFKey hash table stores pointers to this structure
++** given the name of a to-table.  For each to-table, all foreign keys
++** associated with that table are on a linked list using the FKey.pNextTo
++** field.
++*/
++struct FKey {
++  Table *pFrom;     /* The table that constains the REFERENCES clause */
++  FKey *pNextFrom;  /* Next foreign key in pFrom */
++  char *zTo;        /* Name of table that the key points to */
++  FKey *pNextTo;    /* Next foreign key that points to zTo */
++  int nCol;         /* Number of columns in this key */
++  struct sColMap {  /* Mapping of columns in pFrom to columns in zTo */
++    int iFrom;         /* Index of column in pFrom */
++    char *zCol;        /* Name of column in zTo.  If 0 use PRIMARY KEY */
++  } *aCol;          /* One entry for each of nCol column s */
++  u8 isDeferred;    /* True if constraint checking is deferred till COMMIT */
++  u8 updateConf;    /* How to resolve conflicts that occur on UPDATE */
++  u8 deleteConf;    /* How to resolve conflicts that occur on DELETE */
++  u8 insertConf;    /* How to resolve conflicts that occur on INSERT */
++};
++
++/*
++** SQLite supports many different ways to resolve a contraint
++** 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
++** fails and any prior changes from that one operation are backed out,
++** but the transaction is not rolled back.  FAIL processing means that
++** the operation in progress stops and returns an error code.  But prior
++** changes due to the same operation are not backed out and no rollback
++** occurs.  IGNORE means that the particular row that caused the constraint
++** error is not inserted or updated.  Processing continues and no error
++** is returned.  REPLACE means that preexisting database rows that caused
++** a UNIQUE constraint violation are removed so that the new insert or
++** update can proceed.  Processing continues and no error is reported.
++**
++** RESTRICT, SETNULL, and CASCADE actions apply only to foreign keys.
++** RESTRICT is the same as ABORT for IMMEDIATE foreign keys and the
++** same as ROLLBACK for DEFERRED keys.  SETNULL means that the foreign
++** key is set to NULL.  CASCADE means that a DELETE or UPDATE of the
++** referenced table row is propagated into the row that holds the
++** foreign key.
++** 
++** The following symbolic values are used to record which type
++** of action to take.
++*/
++#define OE_None     0   /* There is no constraint to check */
++#define OE_Rollback 1   /* Fail the operation and rollback the transaction */
++#define OE_Abort    2   /* Back out changes but do no rollback transaction */
++#define OE_Fail     3   /* Stop the operation but leave all prior changes */
++#define OE_Ignore   4   /* Ignore the error. Do not do the INSERT or UPDATE */
++#define OE_Replace  5   /* Delete existing record, then do INSERT or UPDATE */
++
++#define OE_Restrict 6   /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */
++#define OE_SetNull  7   /* Set the foreign key value to NULL */
++#define OE_SetDflt  8   /* Set the foreign key value to its default */
++#define OE_Cascade  9   /* Cascade the changes */
++
++#define OE_Default  99  /* Do whatever the default action is */
++
++/*
++** Each SQL index is represented in memory by an
++** instance of the following structure.
++**
++** The columns of the table that are to be indexed are described
++** by the aiColumn[] field of this structure.  For example, suppose
++** we have the following table and index:
++**
++**     CREATE TABLE Ex1(c1 int, c2 int, c3 text);
++**     CREATE INDEX Ex2 ON Ex1(c3,c1);
++**
++** In the Table structure describing Ex1, nCol==3 because there are
++** three columns in the table.  In the Index structure describing
++** Ex2, nColumn==2 since 2 of the 3 columns of Ex1 are indexed.
++** The value of aiColumn is {2, 0}.  aiColumn[0]==2 because the 
++** first column to be indexed (c3) has an index of 2 in Ex1.aCol[].
++** The second column to be indexed (c1) has an index of 0 in
++** Ex1.aCol[], hence Ex2.aiColumn[1]==0.
++**
++** The Index.onError field determines whether or not the indexed columns
++** must be unique and what to do if they are not.  When Index.onError=OE_None,
++** it means this is not a unique index.  Otherwise it is a unique index
++** and the value of Index.onError indicate the which conflict resolution 
++** algorithm to employ whenever an attempt is made to insert a non-unique
++** element.
++*/
++struct Index {
++  char *zName;     /* Name of this index */
++  int nColumn;     /* Number of columns in the table used by this index */
++  int *aiColumn;   /* Which columns are used by this index.  1st is 0 */
++  Table *pTable;   /* The SQL table being indexed */
++  int tnum;        /* Page containing root of this index in database file */
++  u8 onError;      /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
++  u8 autoIndex;    /* True if is automatically created (ex: by UNIQUE) */
++  u8 iDb;          /* Index in sqlite.aDb[] of where this index is stored */
++  Index *pNext;    /* The next index associated with the same table */
++};
++
++/*
++** Each token coming out of the lexer is an instance of
++** this structure.  Tokens are also used as part of an expression.
++**
++** Note if Token.z==0 then Token.dyn and Token.n are undefined and
++** may contain random values.  Do not make any assuptions about Token.dyn
++** and Token.n when Token.z==0.
++*/
++struct Token {
++  const char *z;      /* Text of the token.  Not NULL-terminated! */
++  unsigned dyn  : 1;  /* True for malloced memory, false for static */
++  unsigned n    : 31; /* Number of characters in this token */
++};
++
++/*
++** Each node of an expression in the parse tree is an instance
++** of this structure.
++**
++** Expr.op is the opcode.  The integer parser token codes are reused
++** as opcodes here.  For example, the parser defines TK_GE to be an integer
++** code representing the ">=" operator.  This same integer code is reused
++** to represent the greater-than-or-equal-to operator in the expression
++** tree.
++**
++** Expr.pRight and Expr.pLeft are subexpressions.  Expr.pList is a list
++** of argument if the expression is a function.
++**
++** Expr.token is the operator token for this node.  For some expressions
++** that have subexpressions, Expr.token can be the complete text that gave
++** rise to the Expr.  In the latter case, the token is marked as being
++** a compound token.
++**
++** An expression of the form ID or ID.ID refers to a column in a table.
++** For such expressions, Expr.op is set to TK_COLUMN and Expr.iTable is
++** the integer cursor number of a VDBE cursor pointing to that table and
++** Expr.iColumn is the column number for the specific column.  If the
++** expression is used as a result in an aggregate SELECT, then the
++** value is also stored in the Expr.iAgg column in the aggregate so that
++** it can be accessed after all aggregates are computed.
++**
++** If the expression is a function, the Expr.iTable is an integer code
++** representing which function.  If the expression is an unbound variable
++** marker (a question mark character '?' in the original SQL) then the
++** Expr.iTable holds the index number for that variable.
++**
++** The Expr.pSelect field points to a SELECT statement.  The SELECT might
++** be the right operand of an IN operator.  Or, if a scalar SELECT appears
++** in an expression the opcode is TK_SELECT and Expr.pSelect is the only
++** operand.
++*/
++struct Expr {
++  u8 op;                 /* Operation performed by this node */
++  u8 dataType;           /* Either SQLITE_SO_TEXT or SQLITE_SO_NUM */
++  u8 iDb;                /* Database referenced by this expression */
++  u8 flags;              /* Various flags.  See below */
++  Expr *pLeft, *pRight;  /* Left and right subnodes */
++  ExprList *pList;       /* A list of expressions used as function arguments
++                         ** or in "<expr> IN (<expr-list)" */
++  Token token;           /* An operand token */
++  Token span;            /* Complete text of the expression */
++  int iTable, iColumn;   /* When op==TK_COLUMN, then this expr node means the
++                         ** iColumn-th field of the iTable-th table. */
++  int iAgg;              /* When op==TK_COLUMN and pParse->useAgg==TRUE, pull
++                         ** result from the iAgg-th element of the aggregator */
++  Select *pSelect;       /* When the expression is a sub-select.  Also the
++                         ** right side of "<expr> IN (<select>)" */
++};
++
++/*
++** The following are the meanings of bits in the Expr.flags field.
++*/
++#define EP_FromJoin     0x0001  /* Originated in ON or USING clause of a join */
++
++/*
++** These macros can be used to test, set, or clear bits in the 
++** Expr.flags field.
++*/
++#define ExprHasProperty(E,P)     (((E)->flags&(P))==(P))
++#define ExprHasAnyProperty(E,P)  (((E)->flags&(P))!=0)
++#define ExprSetProperty(E,P)     (E)->flags|=(P)
++#define ExprClearProperty(E,P)   (E)->flags&=~(P)
++
++/*
++** A list of expressions.  Each expression may optionally have a
++** name.  An expr/name combination can be used in several ways, such
++** as the list of "expr AS ID" fields following a "SELECT" or in the
++** list of "ID = expr" items in an UPDATE.  A list of expressions can
++** also be used as the argument to a function, in which case the a.zName
++** field is not used.
++*/
++struct ExprList {
++  int nExpr;             /* Number of expressions on the list */
++  int nAlloc;            /* Number of entries allocated below */
++  struct ExprList_item {
++    Expr *pExpr;           /* The list of expressions */
++    char *zName;           /* Token associated with this expression */
++    u8 sortOrder;          /* 1 for DESC or 0 for ASC */
++    u8 isAgg;              /* True if this is an aggregate like count(*) */
++    u8 done;               /* A flag to indicate when processing is finished */
++  } *a;                  /* One entry for each expression */
++};
++
++/*
++** An instance of this structure can hold a simple list of identifiers,
++** such as the list "a,b,c" in the following statements:
++**
++**      INSERT INTO t(a,b,c) VALUES ...;
++**      CREATE INDEX idx ON t(a,b,c);
++**      CREATE TRIGGER trig BEFORE UPDATE ON t(a,b,c) ...;
++**
++** The IdList.a.idx field is used when the IdList represents the list of
++** column names after a table name in an INSERT statement.  In the statement
++**
++**     INSERT INTO t(a,b,c) ...
++**
++** If "a" is the k-th column of table "t", then IdList.a[0].idx==k.
++*/
++struct IdList {
++  int nId;         /* Number of identifiers on the list */
++  int nAlloc;      /* Number of entries allocated for a[] below */
++  struct IdList_item {
++    char *zName;      /* Name of the identifier */
++    int idx;          /* Index in some Table.aCol[] of a column named zName */
++  } *a;
++};
++
++/*
++** The following structure describes the FROM clause of a SELECT statement.
++** Each table or subquery in the FROM clause is a separate element of
++** the SrcList.a[] array.
++**
++** With the addition of multiple database support, the following structure
++** can also be used to describe a particular table such as the table that
++** 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.
++*/
++struct SrcList {
++  i16 nSrc;        /* Number of tables or subqueries in the FROM clause */
++  i16 nAlloc;      /* Number of entries allocated in a[] below */
++  struct SrcList_item {
++    char *zDatabase;  /* Name of database holding this table */
++    char *zName;      /* Name of the table */
++    char *zAlias;     /* The "B" part of a "A AS B" phrase.  zName is the "A" */
++    Table *pTab;      /* An SQL table corresponding to zName */
++    Select *pSelect;  /* A SELECT statement used in place of a table name */
++    int jointype;     /* Type of join between this table and the next */
++    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 */
++  } a[1];             /* One entry for each identifier on the list */
++};
++
++/*
++** Permitted values of the SrcList.a.jointype field
++*/
++#define JT_INNER     0x0001    /* Any kind of inner or cross join */
++#define JT_NATURAL   0x0002    /* True for a "natural" join */
++#define JT_LEFT      0x0004    /* Left outer join */
++#define JT_RIGHT     0x0008    /* Right outer join */
++#define JT_OUTER     0x0010    /* The "OUTER" keyword is present */
++#define JT_ERROR     0x0020    /* unknown or unsupported join type */
++
++/*
++** For each nested loop in a WHERE clause implementation, the WhereInfo
++** structure contains a single instance of this structure.  This structure
++** is intended to be private the the where.c module and should not be
++** access or modified by other modules.
++*/
++struct WhereLevel {
++  int iMem;            /* Memory cell used by this level */
++  Index *pIdx;         /* Index used */
++  int iCur;            /* Cursor number used for this index */
++  int score;           /* How well this indexed scored */
++  int brk;             /* Jump here to break out of the loop */
++  int cont;            /* Jump here to continue with the next loop cycle */
++  int op, p1, p2;      /* Opcode used to terminate the loop */
++  int iLeftJoin;       /* Memory cell used to implement LEFT OUTER JOIN */
++  int top;             /* First instruction of interior of the loop */
++  int inOp, inP1, inP2;/* Opcode used to implement an IN operator */
++  int bRev;            /* Do the scan in the reverse direction */
++};
++
++/*
++** The WHERE clause processing routine has two halves.  The
++** first part does the start of the WHERE loop and the second
++** half does the tail of the WHERE loop.  An instance of
++** this structure is returned by the first half and passed
++** into the second half to give some continuity.
++*/
++struct WhereInfo {
++  Parse *pParse;
++  SrcList *pTabList;   /* List of tables in the join */
++  int iContinue;       /* Jump here to continue with next record */
++  int iBreak;          /* Jump here to break out of the loop */
++  int nLevel;          /* Number of nested loop */
++  int savedNTab;       /* Value of pParse->nTab before WhereBegin() */
++  int peakNTab;        /* Value of pParse->nTab after WhereBegin() */
++  WhereLevel a[1];     /* Information about each nest loop in the WHERE */
++};
++
++/*
++** An instance of the following structure contains all information
++** needed to generate code for a single SELECT statement.
++**
++** The zSelect field is used when the Select structure must be persistent.
++** Normally, the expression tree points to tokens in the original input
++** string that encodes the select.  But if the Select structure must live
++** longer than its input string (for example when it is used to describe
++** a VIEW) we have to make a copy of the input string so that the nodes
++** of the expression tree will have something to point to.  zSelect is used
++** to hold that copy.
++**
++** nLimit is set to -1 if there is no LIMIT clause.  nOffset is set to 0.
++** If there is a LIMIT clause, the parser sets nLimit to the value of the
++** limit and nOffset to the value of the offset (or 0 if there is not
++** offset).  But later on, nLimit and nOffset become the memory locations
++** in the VDBE that record the limit and offset counters.
++*/
++struct Select {
++  ExprList *pEList;      /* The fields of the result */
++  u8 op;                 /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
++  u8 isDistinct;         /* True if the DISTINCT keyword is present */
++  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 */
++  int nLimit, nOffset;   /* LIMIT and OFFSET values.  -1 means not used */
++  int iLimit, iOffset;   /* Memory registers holding LIMIT & OFFSET counters */
++  char *zSelect;         /* Complete text of the SELECT command */
++};
++
++/*
++** The results of a select can be distributed in several ways.
++*/
++#define SRT_Callback     1  /* Invoke a callback with each row of result */
++#define SRT_Mem          2  /* Store result in a memory cell */
++#define SRT_Set          3  /* Store result as unique keys in a table */
++#define SRT_Union        5  /* Store result as keys in a table */
++#define SRT_Except       6  /* Remove result from a UNION table */
++#define SRT_Table        7  /* Store result as data with a unique key */
++#define SRT_TempTable    8  /* Store result in a trasient table */
++#define SRT_Discard      9  /* Do not save the results anywhere */
++#define SRT_Sorter      10  /* Store results in the sorter */
++#define SRT_Subroutine  11  /* Call a subroutine to handle results */
++
++/*
++** When a SELECT uses aggregate functions (like "count(*)" or "avg(f1)")
++** we have to do some additional analysis of expressions.  An instance
++** of the following structure holds information about a single subexpression
++** somewhere in the SELECT statement.  An array of these structures holds
++** all the information we need to generate code for aggregate
++** expressions.
++**
++** Note that when analyzing a SELECT containing aggregates, both
++** non-aggregate field variables and aggregate functions are stored
++** in the AggExpr array of the Parser structure.
++**
++** The pExpr field points to an expression that is part of either the
++** field list, the GROUP BY clause, the HAVING clause or the ORDER BY
++** clause.  The expression will be freed when those clauses are cleaned
++** up.  Do not try to delete the expression attached to AggExpr.pExpr.
++**
++** If AggExpr.pExpr==0, that means the expression is "count(*)".
++*/
++struct AggExpr {
++  int isAgg;        /* if TRUE contains an aggregate function */
++  Expr *pExpr;      /* The expression */
++  FuncDef *pFunc;   /* Information about the aggregate function */
++};
++
++/*
++** An SQL parser context.  A copy of this structure is passed through
++** the parser and down into all the parser action routine in order to
++** carry around information that is global to the entire parse.
++*/
++struct Parse {
++  sqlite *db;          /* The main database structure */
++  int rc;              /* Return code from execution */
++  char *zErrMsg;       /* An error message */
++  Token sErrToken;     /* The token at which the error occurred */
++  Token sFirstToken;   /* The first token parsed */
++  Token sLastToken;    /* The last token parsed */
++  const char *zTail;   /* All SQL text past the last semicolon parsed */
++  Table *pNewTable;    /* A table being constructed by CREATE TABLE */
++  Vdbe *pVdbe;         /* An engine for executing database bytecode */
++  u8 colNamesSet;      /* TRUE after OP_ColumnName has been issued to pVdbe */
++  u8 explain;          /* True if the EXPLAIN flag is found on the query */
++  u8 nameClash;        /* A permanent table name clashes with temp table name */
++  u8 useAgg;           /* If true, extract field values from the aggregator
++                       ** while generating expressions.  Normally false */
++  int nErr;            /* Number of errors seen */
++  int nTab;            /* Number of previously allocated VDBE cursors */
++  int nMem;            /* Number of memory cells used so far */
++  int nSet;            /* Number of sets used so far */
++  int nAgg;            /* Number of aggregate expressions */
++  int nVar;            /* Number of '?' variables seen in the SQL so far */
++  AggExpr *aAgg;       /* An array of aggregate expressions */
++  const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
++  Trigger *pNewTrigger;     /* Trigger under construct by a CREATE TRIGGER */
++  TriggerStack *trigStack;  /* Trigger actions being coded */
++};
++
++/*
++** An instance of the following structure can be declared on a stack and used
++** to save the Parse.zAuthContext value so that it can be restored later.
++*/
++struct AuthContext {
++  const char *zAuthContext;   /* Put saved Parse.zAuthContext here */
++  Parse *pParse;              /* The Parse structure */
++};
++
++/*
++** Bitfield flags for P2 value in OP_PutIntKey and OP_Delete
++*/
++#define OPFLAG_NCHANGE   1    /* Set to update db->nChange */
++#define OPFLAG_LASTROWID 2    /* Set to update db->lastRowid */
++#define OPFLAG_CSCHANGE  4    /* Set to update db->csChange */
++
++/*
++ * Each trigger present in the database schema is stored as an instance of
++ * struct Trigger. 
++ *
++ * Pointers to instances of struct Trigger are stored in two ways.
++ * 1. In the "trigHash" hash table (part of the sqlite* that represents the 
++ *    database). This allows Trigger structures to be retrieved by name.
++ * 2. All triggers associated with a single table form a linked list, using the
++ *    pNext member of struct Trigger. A pointer to the first element of the
++ *    linked list is stored as the "pTrigger" member of the associated
++ *    struct Table.
++ *
++ * The "step_list" member points to the first element of a linked list
++ * containing the SQL statements specified as the trigger program.
++ */
++struct Trigger {
++  char *name;             /* The name of the trigger                        */
++  char *table;            /* The table or view to which the trigger applies */
++  u8 iDb;                 /* Database containing this trigger               */
++  u8 iTabDb;              /* Database containing Trigger.table              */
++  u8 op;                  /* One of TK_DELETE, TK_UPDATE, TK_INSERT         */
++  u8 tr_tm;               /* One of TK_BEFORE, TK_AFTER */
++  Expr *pWhen;            /* The WHEN clause of the expresion (may be NULL) */
++  IdList *pColumns;       /* If this is an UPDATE OF <column-list> trigger,
++                             the <column-list> is stored here */
++  int foreach;            /* One of TK_ROW or TK_STATEMENT */
++  Token nameToken;        /* Token containing zName. Use during parsing only */
++
++  TriggerStep *step_list; /* Link list of trigger program steps             */
++  Trigger *pNext;         /* Next trigger associated with the table */
++};
++
++/*
++ * An instance of struct TriggerStep is used to store a single SQL statement
++ * that is a part of a trigger-program. 
++ *
++ * Instances of struct TriggerStep are stored in a singly linked list (linked
++ * using the "pNext" member) referenced by the "step_list" member of the 
++ * associated struct Trigger instance. The first element of the linked list is
++ * the first step of the trigger-program.
++ * 
++ * The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or
++ * "SELECT" statement. The meanings of the other members is determined by the 
++ * value of "op" as follows:
++ *
++ * (op == TK_INSERT)
++ * orconf    -> stores the ON CONFLICT algorithm
++ * pSelect   -> If this is an INSERT INTO ... SELECT ... statement, then
++ *              this stores a pointer to the SELECT statement. Otherwise NULL.
++ * target    -> A token holding the name of the table to insert into.
++ * pExprList -> If this is an INSERT INTO ... VALUES ... statement, then
++ *              this stores values to be inserted. Otherwise NULL.
++ * pIdList   -> If this is an INSERT INTO ... (<column-names>) VALUES ... 
++ *              statement, then this stores the column-names to be
++ *              inserted into.
++ *
++ * (op == TK_DELETE)
++ * target    -> A token holding the name of the table to delete from.
++ * pWhere    -> The WHERE clause of the DELETE statement if one is specified.
++ *              Otherwise NULL.
++ * 
++ * (op == TK_UPDATE)
++ * target    -> A token holding the name of the table to update rows of.
++ * pWhere    -> The WHERE clause of the UPDATE statement if one is specified.
++ *              Otherwise NULL.
++ * pExprList -> A list of the columns to update and the expressions to update
++ *              them to. See sqliteUpdate() documentation of "pChanges"
++ *              argument.
++ * 
++ */
++struct TriggerStep {
++  int op;              /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */
++  int orconf;          /* OE_Rollback etc. */
++  Trigger *pTrig;      /* The trigger that this step is a part of */
++
++  Select *pSelect;     /* Valid for SELECT and sometimes 
++                        INSERT steps (when pExprList == 0) */
++  Token target;        /* Valid for DELETE, UPDATE, INSERT steps */
++  Expr *pWhere;        /* Valid for DELETE, UPDATE steps */
++  ExprList *pExprList; /* Valid for UPDATE statements and sometimes 
++                         INSERT steps (when pSelect == 0)         */
++  IdList *pIdList;     /* Valid for INSERT statements only */
++
++  TriggerStep * pNext; /* Next in the link-list */
++};
++
++/*
++ * An instance of struct TriggerStack stores information required during code
++ * generation of a single trigger program. While the trigger program is being
++ * coded, its associated TriggerStack instance is pointed to by the
++ * "pTriggerStack" member of the Parse structure.
++ *
++ * The pTab member points to the table that triggers are being coded on. The 
++ * newIdx member contains the index of the vdbe cursor that points at the temp
++ * table that stores the new.* references. If new.* references are not valid
++ * for the trigger being coded (for example an ON DELETE trigger), then newIdx
++ * is set to -1. The oldIdx member is analogous to newIdx, for old.* references.
++ *
++ * The ON CONFLICT policy to be used for the trigger program steps is stored 
++ * as the orconf member. If this is OE_Default, then the ON CONFLICT clause 
++ * specified for individual triggers steps is used.
++ *
++ * struct TriggerStack has a "pNext" member, to allow linked lists to be
++ * constructed. When coding nested triggers (triggers fired by other triggers)
++ * each nested trigger stores its parent trigger's TriggerStack as the "pNext" 
++ * pointer. Once the nested trigger has been coded, the pNext value is restored
++ * to the pTriggerStack member of the Parse stucture and coding of the parent
++ * trigger continues.
++ *
++ * Before a nested trigger is coded, the linked list pointed to by the 
++ * pTriggerStack is scanned to ensure that the trigger is not about to be coded
++ * recursively. If this condition is detected, the nested trigger is not coded.
++ */
++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 */
++  int orconf;          /* Current orconf policy */
++  int ignoreJump;      /* where to jump to for a RAISE(IGNORE) */
++  Trigger *pTrigger;   /* The trigger currently being coded */
++  TriggerStack *pNext; /* Next trigger down on the trigger stack */
++};
++
++/*
++** The following structure contains information used by the sqliteFix...
++** routines as they walk the parse tree to make database references
++** explicit.  
++*/
++typedef struct DbFixer DbFixer;
++struct DbFixer {
++  Parse *pParse;      /* The parsing context.  Error messages written here */
++  const char *zDb;    /* Make sure all objects are contained in this database */
++  const char *zType;  /* Type of the container - used for error messages */
++  const Token *pName; /* Name of the container - used for error messages */
++};
++
++/*
++ * 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 always_code_trigger_setup;
++
++/*
++** Internal function prototypes
++*/
++int sqliteStrICmp(const char *, const char *);
++int sqliteStrNICmp(const char *, const char *, int);
++int sqliteHashNoCase(const char *, int);
++int sqliteIsNumber(const char*);
++int sqliteCompare(const char *, const char *);
++int sqliteSortCompare(const char *, const char *);
++void sqliteRealToSortable(double r, char *);
++#ifdef MEMORY_DEBUG
++  void *sqliteMalloc_(int,int,char*,int);
++  void sqliteFree_(void*,char*,int);
++  void *sqliteRealloc_(void*,int,char*,int);
++  char *sqliteStrDup_(const char*,char*,int);
++  char *sqliteStrNDup_(const char*, int,char*,int);
++  void sqliteCheckMemory(void*,int);
++#else
++  void *sqliteMalloc(int);
++  void *sqliteMallocRaw(int);
++  void sqliteFree(void*);
++  void *sqliteRealloc(void*,int);
++  char *sqliteStrDup(const char*);
++  char *sqliteStrNDup(const char*, int);
++# define sqliteCheckMemory(a,b)
++#endif
++char *sqliteMPrintf(const char*, ...);
++char *sqliteVMPrintf(const char*, va_list);
++void sqliteSetString(char **, ...);
++void sqliteSetNString(char **, ...);
++void sqliteErrorMsg(Parse*, const char*, ...);
++void sqliteDequote(char*);
++int sqliteKeywordCode(const char*, int);
++int sqliteRunParser(Parse*, const char*, char **);
++void sqliteExec(Parse*);
++Expr *sqliteExpr(int, Expr*, Expr*, Token*);
++void sqliteExprSpan(Expr*,Token*,Token*);
++Expr *sqliteExprFunction(ExprList*, Token*);
++void sqliteExprDelete(Expr*);
++ExprList *sqliteExprListAppend(ExprList*,Expr*,Token*);
++void sqliteExprListDelete(ExprList*);
++int sqliteInit(sqlite*, char**);
++void sqlitePragma(Parse*,Token*,Token*,int);
++void sqliteResetInternalSchema(sqlite*, int);
++void sqliteBeginParse(Parse*,int);
++void sqliteRollbackInternalChanges(sqlite*);
++void sqliteCommitInternalChanges(sqlite*);
++Table *sqliteResultSetOfSelect(Parse*,char*,Select*);
++void sqliteOpenMasterTable(Vdbe *v, int);
++void sqliteStartTable(Parse*,Token*,Token*,int,int);
++void sqliteAddColumn(Parse*,Token*);
++void sqliteAddNotNull(Parse*, int);
++void sqliteAddPrimaryKey(Parse*, IdList*, int);
++void sqliteAddColumnType(Parse*,Token*,Token*);
++void sqliteAddDefaultValue(Parse*,Token*,int);
++int sqliteCollateType(const char*, int);
++void sqliteAddCollateType(Parse*, int);
++void sqliteEndTable(Parse*,Token*,Select*);
++void sqliteCreateView(Parse*,Token*,Token*,Select*,int);
++int sqliteViewGetColumnNames(Parse*,Table*);
++void sqliteDropTable(Parse*, Token*, int);
++void sqliteDeleteTable(sqlite*, Table*);
++void sqliteInsert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
++IdList *sqliteIdListAppend(IdList*, Token*);
++int sqliteIdListIndex(IdList*,const char*);
++SrcList *sqliteSrcListAppend(SrcList*, Token*, Token*);
++void sqliteSrcListAddAlias(SrcList*, Token*);
++void sqliteSrcListAssignCursors(Parse*, SrcList*);
++void sqliteIdListDelete(IdList*);
++void sqliteSrcListDelete(SrcList*);
++void sqliteCreateIndex(Parse*,Token*,SrcList*,IdList*,int,Token*,Token*);
++void sqliteDropIndex(Parse*, SrcList*);
++void sqliteAddKeyType(Vdbe*, ExprList*);
++void sqliteAddIdxKeyType(Vdbe*, Index*);
++int sqliteSelect(Parse*, Select*, int, int, Select*, int, int*);
++Select *sqliteSelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*,
++                        int,int,int);
++void sqliteSelectDelete(Select*);
++void sqliteSelectUnbind(Select*);
++Table *sqliteSrcListLookup(Parse*, SrcList*);
++int sqliteIsReadOnly(Parse*, Table*, int);
++void sqliteDeleteFrom(Parse*, SrcList*, Expr*);
++void sqliteUpdate(Parse*, SrcList*, ExprList*, Expr*, int);
++WhereInfo *sqliteWhereBegin(Parse*, SrcList*, Expr*, int, ExprList**);
++void sqliteWhereEnd(WhereInfo*);
++void sqliteExprCode(Parse*, Expr*);
++int sqliteExprCodeExprList(Parse*, ExprList*, int);
++void sqliteExprIfTrue(Parse*, Expr*, int, int);
++void sqliteExprIfFalse(Parse*, Expr*, int, int);
++Table *sqliteFindTable(sqlite*,const char*, const char*);
++Table *sqliteLocateTable(Parse*,const char*, const char*);
++Index *sqliteFindIndex(sqlite*,const char*, const char*);
++void sqliteUnlinkAndDeleteIndex(sqlite*,Index*);
++void sqliteCopy(Parse*, SrcList*, Token*, Token*, int);
++void sqliteVacuum(Parse*, Token*);
++int sqliteRunVacuum(char**, sqlite*);
++int sqliteGlobCompare(const unsigned char*,const unsigned char*);
++int sqliteLikeCompare(const unsigned char*,const unsigned char*);
++char *sqliteTableNameFromToken(Token*);
++int sqliteExprCheck(Parse*, Expr*, int, int*);
++int sqliteExprType(Expr*);
++int sqliteExprCompare(Expr*, Expr*);
++int sqliteFuncId(Token*);
++int sqliteExprResolveIds(Parse*, SrcList*, ExprList*, Expr*);
++int sqliteExprAnalyzeAggregates(Parse*, Expr*);
++Vdbe *sqliteGetVdbe(Parse*);
++void sqliteRandomness(int, void*);
++void sqliteRollbackAll(sqlite*);
++void sqliteCodeVerifySchema(Parse*, int);
++void sqliteBeginTransaction(Parse*, int);
++void sqliteCommitTransaction(Parse*);
++void sqliteRollbackTransaction(Parse*);
++int sqliteExprIsConstant(Expr*);
++int sqliteExprIsInteger(Expr*, int*);
++int sqliteIsRowid(const char*);
++void sqliteGenerateRowDelete(sqlite*, Vdbe*, Table*, int, int);
++void sqliteGenerateRowIndexDelete(sqlite*, Vdbe*, Table*, int, char*);
++void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
++void sqliteCompleteInsertion(Parse*, Table*, int, char*, int, int, int);
++int sqliteOpenTableAndIndices(Parse*, Table*, int);
++void sqliteBeginWriteOperation(Parse*, int, int);
++void sqliteEndWriteOperation(Parse*);
++Expr *sqliteExprDup(Expr*);
++void sqliteTokenCopy(Token*, Token*);
++ExprList *sqliteExprListDup(ExprList*);
++SrcList *sqliteSrcListDup(SrcList*);
++IdList *sqliteIdListDup(IdList*);
++Select *sqliteSelectDup(Select*);
++FuncDef *sqliteFindFunction(sqlite*,const char*,int,int,int);
++void sqliteRegisterBuiltinFunctions(sqlite*);
++void sqliteRegisterDateTimeFunctions(sqlite*);
++int sqliteSafetyOn(sqlite*);
++int sqliteSafetyOff(sqlite*);
++int sqliteSafetyCheck(sqlite*);
++void sqliteChangeCookie(sqlite*, Vdbe*);
++void sqliteBeginTrigger(Parse*, Token*,int,int,IdList*,SrcList*,int,Expr*,int);
++void sqliteFinishTrigger(Parse*, TriggerStep*, Token*);
++void sqliteDropTrigger(Parse*, SrcList*);
++void sqliteDropTriggerPtr(Parse*, Trigger*, int);
++int sqliteTriggersExist(Parse* , Trigger* , int , int , int, ExprList*);
++int sqliteCodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int, 
++                         int, int);
++void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
++void sqliteDeleteTriggerStep(TriggerStep*);
++TriggerStep *sqliteTriggerSelectStep(Select*);
++TriggerStep *sqliteTriggerInsertStep(Token*, IdList*, ExprList*, Select*, int);
++TriggerStep *sqliteTriggerUpdateStep(Token*, ExprList*, Expr*, int);
++TriggerStep *sqliteTriggerDeleteStep(Token*, Expr*);
++void sqliteDeleteTrigger(Trigger*);
++int sqliteJoinType(Parse*, Token*, Token*, Token*);
++void sqliteCreateForeignKey(Parse*, IdList*, Token*, IdList*, int);
++void sqliteDeferForeignKey(Parse*, int);
++#ifndef SQLITE_OMIT_AUTHORIZATION
++  void sqliteAuthRead(Parse*,Expr*,SrcList*);
++  int sqliteAuthCheck(Parse*,int, const char*, const char*, const char*);
++  void sqliteAuthContextPush(Parse*, AuthContext*, const char*);
++  void sqliteAuthContextPop(AuthContext*);
++#else
++# define sqliteAuthRead(a,b,c)
++# define sqliteAuthCheck(a,b,c,d,e)    SQLITE_OK
++# define sqliteAuthContextPush(a,b,c)
++# define sqliteAuthContextPop(a)  ((void)(a))
++#endif
++void sqliteAttach(Parse*, Token*, Token*, Token*);
++void sqliteDetach(Parse*, Token*);
++int sqliteBtreeFactory(const sqlite *db, const char *zFilename,
++                       int mode, int nPg, Btree **ppBtree);
++int sqliteFixInit(DbFixer*, Parse*, int, const char*, const Token*);
++int sqliteFixSrcList(DbFixer*, SrcList*);
++int sqliteFixSelect(DbFixer*, Select*);
++int sqliteFixExpr(DbFixer*, Expr*);
++int sqliteFixExprList(DbFixer*, ExprList*);
++int sqliteFixTriggerStep(DbFixer*, TriggerStep*);
++double sqliteAtoF(const char *z, const char **);
++char *sqlite_snprintf(int,char*,const char*,...);
++int sqliteFitsIn32Bits(const char *);
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/sqlite.w32.h
+@@ -0,0 +1,764 @@
++/*
++** 2001 September 15
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This header file defines the interface that the SQLite library
++** presents to client programs.
++**
++** @(#) $Id$
++*/
++#ifndef _SQLITE_H_
++#define _SQLITE_H_
++#include <stdarg.h>     /* Needed for the definition of va_list */
++
++/*
++** Make sure we can call this stuff from C++.
++*/
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/*
++** The version of the SQLite library.
++*/
++#define SQLITE_VERSION         "2.8.17"
++
++/*
++** 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.
++*/
++extern const char sqlite_version[];
++
++/*
++** The SQLITE_UTF8 macro is defined if the library expects to see
++** UTF-8 encoded data.  The SQLITE_ISO8859 macro is defined if the
++** iso8859 encoded should be used.
++*/
++#define SQLITE_ISO8859 1
++
++/*
++** The following constant holds one of two strings, "UTF-8" or "iso8859",
++** depending on which character encoding the SQLite library expects to
++** see.  The character encoding makes a difference for the LIKE and GLOB
++** operators and for the LENGTH() and SUBSTR() functions.
++*/
++extern const char sqlite_encoding[];
++
++/*
++** Each open sqlite database is represented by an instance of the
++** following opaque structure.
++*/
++typedef struct sqlite sqlite;
++
++/*
++** A function to open a new sqlite database.  
++**
++** If the database does not exist and mode indicates write
++** permission, then a new database is created.  If the database
++** does not exist and mode does not indicate write permission,
++** then the open fails, an error message generated (if errmsg!=0)
++** and the function returns 0.
++** 
++** If mode does not indicates user write permission, then the 
++** database is opened read-only.
++**
++** The Truth:  As currently implemented, all databases are opened
++** for writing all the time.  Maybe someday we will provide the
++** ability to open a database readonly.  The mode parameters is
++** provided in anticipation of that enhancement.
++*/
++sqlite *sqlite_open(const char *filename, int mode, char **errmsg);
++
++/*
++** A function to close the database.
++**
++** Call this function with a pointer to a structure that was previously
++** returned from sqlite_open() and the corresponding database will by closed.
++*/
++void sqlite_close(sqlite *);
++
++/*
++** The type for a callback function.
++*/
++typedef int (*sqlite_callback)(void*,int,char**, char**);
++
++/*
++** A function to executes one or more statements of SQL.
++**
++** 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 sqlite_exec() function returns the SQLITE_ABORT.
++**
++** The 4th parameter is an arbitrary pointer that is passed
++** to the callback function as its first parameter.
++**
++** 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.
++**
++** 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.
++**
++** 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 sqlite_freemem() for this.  If errmsg==NULL,
++** then no error message is ever written.
++**
++** 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. 
++**
++** 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 sqlite_busy_handler()
++** and sqlite_busy_timeout() functions below.)
++*/
++int sqlite_exec(
++  sqlite*,                      /* An open database */
++  const char *sql,              /* SQL to be executed */
++  sqlite_callback,              /* Callback function */
++  void *,                       /* 1st argument to callback function */
++  char **errmsg                 /* Error msg written here */
++);
++
++/*
++** Return values for sqlite_exec() and sqlite_step()
++*/
++#define SQLITE_OK           0   /* Successful result */
++#define SQLITE_ERROR        1   /* SQL error or missing database */
++#define SQLITE_INTERNAL     2   /* An 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 */
++#define SQLITE_LOCKED       6   /* A table in the database is locked */
++#define SQLITE_NOMEM        7   /* A malloc() failed */
++#define SQLITE_READONLY     8   /* Attempt to write a readonly database */
++#define SQLITE_INTERRUPT    9   /* Operation terminated by sqlite_interrupt() */
++#define SQLITE_IOERR       10   /* Some kind of disk I/O error occurred */
++#define SQLITE_CORRUPT     11   /* The database disk image is malformed */
++#define SQLITE_NOTFOUND    12   /* (Internal Only) 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_EMPTY       16   /* (Internal Only) Database table is empty */
++#define SQLITE_SCHEMA      17   /* The database schema changed */
++#define SQLITE_TOOBIG      18   /* Too much data for one row of a table */
++#define SQLITE_CONSTRAINT  19   /* Abort due to contraint 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 */
++#define SQLITE_AUTH        23   /* Authorization denied */
++#define SQLITE_FORMAT      24   /* Auxiliary database format error */
++#define SQLITE_RANGE       25   /* 2nd parameter to sqlite_bind out of range */
++#define SQLITE_NOTADB      26   /* File opened that is not a database file */
++#define SQLITE_ROW         100  /* sqlite_step() has another row ready */
++#define SQLITE_DONE        101  /* sqlite_step() has finished executing */
++
++/*
++** 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.
++**
++** This function is similar to the mysql_insert_id() function from MySQL.
++*/
++int sqlite_last_insert_rowid(sqlite*);
++
++/*
++** This function returns the number of database rows that were changed
++** (or inserted or deleted) by the most recent called sqlite_exec().
++**
++** 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.
++**
++** If a callback invokes sqlite_exec() recursively, then the changes
++** in the inner, recursive call are counted together with the changes
++** in the outer call.
++**
++** 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.
++*/
++int sqlite_changes(sqlite*);
++
++/* If the parameter to this routine is one of the return value constants
++** defined above, then this routine returns a constant text string which
++** descripts (in English) the meaning of the return value.
++*/
++const char *sqlite_error_string(int);
++#define sqliteErrStr sqlite_error_string  /* Legacy. Do not use in new code. */
++
++/* 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.
++*/
++void sqlite_interrupt(sqlite*);
++
++
++/* This function returns true if the given input string comprises
++** one or more complete SQL statements.
++**
++** The algorithm is simple.  If the last token other than spaces
++** and comments is a semicolon, then return true.  otherwise return
++** false.
++*/
++int sqlite_complete(const char *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 sqlite_exec() returns SQLITE_BUSY immediately if
++** it finds a locked table.  If the busy callback is not NULL, then
++** sqlite_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 sqlite_exec() immediately returns
++** SQLITE_BUSY.  If the callback returns non-zero, then sqlite_exec()
++** tries to open the table again and the cycle repeats.
++**
++** 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.
++*/
++void sqlite_busy_handler(sqlite*, int(*)(void*,const char*,int), void*);
++
++/*
++** This routine sets a 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 sqlite_exec() to return SQLITE_BUSY.
++**
++** Calling this routine with an argument less than or equal to zero
++** turns off all busy handlers.
++*/
++void sqlite_busy_timeout(sqlite*, int ms);
++
++/*
++** This next routine is really just a wrapper around sqlite_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:
++**
++**        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).
++**
++** After the calling function has finished using the result, it should 
++** pass the result data pointer to sqlite_free_table() in order to 
++** release the memory that was malloc-ed.  Because of the way the 
++** malloc() happens, the calling function must not try to call 
++** malloc() directly.  Only sqlite_free_table() is able to release 
++** the memory properly and safely.
++**
++** The return value of this routine is the same as from sqlite_exec().
++*/
++int sqlite_get_table(
++  sqlite*,               /* 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 */
++);
++
++/*
++** Call this routine to free the memory that sqlite_get_table() allocated.
++*/
++void sqlite_free_table(char **result);
++
++/*
++** The following routines are wrappers around sqlite_exec() and
++** sqlite_get_table().  The only difference between the routines that
++** follow and the originals is that the second argument to the 
++** routines that follow is really a printf()-style format
++** string describing the SQL to be executed.  Arguments to the format
++** string appear at the end of the argument list.
++**
++** 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
++** 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
++** the string.
++**
++** For example, so some string variable contains text as follows:
++**
++**      char *zText = "It's a happy day!";
++**
++** We can use this text in an SQL statement as follows:
++**
++**      sqlite_exec_printf(db, "INSERT INTO table VALUES('%q')",
++**          callback1, 0, 0, zText);
++**
++** 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!')
++**
++** 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!');
++**
++** 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.
++*/
++int sqlite_exec_printf(
++  sqlite*,                      /* An open database */
++  const char *sqlFormat,        /* printf-style format string for the SQL */
++  sqlite_callback,              /* Callback function */
++  void *,                       /* 1st argument to callback function */
++  char **errmsg,                /* Error msg written here */
++  ...                           /* Arguments to the format string. */
++);
++int sqlite_exec_vprintf(
++  sqlite*,                      /* An open database */
++  const char *sqlFormat,        /* printf-style format string for the SQL */
++  sqlite_callback,              /* Callback function */
++  void *,                       /* 1st argument to callback function */
++  char **errmsg,                /* Error msg written here */
++  va_list ap                    /* Arguments to the format string. */
++);
++int sqlite_get_table_printf(
++  sqlite*,               /* An open database */
++  const char *sqlFormat, /* printf-style format string for the SQL */
++  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 */
++  ...                    /* Arguments to the format string */
++);
++int sqlite_get_table_vprintf(
++  sqlite*,               /* An open database */
++  const char *sqlFormat, /* printf-style format string for the SQL */
++  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 */
++  va_list ap             /* Arguments to the format string */
++);
++char *sqlite_mprintf(const char*,...);
++char *sqlite_vmprintf(const char*, va_list);
++
++/*
++** Windows systems should call this routine to free memory that
++** is returned in the in the errmsg parameter of sqlite_open() when
++** SQLite is a DLL.  For some reason, it does not work to call free()
++** directly.
++*/
++void sqlite_freemem(void *p);
++
++/*
++** Windows systems need functions to call to return the sqlite_version
++** and sqlite_encoding strings.
++*/
++const char *sqlite_libversion(void);
++const char *sqlite_libencoding(void);
++
++/*
++** A pointer to the following structure is used to communicate with
++** the implementations of user-defined functions.
++*/
++typedef struct sqlite_func sqlite_func;
++
++/*
++** Use the following routines to create new user-defined functions.  See
++** the documentation for details.
++*/
++int sqlite_create_function(
++  sqlite*,                  /* Database where the new function is registered */
++  const char *zName,        /* Name of the new function */
++  int nArg,                 /* Number of arguments.  -1 means any number */
++  void (*xFunc)(sqlite_func*,int,const char**),  /* C code to implement */
++  void *pUserData           /* Available via the sqlite_user_data() call */
++);
++int sqlite_create_aggregate(
++  sqlite*,                  /* Database where the new function is registered */
++  const char *zName,        /* Name of the function */
++  int nArg,                 /* Number of arguments */
++  void (*xStep)(sqlite_func*,int,const char**), /* Called for each row */
++  void (*xFinalize)(sqlite_func*),       /* Called once to get final result */
++  void *pUserData           /* Available via the sqlite_user_data() call */
++);
++
++/*
++** Use the following routine to define the datatype returned by a
++** user-defined function.  The second argument can be one of the
++** constants SQLITE_NUMERIC, SQLITE_TEXT, or SQLITE_ARGS or it
++** can be an integer greater than or equal to zero.  The datatype
++** will be numeric or text (the only two types supported) if the
++** argument is SQLITE_NUMERIC or SQLITE_TEXT.  If the argument is
++** SQLITE_ARGS, then the datatype is numeric if any argument to the
++** function is numeric and is text otherwise.  If the second argument
++** is an integer, then the datatype of the result is the same as the
++** parameter to the function that corresponds to that integer.
++*/
++int sqlite_function_type(
++  sqlite *db,               /* The database there the function is registered */
++  const char *zName,        /* Name of the function */
++  int datatype              /* The datatype for this function */
++);
++#define SQLITE_NUMERIC     (-1)
++#define SQLITE_TEXT        (-2)
++#define SQLITE_ARGS        (-3)
++
++/*
++** The user function implementations call one of the following four routines
++** in order to return their results.  The first parameter to each of these
++** routines is a copy of the first argument to xFunc() or xFinialize().
++** The second parameter to these routines is the result to be returned.
++** A NULL can be passed as the second parameter to sqlite_set_result_string()
++** in order to return a NULL result.
++**
++** The 3rd argument to _string and _error is the number of characters to
++** take from the string.  If this argument is negative, then all characters
++** up to and including the first '\000' are used.
++**
++** The sqlite_set_result_string() function allocates a buffer to hold the
++** result and returns a pointer to this buffer.  The calling routine
++** (that is, the implmentation of a user function) can alter the content
++** of this buffer if desired.
++*/
++char *sqlite_set_result_string(sqlite_func*,const char*,int);
++void sqlite_set_result_int(sqlite_func*,int);
++void sqlite_set_result_double(sqlite_func*,double);
++void sqlite_set_result_error(sqlite_func*,const char*,int);
++
++/*
++** The pUserData parameter to the sqlite_create_function() and
++** sqlite_create_aggregate() routines used to register user functions
++** is available to the implementation of the function using this
++** call.
++*/
++void *sqlite_user_data(sqlite_func*);
++
++/*
++** 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
++** of the aggregate can use the returned buffer to accumulate data.
++**
++** The buffer allocated is freed automatically be SQLite.
++*/
++void *sqlite_aggregate_context(sqlite_func*, int nBytes);
++
++/*
++** The next routine returns the number of calls to xStep for a particular
++** aggregate function instance.  The current call to xStep counts so this
++** routine always returns at least 1.
++*/
++int sqlite_aggregate_count(sqlite_func*);
++
++/*
++** 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.
++*/
++int sqlite_set_authorizer(
++  sqlite*,
++  int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
++  void *pUserData
++);
++
++/*
++** 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
++** 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.
++**
++**                                          Arg-3           Arg-4
++*/
++#define SQLITE_COPY                  0   /* Table Name      File Name       */
++#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      */
++#define SQLITE_CREATE_TEMP_TABLE     4   /* Table Name      NULL            */
++#define SQLITE_CREATE_TEMP_TRIGGER   5   /* Trigger Name    Table Name      */
++#define SQLITE_CREATE_TEMP_VIEW      6   /* View Name       NULL            */
++#define SQLITE_CREATE_TRIGGER        7   /* Trigger Name    Table Name      */
++#define SQLITE_CREATE_VIEW           8   /* View Name       NULL            */
++#define SQLITE_DELETE                9   /* Table Name      NULL            */
++#define SQLITE_DROP_INDEX           10   /* Index Name      Table Name      */
++#define SQLITE_DROP_TABLE           11   /* Table Name      NULL            */
++#define SQLITE_DROP_TEMP_INDEX      12   /* Index Name      Table Name      */
++#define SQLITE_DROP_TEMP_TABLE      13   /* Table Name      NULL            */
++#define SQLITE_DROP_TEMP_TRIGGER    14   /* Trigger Name    Table Name      */
++#define SQLITE_DROP_TEMP_VIEW       15   /* View Name       NULL            */
++#define SQLITE_DROP_TRIGGER         16   /* Trigger Name    Table Name      */
++#define SQLITE_DROP_VIEW            17   /* View Name       NULL            */
++#define SQLITE_INSERT               18   /* Table Name      NULL            */
++#define SQLITE_PRAGMA               19   /* Pragma Name     1st arg or NULL */
++#define SQLITE_READ                 20   /* Table Name      Column Name     */
++#define SQLITE_SELECT               21   /* NULL            NULL            */
++#define SQLITE_TRANSACTION          22   /* NULL            NULL            */
++#define SQLITE_UPDATE               23   /* Table Name      Column Name     */
++#define SQLITE_ATTACH               24   /* Filename        NULL            */
++#define SQLITE_DETACH               25   /* Database Name   NULL            */
++
++
++/*
++** 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 that is called at every invocation of sqlite_exec()
++** or sqlite_compile().  This function can be used (for example) to generate
++** a log file of all SQL executed against a database.
++*/
++void *sqlite_trace(sqlite*, void(*xTrace)(void*,const char*), void*);
++
++/*** The Callback-Free API
++** 
++** The following routines implement a new way to access SQLite that does not
++** involve the use of callbacks.
++**
++** An sqlite_vm is an opaque object that represents a single SQL statement
++** that is ready to be executed.
++*/
++typedef struct sqlite_vm sqlite_vm;
++
++/*
++** To execute an SQLite query without the use of callbacks, you first have
++** to compile the SQL using this routine.  The 1st parameter "db" is a pointer
++** to an sqlite object obtained from sqlite_open().  The 2nd parameter
++** "zSql" is the text of the SQL to be compiled.   The remaining parameters
++** are all outputs.
++**
++** *pzTail is made to point to the first character 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.
++**
++** *ppVm is left pointing to a "virtual machine" that can be used to execute
++** the compiled statement.  Or if there is an error, *ppVm may be set to NULL.
++** If the input text contained no SQL (if the input is and empty string or
++** a comment) then *ppVm is set to NULL.
++**
++** If any errors are detected during compilation, an error message is written
++** into space obtained from malloc() and *pzErrMsg is made to point to that
++** error message.  The calling routine is responsible for freeing the text
++** of this message when it has finished with it.  Use sqlite_freemem() to
++** free the message.  pzErrMsg may be NULL in which case no error message
++** will be generated.
++**
++** On success, SQLITE_OK is returned.  Otherwise and error code is returned.
++*/
++int sqlite_compile(
++  sqlite *db,                   /* The open database */
++  const char *zSql,             /* SQL statement to be compiled */
++  const char **pzTail,          /* OUT: uncompiled tail of zSql */
++  sqlite_vm **ppVm,             /* OUT: the virtual machine to execute zSql */
++  char **pzErrmsg               /* OUT: Error message. */
++);
++
++/*
++** After an SQL statement has been compiled, it is handed to this routine
++** to be executed.  This routine executes the statement as far as it can
++** go then returns.  The return value will be one of SQLITE_DONE,
++** SQLITE_ERROR, SQLITE_BUSY, SQLITE_ROW, or SQLITE_MISUSE.
++**
++** SQLITE_DONE means that the execute of the SQL statement is complete
++** an no errors have occurred.  sqlite_step() should not be called again
++** for the same virtual machine.  *pN is set to the number of columns in
++** the result set and *pazColName is set to an array of strings that
++** describe the column names and datatypes.  The name of the i-th column
++** is (*pazColName)[i] and the datatype of the i-th column is
++** (*pazColName)[i+*pN].  *pazValue is set to NULL.
++**
++** SQLITE_ERROR means that the virtual machine encountered a run-time
++** error.  sqlite_step() should not be called again for the same
++** virtual machine.  *pN is set to 0 and *pazColName and *pazValue are set
++** to NULL.  Use sqlite_finalize() to obtain the specific error code
++** and the error message text for the error.
++**
++** SQLITE_BUSY means that an attempt to open the database failed because
++** another thread or process is holding a lock.  The calling routine
++** can try again to open the database by calling sqlite_step() again.
++** The return code will only be SQLITE_BUSY if no busy handler is registered
++** using the sqlite_busy_handler() or sqlite_busy_timeout() routines.  If
++** a busy handler callback has been registered but returns 0, then this
++** routine will return SQLITE_ERROR and sqltie_finalize() will return
++** SQLITE_BUSY when it is called.
++**
++** SQLITE_ROW means that a single row of the result is now available.
++** The data is contained in *pazValue.  The value of the i-th column is
++** (*azValue)[i].  *pN and *pazColName are set as described in SQLITE_DONE.
++** Invoke sqlite_step() again to advance to the next row.
++**
++** SQLITE_MISUSE is returned if sqlite_step() is called incorrectly.
++** For example, if you call sqlite_step() after the virtual machine
++** has halted (after a prior call to sqlite_step() has returned SQLITE_DONE)
++** or if you call sqlite_step() with an incorrectly initialized virtual
++** machine or a virtual machine that has been deleted or that is associated
++** with an sqlite structure that has been closed.
++*/
++int sqlite_step(
++  sqlite_vm *pVm,              /* The virtual machine to execute */
++  int *pN,                     /* OUT: Number of columns in result */
++  const char ***pazValue,      /* OUT: Column data */
++  const char ***pazColName     /* OUT: Column names and datatypes */
++);
++
++/*
++** This routine is called to delete a virtual machine after it has finished
++** executing.  The return value is the result code.  SQLITE_OK is returned
++** if the statement executed successfully and some other value is returned if
++** there was any kind of error.  If an error occurred and pzErrMsg is not
++** NULL, then an error message is written into memory obtained from malloc()
++** and *pzErrMsg is made to point to that error message.  The calling routine
++** should use sqlite_freemem() to delete this message when it has finished
++** with it.
++**
++** 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 sqlite_interrupt().)  Incomplete updates may be
++** rolled back and transactions cancelled,  depending on the circumstances,
++** and the result code returned will be SQLITE_ABORT.
++*/
++int sqlite_finalize(sqlite_vm*, char **pzErrMsg);
++
++/*
++** This routine deletes the virtual machine, writes any error message to
++** *pzErrMsg and returns an SQLite return code in the same way as the
++** sqlite_finalize() function.
++**
++** Additionally, if ppVm is not NULL, *ppVm is left pointing to a new virtual
++** machine loaded with the compiled version of the original query ready for
++** execution.
++**
++** If sqlite_reset() returns SQLITE_SCHEMA, then *ppVm is set to NULL.
++**
++******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
++*/
++int sqlite_reset(sqlite_vm*, char **pzErrMsg);
++
++/*
++** If the SQL that was handed to sqlite_compile contains variables that
++** are represeted in the SQL text by a question mark ('?').  This routine
++** is used to assign values to those variables.
++**
++** The first parameter is a virtual machine obtained from sqlite_compile().
++** The 2nd "idx" parameter determines which variable in the SQL statement
++** to bind the value to.  The left most '?' is 1.  The 3rd parameter is
++** the value to assign to that variable.  The 4th parameter is the number
++** of bytes in the value, including the terminating \000 for strings.
++** Finally, the 5th "copy" parameter is TRUE if SQLite should make its
++** own private copy of this value, or false if the space that the 3rd
++** parameter points to will be unchanging and can be used directly by
++** SQLite.
++**
++** Unbound variables are treated as having a value of NULL.  To explicitly
++** set a variable to NULL, call this routine with the 3rd parameter as a
++** NULL pointer.
++**
++** If the 4th "len" parameter is -1, then strlen() is used to find the
++** length.
++**
++** This routine can only be called immediately after sqlite_compile()
++** or sqlite_reset() and before any calls to sqlite_step().
++**
++******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
++*/
++int sqlite_bind(sqlite_vm*, int idx, const char *value, int len, int copy);
++
++/*
++** This routine configures a callback function - the progress callback - that
++** is invoked periodically during long running calls to sqlite_exec(),
++** sqlite_step() and sqlite_get_table(). An example use for this API is to keep
++** a GUI updated during a large query.
++**
++** The progress callback is invoked once for every N virtual machine opcodes,
++** where N is the second argument to this function. The progress callback
++** 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.
++**
++** If a call to sqlite_exec(), sqlite_step() or sqlite_get_table() results 
++** in less than N opcodes being executed, then the progress callback is not
++** invoked.
++** 
++** Calling this routine overwrites any previously installed progress callback.
++** To remove the progress callback altogether, pass NULL as the third
++** argument to this function.
++**
++** 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 sqlite_exec() call returns SQLITE_ABORT. 
++*/
++void sqlite_progress_handler(sqlite*, int, int(*)(void*), void*);
++
++#ifdef __cplusplus
++}  /* End of the 'extern "C"' block */
++#endif
++
++#endif /* _SQLITE_H_ */
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/table.c
+@@ -0,0 +1,203 @@
++/*
++** 2001 September 15
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This file contains the sqlite_get_table() and sqlite_free_table()
++** interface routines.  These are just wrappers around the main
++** interface routine of sqlite_exec().
++**
++** These routines are in a separate files so that they will not be linked
++** if they are not used.
++*/
++#include <stdlib.h>
++#include <string.h>
++#include "sqliteInt.h"
++
++/*
++** This structure is used to pass data from sqlite_get_table() through
++** to the callback function is uses to build the result.
++*/
++typedef struct TabResult {
++  char **azResult;
++  char *zErrMsg;
++  int nResult;
++  int nAlloc;
++  int nRow;
++  int nColumn;
++  long nData;
++  int rc;
++} TabResult;
++
++/*
++** This routine is called once for each row in the result table.  Its job
++** is to fill in the TabResult structure appropriately, allocating new
++** memory as necessary.
++*/
++static int sqlite_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
++  TabResult *p = (TabResult*)pArg;
++  int need;
++  int i;
++  char *z;
++
++  /* Make sure there is enough space in p->azResult to hold everything
++  ** we need to remember from this invocation of the callback.
++  */
++  if( p->nRow==0 && argv!=0 ){
++    need = nCol*2;
++  }else{
++    need = nCol;
++  }
++  if( p->nData + need >= p->nAlloc ){
++    char **azNew;
++    p->nAlloc = p->nAlloc*2 + need + 1;
++    azNew = realloc( p->azResult, sizeof(char*)*p->nAlloc );
++    if( azNew==0 ){
++      p->rc = SQLITE_NOMEM;
++      return 1;
++    }
++    p->azResult = azNew;
++  }
++
++  /* If this is the first row, then generate an extra row containing
++  ** the names of all columns.
++  */
++  if( p->nRow==0 ){
++    p->nColumn = nCol;
++    for(i=0; i<nCol; i++){
++      if( colv[i]==0 ){
++        z = 0;
++      }else{
++        z = malloc( strlen(colv[i])+1 );
++        if( z==0 ){
++          p->rc = SQLITE_NOMEM;
++          return 1;
++        }
++        strcpy(z, colv[i]);
++      }
++      p->azResult[p->nData++] = z;
++    }
++  }else if( p->nColumn!=nCol ){
++    sqliteSetString(&p->zErrMsg,
++       "sqlite_get_table() called with two or more incompatible queries",
++       (char*)0);
++    p->rc = SQLITE_ERROR;
++    return 1;
++  }
++
++  /* Copy over the row data
++  */
++  if( argv!=0 ){
++    for(i=0; i<nCol; i++){
++      if( argv[i]==0 ){
++        z = 0;
++      }else{
++        z = malloc( strlen(argv[i])+1 );
++        if( z==0 ){
++          p->rc = SQLITE_NOMEM;
++          return 1;
++        }
++        strcpy(z, argv[i]);
++      }
++      p->azResult[p->nData++] = z;
++    }
++    p->nRow++;
++  }
++  return 0;
++}
++
++/*
++** Query the database.  But instead of invoking a callback for each row,
++** malloc() for space to hold the result and return the entire results
++** at the conclusion of the call.
++**
++** The result that is written to ***pazResult is held in memory obtained
++** from malloc().  But the caller cannot free this memory directly.  
++** Instead, the entire table should be passed to sqlite_free_table() when
++** the calling procedure is finished using it.
++*/
++int sqlite_get_table(
++  sqlite *db,                 /* The database on which the SQL executes */
++  const char *zSql,           /* The SQL to be executed */
++  char ***pazResult,          /* Write the result table here */
++  int *pnRow,                 /* Write the number of rows in the result here */
++  int *pnColumn,              /* Write the number of columns of result here */
++  char **pzErrMsg             /* Write error messages here */
++){
++  int rc;
++  TabResult res;
++  if( pazResult==0 ){ return SQLITE_ERROR; }
++  *pazResult = 0;
++  if( pnColumn ) *pnColumn = 0;
++  if( pnRow ) *pnRow = 0;
++  res.zErrMsg = 0;
++  res.nResult = 0;
++  res.nRow = 0;
++  res.nColumn = 0;
++  res.nData = 1;
++  res.nAlloc = 20;
++  res.rc = SQLITE_OK;
++  res.azResult = malloc( sizeof(char*)*res.nAlloc );
++  if( res.azResult==0 ){
++    return SQLITE_NOMEM;
++  }
++  res.azResult[0] = 0;
++  rc = sqlite_exec(db, zSql, sqlite_get_table_cb, &res, pzErrMsg);
++  if( res.azResult ){
++    res.azResult[0] = (char*)res.nData;
++  }
++  if( rc==SQLITE_ABORT ){
++    sqlite_free_table(&res.azResult[1]);
++    if( res.zErrMsg ){
++      if( pzErrMsg ){
++        free(*pzErrMsg);
++        *pzErrMsg = res.zErrMsg;
++        sqliteStrRealloc(pzErrMsg);
++      }else{
++        sqliteFree(res.zErrMsg);
++      }
++    }
++    return res.rc;
++  }
++  sqliteFree(res.zErrMsg);
++  if( rc!=SQLITE_OK ){
++    sqlite_free_table(&res.azResult[1]);
++    return rc;
++  }
++  if( res.nAlloc>res.nData ){
++    char **azNew;
++    azNew = realloc( res.azResult, sizeof(char*)*(res.nData+1) );
++    if( azNew==0 ){
++      sqlite_free_table(&res.azResult[1]);
++      return SQLITE_NOMEM;
++    }
++    res.nAlloc = res.nData+1;
++    res.azResult = azNew;
++  }
++  *pazResult = &res.azResult[1];
++  if( pnColumn ) *pnColumn = res.nColumn;
++  if( pnRow ) *pnRow = res.nRow;
++  return rc;
++}
++
++/*
++** This routine frees the space the sqlite_get_table() malloced.
++*/
++void sqlite_free_table(
++  char **azResult             /* Result returned from from sqlite_get_table() */
++){
++  if( azResult ){
++    int i, n;
++    azResult--;
++    if( azResult==0 ) return;
++    n = (int)(long)azResult[0];
++    for(i=1; i<n; i++){ if( azResult[i] ) free(azResult[i]); }
++    free(azResult);
++  }
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/tokenize.c
+@@ -0,0 +1,679 @@
++/*
++** 2001 September 15
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** An tokenizer for SQL
++**
++** This file contains C code that splits an SQL input string up into
++** individual tokens and sends those tokens one-by-one over to the
++** parser for analysis.
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++#include "os.h"
++#include <ctype.h>
++#include <stdlib.h>
++
++/*
++** All the keywords of the SQL language are stored as in a hash
++** table composed of instances of the following structure.
++*/
++typedef struct Keyword Keyword;
++struct Keyword {
++  char *zName;             /* The keyword name */
++  u8 tokenType;            /* Token value for this keyword */
++  u8 len;                  /* Length of this keyword */
++  u8 iNext;                /* Index in aKeywordTable[] of next with same hash */
++};
++
++/*
++** These are the keywords
++*/
++static Keyword aKeywordTable[] = {
++  { "ABORT",             TK_ABORT,        },
++  { "AFTER",             TK_AFTER,        },
++  { "ALL",               TK_ALL,          },
++  { "AND",               TK_AND,          },
++  { "AS",                TK_AS,           },
++  { "ASC",               TK_ASC,          },
++  { "ATTACH",            TK_ATTACH,       },
++  { "BEFORE",            TK_BEFORE,       },
++  { "BEGIN",             TK_BEGIN,        },
++  { "BETWEEN",           TK_BETWEEN,      },
++  { "BY",                TK_BY,           },
++  { "CASCADE",           TK_CASCADE,      },
++  { "CASE",              TK_CASE,         },
++  { "CHECK",             TK_CHECK,        },
++  { "CLUSTER",           TK_CLUSTER,      },
++  { "COLLATE",           TK_COLLATE,      },
++  { "COMMIT",            TK_COMMIT,       },
++  { "CONFLICT",          TK_CONFLICT,     },
++  { "CONSTRAINT",        TK_CONSTRAINT,   },
++  { "COPY",              TK_COPY,         },
++  { "CREATE",            TK_CREATE,       },
++  { "CROSS",             TK_JOIN_KW,      },
++  { "DATABASE",          TK_DATABASE,     },
++  { "DEFAULT",           TK_DEFAULT,      },
++  { "DEFERRED",          TK_DEFERRED,     },
++  { "DEFERRABLE",        TK_DEFERRABLE,   },
++  { "DELETE",            TK_DELETE,       },
++  { "DELIMITERS",        TK_DELIMITERS,   },
++  { "DESC",              TK_DESC,         },
++  { "DETACH",            TK_DETACH,       },
++  { "DISTINCT",          TK_DISTINCT,     },
++  { "DROP",              TK_DROP,         },
++  { "END",               TK_END,          },
++  { "EACH",              TK_EACH,         },
++  { "ELSE",              TK_ELSE,         },
++  { "EXCEPT",            TK_EXCEPT,       },
++  { "EXPLAIN",           TK_EXPLAIN,      },
++  { "FAIL",              TK_FAIL,         },
++  { "FOR",               TK_FOR,          },
++  { "FOREIGN",           TK_FOREIGN,      },
++  { "FROM",              TK_FROM,         },
++  { "FULL",              TK_JOIN_KW,      },
++  { "GLOB",              TK_GLOB,         },
++  { "GROUP",             TK_GROUP,        },
++  { "HAVING",            TK_HAVING,       },
++  { "IGNORE",            TK_IGNORE,       },
++  { "IMMEDIATE",         TK_IMMEDIATE,    },
++  { "IN",                TK_IN,           },
++  { "INDEX",             TK_INDEX,        },
++  { "INITIALLY",         TK_INITIALLY,    },
++  { "INNER",             TK_JOIN_KW,      },
++  { "INSERT",            TK_INSERT,       },
++  { "INSTEAD",           TK_INSTEAD,      },
++  { "INTERSECT",         TK_INTERSECT,    },
++  { "INTO",              TK_INTO,         },
++  { "IS",                TK_IS,           },
++  { "ISNULL",            TK_ISNULL,       },
++  { "JOIN",              TK_JOIN,         },
++  { "KEY",               TK_KEY,          },
++  { "LEFT",              TK_JOIN_KW,      },
++  { "LIKE",              TK_LIKE,         },
++  { "LIMIT",             TK_LIMIT,        },
++  { "MATCH",             TK_MATCH,        },
++  { "NATURAL",           TK_JOIN_KW,      },
++  { "NOT",               TK_NOT,          },
++  { "NOTNULL",           TK_NOTNULL,      },
++  { "NULL",              TK_NULL,         },
++  { "OF",                TK_OF,           },
++  { "OFFSET",            TK_OFFSET,       },
++  { "ON",                TK_ON,           },
++  { "OR",                TK_OR,           },
++  { "ORDER",             TK_ORDER,        },
++  { "OUTER",             TK_JOIN_KW,      },
++  { "PRAGMA",            TK_PRAGMA,       },
++  { "PRIMARY",           TK_PRIMARY,      },
++  { "RAISE",             TK_RAISE,        },
++  { "REFERENCES",        TK_REFERENCES,   },
++  { "REPLACE",           TK_REPLACE,      },
++  { "RESTRICT",          TK_RESTRICT,     },
++  { "RIGHT",             TK_JOIN_KW,      },
++  { "ROLLBACK",          TK_ROLLBACK,     },
++  { "ROW",               TK_ROW,          },
++  { "SELECT",            TK_SELECT,       },
++  { "SET",               TK_SET,          },
++  { "STATEMENT",         TK_STATEMENT,    },
++  { "TABLE",             TK_TABLE,        },
++  { "TEMP",              TK_TEMP,         },
++  { "TEMPORARY",         TK_TEMP,         },
++  { "THEN",              TK_THEN,         },
++  { "TRANSACTION",       TK_TRANSACTION,  },
++  { "TRIGGER",           TK_TRIGGER,      },
++  { "UNION",             TK_UNION,        },
++  { "UNIQUE",            TK_UNIQUE,       },
++  { "UPDATE",            TK_UPDATE,       },
++  { "USING",             TK_USING,        },
++  { "VACUUM",            TK_VACUUM,       },
++  { "VALUES",            TK_VALUES,       },
++  { "VIEW",              TK_VIEW,         },
++  { "WHEN",              TK_WHEN,         },
++  { "WHERE",             TK_WHERE,        },
++};
++
++/*
++** This is the hash table
++*/
++#define KEY_HASH_SIZE 101
++static u8 aiHashTable[KEY_HASH_SIZE];
++
++
++/*
++** This function looks up an identifier to determine if it is a
++** keyword.  If it is a keyword, the token code of that keyword is 
++** returned.  If the input is not a keyword, TK_ID is returned.
++*/
++int sqliteKeywordCode(const char *z, int n){
++  int h, i;
++  Keyword *p;
++  static char needInit = 1;
++  if( needInit ){
++    /* Initialize the keyword hash table */
++    sqliteOsEnterMutex();
++    if( needInit ){
++      int nk;
++      nk = sizeof(aKeywordTable)/sizeof(aKeywordTable[0]);
++      for(i=0; i<nk; i++){
++        aKeywordTable[i].len = strlen(aKeywordTable[i].zName);
++        h = sqliteHashNoCase(aKeywordTable[i].zName, aKeywordTable[i].len);
++        h %= KEY_HASH_SIZE;
++        aKeywordTable[i].iNext = aiHashTable[h];
++        aiHashTable[h] = i+1;
++      }
++      needInit = 0;
++    }
++    sqliteOsLeaveMutex();
++  }
++  h = sqliteHashNoCase(z, n) % KEY_HASH_SIZE;
++  for(i=aiHashTable[h]; i; i=p->iNext){
++    p = &aKeywordTable[i-1];
++    if( p->len==n && sqliteStrNICmp(p->zName, z, n)==0 ){
++      return p->tokenType;
++    }
++  }
++  return TK_ID;
++}
++
++
++/*
++** If X is a character that can be used in an identifier and
++** X&0x80==0 then isIdChar[X] will be 1.  If X&0x80==0x80 then
++** X is always an identifier character.  (Hence all UTF-8
++** characters can be part of an identifier).  isIdChar[X] will
++** be 0 for every character in the lower 128 ASCII characters
++** that cannot be used as part of an identifier.
++**
++** In this implementation, an identifier can be a string of
++** alphabetic characters, digits, and "_" plus any character
++** with the high-order bit set.  The latter rule means that
++** any sequence of UTF-8 characters or characters taken from
++** an extended ISO8859 character set can form an identifier.
++*/
++static const char isIdChar[] = {
++/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
++    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x */
++    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 1x */
++    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 2x */
++    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  /* 3x */
++    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 4x */
++    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,  /* 5x */
++    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 */
++};
++
++
++/*
++** Return the length of the token that begins at z[0]. 
++** Store the token type in *tokenType before returning.
++*/
++static int sqliteGetToken(const unsigned char *z, int *tokenType){
++  int i;
++  switch( *z ){
++    case ' ': case '\t': case '\n': case '\f': case '\r': {
++      for(i=1; isspace(z[i]); i++){}
++      *tokenType = TK_SPACE;
++      return i;
++    }
++    case '-': {
++      if( z[1]=='-' ){
++        for(i=2; z[i] && z[i]!='\n'; i++){}
++        *tokenType = TK_COMMENT;
++        return i;
++      }
++      *tokenType = TK_MINUS;
++      return 1;
++    }
++    case '(': {
++      *tokenType = TK_LP;
++      return 1;
++    }
++    case ')': {
++      *tokenType = TK_RP;
++      return 1;
++    }
++    case ';': {
++      *tokenType = TK_SEMI;
++      return 1;
++    }
++    case '+': {
++      *tokenType = TK_PLUS;
++      return 1;
++    }
++    case '*': {
++      *tokenType = TK_STAR;
++      return 1;
++    }
++    case '/': {
++      if( z[1]!='*' || z[2]==0 ){
++        *tokenType = TK_SLASH;
++        return 1;
++      }
++      for(i=3; z[i] && (z[i]!='/' || z[i-1]!='*'); i++){}
++      if( z[i] ) i++;
++      *tokenType = TK_COMMENT;
++      return i;
++    }
++    case '%': {
++      *tokenType = TK_REM;
++      return 1;
++    }
++    case '=': {
++      *tokenType = TK_EQ;
++      return 1 + (z[1]=='=');
++    }
++    case '<': {
++      if( z[1]=='=' ){
++        *tokenType = TK_LE;
++        return 2;
++      }else if( z[1]=='>' ){
++        *tokenType = TK_NE;
++        return 2;
++      }else if( z[1]=='<' ){
++        *tokenType = TK_LSHIFT;
++        return 2;
++      }else{
++        *tokenType = TK_LT;
++        return 1;
++      }
++    }
++    case '>': {
++      if( z[1]=='=' ){
++        *tokenType = TK_GE;
++        return 2;
++      }else if( z[1]=='>' ){
++        *tokenType = TK_RSHIFT;
++        return 2;
++      }else{
++        *tokenType = TK_GT;
++        return 1;
++      }
++    }
++    case '!': {
++      if( z[1]!='=' ){
++        *tokenType = TK_ILLEGAL;
++        return 2;
++      }else{
++        *tokenType = TK_NE;
++        return 2;
++      }
++    }
++    case '|': {
++      if( z[1]!='|' ){
++        *tokenType = TK_BITOR;
++        return 1;
++      }else{
++        *tokenType = TK_CONCAT;
++        return 2;
++      }
++    }
++    case ',': {
++      *tokenType = TK_COMMA;
++      return 1;
++    }
++    case '&': {
++      *tokenType = TK_BITAND;
++      return 1;
++    }
++    case '~': {
++      *tokenType = TK_BITNOT;
++      return 1;
++    }
++    case '\'': case '"': {
++      int delim = z[0];
++      for(i=1; z[i]; i++){
++        if( z[i]==delim ){
++          if( z[i+1]==delim ){
++            i++;
++          }else{
++            break;
++          }
++        }
++      }
++      if( z[i] ) i++;
++      *tokenType = TK_STRING;
++      return i;
++    }
++    case '.': {
++      *tokenType = TK_DOT;
++      return 1;
++    }
++    case '0': case '1': case '2': case '3': case '4':
++    case '5': case '6': case '7': case '8': case '9': {
++      *tokenType = TK_INTEGER;
++      for(i=1; isdigit(z[i]); i++){}
++      if( z[i]=='.' && isdigit(z[i+1]) ){
++        i += 2;
++        while( isdigit(z[i]) ){ i++; }
++        *tokenType = TK_FLOAT;
++      }
++      if( (z[i]=='e' || z[i]=='E') &&
++           ( isdigit(z[i+1]) 
++            || ((z[i+1]=='+' || z[i+1]=='-') && isdigit(z[i+2]))
++           )
++      ){
++        i += 2;
++        while( isdigit(z[i]) ){ i++; }
++        *tokenType = TK_FLOAT;
++      }
++      return i;
++    }
++    case '[': {
++      for(i=1; z[i] && z[i-1]!=']'; i++){}
++      *tokenType = TK_ID;
++      return i;
++    }
++    case '?': {
++      *tokenType = TK_VARIABLE;
++      return 1;
++    }
++    default: {
++      if( (*z&0x80)==0 && !isIdChar[*z] ){
++        break;
++      }
++      for(i=1; (z[i]&0x80)!=0 || isIdChar[z[i]]; i++){}
++      *tokenType = sqliteKeywordCode((char*)z, i);
++      return i;
++    }
++  }
++  *tokenType = TK_ILLEGAL;
++  return 1;
++}
++
++/*
++** 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
++** error message.  Or maybe not.
++*/
++int sqliteRunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
++  int nErr = 0;
++  int i;
++  void *pEngine;
++  int tokenType;
++  int lastTokenParsed = -1;
++  sqlite *db = pParse->db;
++  extern void *sqliteParserAlloc(void*(*)(int));
++  extern void sqliteParserFree(void*, void(*)(void*));
++  extern int sqliteParser(void*, int, Token, Parse*);
++
++  db->flags &= ~SQLITE_Interrupt;
++  pParse->rc = SQLITE_OK;
++  i = 0;
++  pEngine = sqliteParserAlloc((void*(*)(int))malloc);
++  if( pEngine==0 ){
++    sqliteSetString(pzErrMsg, "out of memory", (char*)0);
++    return 1;
++  }
++  pParse->sLastToken.dyn = 0;
++  pParse->zTail = zSql;
++  while( sqlite_malloc_failed==0 && zSql[i]!=0 ){
++    assert( i>=0 );
++    pParse->sLastToken.z = &zSql[i];
++    assert( pParse->sLastToken.dyn==0 );
++    pParse->sLastToken.n = sqliteGetToken((unsigned char*)&zSql[i], &tokenType);
++    i += pParse->sLastToken.n;
++    switch( tokenType ){
++      case TK_SPACE:
++      case TK_COMMENT: {
++        if( (db->flags & SQLITE_Interrupt)!=0 ){
++          pParse->rc = SQLITE_INTERRUPT;
++          sqliteSetString(pzErrMsg, "interrupt", (char*)0);
++          goto abort_parse;
++        }
++        break;
++      }
++      case TK_ILLEGAL: {
++        sqliteSetNString(pzErrMsg, "unrecognized token: \"", -1, 
++           pParse->sLastToken.z, pParse->sLastToken.n, "\"", 1, 0);
++        nErr++;
++        goto abort_parse;
++      }
++      case TK_SEMI: {
++        pParse->zTail = &zSql[i];
++        /* Fall thru into the default case */
++      }
++      default: {
++        sqliteParser(pEngine, tokenType, pParse->sLastToken, pParse);
++        lastTokenParsed = tokenType;
++        if( pParse->rc!=SQLITE_OK ){
++          goto abort_parse;
++        }
++        break;
++      }
++    }
++  }
++abort_parse:
++  if( zSql[i]==0 && nErr==0 && pParse->rc==SQLITE_OK ){
++    if( lastTokenParsed!=TK_SEMI ){
++      sqliteParser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
++      pParse->zTail = &zSql[i];
++    }
++    sqliteParser(pEngine, 0, pParse->sLastToken, pParse);
++  }
++  sqliteParserFree(pEngine, free);
++  if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
++    sqliteSetString(&pParse->zErrMsg, sqlite_error_string(pParse->rc),
++                    (char*)0);
++  }
++  if( pParse->zErrMsg ){
++    if( pzErrMsg && *pzErrMsg==0 ){
++      *pzErrMsg = pParse->zErrMsg;
++    }else{
++      sqliteFree(pParse->zErrMsg);
++    }
++    pParse->zErrMsg = 0;
++    if( !nErr ) nErr++;
++  }
++  if( pParse->pVdbe && pParse->nErr>0 ){
++    sqliteVdbeDelete(pParse->pVdbe);
++    pParse->pVdbe = 0;
++  }
++  if( pParse->pNewTable ){
++    sqliteDeleteTable(pParse->db, pParse->pNewTable);
++    pParse->pNewTable = 0;
++  }
++  if( pParse->pNewTrigger ){
++    sqliteDeleteTrigger(pParse->pNewTrigger);
++    pParse->pNewTrigger = 0;
++  }
++  if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){
++    pParse->rc = SQLITE_ERROR;
++  }
++  return nErr;
++}
++
++/*
++** Token types used by the sqlite_complete() routine.  See the header
++** comments on that procedure for additional information.
++*/
++#define tkEXPLAIN 0
++#define tkCREATE  1
++#define tkTEMP    2
++#define tkTRIGGER 3
++#define tkEND     4
++#define tkSEMI    5
++#define tkWS      6
++#define tkOTHER   7
++
++/*
++** Return TRUE if the given SQL string ends in a semicolon.
++**
++** Special handling is require for CREATE TRIGGER statements.
++** Whenever the CREATE TRIGGER keywords are seen, the statement
++** must end with ";END;".
++**
++** This implementation uses a state machine with 7 states:
++**
++**   (0) START     At the beginning or end of an SQL statement.  This routine
++**                 returns 1 if it ends in the START state and 0 if it ends
++**                 in any other state.
++**
++**   (1) EXPLAIN   The keyword EXPLAIN has been seen at the beginning of 
++**                 a statement.
++**
++**   (2) CREATE    The keyword CREATE has been seen at the beginning of a
++**                 statement, possibly preceeded by EXPLAIN and/or followed by
++**                 TEMP or TEMPORARY
++**
++**   (3) NORMAL    We are in the middle of statement which ends with a single
++**                 semicolon.
++**
++**   (4) TRIGGER   We are in the middle of a trigger definition that must be
++**                 ended by a semicolon, the keyword END, and another semicolon.
++**
++**   (5) SEMI      We've seen the first semicolon in the ";END;" that occurs at
++**                 the end of a trigger definition.
++**
++**   (6) END       We've seen the ";END" of the ";END;" that occurs at the end
++**                 of a trigger difinition.
++**
++** Transitions between states above are determined by tokens extracted
++** from the input.  The following tokens are significant:
++**
++**   (0) tkEXPLAIN   The "explain" keyword.
++**   (1) tkCREATE    The "create" keyword.
++**   (2) tkTEMP      The "temp" or "temporary" keyword.
++**   (3) tkTRIGGER   The "trigger" keyword.
++**   (4) tkEND       The "end" keyword.
++**   (5) tkSEMI      A semicolon.
++**   (6) tkWS        Whitespace
++**   (7) tkOTHER     Any other SQL token.
++**
++** Whitespace never causes a state transition and is always ignored.
++*/
++int sqlite_complete(const char *zSql){
++  u8 state = 0;   /* Current state, using numbers defined in header comment */
++  u8 token;       /* Value of the next token */
++
++  /* The following matrix defines the transition from one state to another
++  ** according to what token is seen.  trans[state][token] returns the
++  ** next state.
++  */
++  static const u8 trans[7][8] = {
++                     /* Token:                                                */
++     /* State:       **  EXPLAIN  CREATE  TEMP  TRIGGER  END  SEMI  WS  OTHER */
++     /* 0   START: */ {       1,      2,    3,       3,   3,    0,  0,     3, },
++     /* 1 EXPLAIN: */ {       3,      2,    3,       3,   3,    0,  1,     3, },
++     /* 2  CREATE: */ {       3,      3,    2,       4,   3,    0,  2,     3, },
++     /* 3  NORMAL: */ {       3,      3,    3,       3,   3,    0,  3,     3, },
++     /* 4 TRIGGER: */ {       4,      4,    4,       4,   4,    5,  4,     4, },
++     /* 5    SEMI: */ {       4,      4,    4,       4,   6,    5,  5,     4, },
++     /* 6     END: */ {       4,      4,    4,       4,   4,    0,  6,     4, },
++  };
++
++  while( *zSql ){
++    switch( *zSql ){
++      case ';': {  /* A semicolon */
++        token = tkSEMI;
++        break;
++      }
++      case ' ':
++      case '\r':
++      case '\t':
++      case '\n':
++      case '\f': {  /* White space is ignored */
++        token = tkWS;
++        break;
++      }
++      case '/': {   /* C-style comments */
++        if( zSql[1]!='*' ){
++          token = tkOTHER;
++          break;
++        }
++        zSql += 2;
++        while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; }
++        if( zSql[0]==0 ) return 0;
++        zSql++;
++        token = tkWS;
++        break;
++      }
++      case '-': {   /* SQL-style comments from "--" to end of line */
++        if( zSql[1]!='-' ){
++          token = tkOTHER;
++          break;
++        }
++        while( *zSql && *zSql!='\n' ){ zSql++; }
++        if( *zSql==0 ) return state==0;
++        token = tkWS;
++        break;
++      }
++      case '[': {   /* Microsoft-style identifiers in [...] */
++        zSql++;
++        while( *zSql && *zSql!=']' ){ zSql++; }
++        if( *zSql==0 ) return 0;
++        token = tkOTHER;
++        break;
++      }
++      case '"':     /* single- and double-quoted strings */
++      case '\'': {
++        int c = *zSql;
++        zSql++;
++        while( *zSql && *zSql!=c ){ zSql++; }
++        if( *zSql==0 ) return 0;
++        token = tkOTHER;
++        break;
++      }
++      default: {
++        if( isIdChar[(u8)*zSql] ){
++          /* Keywords and unquoted identifiers */
++          int nId;
++          for(nId=1; isIdChar[(u8)zSql[nId]]; nId++){}
++          switch( *zSql ){
++            case 'c': case 'C': {
++              if( nId==6 && sqliteStrNICmp(zSql, "create", 6)==0 ){
++                token = tkCREATE;
++              }else{
++                token = tkOTHER;
++              }
++              break;
++            }
++            case 't': case 'T': {
++              if( nId==7 && sqliteStrNICmp(zSql, "trigger", 7)==0 ){
++                token = tkTRIGGER;
++              }else if( nId==4 && sqliteStrNICmp(zSql, "temp", 4)==0 ){
++                token = tkTEMP;
++              }else if( nId==9 && sqliteStrNICmp(zSql, "temporary", 9)==0 ){
++                token = tkTEMP;
++              }else{
++                token = tkOTHER;
++              }
++              break;
++            }
++            case 'e':  case 'E': {
++              if( nId==3 && sqliteStrNICmp(zSql, "end", 3)==0 ){
++                token = tkEND;
++              }else if( nId==7 && sqliteStrNICmp(zSql, "explain", 7)==0 ){
++                token = tkEXPLAIN;
++              }else{
++                token = tkOTHER;
++              }
++              break;
++            }
++            default: {
++              token = tkOTHER;
++              break;
++            }
++          }
++          zSql += nId-1;
++        }else{
++          /* Operators and special symbols */
++          token = tkOTHER;
++        }
++        break;
++      }
++    }
++    state = trans[state][token];
++    zSql++;
++  }
++  return state==0;
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/trigger.c
+@@ -0,0 +1,764 @@
++/*
++**
++** 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.
++**
++*************************************************************************
++*
++*/
++#include "sqliteInt.h"
++
++/*
++** Delete a linked list of TriggerStep structures.
++*/
++void sqliteDeleteTriggerStep(TriggerStep *pTriggerStep){
++  while( pTriggerStep ){
++    TriggerStep * pTmp = pTriggerStep;
++    pTriggerStep = pTriggerStep->pNext;
++
++    if( pTmp->target.dyn ) sqliteFree((char*)pTmp->target.z);
++    sqliteExprDelete(pTmp->pWhere);
++    sqliteExprListDelete(pTmp->pExprList);
++    sqliteSelectDelete(pTmp->pSelect);
++    sqliteIdListDelete(pTmp->pIdList);
++
++    sqliteFree(pTmp);
++  }
++}
++
++/*
++** This is called by the parser when it sees a CREATE TRIGGER statement
++** up to the point of the BEGIN before the trigger actions.  A Trigger
++** structure is generated based on the information available and stored
++** in pParse->pNewTrigger.  After the trigger actions have been parsed, the
++** sqliteFinishTrigger() function is called to complete the trigger
++** construction process.
++*/
++void sqliteBeginTrigger(
++  Parse *pParse,      /* The parse context of the CREATE TRIGGER statement */
++  Token *pName,       /* The name of the trigger */
++  int tr_tm,          /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD */
++  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 */
++){
++  Trigger *nt;
++  Table   *tab;
++  char *zName = 0;        /* Name of the trigger */
++  sqlite *db = pParse->db;
++  int iDb;                /* When database to store the trigger in */
++  DbFixer sFix;
++
++  /* Check that: 
++  ** 1. the trigger name does not already exist.
++  ** 2. the table (or view) does exist in the same database as the trigger.
++  ** 3. that we are not trying to create a trigger on the sqlite_master table
++  ** 4. That we are not trying to create an INSTEAD OF trigger on a table.
++  ** 5. That we are not trying to create a BEFORE or AFTER trigger on a view.
++  */
++  if( sqlite_malloc_failed ) goto trigger_cleanup;
++  assert( pTableName->nSrc==1 );
++  if( db->init.busy
++   && sqliteFixInit(&sFix, pParse, db->init.iDb, "trigger", pName)
++   && sqliteFixSrcList(&sFix, pTableName)
++  ){
++    goto trigger_cleanup;
++  }
++  tab = sqliteSrcListLookup(pParse, pTableName);
++  if( !tab ){
++    goto trigger_cleanup;
++  }
++  iDb = isTemp ? 1 : tab->iDb;
++  if( iDb>=2 && !db->init.busy ){
++    sqliteErrorMsg(pParse, "triggers may not be added to auxiliary "
++       "database %s", db->aDb[tab->iDb].zName);
++    goto trigger_cleanup;
++  }
++
++  zName = sqliteStrNDup(pName->z, pName->n);
++  sqliteDequote(zName);
++  if( sqliteHashFind(&(db->aDb[iDb].trigHash), zName,pName->n+1) ){
++    sqliteErrorMsg(pParse, "trigger %T already exists", pName);
++    goto trigger_cleanup;
++  }
++  if( sqliteStrNICmp(tab->zName, "sqlite_", 7)==0 ){
++    sqliteErrorMsg(pParse, "cannot create trigger on system table");
++    pParse->nErr++;
++    goto trigger_cleanup;
++  }
++  if( tab->pSelect && tr_tm != TK_INSTEAD ){
++    sqliteErrorMsg(pParse, "cannot create %s trigger on view: %S", 
++        (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
++    goto trigger_cleanup;
++  }
++  if( !tab->pSelect && tr_tm == TK_INSTEAD ){
++    sqliteErrorMsg(pParse, "cannot create INSTEAD OF"
++        " trigger on table: %S", pTableName, 0);
++    goto trigger_cleanup;
++  }
++#ifndef SQLITE_OMIT_AUTHORIZATION
++  {
++    int code = SQLITE_CREATE_TRIGGER;
++    const char *zDb = db->aDb[tab->iDb].zName;
++    const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb;
++    if( tab->iDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
++    if( sqliteAuthCheck(pParse, code, zName, tab->zName, zDbTrig) ){
++      goto trigger_cleanup;
++    }
++    if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->iDb), 0, zDb)){
++      goto trigger_cleanup;
++    }
++  }
++#endif
++
++  /* INSTEAD OF triggers can only appear on views and BEGIN triggers
++  ** cannot appear on views.  So we might as well translate every
++  ** INSTEAD OF trigger into a BEFORE trigger.  It simplifies code
++  ** elsewhere.
++  */
++  if (tr_tm == TK_INSTEAD){
++    tr_tm = TK_BEFORE;
++  }
++
++  /* Build the Trigger object */
++  nt = (Trigger*)sqliteMalloc(sizeof(Trigger));
++  if( nt==0 ) goto trigger_cleanup;
++  nt->name = zName;
++  zName = 0;
++  nt->table = sqliteStrDup(pTableName->a[0].zName);
++  if( sqlite_malloc_failed ) goto trigger_cleanup;
++  nt->iDb = iDb;
++  nt->iTabDb = tab->iDb;
++  nt->op = op;
++  nt->tr_tm = tr_tm;
++  nt->pWhen = sqliteExprDup(pWhen);
++  nt->pColumns = sqliteIdListDup(pColumns);
++  nt->foreach = foreach;
++  sqliteTokenCopy(&nt->nameToken,pName);
++  assert( pParse->pNewTrigger==0 );
++  pParse->pNewTrigger = nt;
++
++trigger_cleanup:
++  sqliteFree(zName);
++  sqliteSrcListDelete(pTableName);
++  sqliteIdListDelete(pColumns);
++  sqliteExprDelete(pWhen);
++}
++
++/*
++** This routine is called after all of the trigger actions have been parsed
++** in order to complete the process of building the trigger.
++*/
++void sqliteFinishTrigger(
++  Parse *pParse,          /* Parser context */
++  TriggerStep *pStepList, /* The triggered program */
++  Token *pAll             /* Token that describes the complete CREATE TRIGGER */
++){
++  Trigger *nt = 0;          /* The trigger whose construction is finishing up */
++  sqlite *db = pParse->db;  /* The database */
++  DbFixer sFix;
++
++  if( pParse->nErr || pParse->pNewTrigger==0 ) goto triggerfinish_cleanup;
++  nt = pParse->pNewTrigger;
++  pParse->pNewTrigger = 0;
++  nt->step_list = pStepList;
++  while( pStepList ){
++    pStepList->pTrig = nt;
++    pStepList = pStepList->pNext;
++  }
++  if( sqliteFixInit(&sFix, pParse, nt->iDb, "trigger", &nt->nameToken) 
++          && sqliteFixTriggerStep(&sFix, nt->step_list) ){
++    goto triggerfinish_cleanup;
++  }
++
++  /* if we are not initializing, and this trigger is not on a TEMP table, 
++  ** build the sqlite_master entry
++  */
++  if( !db->init.busy ){
++    static VdbeOpList insertTrig[] = {
++      { OP_NewRecno,   0, 0,  0          },
++      { OP_String,     0, 0,  "trigger"  },
++      { OP_String,     0, 0,  0          },  /* 2: trigger name */
++      { OP_String,     0, 0,  0          },  /* 3: table name */
++      { OP_Integer,    0, 0,  0          },
++      { OP_String,     0, 0,  0          },  /* 5: SQL */
++      { OP_MakeRecord, 5, 0,  0          },
++      { OP_PutIntKey,  0, 0,  0          },
++    };
++    int addr;
++    Vdbe *v;
++
++    /* Make an entry in the sqlite_master table */
++    v = sqliteGetVdbe(pParse);
++    if( v==0 ) goto triggerfinish_cleanup;
++    sqliteBeginWriteOperation(pParse, 0, 0);
++    sqliteOpenMasterTable(v, nt->iDb);
++    addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
++    sqliteVdbeChangeP3(v, addr+2, nt->name, 0); 
++    sqliteVdbeChangeP3(v, addr+3, nt->table, 0); 
++    sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n);
++    if( nt->iDb==0 ){
++      sqliteChangeCookie(db, v);
++    }
++    sqliteVdbeAddOp(v, OP_Close, 0, 0);
++    sqliteEndWriteOperation(pParse);
++  }
++
++  if( !pParse->explain ){
++    Table *pTab;
++    sqliteHashInsert(&db->aDb[nt->iDb].trigHash, 
++                     nt->name, strlen(nt->name)+1, nt);
++    pTab = sqliteLocateTable(pParse, nt->table, db->aDb[nt->iTabDb].zName);
++    assert( pTab!=0 );
++    nt->pNext = pTab->pTrigger;
++    pTab->pTrigger = nt;
++    nt = 0;
++  }
++
++triggerfinish_cleanup:
++  sqliteDeleteTrigger(nt);
++  sqliteDeleteTrigger(pParse->pNewTrigger);
++  pParse->pNewTrigger = 0;
++  sqliteDeleteTriggerStep(pStepList);
++}
++
++/*
++** Make a copy of all components of the given trigger step.  This has
++** the effect of copying all Expr.token.z values into memory obtained
++** from sqliteMalloc().  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 sqlite_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 sqlite_exec() call returns.
++*/
++static void sqlitePersistTriggerStep(TriggerStep *p){
++  if( p->target.z ){
++    p->target.z = sqliteStrNDup(p->target.z, p->target.n);
++    p->target.dyn = 1;
++  }
++  if( p->pSelect ){
++    Select *pNew = sqliteSelectDup(p->pSelect);
++    sqliteSelectDelete(p->pSelect);
++    p->pSelect = pNew;
++  }
++  if( p->pWhere ){
++    Expr *pNew = sqliteExprDup(p->pWhere);
++    sqliteExprDelete(p->pWhere);
++    p->pWhere = pNew;
++  }
++  if( p->pExprList ){
++    ExprList *pNew = sqliteExprListDup(p->pExprList);
++    sqliteExprListDelete(p->pExprList);
++    p->pExprList = pNew;
++  }
++  if( p->pIdList ){
++    IdList *pNew = sqliteIdListDup(p->pIdList);
++    sqliteIdListDelete(p->pIdList);
++    p->pIdList = pNew;
++  }
++}
++
++/*
++** Turn a SELECT statement (that the pSelect parameter points to) into
++** a trigger step.  Return a pointer to a TriggerStep structure.
++**
++** The parser calls this routine when it finds a SELECT statement in
++** body of a TRIGGER.  
++*/
++TriggerStep *sqliteTriggerSelectStep(Select *pSelect){
++  TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
++  if( pTriggerStep==0 ) return 0;
++
++  pTriggerStep->op = TK_SELECT;
++  pTriggerStep->pSelect = pSelect;
++  pTriggerStep->orconf = OE_Default;
++  sqlitePersistTriggerStep(pTriggerStep);
++
++  return pTriggerStep;
++}
++
++/*
++** Build a trigger step out of an INSERT statement.  Return a pointer
++** to the new trigger step.
++**
++** The parser calls this routine when it sees an INSERT inside the
++** body of a trigger.
++*/
++TriggerStep *sqliteTriggerInsertStep(
++  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));
++  if( pTriggerStep==0 ) return 0;
++
++  assert(pEList == 0 || pSelect == 0);
++  assert(pEList != 0 || pSelect != 0);
++
++  pTriggerStep->op = TK_INSERT;
++  pTriggerStep->pSelect = pSelect;
++  pTriggerStep->target  = *pTableName;
++  pTriggerStep->pIdList = pColumn;
++  pTriggerStep->pExprList = pEList;
++  pTriggerStep->orconf = orconf;
++  sqlitePersistTriggerStep(pTriggerStep);
++
++  return pTriggerStep;
++}
++
++/*
++** Construct a trigger step that implements an UPDATE statement and return
++** a pointer to that trigger step.  The parser calls this routine when it
++** sees an UPDATE statement inside the body of a CREATE TRIGGER.
++*/
++TriggerStep *sqliteTriggerUpdateStep(
++  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;
++
++  pTriggerStep->op = TK_UPDATE;
++  pTriggerStep->target  = *pTableName;
++  pTriggerStep->pExprList = pEList;
++  pTriggerStep->pWhere = pWhere;
++  pTriggerStep->orconf = orconf;
++  sqlitePersistTriggerStep(pTriggerStep);
++
++  return pTriggerStep;
++}
++
++/*
++** Construct a trigger step that implements a DELETE statement and return
++** 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 *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){
++  TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
++  if( pTriggerStep==0 ) return 0;
++
++  pTriggerStep->op = TK_DELETE;
++  pTriggerStep->target  = *pTableName;
++  pTriggerStep->pWhere = pWhere;
++  pTriggerStep->orconf = OE_Default;
++  sqlitePersistTriggerStep(pTriggerStep);
++
++  return pTriggerStep;
++}
++
++/* 
++** Recursively delete a Trigger structure
++*/
++void sqliteDeleteTrigger(Trigger *pTrigger){
++  if( pTrigger==0 ) return;
++  sqliteDeleteTriggerStep(pTrigger->step_list);
++  sqliteFree(pTrigger->name);
++  sqliteFree(pTrigger->table);
++  sqliteExprDelete(pTrigger->pWhen);
++  sqliteIdListDelete(pTrigger->pColumns);
++  if( pTrigger->nameToken.dyn ) sqliteFree((char*)pTrigger->nameToken.z);
++  sqliteFree(pTrigger);
++}
++
++/*
++ * This function is called to drop a trigger from the database schema. 
++ *
++ * This may be called directly from the parser and therefore identifies
++ * the trigger by name.  The sqliteDropTriggerPtr() routine does the
++ * same job as this routine except it take a spointer to the trigger
++ * instead of the trigger name.
++ *
++ * Note that this function does not delete the trigger entirely. Instead it
++ * removes it from the internal schema and places it in the trigDrop hash 
++ * table. This is so that the trigger can be restored into the database schema
++ * if the transaction is rolled back.
++ */
++void sqliteDropTrigger(Parse *pParse, SrcList *pName){
++  Trigger *pTrigger;
++  int i;
++  const char *zDb;
++  const char *zName;
++  int nName;
++  sqlite *db = pParse->db;
++
++  if( sqlite_malloc_failed ) goto drop_trigger_cleanup;
++  assert( pName->nSrc==1 );
++  zDb = pName->a[0].zDatabase;
++  zName = pName->a[0].zName;
++  nName = strlen(zName);
++  for(i=0; i<db->nDb; i++){
++    int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
++    if( zDb && sqliteStrICmp(db->aDb[j].zName, zDb) ) continue;
++    pTrigger = sqliteHashFind(&(db->aDb[j].trigHash), zName, nName+1);
++    if( pTrigger ) break;
++  }
++  if( !pTrigger ){
++    sqliteErrorMsg(pParse, "no such trigger: %S", pName, 0);
++    goto drop_trigger_cleanup;
++  }
++  sqliteDropTriggerPtr(pParse, pTrigger, 0);
++
++drop_trigger_cleanup:
++  sqliteSrcListDelete(pName);
++}
++
++/*
++** Drop a trigger given a pointer to that trigger.  If nested is false,
++** then also generate code to remove the trigger from the SQLITE_MASTER
++** table.
++*/
++void sqliteDropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
++  Table   *pTable;
++  Vdbe *v;
++  sqlite *db = pParse->db;
++
++  assert( pTrigger->iDb<db->nDb );
++  if( pTrigger->iDb>=2 ){
++    sqliteErrorMsg(pParse, "triggers may not be removed from "
++       "auxiliary database %s", db->aDb[pTrigger->iDb].zName);
++    return;
++  }
++  pTable = sqliteFindTable(db, pTrigger->table,db->aDb[pTrigger->iTabDb].zName);
++  assert(pTable);
++  assert( pTable->iDb==pTrigger->iDb || pTrigger->iDb==1 );
++#ifndef SQLITE_OMIT_AUTHORIZATION
++  {
++    int code = SQLITE_DROP_TRIGGER;
++    const char *zDb = db->aDb[pTrigger->iDb].zName;
++    const char *zTab = SCHEMA_TABLE(pTrigger->iDb);
++    if( pTrigger->iDb ) code = SQLITE_DROP_TEMP_TRIGGER;
++    if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName, zDb) ||
++      sqliteAuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
++      return;
++    }
++  }
++#endif
++
++  /* Generate code to destroy the database record of the trigger.
++  */
++  if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){
++    int base;
++    static VdbeOpList dropTrigger[] = {
++      { OP_Rewind,     0, ADDR(9),  0},
++      { OP_String,     0, 0,        0}, /* 1 */
++      { OP_Column,     0, 1,        0},
++      { OP_Ne,         0, ADDR(8),  0},
++      { OP_String,     0, 0,        "trigger"},
++      { OP_Column,     0, 0,        0},
++      { OP_Ne,         0, ADDR(8),  0},
++      { OP_Delete,     0, 0,        0},
++      { OP_Next,       0, ADDR(1),  0}, /* 8 */
++    };
++
++    sqliteBeginWriteOperation(pParse, 0, 0);
++    sqliteOpenMasterTable(v, pTrigger->iDb);
++    base = sqliteVdbeAddOpList(v,  ArraySize(dropTrigger), dropTrigger);
++    sqliteVdbeChangeP3(v, base+1, pTrigger->name, 0);
++    if( pTrigger->iDb==0 ){
++      sqliteChangeCookie(db, v);
++    }
++    sqliteVdbeAddOp(v, OP_Close, 0, 0);
++    sqliteEndWriteOperation(pParse);
++  }
++
++  /*
++   * If this is not an "explain", then delete the trigger structure.
++   */
++  if( !pParse->explain ){
++    const char *zName = pTrigger->name;
++    int nName = strlen(zName);
++    if( pTable->pTrigger == pTrigger ){
++      pTable->pTrigger = pTrigger->pNext;
++    }else{
++      Trigger *cc = pTable->pTrigger;
++      while( cc ){ 
++        if( cc->pNext == pTrigger ){
++          cc->pNext = cc->pNext->pNext;
++          break;
++        }
++        cc = cc->pNext;
++      }
++      assert(cc);
++    }
++    sqliteHashInsert(&(db->aDb[pTrigger->iDb].trigHash), zName, nName+1, 0);
++    sqliteDeleteTrigger(pTrigger);
++  }
++}
++
++/*
++** pEList is the SET clause of an UPDATE statement.  Each entry
++** in pEList is of the format <id>=<expr>.  If any of the entries
++** in pEList have an <id> which matches an identifier in pIdList,
++** then return TRUE.  If pIdList==NULL, then it is considered a
++** wildcard that matches anything.  Likewise if pEList==NULL then
++** it matches anything so always return true.  Return false only
++** if there is no match.
++*/
++static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
++  int e;
++  if( !pIdList || !pEList ) return 1;
++  for(e=0; e<pEList->nExpr; e++){
++    if( sqliteIdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
++  }
++  return 0; 
++}
++
++/* A global variable that is TRUE if we should always set up temp tables for
++ * for triggers, even if there are no triggers to code. This is used to test 
++ * how much overhead the triggers algorithm is causing.
++ *
++ * This flag can be set or cleared using the "trigger_overhead_test" pragma.
++ * The pragma is not documented since it is not really part of the interface
++ * to SQLite, just the test procedure.
++*/
++int always_code_trigger_setup = 0;
++
++/*
++ * Returns true if a trigger matching op, tr_tm and foreach that is NOT already
++ * on the Parse objects trigger-stack (to prevent recursive trigger firing) is
++ * found in the list specified as pTrigger.
++ */
++int sqliteTriggersExist(
++  Parse *pParse,          /* Used to check for recursive triggers */
++  Trigger *pTrigger,      /* A list of triggers associated with a table */
++  int op,                 /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
++  int tr_tm,              /* one of TK_BEFORE, TK_AFTER */
++  int foreach,            /* one of TK_ROW or TK_STATEMENT */
++  ExprList *pChanges      /* Columns that change in an UPDATE statement */
++){
++  Trigger * pTriggerCursor;
++
++  if( always_code_trigger_setup ){
++    return 1;
++  }
++
++  pTriggerCursor = pTrigger;
++  while( pTriggerCursor ){
++    if( pTriggerCursor->op == op && 
++      pTriggerCursor->tr_tm == tr_tm && 
++      pTriggerCursor->foreach == foreach &&
++      checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){
++      TriggerStack * ss;
++      ss = pParse->trigStack;
++      while( ss && ss->pTrigger != pTrigger ){
++      ss = ss->pNext;
++      }
++      if( !ss )return 1;
++    }
++    pTriggerCursor = pTriggerCursor->pNext;
++  }
++
++  return 0;
++}
++
++/*
++** Convert the pStep->target token into a SrcList and return a pointer
++** to that SrcList.
++**
++** This routine adds a specific database name, if needed, to the target when
++** forming the SrcList.  This prevents a trigger in one database from
++** referring to a target in another database.  An exception is when the
++** trigger is in TEMP in which case it can refer to any other database it
++** wants.
++*/
++static SrcList *targetSrcList(
++  Parse *pParse,       /* The parsing context */
++  TriggerStep *pStep   /* The trigger containing the target token */
++){
++  Token sDb;           /* Dummy database name token */
++  int iDb;             /* Index of the database to use */
++  SrcList *pSrc;       /* SrcList to be returned */
++
++  iDb = pStep->pTrig->iDb;
++  if( iDb==0 || iDb>=2 ){
++    assert( iDb<pParse->db->nDb );
++    sDb.z = pParse->db->aDb[iDb].zName;
++    sDb.n = strlen(sDb.z);
++    pSrc = sqliteSrcListAppend(0, &sDb, &pStep->target);
++  } else {
++    pSrc = sqliteSrcListAppend(0, &pStep->target, 0);
++  }
++  return pSrc;
++}
++
++/*
++** Generate VDBE code for zero or more statements inside the body of a
++** trigger.  
++*/
++static int codeTriggerProgram(
++  Parse *pParse,            /* The parser context */
++  TriggerStep *pStepList,   /* List of statements inside the trigger body */
++  int orconfin              /* Conflict algorithm. (OE_Abort, etc) */  
++){
++  TriggerStep * pTriggerStep = pStepList;
++  int orconf;
++
++  while( pTriggerStep ){
++    int saveNTab = pParse->nTab;
++ 
++    orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
++    pParse->trigStack->orconf = orconf;
++    switch( pTriggerStep->op ){
++      case TK_SELECT: {
++      Select * ss = sqliteSelectDup(pTriggerStep->pSelect);             
++      assert(ss);
++      assert(ss->pSrc);
++      sqliteSelect(pParse, ss, SRT_Discard, 0, 0, 0, 0);
++      sqliteSelectDelete(ss);
++      break;
++      }
++      case TK_UPDATE: {
++        SrcList *pSrc;
++        pSrc = targetSrcList(pParse, pTriggerStep);
++        sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
++        sqliteUpdate(pParse, pSrc,
++              sqliteExprListDup(pTriggerStep->pExprList), 
++              sqliteExprDup(pTriggerStep->pWhere), orconf);
++        sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
++        break;
++      }
++      case TK_INSERT: {
++        SrcList *pSrc;
++        pSrc = targetSrcList(pParse, pTriggerStep);
++        sqliteInsert(pParse, pSrc,
++          sqliteExprListDup(pTriggerStep->pExprList), 
++          sqliteSelectDup(pTriggerStep->pSelect), 
++          sqliteIdListDup(pTriggerStep->pIdList), orconf);
++        break;
++      }
++      case TK_DELETE: {
++        SrcList *pSrc;
++        sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
++        pSrc = targetSrcList(pParse, pTriggerStep);
++        sqliteDeleteFrom(pParse, pSrc, sqliteExprDup(pTriggerStep->pWhere));
++        sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
++        break;
++      }
++      default:
++        assert(0);
++    } 
++    pParse->nTab = saveNTab;
++    pTriggerStep = pTriggerStep->pNext;
++  }
++
++  return 0;
++}
++
++/*
++** This is called to code FOR EACH ROW triggers.
++**
++** When the code that this function generates is executed, the following 
++** must be true:
++**
++** 1. No cursors may be open in the main database.  (But newIdx and oldIdx
++**    can be indices of cursors in temporary tables.  See below.)
++**
++** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then
++**    a temporary vdbe cursor (index newIdx) must be open and pointing at
++**    a row containing values to be substituted for new.* expressions in the
++**    trigger program(s).
++**
++** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then
++**    a temporary vdbe cursor (index oldIdx) must be open and pointing at
++**    a row containing values to be substituted for old.* expressions in the
++**    trigger program(s).
++**
++*/
++int sqliteCodeRowTrigger(
++  Parse *pParse,       /* Parse context */
++  int op,              /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
++  ExprList *pChanges,  /* Changes list for any UPDATE OF triggers */
++  int tr_tm,           /* One of TK_BEFORE, TK_AFTER */
++  Table *pTab,         /* The table to code triggers from */
++  int newIdx,          /* The indice of the "new" row to access */
++  int oldIdx,          /* The indice of the "old" row to access */
++  int orconf,          /* ON CONFLICT policy */
++  int ignoreJump       /* Instruction to jump to for RAISE(IGNORE) */
++){
++  Trigger * pTrigger;
++  TriggerStack * pTriggerStack;
++
++  assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
++  assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER );
++
++  assert(newIdx != -1 || oldIdx != -1);
++
++  pTrigger = pTab->pTrigger;
++  while( pTrigger ){
++    int fire_this = 0;
++
++    /* determine whether we should code this trigger */
++    if( pTrigger->op == op && pTrigger->tr_tm == tr_tm && 
++        pTrigger->foreach == TK_ROW ){
++      fire_this = 1;
++      pTriggerStack = pParse->trigStack;
++      while( pTriggerStack ){
++        if( pTriggerStack->pTrigger == pTrigger ){
++        fire_this = 0;
++      }
++        pTriggerStack = pTriggerStack->pNext;
++      }
++      if( op == TK_UPDATE && pTrigger->pColumns &&
++          !checkColumnOverLap(pTrigger->pColumns, pChanges) ){
++        fire_this = 0;
++      }
++    }
++
++    if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){
++      int endTrigger;
++      SrcList dummyTablist;
++      Expr * whenExpr;
++      AuthContext sContext;
++
++      dummyTablist.nSrc = 0;
++
++      /* Push an entry on to the trigger stack */
++      pTriggerStack->pTrigger = pTrigger;
++      pTriggerStack->newIdx = newIdx;
++      pTriggerStack->oldIdx = oldIdx;
++      pTriggerStack->pTab = pTab;
++      pTriggerStack->pNext = pParse->trigStack;
++      pTriggerStack->ignoreJump = ignoreJump;
++      pParse->trigStack = pTriggerStack;
++      sqliteAuthContextPush(pParse, &sContext, pTrigger->name);
++
++      /* code the WHEN clause */
++      endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe);
++      whenExpr = sqliteExprDup(pTrigger->pWhen);
++      if( sqliteExprResolveIds(pParse, &dummyTablist, 0, whenExpr) ){
++        pParse->trigStack = pParse->trigStack->pNext;
++        sqliteFree(pTriggerStack);
++        sqliteExprDelete(whenExpr);
++        return 1;
++      }
++      sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1);
++      sqliteExprDelete(whenExpr);
++
++      sqliteVdbeAddOp(pParse->pVdbe, OP_ContextPush, 0, 0);
++      codeTriggerProgram(pParse, pTrigger->step_list, orconf); 
++      sqliteVdbeAddOp(pParse->pVdbe, OP_ContextPop, 0, 0);
++
++      /* Pop the entry off the trigger stack */
++      pParse->trigStack = pParse->trigStack->pNext;
++      sqliteAuthContextPop(&sContext);
++      sqliteFree(pTriggerStack);
++
++      sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger);
++    }
++    pTrigger = pTrigger->pNext;
++  }
++
++  return 0;
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/update.c
+@@ -0,0 +1,459 @@
++/*
++** 2001 September 15
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This file contains C code routines that are called by the parser
++** to handle UPDATE statements.
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++
++/*
++** Process an UPDATE statement.
++**
++**   UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
++**          \_______/ \________/     \______/       \________________/
++*            onError   pTabList      pChanges             pWhere
++*/
++void sqliteUpdate(
++  Parse *pParse,         /* The parser context */
++  SrcList *pTabList,     /* The table in which we should change things */
++  ExprList *pChanges,    /* Things to be changed */
++  Expr *pWhere,          /* The WHERE clause.  May be null */
++  int onError            /* How to handle constraint errors */
++){
++  int i, j;              /* Loop counters */
++  Table *pTab;           /* The table to be updated */
++  int loopStart;         /* VDBE instruction address of the start of the loop */
++  int jumpInst;          /* Addr of VDBE instruction to jump out of loop */
++  WhereInfo *pWInfo;     /* Information about the WHERE clause */
++  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 */
++  sqlite *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 *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. */
++  int chngRecno;         /* True if the record number is being changed */
++  Expr *pRecnoExpr;      /* Expression defining the new record number */
++  int openAll;           /* True if all indices need to be opened */
++  int isView;            /* Trying to update a view */
++  int iStackDepth;       /* Index of memory cell holding stack depth */
++  AuthContext sContext;  /* The authorization context */
++
++  int before_triggers;         /* True if there are any BEFORE triggers */
++  int after_triggers;          /* True if there are any AFTER triggers */
++  int row_triggers_exist = 0;  /* True if any row triggers exist */
++
++  int newIdx      = -1;  /* index of trigger "new" temp table       */
++  int oldIdx      = -1;  /* index of trigger "old" temp table       */
++
++  sContext.pParse = 0;
++  if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup;
++  db = pParse->db;
++  assert( pTabList->nSrc==1 );
++  iStackDepth = pParse->nMem++;
++
++  /* Locate the table which we want to update. 
++  */
++  pTab = sqliteSrcListLookup(pParse, pTabList);
++  if( pTab==0 ) goto update_cleanup;
++  before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, 
++            TK_UPDATE, TK_BEFORE, TK_ROW, pChanges);
++  after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, 
++            TK_UPDATE, TK_AFTER, TK_ROW, pChanges);
++  row_triggers_exist = before_triggers || after_triggers;
++  isView = pTab->pSelect!=0;
++  if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){
++    goto update_cleanup;
++  }
++  if( isView ){
++    if( sqliteViewGetColumnNames(pParse, pTab) ){
++      goto update_cleanup;
++    }
++  }
++  aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
++  if( aXRef==0 ) goto update_cleanup;
++  for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
++
++  /* If there are FOR EACH ROW triggers, allocate cursors for the
++  ** special OLD and NEW tables
++  */
++  if( row_triggers_exist ){
++    newIdx = pParse->nTab++;
++    oldIdx = pParse->nTab++;
++  }
++
++  /* Allocate a cursors for the main database table and for all indices.
++  ** The index cursors might not be used, but if they are used they
++  ** need to occur right after the database cursor.  So go ahead and
++  ** allocate enough space, just in case.
++  */
++  pTabList->a[0].iCursor = iCur = pParse->nTab++;
++  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
++    pParse->nTab++;
++  }
++
++  /* Resolve the column names in all the expressions of the
++  ** of the UPDATE statement.  Also find the column index
++  ** for each column to be updated in the pChanges array.  For each
++  ** column to be updated, make sure we have authorization to change
++  ** that column.
++  */
++  chngRecno = 0;
++  for(i=0; i<pChanges->nExpr; i++){
++    if( sqliteExprResolveIds(pParse, pTabList, 0, pChanges->a[i].pExpr) ){
++      goto update_cleanup;
++    }
++    if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){
++      goto update_cleanup;
++    }
++    for(j=0; j<pTab->nCol; j++){
++      if( sqliteStrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
++        if( j==pTab->iPKey ){
++          chngRecno = 1;
++          pRecnoExpr = pChanges->a[i].pExpr;
++        }
++        aXRef[j] = i;
++        break;
++      }
++    }
++    if( j>=pTab->nCol ){
++      if( sqliteIsRowid(pChanges->a[i].zName) ){
++        chngRecno = 1;
++        pRecnoExpr = pChanges->a[i].pExpr;
++      }else{
++        sqliteErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
++        goto update_cleanup;
++      }
++    }
++#ifndef SQLITE_OMIT_AUTHORIZATION
++    {
++      int rc;
++      rc = sqliteAuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
++                           pTab->aCol[j].zName, db->aDb[pTab->iDb].zName);
++      if( rc==SQLITE_DENY ){
++        goto update_cleanup;
++      }else if( rc==SQLITE_IGNORE ){
++        aXRef[j] = -1;
++      }
++    }
++#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.
++  */
++  for(nIdx=nIdxTotal=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdxTotal++){
++    if( chngRecno ){
++      i = 0;
++    }else {
++      for(i=0; i<pIdx->nColumn; i++){
++        if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
++      }
++    }
++    if( i<pIdx->nColumn ) nIdx++;
++  }
++  if( nIdxTotal>0 ){
++    apIdx = sqliteMalloc( 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++){
++    if( chngRecno ){
++      i = 0;
++    }else{
++      for(i=0; i<pIdx->nColumn; i++){
++        if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
++      }
++    }
++    if( i<pIdx->nColumn ){
++      apIdx[nIdx++] = pIdx;
++      aIdxUsed[j] = 1;
++    }else{
++      aIdxUsed[j] = 0;
++    }
++  }
++
++  /* Resolve the column names in all the expressions in the
++  ** WHERE clause.
++  */
++  if( pWhere ){
++    if( sqliteExprResolveIds(pParse, pTabList, 0, pWhere) ){
++      goto update_cleanup;
++    }
++    if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
++      goto update_cleanup;
++    }
++  }
++
++  /* Start the view context
++  */
++  if( isView ){
++    sqliteAuthContextPush(pParse, &sContext, pTab->zName);
++  }
++
++  /* Begin generating code.
++  */
++  v = sqliteGetVdbe(pParse);
++  if( v==0 ) goto update_cleanup;
++  sqliteBeginWriteOperation(pParse, 1, pTab->iDb);
++
++  /* If we are trying to update a view, construct that view into
++  ** a temporary table.
++  */
++  if( isView ){
++    Select *pView;
++    pView = sqliteSelectDup(pTab->pSelect);
++    sqliteSelect(pParse, pView, SRT_TempTable, iCur, 0, 0, 0);
++    sqliteSelectDelete(pView);
++  }
++
++  /* Begin the database scan
++  */
++  pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1, 0);
++  if( pWInfo==0 ) goto update_cleanup;
++
++  /* Remember the index of every item to be updated.
++  */
++  sqliteVdbeAddOp(v, OP_ListWrite, 0, 0);
++
++  /* End the database scan loop.
++  */
++  sqliteWhereEnd(pWInfo);
++
++  /* Initialize the count of updated rows
++  */
++  if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
++    sqliteVdbeAddOp(v, OP_Integer, 0, 0);
++  }
++
++  if( row_triggers_exist ){
++    /* Create pseudo-tables for NEW and OLD
++    */
++    sqliteVdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
++    sqliteVdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
++
++    /* The top of the update loop for when there are triggers.
++    */
++    sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
++    sqliteVdbeAddOp(v, OP_StackDepth, 0, 0);
++    sqliteVdbeAddOp(v, OP_MemStore, iStackDepth, 1);
++    loopStart = sqliteVdbeAddOp(v, OP_MemLoad, iStackDepth, 0);
++    sqliteVdbeAddOp(v, OP_StackReset, 0, 0);
++    jumpInst = sqliteVdbeAddOp(v, OP_ListRead, 0, 0);
++    sqliteVdbeAddOp(v, OP_Dup, 0, 0);
++
++    /* Open a cursor and make it point to the record that is
++    ** being updated.
++    */
++    sqliteVdbeAddOp(v, OP_Dup, 0, 0);
++    if( !isView ){
++      sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
++      sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
++    }
++    sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
++
++    /* Generate the OLD table
++    */
++    sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
++    sqliteVdbeAddOp(v, OP_RowData, iCur, 0);
++    sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
++
++    /* Generate the NEW table
++    */
++    if( chngRecno ){
++      sqliteExprCode(pParse, pRecnoExpr);
++    }else{
++      sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
++    }
++    for(i=0; i<pTab->nCol; i++){
++      if( i==pTab->iPKey ){
++        sqliteVdbeAddOp(v, OP_String, 0, 0);
++        continue;
++      }
++      j = aXRef[i];
++      if( j<0 ){
++        sqliteVdbeAddOp(v, OP_Column, iCur, i);
++      }else{
++        sqliteExprCode(pParse, pChanges->a[j].pExpr);
++      }
++    }
++    sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
++    sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
++    if( !isView ){
++      sqliteVdbeAddOp(v, OP_Close, iCur, 0);
++    }
++
++    /* Fire the BEFORE and INSTEAD OF triggers
++    */
++    if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, pTab, 
++          newIdx, oldIdx, onError, loopStart) ){
++      goto update_cleanup;
++    }
++  }
++
++  if( !isView ){
++    /* 
++    ** 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.
++    */
++    sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
++    sqliteVdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum);
++    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] ){
++        sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
++        sqliteVdbeAddOp(v, OP_OpenWrite, iCur+i+1, pIdx->tnum);
++        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 entires.
++    ** So make the cursor point at the old record.
++    */
++    if( !row_triggers_exist ){
++      sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
++      jumpInst = loopStart = sqliteVdbeAddOp(v, OP_ListRead, 0, 0);
++      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
++    }
++    sqliteVdbeAddOp(v, OP_NotExists, iCur, loopStart);
++
++    /* 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( chngRecno ){
++      sqliteExprCode(pParse, pRecnoExpr);
++      sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
++    }
++
++    /* Compute new data for this record.  
++    */
++    for(i=0; i<pTab->nCol; i++){
++      if( i==pTab->iPKey ){
++        sqliteVdbeAddOp(v, OP_String, 0, 0);
++        continue;
++      }
++      j = aXRef[i];
++      if( j<0 ){
++        sqliteVdbeAddOp(v, OP_Column, iCur, i);
++      }else{
++        sqliteExprCode(pParse, pChanges->a[j].pExpr);
++      }
++    }
++
++    /* Do constraint checks
++    */
++    sqliteGenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRecno, 1,
++                                   onError, loopStart);
++
++    /* Delete the old indices for the current record.
++    */
++    sqliteGenerateRowIndexDelete(db, v, pTab, iCur, aIdxUsed);
++
++    /* If changing the record number, delete the old record.
++    */
++    if( chngRecno ){
++      sqliteVdbeAddOp(v, OP_Delete, iCur, 0);
++    }
++
++    /* Create the new index entries and the new record.
++    */
++    sqliteCompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRecno, 1, -1);
++  }
++
++  /* Increment the row counter 
++  */
++  if( db->flags & SQLITE_CountRows && !pParse->trigStack){
++    sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
++  }
++
++  /* If there are triggers, close all the cursors after each iteration
++  ** through the loop.  The fire the after triggers.
++  */
++  if( row_triggers_exist ){
++    if( !isView ){
++      for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
++        if( openAll || aIdxUsed[i] )
++          sqliteVdbeAddOp(v, OP_Close, iCur+i+1, 0);
++      }
++      sqliteVdbeAddOp(v, OP_Close, iCur, 0);
++      pParse->nTab = iCur;
++    }
++    if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, pTab, 
++          newIdx, oldIdx, onError, loopStart) ){
++      goto update_cleanup;
++    }
++  }
++
++  /* Repeat the above with the next record to be updated, until
++  ** all record selected by the WHERE clause have been updated.
++  */
++  sqliteVdbeAddOp(v, OP_Goto, 0, loopStart);
++  sqliteVdbeChangeP2(v, jumpInst, sqliteVdbeCurrentAddr(v));
++  sqliteVdbeAddOp(v, OP_ListReset, 0, 0);
++
++  /* Close all tables if there were no FOR EACH ROW triggers */
++  if( !row_triggers_exist ){
++    for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
++      if( openAll || aIdxUsed[i] ){
++        sqliteVdbeAddOp(v, OP_Close, iCur+i+1, 0);
++      }
++    }
++    sqliteVdbeAddOp(v, OP_Close, iCur, 0);
++    pParse->nTab = iCur;
++  }else{
++    sqliteVdbeAddOp(v, OP_Close, newIdx, 0);
++    sqliteVdbeAddOp(v, OP_Close, oldIdx, 0);
++  }
++
++  sqliteVdbeAddOp(v, OP_SetCounts, 0, 0);
++  sqliteEndWriteOperation(pParse);
++
++  /*
++  ** Return the number of rows that were changed.
++  */
++  if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
++    sqliteVdbeOp3(v, OP_ColumnName, 0, 1, "rows updated", P3_STATIC);
++    sqliteVdbeAddOp(v, OP_Callback, 1, 0);
++  }
++
++update_cleanup:
++  sqliteAuthContextPop(&sContext);
++  sqliteFree(apIdx);
++  sqliteFree(aXRef);
++  sqliteSrcListDelete(pTabList);
++  sqliteExprListDelete(pChanges);
++  sqliteExprDelete(pWhere);
++  return;
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/util.c
+@@ -0,0 +1,1134 @@
++/*
++** 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.
++**
++*************************************************************************
++** Utility functions used throughout sqlite.
++**
++** This file contains functions for allocating memory, comparing
++** strings, and stuff like that.
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++#include <stdarg.h>
++#include <ctype.h>
++
++/*
++** If malloc() ever fails, this global variable gets set to 1.
++** This causes the library to abort and never again function.
++*/
++int sqlite_malloc_failed = 0;
++
++/*
++** If MEMORY_DEBUG is defined, then use versions of malloc() and
++** free() that track memory usage and check for buffer overruns.
++*/
++#ifdef MEMORY_DEBUG
++
++/*
++** For keeping track of the number of mallocs and frees.   This
++** is used to check for memory leaks.
++*/
++int sqlite_nMalloc;         /* Number of sqliteMalloc() calls */
++int sqlite_nFree;           /* Number of sqliteFree() calls */
++int sqlite_iMallocFail;     /* Fail sqliteMalloc() after this many calls */
++#if MEMORY_DEBUG>1
++static int memcnt = 0;
++#endif
++
++/*
++** Number of 32-bit guard words
++*/
++#define N_GUARD 1
++
++/*
++** Allocate new memory and set it to zero.  Return NULL if
++** no memory is available.
++*/
++void *sqliteMalloc_(int n, int bZero, char *zFile, int line){
++  void *p;
++  int *pi;
++  int i, k;
++  if( sqlite_iMallocFail>=0 ){
++    sqlite_iMallocFail--;
++    if( sqlite_iMallocFail==0 ){
++      sqlite_malloc_failed++;
++#if MEMORY_DEBUG>1
++      fprintf(stderr,"**** failed to allocate %d bytes at %s:%d\n",
++              n, zFile,line);
++#endif
++      sqlite_iMallocFail--;
++      return 0;
++    }
++  }
++  if( n==0 ) return 0;
++  k = (n+sizeof(int)-1)/sizeof(int);
++  pi = malloc( (N_GUARD*2+1+k)*sizeof(int));
++  if( pi==0 ){
++    sqlite_malloc_failed++;
++    return 0;
++  }
++  sqlite_nMalloc++;
++  for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122;
++  pi[N_GUARD] = n;
++  for(i=0; i<N_GUARD; i++) pi[k+1+N_GUARD+i] = 0xdead3344;
++  p = &pi[N_GUARD+1];
++  memset(p, bZero==0, n);
++#if MEMORY_DEBUG>1
++  fprintf(stderr,"%06d malloc %d bytes at 0x%x from %s:%d\n",
++      ++memcnt, n, (int)p, zFile,line);
++#endif
++  return p;
++}
++
++/*
++** Check to see if the given pointer was obtained from sqliteMalloc()
++** and is able to hold at least N bytes.  Raise an exception if this
++** is not the case.
++**
++** This routine is used for testing purposes only.
++*/
++void sqliteCheckMemory(void *p, int N){
++  int *pi = p;
++  int n, i, k;
++  pi -= N_GUARD+1;
++  for(i=0; i<N_GUARD; i++){
++    assert( pi[i]==0xdead1122 );
++  }
++  n = pi[N_GUARD];
++  assert( N>=0 && N<n );
++  k = (n+sizeof(int)-1)/sizeof(int);
++  for(i=0; i<N_GUARD; i++){
++    assert( pi[k+N_GUARD+1+i]==0xdead3344 );
++  }
++}
++
++/*
++** Free memory previously obtained from sqliteMalloc()
++*/
++void sqliteFree_(void *p, char *zFile, int line){
++  if( p ){
++    int *pi, i, k, n;
++    pi = p;
++    pi -= N_GUARD+1;
++    sqlite_nFree++;
++    for(i=0; i<N_GUARD; i++){
++      if( pi[i]!=0xdead1122 ){
++        fprintf(stderr,"Low-end memory corruption at 0x%x\n", (int)p);
++        return;
++      }
++    }
++    n = pi[N_GUARD];
++    k = (n+sizeof(int)-1)/sizeof(int);
++    for(i=0; i<N_GUARD; i++){
++      if( pi[k+N_GUARD+1+i]!=0xdead3344 ){
++        fprintf(stderr,"High-end memory corruption at 0x%x\n", (int)p);
++        return;
++      }
++    }
++    memset(pi, 0xff, (k+N_GUARD*2+1)*sizeof(int));
++#if MEMORY_DEBUG>1
++    fprintf(stderr,"%06d free %d bytes at 0x%x from %s:%d\n",
++         ++memcnt, n, (int)p, zFile,line);
++#endif
++    free(pi);
++  }
++}
++
++/*
++** Resize a prior allocation.  If p==0, then this routine
++** works just like sqliteMalloc().  If n==0, then this routine
++** works just like sqliteFree().
++*/
++void *sqliteRealloc_(void *oldP, int n, char *zFile, int line){
++  int *oldPi, *pi, i, k, oldN, oldK;
++  void *p;
++  if( oldP==0 ){
++    return sqliteMalloc_(n,1,zFile,line);
++  }
++  if( n==0 ){
++    sqliteFree_(oldP,zFile,line);
++    return 0;
++  }
++  oldPi = oldP;
++  oldPi -= N_GUARD+1;
++  if( oldPi[0]!=0xdead1122 ){
++    fprintf(stderr,"Low-end memory corruption in realloc at 0x%x\n", (int)oldP);
++    return 0;
++  }
++  oldN = oldPi[N_GUARD];
++  oldK = (oldN+sizeof(int)-1)/sizeof(int);
++  for(i=0; i<N_GUARD; i++){
++    if( oldPi[oldK+N_GUARD+1+i]!=0xdead3344 ){
++      fprintf(stderr,"High-end memory corruption in realloc at 0x%x\n",
++              (int)oldP);
++      return 0;
++    }
++  }
++  k = (n + sizeof(int) - 1)/sizeof(int);
++  pi = malloc( (k+N_GUARD*2+1)*sizeof(int) );
++  if( pi==0 ){
++    sqlite_malloc_failed++;
++    return 0;
++  }
++  for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122;
++  pi[N_GUARD] = n;
++  for(i=0; i<N_GUARD; i++) pi[k+N_GUARD+1+i] = 0xdead3344;
++  p = &pi[N_GUARD+1];
++  memcpy(p, oldP, n>oldN ? oldN : n);
++  if( n>oldN ){
++    memset(&((char*)p)[oldN], 0, n-oldN);
++  }
++  memset(oldPi, 0xab, (oldK+N_GUARD+2)*sizeof(int));
++  free(oldPi);
++#if MEMORY_DEBUG>1
++  fprintf(stderr,"%06d realloc %d to %d bytes at 0x%x to 0x%x at %s:%d\n",
++    ++memcnt, oldN, n, (int)oldP, (int)p, zFile, line);
++#endif
++  return p;
++}
++
++/*
++** Make a duplicate of a string into memory obtained from malloc()
++** Free the original string using sqliteFree().
++**
++** This routine is called on all strings that are passed outside of
++** the SQLite library.  That way clients can free the string using free()
++** rather than having to call sqliteFree().
++*/
++void sqliteStrRealloc(char **pz){
++  char *zNew;
++  if( pz==0 || *pz==0 ) return;
++  zNew = malloc( strlen(*pz) + 1 );
++  if( zNew==0 ){
++    sqlite_malloc_failed++;
++    sqliteFree(*pz);
++    *pz = 0;
++  }
++  strcpy(zNew, *pz);
++  sqliteFree(*pz);
++  *pz = zNew;
++}
++
++/*
++** Make a copy of a string in memory obtained from sqliteMalloc()
++*/
++char *sqliteStrDup_(const char *z, char *zFile, int line){
++  char *zNew;
++  if( z==0 ) return 0;
++  zNew = sqliteMalloc_(strlen(z)+1, 0, zFile, line);
++  if( zNew ) strcpy(zNew, z);
++  return zNew;
++}
++char *sqliteStrNDup_(const char *z, int n, char *zFile, int line){
++  char *zNew;
++  if( z==0 ) return 0;
++  zNew = sqliteMalloc_(n+1, 0, zFile, line);
++  if( zNew ){
++    memcpy(zNew, z, n);
++    zNew[n] = 0;
++  }
++  return zNew;
++}
++#endif /* MEMORY_DEBUG */
++
++/*
++** The following versions of malloc() and free() are for use in a
++** normal build.
++*/
++#if !defined(MEMORY_DEBUG)
++
++/*
++** Allocate new memory and set it to zero.  Return NULL if
++** no memory is available.  See also sqliteMallocRaw().
++*/
++void *sqliteMalloc(int n){
++  void *p;
++  if( (p = malloc(n))==0 ){
++    if( n>0 ) sqlite_malloc_failed++;
++  }else{
++    memset(p, 0, n);
++  }
++  return p;
++}
++
++/*
++** Allocate new memory but do not set it to zero.  Return NULL if
++** no memory is available.  See also sqliteMalloc().
++*/
++void *sqliteMallocRaw(int n){
++  void *p;
++  if( (p = malloc(n))==0 ){
++    if( n>0 ) sqlite_malloc_failed++;
++  }
++  return p;
++}
++
++/*
++** Free memory previously obtained from sqliteMalloc()
++*/
++void sqliteFree(void *p){
++  if( p ){
++    free(p);
++  }
++}
++
++/*
++** Resize a prior allocation.  If p==0, then this routine
++** works just like sqliteMalloc().  If n==0, then this routine
++** works just like sqliteFree().
++*/
++void *sqliteRealloc(void *p, int n){
++  void *p2;
++  if( p==0 ){
++    return sqliteMalloc(n);
++  }
++  if( n==0 ){
++    sqliteFree(p);
++    return 0;
++  }
++  p2 = realloc(p, n);
++  if( p2==0 ){
++    sqlite_malloc_failed++;
++  }
++  return p2;
++}
++
++/*
++** Make a copy of a string in memory obtained from sqliteMalloc()
++*/
++char *sqliteStrDup(const char *z){
++  char *zNew;
++  if( z==0 ) return 0;
++  zNew = sqliteMallocRaw(strlen(z)+1);
++  if( zNew ) strcpy(zNew, z);
++  return zNew;
++}
++char *sqliteStrNDup(const char *z, int n){
++  char *zNew;
++  if( z==0 ) return 0;
++  zNew = sqliteMallocRaw(n+1);
++  if( zNew ){
++    memcpy(zNew, z, n);
++    zNew[n] = 0;
++  }
++  return zNew;
++}
++#endif /* !defined(MEMORY_DEBUG) */
++
++/*
++** 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 sqliteSetString(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);
++#ifdef MEMORY_DEBUG
++#if MEMORY_DEBUG>1
++  fprintf(stderr,"string at 0x%x is %s\n", (int)*pz, *pz);
++#endif
++#endif
++}
++
++/*
++** Works like sqliteSetString, but each string is now followed by
++** a length integer which specifies how much of the source string 
++** to copy (in bytes).  -1 means use the whole string.  The 1st 
++** argument must either be NULL or point to memory obtained from 
++** sqliteMalloc().
++*/
++void sqliteSetNString(char **pz, ...){
++  va_list ap;
++  int nByte;
++  const char *z;
++  char *zResult;
++  int n;
++
++  if( pz==0 ) return;
++  nByte = 0;
++  va_start(ap, pz);
++  while( (z = va_arg(ap, const char*))!=0 ){
++    n = va_arg(ap, int);
++    if( n<=0 ) n = strlen(z);
++    nByte += n;
++  }
++  va_end(ap);
++  sqliteFree(*pz);
++  *pz = zResult = sqliteMallocRaw( nByte + 1 );
++  if( zResult==0 ) return;
++  va_start(ap, pz);
++  while( (z = va_arg(ap, const char*))!=0 ){
++    n = va_arg(ap, int);
++    if( n<=0 ) n = strlen(z);
++    strncpy(zResult, z, n);
++    zResult += n;
++  }
++  *zResult = 0;
++#ifdef MEMORY_DEBUG
++#if MEMORY_DEBUG>1
++  fprintf(stderr,"string at 0x%x is %s\n", (int)*pz, *pz);
++#endif
++#endif
++  va_end(ap);
++}
++
++/*
++** Add an error message to pParse->zErrMsg and increment pParse->nErr.
++** The following formatting characters are allowed:
++**
++**      %s      Insert a string
++**      %z      A string that should be freed after use
++**      %d      Insert an integer
++**      %T      Insert a token
++**      %S      Insert the first element of a SrcList
++*/
++void sqliteErrorMsg(Parse *pParse, const char *zFormat, ...){
++  va_list ap;
++  pParse->nErr++;
++  sqliteFree(pParse->zErrMsg);
++  va_start(ap, zFormat);
++  pParse->zErrMsg = sqliteVMPrintf(zFormat, ap);
++  va_end(ap);
++}
++
++/*
++** Convert an SQL-style quoted string into a normal string by removing
++** the quote characters.  The conversion is done in-place.  If the
++** input does not begin with a quote character, then this routine
++** is a no-op.
++**
++** 2002-Feb-14: This routine is extended to remove MS-Access style
++** brackets from around identifers.  For example:  "[a-b-c]" becomes
++** "a-b-c".
++*/
++void sqliteDequote(char *z){
++  int quote;
++  int i, j;
++  if( z==0 ) return;
++  quote = z[0];
++  switch( quote ){
++    case '\'':  break;
++    case '"':   break;
++    case '[':   quote = ']';  break;
++    default:    return;
++  }
++  for(i=1, j=0; z[i]; i++){
++    if( z[i]==quote ){
++      if( z[i+1]==quote ){
++        z[j++] = quote;
++        i++;
++      }else{
++        z[j++] = 0;
++        break;
++      }
++    }else{
++      z[j++] = z[i];
++    }
++  }
++}
++
++/* An array to map all upper-case characters into their corresponding
++** lower-case character. 
++*/
++static unsigned char UpperToLower[] = {
++      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
++     18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
++     36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
++     54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
++    104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
++    122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
++    108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
++    126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
++    144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
++    162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
++    180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
++    198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
++    216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
++    234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
++    252,253,254,255
++};
++
++/*
++** This function computes a hash on the name of a keyword.
++** Case is not significant.
++*/
++int sqliteHashNoCase(const char *z, int n){
++  int h = 0;
++  if( n<=0 ) n = strlen(z);
++  while( n > 0  ){
++    h = (h<<3) ^ h ^ UpperToLower[(unsigned char)*z++];
++    n--;
++  }
++  return h & 0x7fffffff;
++}
++
++/*
++** Some systems have stricmp().  Others have strcasecmp().  Because
++** there is no consistency, we will define our own.
++*/
++int sqliteStrICmp(const char *zLeft, const char *zRight){
++  register unsigned char *a, *b;
++  a = (unsigned char *)zLeft;
++  b = (unsigned char *)zRight;
++  while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
++  return UpperToLower[*a] - UpperToLower[*b];
++}
++int sqliteStrNICmp(const char *zLeft, const char *zRight, int N){
++  register unsigned char *a, *b;
++  a = (unsigned char *)zLeft;
++  b = (unsigned char *)zRight;
++  while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
++  return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];
++}
++
++/*
++** Return TRUE if z is a pure numeric string.  Return FALSE if the
++** string contains any character which is not part of a number.
++**
++** Am empty string is considered non-numeric.
++*/
++int sqliteIsNumber(const char *z){
++  if( *z=='-' || *z=='+' ) z++;
++  if( !isdigit(*z) ){
++    return 0;
++  }
++  z++;
++  while( isdigit(*z) ){ z++; }
++  if( *z=='.' ){
++    z++;
++    if( !isdigit(*z) ) return 0;
++    while( isdigit(*z) ){ z++; }
++  }
++  if( *z=='e' || *z=='E' ){
++    z++;
++    if( *z=='+' || *z=='-' ) z++;
++    if( !isdigit(*z) ) return 0;
++    while( isdigit(*z) ){ z++; }
++  }
++  return *z==0;
++}
++
++/*
++** The string z[] is an ascii representation of a real number.
++** Convert this string to a double.
++**
++** This routine assumes that z[] really is a valid number.  If it
++** is not, the result is undefined.
++**
++** This routine is used instead of the library atof() function because
++** the library atof() might want to use "," as the decimal point instead
++** of "." depending on how locale is set.  But that would cause problems
++** for SQL.  So this routine always uses "." regardless of locale.
++*/
++double sqliteAtoF(const char *z, const char **pzEnd){
++  int sign = 1;
++  LONGDOUBLE_TYPE v1 = 0.0;
++  if( *z=='-' ){
++    sign = -1;
++    z++;
++  }else if( *z=='+' ){
++    z++;
++  }
++  while( isdigit(*z) ){
++    v1 = v1*10.0 + (*z - '0');
++    z++;
++  }
++  if( *z=='.' ){
++    LONGDOUBLE_TYPE divisor = 1.0;
++    z++;
++    while( isdigit(*z) ){
++      v1 = v1*10.0 + (*z - '0');
++      divisor *= 10.0;
++      z++;
++    }
++    v1 /= divisor;
++  }
++  if( *z=='e' || *z=='E' ){
++    int esign = 1;
++    int eval = 0;
++    LONGDOUBLE_TYPE scale = 1.0;
++    z++;
++    if( *z=='-' ){
++      esign = -1;
++      z++;
++    }else if( *z=='+' ){
++      z++;
++    }
++    while( isdigit(*z) ){
++      eval = eval*10 + *z - '0';
++      z++;
++    }
++    while( eval>=64 ){ scale *= 1.0e+64; eval -= 64; }
++    while( eval>=16 ){ scale *= 1.0e+16; eval -= 16; }
++    while( eval>=4 ){ scale *= 1.0e+4; eval -= 4; }
++    while( eval>=1 ){ scale *= 1.0e+1; eval -= 1; }
++    if( esign<0 ){
++      v1 /= scale;
++    }else{
++      v1 *= scale;
++    }
++  }
++  if( pzEnd ) *pzEnd = z;
++  return sign<0 ? -v1 : v1;
++}
++
++/*
++** 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 theory fit in a 32-bit integer.  But positive
++** 2147483648 will not fit in 32 bits.  So it seems safer to return
++** false.
++*/
++int sqliteFitsIn32Bits(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);
++}
++
++/* This comparison routine is what we use for comparison operations
++** between numeric values in an SQL expression.  "Numeric" is a little
++** bit misleading here.  What we mean is that the strings have a
++** type of "numeric" from the point of view of SQL.  The strings
++** do not necessarily contain numbers.  They could contain text.
++**
++** If the input strings both look like actual numbers then they
++** compare in numerical order.  Numerical strings are always less 
++** than non-numeric strings so if one input string looks like a
++** number and the other does not, then the one that looks like
++** a number is the smaller.  Non-numeric strings compare in 
++** lexigraphical order (the same order as strcmp()).
++*/
++int sqliteCompare(const char *atext, const char *btext){
++  int result;
++  int isNumA, isNumB;
++  if( atext==0 ){
++    return -1;
++  }else if( btext==0 ){
++    return 1;
++  }
++  isNumA = sqliteIsNumber(atext);
++  isNumB = sqliteIsNumber(btext);
++  if( isNumA ){
++    if( !isNumB ){
++      result = -1;
++    }else{
++      double rA, rB;
++      rA = sqliteAtoF(atext, 0);
++      rB = sqliteAtoF(btext, 0);
++      if( rA<rB ){
++        result = -1;
++      }else if( rA>rB ){
++        result = +1;
++      }else{
++        result = 0;
++      }
++    }
++  }else if( isNumB ){
++    result = +1;
++  }else {
++    result = strcmp(atext, btext);
++  }
++  return result; 
++}
++
++/*
++** This routine is used for sorting.  Each key is a list of one or more
++** null-terminated elements.  The list is terminated by two nulls in
++** a row.  For example, the following text is a key with three elements
++**
++**            Aone\000Dtwo\000Athree\000\000
++**
++** All elements begin with one of the characters "+-AD" and end with "\000"
++** with zero or more text elements in between.  Except, NULL elements
++** consist of the special two-character sequence "N\000".
++**
++** Both arguments will have the same number of elements.  This routine
++** returns negative, zero, or positive if the first argument is less
++** than, equal to, or greater than the first.  (Result is a-b).
++**
++** Each element begins with one of the characters "+", "-", "A", "D".
++** This character determines the sort order and collating sequence:
++**
++**     +      Sort numerically in ascending order
++**     -      Sort numerically in descending order
++**     A      Sort as strings in ascending order
++**     D      Sort as strings in descending order.
++**
++** For the "+" and "-" sorting, pure numeric strings (strings for which the
++** isNum() function above returns TRUE) always compare less than strings
++** that are not pure numerics.  Non-numeric strings compare in memcmp()
++** order.  This is the same sort order as the sqliteCompare() function
++** above generates.
++**
++** The last point is a change from version 2.6.3 to version 2.7.0.  In
++** version 2.6.3 and earlier, substrings of digits compare in numerical 
++** and case was used only to break a tie.
++**
++** Elements that begin with 'A' or 'D' compare in memcmp() order regardless
++** of whether or not they look like a number.
++**
++** Note that the sort order imposed by the rules above is the same
++** from the ordering defined by the "<", "<=", ">", and ">=" operators
++** of expressions and for indices.  This was not the case for version
++** 2.6.3 and earlier.
++*/
++int sqliteSortCompare(const char *a, const char *b){
++  int res = 0;
++  int isNumA, isNumB;
++  int dir = 0;
++
++  while( res==0 && *a && *b ){
++    if( a[0]=='N' || b[0]=='N' ){
++      if( a[0]==b[0] ){
++        a += 2;
++        b += 2;
++        continue;
++      }
++      if( a[0]=='N' ){
++        dir = b[0];
++        res = -1;
++      }else{
++        dir = a[0];
++        res = +1;
++      }
++      break;
++    }
++    assert( a[0]==b[0] );
++    if( (dir=a[0])=='A' || a[0]=='D' ){
++      res = strcmp(&a[1],&b[1]);
++      if( res ) break;
++    }else{
++      isNumA = sqliteIsNumber(&a[1]);
++      isNumB = sqliteIsNumber(&b[1]);
++      if( isNumA ){
++        double rA, rB;
++        if( !isNumB ){
++          res = -1;
++          break;
++        }
++        rA = sqliteAtoF(&a[1], 0);
++        rB = sqliteAtoF(&b[1], 0);
++        if( rA<rB ){
++          res = -1;
++          break;
++        }
++        if( rA>rB ){
++          res = +1;
++          break;
++        }
++      }else if( isNumB ){
++        res = +1;
++        break;
++      }else{
++        res = strcmp(&a[1],&b[1]);
++        if( res ) break;
++      }
++    }
++    a += strlen(&a[1]) + 2;
++    b += strlen(&b[1]) + 2;
++  }
++  if( dir=='-' || dir=='D' ) res = -res;
++  return res;
++}
++
++/*
++** Some powers of 64.  These constants are needed in the
++** sqliteRealToSortable() routine below.
++*/
++#define _64e3  (64.0 * 64.0 * 64.0)
++#define _64e4  (64.0 * 64.0 * 64.0 * 64.0)
++#define _64e15 (_64e3 * _64e4 * _64e4 * _64e4)
++#define _64e16 (_64e4 * _64e4 * _64e4 * _64e4)
++#define _64e63 (_64e15 * _64e16 * _64e16 * _64e16)
++#define _64e64 (_64e16 * _64e16 * _64e16 * _64e16)
++
++/*
++** The following procedure converts a double-precision floating point
++** number into a string.  The resulting string has the property that
++** two such strings comparied using strcmp() or memcmp() will give the
++** same results as a numeric comparison of the original floating point
++** numbers.
++**
++** This routine is used to generate database keys from floating point
++** numbers such that the keys sort in the same order as the original
++** floating point numbers even though the keys are compared using
++** memcmp().
++**
++** The calling function should have allocated at least 14 characters
++** of space for the buffer z[].
++*/
++void sqliteRealToSortable(double r, char *z){
++  int neg;
++  int exp;
++  int cnt = 0;
++
++  /* This array maps integers between 0 and 63 into base-64 digits.
++  ** The digits must be chosen such at their ASCII codes are increasing.
++  ** This means we can not use the traditional base-64 digit set. */
++  static const char zDigit[] = 
++     "0123456789"
++     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
++     "abcdefghijklmnopqrstuvwxyz"
++     "|~";
++  if( r<0.0 ){
++    neg = 1;
++    r = -r;
++    *z++ = '-';
++  } else {
++    neg = 0;
++    *z++ = '0';
++  }
++  exp = 0;
++
++  if( r==0.0 ){
++    exp = -1024;
++  }else if( r<(0.5/64.0) ){
++    while( r < 0.5/_64e64 && exp > -961  ){ r *= _64e64;  exp -= 64; }
++    while( r < 0.5/_64e16 && exp > -1009 ){ r *= _64e16;  exp -= 16; }
++    while( r < 0.5/_64e4  && exp > -1021 ){ r *= _64e4;   exp -= 4; }
++    while( r < 0.5/64.0   && exp > -1024 ){ r *= 64.0;    exp -= 1; }
++  }else if( r>=0.5 ){
++    while( r >= 0.5*_64e63 && exp < 960  ){ r *= 1.0/_64e64; exp += 64; }
++    while( r >= 0.5*_64e15 && exp < 1008 ){ r *= 1.0/_64e16; exp += 16; }
++    while( r >= 0.5*_64e3  && exp < 1020 ){ r *= 1.0/_64e4;  exp += 4; }
++    while( r >= 0.5        && exp < 1023 ){ r *= 1.0/64.0;   exp += 1; }
++  }
++  if( neg ){
++    exp = -exp;
++    r = -r;
++  }
++  exp += 1024;
++  r += 0.5;
++  if( exp<0 ) return;
++  if( exp>=2048 || r>=1.0 ){
++    strcpy(z, "~~~~~~~~~~~~");
++    return;
++  }
++  *z++ = zDigit[(exp>>6)&0x3f];
++  *z++ = zDigit[exp & 0x3f];
++  while( r>0.0 && cnt<10 ){
++    int digit;
++    r *= 64.0;
++    digit = (int)r;
++    assert( digit>=0 && digit<64 );
++    *z++ = zDigit[digit & 0x3f];
++    r -= digit;
++    cnt++;
++  }
++  *z = 0;
++}
++
++#ifdef SQLITE_UTF8
++/*
++** 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)   sqlite_utf8_to_int(X)
++
++#else /* !defined(SQLITE_UTF8) */
++/*
++** For iso8859 encoding, the next character is just the next byte.
++*/
++#define sqliteNextChar(X)  (++(X));
++#define sqliteCharVal(X)   ((int)*(X))
++
++#endif /* defined(SQLITE_UTF8) */
++
++
++#ifdef SQLITE_UTF8
++/*
++** Convert the UTF-8 character to which z points into a 31-bit
++** UCS character.  This only works right if z points to a well-formed
++** UTF-8 string.
++*/
++static int sqlite_utf8_to_int(const unsigned char *z){
++  int c;
++  static const int initVal[] = {
++      0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
++     15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,
++     30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,
++     45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,
++     60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,
++     75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,
++     90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104,
++    105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
++    120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
++    135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
++    150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
++    165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
++    180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,   0,   1,   2,
++      3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,
++     18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,   0,
++      1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
++      0,   1,   2,   3,   4,   5,   6,   7,   0,   1,   2,   3,   0,   1, 254,
++    255,
++  };
++  c = initVal[*(z++)];
++  while( (0xc0&*z)==0x80 ){
++    c = (c<<6) | (0x3f&*(z++));
++  }
++  return c;
++}
++#endif
++
++/*
++** 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.
++**
++** Globbing rules:
++**
++**      '*'       Matches any sequence of zero or more characters.
++**
++**      '?'       Matches exactly one character.
++**
++**     [...]      Matches one character from the enclosed list of
++**                characters.
++**
++**     [^...]     Matches one character not in the enclosed list.
++**
++** With the [...] and [^...] matching, a ']' character can be included
++** in the list by making it the first character after '[' or '^'.  A
++** range of characters can be specified using '-'.  Example:
++** "[a-z]" matches any single lower-case letter.  To match a '-', make
++** it the last character in the list.
++**
++** This routine is usually quick, but can be N**2 in the worst case.
++**
++** Hints: to match '*' or '?', put them in "[]".  Like this:
++**
++**         abc[*]xyz        Matches "abc*xyz" only
++*/
++int 
++sqliteGlobCompare(const unsigned char *zPattern, const unsigned char *zString){
++  register int c;
++  int invert;
++  int seen;
++  int c2;
++
++  while( (c = *zPattern)!=0 ){
++    switch( c ){
++      case '*':
++        while( (c=zPattern[1]) == '*' || c == '?' ){
++          if( c=='?' ){
++            if( *zString==0 ) return 0;
++            sqliteNextChar(zString);
++          }
++          zPattern++;
++        }
++        if( c==0 ) return 1;
++        if( c=='[' ){
++          while( *zString && sqliteGlobCompare(&zPattern[1],zString)==0 ){
++            sqliteNextChar(zString);
++          }
++          return *zString!=0;
++        }else{
++          while( (c2 = *zString)!=0 ){
++            while( c2 != 0 && c2 != c ){ c2 = *++zString; }
++            if( c2==0 ) return 0;
++            if( sqliteGlobCompare(&zPattern[1],zString) ) return 1;
++            sqliteNextChar(zString);
++          }
++          return 0;
++        }
++      case '?': {
++        if( *zString==0 ) return 0;
++        sqliteNextChar(zString);
++        zPattern++;
++        break;
++      }
++      case '[': {
++        int prior_c = 0;
++        seen = 0;
++        invert = 0;
++        c = sqliteCharVal(zString);
++        if( c==0 ) return 0;
++        c2 = *++zPattern;
++        if( c2=='^' ){ invert = 1; c2 = *++zPattern; }
++        if( c2==']' ){
++          if( c==']' ) seen = 1;
++          c2 = *++zPattern;
++        }
++        while( (c2 = sqliteCharVal(zPattern))!=0 && c2!=']' ){
++          if( c2=='-' && zPattern[1]!=']' && zPattern[1]!=0 && prior_c>0 ){
++            zPattern++;
++            c2 = sqliteCharVal(zPattern);
++            if( c>=prior_c && c<=c2 ) seen = 1;
++            prior_c = 0;
++          }else if( c==c2 ){
++            seen = 1;
++            prior_c = c2;
++          }else{
++            prior_c = c2;
++          }
++          sqliteNextChar(zPattern);
++        }
++        if( c2==0 || (seen ^ invert)==0 ) return 0;
++        sqliteNextChar(zString);
++        zPattern++;
++        break;
++      }
++      default: {
++        if( c != *zString ) return 0;
++        zPattern++;
++        zString++;
++        break;
++      }
++    }
++  }
++  return *zString==0;
++}
++
++/*
++** Compare two UTF-8 strings for equality using the "LIKE" operator of
++** SQL.  The '%' character matches any sequence of 0 or more
++** characters and '_' matches any single character.  Case is
++** not significant.
++**
++** This routine is just an adaptation of the sqliteGlobCompare()
++** routine above.
++*/
++int 
++sqliteLikeCompare(const unsigned char *zPattern, const unsigned char *zString){
++  register int c;
++  int c2;
++
++  while( (c = UpperToLower[*zPattern])!=0 ){
++    switch( c ){
++      case '%': {
++        while( (c=zPattern[1]) == '%' || c == '_' ){
++          if( c=='_' ){
++            if( *zString==0 ) return 0;
++            sqliteNextChar(zString);
++          }
++          zPattern++;
++        }
++        if( c==0 ) return 1;
++        c = UpperToLower[c];
++        while( (c2=UpperToLower[*zString])!=0 ){
++          while( c2 != 0 && c2 != c ){ c2 = UpperToLower[*++zString]; }
++          if( c2==0 ) return 0;
++          if( sqliteLikeCompare(&zPattern[1],zString) ) return 1;
++          sqliteNextChar(zString);
++        }
++        return 0;
++      }
++      case '_': {
++        if( *zString==0 ) return 0;
++        sqliteNextChar(zString);
++        zPattern++;
++        break;
++      }
++      default: {
++        if( c != UpperToLower[*zString] ) return 0;
++        zPattern++;
++        zString++;
++        break;
++      }
++    }
++  }
++  return *zString==0;
++}
++
++/*
++** 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.
++**
++** 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 sqlite_close(db) and db has been deallocated.  And we do
++** not want to write into deallocated memory.
++*/
++int sqliteSafetyOn(sqlite *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->want_to_close ){
++    db->magic = SQLITE_MAGIC_ERROR;
++    db->flags |= SQLITE_Interrupt;
++  }
++  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 sqliteSafetyOff(sqlite *db){
++  if( db->magic==SQLITE_MAGIC_BUSY ){
++    db->magic = SQLITE_MAGIC_OPEN;
++    return 0;
++  }else if( db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_ERROR
++             || db->want_to_close ){
++    db->magic = SQLITE_MAGIC_ERROR;
++    db->flags |= SQLITE_Interrupt;
++  }
++  return 1;
++}
++
++/*
++** Check to make sure we are not currently executing an sqlite_exec().
++** If we are currently in an sqlite_exec(), return true and set
++** sqlite.magic to SQLITE_MAGIC_ERROR.  This will cause a complete
++** shutdown of the database.
++**
++** This routine is used to try to detect when API routines are called
++** at the wrong time or in the wrong sequence.
++*/
++int sqliteSafetyCheck(sqlite *db){
++  if( db->pVdbe!=0 ){
++    db->magic = SQLITE_MAGIC_ERROR;
++    return 1;
++  }
++  return 0;
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/vacuum.c
+@@ -0,0 +1,305 @@
++/*
++** 2003 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.
++**
++*************************************************************************
++** This file contains code used to implement the VACUUM command.
++**
++** Most of the code in this file may be omitted by defining the
++** SQLITE_OMIT_VACUUM macro.
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++#include "os.h"
++
++/*
++** A structure for holding a dynamic string - a string that can grow
++** without bound. 
++*/
++typedef struct dynStr dynStr;
++struct dynStr {
++  char *z;        /* Text of the string in space obtained from sqliteMalloc() */
++  int nAlloc;     /* Amount of space allocated to z[] */
++  int nUsed;      /* Next unused slot in z[] */
++};
++
++/*
++** A structure that holds the vacuum context
++*/
++typedef struct vacuumStruct vacuumStruct;
++struct vacuumStruct {
++  sqlite *dbOld;       /* Original database */
++  sqlite *dbNew;       /* New database */
++  char **pzErrMsg;     /* Write errors here */
++  int rc;              /* Set to non-zero on an error */
++  const char *zTable;  /* Name of a table being copied */
++  const char *zPragma; /* Pragma to execute with results */
++  dynStr s1, s2;       /* Two dynamic strings */
++};
++
++#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
++/*
++** Append text to a dynamic string
++*/
++static void appendText(dynStr *p, const char *zText, int nText){
++  if( nText<0 ) nText = strlen(zText);
++  if( p->z==0 || p->nUsed + nText + 1 >= p->nAlloc ){
++    char *zNew;
++    p->nAlloc = p->nUsed + nText + 1000;
++    zNew = sqliteRealloc(p->z, p->nAlloc);
++    if( zNew==0 ){
++      sqliteFree(p->z);
++      memset(p, 0, sizeof(*p));
++      return;
++    }
++    p->z = zNew;
++  }
++  memcpy(&p->z[p->nUsed], zText, nText+1);
++  p->nUsed += nText;
++}
++
++/*
++** Append text to a dynamic string, having first put the text in quotes.
++*/
++static void appendQuoted(dynStr *p, const char *zText){
++  int i, j;
++  appendText(p, "'", 1);
++  for(i=j=0; zText[i]; i++){
++    if( zText[i]=='\'' ){
++      appendText(p, &zText[j], i-j+1);
++      j = i + 1;
++      appendText(p, "'", 1);
++    }
++  }
++  if( j<i ){
++    appendText(p, &zText[j], i-j);
++  }
++  appendText(p, "'", 1);
++}
++
++/*
++** Execute statements of SQL.  If an error occurs, write the error
++** message into *pzErrMsg and return non-zero.
++*/
++static int execsql(char **pzErrMsg, sqlite *db, const char *zSql){ 
++  char *zErrMsg = 0;
++  int rc;
++
++  /* printf("***** executing *****\n%s\n", zSql); */
++  rc = sqlite_exec(db, zSql, 0, 0, &zErrMsg);
++  if( zErrMsg ){
++    sqliteSetString(pzErrMsg, zErrMsg, (char*)0);
++    sqlite_freemem(zErrMsg);
++  }
++  return rc;
++}
++
++/*
++** This is the second stage callback.  Each invocation contains all the
++** data for a single row of a single table in the original database.  This
++** routine must write that information into the new database.
++*/
++static int vacuumCallback2(void *pArg, int argc, char **argv, char **NotUsed){
++  vacuumStruct *p = (vacuumStruct*)pArg;
++  const char *zSep = "(";
++  int i;
++
++  if( argv==0 ) return 0;
++  p->s2.nUsed = 0;
++  appendText(&p->s2, "INSERT INTO ", -1);
++  appendQuoted(&p->s2, p->zTable);
++  appendText(&p->s2, " VALUES", -1);
++  for(i=0; i<argc; i++){
++    appendText(&p->s2, zSep, 1);
++    zSep = ",";
++    if( argv[i]==0 ){
++      appendText(&p->s2, "NULL", 4);
++    }else{
++      appendQuoted(&p->s2, argv[i]);
++    }
++  }
++  appendText(&p->s2,")", 1);
++  p->rc = execsql(p->pzErrMsg, p->dbNew, p->s2.z);
++  return p->rc;
++}
++
++/*
++** This is the first stage callback.  Each invocation contains three
++** arguments where are taken from the SQLITE_MASTER table of the original
++** database:  (1) the entry type, (2) the entry name, and (3) the SQL for
++** the entry.  In all cases, execute the SQL of the third argument.
++** For tables, run a query to select all entries in that table and 
++** transfer them to the second-stage callback.
++*/
++static int vacuumCallback1(void *pArg, int argc, char **argv, char **NotUsed){
++  vacuumStruct *p = (vacuumStruct*)pArg;
++  int rc = 0;
++  assert( argc==3 );
++  if( argv==0 ) return 0;
++  assert( argv[0]!=0 );
++  assert( argv[1]!=0 );
++  assert( argv[2]!=0 );
++  rc = execsql(p->pzErrMsg, p->dbNew, argv[2]);
++  if( rc==SQLITE_OK && strcmp(argv[0],"table")==0 ){
++    char *zErrMsg = 0;
++    p->s1.nUsed = 0;
++    appendText(&p->s1, "SELECT * FROM ", -1);
++    appendQuoted(&p->s1, argv[1]);
++    p->zTable = argv[1];
++    rc = sqlite_exec(p->dbOld, p->s1.z, vacuumCallback2, p, &zErrMsg);
++    if( zErrMsg ){
++      sqliteSetString(p->pzErrMsg, zErrMsg, (char*)0);
++      sqlite_freemem(zErrMsg);
++    }
++  }
++  if( rc!=SQLITE_ABORT ) p->rc = rc;
++  return rc;
++}
++
++/*
++** Generate a random name of 20 character in length.
++*/
++static void randomName(unsigned char *zBuf){
++  static const unsigned char zChars[] =
++    "abcdefghijklmnopqrstuvwxyz"
++    "0123456789";
++  int i;
++  sqliteRandomness(20, zBuf);
++  for(i=0; i<20; i++){
++    zBuf[i] = zChars[ zBuf[i]%(sizeof(zChars)-1) ];
++  }
++}
++#endif
++
++/*
++** The non-standard VACUUM command is used to clean up the database,
++** collapse free space, etc.  It is modelled after the VACUUM command
++** in PostgreSQL.
++**
++** In version 1.0.x of SQLite, the VACUUM command would call
++** gdbm_reorganize() on all the database tables.  But beginning
++** with 2.0.0, SQLite no longer uses GDBM so this command has
++** become a no-op.
++*/
++void sqliteVacuum(Parse *pParse, Token *pTableName){
++  Vdbe *v = sqliteGetVdbe(pParse);
++  sqliteVdbeAddOp(v, OP_Vacuum, 0, 0);
++  return;
++}
++
++/*
++** This routine implements the OP_Vacuum opcode of the VDBE.
++*/
++int sqliteRunVacuum(char **pzErrMsg, sqlite *db){
++#if !defined(SQLITE_OMIT_VACUUM) || 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 */
++  sqlite *dbNew = 0;      /* The new vacuumed database */
++  int rc = SQLITE_OK;     /* Return code from service routines */
++  int i;                  /* Loop counter */
++  char *zErrMsg;          /* Error message */
++  vacuumStruct sVac;      /* Information passed to callbacks */
++
++  if( db->flags & SQLITE_InTrans ){
++    sqliteSetString(pzErrMsg, "cannot VACUUM from within a transaction", 
++       (char*)0);
++    return SQLITE_ERROR;
++  }
++  if( db->flags & SQLITE_Interrupt ){
++    return SQLITE_INTERRUPT;
++  }
++  memset(&sVac, 0, sizeof(sVac));
++
++  /* Get the full pathname of the database file and create two
++  ** temporary filenames in the same directory as the original file.
++  */
++  zFilename = sqliteBtreeGetFilename(db->aDb[0].pBt);
++  if( zFilename==0 ){
++    /* This only happens with the in-memory database.  VACUUM is a no-op
++    ** there, so just return */
++    return SQLITE_OK;
++  }
++  nFilename = strlen(zFilename);
++  zTemp = sqliteMalloc( nFilename+100 );
++  if( zTemp==0 ) return SQLITE_NOMEM;
++  strcpy(zTemp, zFilename);
++  for(i=0; i<10; i++){
++    zTemp[nFilename] = '-';
++    randomName((unsigned char*)&zTemp[nFilename+1]);
++    if( !sqliteOsFileExists(zTemp) ) break;
++  }
++  if( i>=10 ){
++    sqliteSetString(pzErrMsg, "unable to create a temporary database file "
++       "in the same directory as the original database", (char*)0);
++    goto end_of_vacuum;
++  }
++
++  
++  dbNew = sqlite_open(zTemp, 0, &zErrMsg);
++  if( dbNew==0 ){
++    sqliteSetString(pzErrMsg, "unable to open a temporary database at ",
++       zTemp, " - ", zErrMsg, (char*)0);
++    goto end_of_vacuum;
++  }
++  if( (rc = execsql(pzErrMsg, db, "BEGIN"))!=0 ) goto end_of_vacuum;
++  if( (rc = execsql(pzErrMsg, dbNew, "PRAGMA synchronous=off; BEGIN"))!=0 ){
++    goto end_of_vacuum;
++  }
++  
++  sVac.dbOld = db;
++  sVac.dbNew = dbNew;
++  sVac.pzErrMsg = pzErrMsg;
++  if( rc==SQLITE_OK ){
++    rc = sqlite_exec(db, 
++      "SELECT type, name, sql FROM sqlite_master "
++      "WHERE sql NOT NULL AND type!='view' "
++      "UNION ALL "
++      "SELECT type, name, sql FROM sqlite_master "
++      "WHERE sql NOT NULL AND type=='view'",
++      vacuumCallback1, &sVac, &zErrMsg);
++  }
++  if( rc==SQLITE_OK ){
++    int meta1[SQLITE_N_BTREE_META];
++    int meta2[SQLITE_N_BTREE_META];
++    sqliteBtreeGetMeta(db->aDb[0].pBt, meta1);
++    sqliteBtreeGetMeta(dbNew->aDb[0].pBt, meta2);
++    meta2[1] = meta1[1]+1;
++    meta2[3] = meta1[3];
++    meta2[4] = meta1[4];
++    meta2[6] = meta1[6];
++    rc = sqliteBtreeUpdateMeta(dbNew->aDb[0].pBt, meta2);
++  }
++  if( rc==SQLITE_OK ){
++    rc = sqliteBtreeCopyFile(db->aDb[0].pBt, dbNew->aDb[0].pBt);
++    sqlite_exec(db, "COMMIT", 0, 0, 0);
++    sqliteResetInternalSchema(db, 0);
++  }
++
++end_of_vacuum:
++  if( rc && zErrMsg!=0 ){
++    sqliteSetString(pzErrMsg, "unable to vacuum database - ", 
++       zErrMsg, (char*)0);
++  }
++  sqlite_exec(db, "ROLLBACK", 0, 0, 0);
++  if( (dbNew && (dbNew->flags & SQLITE_Interrupt)) 
++         || (db->flags & SQLITE_Interrupt) ){
++    rc = SQLITE_INTERRUPT;
++  }
++  if( dbNew ) sqlite_close(dbNew);
++  sqliteOsDelete(zTemp);
++  sqliteFree(zTemp);
++  sqliteFree(sVac.s1.z);
++  sqliteFree(sVac.s2.z);
++  if( zErrMsg ) sqlite_freemem(zErrMsg);
++  if( rc==SQLITE_ABORT && sVac.rc!=SQLITE_INTERRUPT ) sVac.rc = SQLITE_ERROR;
++  return sVac.rc;
++#endif
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/vdbeaux.c
+@@ -0,0 +1,1061 @@
++/*
++** 2003 September 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.
++**
++*************************************************************************
++** This file contains code used for creating, destroying, and populating
++** a VDBE (or an "sqlite_vm" as it is known to the outside world.)  Prior
++** to version 2.8.7, all this code was combined into the vdbe.c source file.
++** But that file was getting too big so this subroutines were split out.
++*/
++#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 sqlite_vdbe_addop_trace to 1 and all opcodes will be printed
++** as they are added to the instruction stream.
++*/
++#ifndef NDEBUG
++int sqlite_vdbe_addop_trace = 0;
++#endif
++
++
++/*
++** Create a new virtual database engine.
++*/
++Vdbe *sqliteVdbeCreate(sqlite *db){
++  Vdbe *p;
++  p = sqliteMalloc( sizeof(Vdbe) );
++  if( p==0 ) return 0;
++  p->db = db;
++  if( db->pVdbe ){
++    db->pVdbe->pPrev = p;
++  }
++  p->pNext = db->pVdbe;
++  p->pPrev = 0;
++  db->pVdbe = p;
++  p->magic = VDBE_MAGIC_INIT;
++  return p;
++}
++
++/*
++** Turn tracing on or off
++*/
++void sqliteVdbeTrace(Vdbe *p, FILE *trace){
++  p->trace = trace;
++}
++
++/*
++** Add a new instruction to the list of instructions current in the
++** VDBE.  Return the address of the new instruction.
++**
++** Parameters:
++**
++**    p               Pointer to the VDBE
++**
++**    op              The opcode for this instruction
++**
++**    p1, p2          First two of the three possible operands.
++**
++** Use the sqliteVdbeResolveLabel() function to fix an address and
++** the sqliteVdbeChangeP3() function to change the value of the P3
++** operand.
++*/
++int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2){
++  int i;
++  VdbeOp *pOp;
++
++  i = p->nOp;
++  p->nOp++;
++  assert( p->magic==VDBE_MAGIC_INIT );
++  if( i>=p->nOpAlloc ){
++    int oldSize = p->nOpAlloc;
++    Op *aNew;
++    p->nOpAlloc = p->nOpAlloc*2 + 100;
++    aNew = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op));
++    if( aNew==0 ){
++      p->nOpAlloc = oldSize;
++      return 0;
++    }
++    p->aOp = aNew;
++    memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op));
++  }
++  pOp = &p->aOp[i];
++  pOp->opcode = op;
++  pOp->p1 = p1;
++  if( p2<0 && (-1-p2)<p->nLabel && p->aLabel[-1-p2]>=0 ){
++    p2 = p->aLabel[-1-p2];
++  }
++  pOp->p2 = p2;
++  pOp->p3 = 0;
++  pOp->p3type = P3_NOTUSED;
++#ifndef NDEBUG
++  if( sqlite_vdbe_addop_trace ) sqliteVdbePrintOp(0, i, &p->aOp[i]);
++#endif
++  return i;
++}
++
++/*
++** Add an opcode that includes the p3 value.
++*/
++int sqliteVdbeOp3(Vdbe *p, int op, int p1, int p2, const char *zP3, int p3type){
++  int addr = sqliteVdbeAddOp(p, op, p1, p2);
++  sqliteVdbeChangeP3(p, addr, zP3, p3type);
++  return addr;
++}
++
++/*
++** Add multiple opcodes.  The list is terminated by an opcode of 0.
++*/
++int sqliteVdbeCode(Vdbe *p, ...){
++  int addr;
++  va_list ap;
++  int opcode, p1, p2;
++  va_start(ap, p);
++  addr = p->nOp;
++  while( (opcode = va_arg(ap,int))!=0 ){
++    p1 = va_arg(ap,int);
++    p2 = va_arg(ap,int);
++    sqliteVdbeAddOp(p, opcode, p1, p2);
++  }
++  va_end(ap);
++  return addr;
++}
++
++
++
++/*
++** Create a new symbolic label for an instruction that has yet to be
++** coded.  The symbolic label is really just a negative number.  The
++** label can be used as the P2 value of an operation.  Later, when
++** the label is resolved to a specific address, the VDBE will scan
++** through its operation list and change all values of P2 which match
++** the label into the resolved address.
++**
++** The VDBE knows that a P2 value is a label because labels are
++** always negative and P2 values are suppose to be non-negative.
++** Hence, a negative P2 value is a label that has yet to be resolved.
++*/
++int sqliteVdbeMakeLabel(Vdbe *p){
++  int i;
++  i = p->nLabel++;
++  assert( p->magic==VDBE_MAGIC_INIT );
++  if( i>=p->nLabelAlloc ){
++    int *aNew;
++    p->nLabelAlloc = p->nLabelAlloc*2 + 10;
++    aNew = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0]));
++    if( aNew==0 ){
++      sqliteFree(p->aLabel);
++    }
++    p->aLabel = aNew;
++  }
++  if( p->aLabel==0 ){
++    p->nLabel = 0;
++    p->nLabelAlloc = 0;
++    return 0;
++  }
++  p->aLabel[i] = -1;
++  return -1-i;
++}
++
++/*
++** Resolve label "x" to be the address of the next instruction to
++** be inserted.  The parameter "x" must have been obtained from
++** a prior call to sqliteVdbeMakeLabel().
++*/
++void sqliteVdbeResolveLabel(Vdbe *p, int x){
++  int j;
++  assert( p->magic==VDBE_MAGIC_INIT );
++  if( x<0 && (-x)<=p->nLabel && p->aOp ){
++    if( p->aLabel[-1-x]==p->nOp ) return;
++    assert( p->aLabel[-1-x]<0 );
++    p->aLabel[-1-x] = p->nOp;
++    for(j=0; j<p->nOp; j++){
++      if( p->aOp[j].p2==x ) p->aOp[j].p2 = p->nOp;
++    }
++  }
++}
++
++/*
++** Return the address of the next instruction to be inserted.
++*/
++int sqliteVdbeCurrentAddr(Vdbe *p){
++  assert( p->magic==VDBE_MAGIC_INIT );
++  return p->nOp;
++}
++
++/*
++** Add a whole list of operations to the operation stack.  Return the
++** address of the first operation added.
++*/
++int sqliteVdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
++  int addr;
++  assert( p->magic==VDBE_MAGIC_INIT );
++  if( p->nOp + nOp >= p->nOpAlloc ){
++    int oldSize = p->nOpAlloc;
++    Op *aNew;
++    p->nOpAlloc = p->nOpAlloc*2 + nOp + 10;
++    aNew = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op));
++    if( aNew==0 ){
++      p->nOpAlloc = oldSize;
++      return 0;
++    }
++    p->aOp = aNew;
++    memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op));
++  }
++  addr = p->nOp;
++  if( nOp>0 ){
++    int i;
++    VdbeOpList const *pIn = aOp;
++    for(i=0; i<nOp; i++, pIn++){
++      int p2 = pIn->p2;
++      VdbeOp *pOut = &p->aOp[i+addr];
++      pOut->opcode = pIn->opcode;
++      pOut->p1 = pIn->p1;
++      pOut->p2 = p2<0 ? addr + ADDR(p2) : p2;
++      pOut->p3 = pIn->p3;
++      pOut->p3type = pIn->p3 ? P3_STATIC : P3_NOTUSED;
++#ifndef NDEBUG
++      if( sqlite_vdbe_addop_trace ){
++        sqliteVdbePrintOp(0, i+addr, &p->aOp[i+addr]);
++      }
++#endif
++    }
++    p->nOp += nOp;
++  }
++  return addr;
++}
++
++/*
++** Change the value of the P1 operand for a specific instruction.
++** This routine is useful when a large program is loaded from a
++** static array using sqliteVdbeAddOpList but we want to make a
++** few minor changes to the program.
++*/
++void sqliteVdbeChangeP1(Vdbe *p, int addr, int val){
++  assert( p->magic==VDBE_MAGIC_INIT );
++  if( p && addr>=0 && p->nOp>addr && p->aOp ){
++    p->aOp[addr].p1 = val;
++  }
++}
++
++/*
++** Change the value of the P2 operand for a specific instruction.
++** This routine is useful for setting a jump destination.
++*/
++void sqliteVdbeChangeP2(Vdbe *p, int addr, int val){
++  assert( val>=0 );
++  assert( p->magic==VDBE_MAGIC_INIT );
++  if( p && addr>=0 && p->nOp>addr && p->aOp ){
++    p->aOp[addr].p2 = val;
++  }
++}
++
++/*
++** Change the value of the P3 operand for a specific instruction.
++** This routine is useful when a large program is loaded from a
++** static array using sqliteVdbeAddOpList 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==P3_STATIC  it means that zP3 is a pointer to a constant static
++** string and we can just copy the pointer.  n==P3_POINTER means zP3 is
++** a pointer to some object other than a string.
++**
++** If addr<0 then change P3 on the most recently inserted instruction.
++*/
++void sqliteVdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
++  Op *pOp;
++  assert( p->magic==VDBE_MAGIC_INIT );
++  if( p==0 || p->aOp==0 ) return;
++  if( addr<0 || addr>=p->nOp ){
++    addr = p->nOp - 1;
++    if( addr<0 ) return;
++  }
++  pOp = &p->aOp[addr];
++  if( pOp->p3 && pOp->p3type==P3_DYNAMIC ){
++    sqliteFree(pOp->p3);
++    pOp->p3 = 0;
++  }
++  if( zP3==0 ){
++    pOp->p3 = 0;
++    pOp->p3type = P3_NOTUSED;
++  }else if( n<0 ){
++    pOp->p3 = (char*)zP3;
++    pOp->p3type = n;
++  }else{
++    sqliteSetNString(&pOp->p3, zP3, n, 0);
++    pOp->p3type = P3_DYNAMIC;
++  }
++}
++
++/*
++** If the P3 operand to the specified instruction appears
++** to be a quoted string token, then this procedure removes 
++** the quotes.
++**
++** The quoting operator can be either a grave ascent (ASCII 0x27)
++** or a double quote character (ASCII 0x22).  Two quotes in a row
++** resolve to be a single actual quote character within the string.
++*/
++void sqliteVdbeDequoteP3(Vdbe *p, int addr){
++  Op *pOp;
++  assert( p->magic==VDBE_MAGIC_INIT );
++  if( p->aOp==0 ) return;
++  if( addr<0 || addr>=p->nOp ){
++    addr = p->nOp - 1;
++    if( addr<0 ) return;
++  }
++  pOp = &p->aOp[addr];
++  if( pOp->p3==0 || pOp->p3[0]==0 ) return;
++  if( pOp->p3type==P3_POINTER ) return;
++  if( pOp->p3type!=P3_DYNAMIC ){
++    pOp->p3 = sqliteStrDup(pOp->p3);
++    pOp->p3type = P3_DYNAMIC;
++  }
++  sqliteDequote(pOp->p3);
++}
++
++/*
++** On the P3 argument of the given instruction, change all
++** strings of whitespace characters into a single space and
++** delete leading and trailing whitespace.
++*/
++void sqliteVdbeCompressSpace(Vdbe *p, int addr){
++  unsigned char *z;
++  int i, j;
++  Op *pOp;
++  assert( p->magic==VDBE_MAGIC_INIT );
++  if( p->aOp==0 || addr<0 || addr>=p->nOp ) return;
++  pOp = &p->aOp[addr];
++  if( pOp->p3type==P3_POINTER ){
++    return;
++  }
++  if( pOp->p3type!=P3_DYNAMIC ){
++    pOp->p3 = sqliteStrDup(pOp->p3);
++    pOp->p3type = P3_DYNAMIC;
++  }
++  z = (unsigned char*)pOp->p3;
++  if( z==0 ) return;
++  i = j = 0;
++  while( isspace(z[i]) ){ i++; }
++  while( z[i] ){
++    if( isspace(z[i]) ){
++      z[j++] = ' ';
++      while( isspace(z[++i]) ){}
++    }else{
++      z[j++] = z[i++];
++    }
++  }
++  while( j>0 && isspace(z[j-1]) ){ j--; }
++  z[j] = 0;
++}
++
++/*
++** Search for the current program for the given opcode and P2
++** value.  Return the address plus 1 if found and 0 if not found.
++*/
++int sqliteVdbeFindOp(Vdbe *p, int op, int p2){
++  int i;
++  assert( p->magic==VDBE_MAGIC_INIT );
++  for(i=0; i<p->nOp; i++){
++    if( p->aOp[i].opcode==op && p->aOp[i].p2==p2 ) return i+1;
++  }
++  return 0;
++}
++
++/*
++** Return the opcode for a given address.
++*/
++VdbeOp *sqliteVdbeGetOp(Vdbe *p, int addr){
++  assert( p->magic==VDBE_MAGIC_INIT );
++  assert( addr>=0 && addr<p->nOp );
++  return &p->aOp[addr];
++}
++
++/*
++** The following group or routines are employed by installable functions
++** to return their results.
++**
++** The sqlite_set_result_string() routine can be used to return a string
++** value or to return a NULL.  To return a NULL, pass in NULL for zResult.
++** A copy is made of the string before this routine returns so it is safe
++** to pass in an ephemeral string.
++**
++** sqlite_set_result_error() works like sqlite_set_result_string() except
++** that it signals a fatal error.  The string argument, if any, is the
++** error message.  If the argument is NULL a generic substitute error message
++** is used.
++**
++** The sqlite_set_result_int() and sqlite_set_result_double() set the return
++** value of the user function to an integer or a double.
++**
++** These routines are defined here in vdbe.c because they depend on knowing
++** the internals of the sqlite_func structure which is only defined in 
++** this source file.
++*/
++char *sqlite_set_result_string(sqlite_func *p, const char *zResult, int n){
++  assert( !p->isStep );
++  if( p->s.flags & MEM_Dyn ){
++    sqliteFree(p->s.z);
++  }
++  if( zResult==0 ){
++    p->s.flags = MEM_Null;
++    n = 0;
++    p->s.z = 0;
++    p->s.n = 0;
++  }else{
++    if( n<0 ) n = strlen(zResult);
++    if( n<NBFS-1 ){
++      memcpy(p->s.zShort, zResult, n);
++      p->s.zShort[n] = 0;
++      p->s.flags = MEM_Str | MEM_Short;
++      p->s.z = p->s.zShort;
++    }else{
++      p->s.z = sqliteMallocRaw( n+1 );
++      if( p->s.z ){
++        memcpy(p->s.z, zResult, n);
++        p->s.z[n] = 0;
++      }
++      p->s.flags = MEM_Str | MEM_Dyn;
++    }
++    p->s.n = n+1;
++  }
++  return p->s.z;
++}
++void sqlite_set_result_int(sqlite_func *p, int iResult){
++  assert( !p->isStep );
++  if( p->s.flags & MEM_Dyn ){
++    sqliteFree(p->s.z);
++  }
++  p->s.i = iResult;
++  p->s.flags = MEM_Int;
++}
++void sqlite_set_result_double(sqlite_func *p, double rResult){
++  assert( !p->isStep );
++  if( p->s.flags & MEM_Dyn ){
++    sqliteFree(p->s.z);
++  }
++  p->s.r = rResult;
++  p->s.flags = MEM_Real;
++}
++void sqlite_set_result_error(sqlite_func *p, const char *zMsg, int n){
++  assert( !p->isStep );
++  sqlite_set_result_string(p, zMsg, n);
++  p->isError = 1;
++}
++
++/*
++** Extract the user data from a sqlite_func structure and return a
++** pointer to it.
++*/
++void *sqlite_user_data(sqlite_func *p){
++  assert( p && p->pFunc );
++  return p->pFunc->pUserData;
++}
++
++/*
++** 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.
++**
++** This routine is defined here in vdbe.c because it depends on knowing
++** the internals of the sqlite_func structure which is only defined in
++** this source file.
++*/
++void *sqlite_aggregate_context(sqlite_func *p, int nByte){
++  assert( p && p->pFunc && p->pFunc->xStep );
++  if( p->pAgg==0 ){
++    if( nByte<=NBFS ){
++      p->pAgg = (void*)p->s.z;
++      memset(p->pAgg, 0, nByte);
++    }else{
++      p->pAgg = sqliteMalloc( nByte );
++    }
++  }
++  return p->pAgg;
++}
++
++/*
++** Return the number of times the Step function of a aggregate has been 
++** called.
++**
++** This routine is defined here in vdbe.c because it depends on knowing
++** the internals of the sqlite_func structure which is only defined in
++** this source file.
++*/
++int sqlite_aggregate_count(sqlite_func *p){
++  assert( p && p->pFunc && p->pFunc->xStep );
++  return p->cnt;
++}
++
++#if !defined(NDEBUG) || defined(VDBE_PROFILE)
++/*
++** Print a single opcode.  This routine is used for debugging only.
++*/
++void sqliteVdbePrintOp(FILE *pOut, int pc, Op *pOp){
++  char *zP3;
++  char zPtr[40];
++  if( pOp->p3type==P3_POINTER ){
++    sprintf(zPtr, "ptr(%#lx)", (long)pOp->p3);
++    zP3 = zPtr;
++  }else{
++    zP3 = pOp->p3;
++  }
++  if( pOut==0 ) pOut = stdout;
++  fprintf(pOut,"%4d %-12s %4d %4d %s\n",
++      pc, sqliteOpcodeNames[pOp->opcode], pOp->p1, pOp->p2, zP3 ? zP3 : "");
++  fflush(pOut);
++}
++#endif
++
++/*
++** Give a listing of the program in the virtual machine.
++**
++** The interface is the same as sqliteVdbeExec().  But instead of
++** running the code, it invokes the callback once for each instruction.
++** This feature is used to implement "EXPLAIN".
++*/
++int sqliteVdbeList(
++  Vdbe *p                   /* The VDBE */
++){
++  sqlite *db = p->db;
++  int i;
++  int rc = SQLITE_OK;
++  static char *azColumnNames[] = {
++     "addr", "opcode", "p1",  "p2",  "p3", 
++     "int",  "text",   "int", "int", "text",
++     0
++  };
++
++  assert( p->popStack==0 );
++  assert( p->explain );
++  p->azColName = azColumnNames;
++  p->azResColumn = p->zArgv;
++  for(i=0; i<5; i++) p->zArgv[i] = p->aStack[i].zShort;
++  i = p->pc;
++  if( i>=p->nOp ){
++    p->rc = SQLITE_OK;
++    rc = SQLITE_DONE;
++  }else if( db->flags & SQLITE_Interrupt ){
++    db->flags &= ~SQLITE_Interrupt;
++    if( db->magic!=SQLITE_MAGIC_BUSY ){
++      p->rc = SQLITE_MISUSE;
++    }else{
++      p->rc = SQLITE_INTERRUPT;
++    }
++    rc = SQLITE_ERROR;
++    sqliteSetString(&p->zErrMsg, sqlite_error_string(p->rc), (char*)0);
++  }else{
++    sprintf(p->zArgv[0],"%d",i);
++    sprintf(p->zArgv[2],"%d", p->aOp[i].p1);
++    sprintf(p->zArgv[3],"%d", p->aOp[i].p2);
++    if( p->aOp[i].p3type==P3_POINTER ){
++      sprintf(p->aStack[4].zShort, "ptr(%#lx)", (long)p->aOp[i].p3);
++      p->zArgv[4] = p->aStack[4].zShort;
++    }else{
++      p->zArgv[4] = p->aOp[i].p3;
++    }
++    p->zArgv[1] = sqliteOpcodeNames[p->aOp[i].opcode];
++    p->pc = i+1;
++    p->azResColumn = p->zArgv;
++    p->nResColumn = 5;
++    p->rc = SQLITE_OK;
++    rc = SQLITE_ROW;
++  }
++  return rc;
++}
++
++/*
++** Prepare a virtual machine for execution.  This involves things such
++** as allocating stack space and initializing the program counter.
++** After the VDBE has be prepped, it can be executed by one or more
++** calls to sqliteVdbeExec().  
++*/
++void sqliteVdbeMakeReady(
++  Vdbe *p,                       /* The VDBE */
++  int nVar,                      /* Number of '?' see in the SQL statement */
++  int isExplain                  /* True if the EXPLAIN keywords is present */
++){
++  int n;
++
++  assert( p!=0 );
++  assert( p->magic==VDBE_MAGIC_INIT );
++
++  /* Add a HALT instruction to the very end of the program.
++  */
++  if( p->nOp==0 || (p->aOp && p->aOp[p->nOp-1].opcode!=OP_Halt) ){
++    sqliteVdbeAddOp(p, OP_Halt, 0, 0);
++  }
++
++  /* 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.
++  **
++  ** Allocation all the stack space we will ever need.
++  */
++  if( p->aStack==0 ){
++    p->nVar = nVar;
++    assert( nVar>=0 );
++    n = isExplain ? 10 : p->nOp;
++    p->aStack = sqliteMalloc(
++      n*(sizeof(p->aStack[0]) + 2*sizeof(char*))     /* aStack and zArgv */
++        + p->nVar*(sizeof(char*)+sizeof(int)+1)    /* azVar, anVar, abVar */
++    );
++    p->zArgv = (char**)&p->aStack[n];
++    p->azColName = (char**)&p->zArgv[n];
++    p->azVar = (char**)&p->azColName[n];
++    p->anVar = (int*)&p->azVar[p->nVar];
++    p->abVar = (u8*)&p->anVar[p->nVar];
++  }
++
++  sqliteHashInit(&p->agg.hash, SQLITE_HASH_BINARY, 0);
++  p->agg.pSearch = 0;
++#ifdef MEMORY_DEBUG
++  if( sqliteOsFileExists("vdbe_trace") ){
++    p->trace = stdout;
++  }
++#endif
++  p->pTos = &p->aStack[-1];
++  p->pc = 0;
++  p->rc = SQLITE_OK;
++  p->uniqueCnt = 0;
++  p->returnDepth = 0;
++  p->errorAction = OE_Abort;
++  p->undoTransOnError = 0;
++  p->popStack =  0;
++  p->explain |= isExplain;
++  p->magic = VDBE_MAGIC_RUN;
++#ifdef VDBE_PROFILE
++  {
++    int i;
++    for(i=0; i<p->nOp; i++){
++      p->aOp[i].cnt = 0;
++      p->aOp[i].cycles = 0;
++    }
++  }
++#endif
++}
++
++
++/*
++** Remove any elements that remain on the sorter for the VDBE given.
++*/
++void sqliteVdbeSorterReset(Vdbe *p){
++  while( p->pSort ){
++    Sorter *pSorter = p->pSort;
++    p->pSort = pSorter->pNext;
++    sqliteFree(pSorter->zKey);
++    sqliteFree(pSorter->pData);
++    sqliteFree(pSorter);
++  }
++}
++
++/*
++** Reset an Agg structure.  Delete all its contents. 
++**
++** For installable aggregate functions, if the step function has been
++** called, make sure the finalizer function has also been called.  The
++** finalizer might need to free memory that was allocated as part of its
++** private context.  If the finalizer has not been called yet, call it
++** now.
++*/
++void sqliteVdbeAggReset(Agg *pAgg){
++  int i;
++  HashElem *p;
++  for(p = sqliteHashFirst(&pAgg->hash); p; p = sqliteHashNext(p)){
++    AggElem *pElem = sqliteHashData(p);
++    assert( pAgg->apFunc!=0 );
++    for(i=0; i<pAgg->nMem; i++){
++      Mem *pMem = &pElem->aMem[i];
++      if( pAgg->apFunc[i] && (pMem->flags & MEM_AggCtx)!=0 ){
++        sqlite_func ctx;
++        ctx.pFunc = pAgg->apFunc[i];
++        ctx.s.flags = MEM_Null;
++        ctx.pAgg = pMem->z;
++        ctx.cnt = pMem->i;
++        ctx.isStep = 0;
++        ctx.isError = 0;
++        (*pAgg->apFunc[i]->xFinalize)(&ctx);
++        if( pMem->z!=0 && pMem->z!=pMem->zShort ){
++          sqliteFree(pMem->z);
++        }
++        if( ctx.s.flags & MEM_Dyn ){
++          sqliteFree(ctx.s.z);
++        }
++      }else if( pMem->flags & MEM_Dyn ){
++        sqliteFree(pMem->z);
++      }
++    }
++    sqliteFree(pElem);
++  }
++  sqliteHashClear(&pAgg->hash);
++  sqliteFree(pAgg->apFunc);
++  pAgg->apFunc = 0;
++  pAgg->pCurrent = 0;
++  pAgg->pSearch = 0;
++  pAgg->nMem = 0;
++}
++
++/*
++** Delete a keylist
++*/
++void sqliteVdbeKeylistFree(Keylist *p){
++  while( p ){
++    Keylist *pNext = p->pNext;
++    sqliteFree(p);
++    p = pNext;
++  }
++}
++
++/*
++** Close a cursor and release all the resources that cursor happens
++** to hold.
++*/
++void sqliteVdbeCleanupCursor(Cursor *pCx){
++  if( pCx->pCursor ){
++    sqliteBtreeCloseCursor(pCx->pCursor);
++  }
++  if( pCx->pBt ){
++    sqliteBtreeClose(pCx->pBt);
++  }
++  sqliteFree(pCx->pData);
++  memset(pCx, 0, sizeof(Cursor));
++}
++
++/*
++** Close all cursors
++*/
++static void closeAllCursors(Vdbe *p){
++  int i;
++  for(i=0; i<p->nCursor; i++){
++    sqliteVdbeCleanupCursor(&p->aCsr[i]);
++  }
++  sqliteFree(p->aCsr);
++  p->aCsr = 0;
++  p->nCursor = 0;
++}
++
++/*
++** Clean up the VM after execution.
++**
++** This routine will automatically close any cursors, lists, and/or
++** sorters that were left open.  It also deletes the values of
++** variables in the azVariable[] array.
++*/
++static void Cleanup(Vdbe *p){
++  int i;
++  if( p->aStack ){
++    Mem *pTos = p->pTos;
++    while( pTos>=p->aStack ){
++      if( pTos->flags & MEM_Dyn ){
++        sqliteFree(pTos->z);
++      }
++      pTos--;
++    }
++    p->pTos = pTos;
++  }
++  closeAllCursors(p);
++  if( p->aMem ){
++    for(i=0; i<p->nMem; i++){
++      if( p->aMem[i].flags & MEM_Dyn ){
++        sqliteFree(p->aMem[i].z);
++      }
++    }
++  }
++  sqliteFree(p->aMem);
++  p->aMem = 0;
++  p->nMem = 0;
++  if( p->pList ){
++    sqliteVdbeKeylistFree(p->pList);
++    p->pList = 0;
++  }
++  sqliteVdbeSorterReset(p);
++  if( p->pFile ){
++    if( p->pFile!=stdin ) fclose(p->pFile);
++    p->pFile = 0;
++  }
++  if( p->azField ){
++    sqliteFree(p->azField);
++    p->azField = 0;
++  }
++  p->nField = 0;
++  if( p->zLine ){
++    sqliteFree(p->zLine);
++    p->zLine = 0;
++  }
++  p->nLineAlloc = 0;
++  sqliteVdbeAggReset(&p->agg);
++  if( p->aSet ){
++    for(i=0; i<p->nSet; i++){
++      sqliteHashClear(&p->aSet[i].hash);
++    }
++  }
++  sqliteFree(p->aSet);
++  p->aSet = 0;
++  p->nSet = 0;
++  if( p->keylistStack ){
++    int ii;
++    for(ii = 0; ii < p->keylistStackDepth; ii++){
++      sqliteVdbeKeylistFree(p->keylistStack[ii]);
++    }
++    sqliteFree(p->keylistStack);
++    p->keylistStackDepth = 0;
++    p->keylistStack = 0;
++  }
++  sqliteFree(p->contextStack);
++  p->contextStack = 0;
++  sqliteFree(p->zErrMsg);
++  p->zErrMsg = 0;
++}
++
++/*
++** Clean up a VDBE after execution but do not delete the VDBE just yet.
++** Write any error messages into *pzErrMsg.  Return the result code.
++**
++** After this routine is run, the VDBE should be ready to be executed
++** again.
++*/
++int sqliteVdbeReset(Vdbe *p, char **pzErrMsg){
++  sqlite *db = p->db;
++  int i;
++
++  if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
++    sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), (char*)0);
++    return SQLITE_MISUSE;
++  }
++  if( p->zErrMsg ){
++    if( pzErrMsg && *pzErrMsg==0 ){
++      *pzErrMsg = p->zErrMsg;
++    }else{
++      sqliteFree(p->zErrMsg);
++    }
++    p->zErrMsg = 0;
++  }else if( p->rc ){
++    sqliteSetString(pzErrMsg, sqlite_error_string(p->rc), (char*)0);
++  }
++  Cleanup(p);
++  if( p->rc!=SQLITE_OK ){
++    switch( p->errorAction ){
++      case OE_Abort: {
++        if( !p->undoTransOnError ){
++          for(i=0; i<db->nDb; i++){
++            if( db->aDb[i].pBt ){
++              sqliteBtreeRollbackCkpt(db->aDb[i].pBt);
++            }
++          }
++          break;
++        }
++        /* Fall through to ROLLBACK */
++      }
++      case OE_Rollback: {
++        sqliteRollbackAll(db);
++        db->flags &= ~SQLITE_InTrans;
++        db->onError = OE_Default;
++        break;
++      }
++      default: {
++        if( p->undoTransOnError ){
++          sqliteRollbackAll(db);
++          db->flags &= ~SQLITE_InTrans;
++          db->onError = OE_Default;
++        }
++        break;
++      }
++    }
++    sqliteRollbackInternalChanges(db);
++  }
++  for(i=0; i<db->nDb; i++){
++    if( db->aDb[i].pBt && db->aDb[i].inTrans==2 ){
++      sqliteBtreeCommitCkpt(db->aDb[i].pBt);
++      db->aDb[i].inTrans = 1;
++    }
++  }
++  assert( p->pTos<&p->aStack[p->pc] || sqlite_malloc_failed==1 );
++#ifdef VDBE_PROFILE
++  {
++    FILE *out = fopen("vdbe_profile.out", "a");
++    if( out ){
++      int i;
++      fprintf(out, "---- ");
++      for(i=0; i<p->nOp; i++){
++        fprintf(out, "%02x", p->aOp[i].opcode);
++      }
++      fprintf(out, "\n");
++      for(i=0; i<p->nOp; i++){
++        fprintf(out, "%6d %10lld %8lld ",
++           p->aOp[i].cnt,
++           p->aOp[i].cycles,
++           p->aOp[i].cnt>0 ? p->aOp[i].cycles/p->aOp[i].cnt : 0
++        );
++        sqliteVdbePrintOp(out, i, &p->aOp[i]);
++      }
++      fclose(out);
++    }
++  }
++#endif
++  p->magic = VDBE_MAGIC_INIT;
++  return p->rc;
++}
++
++/*
++** Clean up and delete a VDBE after execution.  Return an integer which is
++** the result code.  Write any error message text into *pzErrMsg.
++*/
++int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){
++  int rc;
++  sqlite *db;
++
++  if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
++    sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), (char*)0);
++    return SQLITE_MISUSE;
++  }
++  db = p->db;
++  rc = sqliteVdbeReset(p, pzErrMsg);
++  sqliteVdbeDelete(p);
++  if( db->want_to_close && db->pVdbe==0 ){
++    sqlite_close(db);
++  }
++  if( rc==SQLITE_SCHEMA ){
++    sqliteResetInternalSchema(db, 0);
++  }
++  return rc;
++}
++
++/*
++** Set the values of all variables.  Variable $1 in the original SQL will
++** be the string azValue[0].  $2 will have the value azValue[1].  And
++** so forth.  If a value is out of range (for example $3 when nValue==2)
++** then its value will be NULL.
++**
++** This routine overrides any prior call.
++*/
++int sqlite_bind(sqlite_vm *pVm, int i, const char *zVal, int len, int copy){
++  Vdbe *p = (Vdbe*)pVm;
++  if( p->magic!=VDBE_MAGIC_RUN || p->pc!=0 ){
++    return SQLITE_MISUSE;
++  }
++  if( i<1 || i>p->nVar ){
++    return SQLITE_RANGE;
++  }
++  i--;
++  if( p->abVar[i] ){
++    sqliteFree(p->azVar[i]);
++  }
++  if( zVal==0 ){
++    copy = 0;
++    len = 0;
++  }
++  if( len<0 ){
++    len = strlen(zVal)+1;
++  }
++  if( copy ){
++    p->azVar[i] = sqliteMalloc( len );
++    if( p->azVar[i] ) memcpy(p->azVar[i], zVal, len);
++  }else{
++    p->azVar[i] = (char*)zVal;
++  }
++  p->abVar[i] = copy;
++  p->anVar[i] = len;
++  return SQLITE_OK;
++}
++
++
++/*
++** Delete an entire VDBE.
++*/
++void sqliteVdbeDelete(Vdbe *p){
++  int i;
++  if( p==0 ) return;
++  Cleanup(p);
++  if( p->pPrev ){
++    p->pPrev->pNext = p->pNext;
++  }else{
++    assert( p->db->pVdbe==p );
++    p->db->pVdbe = p->pNext;
++  }
++  if( p->pNext ){
++    p->pNext->pPrev = p->pPrev;
++  }
++  p->pPrev = p->pNext = 0;
++  if( p->nOpAlloc==0 ){
++    p->aOp = 0;
++    p->nOp = 0;
++  }
++  for(i=0; i<p->nOp; i++){
++    if( p->aOp[i].p3type==P3_DYNAMIC ){
++      sqliteFree(p->aOp[i].p3);
++    }
++  }
++  for(i=0; i<p->nVar; i++){
++    if( p->abVar[i] ) sqliteFree(p->azVar[i]);
++  }
++  sqliteFree(p->aOp);
++  sqliteFree(p->aLabel);
++  sqliteFree(p->aStack);
++  p->magic = VDBE_MAGIC_DEAD;
++  sqliteFree(p);
++}
++
++/*
++** Convert an integer in between the native integer format and
++** the bigEndian format used as the record number for tables.
++**
++** The bigEndian format (most significant byte first) is used for
++** record numbers so that records will sort into the correct order
++** even though memcmp() is used to compare the keys.  On machines
++** whose native integer format is little endian (ex: i486) the
++** order of bytes is reversed.  On native big-endian machines
++** (ex: Alpha, Sparc, Motorola) the byte order is the same.
++**
++** This function is its own inverse.  In other words
++**
++**         X == byteSwap(byteSwap(X))
++*/
++int sqliteVdbeByteSwap(int x){
++  union {
++     char zBuf[sizeof(int)];
++     int i;
++  } ux;
++  ux.zBuf[3] = x&0xff;
++  ux.zBuf[2] = (x>>8)&0xff;
++  ux.zBuf[1] = (x>>16)&0xff;
++  ux.zBuf[0] = (x>>24)&0xff;
++  return ux.i;
++}
++
++/*
++** If a MoveTo operation is pending on the given cursor, then do that
++** MoveTo now.  Return an error code.  If no MoveTo is pending, this
++** routine does nothing and returns SQLITE_OK.
++*/
++int sqliteVdbeCursorMoveto(Cursor *p){
++  if( p->deferredMoveto ){
++    int res;
++    extern int sqlite_search_count;
++    sqliteBtreeMoveto(p->pCursor, (char*)&p->movetoTarget, sizeof(int), &res);
++    p->lastRecno = keyToInt(p->movetoTarget);
++    p->recnoIsValid = res==0;
++    if( res<0 ){
++      sqliteBtreeNext(p->pCursor, &res);
++    }
++    sqlite_search_count++;
++    p->deferredMoveto = 0;
++  }
++  return SQLITE_OK;
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/vdbe.c
+@@ -0,0 +1,4921 @@
++/*
++** 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.
++**
++*************************************************************************
++** The code in this file implements execution method of the 
++** Virtual Database Engine (VDBE).  A separate file ("vdbeaux.c")
++** handles housekeeping details such as creating and deleting
++** VDBE instances.  This file is solely interested in executing
++** the VDBE program.
++**
++** In the external interface, an "sqlite_vm*" is an opaque pointer
++** to a VDBE.
++**
++** The SQL parser generates a program which is then executed by
++** 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.
++**
++** Computation results are stored on a stack.  Each entry on the
++** stack is 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.
++** 
++** Most of the code in this file is taken up by the sqliteVdbeExec()
++** function which does the work of interpreting a VDBE program.
++** But other routines are also provided to help in building up
++** a program instruction by instruction.
++**
++** Various scripts scan this source file in order to generate HTML
++** documentation, headers files, or other derived files.  The formatting
++** of the code in this file is, therefore, important.  See other comments
++** in this file for details.  If in doubt, do not deviate from existing
++** commenting and indentation practices when changing or adding code.
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++#include "os.h"
++#include <ctype.h>
++#include "vdbeInt.h"
++
++/*
++** The following global variable is incremented every time a cursor
++** moves, either by the OP_MoveTo or the OP_Next opcode.  The test
++** procedures use this information to make sure that indices are
++** working correctly.  This variable has no function other than to
++** help verify the correct operation of the library.
++*/
++int sqlite_search_count = 0;
++
++/*
++** When this global variable is positive, it gets decremented once before
++** each instruction in the VDBE.  When reaches zero, the SQLITE_Interrupt
++** of the db.flags field is set in order to simulate an interrupt.
++**
++** This facility is used for testing purposes only.  It does not function
++** in an ordinary build.
++*/
++int sqlite_interrupt_count = 0;
++
++/*
++** Advance the virtual machine to the next output row.
++**
++** The return vale will be either SQLITE_BUSY, SQLITE_DONE, 
++** SQLITE_ROW, SQLITE_ERROR, or SQLITE_MISUSE.
++**
++** SQLITE_BUSY means that the virtual machine attempted to open
++** a locked database and there is no busy callback registered.
++** Call sqlite_step() again to retry the open.  *pN is set to 0
++** and *pazColName and *pazValue are both set to NULL.
++**
++** SQLITE_DONE means that the virtual machine has finished
++** executing.  sqlite_step() should not be called again on this
++** virtual machine.  *pN and *pazColName are set appropriately
++** but *pazValue is set to NULL.
++**
++** SQLITE_ROW means that the virtual machine has generated another
++** row of the result set.  *pN is set to the number of columns in
++** the row.  *pazColName is set to the names of the columns followed
++** by the column datatypes.  *pazValue is set to the values of each
++** column in the row.  The value of the i-th column is (*pazValue)[i].
++** The name of the i-th column is (*pazColName)[i] and the datatype
++** of the i-th column is (*pazColName)[i+*pN].
++**
++** SQLITE_ERROR means that a run-time error (such as a constraint
++** violation) has occurred.  The details of the error will be returned
++** by the next call to sqlite_finalize().  sqlite_step() should not
++** be called again on the VM.
++**
++** 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.
++*/
++int sqlite_step(
++  sqlite_vm *pVm,              /* The virtual machine to execute */
++  int *pN,                     /* OUT: Number of columns in result */
++  const char ***pazValue,      /* OUT: Column data */
++  const char ***pazColName     /* OUT: Column names and datatypes */
++){
++  Vdbe *p = (Vdbe*)pVm;
++  sqlite *db;
++  int rc;
++
++  if( !p || p->magic!=VDBE_MAGIC_RUN ){
++    return SQLITE_MISUSE;
++  }
++  db = p->db;
++  if( sqliteSafetyOn(db) ){
++    p->rc = SQLITE_MISUSE;
++    return SQLITE_MISUSE;
++  }
++  if( p->explain ){
++    rc = sqliteVdbeList(p);
++  }else{
++    rc = sqliteVdbeExec(p);
++  }
++  if( rc==SQLITE_DONE || rc==SQLITE_ROW ){
++    if( pazColName ) *pazColName = (const char**)p->azColName;
++    if( pN ) *pN = p->nResColumn;
++  }else{
++    if( pazColName) *pazColName = 0;
++    if( pN ) *pN = 0;
++  }
++  if( pazValue ){
++    if( rc==SQLITE_ROW ){
++      *pazValue = (const char**)p->azResColumn;
++    }else{
++      *pazValue = 0;
++    }
++  }
++  if( sqliteSafetyOff(db) ){
++    return SQLITE_MISUSE;
++  }
++  return rc;
++}
++
++/*
++** Insert a new aggregate element and make it the element that
++** has focus.
++**
++** Return 0 on success and 1 if memory is exhausted.
++*/
++static int AggInsert(Agg *p, char *zKey, int nKey){
++  AggElem *pElem, *pOld;
++  int i;
++  Mem *pMem;
++  pElem = sqliteMalloc( sizeof(AggElem) + nKey +
++                        (p->nMem-1)*sizeof(pElem->aMem[0]) );
++  if( pElem==0 ) return 1;
++  pElem->zKey = (char*)&pElem->aMem[p->nMem];
++  memcpy(pElem->zKey, zKey, nKey);
++  pElem->nKey = nKey;
++  pOld = sqliteHashInsert(&p->hash, pElem->zKey, pElem->nKey, pElem);
++  if( pOld!=0 ){
++    assert( pOld==pElem );  /* Malloc failed on insert */
++    sqliteFree(pOld);
++    return 0;
++  }
++  for(i=0, pMem=pElem->aMem; i<p->nMem; i++, pMem++){
++    pMem->flags = MEM_Null;
++  }
++  p->pCurrent = pElem;
++  return 0;
++}
++
++/*
++** Get the AggElem currently in focus
++*/
++#define AggInFocus(P)   ((P).pCurrent ? (P).pCurrent : _AggInFocus(&(P)))
++static AggElem *_AggInFocus(Agg *p){
++  HashElem *pElem = sqliteHashFirst(&p->hash);
++  if( pElem==0 ){
++    AggInsert(p,"",1);
++    pElem = sqliteHashFirst(&p->hash);
++  }
++  return pElem ? sqliteHashData(pElem) : 0;
++}
++
++/*
++** Convert the given stack entity into a string if it isn't one
++** already.
++*/
++#define Stringify(P) if(((P)->flags & MEM_Str)==0){hardStringify(P);}
++static int hardStringify(Mem *pStack){
++  int fg = pStack->flags;
++  if( fg & MEM_Real ){
++    sqlite_snprintf(sizeof(pStack->zShort),pStack->zShort,"%.15g",pStack->r);
++  }else if( fg & MEM_Int ){
++    sqlite_snprintf(sizeof(pStack->zShort),pStack->zShort,"%d",pStack->i);
++  }else{
++    pStack->zShort[0] = 0;
++  }
++  pStack->z = pStack->zShort;
++  pStack->n = strlen(pStack->zShort)+1;
++  pStack->flags = MEM_Str | MEM_Short;
++  return 0;
++}
++
++/*
++** 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) (((P)->flags & MEM_Dyn)==0 ? hardDynamicify(P):0)
++static int hardDynamicify(Mem *pStack){
++  int fg = pStack->flags;
++  char *z;
++  if( (fg & MEM_Str)==0 ){
++    hardStringify(pStack);
++  }
++  assert( (fg & MEM_Dyn)==0 );
++  z = sqliteMallocRaw( pStack->n );
++  if( z==0 ) return 1;
++  memcpy(z, pStack->z, pStack->n);
++  pStack->z = z;
++  pStack->flags |= MEM_Dyn;
++  return 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.
++**
++** This routine converts an ephemeral string into a dynamically allocated
++** string that the stack entry itself controls.  In other words, it
++** converts an MEM_Ephem string into an MEM_Dyn string.
++*/
++#define Deephemeralize(P) \
++   if( ((P)->flags&MEM_Ephem)!=0 && hardDeephem(P) ){ goto no_mem;}
++static int hardDeephem(Mem *pStack){
++  char *z;
++  assert( (pStack->flags & MEM_Ephem)!=0 );
++  z = sqliteMallocRaw( pStack->n );
++  if( z==0 ) return 1;
++  memcpy(z, pStack->z, pStack->n);
++  pStack->z = z;
++  pStack->flags &= ~MEM_Ephem;
++  pStack->flags |= MEM_Dyn;
++  return 0;
++}
++
++/*
++** Release the memory associated with the given stack level.  This
++** leaves the Mem.flags field in an inconsistent state.
++*/
++#define Release(P) if((P)->flags&MEM_Dyn){ sqliteFree((P)->z); }
++
++/*
++** Pop the stack N times.
++*/
++static void popStack(Mem **ppTos, int N){
++  Mem *pTos = *ppTos;
++  while( N>0 ){
++    N--;
++    Release(pTos);
++    pTos--;
++  }
++  *ppTos = pTos;
++}
++
++/*
++** Return TRUE if zNum is a 32-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 just 32
++** bits, then return false.
++**
++** Under Linux (RedHat 7.2) this routine is much faster than atoi()
++** for converting strings into integers.
++*/
++static int toInt(const char *zNum, int *pNum){
++  int v = 0;
++  int neg;
++  int i, c;
++  if( *zNum=='-' ){
++    neg = 1;
++    zNum++;
++  }else if( *zNum=='+' ){
++    neg = 0;
++    zNum++;
++  }else{
++    neg = 0;
++  }
++  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<10 || (i==10 && memcmp(zNum,"2147483647",10)<=0));
++}
++
++/*
++** Convert the given stack entity into a integer if it isn't one
++** already.
++**
++** Any prior string or real representation is invalidated.  
++** NULLs are converted into 0.
++*/
++#define Integerify(P) if(((P)->flags&MEM_Int)==0){ hardIntegerify(P); }
++static void hardIntegerify(Mem *pStack){
++  if( pStack->flags & MEM_Real ){
++    pStack->i = (int)pStack->r;
++    Release(pStack);
++  }else if( pStack->flags & MEM_Str ){
++    toInt(pStack->z, &pStack->i);
++    Release(pStack);
++  }else{
++    pStack->i = 0;
++  }
++  pStack->flags = MEM_Int;
++}
++
++/*
++** Get a valid Real representation for the given stack element.
++**
++** Any prior string or integer representation is retained.
++** NULLs are converted into 0.0.
++*/
++#define Realify(P) if(((P)->flags&MEM_Real)==0){ hardRealify(P); }
++static void hardRealify(Mem *pStack){
++  if( pStack->flags & MEM_Str ){
++    pStack->r = sqliteAtoF(pStack->z, 0);
++  }else if( pStack->flags & MEM_Int ){
++    pStack->r = pStack->i;
++  }else{
++    pStack->r = 0.0;
++  }
++  pStack->flags |= MEM_Real;
++}
++
++/*
++** The parameters are pointers to the head of two sorted lists
++** of Sorter structures.  Merge these two lists together and return
++** a single sorted list.  This routine forms the core of the merge-sort
++** algorithm.
++**
++** In the case of a tie, left sorts in front of right.
++*/
++static Sorter *Merge(Sorter *pLeft, Sorter *pRight){
++  Sorter sHead;
++  Sorter *pTail;
++  pTail = &sHead;
++  pTail->pNext = 0;
++  while( pLeft && pRight ){
++    int c = sqliteSortCompare(pLeft->zKey, pRight->zKey);
++    if( c<=0 ){
++      pTail->pNext = pLeft;
++      pLeft = pLeft->pNext;
++    }else{
++      pTail->pNext = pRight;
++      pRight = pRight->pNext;
++    }
++    pTail = pTail->pNext;
++  }
++  if( pLeft ){
++    pTail->pNext = pLeft;
++  }else if( pRight ){
++    pTail->pNext = pRight;
++  }
++  return sHead.pNext;
++}
++
++/*
++** The following routine works like a replacement for the standard
++** library routine fgets().  The difference is in how end-of-line (EOL)
++** is handled.  Standard fgets() uses LF for EOL under unix, CRLF
++** under windows, and CR under mac.  This routine accepts any of these
++** character sequences as an EOL mark.  The EOL mark is replaced by
++** a single LF character in zBuf.
++*/
++static char *vdbe_fgets(char *zBuf, int nBuf, FILE *in){
++  int i, c;
++  for(i=0; i<nBuf-1 && (c=getc(in))!=EOF; i++){
++    zBuf[i] = c;
++    if( c=='\r' || c=='\n' ){
++      if( c=='\r' ){
++        zBuf[i] = '\n';
++        c = getc(in);
++        if( c!=EOF && c!='\n' ) ungetc(c, in);
++      }
++      i++;
++      break;
++    }
++  }
++  zBuf[i]  = 0;
++  return i>0 ? zBuf : 0;
++}
++
++/*
++** Make sure there is space in the Vdbe structure to hold at least
++** mxCursor cursors.  If there is not currently enough space, then
++** allocate more.
++**
++** If a memory allocation error occurs, return 1.  Return 0 if
++** everything works.
++*/
++static int expandCursorArraySize(Vdbe *p, int mxCursor){
++  if( mxCursor>=p->nCursor ){
++    Cursor *aCsr = sqliteRealloc( p->aCsr, (mxCursor+1)*sizeof(Cursor) );
++    if( aCsr==0 ) return 1;
++    p->aCsr = aCsr;
++    memset(&p->aCsr[p->nCursor], 0, sizeof(Cursor)*(mxCursor+1-p->nCursor));
++    p->nCursor = mxCursor+1;
++  }
++  return 0;
++}
++
++#ifdef VDBE_PROFILE
++/*
++** The following routine only works on pentium-class processors.
++** It uses the RDTSC opcode to read cycle count value out of the
++** processor and returns that value.  This can be used for high-res
++** profiling.
++*/
++__inline__ unsigned long long int hwtime(void){
++  unsigned long long int x;
++  __asm__("rdtsc\n\t"
++          "mov %%edx, %%ecx\n\t"
++          :"=A" (x));
++  return x;
++}
++#endif
++
++/*
++** The CHECK_FOR_INTERRUPT macro defined here looks to see if the
++** sqlite_interrupt() routine has been called.  If it has been, then
++** processing of the VDBE program is interrupted.
++**
++** This macro added to every instruction that does a jump in order to
++** implement a loop.  This test used to be on every single instruction,
++** but that meant we more testing that we needed.  By only testing the
++** flag on jump instructions, we get a (small) speed improvement.
++*/
++#define CHECK_FOR_INTERRUPT \
++   if( db->flags & SQLITE_Interrupt ) goto abort_due_to_interrupt;
++
++
++/*
++** Execute as much of a VDBE program as we can then return.
++**
++** sqliteVdbeMakeReady() must be called before this routine in order to
++** close the program with a final OP_Halt and to set up the callbacks
++** and the error message pointer.
++**
++** Whenever a row or result data is available, this routine will either
++** invoke the result callback (if there is one) or return with
++** SQLITE_ROW.
++**
++** If an attempt is made to open a locked database, then this routine
++** will either invoke the busy callback (if there is one) or it will
++** 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.
++** 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
++** immediately.  There will be no error message but the p->rc field is
++** set to SQLITE_ABORT and this routine will return SQLITE_ERROR.
++**
++** A memory allocation error causes p->rc to be set to SQLITE_NOMEM and this
++** routine to return SQLITE_ERROR.
++**
++** Other fatal errors return SQLITE_ERROR.
++**
++** After this routine has finished, sqliteVdbeFinalize() should be
++** used to clean up the mess that was left behind.
++*/
++int sqliteVdbeExec(
++  Vdbe *p                    /* The VDBE */
++){
++  int pc;                    /* The program counter */
++  Op *pOp;                   /* Current operation */
++  int rc = SQLITE_OK;        /* Value to return */
++  sqlite *db = p->db;        /* The database */
++  Mem *pTos;                 /* Top entry in the operand stack */
++  char zBuf[100];            /* Space to sprintf() an integer */
++#ifdef VDBE_PROFILE
++  unsigned long long start;  /* CPU clock count at start of opcode */
++  int origPc;                /* Program counter at start of opcode */
++#endif
++#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
++  int nProgressOps = 0;      /* Opcodes executed since progress callback. */
++#endif
++
++  if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
++  assert( db->magic==SQLITE_MAGIC_BUSY );
++  assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY );
++  p->rc = SQLITE_OK;
++  assert( p->explain==0 );
++  if( sqlite_malloc_failed ) goto no_mem;
++  pTos = p->pTos;
++  if( p->popStack ){
++    popStack(&pTos, p->popStack);
++    p->popStack = 0;
++  }
++  CHECK_FOR_INTERRUPT;
++  for(pc=p->pc; rc==SQLITE_OK; pc++){
++    assert( pc>=0 && pc<p->nOp );
++    assert( pTos<=&p->aStack[pc] );
++#ifdef VDBE_PROFILE
++    origPc = pc;
++    start = hwtime();
++#endif
++    pOp = &p->aOp[pc];
++
++    /* Only allow tracing if NDEBUG is not defined.
++    */
++#ifndef NDEBUG
++    if( p->trace ){
++      sqliteVdbePrintOp(p->trace, pc, pOp);
++    }
++#endif
++
++    /* Check to see if we need to simulate an interrupt.  This only happens
++    ** if we have a special test build.
++    */
++#ifdef SQLITE_TEST
++    if( sqlite_interrupt_count>0 ){
++      sqlite_interrupt_count--;
++      if( sqlite_interrupt_count==0 ){
++        sqlite_interrupt(db);
++      }
++    }
++#endif
++
++#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
++    /* Call the progress callback if it is configured and the required number
++    ** of VDBE ops have been executed (either since this invocation of
++    ** sqliteVdbeExec() or since last time the progress callback was called).
++    ** If the progress callback returns non-zero, exit the virtual machine with
++    ** a return code SQLITE_ABORT.
++    */
++    if( db->xProgress ){
++      if( db->nProgressOps==nProgressOps ){
++        if( db->xProgress(db->pProgressArg)!=0 ){
++          rc = SQLITE_ABORT;
++          continue; /* skip to the next iteration of the for loop */
++        }
++        nProgressOps = 0;
++      }
++      nProgressOps++;
++    }
++#endif
++
++    switch( pOp->opcode ){
++
++/*****************************************************************************
++** What follows is a massive switch statement where each case implements a
++** separate instruction in the virtual machine.  If we follow the usual
++** indentation conventions, each case should be indented by 6 spaces.  But
++** that is a lot of wasted space on the left margin.  So the code within
++** the switch statement will break with convention and be flush-left. Another
++** big comment (similar to this one) will mark the point in the code where
++** we transition back to normal indentation.
++**
++** The formatting of each case is important.  The makefile for SQLite
++** generates two C files "opcodes.h" and "opcodes.c" by scanning this
++** file looking for lines that begin with "case OP_".  The opcodes.h files
++** will be filled with #defines that give unique integer values to each
++** opcode and the opcodes.c file is filled with an array of strings where
++** each string is the symbolic name for the corresponding opcode.
++**
++** Documentation about VDBE opcodes is generated by scanning this file
++** for lines of that contain "Opcode:".  That line and all subsequent
++** comment lines are used in the generation of the opcode.html documentation
++** file.
++**
++** SUMMARY:
++**
++**     Formatting is important to scripts that scan this file.
++**     Do not deviate from the formatting style currently in use.
++**
++*****************************************************************************/
++
++/* 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: {
++  CHECK_FOR_INTERRUPT;
++  pc = pOp->p2 - 1;
++  break;
++}
++
++/* Opcode:  Gosub * P2 *
++**
++** Push the current address plus 1 onto the return address stack
++** and then jump to address P2.
++**
++** The return address stack is of limited depth.  If too many
++** OP_Gosub operations occur without intervening OP_Returns, then
++** the return address stack will fill up and processing will abort
++** with a fatal error.
++*/
++case OP_Gosub: {
++  if( p->returnDepth>=sizeof(p->returnStack)/sizeof(p->returnStack[0]) ){
++    sqliteSetString(&p->zErrMsg, "return address stack overflow", (char*)0);
++    p->rc = SQLITE_INTERNAL;
++    return SQLITE_ERROR;
++  }
++  p->returnStack[p->returnDepth++] = pc+1;
++  pc = pOp->p2 - 1;
++  break;
++}
++
++/* 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: {
++  if( p->returnDepth<=0 ){
++    sqliteSetString(&p->zErrMsg, "return address stack underflow", (char*)0);
++    p->rc = SQLITE_INTERNAL;
++    return SQLITE_ERROR;
++  }
++  p->returnDepth--;
++  pc = p->returnStack[p->returnDepth] - 1;
++  break;
++}
++
++/* Opcode:  Halt P1 P2 *
++**
++** Exit immediately.  All open cursors, Lists, Sorts, etc are closed
++** automatically.
++**
++** P1 is the result code returned by sqlite_exec().  For a normal
++** halt, this should be SQLITE_OK (0).  For errors, it can be some
++** other value.  If P1!=0 then P2 will determine whether or not to
++** rollback the current transaction.  Do not rollback if P2==OE_Fail.
++** Do the rollback if P2==OE_Rollback.  If P2==OE_Abort, then back
++** out all changes that have occurred during this execution of the
++** VDBE, but do not rollback the transaction. 
++**
++** 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: {
++  p->magic = VDBE_MAGIC_HALT;
++  p->pTos = pTos;
++  if( pOp->p1!=SQLITE_OK ){
++    p->rc = pOp->p1;
++    p->errorAction = pOp->p2;
++    if( pOp->p3 ){
++      sqliteSetString(&p->zErrMsg, pOp->p3, (char*)0);
++    }
++    return SQLITE_ERROR;
++  }else{
++    p->rc = SQLITE_OK;
++    return SQLITE_DONE;
++  }
++}
++
++/* Opcode: Integer P1 * P3
++**
++** The integer value P1 is pushed onto the stack.  If P3 is not zero
++** then it is assumed to be a string representation of the same integer.
++*/
++case OP_Integer: {
++  pTos++;
++  pTos->i = pOp->p1;
++  pTos->flags = MEM_Int;
++  if( pOp->p3 ){
++    pTos->z = pOp->p3;
++    pTos->flags |= MEM_Str | MEM_Static;
++    pTos->n = strlen(pOp->p3)+1;
++  }
++  break;
++}
++
++/* Opcode: String * * P3
++**
++** The string value P3 is pushed onto the stack.  If P3==0 then a
++** NULL is pushed onto the stack.
++*/
++case OP_String: {
++  char *z = pOp->p3;
++  pTos++;
++  if( z==0 ){
++    pTos->flags = MEM_Null;
++  }else{
++    pTos->z = z;
++    pTos->n = strlen(z) + 1;
++    pTos->flags = MEM_Str | MEM_Static;
++  }
++  break;
++}
++
++/* Opcode: Variable P1 * *
++**
++** Push the value of variable P1 onto the stack.  A variable is
++** an unknown in the original SQL string as handed to sqlite_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
++** sqlite_bind() API.
++*/
++case OP_Variable: {
++  int j = pOp->p1 - 1;
++  pTos++;
++  if( j>=0 && j<p->nVar && p->azVar[j]!=0 ){
++    pTos->z = p->azVar[j];
++    pTos->n = p->anVar[j];
++    pTos->flags = MEM_Str | MEM_Static;
++  }else{
++    pTos->flags = MEM_Null;
++  }
++  break;
++}
++
++/* Opcode: Pop P1 * *
++**
++** P1 elements are popped off of the top of stack and discarded.
++*/
++case OP_Pop: {
++  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.
++**
++** 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.
++**
++** Also see the Pull instruction.
++*/
++case OP_Dup: {
++  Mem *pFrom = &pTos[-pOp->p1];
++  assert( pFrom<=pTos && pFrom>=p->aStack );
++  pTos++;
++  memcpy(pTos, pFrom, sizeof(*pFrom)-NBFS);
++  if( pTos->flags & MEM_Str ){
++    if( pOp->p2 && (pTos->flags & (MEM_Dyn|MEM_Ephem)) ){
++      pTos->flags &= ~MEM_Dyn;
++      pTos->flags |= MEM_Ephem;
++    }else if( pTos->flags & MEM_Short ){
++      memcpy(pTos->zShort, pFrom->zShort, pTos->n);
++      pTos->z = pTos->zShort;
++    }else if( (pTos->flags & MEM_Static)==0 ){
++      pTos->z = sqliteMallocRaw(pFrom->n);
++      if( sqlite_malloc_failed ) goto no_mem;
++      memcpy(pTos->z, pFrom->z, pFrom->n);
++      pTos->flags &= ~(MEM_Static|MEM_Ephem|MEM_Short);
++      pTos->flags |= MEM_Dyn;
++    }
++  }
++  break;
++}
++
++/* Opcode: Pull P1 * *
++**
++** 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.
++**
++** See also the Dup instruction.
++*/
++case OP_Pull: {
++  Mem *pFrom = &pTos[-pOp->p1];
++  int i;
++  Mem ts;
++
++  ts = *pFrom;
++  Deephemeralize(pTos);
++  for(i=0; i<pOp->p1; i++, pFrom++){
++    Deephemeralize(&pFrom[1]);
++    *pFrom = pFrom[1];
++    assert( (pFrom->flags & MEM_Ephem)==0 );
++    if( pFrom->flags & MEM_Short ){
++      assert( pFrom->flags & MEM_Str );
++      assert( pFrom->z==pFrom[1].zShort );
++      pFrom->z = pFrom->zShort;
++    }
++  }
++  *pTos = ts;
++  if( pTos->flags & MEM_Short ){
++    assert( pTos->flags & MEM_Str );
++    assert( pTos->z==pTos[-pOp->p1].zShort );
++    pTos->z = pTos->zShort;
++  }
++  break;
++}
++
++/* Opcode: Push P1 * *
++**
++** 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: {
++  Mem *pTo = &pTos[-pOp->p1];
++
++  assert( pTo>=p->aStack );
++  Deephemeralize(pTos);
++  Release(pTo);
++  *pTo = *pTos;
++  if( pTo->flags & MEM_Short ){
++    assert( pTo->z==pTos->zShort );
++    pTo->z = pTo->zShort;
++  }
++  pTos--;
++  break;
++}
++
++
++/* Opcode: ColumnName P1 P2 P3
++**
++** P3 becomes the P1-th column name (first is 0).  An array of pointers
++** to all column names is passed as the 4th parameter to the callback.
++** If P2==1 then this is the last column in the result set and thus the
++** number of columns in the result set will be P1.  There must be at least
++** one OP_ColumnName with a P2==1 before invoking OP_Callback and the
++** number of columns specified in OP_Callback must one more than the P1
++** value of the OP_ColumnName that has P2==1.
++*/
++case OP_ColumnName: {
++  assert( pOp->p1>=0 && pOp->p1<p->nOp );
++  p->azColName[pOp->p1] = pOp->p3;
++  p->nCallback = 0;
++  if( pOp->p2 ) p->nResColumn = pOp->p1+1;
++  break;
++}
++
++/* Opcode: Callback P1 * *
++**
++** Pop P1 values off the stack and form them into an array.  Then
++** invoke the callback function using the newly formed array as the
++** 3rd parameter.
++*/
++case OP_Callback: {
++  int i;
++  char **azArgv = p->zArgv;
++  Mem *pCol;
++
++  pCol = &pTos[1-pOp->p1];
++  assert( pCol>=p->aStack );
++  for(i=0; i<pOp->p1; i++, pCol++){
++    if( pCol->flags & MEM_Null ){
++      azArgv[i] = 0;
++    }else{
++      Stringify(pCol);
++      azArgv[i] = pCol->z;
++    }
++  }
++  azArgv[i] = 0;
++  p->nCallback++;
++  p->azResColumn = azArgv;
++  assert( p->nResColumn==pOp->p1 );
++  p->popStack = pOp->p1;
++  p->pc = pc + 1;
++  p->pTos = pTos;
++  return SQLITE_ROW;
++}
++
++/* Opcode: Concat P1 P2 P3
++**
++** Look at the first P1 elements of the stack.  Append them all 
++** together with the lowest element first.  Use P3 as a separator.  
++** Put the result on the top of the stack.  The original P1 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.
++**
++** If P3 is NULL, then use no separator.  When P1==1, this routine
++** makes a copy of the top stack element into memory obtained
++** from sqliteMalloc().
++*/
++case OP_Concat: {
++  char *zNew;
++  int nByte;
++  int nField;
++  int i, j;
++  char *zSep;
++  int nSep;
++  Mem *pTerm;
++
++  nField = pOp->p1;
++  zSep = pOp->p3;
++  if( zSep==0 ) zSep = "";
++  nSep = strlen(zSep);
++  assert( &pTos[1-nField] >= p->aStack );
++  nByte = 1 - nSep;
++  pTerm = &pTos[1-nField];
++  for(i=0; i<nField; i++, pTerm++){
++    if( pTerm->flags & MEM_Null ){
++      nByte = -1;
++      break;
++    }else{
++      Stringify(pTerm);
++      nByte += pTerm->n - 1 + nSep;
++    }
++  }
++  if( nByte<0 ){
++    if( pOp->p2==0 ){
++      popStack(&pTos, nField);
++    }
++    pTos++;
++    pTos->flags = MEM_Null;
++    break;
++  }
++  zNew = sqliteMallocRaw( nByte );
++  if( zNew==0 ) goto no_mem;
++  j = 0;
++  pTerm = &pTos[1-nField];
++  for(i=j=0; i<nField; i++, pTerm++){
++    assert( pTerm->flags & MEM_Str );
++    memcpy(&zNew[j], pTerm->z, pTerm->n-1);
++    j += pTerm->n-1;
++    if( nSep>0 && i<nField-1 ){
++      memcpy(&zNew[j], zSep, nSep);
++      j += nSep;
++    }
++  }
++  zNew[j] = 0;
++  if( pOp->p2==0 ){
++    popStack(&pTos, nField);
++  }
++  pTos++;
++  pTos->n = nByte;
++  pTos->flags = MEM_Str|MEM_Dyn;
++  pTos->z = zNew;
++  break;
++}
++
++/* Opcode: Add * * *
++**
++** 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.
++*/
++/* Opcode: Multiply * * *
++**
++** 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.
++*/
++/* Opcode: Subtract * * *
++**
++** 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.
++*/
++/* Opcode: Divide * * *
++**
++** 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.
++*/
++/* Opcode: Remainder * * *
++**
++** 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.
++** If either operand is NULL, the result is NULL.
++*/
++case OP_Add:
++case OP_Subtract:
++case OP_Multiply:
++case OP_Divide:
++case OP_Remainder: {
++  Mem *pNos = &pTos[-1];
++  assert( pNos>=p->aStack );
++  if( ((pTos->flags | pNos->flags) & MEM_Null)!=0 ){
++    Release(pTos);
++    pTos--;
++    Release(pTos);
++    pTos->flags = MEM_Null;
++  }else if( (pTos->flags & pNos->flags & MEM_Int)==MEM_Int ){
++    int a, b;
++    a = pTos->i;
++    b = pNos->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;
++        b /= a;
++        break;
++      }
++      default: {
++        if( a==0 ) goto divide_by_zero;
++        b %= a;
++        break;
++      }
++    }
++    Release(pTos);
++    pTos--;
++    Release(pTos);
++    pTos->i = b;
++    pTos->flags = MEM_Int;
++  }else{
++    double a, b;
++    Realify(pTos);
++    Realify(pNos);
++    a = pTos->r;
++    b = pNos->r;
++    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;
++        b /= a;
++        break;
++      }
++      default: {
++        int ia = (int)a;
++        int ib = (int)b;
++        if( ia==0.0 ) goto divide_by_zero;
++        b = ib % ia;
++        break;
++      }
++    }
++    Release(pTos);
++    pTos--;
++    Release(pTos);
++    pTos->r = b;
++    pTos->flags = MEM_Real;
++  }
++  break;
++
++divide_by_zero:
++  Release(pTos);
++  pTos--;
++  Release(pTos);
++  pTos->flags = MEM_Null;
++  break;
++}
++
++/* Opcode: Function P1 * P3
++**
++** Invoke a user function (P3 is a pointer to a Function structure that
++** defines the function) with P1 string arguments taken from the stack.
++** Pop all arguments from the stack and push back the result.
++**
++** See also: AggFunc
++*/
++case OP_Function: {
++  int n, i;
++  Mem *pArg;
++  char **azArgv;
++  sqlite_func ctx;
++
++  n = pOp->p1;
++  pArg = &pTos[1-n];
++  azArgv = p->zArgv;
++  for(i=0; i<n; i++, pArg++){
++    if( pArg->flags & MEM_Null ){
++      azArgv[i] = 0;
++    }else{
++      Stringify(pArg);
++      azArgv[i] = pArg->z;
++    }
++  }
++  ctx.pFunc = (FuncDef*)pOp->p3;
++  ctx.s.flags = MEM_Null;
++  ctx.s.z = 0;
++  ctx.isError = 0;
++  ctx.isStep = 0;
++  if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
++  (*ctx.pFunc->xFunc)(&ctx, n, (const char**)azArgv);
++  if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
++  popStack(&pTos, n);
++  pTos++;
++  *pTos = ctx.s;
++  if( pTos->flags & MEM_Short ){
++    pTos->z = pTos->zShort;
++  }
++  if( ctx.isError ){
++    sqliteSetString(&p->zErrMsg, 
++       (pTos->flags & MEM_Str)!=0 ? pTos->z : "user function error", (char*)0);
++    rc = SQLITE_ERROR;
++  }
++  break;
++}
++
++/* Opcode: BitAnd * * *
++**
++** 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.
++*/
++/* Opcode: BitOr * * *
++**
++** 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.
++*/
++/* Opcode: ShiftLeft * * *
++**
++** Pop the top two elements from the stack.  Convert both elements
++** to integers.  Push back onto the stack the top element shifted
++** left by N bits where N is the second element on the stack.
++** If either operand is NULL, the result is NULL.
++*/
++/* Opcode: ShiftRight * * *
++**
++** Pop the top two elements from the stack.  Convert both elements
++** to integers.  Push back onto the stack the top element shifted
++** right by N bits where N is the second element on the stack.
++** If either operand is NULL, the result is NULL.
++*/
++case OP_BitAnd:
++case OP_BitOr:
++case OP_ShiftLeft:
++case OP_ShiftRight: {
++  Mem *pNos = &pTos[-1];
++  int a, b;
++
++  assert( pNos>=p->aStack );
++  if( (pTos->flags | pNos->flags) & MEM_Null ){
++    popStack(&pTos, 2);
++    pTos++;
++    pTos->flags = MEM_Null;
++    break;
++  }
++  Integerify(pTos);
++  Integerify(pNos);
++  a = pTos->i;
++  b = pNos->i;
++  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;
++  }
++  assert( (pTos->flags & MEM_Dyn)==0 );
++  assert( (pNos->flags & MEM_Dyn)==0 );
++  pTos--;
++  Release(pTos);
++  pTos->i = a;
++  pTos->flags = MEM_Int;
++  break;
++}
++
++/* Opcode: AddImm  P1 * *
++** 
++** Add the value P1 to whatever is on top of the stack.  The result
++** is always an integer.
++**
++** To force the top of the stack to be an integer, just add 0.
++*/
++case OP_AddImm: {
++  assert( pTos>=p->aStack );
++  Integerify(pTos);
++  pTos->i += pOp->p1;
++  break;
++}
++
++/* Opcode: ForceInt P1 P2 *
++**
++** 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 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.
++*/
++case OP_ForceInt: {
++  int v;
++  assert( pTos>=p->aStack );
++  if( (pTos->flags & (MEM_Int|MEM_Real))==0
++         && ((pTos->flags & MEM_Str)==0 || sqliteIsNumber(pTos->z)==0) ){
++    Release(pTos);
++    pTos--;
++    pc = pOp->p2 - 1;
++    break;
++  }
++  if( pTos->flags & MEM_Int ){
++    v = pTos->i + (pOp->p1!=0);
++  }else{
++    Realify(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;
++  break;
++}
++
++/* 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
++** 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: {
++  assert( pTos>=p->aStack );
++  if( pTos->flags & MEM_Int ){
++    /* Do nothing */
++  }else if( pTos->flags & MEM_Real ){
++    int i = (int)pTos->r;
++    double r = (double)i;
++    if( r!=pTos->r ){
++      goto mismatch;
++    }
++    pTos->i = i;
++  }else if( pTos->flags & MEM_Str ){
++    int v;
++    if( !toInt(pTos->z, &v) ){
++      double r;
++      if( !sqliteIsNumber(pTos->z) ){
++        goto mismatch;
++      }
++      Realify(pTos);
++      v = (int)pTos->r;
++      r = (double)v;
++      if( r!=pTos->r ){
++        goto mismatch;
++      }
++    }
++    pTos->i = v;
++  }else{
++    goto mismatch;
++  }
++  Release(pTos);
++  pTos->flags = MEM_Int;
++  break;
++
++mismatch:
++  if( pOp->p2==0 ){
++    rc = SQLITE_MISMATCH;
++    goto abort_due_to_error;
++  }else{
++    if( pOp->p1 ) popStack(&pTos, 1);
++    pc = pOp->p2 - 1;
++  }
++  break;
++}
++
++/* Opcode: Eq P1 P2 *
++**
++** Pop the top two elements from the stack.  If they are equal, then
++** jump to instruction P2.  Otherwise, continue to the next instruction.
++**
++** If either operand is NULL (and thus if the result is unknown) then
++** take the jump if P1 is true.
++**
++** If both values are numeric, they are converted to doubles using atof()
++** and compared for equality that way.  Otherwise the strcmp() library
++** routine is used for the comparison.  For a pure text comparison
++** use OP_StrEq.
++**
++** 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.
++*/
++/* Opcode: Ne P1 P2 *
++**
++** Pop the top two elements from the stack.  If they are not equal, then
++** jump to instruction P2.  Otherwise, continue to the next instruction.
++**
++** If either operand is NULL (and thus if the result is unknown) then
++** take the jump if P1 is true.
++**
++** If both values are numeric, they are converted to doubles using atof()
++** and compared in that format.  Otherwise the strcmp() library
++** routine is used for the comparison.  For a pure text comparison
++** use OP_StrNe.
++**
++** 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.
++*/
++/* Opcode: Lt P1 P2 *
++**
++** Pop the top two elements from the stack.  If second element (the
++** next on stack) is less than the first (the top of stack), then
++** jump to instruction P2.  Otherwise, continue to the next instruction.
++** In other words, jump if NOS<TOS.
++**
++** If either operand is NULL (and thus if the result is unknown) then
++** take the jump if P1 is true.
++**
++** If both values are numeric, they are converted to doubles using atof()
++** and compared in that format.  Numeric values are always less than
++** non-numeric values.  If both operands are non-numeric, the strcmp() library
++** routine is used for the comparison.  For a pure text comparison
++** use OP_StrLt.
++**
++** 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.
++*/
++/* Opcode: Le P1 P2 *
++**
++** Pop the top two elements from the stack.  If second element (the
++** next on stack) is less than or equal to the first (the top of stack),
++** then jump to instruction P2. In other words, jump if NOS<=TOS.
++**
++** If either operand is NULL (and thus if the result is unknown) then
++** take the jump if P1 is true.
++**
++** If both values are numeric, they are converted to doubles using atof()
++** and compared in that format.  Numeric values are always less than
++** non-numeric values.  If both operands are non-numeric, the strcmp() library
++** routine is used for the comparison.  For a pure text comparison
++** use OP_StrLe.
++**
++** 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.
++*/
++/* Opcode: Gt P1 P2 *
++**
++** Pop the top two elements from the stack.  If second element (the
++** next on stack) is greater than the first (the top of stack),
++** then jump to instruction P2. In other words, jump if NOS>TOS.
++**
++** If either operand is NULL (and thus if the result is unknown) then
++** take the jump if P1 is true.
++**
++** If both values are numeric, they are converted to doubles using atof()
++** and compared in that format.  Numeric values are always less than
++** non-numeric values.  If both operands are non-numeric, the strcmp() library
++** routine is used for the comparison.  For a pure text comparison
++** use OP_StrGt.
++**
++** 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.
++*/
++/* Opcode: Ge P1 P2 *
++**
++** Pop the top two elements from the stack.  If second element (the next
++** on stack) is greater than or equal to the first (the top of stack),
++** then jump to instruction P2. In other words, jump if NOS>=TOS.
++**
++** If either operand is NULL (and thus if the result is unknown) then
++** take the jump if P1 is true.
++**
++** If both values are numeric, they are converted to doubles using atof()
++** and compared in that format.  Numeric values are always less than
++** non-numeric values.  If both operands are non-numeric, the strcmp() library
++** routine is used for the comparison.  For a pure text comparison
++** use OP_StrGe.
++**
++** 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.
++*/
++case OP_Eq:
++case OP_Ne:
++case OP_Lt:
++case OP_Le:
++case OP_Gt:
++case OP_Ge: {
++  Mem *pNos = &pTos[-1];
++  int c, v;
++  int ft, fn;
++  assert( pNos>=p->aStack );
++  ft = pTos->flags;
++  fn = pNos->flags;
++  if( (ft | fn) & MEM_Null ){
++    popStack(&pTos, 2);
++    if( pOp->p2 ){
++      if( pOp->p1 ) pc = pOp->p2-1;
++    }else{
++      pTos++;
++      pTos->flags = MEM_Null;
++    }
++    break;
++  }else if( (ft & fn & MEM_Int)==MEM_Int ){
++    c = pNos->i - pTos->i;
++  }else if( (ft & MEM_Int)!=0 && (fn & MEM_Str)!=0 && toInt(pNos->z,&v) ){
++    c = v - pTos->i;
++  }else if( (fn & MEM_Int)!=0 && (ft & MEM_Str)!=0 && toInt(pTos->z,&v) ){
++    c = pNos->i - v;
++  }else{
++    Stringify(pTos);
++    Stringify(pNos);
++    c = sqliteCompare(pNos->z, pTos->z);
++  }
++  switch( pOp->opcode ){
++    case OP_Eq:    c = c==0;     break;
++    case OP_Ne:    c = c!=0;     break;
++    case OP_Lt:    c = c<0;      break;
++    case OP_Le:    c = c<=0;     break;
++    case OP_Gt:    c = c>0;      break;
++    default:       c = c>=0;     break;
++  }
++  popStack(&pTos, 2);
++  if( pOp->p2 ){
++    if( c ) pc = pOp->p2-1;
++  }else{
++    pTos++;
++    pTos->i = c;
++    pTos->flags = MEM_Int;
++  }
++  break;
++}
++/* INSERT NO CODE HERE!
++**
++** The opcode numbers are extracted from this source file by doing
++**
++**    grep '^case OP_' vdbe.c | ... >opcodes.h
++**
++** The opcodes are numbered in the order that they appear in this file.
++** But in order for the expression generating code to work right, the
++** string comparison operators that follow must be numbered exactly 6
++** greater than the numeric comparison opcodes above.  So no other
++** cases can appear between the two.
++*/
++/* Opcode: StrEq P1 P2 *
++**
++** Pop the top two elements from the stack.  If they are equal, then
++** jump to instruction P2.  Otherwise, continue to the next instruction.
++**
++** If either operand is NULL (and thus if the result is unknown) then
++** take the jump if P1 is true.
++**
++** The strcmp() library routine is used for the comparison.  For a
++** numeric comparison, use OP_Eq.
++**
++** 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.
++*/
++/* Opcode: StrNe P1 P2 *
++**
++** Pop the top two elements from the stack.  If they are not equal, then
++** jump to instruction P2.  Otherwise, continue to the next instruction.
++**
++** If either operand is NULL (and thus if the result is unknown) then
++** take the jump if P1 is true.
++**
++** The strcmp() library routine is used for the comparison.  For a
++** numeric comparison, use OP_Ne.
++**
++** 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.
++*/
++/* Opcode: StrLt P1 P2 *
++**
++** Pop the top two elements from the stack.  If second element (the
++** next on stack) is less than the first (the top of stack), then
++** jump to instruction P2.  Otherwise, continue to the next instruction.
++** In other words, jump if NOS<TOS.
++**
++** If either operand is NULL (and thus if the result is unknown) then
++** take the jump if P1 is true.
++**
++** The strcmp() library routine is used for the comparison.  For a
++** numeric comparison, use OP_Lt.
++**
++** 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.
++*/
++/* Opcode: StrLe P1 P2 *
++**
++** Pop the top two elements from the stack.  If second element (the
++** next on stack) is less than or equal to the first (the top of stack),
++** then jump to instruction P2. In other words, jump if NOS<=TOS.
++**
++** If either operand is NULL (and thus if the result is unknown) then
++** take the jump if P1 is true.
++**
++** The strcmp() library routine is used for the comparison.  For a
++** numeric comparison, use OP_Le.
++**
++** 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.
++*/
++/* Opcode: StrGt P1 P2 *
++**
++** Pop the top two elements from the stack.  If second element (the
++** next on stack) is greater than the first (the top of stack),
++** then jump to instruction P2. In other words, jump if NOS>TOS.
++**
++** If either operand is NULL (and thus if the result is unknown) then
++** take the jump if P1 is true.
++**
++** The strcmp() library routine is used for the comparison.  For a
++** numeric comparison, use OP_Gt.
++**
++** 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.
++*/
++/* Opcode: StrGe P1 P2 *
++**
++** Pop the top two elements from the stack.  If second element (the next
++** on stack) is greater than or equal to the first (the top of stack),
++** then jump to instruction P2. In other words, jump if NOS>=TOS.
++**
++** If either operand is NULL (and thus if the result is unknown) then
++** take the jump if P1 is true.
++**
++** The strcmp() library routine is used for the comparison.  For a
++** numeric comparison, use OP_Ge.
++**
++** 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.
++*/
++case OP_StrEq:
++case OP_StrNe:
++case OP_StrLt:
++case OP_StrLe:
++case OP_StrGt:
++case OP_StrGe: {
++  Mem *pNos = &pTos[-1];
++  int c;
++  assert( pNos>=p->aStack );
++  if( (pNos->flags | pTos->flags) & MEM_Null ){
++    popStack(&pTos, 2);
++    if( pOp->p2 ){
++      if( pOp->p1 ) pc = pOp->p2-1;
++    }else{
++      pTos++;
++      pTos->flags = MEM_Null;
++    }
++    break;
++  }else{
++    Stringify(pTos);
++    Stringify(pNos);
++    c = strcmp(pNos->z, pTos->z);
++  }
++  /* The asserts on each case of the following switch are there to verify
++  ** that string comparison opcodes are always exactly 6 greater than the
++  ** corresponding numeric comparison opcodes.  The code generator depends
++  ** on this fact.
++  */
++  switch( pOp->opcode ){
++    case OP_StrEq:    c = c==0;    assert( pOp->opcode-6==OP_Eq );   break;
++    case OP_StrNe:    c = c!=0;    assert( pOp->opcode-6==OP_Ne );   break;
++    case OP_StrLt:    c = c<0;     assert( pOp->opcode-6==OP_Lt );   break;
++    case OP_StrLe:    c = c<=0;    assert( pOp->opcode-6==OP_Le );   break;
++    case OP_StrGt:    c = c>0;     assert( pOp->opcode-6==OP_Gt );   break;
++    default:          c = c>=0;    assert( pOp->opcode-6==OP_Ge );   break;
++  }
++  popStack(&pTos, 2);
++  if( pOp->p2 ){
++    if( c ) pc = pOp->p2-1;
++  }else{
++    pTos++;
++    pTos->flags = MEM_Int;
++    pTos->i = c;
++  }
++  break;
++}
++
++/* Opcode: And * * *
++**
++** Pop two values off the stack.  Take the logical AND of the
++** two values and push the resulting boolean value back onto the
++** stack. 
++*/
++/* Opcode: Or * * *
++**
++** Pop two values off the stack.  Take the logical OR of the
++** two values and push the resulting boolean value back onto the
++** stack. 
++*/
++case OP_And:
++case OP_Or: {
++  Mem *pNos = &pTos[-1];
++  int v1, v2;    /* 0==TRUE, 1==FALSE, 2==UNKNOWN or NULL */
++
++  assert( pNos>=p->aStack );
++  if( pTos->flags & MEM_Null ){
++    v1 = 2;
++  }else{
++    Integerify(pTos);
++    v1 = pTos->i==0;
++  }
++  if( pNos->flags & MEM_Null ){
++    v2 = 2;
++  }else{
++    Integerify(pNos);
++    v2 = pNos->i==0;
++  }
++  if( pOp->opcode==OP_And ){
++    static const unsigned char and_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 };
++    v1 = and_logic[v1*3+v2];
++  }else{
++    static const unsigned char or_logic[] = { 0, 0, 0, 0, 1, 2, 0, 2, 2 };
++    v1 = or_logic[v1*3+v2];
++  }
++  popStack(&pTos, 2);
++  pTos++;
++  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:
++case OP_AbsValue: {
++  assert( pTos>=p->aStack );
++  if( pTos->flags & MEM_Real ){
++    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 */
++  }else{
++    Realify(pTos);
++    Release(pTos);
++    if( pOp->opcode==OP_Negative || pTos->r<0.0 ){
++      pTos->r = -pTos->r;
++    }
++    pTos->flags = MEM_Real;
++  }
++  break;
++}
++
++/* Opcode: Not * * *
++**
++** 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
++** is unchanged.
++*/
++case OP_Not: {
++  assert( pTos>=p->aStack );
++  if( pTos->flags & MEM_Null ) break;  /* Do nothing to NULLs */
++  Integerify(pTos);
++  Release(pTos);
++  pTos->i = !pTos->i;
++  pTos->flags = MEM_Int;
++  break;
++}
++
++/* Opcode: BitNot * * *
++**
++** 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.
++*/
++case OP_BitNot: {
++  assert( pTos>=p->aStack );
++  if( pTos->flags & MEM_Null ) break;  /* Do nothing to NULLs */
++  Integerify(pTos);
++  Release(pTos);
++  pTos->i = ~pTos->i;
++  pTos->flags = MEM_Int;
++  break;
++}
++
++/* Opcode: Noop * * *
++**
++** Do nothing.  This instruction is often useful as a jump
++** destination.
++*/
++case OP_Noop: {
++  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.
++**
++** If the value popped of the stack is NULL, then take the jump if P1
++** is true and fall through if P1 is false.
++*/
++case OP_If:
++case OP_IfNot: {
++  int c;
++  assert( pTos>=p->aStack );
++  if( pTos->flags & MEM_Null ){
++    c = pOp->p1;
++  }else{
++    Integerify(pTos);
++    c = pTos->i;
++    if( pOp->opcode==OP_IfNot ) c = !c;
++  }
++  assert( (pTos->flags & MEM_Dyn)==0 );
++  pTos--;
++  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: {
++  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;
++      break;
++    }
++  }
++  if( pOp->p1>0 ) popStack(&pTos, cnt);
++  break;
++}
++
++/* 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.
++*/
++case OP_NotNull: {
++  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);
++  break;
++}
++
++/* Opcode: MakeRecord P1 P2 *
++**
++** Convert the top P1 entries of the stack into a single entry
++** suitable for use as a data record in a database table.  The
++** details of the format are irrelavant as long as the OP_Column
++** opcode can decode the record later.  Refer to source code
++** comments for the details of the record format.
++**
++** If P2 is true (non-zero) and one or more of the P1 entries
++** that go into building the record is NULL, then add some extra
++** bytes to the record to make it distinct for other entries created
++** during the same run of the VDBE.  The extra bytes added are a
++** counter that is reset with each run of the VDBE, so records
++** created this way will not necessarily be distinct across runs.
++** But they should be distinct for transient tables (created using
++** OP_OpenTemp) which is what they are intended for.
++**
++** (Later:) The P2==1 option was intended to make NULLs distinct
++** for the UNION operator.  But I have since discovered that NULLs
++** are indistinct for UNION.  So this option is never used.
++*/
++case OP_MakeRecord: {
++  char *zNewRecord;
++  int nByte;
++  int nField;
++  int i, j;
++  int idxWidth;
++  u32 addr;
++  Mem *pRec;
++  int addUnique = 0;   /* True to cause bytes to be added to make the
++                       ** generated record distinct */
++  char zTemp[NBFS];    /* Temp space for small records */
++
++  /* Assuming the record contains N fields, the record format looks
++  ** like this:
++  **
++  **   -------------------------------------------------------------------
++  **   | idx0 | idx1 | ... | idx(N-1) | idx(N) | data0 | ... | data(N-1) |
++  **   -------------------------------------------------------------------
++  **
++  ** All data fields are converted to strings before being stored and
++  ** are stored with their null terminators.  NULL entries omit the
++  ** null terminator.  Thus an empty string uses 1 byte and a NULL uses
++  ** zero bytes.  Data(0) is taken from the lowest element of the stack
++  ** and data(N-1) is the top of the stack.
++  **
++  ** Each of the idx() entries is either 1, 2, or 3 bytes depending on
++  ** how big the total record is.  Idx(0) contains the offset to the start
++  ** of data(0).  Idx(k) contains the offset to the start of data(k).
++  ** Idx(N) contains the total number of bytes in the record.
++  */
++  nField = pOp->p1;
++  pRec = &pTos[1-nField];
++  assert( pRec>=p->aStack );
++  nByte = 0;
++  for(i=0; i<nField; i++, pRec++){
++    if( pRec->flags & MEM_Null ){
++      addUnique = pOp->p2;
++    }else{
++      Stringify(pRec);
++      nByte += pRec->n;
++    }
++  }
++  if( addUnique ) nByte += sizeof(p->uniqueCnt);
++  if( nByte + nField + 1 < 256 ){
++    idxWidth = 1;
++  }else if( nByte + 2*nField + 2 < 65536 ){
++    idxWidth = 2;
++  }else{
++    idxWidth = 3;
++  }
++  nByte += idxWidth*(nField + 1);
++  if( nByte>MAX_BYTES_PER_ROW ){
++    rc = SQLITE_TOOBIG;
++    goto abort_due_to_error;
++  }
++  if( nByte<=NBFS ){
++    zNewRecord = zTemp;
++  }else{
++    zNewRecord = sqliteMallocRaw( nByte );
++    if( zNewRecord==0 ) goto no_mem;
++  }
++  j = 0;
++  addr = idxWidth*(nField+1) + addUnique*sizeof(p->uniqueCnt);
++  for(i=0, pRec=&pTos[1-nField]; i<nField; i++, pRec++){
++    zNewRecord[j++] = addr & 0xff;
++    if( idxWidth>1 ){
++      zNewRecord[j++] = (addr>>8)&0xff;
++      if( idxWidth>2 ){
++        zNewRecord[j++] = (addr>>16)&0xff;
++      }
++    }
++    if( (pRec->flags & MEM_Null)==0 ){
++      addr += pRec->n;
++    }
++  }
++  zNewRecord[j++] = addr & 0xff;
++  if( idxWidth>1 ){
++    zNewRecord[j++] = (addr>>8)&0xff;
++    if( idxWidth>2 ){
++      zNewRecord[j++] = (addr>>16)&0xff;
++    }
++  }
++  if( addUnique ){
++    memcpy(&zNewRecord[j], &p->uniqueCnt, sizeof(p->uniqueCnt));
++    p->uniqueCnt++;
++    j += sizeof(p->uniqueCnt);
++  }
++  for(i=0, pRec=&pTos[1-nField]; i<nField; i++, pRec++){
++    if( (pRec->flags & MEM_Null)==0 ){
++      memcpy(&zNewRecord[j], pRec->z, pRec->n);
++      j += pRec->n;
++    }
++  }
++  popStack(&pTos, nField);
++  pTos++;
++  pTos->n = nByte;
++  if( nByte<=NBFS ){
++    assert( zNewRecord==zTemp );
++    memcpy(pTos->zShort, zTemp, nByte);
++    pTos->z = pTos->zShort;
++    pTos->flags = MEM_Str | MEM_Short;
++  }else{
++    assert( zNewRecord!=zTemp );
++    pTos->z = zNewRecord;
++    pTos->flags = MEM_Str | MEM_Dyn;
++  }
++  break;
++}
++
++/* Opcode: MakeKey P1 P2 P3
++**
++** Convert the top P1 entries of the stack into a single entry suitable
++** for use as the key in an index.  The top P1 records are
++** converted to strings and merged.  The null-terminators 
++** are retained and used as separators.
++** The lowest entry in the stack is the first field and the top of the
++** stack becomes the last.
++**
++** If P2 is not zero, then the original entries remain on the stack
++** and the new key is pushed on top.  If P2 is zero, the original
++** data is popped off the stack first then the new key is pushed
++** back in its place.
++**
++** P3 is a string that is P1 characters long.  Each character is either
++** an 'n' or a 't' to indicates if the argument should be intepreted as
++** numeric or text type.  The first character of P3 corresponds to the
++** lowest element on the stack.  If P3 is NULL then all arguments are
++** assumed to be of the numeric type.
++**
++** The type makes a difference in that text-type fields may not be 
++** introduced by 'b' (as described in the next paragraph).  The
++** first character of a text-type field must be either 'a' (if it is NULL)
++** or 'c'.  Numeric fields will be introduced by 'b' if their content
++** looks like a well-formed number.  Otherwise the 'a' or 'c' will be
++** used.
++**
++** The key is a concatenation of fields.  Each field is terminated by
++** a single 0x00 character.  A NULL field is introduced by an 'a' and
++** is followed immediately by its 0x00 terminator.  A numeric field is
++** introduced by a single character 'b' and is followed by a sequence
++** of characters that represent the number such that a comparison of
++** the character string using memcpy() sorts the numbers in numerical
++** order.  The character strings for numbers are generated using the
++** sqliteRealToSortable() function.  A text field is introduced by a
++** 'c' character and is followed by the exact text of the field.  The
++** use of an 'a', 'b', or 'c' character at the beginning of each field
++** guarantees that NULLs sort before numbers and that numbers sort
++** before text.  0x00 characters do not occur except as separators
++** between fields.
++**
++** See also: MakeIdxKey, SortMakeKey
++*/
++/* Opcode: MakeIdxKey P1 P2 P3
++**
++** Convert the top P1 entries of the stack into a single entry suitable
++** for use as the key in an index.  In addition, take one additional integer
++** off of the stack, treat that integer as a four-byte record number, and
++** append the four bytes to the key.  Thus a total of P1+1 entries are
++** popped from the stack for this instruction and a single entry is pushed
++** back.  The first P1 entries that are popped are strings and the last
++** entry (the lowest on the stack) is an integer record number.
++**
++** The converstion of the first P1 string entries occurs just like in
++** MakeKey.  Each entry is separated from the others by a null.
++** The entire concatenation is null-terminated.  The lowest entry
++** in the stack is the first field and the top of the stack becomes the
++** last.
++**
++** If P2 is not zero and one or more of the P1 entries that go into the
++** generated key is NULL, then jump to P2 after the new key has been
++** pushed on the stack.  In other words, jump to P2 if the key is
++** guaranteed to be unique.  This jump can be used to skip a subsequent
++** uniqueness test.
++**
++** P3 is a string that is P1 characters long.  Each character is either
++** an 'n' or a 't' to indicates if the argument should be numeric or
++** text.  The first character corresponds to the lowest element on the
++** stack.  If P3 is null then all arguments are assumed to be numeric.
++**
++** See also:  MakeKey, SortMakeKey
++*/
++case OP_MakeIdxKey:
++case OP_MakeKey: {
++  char *zNewKey;
++  int nByte;
++  int nField;
++  int addRowid;
++  int i, j;
++  int containsNull = 0;
++  Mem *pRec;
++  char zTemp[NBFS];
++
++  addRowid = pOp->opcode==OP_MakeIdxKey;
++  nField = pOp->p1;
++  pRec = &pTos[1-nField];
++  assert( pRec>=p->aStack );
++  nByte = 0;
++  for(j=0, i=0; i<nField; i++, j++, pRec++){
++    int flags = pRec->flags;
++    int len;
++    char *z;
++    if( flags & MEM_Null ){
++      nByte += 2;
++      containsNull = 1;
++    }else if( pOp->p3 && pOp->p3[j]=='t' ){
++      Stringify(pRec);
++      pRec->flags &= ~(MEM_Int|MEM_Real);
++      nByte += pRec->n+1;
++    }else if( (flags & (MEM_Real|MEM_Int))!=0 || sqliteIsNumber(pRec->z) ){
++      if( (flags & (MEM_Real|MEM_Int))==MEM_Int ){
++        pRec->r = pRec->i;
++      }else if( (flags & (MEM_Real|MEM_Int))==0 ){
++        pRec->r = sqliteAtoF(pRec->z, 0);
++      }
++      Release(pRec);
++      z = pRec->zShort;
++      sqliteRealToSortable(pRec->r, z);
++      len = strlen(z);
++      pRec->z = 0;
++      pRec->flags = MEM_Real;
++      pRec->n = len+1;
++      nByte += pRec->n+1;
++    }else{
++      nByte += pRec->n+1;
++    }
++  }
++  if( nByte+sizeof(u32)>MAX_BYTES_PER_ROW ){
++    rc = SQLITE_TOOBIG;
++    goto abort_due_to_error;
++  }
++  if( addRowid ) nByte += sizeof(u32);
++  if( nByte<=NBFS ){
++    zNewKey = zTemp;
++  }else{
++    zNewKey = sqliteMallocRaw( nByte );
++    if( zNewKey==0 ) goto no_mem;
++  }
++  j = 0;
++  pRec = &pTos[1-nField];
++  for(i=0; i<nField; i++, pRec++){
++    if( pRec->flags & MEM_Null ){
++      zNewKey[j++] = 'a';
++      zNewKey[j++] = 0;
++    }else if( pRec->flags==MEM_Real ){
++      zNewKey[j++] = 'b';
++      memcpy(&zNewKey[j], pRec->zShort, pRec->n);
++      j += pRec->n;
++    }else{
++      assert( pRec->flags & MEM_Str );
++      zNewKey[j++] = 'c';
++      memcpy(&zNewKey[j], pRec->z, pRec->n);
++      j += pRec->n;
++    }
++  }
++  if( addRowid ){
++    u32 iKey;
++    pRec = &pTos[-nField];
++    assert( pRec>=p->aStack );
++    Integerify(pRec);
++    iKey = intToKey(pRec->i);
++    memcpy(&zNewKey[j], &iKey, sizeof(u32));
++    popStack(&pTos, nField+1);
++    if( pOp->p2 && containsNull ) pc = pOp->p2 - 1;
++  }else{
++    if( pOp->p2==0 ) popStack(&pTos, nField);
++  }
++  pTos++;
++  pTos->n = nByte;
++  if( nByte<=NBFS ){
++    assert( zNewKey==zTemp );
++    pTos->z = pTos->zShort;
++    memcpy(pTos->zShort, zTemp, nByte);
++    pTos->flags = MEM_Str | MEM_Short;
++  }else{
++    pTos->z = zNewKey;
++    pTos->flags = MEM_Str | MEM_Dyn;
++  }
++  break;
++}
++
++/* Opcode: IncrKey * * *
++**
++** The top of the stack should contain an index key generated by
++** The MakeKey opcode.  This routine increases the least significant
++** byte of that key by one.  This is used so that the MoveTo opcode
++** will move to the first entry greater than the key rather than to
++** the key itself.
++*/
++case OP_IncrKey: {
++  assert( pTos>=p->aStack );
++  /* The IncrKey opcode is only applied to keys generated by
++  ** MakeKey or MakeIdxKey and the results of those operands
++  ** are always dynamic strings or zShort[] strings.  So we
++  ** are always free to modify the string in place.
++  */
++  assert( pTos->flags & (MEM_Dyn|MEM_Short) );
++  pTos->z[pTos->n-1]++;
++  break;
++}
++
++/* Opcode: Checkpoint P1 * *
++**
++** Begin a checkpoint.  A checkpoint is the beginning of a operation that
++** is part of a larger transaction but which might need to be rolled back
++** itself without effecting the containing transaction.  A checkpoint will
++** be automatically committed or rollback when the VDBE halts.
++**
++** The checkpoint is begun on the database file with index P1.  The main
++** database file has an index of 0 and the file used for temporary tables
++** has an index of 1.
++*/
++case OP_Checkpoint: {
++  int i = pOp->p1;
++  if( i>=0 && i<db->nDb && db->aDb[i].pBt && db->aDb[i].inTrans==1 ){
++    rc = sqliteBtreeBeginCkpt(db->aDb[i].pBt);
++    if( rc==SQLITE_OK ) db->aDb[i].inTrans = 2;
++  }
++  break;
++}
++
++/* Opcode: Transaction P1 * *
++**
++** Begin a transaction.  The transaction ends when a Commit or Rollback
++** opcode is encountered.  Depending on the ON CONFLICT setting, the
++** transaction might also be rolled back if an error is encountered.
++**
++** 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.
++**
++** A write lock is obtained on the database file when a transaction is
++** started.  No other process can read or write the file while the
++** transaction is underway.  Starting a transaction also creates a
++** rollback journal.  A transaction must be started before any changes
++** can be made to the database.
++*/
++case OP_Transaction: {
++  int busy = 1;
++  int i = pOp->p1;
++  assert( i>=0 && i<db->nDb );
++  if( db->aDb[i].inTrans ) break;
++  while( db->aDb[i].pBt!=0 && busy ){
++    rc = sqliteBtreeBeginTrans(db->aDb[i].pBt);
++    switch( rc ){
++      case SQLITE_BUSY: {
++        if( db->xBusyCallback==0 ){
++          p->pc = pc;
++          p->undoTransOnError = 1;
++          p->rc = SQLITE_BUSY;
++          p->pTos = pTos;
++          return SQLITE_BUSY;
++        }else if( (*db->xBusyCallback)(db->pBusyArg, "", busy++)==0 ){
++          sqliteSetString(&p->zErrMsg, sqlite_error_string(rc), (char*)0);
++          busy = 0;
++        }
++        break;
++      }
++      case SQLITE_READONLY: {
++        rc = SQLITE_OK;
++        /* Fall thru into the next case */
++      }
++      case SQLITE_OK: {
++        p->inTempTrans = 0;
++        busy = 0;
++        break;
++      }
++      default: {
++        goto abort_due_to_error;
++      }
++    }
++  }
++  db->aDb[i].inTrans = 1;
++  p->undoTransOnError = 1;
++  break;
++}
++
++/* Opcode: Commit * * *
++**
++** Cause all modifications to the database that have been made since the
++** last Transaction to actually take effect.  No additional modifications
++** are allowed until another transaction is started.  The Commit instruction
++** deletes the journal file and releases the write lock on the database.
++** A read lock continues to be held if there are still cursors open.
++*/
++case OP_Commit: {
++  int i;
++  if( db->xCommitCallback!=0 ){
++    if( sqliteSafetyOff(db) ) goto abort_due_to_misuse; 
++    if( db->xCommitCallback(db->pCommitArg)!=0 ){
++      rc = SQLITE_CONSTRAINT;
++    }
++    if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
++  }
++  for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
++    if( db->aDb[i].inTrans ){
++      rc = sqliteBtreeCommit(db->aDb[i].pBt);
++      db->aDb[i].inTrans = 0;
++    }
++  }
++  if( rc==SQLITE_OK ){
++    sqliteCommitInternalChanges(db);
++  }else{
++    sqliteRollbackAll(db);
++  }
++  break;
++}
++
++/* Opcode: Rollback P1 * *
++**
++** Cause all modifications to the database that have been made since the
++** last Transaction to be undone. The database is restored to its state
++** before the Transaction opcode was executed.  No additional modifications
++** are allowed until another transaction is started.
++**
++** P1 is the index of the database file that is committed.  An index of 0
++** is used for the main database and an index of 1 is used for the file used
++** to hold temporary tables.
++**
++** This instruction automatically closes all cursors and releases both
++** the read and write locks on the indicated database.
++*/
++case OP_Rollback: {
++  sqliteRollbackAll(db);
++  break;
++}
++
++/* Opcode: ReadCookie P1 P2 *
++**
++** 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
++** the main database file and P1==1 is the database file used to store
++** temporary tables.
++**
++** 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: {
++  int aMeta[SQLITE_N_BTREE_META];
++  assert( pOp->p2<SQLITE_N_BTREE_META );
++  assert( pOp->p1>=0 && pOp->p1<db->nDb );
++  assert( db->aDb[pOp->p1].pBt!=0 );
++  rc = sqliteBtreeGetMeta(db->aDb[pOp->p1].pBt, aMeta);
++  pTos++;
++  pTos->i = aMeta[1+pOp->p2];
++  pTos->flags = MEM_Int;
++  break;
++}
++
++/* Opcode: SetCookie P1 P2 *
++**
++** Write the top of the stack 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
++** temporary tables.
++**
++** A transaction must be started before executing this opcode.
++*/
++case OP_SetCookie: {
++  int aMeta[SQLITE_N_BTREE_META];
++  assert( pOp->p2<SQLITE_N_BTREE_META );
++  assert( pOp->p1>=0 && pOp->p1<db->nDb );
++  assert( db->aDb[pOp->p1].pBt!=0 );
++  assert( pTos>=p->aStack );
++  Integerify(pTos)
++  rc = sqliteBtreeGetMeta(db->aDb[pOp->p1].pBt, aMeta);
++  if( rc==SQLITE_OK ){
++    aMeta[1+pOp->p2] = pTos->i;
++    rc = sqliteBtreeUpdateMeta(db->aDb[pOp->p1].pBt, aMeta);
++  }
++  Release(pTos);
++  pTos--;
++  break;
++}
++
++/* Opcode: VerifyCookie P1 P2 *
++**
++** Check the value of global database parameter number 0 (the
++** schema version) and make sure it is equal to P2.  
++** P1 is the database number which is 0 for the main database file
++** and 1 for the file holding temporary tables and some higher number
++** for auxiliary databases.
++**
++** The cookie changes its value whenever the database schema changes.
++** This operation is used to detect when that the cookie has changed
++** and that the current process needs to reread the schema.
++**
++** Either a transaction needs to have been started or an OP_Open needs
++** to be executed (to establish a read lock) before this opcode is
++** invoked.
++*/
++case OP_VerifyCookie: {
++  int aMeta[SQLITE_N_BTREE_META];
++  assert( pOp->p1>=0 && pOp->p1<db->nDb );
++  rc = sqliteBtreeGetMeta(db->aDb[pOp->p1].pBt, aMeta);
++  if( rc==SQLITE_OK && aMeta[1]!=pOp->p2 ){
++    sqliteSetString(&p->zErrMsg, "database schema has changed", (char*)0);
++    rc = SQLITE_SCHEMA;
++  }
++  break;
++}
++
++/* Opcode: OpenRead P1 P2 P3
++**
++** 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.
++**
++** If P2==0 then take the root page number from the next of the stack.
++**
++** There will be a read lock on the database whenever there is an
++** open cursor.  If the database was unlocked prior to this instruction
++** then a read lock is acquired as part of this instruction.  A read
++** lock allows other processes to read the database but prohibits
++** any other process from modifying the database.  The read lock is
++** released when all cursors are closed.  If this instruction attempts
++** to get a read lock but fails, the script terminates with an
++** SQLITE_BUSY error code.
++**
++** The P3 value is the name of the table or index being opened.
++** The P3 value is not actually used by this opcode and may be
++** omitted.  But the code generator usually inserts the index or
++** table name into P3 to make the code easier to read.
++**
++** See also OpenWrite.
++*/
++/* Opcode: OpenWrite P1 P2 P3
++**
++** 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.
++**
++** The P3 value is the name of the table or index being opened.
++** The P3 value is not actually used by this opcode and may be
++** omitted.  But the code generator usually inserts the index or
++** table name into P3 to make the code easier to read.
++**
++** This instruction works just like OpenRead except that it opens the cursor
++** in read/write mode.  For a given table, there can be one or more read-only
++** cursors or a single read/write cursor but not both.
++**
++** See also OpenRead.
++*/
++case OP_OpenRead:
++case OP_OpenWrite: {
++  int busy = 0;
++  int i = pOp->p1;
++  int p2 = pOp->p2;
++  int wrFlag;
++  Btree *pX;
++  int iDb;
++  
++  assert( pTos>=p->aStack );
++  Integerify(pTos);
++  iDb = pTos->i;
++  pTos--;
++  assert( iDb>=0 && iDb<db->nDb );
++  pX = db->aDb[iDb].pBt;
++  assert( pX!=0 );
++  wrFlag = pOp->opcode==OP_OpenWrite;
++  if( p2<=0 ){
++    assert( pTos>=p->aStack );
++    Integerify(pTos);
++    p2 = pTos->i;
++    pTos--;
++    if( p2<2 ){
++      sqliteSetString(&p->zErrMsg, "root page number less than 2", (char*)0);
++      rc = SQLITE_INTERNAL;
++      break;
++    }
++  }
++  assert( i>=0 );
++  if( expandCursorArraySize(p, i) ) goto no_mem;
++  sqliteVdbeCleanupCursor(&p->aCsr[i]);
++  memset(&p->aCsr[i], 0, sizeof(Cursor));
++  p->aCsr[i].nullRow = 1;
++  if( pX==0 ) break;
++  do{
++    rc = sqliteBtreeCursor(pX, p2, wrFlag, &p->aCsr[i].pCursor);
++    switch( rc ){
++      case SQLITE_BUSY: {
++        if( db->xBusyCallback==0 ){
++          p->pc = pc;
++          p->rc = SQLITE_BUSY;
++          p->pTos = &pTos[1 + (pOp->p2<=0)]; /* Operands must remain on stack */
++          return SQLITE_BUSY;
++        }else if( (*db->xBusyCallback)(db->pBusyArg, pOp->p3, ++busy)==0 ){
++          sqliteSetString(&p->zErrMsg, sqlite_error_string(rc), (char*)0);
++          busy = 0;
++        }
++        break;
++      }
++      case SQLITE_OK: {
++        busy = 0;
++        break;
++      }
++      default: {
++        goto abort_due_to_error;
++      }
++    }
++  }while( busy );
++  break;
++}
++
++/* Opcode: OpenTemp P1 P2 *
++**
++** Open a new cursor to a transient table.
++** The transient cursor is always opened read/write even if 
++** the main database is read-only.  The transient table is deleted
++** automatically when the cursor is closed.
++**
++** The cursor points to a BTree table if P2==0 and to a BTree index
++** if P2==1.  A BTree table must have an integer key and can have arbitrary
++** data.  A BTree index has no data but can have an arbitrary key.
++**
++** This opcode is used for tables that exist for the duration of a single
++** SQL statement only.  Tables created using CREATE TEMPORARY TABLE
++** are opened using OP_OpenRead or OP_OpenWrite.  "Temporary" in the
++** context of this opcode means for the duration of a single SQL statement
++** whereas "Temporary" in the context of CREATE TABLE means for the duration
++** of the connection to the database.  Same word; different meanings.
++*/
++case OP_OpenTemp: {
++  int i = pOp->p1;
++  Cursor *pCx;
++  assert( i>=0 );
++  if( expandCursorArraySize(p, i) ) goto no_mem;
++  pCx = &p->aCsr[i];
++  sqliteVdbeCleanupCursor(pCx);
++  memset(pCx, 0, sizeof(*pCx));
++  pCx->nullRow = 1;
++  rc = sqliteBtreeFactory(db, 0, 1, TEMP_PAGES, &pCx->pBt);
++
++  if( rc==SQLITE_OK ){
++    rc = sqliteBtreeBeginTrans(pCx->pBt);
++  }
++  if( rc==SQLITE_OK ){
++    if( pOp->p2 ){
++      int pgno;
++      rc = sqliteBtreeCreateIndex(pCx->pBt, &pgno);
++      if( rc==SQLITE_OK ){
++        rc = sqliteBtreeCursor(pCx->pBt, pgno, 1, &pCx->pCursor);
++      }
++    }else{
++      rc = sqliteBtreeCursor(pCx->pBt, 2, 1, &pCx->pCursor);
++    }
++  }
++  break;
++}
++
++/* 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
++** first row to be deleted.  All data is deleted when the cursor is
++** closed.
++**
++** A pseudo-table created by this opcode is useful for holding the
++** NEW or OLD tables in a trigger.
++*/
++case OP_OpenPseudo: {
++  int i = pOp->p1;
++  Cursor *pCx;
++  assert( i>=0 );
++  if( expandCursorArraySize(p, i) ) goto no_mem;
++  pCx = &p->aCsr[i];
++  sqliteVdbeCleanupCursor(pCx);
++  memset(pCx, 0, sizeof(*pCx));
++  pCx->nullRow = 1;
++  pCx->pseudoTable = 1;
++  break;
++}
++
++/* 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: {
++  int i = pOp->p1;
++  if( i>=0 && i<p->nCursor ){
++    sqliteVdbeCleanupCursor(&p->aCsr[i]);
++  }
++  break;
++}
++
++/* Opcode: MoveTo P1 P2 *
++**
++** Pop the top of the stack and use its value as a key.  Reposition
++** cursor P1 so that it points to an entry with a matching key.  If
++** the table contains no record with a matching key, then the cursor
++** is left pointing at the first record that is greater than the key.
++** If there are no records greater than the key and P2 is not zero,
++** then an immediate jump to P2 is made.
++**
++** See also: Found, NotFound, Distinct, MoveLt
++*/
++/* Opcode: MoveLt P1 P2 *
++**
++** Pop the top of the stack and use its value as a key.  Reposition
++** cursor P1 so that it points to the entry with the largest key that is
++** less than the key popped from the stack.
++** If there are no records less than than the key and P2
++** is not zero then an immediate jump to P2 is made.
++**
++** See also: MoveTo
++*/
++case OP_MoveLt:
++case OP_MoveTo: {
++  int i = pOp->p1;
++  Cursor *pC;
++
++  assert( pTos>=p->aStack );
++  assert( i>=0 && i<p->nCursor );
++  pC = &p->aCsr[i];
++  if( pC->pCursor!=0 ){
++    int res, oc;
++    pC->nullRow = 0;
++    if( pTos->flags & MEM_Int ){
++      int iKey = intToKey(pTos->i);
++      if( pOp->p2==0 && pOp->opcode==OP_MoveTo ){
++        pC->movetoTarget = iKey;
++        pC->deferredMoveto = 1;
++        Release(pTos);
++        pTos--;
++        break;
++      }
++      sqliteBtreeMoveto(pC->pCursor, (char*)&iKey, sizeof(int), &res);
++      pC->lastRecno = pTos->i;
++      pC->recnoIsValid = res==0;
++    }else{
++      Stringify(pTos);
++      sqliteBtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
++      pC->recnoIsValid = 0;
++    }
++    pC->deferredMoveto = 0;
++    sqlite_search_count++;
++    oc = pOp->opcode;
++    if( oc==OP_MoveTo && res<0 ){
++      sqliteBtreeNext(pC->pCursor, &res);
++      pC->recnoIsValid = 0;
++      if( res && pOp->p2>0 ){
++        pc = pOp->p2 - 1;
++      }
++    }else if( oc==OP_MoveLt ){
++      if( res>=0 ){
++        sqliteBtreePrevious(pC->pCursor, &res);
++        pC->recnoIsValid = 0;
++      }else{
++        /* res might be negative because the table is empty.  Check to
++        ** see if this is the case.
++        */
++        int keysize;
++        res = sqliteBtreeKeySize(pC->pCursor,&keysize)!=0 || keysize==0;
++      }
++      if( res && pOp->p2>0 ){
++        pc = pOp->p2 - 1;
++      }
++    }
++  }
++  Release(pTos);
++  pTos--;
++  break;
++}
++
++/* Opcode: Distinct P1 P2 *
++**
++** Use the top of the stack as a string key.  If a record with that key does
++** not exist in the table of cursor P1, then jump to P2.  If the record
++** does already exist, then fall thru.  The cursor is left pointing
++** at the record if it exists. The key is not popped from the stack.
++**
++** This operation is similar to NotFound except that this operation
++** does not pop the key from the stack.
++**
++** See also: Found, NotFound, MoveTo, IsUnique, NotExists
++*/
++/* Opcode: Found P1 P2 *
++**
++** Use the top of the stack as a string key.  If a record with that key
++** does exist in table of P1, then jump to P2.  If the record
++** does not exist, then fall thru.  The cursor is left pointing
++** to the record if it exists.  The key is popped from the stack.
++**
++** See also: Distinct, NotFound, MoveTo, IsUnique, NotExists
++*/
++/* Opcode: NotFound P1 P2 *
++**
++** Use the top of the stack as a string 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 key is popped from the stack.
++**
++** 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
++*/
++case OP_Distinct:
++case OP_NotFound:
++case OP_Found: {
++  int i = pOp->p1;
++  int alreadyExists = 0;
++  Cursor *pC;
++  assert( pTos>=p->aStack );
++  assert( i>=0 && i<p->nCursor );
++  if( (pC = &p->aCsr[i])->pCursor!=0 ){
++    int res, rx;
++    Stringify(pTos);
++    rx = sqliteBtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
++    alreadyExists = rx==SQLITE_OK && res==0;
++    pC->deferredMoveto = 0;
++  }
++  if( pOp->opcode==OP_Found ){
++    if( alreadyExists ) pc = pOp->p2 - 1;
++  }else{
++    if( !alreadyExists ) pc = pOp->p2 - 1;
++  }
++  if( pOp->opcode!=OP_Distinct ){
++    Release(pTos);
++    pTos--;
++  }
++  break;
++}
++
++/* Opcode: IsUnique P1 P2 *
++**
++** The top of the stack is an integer record number.  Call this
++** record number R.  The next on the stack is an index key created
++** using MakeIdxKey.  Call it K.  This instruction pops R from the
++** stack but it leaves K unchanged.
++**
++** P1 is an index.  So all but the last four bytes of K are an
++** index string.  The last four bytes of K are a record number.
++**
++** This instruction asks if there is an entry in P1 where the
++** index string matches K but the record number is different
++** from R.  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
++** falls through to the next instruction.
++**
++** See also: Distinct, NotFound, NotExists, Found
++*/
++case OP_IsUnique: {
++  int i = pOp->p1;
++  Mem *pNos = &pTos[-1];
++  BtCursor *pCrsr;
++  int R;
++
++  /* Pop the value R off the top of the stack
++  */
++  assert( pNos>=p->aStack );
++  Integerify(pTos);
++  R = pTos->i;
++  pTos--;
++  assert( i>=0 && i<=p->nCursor );
++  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
++    int res, rc;
++    int v;         /* The record number on the P1 entry that matches K */
++    char *zKey;    /* The value of K */
++    int nKey;      /* Number of bytes in K */
++
++    /* Make sure K is a string and make zKey point to K
++    */
++    Stringify(pNos);
++    zKey = pNos->z;
++    nKey = pNos->n;
++    assert( nKey >= 4 );
++
++    /* Search for an entry in P1 where all but the last four bytes match K.
++    ** If there is no such entry, jump immediately to P2.
++    */
++    assert( p->aCsr[i].deferredMoveto==0 );
++    rc = sqliteBtreeMoveto(pCrsr, zKey, nKey-4, &res);
++    if( rc!=SQLITE_OK ) goto abort_due_to_error;
++    if( res<0 ){
++      rc = sqliteBtreeNext(pCrsr, &res);
++      if( res ){
++        pc = pOp->p2 - 1;
++        break;
++      }
++    }
++    rc = sqliteBtreeKeyCompare(pCrsr, zKey, nKey-4, 4, &res);
++    if( rc!=SQLITE_OK ) goto abort_due_to_error;
++    if( res>0 ){
++      pc = pOp->p2 - 1;
++      break;
++    }
++
++    /* At this point, pCrsr is pointing to an entry in P1 where all but
++    ** the last for bytes of the key match K.  Check to see if the last
++    ** four bytes of the key are different from R.  If the last four
++    ** bytes equal R then jump immediately to P2.
++    */
++    sqliteBtreeKey(pCrsr, nKey - 4, 4, (char*)&v);
++    v = keyToInt(v);
++    if( v==R ){
++      pc = pOp->p2 - 1;
++      break;
++    }
++
++    /* The last four bytes of the key are different from R.  Convert the
++    ** last four bytes of the key into an integer and push it onto the
++    ** stack.  (These bytes are the record number of an entry that
++    ** violates a UNIQUE constraint.)
++    */
++    pTos++;
++    pTos->i = v;
++    pTos->flags = MEM_Int;
++  }
++  break;
++}
++
++/* Opcode: NotExists P1 P2 *
++**
++** 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.
++**
++** The difference between this operation and NotFound is that this
++** operation assumes the key is an integer and NotFound assumes it
++** is a string.
++**
++** See also: Distinct, Found, MoveTo, NotFound, IsUnique
++*/
++case OP_NotExists: {
++  int i = pOp->p1;
++  BtCursor *pCrsr;
++  assert( pTos>=p->aStack );
++  assert( i>=0 && i<p->nCursor );
++  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
++    int res, rx, iKey;
++    assert( pTos->flags & MEM_Int );
++    iKey = intToKey(pTos->i);
++    rx = sqliteBtreeMoveto(pCrsr, (char*)&iKey, sizeof(int), &res);
++    p->aCsr[i].lastRecno = pTos->i;
++    p->aCsr[i].recnoIsValid = res==0;
++    p->aCsr[i].nullRow = 0;
++    if( rx!=SQLITE_OK || res!=0 ){
++      pc = pOp->p2 - 1;
++      p->aCsr[i].recnoIsValid = 0;
++    }
++  }
++  Release(pTos);
++  pTos--;
++  break;
++}
++
++/* Opcode: NewRecno P1 * *
++**
++** Get a new integer record number used as the key to a table.
++** The record number is not previously used as a key in the database
++** table that cursor P1 points to.  The new record number is pushed 
++** onto the stack.
++*/
++case OP_NewRecno: {
++  int i = pOp->p1;
++  int v = 0;
++  Cursor *pC;
++  assert( i>=0 && i<p->nCursor );
++  if( (pC = &p->aCsr[i])->pCursor==0 ){
++    v = 0;
++  }else{
++    /* The next rowid or record number (different terms for the same
++    ** thing) is obtained in a two-step algorithm.
++    **
++    ** First we attempt to find the largest existing rowid and add one
++    ** to that.  But if the largest existing rowid is already the maximum
++    ** positive integer, we have to fall through to the second
++    ** probabilistic algorithm
++    **
++    ** The second algorithm is to select a rowid at random and see if
++    ** it already exists in the table.  If it does not exist, we have
++    ** succeeded.  If the random rowid does exist, we select a new one
++    ** and try again, up to 1000 times.
++    **
++    ** For a table with less than 2 billion entries, the probability
++    ** of not finding a unused rowid is about 1.0e-300.  This is a 
++    ** non-zero probability, but it is still vanishingly small and should
++    ** never cause a problem.  You are much, much more likely to have a
++    ** hardware failure than for this algorithm to fail.
++    **
++    ** The analysis in the previous paragraph assumes that you have a good
++    ** source of random numbers.  Is a library function like lrand48()
++    ** good enough?  Maybe. Maybe not. It's hard to know whether there
++    ** might be subtle bugs is some implementations of lrand48() that
++    ** could cause problems. To avoid uncertainty, SQLite uses its own 
++    ** random number generator based on the RC4 algorithm.
++    **
++    ** To promote locality of reference for repetitive inserts, the
++    ** first few attempts at chosing a random rowid pick values just a little
++    ** larger than the previous rowid.  This has been shown experimentally
++    ** to double the speed of the COPY operation.
++    */
++    int res, rx, cnt, x;
++    cnt = 0;
++    if( !pC->useRandomRowid ){
++      if( pC->nextRowidValid ){
++        v = pC->nextRowid;
++      }else{
++        rx = sqliteBtreeLast(pC->pCursor, &res);
++        if( res ){
++          v = 1;
++        }else{
++          sqliteBtreeKey(pC->pCursor, 0, sizeof(v), (void*)&v);
++          v = keyToInt(v);
++          if( v==0x7fffffff ){
++            pC->useRandomRowid = 1;
++          }else{
++            v++;
++          }
++        }
++      }
++      if( v<0x7fffffff ){
++        pC->nextRowidValid = 1;
++        pC->nextRowid = v+1;
++      }else{
++        pC->nextRowidValid = 0;
++      }
++    }
++    if( pC->useRandomRowid ){
++      v = db->priorNewRowid;
++      cnt = 0;
++      do{
++        if( v==0 || cnt>2 ){
++          sqliteRandomness(sizeof(v), &v);
++          if( cnt<5 ) v &= 0xffffff;
++        }else{
++          unsigned char r;
++          sqliteRandomness(1, &r);
++          v += r + 1;
++        }
++        if( v==0 ) continue;
++        x = intToKey(v);
++        rx = sqliteBtreeMoveto(pC->pCursor, &x, sizeof(int), &res);
++        cnt++;
++      }while( cnt<1000 && rx==SQLITE_OK && res==0 );
++      db->priorNewRowid = v;
++      if( rx==SQLITE_OK && res==0 ){
++        rc = SQLITE_FULL;
++        goto abort_due_to_error;
++      }
++    }
++    pC->recnoIsValid = 0;
++    pC->deferredMoveto = 0;
++  }
++  pTos++;
++  pTos->i = v;
++  pTos->flags = MEM_Int;
++  break;
++}
++
++/* Opcode: PutIntKey P1 P2 *
++**
++** 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.
++**
++** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
++** incremented (otherwise not).  If the OPFLAG_CSCHANGE flag is set,
++** then the current statement change count is incremented (otherwise not).
++** If the OPFLAG_LASTROWID flag of P2 is set, then rowid is
++** stored for subsequent return by the sqlite_last_insert_rowid() function
++** (otherwise it's unmodified).
++*/
++/* Opcode: PutStrKey P1 * *
++**
++** 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 a string.  The stack is popped twice by this instruction.
++**
++** P1 may not be a pseudo-table opened using the OpenPseudo opcode.
++*/
++case OP_PutIntKey:
++case OP_PutStrKey: {
++  Mem *pNos = &pTos[-1];
++  int i = pOp->p1;
++  Cursor *pC;
++  assert( pNos>=p->aStack );
++  assert( i>=0 && i<p->nCursor );
++  if( ((pC = &p->aCsr[i])->pCursor!=0 || pC->pseudoTable) ){
++    char *zKey;
++    int nKey, iKey;
++    if( pOp->opcode==OP_PutStrKey ){
++      Stringify(pNos);
++      nKey = pNos->n;
++      zKey = pNos->z;
++    }else{
++      assert( pNos->flags & MEM_Int );
++      nKey = sizeof(int);
++      iKey = intToKey(pNos->i);
++      zKey = (char*)&iKey;
++      if( pOp->p2 & OPFLAG_NCHANGE ) db->nChange++;
++      if( pOp->p2 & OPFLAG_LASTROWID ) db->lastRowid = pNos->i;
++      if( pOp->p2 & OPFLAG_CSCHANGE ) db->csChange++;
++      if( pC->nextRowidValid && pTos->i>=pC->nextRowid ){
++        pC->nextRowidValid = 0;
++      }
++    }
++    if( pTos->flags & MEM_Null ){
++      pTos->z = 0;
++      pTos->n = 0;
++    }else{
++      assert( pTos->flags & MEM_Str );
++    }
++    if( pC->pseudoTable ){
++      /* PutStrKey does not work for pseudo-tables.
++      ** The following assert makes sure we are not trying to use
++      ** PutStrKey on a pseudo-table
++      */
++      assert( pOp->opcode==OP_PutIntKey );
++      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 );
++        if( pC->pData ){
++          memcpy(pC->pData, pTos->z, pC->nData);
++        }
++      }
++      pC->nullRow = 0;
++    }else{
++      rc = sqliteBtreeInsert(pC->pCursor, zKey, nKey, pTos->z, pTos->n);
++    }
++    pC->recnoIsValid = 0;
++    pC->deferredMoveto = 0;
++  }
++  popStack(&pTos, 2);
++  break;
++}
++
++/* Opcode: Delete P1 P2 *
++**
++** Delete the record at which the P1 cursor is currently pointing.
++**
++** The cursor will be left pointing at either the next or the previous
++** record in the table. If it is left pointing at the next record, then
++** the next Next instruction will be a no-op.  Hence it is OK to delete
++** a record from within an Next loop.
++**
++** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
++** incremented (otherwise not).  If OPFLAG_CSCHANGE flag is set,
++** then the current statement change count is incremented (otherwise not).
++**
++** If P1 is a pseudo-table, then this instruction is a no-op.
++*/
++case OP_Delete: {
++  int i = pOp->p1;
++  Cursor *pC;
++  assert( i>=0 && i<p->nCursor );
++  pC = &p->aCsr[i];
++  if( pC->pCursor!=0 ){
++    sqliteVdbeCursorMoveto(pC);
++    rc = sqliteBtreeDelete(pC->pCursor);
++    pC->nextRowidValid = 0;
++  }
++  if( pOp->p2 & OPFLAG_NCHANGE ) db->nChange++;
++  if( pOp->p2 & OPFLAG_CSCHANGE ) db->csChange++;
++  break;
++}
++
++/* Opcode: SetCounts * * *
++**
++** Called at end of statement.  Updates lsChange (last statement change count)
++** and resets csChange (current statement change count) to 0.
++*/
++case OP_SetCounts: {
++  db->lsChange=db->csChange;
++  db->csChange=0;
++  break;
++}
++
++/* Opcode: KeyAsData P1 P2 *
++**
++** Turn the key-as-data mode for cursor P1 either on (if P2==1) or
++** off (if P2==0).  In key-as-data mode, the OP_Column opcode pulls
++** data off of the key rather than the data.  This is used for
++** processing compound selects.
++*/
++case OP_KeyAsData: {
++  int i = pOp->p1;
++  assert( i>=0 && i<p->nCursor );
++  p->aCsr[i].keyAsData = pOp->p2;
++  break;
++}
++
++/* Opcode: RowData P1 * *
++**
++** 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.
++**
++** If the cursor is not pointing to a valid row, a NULL is pushed
++** onto the stack.
++*/
++/* Opcode: RowKey P1 * *
++**
++** 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.
++**
++** If the cursor is not pointing to a valid row, a NULL is pushed
++** onto the stack.
++*/
++case OP_RowKey:
++case OP_RowData: {
++  int i = pOp->p1;
++  Cursor *pC;
++  int n;
++
++  pTos++;
++  assert( i>=0 && i<p->nCursor );
++  pC = &p->aCsr[i];
++  if( pC->nullRow ){
++    pTos->flags = MEM_Null;
++  }else if( pC->pCursor!=0 ){
++    BtCursor *pCrsr = pC->pCursor;
++    sqliteVdbeCursorMoveto(pC);
++    if( pC->nullRow ){
++      pTos->flags = MEM_Null;
++      break;
++    }else if( pC->keyAsData || pOp->opcode==OP_RowKey ){
++      sqliteBtreeKeySize(pCrsr, &n);
++    }else{
++      sqliteBtreeDataSize(pCrsr, &n);
++    }
++    pTos->n = n;
++    if( n<=NBFS ){
++      pTos->flags = MEM_Str | MEM_Short;
++      pTos->z = pTos->zShort;
++    }else{
++      char *z = sqliteMallocRaw( n );
++      if( z==0 ) goto no_mem;
++      pTos->flags = MEM_Str | MEM_Dyn;
++      pTos->z = z;
++    }
++    if( pC->keyAsData || pOp->opcode==OP_RowKey ){
++      sqliteBtreeKey(pCrsr, 0, n, pTos->z);
++    }else{
++      sqliteBtreeData(pCrsr, 0, n, pTos->z);
++    }
++  }else if( pC->pseudoTable ){
++    pTos->n = pC->nData;
++    pTos->z = pC->pData;
++    pTos->flags = MEM_Str|MEM_Ephem;
++  }else{
++    pTos->flags = MEM_Null;
++  }
++  break;
++}
++
++/* Opcode: Column P1 P2 *
++**
++** Interpret the data that cursor P1 points to as
++** a structure built using the MakeRecord instruction.
++** (See the MakeRecord opcode for additional information about
++** the format of the data.)
++** Push onto the stack the value of the P2-th column contained
++** in the data.
++**
++** If the KeyAsData opcode has previously executed on this cursor,
++** then the field might be extracted from the key rather than the
++** data.
++**
++** If P1 is negative, then the record is stored on the stack rather
++** than in a table.  For P1==-1, the top of the stack is used.
++** For P1==-2, the next on the stack is used.  And so forth.  The
++** value pushed is always just a pointer into the record which is
++** stored further down on the stack.  The column value is not copied.
++*/
++case OP_Column: {
++  int amt, offset, end, payloadSize;
++  int i = pOp->p1;
++  int p2 = pOp->p2;
++  Cursor *pC;
++  char *zRec;
++  BtCursor *pCrsr;
++  int idxWidth;
++  unsigned char aHdr[10];
++
++  assert( i<p->nCursor );
++  pTos++;
++  if( i<0 ){
++    assert( &pTos[i]>=p->aStack );
++    assert( pTos[i].flags & MEM_Str );
++    zRec = pTos[i].z;
++    payloadSize = pTos[i].n;
++  }else if( (pC = &p->aCsr[i])->pCursor!=0 ){
++    sqliteVdbeCursorMoveto(pC);
++    zRec = 0;
++    pCrsr = pC->pCursor;
++    if( pC->nullRow ){
++      payloadSize = 0;
++    }else if( pC->keyAsData ){
++      sqliteBtreeKeySize(pCrsr, &payloadSize);
++    }else{
++      sqliteBtreeDataSize(pCrsr, &payloadSize);
++    }
++  }else if( pC->pseudoTable ){
++    payloadSize = pC->nData;
++    zRec = pC->pData;
++    assert( payloadSize==0 || zRec!=0 );
++  }else{
++    payloadSize = 0;
++  }
++
++  /* Figure out how many bytes in the column data and where the column
++  ** data begins.
++  */
++  if( payloadSize==0 ){
++    pTos->flags = MEM_Null;
++    break;
++  }else if( payloadSize<256 ){
++    idxWidth = 1;
++  }else if( payloadSize<65536 ){
++    idxWidth = 2;
++  }else{
++    idxWidth = 3;
++  }
++
++  /* Figure out where the requested column is stored and how big it is.
++  */
++  if( payloadSize < idxWidth*(p2+1) ){
++    rc = SQLITE_CORRUPT;
++    goto abort_due_to_error;
++  }
++  if( zRec ){
++    memcpy(aHdr, &zRec[idxWidth*p2], idxWidth*2);
++  }else if( pC->keyAsData ){
++    sqliteBtreeKey(pCrsr, idxWidth*p2, idxWidth*2, (char*)aHdr);
++  }else{
++    sqliteBtreeData(pCrsr, idxWidth*p2, idxWidth*2, (char*)aHdr);
++  }
++  offset = aHdr[0];
++  end = aHdr[idxWidth];
++  if( idxWidth>1 ){
++    offset |= aHdr[1]<<8;
++    end |= aHdr[idxWidth+1]<<8;
++    if( idxWidth>2 ){
++      offset |= aHdr[2]<<16;
++      end |= aHdr[idxWidth+2]<<16;
++    }
++  }
++  amt = end - offset;
++  if( amt<0 || offset<0 || end>payloadSize ){
++    rc = SQLITE_CORRUPT;
++    goto abort_due_to_error;
++  }
++
++  /* amt and offset now hold the offset to the start of data and the
++  ** amount of data.  Go get the data and put it on the stack.
++  */
++  pTos->n = amt;
++  if( amt==0 ){
++    pTos->flags = MEM_Null;
++  }else if( zRec ){
++    pTos->flags = MEM_Str | MEM_Ephem;
++    pTos->z = &zRec[offset];
++  }else{
++    if( amt<=NBFS ){
++      pTos->flags = MEM_Str | MEM_Short;
++      pTos->z = pTos->zShort;
++    }else{
++      char *z = sqliteMallocRaw( amt );
++      if( z==0 ) goto no_mem;
++      pTos->flags = MEM_Str | MEM_Dyn;
++      pTos->z = z;
++    }
++    if( pC->keyAsData ){
++      sqliteBtreeKey(pCrsr, offset, amt, pTos->z);
++    }else{
++      sqliteBtreeData(pCrsr, offset, amt, pTos->z);
++    }
++  }
++  break;
++}
++
++/* Opcode: Recno P1 * *
++**
++** Push onto the stack an integer which is the first 4 bytes of the
++** the key to the current entry in a sequential scan of the database
++** file P1.  The sequential scan should have been started using the 
++** Next opcode.
++*/
++case OP_Recno: {
++  int i = pOp->p1;
++  Cursor *pC;
++  int v;
++
++  assert( i>=0 && i<p->nCursor );
++  pC = &p->aCsr[i];
++  sqliteVdbeCursorMoveto(pC);
++  pTos++;
++  if( pC->recnoIsValid ){
++    v = pC->lastRecno;
++  }else if( pC->pseudoTable ){
++    v = keyToInt(pC->iKey);
++  }else if( pC->nullRow || pC->pCursor==0 ){
++    pTos->flags = MEM_Null;
++    break;
++  }else{
++    assert( pC->pCursor!=0 );
++    sqliteBtreeKey(pC->pCursor, 0, sizeof(u32), (char*)&v);
++    v = keyToInt(v);
++  }
++  pTos->i = v;
++  pTos->flags = MEM_Int;
++  break;
++}
++
++/* Opcode: FullKey P1 * *
++**
++** Extract the complete key from the record that cursor P1 is currently
++** pointing to and push the key onto the stack as a string.
++**
++** Compare this opcode to Recno.  The Recno opcode extracts the first
++** 4 bytes of the key and pushes those bytes onto the stack as an
++** integer.  This instruction pushes the entire key as a string.
++**
++** This opcode may not be used on a pseudo-table.
++*/
++case OP_FullKey: {
++  int i = pOp->p1;
++  BtCursor *pCrsr;
++
++  assert( p->aCsr[i].keyAsData );
++  assert( !p->aCsr[i].pseudoTable );
++  assert( i>=0 && i<p->nCursor );
++  pTos++;
++  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
++    int amt;
++    char *z;
++
++    sqliteVdbeCursorMoveto(&p->aCsr[i]);
++    sqliteBtreeKeySize(pCrsr, &amt);
++    if( amt<=0 ){
++      rc = SQLITE_CORRUPT;
++      goto abort_due_to_error;
++    }
++    if( amt>NBFS ){
++      z = sqliteMallocRaw( amt );
++      if( z==0 ) goto no_mem;
++      pTos->flags = MEM_Str | MEM_Dyn;
++    }else{
++      z = pTos->zShort;
++      pTos->flags = MEM_Str | MEM_Short;
++    }
++    sqliteBtreeKey(pCrsr, 0, amt, z);
++    pTos->z = z;
++    pTos->n = amt;
++  }
++  break;
++}
++
++/* 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.
++*/
++case OP_NullRow: {
++  int i = pOp->p1;
++
++  assert( i>=0 && i<p->nCursor );
++  p->aCsr[i].nullRow = 1;
++  p->aCsr[i].recnoIsValid = 0;
++  break;
++}
++
++/* Opcode: Last P1 P2 *
++**
++** The next use of the Recno or Column or Next instruction for P1 
++** will refer to the last entry in the database table or index.
++** If the table or index is empty and P2>0, then jump immediately to P2.
++** If P2 is 0 or if the table or index is not empty, fall through
++** to the following instruction.
++*/
++case OP_Last: {
++  int i = pOp->p1;
++  Cursor *pC;
++  BtCursor *pCrsr;
++
++  assert( i>=0 && i<p->nCursor );
++  pC = &p->aCsr[i];
++  if( (pCrsr = pC->pCursor)!=0 ){
++    int res;
++    rc = sqliteBtreeLast(pCrsr, &res);
++    pC->nullRow = res;
++    pC->deferredMoveto = 0;
++    if( res && pOp->p2>0 ){
++      pc = pOp->p2 - 1;
++    }
++  }else{
++    pC->nullRow = 0;
++  }
++  break;
++}
++
++/* Opcode: Rewind P1 P2 *
++**
++** The next use of the Recno or Column or Next instruction for P1 
++** will refer to the first entry in the database table or index.
++** If the table or index is empty and P2>0, then jump immediately to P2.
++** If P2 is 0 or if the table or index is not empty, fall through
++** to the following instruction.
++*/
++case OP_Rewind: {
++  int i = pOp->p1;
++  Cursor *pC;
++  BtCursor *pCrsr;
++
++  assert( i>=0 && i<p->nCursor );
++  pC = &p->aCsr[i];
++  if( (pCrsr = pC->pCursor)!=0 ){
++    int res;
++    rc = sqliteBtreeFirst(pCrsr, &res);
++    pC->atFirst = res==0;
++    pC->nullRow = res;
++    pC->deferredMoveto = 0;
++    if( res && pOp->p2>0 ){
++      pc = pOp->p2 - 1;
++    }
++  }else{
++    pC->nullRow = 0;
++  }
++  break;
++}
++
++/* 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.
++**
++** See also: Prev
++*/
++/* 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.
++*/
++case OP_Prev:
++case OP_Next: {
++  Cursor *pC;
++  BtCursor *pCrsr;
++
++  CHECK_FOR_INTERRUPT;
++  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
++  pC = &p->aCsr[pOp->p1];
++  if( (pCrsr = pC->pCursor)!=0 ){
++    int res;
++    if( pC->nullRow ){
++      res = 1;
++    }else{
++      assert( pC->deferredMoveto==0 );
++      rc = pOp->opcode==OP_Next ? sqliteBtreeNext(pCrsr, &res) :
++                                  sqliteBtreePrevious(pCrsr, &res);
++      pC->nullRow = res;
++    }
++    if( res==0 ){
++      pc = pOp->p2 - 1;
++      sqlite_search_count++;
++    }
++  }else{
++    pC->nullRow = 1;
++  }
++  pC->recnoIsValid = 0;
++  break;
++}
++
++/* Opcode: IdxPut P1 P2 P3
++**
++** The top of the stack holds a SQL index key made using the
++** MakeIdxKey instruction.  This opcode writes that key into the
++** index P1.  Data for the entry is nil.
++**
++** If P2==1, then the key must be unique.  If the key is not unique,
++** the program aborts with a SQLITE_CONSTRAINT error and the database
++** is rolled back.  If P3 is not null, then it becomes part of the
++** error message returned with the SQLITE_CONSTRAINT.
++*/
++case OP_IdxPut: {
++  int i = pOp->p1;
++  BtCursor *pCrsr;
++  assert( pTos>=p->aStack );
++  assert( i>=0 && i<p->nCursor );
++  assert( pTos->flags & MEM_Str );
++  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
++    int nKey = pTos->n;
++    const char *zKey = pTos->z;
++    if( pOp->p2 ){
++      int res, n;
++      assert( nKey >= 4 );
++      rc = sqliteBtreeMoveto(pCrsr, zKey, nKey-4, &res);
++      if( rc!=SQLITE_OK ) goto abort_due_to_error;
++      while( res!=0 ){
++        int c;
++        sqliteBtreeKeySize(pCrsr, &n);
++        if( n==nKey
++           && sqliteBtreeKeyCompare(pCrsr, zKey, nKey-4, 4, &c)==SQLITE_OK
++           && c==0
++        ){
++          rc = SQLITE_CONSTRAINT;
++          if( pOp->p3 && pOp->p3[0] ){
++            sqliteSetString(&p->zErrMsg, pOp->p3, (char*)0);
++          }
++          goto abort_due_to_error;
++        }
++        if( res<0 ){
++          sqliteBtreeNext(pCrsr, &res);
++          res = +1;
++        }else{
++          break;
++        }
++      }
++    }
++    rc = sqliteBtreeInsert(pCrsr, zKey, nKey, "", 0);
++    assert( p->aCsr[i].deferredMoveto==0 );
++  }
++  Release(pTos);
++  pTos--;
++  break;
++}
++
++/* Opcode: IdxDelete P1 * *
++**
++** The top of the stack is an index key built using the MakeIdxKey opcode.
++** This opcode removes that entry from the index.
++*/
++case OP_IdxDelete: {
++  int i = pOp->p1;
++  BtCursor *pCrsr;
++  assert( pTos>=p->aStack );
++  assert( pTos->flags & MEM_Str );
++  assert( i>=0 && i<p->nCursor );
++  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
++    int rx, res;
++    rx = sqliteBtreeMoveto(pCrsr, pTos->z, pTos->n, &res);
++    if( rx==SQLITE_OK && res==0 ){
++      rc = sqliteBtreeDelete(pCrsr);
++    }
++    assert( p->aCsr[i].deferredMoveto==0 );
++  }
++  Release(pTos);
++  pTos--;
++  break;
++}
++
++/* Opcode: IdxRecno P1 * *
++**
++** Push onto the stack an integer which is the last 4 bytes of the
++** the key to the current entry in index P1.  These 4 bytes should
++** be the record number of the table entry to which this index entry
++** points.
++**
++** See also: Recno, MakeIdxKey.
++*/
++case OP_IdxRecno: {
++  int i = pOp->p1;
++  BtCursor *pCrsr;
++
++  assert( i>=0 && i<p->nCursor );
++  pTos++;
++  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
++    int v;
++    int sz;
++    assert( p->aCsr[i].deferredMoveto==0 );
++    sqliteBtreeKeySize(pCrsr, &sz);
++    if( sz<sizeof(u32) ){
++      pTos->flags = MEM_Null;
++    }else{
++      sqliteBtreeKey(pCrsr, sz - sizeof(u32), sizeof(u32), (char*)&v);
++      v = keyToInt(v);
++      pTos->i = v;
++      pTos->flags = MEM_Int;
++    }
++  }else{
++    pTos->flags = MEM_Null;
++  }
++  break;
++}
++
++/* Opcode: IdxGT P1 P2 *
++**
++** Compare the top of the stack against the key on the index entry that
++** cursor P1 is currently pointing to.  Ignore the last 4 bytes of the
++** index entry.  If the 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 *
++**
++** Compare the top of the stack against the key on the index entry that
++** cursor P1 is currently pointing to.  Ignore the last 4 bytes of the
++** index entry.  If the 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.
++*/
++/* Opcode: IdxLT P1 P2 *
++**
++** Compare the top of the stack against the key on the index entry that
++** cursor P1 is currently pointing to.  Ignore the last 4 bytes of the
++** index entry.  If the index entry is less 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.
++*/
++case OP_IdxLT:
++case OP_IdxGT:
++case OP_IdxGE: {
++  int i= pOp->p1;
++  BtCursor *pCrsr;
++
++  assert( i>=0 && i<p->nCursor );
++  assert( pTos>=p->aStack );
++  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
++    int res, rc;
++ 
++    Stringify(pTos);
++    assert( p->aCsr[i].deferredMoveto==0 );
++    rc = sqliteBtreeKeyCompare(pCrsr, pTos->z, pTos->n, 4, &res);
++    if( rc!=SQLITE_OK ){
++      break;
++    }
++    if( pOp->opcode==OP_IdxLT ){
++      res = -res;
++    }else if( 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 MakeIdxKey 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: {
++  int i = pOp->p1;
++  int k, n;
++  const char *z;
++
++  assert( pTos>=p->aStack );
++  assert( pTos->flags & MEM_Str );
++  z = pTos->z;
++  n = pTos->n;
++  for(k=0; k<n && i>0; i--){
++    if( z[k]=='a' ){
++      pc = pOp->p2-1;
++      break;
++    }
++    while( k<n && z[k] ){ k++; }
++    k++;
++  }
++  Release(pTos);
++  pTos--;
++  break;
++}
++
++/* Opcode: Destroy P1 P2 *
++**
++** 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
++** that is used to store tables create using CREATE TEMPORARY TABLE.
++**
++** See also: Clear
++*/
++case OP_Destroy: {
++  rc = sqliteBtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
++  break;
++}
++
++/* Opcode: Clear P1 P2 *
++**
++** Delete all contents of the database table or index whose root page
++** in the database file is given by P1.  But, unlike Destroy, do not
++** remove the table or index from the database file.
++**
++** The table being clear is in the main database file if P2==0.  If
++** P2==1 then the table to be clear is in the auxiliary database file
++** that is used to store tables create using CREATE TEMPORARY TABLE.
++**
++** See also: Destroy
++*/
++case OP_Clear: {
++  rc = sqliteBtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
++  break;
++}
++
++/* Opcode: CreateTable * P2 P3
++**
++** 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.
++**
++** The root page number is also written to a memory location that P3
++** points to.  This is the mechanism is used to write the root page
++** number into the parser's internal data structures that describe the
++** new table.
++**
++** 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
++** has an arbitrary key but no data.
++**
++** See also: CreateIndex
++*/
++/* Opcode: CreateIndex * P2 P3
++**
++** 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.
++**
++** See documentation on OP_CreateTable for additional information.
++*/
++case OP_CreateIndex:
++case OP_CreateTable: {
++  int pgno;
++  assert( pOp->p3!=0 && pOp->p3type==P3_POINTER );
++  assert( pOp->p2>=0 && pOp->p2<db->nDb );
++  assert( db->aDb[pOp->p2].pBt!=0 );
++  if( pOp->opcode==OP_CreateTable ){
++    rc = sqliteBtreeCreateTable(db->aDb[pOp->p2].pBt, &pgno);
++  }else{
++    rc = sqliteBtreeCreateIndex(db->aDb[pOp->p2].pBt, &pgno);
++  }
++  pTos++;
++  if( rc==SQLITE_OK ){
++    pTos->i = pgno;
++    pTos->flags = MEM_Int;
++    *(u32*)pOp->p3 = pgno;
++    pOp->p3 = 0;
++  }else{
++    pTos->flags = MEM_Null;
++  }
++  break;
++}
++
++/* Opcode: IntegrityCk P1 P2 *
++**
++** 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.
++**
++** P1 is the index of a set that contains the root page numbers
++** for all tables and indices in the main database file.  The set
++** is cleared by this opcode.  In other words, after this opcode
++** has executed, the set will be empty.
++**
++** If P2 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.
++*/
++case OP_IntegrityCk: {
++  int nRoot;
++  int *aRoot;
++  int iSet = pOp->p1;
++  Set *pSet;
++  int j;
++  HashElem *i;
++  char *z;
++
++  assert( iSet>=0 && iSet<p->nSet );
++  pTos++;
++  pSet = &p->aSet[iSet];
++  nRoot = sqliteHashCount(&pSet->hash);
++  aRoot = sqliteMallocRaw( sizeof(int)*(nRoot+1) );
++  if( aRoot==0 ) goto no_mem;
++  for(j=0, i=sqliteHashFirst(&pSet->hash); i; i=sqliteHashNext(i), j++){
++    toInt((char*)sqliteHashKey(i), &aRoot[j]);
++  }
++  aRoot[j] = 0;
++  sqliteHashClear(&pSet->hash);
++  pSet->prev = 0;
++  z = sqliteBtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot);
++  if( z==0 || z[0]==0 ){
++    if( z ) sqliteFree(z);
++    pTos->z = "ok";
++    pTos->n = 3;
++    pTos->flags = MEM_Str | MEM_Static;
++  }else{
++    pTos->z = z;
++    pTos->n = strlen(z) + 1;
++    pTos->flags = MEM_Str | MEM_Dyn;
++  }
++  sqliteFree(aRoot);
++  break;
++}
++
++/* Opcode: ListWrite * * *
++**
++** Write the integer on the top of the stack
++** into the temporary storage list.
++*/
++case OP_ListWrite: {
++  Keylist *pKeylist;
++  assert( pTos>=p->aStack );
++  pKeylist = p->pList;
++  if( pKeylist==0 || pKeylist->nUsed>=pKeylist->nKey ){
++    pKeylist = sqliteMallocRaw( sizeof(Keylist)+999*sizeof(pKeylist->aKey[0]) );
++    if( pKeylist==0 ) goto no_mem;
++    pKeylist->nKey = 1000;
++    pKeylist->nRead = 0;
++    pKeylist->nUsed = 0;
++    pKeylist->pNext = p->pList;
++    p->pList = pKeylist;
++  }
++  Integerify(pTos);
++  pKeylist->aKey[pKeylist->nUsed++] = pTos->i;
++  Release(pTos);
++  pTos--;
++  break;
++}
++
++/* Opcode: ListRewind * * *
++**
++** Rewind the temporary buffer back to the beginning.
++*/
++case OP_ListRewind: {
++  /* What this opcode codes, really, is reverse the order of the
++  ** linked list of Keylist structures so that they are read out
++  ** in the same order that they were read in. */
++  Keylist *pRev, *pTop;
++  pRev = 0;
++  while( p->pList ){
++    pTop = p->pList;
++    p->pList = pTop->pNext;
++    pTop->pNext = pRev;
++    pRev = pTop;
++  }
++  p->pList = pRev;
++  break;
++}
++
++/* Opcode: ListRead * P2 *
++**
++** Attempt to read an integer from the temporary storage buffer
++** and push it onto the stack.  If the storage buffer is empty, 
++** push nothing but instead jump to P2.
++*/
++case OP_ListRead: {
++  Keylist *pKeylist;
++  CHECK_FOR_INTERRUPT;
++  pKeylist = p->pList;
++  if( pKeylist!=0 ){
++    assert( pKeylist->nRead>=0 );
++    assert( pKeylist->nRead<pKeylist->nUsed );
++    assert( pKeylist->nRead<pKeylist->nKey );
++    pTos++;
++    pTos->i = pKeylist->aKey[pKeylist->nRead++];
++    pTos->flags = MEM_Int;
++    if( pKeylist->nRead>=pKeylist->nUsed ){
++      p->pList = pKeylist->pNext;
++      sqliteFree(pKeylist);
++    }
++  }else{
++    pc = pOp->p2 - 1;
++  }
++  break;
++}
++
++/* Opcode: ListReset * * *
++**
++** Reset the temporary storage buffer so that it holds nothing.
++*/
++case OP_ListReset: {
++  if( p->pList ){
++    sqliteVdbeKeylistFree(p->pList);
++    p->pList = 0;
++  }
++  break;
++}
++
++/* Opcode: ListPush * * * 
++**
++** Save the current Vdbe list such that it can be restored by a ListPop
++** opcode. The list is empty after this is executed.
++*/
++case OP_ListPush: {
++  p->keylistStackDepth++;
++  assert(p->keylistStackDepth > 0);
++  p->keylistStack = sqliteRealloc(p->keylistStack, 
++          sizeof(Keylist *) * p->keylistStackDepth);
++  if( p->keylistStack==0 ) goto no_mem;
++  p->keylistStack[p->keylistStackDepth - 1] = p->pList;
++  p->pList = 0;
++  break;
++}
++
++/* Opcode: ListPop * * * 
++**
++** Restore the Vdbe list to the state it was in when ListPush was last
++** executed.
++*/
++case OP_ListPop: {
++  assert(p->keylistStackDepth > 0);
++  p->keylistStackDepth--;
++  sqliteVdbeKeylistFree(p->pList);
++  p->pList = p->keylistStack[p->keylistStackDepth];
++  p->keylistStack[p->keylistStackDepth] = 0;
++  if( p->keylistStackDepth == 0 ){
++    sqliteFree(p->keylistStack);
++    p->keylistStack = 0;
++  }
++  break;
++}
++
++/* Opcode: ContextPush * * * 
++**
++** Save the current Vdbe context such that it can be restored by a ContextPop
++** opcode. The context stores the last insert row id, the last statement change
++** count, and the current statement change count.
++*/
++case OP_ContextPush: {
++  p->contextStackDepth++;
++  assert(p->contextStackDepth > 0);
++  p->contextStack = sqliteRealloc(p->contextStack, 
++          sizeof(Context) * p->contextStackDepth);
++  if( p->contextStack==0 ) goto no_mem;
++  p->contextStack[p->contextStackDepth - 1].lastRowid = p->db->lastRowid;
++  p->contextStack[p->contextStackDepth - 1].lsChange = p->db->lsChange;
++  p->contextStack[p->contextStackDepth - 1].csChange = p->db->csChange;
++  break;
++}
++
++/* Opcode: ContextPop * * * 
++**
++** Restore the Vdbe context to the state it was in when contextPush was last
++** executed. The context stores the last insert row id, the last statement
++** change count, and the current statement change count.
++*/
++case OP_ContextPop: {
++  assert(p->contextStackDepth > 0);
++  p->contextStackDepth--;
++  p->db->lastRowid = p->contextStack[p->contextStackDepth].lastRowid;
++  p->db->lsChange = p->contextStack[p->contextStackDepth].lsChange;
++  p->db->csChange = p->contextStack[p->contextStackDepth].csChange;
++  if( p->contextStackDepth == 0 ){
++    sqliteFree(p->contextStack);
++    p->contextStack = 0;
++  }
++  break;
++}
++
++/* Opcode: SortPut * * *
++**
++** The TOS is the key and the NOS is the data.  Pop both from the stack
++** and put them on the sorter.  The key and data should have been
++** made using SortMakeKey and SortMakeRec, respectively.
++*/
++case OP_SortPut: {
++  Mem *pNos = &pTos[-1];
++  Sorter *pSorter;
++  assert( pNos>=p->aStack );
++  if( Dynamicify(pTos) || Dynamicify(pNos) ) goto no_mem;
++  pSorter = sqliteMallocRaw( sizeof(Sorter) );
++  if( pSorter==0 ) goto no_mem;
++  pSorter->pNext = p->pSort;
++  p->pSort = pSorter;
++  assert( pTos->flags & MEM_Dyn );
++  pSorter->nKey = pTos->n;
++  pSorter->zKey = pTos->z;
++  assert( pNos->flags & MEM_Dyn );
++  pSorter->nData = pNos->n;
++  pSorter->pData = pNos->z;
++  pTos -= 2;
++  break;
++}
++
++/* Opcode: SortMakeRec P1 * *
++**
++** The top P1 elements are the arguments to a callback.  Form these
++** elements into a single data entry that can be stored on a sorter
++** using SortPut and later fed to a callback using SortCallback.
++*/
++case OP_SortMakeRec: {
++  char *z;
++  char **azArg;
++  int nByte;
++  int nField;
++  int i;
++  Mem *pRec;
++
++  nField = pOp->p1;
++  pRec = &pTos[1-nField];
++  assert( pRec>=p->aStack );
++  nByte = 0;
++  for(i=0; i<nField; i++, pRec++){
++    if( (pRec->flags & MEM_Null)==0 ){
++      Stringify(pRec);
++      nByte += pRec->n;
++    }
++  }
++  nByte += sizeof(char*)*(nField+1);
++  azArg = sqliteMallocRaw( nByte );
++  if( azArg==0 ) goto no_mem;
++  z = (char*)&azArg[nField+1];
++  for(pRec=&pTos[1-nField], i=0; i<nField; i++, pRec++){
++    if( pRec->flags & MEM_Null ){
++      azArg[i] = 0;
++    }else{
++      azArg[i] = z;
++      memcpy(z, pRec->z, pRec->n);
++      z += pRec->n;
++    }
++  }
++  popStack(&pTos, nField);
++  pTos++;
++  pTos->n = nByte;
++  pTos->z = (char*)azArg;
++  pTos->flags = MEM_Str | MEM_Dyn;
++  break;
++}
++
++/* Opcode: SortMakeKey * * P3
++**
++** Convert the top few entries of the stack into a sort key.  The
++** number of stack entries consumed is the number of characters in 
++** the string P3.  One character from P3 is prepended to each entry.
++** The first character of P3 is prepended to the element lowest in
++** the stack and the last character of P3 is prepended to the top of
++** the stack.  All stack entries are separated by a \000 character
++** in the result.  The whole key is terminated by two \000 characters
++** in a row.
++**
++** "N" is substituted in place of the P3 character for NULL values.
++**
++** See also the MakeKey and MakeIdxKey opcodes.
++*/
++case OP_SortMakeKey: {
++  char *zNewKey;
++  int nByte;
++  int nField;
++  int i, j, k;
++  Mem *pRec;
++
++  nField = strlen(pOp->p3);
++  pRec = &pTos[1-nField];
++  nByte = 1;
++  for(i=0; i<nField; i++, pRec++){
++    if( pRec->flags & MEM_Null ){
++      nByte += 2;
++    }else{
++      Stringify(pRec);
++      nByte += pRec->n+2;
++    }
++  }
++  zNewKey = sqliteMallocRaw( nByte );
++  if( zNewKey==0 ) goto no_mem;
++  j = 0;
++  k = 0;
++  for(pRec=&pTos[1-nField], i=0; i<nField; i++, pRec++){
++    if( pRec->flags & MEM_Null ){
++      zNewKey[j++] = 'N';
++      zNewKey[j++] = 0;
++      k++;
++    }else{
++      zNewKey[j++] = pOp->p3[k++];
++      memcpy(&zNewKey[j], pRec->z, pRec->n-1);
++      j += pRec->n-1;
++      zNewKey[j++] = 0;
++    }
++  }
++  zNewKey[j] = 0;
++  assert( j<nByte );
++  popStack(&pTos, nField);
++  pTos++;
++  pTos->n = nByte;
++  pTos->flags = MEM_Str|MEM_Dyn;
++  pTos->z = zNewKey;
++  break;
++}
++
++/* Opcode: Sort * * *
++**
++** Sort all elements on the sorter.  The algorithm is a
++** mergesort.
++*/
++case OP_Sort: {
++  int i;
++  Sorter *pElem;
++  Sorter *apSorter[NSORT];
++  for(i=0; i<NSORT; i++){
++    apSorter[i] = 0;
++  }
++  while( p->pSort ){
++    pElem = p->pSort;
++    p->pSort = pElem->pNext;
++    pElem->pNext = 0;
++    for(i=0; i<NSORT-1; i++){
++    if( apSorter[i]==0 ){
++        apSorter[i] = pElem;
++        break;
++      }else{
++        pElem = Merge(apSorter[i], pElem);
++        apSorter[i] = 0;
++      }
++    }
++    if( i>=NSORT-1 ){
++      apSorter[NSORT-1] = Merge(apSorter[NSORT-1],pElem);
++    }
++  }
++  pElem = 0;
++  for(i=0; i<NSORT; i++){
++    pElem = Merge(apSorter[i], pElem);
++  }
++  p->pSort = pElem;
++  break;
++}
++
++/* Opcode: SortNext * P2 *
++**
++** Push the data for the topmost element in the sorter onto the
++** stack, then remove the element from the sorter.  If the sorter
++** is empty, push nothing on the stack and instead jump immediately 
++** to instruction P2.
++*/
++case OP_SortNext: {
++  Sorter *pSorter = p->pSort;
++  CHECK_FOR_INTERRUPT;
++  if( pSorter!=0 ){
++    p->pSort = pSorter->pNext;
++    pTos++;
++    pTos->z = pSorter->pData;
++    pTos->n = pSorter->nData;
++    pTos->flags = MEM_Str|MEM_Dyn;
++    sqliteFree(pSorter->zKey);
++    sqliteFree(pSorter);
++  }else{
++    pc = pOp->p2 - 1;
++  }
++  break;
++}
++
++/* Opcode: SortCallback P1 * *
++**
++** The top of the stack contains a callback record built using
++** the SortMakeRec operation with the same P1 value as this
++** instruction.  Pop this record from the stack and invoke the
++** callback on it.
++*/
++case OP_SortCallback: {
++  assert( pTos>=p->aStack );
++  assert( pTos->flags & MEM_Str );
++  p->nCallback++;
++  p->pc = pc+1;
++  p->azResColumn = (char**)pTos->z;
++  assert( p->nResColumn==pOp->p1 );
++  p->popStack = 1;
++  p->pTos = pTos;
++  return SQLITE_ROW;
++}
++
++/* Opcode: SortReset * * *
++**
++** Remove any elements that remain on the sorter.
++*/
++case OP_SortReset: {
++  sqliteVdbeSorterReset(p);
++  break;
++}
++
++/* Opcode: FileOpen * * P3
++**
++** Open the file named by P3 for reading using the FileRead opcode.
++** If P3 is "stdin" then open standard input for reading.
++*/
++case OP_FileOpen: {
++  assert( pOp->p3!=0 );
++  if( p->pFile ){
++    if( p->pFile!=stdin ) fclose(p->pFile);
++    p->pFile = 0;
++  }
++  if( sqliteStrICmp(pOp->p3,"stdin")==0 ){
++    p->pFile = stdin;
++  }else{
++    p->pFile = fopen(pOp->p3, "r");
++  }
++  if( p->pFile==0 ){
++    sqliteSetString(&p->zErrMsg,"unable to open file: ", pOp->p3, (char*)0);
++    rc = SQLITE_ERROR;
++  }
++  break;
++}
++
++/* Opcode: FileRead P1 P2 P3
++**
++** Read a single line of input from the open file (the file opened using
++** FileOpen).  If we reach end-of-file, jump immediately to P2.  If
++** we are able to get another line, split the line apart using P3 as
++** a delimiter.  There should be P1 fields.  If the input line contains
++** more than P1 fields, ignore the excess.  If the input line contains
++** fewer than P1 fields, assume the remaining fields contain NULLs.
++**
++** Input ends if a line consists of just "\.".  A field containing only
++** "\N" is a null field.  The backslash \ character can be used be used
++** to escape newlines or the delimiter.
++*/
++case OP_FileRead: {
++  int n, eol, nField, i, c, nDelim;
++  char *zDelim, *z;
++  CHECK_FOR_INTERRUPT;
++  if( p->pFile==0 ) goto fileread_jump;
++  nField = pOp->p1;
++  if( nField<=0 ) goto fileread_jump;
++  if( nField!=p->nField || p->azField==0 ){
++    char **azField = sqliteRealloc(p->azField, sizeof(char*)*nField+1);
++    if( azField==0 ){ goto no_mem; }
++    p->azField = azField;
++    p->nField = nField;
++  }
++  n = 0;
++  eol = 0;
++  while( eol==0 ){
++    if( p->zLine==0 || n+200>p->nLineAlloc ){
++      char *zLine;
++      p->nLineAlloc = p->nLineAlloc*2 + 300;
++      zLine = sqliteRealloc(p->zLine, p->nLineAlloc);
++      if( zLine==0 ){
++        p->nLineAlloc = 0;
++        sqliteFree(p->zLine);
++        p->zLine = 0;
++        goto no_mem;
++      }
++      p->zLine = zLine;
++    }
++    if( vdbe_fgets(&p->zLine[n], p->nLineAlloc-n, p->pFile)==0 ){
++      eol = 1;
++      p->zLine[n] = 0;
++    }else{
++      int c;
++      while( (c = p->zLine[n])!=0 ){
++        if( c=='\\' ){
++          if( p->zLine[n+1]==0 ) break;
++          n += 2;
++        }else if( c=='\n' ){
++          p->zLine[n] = 0;
++          eol = 1;
++          break;
++        }else{
++          n++;
++        }
++      }
++    }
++  }
++  if( n==0 ) goto fileread_jump;
++  z = p->zLine;
++  if( z[0]=='\\' && z[1]=='.' && z[2]==0 ){
++    goto fileread_jump;
++  }
++  zDelim = pOp->p3;
++  if( zDelim==0 ) zDelim = "\t";
++  c = zDelim[0];
++  nDelim = strlen(zDelim);
++  p->azField[0] = z;
++  for(i=1; *z!=0 && i<=nField; i++){
++    int from, to;
++    from = to = 0;
++    if( z[0]=='\\' && z[1]=='N' 
++       && (z[2]==0 || strncmp(&z[2],zDelim,nDelim)==0) ){
++      if( i<=nField ) p->azField[i-1] = 0;
++      z += 2 + nDelim;
++      if( i<nField ) p->azField[i] = z;
++      continue;
++    }
++    while( z[from] ){
++      if( z[from]=='\\' && z[from+1]!=0 ){
++        int tx = z[from+1];
++        switch( tx ){
++          case 'b':  tx = '\b'; break;
++          case 'f':  tx = '\f'; break;
++          case 'n':  tx = '\n'; break;
++          case 'r':  tx = '\r'; break;
++          case 't':  tx = '\t'; break;
++          case 'v':  tx = '\v'; break;
++          default:   break;
++        }
++        z[to++] = tx;
++        from += 2;
++        continue;
++      }
++      if( z[from]==c && strncmp(&z[from],zDelim,nDelim)==0 ) break;
++      z[to++] = z[from++];
++    }
++    if( z[from] ){
++      z[to] = 0;
++      z += from + nDelim;
++      if( i<nField ) p->azField[i] = z;
++    }else{
++      z[to] = 0;
++      z = "";
++    }
++  }
++  while( i<nField ){
++    p->azField[i++] = 0;
++  }
++  break;
++
++  /* If we reach end-of-file, or if anything goes wrong, jump here.
++  ** This code will cause a jump to P2 */
++fileread_jump:
++  pc = pOp->p2 - 1;
++  break;
++}
++
++/* Opcode: FileColumn P1 * *
++**
++** Push onto the stack the P1-th column of the most recently read line
++** from the input file.
++*/
++case OP_FileColumn: {
++  int i = pOp->p1;
++  char *z;
++  assert( i>=0 && i<p->nField );
++  if( p->azField ){
++    z = p->azField[i];
++  }else{
++    z = 0;
++  }
++  pTos++;
++  if( z ){
++    pTos->n = strlen(z) + 1;
++    pTos->z = z;
++    pTos->flags = MEM_Str | MEM_Ephem;
++  }else{
++    pTos->flags = MEM_Null;
++  }
++  break;
++}
++
++/* 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: {
++  int i = pOp->p1;
++  Mem *pMem;
++  assert( pTos>=p->aStack );
++  if( i>=p->nMem ){
++    int nOld = p->nMem;
++    Mem *aMem;
++    p->nMem = i + 5;
++    aMem = sqliteRealloc(p->aMem, p->nMem*sizeof(p->aMem[0]));
++    if( aMem==0 ) goto no_mem;
++    if( aMem!=p->aMem ){
++      int j;
++      for(j=0; j<nOld; j++){
++        if( aMem[j].flags & MEM_Short ){
++          aMem[j].z = aMem[j].zShort;
++        }
++      }
++    }
++    p->aMem = aMem;
++    if( nOld<p->nMem ){
++      memset(&p->aMem[nOld], 0, sizeof(p->aMem[0])*(p->nMem-nOld));
++    }
++  }
++  Deephemeralize(pTos);
++  pMem = &p->aMem[i];
++  Release(pMem);
++  *pMem = *pTos;
++  if( pMem->flags & MEM_Dyn ){
++    if( pOp->p2 ){
++      pTos->flags = MEM_Null;
++    }else{
++      pMem->z = sqliteMallocRaw( pMem->n );
++      if( pMem->z==0 ) goto no_mem;
++      memcpy(pMem->z, pTos->z, pMem->n);
++    }
++  }else if( pMem->flags & MEM_Short ){
++    pMem->z = pMem->zShort;
++  }
++  if( pOp->p2 ){
++    Release(pTos);
++    pTos--;
++  }
++  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++;
++  memcpy(pTos, &p->aMem[i], sizeof(pTos[0])-NBFS);;
++  if( pTos->flags & MEM_Str ){
++    pTos->flags |= MEM_Ephem;
++    pTos->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short);
++  }
++  break;
++}
++
++/* Opcode: MemIncr P1 P2 *
++**
++** Increment the integer valued memory cell P1 by 1.  If P2 is not zero
++** and the result after the increment is greater than zero, then jump
++** to P2.
++**
++** This instruction throws an error if the memory cell is not initially
++** an integer.
++*/
++case OP_MemIncr: {
++  int i = pOp->p1;
++  Mem *pMem;
++  assert( i>=0 && i<p->nMem );
++  pMem = &p->aMem[i];
++  assert( pMem->flags==MEM_Int );
++  pMem->i++;
++  if( pOp->p2>0 && pMem->i>0 ){
++     pc = pOp->p2 - 1;
++  }
++  break;
++}
++
++/* Opcode: AggReset * P2 *
++**
++** Reset the aggregator so that it no longer contains any data.
++** Future aggregator elements will contain P2 values each.
++*/
++case OP_AggReset: {
++  sqliteVdbeAggReset(&p->agg);
++  p->agg.nMem = pOp->p2;
++  p->agg.apFunc = sqliteMalloc( p->agg.nMem*sizeof(p->agg.apFunc[0]) );
++  if( p->agg.apFunc==0 ) goto no_mem;
++  break;
++}
++
++/* Opcode: AggInit * P2 P3
++**
++** Initialize the function parameters for an aggregate function.
++** The aggregate will operate out of aggregate column P2.
++** P3 is a pointer to the FuncDef structure for the function.
++*/
++case OP_AggInit: {
++  int i = pOp->p2;
++  assert( i>=0 && i<p->agg.nMem );
++  p->agg.apFunc[i] = (FuncDef*)pOp->p3;
++  break;
++}
++
++/* Opcode: AggFunc * P2 P3
++**
++** Execute the step function for an aggregate.  The
++** function has P2 arguments.  P3 is a pointer to the FuncDef
++** structure that specifies the function.
++**
++** The top of the stack must be an integer which is the index of
++** the aggregate column that corresponds to this aggregate function.
++** Ideally, this index would be another parameter, but there are
++** no free parameters left.  The integer is popped from the stack.
++*/
++case OP_AggFunc: {
++  int n = pOp->p2;
++  int i;
++  Mem *pMem, *pRec;
++  char **azArgv = p->zArgv;
++  sqlite_func ctx;
++
++  assert( n>=0 );
++  assert( pTos->flags==MEM_Int );
++  pRec = &pTos[-n];
++  assert( pRec>=p->aStack );
++  for(i=0; i<n; i++, pRec++){
++    if( pRec->flags & MEM_Null ){
++      azArgv[i] = 0;
++    }else{
++      Stringify(pRec);
++      azArgv[i] = pRec->z;
++    }
++  }
++  i = pTos->i;
++  assert( i>=0 && i<p->agg.nMem );
++  ctx.pFunc = (FuncDef*)pOp->p3;
++  pMem = &p->agg.pCurrent->aMem[i];
++  ctx.s.z = pMem->zShort;  /* Space used for small aggregate contexts */
++  ctx.pAgg = pMem->z;
++  ctx.cnt = ++pMem->i;
++  ctx.isError = 0;
++  ctx.isStep = 1;
++  (ctx.pFunc->xStep)(&ctx, n, (const char**)azArgv);
++  pMem->z = ctx.pAgg;
++  pMem->flags = MEM_AggCtx;
++  popStack(&pTos, n+1);
++  if( ctx.isError ){
++    rc = SQLITE_ERROR;
++  }
++  break;
++}
++
++/* Opcode: AggFocus * P2 *
++**
++** Pop the top of the stack and use that as an aggregator key.  If
++** an aggregator with that same key already exists, then make the
++** aggregator the current aggregator and jump to P2.  If no aggregator
++** with the given key exists, create one and make it current but
++** do not jump.
++**
++** The order of aggregator opcodes is important.  The order is:
++** AggReset AggFocus AggNext.  In other words, you must execute
++** AggReset first, then zero or more AggFocus operations, then
++** zero or more AggNext operations.  You must not execute an AggFocus
++** in between an AggNext and an AggReset.
++*/
++case OP_AggFocus: {
++  AggElem *pElem;
++  char *zKey;
++  int nKey;
++
++  assert( pTos>=p->aStack );
++  Stringify(pTos);
++  zKey = pTos->z;
++  nKey = pTos->n;
++  pElem = sqliteHashFind(&p->agg.hash, zKey, nKey);
++  if( pElem ){
++    p->agg.pCurrent = pElem;
++    pc = pOp->p2 - 1;
++  }else{
++    AggInsert(&p->agg, zKey, nKey);
++    if( sqlite_malloc_failed ) goto no_mem;
++  }
++  Release(pTos);
++  pTos--;
++  break; 
++}
++
++/* Opcode: AggSet * P2 *
++**
++** Move the top of the stack into the P2-th field of the current
++** aggregate.  String values are duplicated into new memory.
++*/
++case OP_AggSet: {
++  AggElem *pFocus = AggInFocus(p->agg);
++  Mem *pMem;
++  int i = pOp->p2;
++  assert( pTos>=p->aStack );
++  if( pFocus==0 ) goto no_mem;
++  assert( i>=0 && i<p->agg.nMem );
++  Deephemeralize(pTos);
++  pMem = &pFocus->aMem[i];
++  Release(pMem);
++  *pMem = *pTos;
++  if( pMem->flags & MEM_Dyn ){
++    pTos->flags = MEM_Null;
++  }else if( pMem->flags & MEM_Short ){
++    pMem->z = pMem->zShort;
++  }
++  Release(pTos);
++  pTos--;
++  break;
++}
++
++/* Opcode: AggGet * P2 *
++**
++** Push a new entry onto the stack which is a copy of the P2-th field
++** of the current aggregate.  Strings are not duplicated so
++** string values will be ephemeral.
++*/
++case OP_AggGet: {
++  AggElem *pFocus = AggInFocus(p->agg);
++  Mem *pMem;
++  int i = pOp->p2;
++  if( pFocus==0 ) goto no_mem;
++  assert( i>=0 && i<p->agg.nMem );
++  pTos++;
++  pMem = &pFocus->aMem[i];
++  *pTos = *pMem;
++  if( pTos->flags & MEM_Str ){
++    pTos->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short);
++    pTos->flags |= MEM_Ephem;
++  }
++  if( pTos->flags & MEM_AggCtx ){
++    Release(pTos);
++    pTos->flags = MEM_Null;
++  }
++  break;
++}
++
++/* Opcode: AggNext * P2 *
++**
++** Make the next aggregate value the current aggregate.  The prior
++** aggregate is deleted.  If all aggregate values have been consumed,
++** jump to P2.
++**
++** The order of aggregator opcodes is important.  The order is:
++** AggReset AggFocus AggNext.  In other words, you must execute
++** AggReset first, then zero or more AggFocus operations, then
++** zero or more AggNext operations.  You must not execute an AggFocus
++** in between an AggNext and an AggReset.
++*/
++case OP_AggNext: {
++  CHECK_FOR_INTERRUPT;
++  if( p->agg.pSearch==0 ){
++    p->agg.pSearch = sqliteHashFirst(&p->agg.hash);
++  }else{
++    p->agg.pSearch = sqliteHashNext(p->agg.pSearch);
++  }
++  if( p->agg.pSearch==0 ){
++    pc = pOp->p2 - 1;
++  } else {
++    int i;
++    sqlite_func ctx;
++    Mem *aMem;
++    p->agg.pCurrent = sqliteHashData(p->agg.pSearch);
++    aMem = p->agg.pCurrent->aMem;
++    for(i=0; i<p->agg.nMem; i++){
++      int freeCtx;
++      if( p->agg.apFunc[i]==0 ) continue;
++      if( p->agg.apFunc[i]->xFinalize==0 ) continue;
++      ctx.s.flags = MEM_Null;
++      ctx.s.z = aMem[i].zShort;
++      ctx.pAgg = (void*)aMem[i].z;
++      freeCtx = aMem[i].z && aMem[i].z!=aMem[i].zShort;
++      ctx.cnt = aMem[i].i;
++      ctx.isStep = 0;
++      ctx.pFunc = p->agg.apFunc[i];
++      (*p->agg.apFunc[i]->xFinalize)(&ctx);
++      if( freeCtx ){
++        sqliteFree( aMem[i].z );
++      }
++      aMem[i] = ctx.s;
++      if( aMem[i].flags & MEM_Short ){
++        aMem[i].z = aMem[i].zShort;
++      }
++    }
++  }
++  break;
++}
++
++/* Opcode: SetInsert P1 * P3
++**
++** If Set P1 does not exist then create it.  Then insert value
++** P3 into that set.  If P3 is NULL, then insert the top of the
++** stack into the set.
++*/
++case OP_SetInsert: {
++  int i = pOp->p1;
++  if( p->nSet<=i ){
++    int k;
++    Set *aSet = sqliteRealloc(p->aSet, (i+1)*sizeof(p->aSet[0]) );
++    if( aSet==0 ) goto no_mem;
++    p->aSet = aSet;
++    for(k=p->nSet; k<=i; k++){
++      sqliteHashInit(&p->aSet[k].hash, SQLITE_HASH_BINARY, 1);
++    }
++    p->nSet = i+1;
++  }
++  if( pOp->p3 ){
++    sqliteHashInsert(&p->aSet[i].hash, pOp->p3, strlen(pOp->p3)+1, p);
++  }else{
++    assert( pTos>=p->aStack );
++    Stringify(pTos);
++    sqliteHashInsert(&p->aSet[i].hash, pTos->z, pTos->n, p);
++    Release(pTos);
++    pTos--;
++  }
++  if( sqlite_malloc_failed ) goto no_mem;
++  break;
++}
++
++/* Opcode: SetFound P1 P2 *
++**
++** Pop the stack once and compare the value popped off with the
++** contents of set P1.  If the element popped exists in set P1,
++** then jump to P2.  Otherwise fall through.
++*/
++case OP_SetFound: {
++  int i = pOp->p1;
++  assert( pTos>=p->aStack );
++  Stringify(pTos);
++  if( i>=0 && i<p->nSet && sqliteHashFind(&p->aSet[i].hash, pTos->z, pTos->n)){
++    pc = pOp->p2 - 1;
++  }
++  Release(pTos);
++  pTos--;
++  break;
++}
++
++/* Opcode: SetNotFound P1 P2 *
++**
++** Pop the stack once and compare the value popped off with the
++** contents of set P1.  If the element popped does not exists in 
++** set P1, then jump to P2.  Otherwise fall through.
++*/
++case OP_SetNotFound: {
++  int i = pOp->p1;
++  assert( pTos>=p->aStack );
++  Stringify(pTos);
++  if( i<0 || i>=p->nSet ||
++       sqliteHashFind(&p->aSet[i].hash, pTos->z, pTos->n)==0 ){
++    pc = pOp->p2 - 1;
++  }
++  Release(pTos);
++  pTos--;
++  break;
++}
++
++/* Opcode: SetFirst P1 P2 *
++**
++** Read the first element from set P1 and push it onto the stack.  If the
++** set is empty, push nothing and jump immediately to P2.  This opcode is
++** used in combination with OP_SetNext to loop over all elements of a set.
++*/
++/* Opcode: SetNext P1 P2 *
++**
++** Read the next element from set P1 and push it onto the stack.  If there
++** are no more elements in the set, do not do the push and fall through.
++** Otherwise, jump to P2 after pushing the next set element.
++*/
++case OP_SetFirst: 
++case OP_SetNext: {
++  Set *pSet;
++  CHECK_FOR_INTERRUPT;
++  if( pOp->p1<0 || pOp->p1>=p->nSet ){
++    if( pOp->opcode==OP_SetFirst ) pc = pOp->p2 - 1;
++    break;
++  }
++  pSet = &p->aSet[pOp->p1];
++  if( pOp->opcode==OP_SetFirst ){
++    pSet->prev = sqliteHashFirst(&pSet->hash);
++    if( pSet->prev==0 ){
++      pc = pOp->p2 - 1;
++      break;
++    }
++  }else{
++    if( pSet->prev ){
++      pSet->prev = sqliteHashNext(pSet->prev);
++    }
++    if( pSet->prev==0 ){
++      break;
++    }else{
++      pc = pOp->p2 - 1;
++    }
++  }
++  pTos++;
++  pTos->z = sqliteHashKey(pSet->prev);
++  pTos->n = sqliteHashKeysize(pSet->prev);
++  pTos->flags = MEM_Str | MEM_Ephem;
++  break;
++}
++
++/* 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: {
++  if( sqliteSafetyOff(db) ) goto abort_due_to_misuse; 
++  rc = sqliteRunVacuum(&p->zErrMsg, db);
++  if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
++  break;
++}
++
++/* Opcode: StackDepth * * *
++**
++** Push an integer onto the stack which is the depth of the stack prior
++** to that integer being pushed.
++*/
++case OP_StackDepth: {
++  int depth = (&pTos[1]) - p->aStack;
++  pTos++;
++  pTos->i = depth;
++  pTos->flags = MEM_Int;
++  break;
++}
++
++/* Opcode: StackReset * * *
++**
++** Pop a single integer off of the stack.  Then pop the stack
++** as many times as necessary to get the depth of the stack down
++** to the value of the integer that was popped.
++*/
++case OP_StackReset: {
++  int depth, goal;
++  assert( pTos>=p->aStack );
++  Integerify(pTos);
++  goal = pTos->i;
++  depth = (&pTos[1]) - p->aStack;
++  assert( goal<depth );
++  popStack(&pTos, depth-goal);
++  break;
++}
++
++/* An other opcode is illegal...
++*/
++default: {
++  sqlite_snprintf(sizeof(zBuf),zBuf,"%d",pOp->opcode);
++  sqliteSetString(&p->zErrMsg, "unknown opcode ", zBuf, (char*)0);
++  rc = SQLITE_INTERNAL;
++  break;
++}
++
++/*****************************************************************************
++** The cases of the switch statement above this line should all be indented
++** by 6 spaces.  But the left-most 6 spaces have been removed to improve the
++** readability.  From this point on down, the normal indentation rules are
++** restored.
++*****************************************************************************/
++    }
++
++#ifdef VDBE_PROFILE
++    {
++      long long elapse = hwtime() - start;
++      pOp->cycles += elapse;
++      pOp->cnt++;
++#if 0
++        fprintf(stdout, "%10lld ", elapse);
++        sqliteVdbePrintOp(stdout, origPc, &p->aOp[origPc]);
++#endif
++    }
++#endif
++
++    /* The following code adds nothing to the actual functionality
++    ** of the program.  It is only here for testing and debugging.
++    ** On the other hand, it does burn CPU cycles every time through
++    ** the evaluator loop.  So we can leave it out when NDEBUG is defined.
++    */
++#ifndef NDEBUG
++    /* Sanity checking on the top element of the stack */
++    if( pTos>=p->aStack ){
++      assert( pTos->flags!=0 );  /* Must define some type */
++      if( pTos->flags & MEM_Str ){
++        int x = pTos->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( pTos->z!=0 );      /* Strings must have a value */
++        /* Mem.z points to Mem.zShort iff the subtype is MEM_Short */
++        assert( (pTos->flags & MEM_Short)==0 || pTos->z==pTos->zShort );
++        assert( (pTos->flags & MEM_Short)!=0 || pTos->z!=pTos->zShort );
++      }else{
++        /* Cannot define a string subtype for non-string objects */
++        assert( (pTos->flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short))==0 );
++      }
++      /* MEM_Null excludes all other types */
++      assert( pTos->flags==MEM_Null || (pTos->flags&MEM_Null)==0 );
++    }
++    if( pc<-1 || pc>=p->nOp ){
++      sqliteSetString(&p->zErrMsg, "jump destination out of range", (char*)0);
++      rc = SQLITE_INTERNAL;
++    }
++    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:%d", pTos[i].i);
++        }else if( pTos[i].flags & MEM_Int ){
++          fprintf(p->trace, " i:%d", pTos[i].i);
++        }else if( pTos[i].flags & MEM_Real ){
++          fprintf(p->trace, " r:%g", pTos[i].r);
++        }else if( pTos[i].flags & MEM_Str ){
++          int j, k;
++          char zBuf[100];
++          zBuf[0] = ' ';
++          if( pTos[i].flags & MEM_Dyn ){
++            zBuf[1] = 'z';
++            assert( (pTos[i].flags & (MEM_Static|MEM_Ephem))==0 );
++          }else if( pTos[i].flags & MEM_Static ){
++            zBuf[1] = 't';
++            assert( (pTos[i].flags & (MEM_Dyn|MEM_Ephem))==0 );
++          }else if( pTos[i].flags & MEM_Ephem ){
++            zBuf[1] = 'e';
++            assert( (pTos[i].flags & (MEM_Static|MEM_Dyn))==0 );
++          }else{
++            zBuf[1] = 's';
++          }
++          zBuf[2] = '[';
++          k = 3;
++          for(j=0; j<20 && j<pTos[i].n; j++){
++            int c = pTos[i].z[j];
++            if( c==0 && j==pTos[i].n-1 ) break;
++            if( isprint(c) && !isspace(c) ){
++              zBuf[k++] = c;
++            }else{
++              zBuf[k++] = '.';
++            }
++          }
++          zBuf[k++] = ']';
++          zBuf[k++] = 0;
++          fprintf(p->trace, "%s", zBuf);
++        }else{
++          fprintf(p->trace, " ???");
++        }
++      }
++      if( rc!=0 ) fprintf(p->trace," rc=%d",rc);
++      fprintf(p->trace,"\n");
++    }
++#endif
++  }  /* The end of the for(;;) loop the loops through opcodes */
++
++  /* If we reach this point, it means that execution is finished.
++  */
++vdbe_halt:
++  CHECK_FOR_INTERRUPT
++  if( rc ){
++    p->rc = rc;
++    rc = SQLITE_ERROR;
++  }else{
++    rc = SQLITE_DONE;
++  }
++  p->magic = VDBE_MAGIC_HALT;
++  p->pTos = pTos;
++  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.
++  */
++no_mem:
++  sqliteSetString(&p->zErrMsg, "out of memory", (char*)0);
++  rc = SQLITE_NOMEM;
++  goto vdbe_halt;
++
++  /* Jump to here for an SQLITE_MISUSE error.
++  */
++abort_due_to_misuse:
++  rc = SQLITE_MISUSE;
++  /* Fall thru into abort_due_to_error */
++
++  /* Jump to here for any other kind of fatal error.  The "rc" variable
++  ** should hold the error number.
++  */
++abort_due_to_error:
++  if( p->zErrMsg==0 ){
++    if( sqlite_malloc_failed ) rc = SQLITE_NOMEM;
++    sqliteSetString(&p->zErrMsg, sqlite_error_string(rc), (char*)0);
++  }
++  goto vdbe_halt;
++
++  /* Jump to here if the sqlite_interrupt() API sets the interrupt
++  ** flag.
++  */
++abort_due_to_interrupt:
++  assert( db->flags & SQLITE_Interrupt );
++  db->flags &= ~SQLITE_Interrupt;
++  if( db->magic!=SQLITE_MAGIC_BUSY ){
++    rc = SQLITE_MISUSE;
++  }else{
++    rc = SQLITE_INTERRUPT;
++  }
++  sqliteSetString(&p->zErrMsg, sqlite_error_string(rc), (char*)0);
++  goto vdbe_halt;
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/vdbe.h
+@@ -0,0 +1,112 @@
++/*
++** 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.
++**
++*************************************************************************
++** Header file for the Virtual DataBase Engine (VDBE)
++**
++** This header defines the interface to the virtual database engine
++** or VDBE.  The VDBE implements an abstract machine that runs a
++** simple program to access and modify the underlying database.
++**
++** $Id$
++*/
++#ifndef _SQLITE_VDBE_H_
++#define _SQLITE_VDBE_H_
++#include <stdio.h>
++
++/*
++** A single VDBE is an opaque structure named "Vdbe".  Only routines
++** in the source file sqliteVdbe.c are allowed to see the insides
++** of this structure.
++*/
++typedef struct Vdbe Vdbe;
++
++/*
++** 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 */
++  int p1;             /* First operand */
++  int p2;             /* Second parameter (often the jump destination) */
++  char *p3;           /* Third parameter */
++  int p3type;         /* P3_STATIC, P3_DYNAMIC or P3_POINTER */
++#ifdef VDBE_PROFILE
++  int cnt;            /* Number of times this instruction was executed */
++  long long cycles;   /* Total time spend executing this instruction */
++#endif
++};
++typedef struct VdbeOp VdbeOp;
++
++/*
++** A smaller version of VdbeOp used for the VdbeAddOpList() function because
++** it takes up less space.
++*/
++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 */
++};
++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_POINTER  (-3)  /* P3 is a pointer to some structure or object */
++
++/*
++** The following macro converts a relative address in the p2 field
++** of a VdbeOp structure into a negative number so that 
++** sqliteVdbeAddOpList() knows that the address is relative.  Calling
++** the macro again restores the address.
++*/
++#define ADDR(X)  (-1-(X))
++
++/*
++** The makefile scans the vdbe.c source file and creates the "opcodes.h"
++** header file that defines a number for each opcode used by the VDBE.
++*/
++#include "opcodes.h"
++
++/*
++** Prototypes for the VDBE interface.  See comments on the implementation
++** for a description of what each of these routines does.
++*/
++Vdbe *sqliteVdbeCreate(sqlite*);
++void sqliteVdbeCreateCallback(Vdbe*, int*);
++int sqliteVdbeAddOp(Vdbe*,int,int,int);
++int sqliteVdbeOp3(Vdbe*,int,int,int,const char *zP3,int);
++int sqliteVdbeCode(Vdbe*,...);
++int sqliteVdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
++void sqliteVdbeChangeP1(Vdbe*, int addr, int P1);
++void sqliteVdbeChangeP2(Vdbe*, int addr, int P2);
++void sqliteVdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
++void sqliteVdbeDequoteP3(Vdbe*, int addr);
++int sqliteVdbeFindOp(Vdbe*, int, int);
++VdbeOp *sqliteVdbeGetOp(Vdbe*, int);
++int sqliteVdbeMakeLabel(Vdbe*);
++void sqliteVdbeDelete(Vdbe*);
++void sqliteVdbeMakeReady(Vdbe*,int,int);
++int sqliteVdbeExec(Vdbe*);
++int sqliteVdbeList(Vdbe*);
++int sqliteVdbeFinalize(Vdbe*,char**);
++void sqliteVdbeResolveLabel(Vdbe*, int);
++int sqliteVdbeCurrentAddr(Vdbe*);
++void sqliteVdbeTrace(Vdbe*,FILE*);
++void sqliteVdbeCompressSpace(Vdbe*,int);
++int sqliteVdbeReset(Vdbe*,char **);
++int sqliteVdbeSetVariables(Vdbe*,int,const char**);
++
++#endif
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/vdbeInt.h
+@@ -0,0 +1,303 @@
++/*
++** 2003 September 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.
++**
++*************************************************************************
++** This is the header file for information that is private to the
++** VDBE.  This information used to all be at the top of the single
++** source code file "vdbe.c".  When that file became too big (over
++** 6000 lines long) it was split up into several smaller files and
++** this header information was factored out.
++*/
++
++/*
++** When converting from the native format to the key format and back
++** again, in addition to changing the byte order we invert the high-order
++** bit of the most significant byte.  This causes negative numbers to
++** sort before positive numbers in the memcmp() function.
++*/
++#define keyToInt(X)   (sqliteVdbeByteSwap(X) ^ 0x80000000)
++#define intToKey(X)   (sqliteVdbeByteSwap((X) ^ 0x80000000))
++
++/*
++** The makefile scans this 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 *sqliteOpcodeNames[];
++
++/*
++** SQL is translated into a sequence of instructions to be
++** executed by a virtual machine.  Each instruction is an instance
++** of the following structure.
++*/
++typedef struct VdbeOp Op;
++
++/*
++** Boolean values
++*/
++typedef unsigned char Bool;
++
++/*
++** A cursor is a pointer into a single BTree within a database file.
++** The cursor can seek to a BTree entry with a particular key, or
++** loop over all entries of the Btree.  You can also insert new BTree
++** entries or retrieve the key or data from the entry that the cursor
++** is currently pointing to.
++** 
++** Every cursor that the virtual machine has open is represented by an
++** instance of the following structure.
++**
++** If the Cursor.isTriggerRow flag is set it means that this cursor is
++** really a single row that represents the NEW or OLD pseudo-table of
++** a row trigger.  The data for the row is stored in Cursor.pData and
++** the rowid is in Cursor.iKey.
++*/
++struct Cursor {
++  BtCursor *pCursor;    /* The cursor structure of the backend */
++  int lastRecno;        /* Last recno from a Next or NextIdx operation */
++  int nextRowid;        /* Next rowid returned by OP_NewRowid */
++  Bool recnoIsValid;    /* True if lastRecno is valid */
++  Bool keyAsData;       /* The OP_Column command works on key instead of data */
++  Bool atFirst;         /* True if pointing to first entry */
++  Bool useRandomRowid;  /* Generate new record numbers semi-randomly */
++  Bool nullRow;         /* True if pointing to a row with no data */
++  Bool nextRowidValid;  /* True if the nextRowid field is valid */
++  Bool pseudoTable;     /* This is a NEW or OLD pseudo-tables of a trigger */
++  Bool deferredMoveto;  /* A call to sqliteBtreeMoveto() is needed */
++  int movetoTarget;     /* Argument to the deferred sqliteBtreeMoveto() */
++  Btree *pBt;           /* Separate file holding temporary table */
++  int nData;            /* Number of bytes in pData */
++  char *pData;          /* Data for a NEW or OLD pseudo-table */
++  int iKey;             /* Key for the NEW or OLD pseudo-table row */
++};
++typedef struct Cursor Cursor;
++
++/*
++** A sorter builds a list of elements to be sorted.  Each element of
++** the list is an instance of the following structure.
++*/
++typedef struct Sorter Sorter;
++struct Sorter {
++  int nKey;           /* Number of bytes in the key */
++  char *zKey;         /* The key by which we will sort */
++  int nData;          /* Number of bytes in the data */
++  char *pData;        /* The data associated with this key */
++  Sorter *pNext;      /* Next in the list */
++};
++
++/* 
++** Number of buckets used for merge-sort.  
++*/
++#define NSORT 30
++
++/*
++** Number of bytes of string storage space available to each stack
++** layer without having to malloc.  NBFS is short for Number of Bytes
++** For Strings.
++*/
++#define NBFS 32
++
++/*
++** A single level of the stack or a single memory cell
++** is an instance of the following structure. 
++*/
++struct Mem {
++  int i;              /* Integer value */
++  int n;              /* Number of characters in string value, including '\0' */
++  int flags;          /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
++  double r;           /* Real value */
++  char *z;            /* String value */
++  char zShort[NBFS];  /* Space for short strings */
++};
++typedef struct Mem Mem;
++
++/*
++** Allowed values for Mem.flags
++*/
++#define MEM_Null      0x0001   /* Value is NULL */
++#define MEM_Str       0x0002   /* Value is a string */
++#define MEM_Int       0x0004   /* Value is an integer */
++#define MEM_Real      0x0008   /* Value is a real number */
++#define MEM_Dyn       0x0010   /* Need to call sqliteFree() on Mem.z */
++#define MEM_Static    0x0020   /* Mem.z points to a static string */
++#define MEM_Ephem     0x0040   /* Mem.z points to an ephemeral string */
++#define MEM_Short     0x0080   /* Mem.z points to Mem.zShort */
++
++/* The following MEM_ value appears only in AggElem.aMem.s.flag fields.
++** It indicates that the corresponding AggElem.aMem.z points to a
++** aggregate function context that needs to be finalized.
++*/
++#define MEM_AggCtx    0x0100   /* Mem.z points to an agg function context */
++
++/*
++** The "context" argument for a installable function.  A pointer to an
++** instance of this structure is the first argument to the routines used
++** implement the SQL functions.
++**
++** There is a typedef for this structure in sqlite.h.  So all routines,
++** even the public interface to SQLite, can use a pointer to this structure.
++** But this file is the only place where the internal details of this
++** structure are known.
++**
++** This structure is defined inside of vdbe.c because it uses substructures
++** (Mem) which are only defined there.
++*/
++struct sqlite_func {
++  FuncDef *pFunc;   /* Pointer to function information.  MUST BE FIRST */
++  Mem s;            /* The return value is stored here */
++  void *pAgg;       /* Aggregate context */
++  u8 isError;       /* Set to true for an error */
++  u8 isStep;        /* Current in the step function */
++  int cnt;          /* Number of times that the step function has been called */
++};
++
++/*
++** An Agg structure describes an Aggregator.  Each Agg consists of
++** zero or more Aggregator elements (AggElem).  Each AggElem contains
++** a key and one or more values.  The values are used in processing
++** aggregate functions in a SELECT.  The key is used to implement
++** the GROUP BY clause of a select.
++*/
++typedef struct Agg Agg;
++typedef struct AggElem AggElem;
++struct Agg {
++  int nMem;            /* Number of values stored in each AggElem */
++  AggElem *pCurrent;   /* The AggElem currently in focus */
++  HashElem *pSearch;   /* The hash element for pCurrent */
++  Hash hash;           /* Hash table of all aggregate elements */
++  FuncDef **apFunc;    /* Information about aggregate functions */
++};
++struct AggElem {
++  char *zKey;          /* The key to this AggElem */
++  int nKey;            /* Number of bytes in the key, including '\0' at end */
++  Mem aMem[1];         /* The values for this AggElem */
++};
++
++/*
++** A Set structure is used for quick testing to see if a value
++** is part of a small set.  Sets are used to implement code like
++** this:
++**            x.y IN ('hi','hoo','hum')
++*/
++typedef struct Set Set;
++struct Set {
++  Hash hash;             /* A set is just a hash table */
++  HashElem *prev;        /* Previously accessed hash elemen */
++};
++
++/*
++** A Keylist is a bunch of keys into a table.  The keylist can
++** grow without bound.  The keylist stores the ROWIDs of database
++** records that need to be deleted or updated.
++*/
++typedef struct Keylist Keylist;
++struct Keylist {
++  int nKey;         /* Number of slots in aKey[] */
++  int nUsed;        /* Next unwritten slot in aKey[] */
++  int nRead;        /* Next unread slot in aKey[] */
++  Keylist *pNext;   /* Next block of keys */
++  int aKey[1];      /* One or more keys.  Extra space allocated as needed */
++};
++
++/*
++** A Context stores the last insert rowid, the last statement change count,
++** and the current statement change count (i.e. changes since last statement).
++** Elements of Context structure type make up the ContextStack, which is
++** updated by the ContextPush and ContextPop opcodes (used by triggers)
++*/
++typedef struct Context Context;
++struct Context {
++  int lastRowid;    /* Last insert rowid (from db->lastRowid) */
++  int lsChange;     /* Last statement change count (from db->lsChange) */
++  int csChange;     /* Current statement change count (from db->csChange) */
++};
++
++/*
++** An instance of the virtual machine.  This structure contains the complete
++** state of the virtual machine.
++**
++** The "sqlite_vm" structure pointer that is returned by sqlite_compile()
++** is really a pointer to an instance of this structure.
++*/
++struct Vdbe {
++  sqlite *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 */
++  char **zArgv;       /* Text values used by the callback */
++  char **azColName;   /* Becomes the 4th parameter to callbacks */
++  int nCursor;        /* Number of slots in aCsr[] */
++  Cursor *aCsr;       /* One element of this array for each open cursor */
++  Sorter *pSort;      /* A linked list of objects to be sorted */
++  FILE *pFile;        /* At most one open file handler */
++  int nField;         /* Number of file fields */
++  char **azField;     /* Data for each file field */
++  int nVar;           /* Number of entries in azVariable[] */
++  char **azVar;       /* Values for the OP_Variable opcode */
++  int *anVar;         /* Length of each value in azVariable[] */
++  u8 *abVar;          /* TRUE if azVariable[i] needs to be sqliteFree()ed */
++  char *zLine;            /* A single line from the input file */
++  int nLineAlloc;         /* Number of spaces allocated for zLine */
++  int magic;              /* Magic number for sanity checking */
++  int nMem;               /* Number of memory locations currently allocated */
++  Mem *aMem;              /* The memory locations */
++  Agg agg;                /* Aggregate information */
++  int nSet;               /* Number of sets allocated */
++  Set *aSet;              /* An array of sets */
++  int nCallback;          /* Number of callbacks invoked so far */
++  Keylist *pList;         /* A list of ROWIDs */
++  int keylistStackDepth;  /* The size of the "keylist" stack */
++  Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */
++  int contextStackDepth;  /* The size of the "context" stack */
++  Context *contextStack;  /* Stack used by opcodes ContextPush & ContextPop*/
++  int pc;                 /* The program counter */
++  int rc;                 /* Value to return */
++  unsigned uniqueCnt;     /* Used by OP_MakeRecord when P2!=0 */
++  int errorAction;        /* Recovery action to do in case of an error */
++  int undoTransOnError;   /* If error, either ROLLBACK or COMMIT */
++  int inTempTrans;        /* True if temp database is transactioned */
++  int returnStack[100];   /* 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 explain;             /* True if EXPLAIN present on SQL command */
++};
++
++/*
++** The following are allowed values for Vdbe.magic
++*/
++#define VDBE_MAGIC_INIT     0x26bceaa5    /* Building a VDBE program */
++#define VDBE_MAGIC_RUN      0xbdf20da3    /* VDBE is ready to execute */
++#define VDBE_MAGIC_HALT     0x519c2973    /* VDBE has completed execution */
++#define VDBE_MAGIC_DEAD     0xb606c3c8    /* The VDBE has been deallocated */
++
++/*
++** Function prototypes
++*/
++void sqliteVdbeCleanupCursor(Cursor*);
++void sqliteVdbeSorterReset(Vdbe*);
++void sqliteVdbeAggReset(Agg*);
++void sqliteVdbeKeylistFree(Keylist*);
++void sqliteVdbePopStack(Vdbe*,int);
++int sqliteVdbeCursorMoveto(Cursor*);
++int sqliteVdbeByteSwap(int);
++#if !defined(NDEBUG) || defined(VDBE_PROFILE)
++void sqliteVdbePrintOp(FILE*, int, Op*);
++#endif
+--- /dev/null
++++ b/ext/sqlite/libsqlite/src/where.c
+@@ -0,0 +1,1235 @@
++/*
++** 2001 September 15
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This module contains C code that generates VDBE code used to process
++** the WHERE clause of SQL statements.
++**
++** $Id$
++*/
++#include "sqliteInt.h"
++
++/*
++** The query generator uses an array of instances of this structure to
++** help it analyze the subexpressions of the WHERE clause.  Each WHERE
++** clause subexpression is separated from the others by an AND operator.
++*/
++typedef struct ExprInfo ExprInfo;
++struct ExprInfo {
++  Expr *p;                /* Pointer to the subexpression */
++  u8 indexable;           /* True if this subexprssion is usable by an index */
++  short int idxLeft;      /* p->pLeft is a column in this table number. -1 if
++                          ** p->pLeft is not the column of any table */
++  short int idxRight;     /* p->pRight is a column in this table number. -1 if
++                          ** p->pRight is not the column of any table */
++  unsigned prereqLeft;    /* Bitmask of tables referenced by p->pLeft */
++  unsigned prereqRight;   /* Bitmask of tables referenced by p->pRight */
++  unsigned prereqAll;     /* Bitmask of tables referenced by p */
++};
++
++/*
++** An instance of the following structure keeps track of a mapping
++** between VDBE cursor numbers and bitmasks.  The VDBE cursor numbers
++** are small integers contained in SrcList_item.iCursor and Expr.iTable
++** fields.  For any given WHERE clause, we want to track which cursors
++** are being used, so we assign a single bit in a 32-bit word to track
++** that cursor.  Then a 32-bit integer is able to show the set of all
++** cursors being used.
++*/
++typedef struct ExprMaskSet ExprMaskSet;
++struct ExprMaskSet {
++  int n;          /* Number of assigned cursor values */
++  int ix[31];     /* Cursor assigned to each bit */
++};
++
++/*
++** Determine the number of elements in an array.
++*/
++#define ARRAYSIZE(X)  (sizeof(X)/sizeof(X[0]))
++
++/*
++** This routine is used to divide the WHERE expression into subexpressions
++** separated by the AND operator.
++**
++** aSlot[] is an array of subexpressions structures.
++** There are nSlot spaces left in this array.  This routine attempts to
++** split pExpr into subexpressions and fills aSlot[] with those subexpressions.
++** The return value is the number of slots filled.
++*/
++static int exprSplit(int nSlot, ExprInfo *aSlot, Expr *pExpr){
++  int cnt = 0;
++  if( pExpr==0 || nSlot<1 ) return 0;
++  if( nSlot==1 || pExpr->op!=TK_AND ){
++    aSlot[0].p = pExpr;
++    return 1;
++  }
++  if( pExpr->pLeft->op!=TK_AND ){
++    aSlot[0].p = pExpr->pLeft;
++    cnt = 1 + exprSplit(nSlot-1, &aSlot[1], pExpr->pRight);
++  }else{
++    cnt = exprSplit(nSlot, aSlot, pExpr->pLeft);
++    cnt += exprSplit(nSlot-cnt, &aSlot[cnt], pExpr->pRight);
++  }
++  return cnt;
++}
++
++/*
++** Initialize an expression mask set
++*/
++#define initMaskSet(P)  memset(P, 0, sizeof(*P))
++
++/*
++** Return the bitmask for the given cursor.  Assign a new bitmask
++** if this is the first time the cursor has been seen.
++*/
++static int getMask(ExprMaskSet *pMaskSet, int iCursor){
++  int i;
++  for(i=0; i<pMaskSet->n; i++){
++    if( pMaskSet->ix[i]==iCursor ) return 1<<i;
++  }
++  if( i==pMaskSet->n && i<ARRAYSIZE(pMaskSet->ix) ){
++    pMaskSet->n++;
++    pMaskSet->ix[i] = iCursor;
++    return 1<<i;
++  }
++  return 0;
++}
++
++/*
++** Destroy an expression mask set
++*/
++#define freeMaskSet(P)   /* NO-OP */
++
++/*
++** This routine walks (recursively) an expression tree and generates
++** a bitmask indicating which tables are used in that expression
++** tree.
++**
++** In order for this routine to work, the calling function must have
++** previously invoked sqliteExprResolveIds() on the expression.  See
++** the header comment on that routine for additional information.
++** The sqliteExprResolveIds() routines looks for column names and
++** sets their opcodes to TK_COLUMN and their Expr.iTable fields to
++** the VDBE cursor number of the table.
++*/
++static int exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){
++  unsigned int mask = 0;
++  if( p==0 ) return 0;
++  if( p->op==TK_COLUMN ){
++    mask = getMask(pMaskSet, p->iTable);
++    if( mask==0 ) mask = -1;
++    return mask;
++  }
++  if( p->pRight ){
++    mask = exprTableUsage(pMaskSet, p->pRight);
++  }
++  if( p->pLeft ){
++    mask |= exprTableUsage(pMaskSet, p->pLeft);
++  }
++  if( p->pList ){
++    int i;
++    for(i=0; i<p->pList->nExpr; i++){
++      mask |= exprTableUsage(pMaskSet, p->pList->a[i].pExpr);
++    }
++  }
++  return mask;
++}
++
++/*
++** Return TRUE if the given operator is one of the operators that is
++** allowed for an indexable WHERE clause.  The allowed operators are
++** "=", "<", ">", "<=", ">=", and "IN".
++*/
++static int allowedOp(int op){
++  switch( op ){
++    case TK_LT:
++    case TK_LE:
++    case TK_GT:
++    case TK_GE:
++    case TK_EQ:
++    case TK_IN:
++      return 1;
++    default:
++      return 0;
++  }
++}
++
++/*
++** The input to this routine is an ExprInfo structure with only the
++** "p" field filled in.  The job of this routine is to analyze the
++** subexpression and populate all the other fields of the ExprInfo
++** structure.
++*/
++static void exprAnalyze(ExprMaskSet *pMaskSet, ExprInfo *pInfo){
++  Expr *pExpr = pInfo->p;
++  pInfo->prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
++  pInfo->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
++  pInfo->prereqAll = exprTableUsage(pMaskSet, pExpr);
++  pInfo->indexable = 0;
++  pInfo->idxLeft = -1;
++  pInfo->idxRight = -1;
++  if( allowedOp(pExpr->op) && (pInfo->prereqRight & pInfo->prereqLeft)==0 ){
++    if( pExpr->pRight && pExpr->pRight->op==TK_COLUMN ){
++      pInfo->idxRight = pExpr->pRight->iTable;
++      pInfo->indexable = 1;
++    }
++    if( pExpr->pLeft->op==TK_COLUMN ){
++      pInfo->idxLeft = pExpr->pLeft->iTable;
++      pInfo->indexable = 1;
++    }
++  }
++}
++
++/*
++** pOrderBy is an ORDER BY clause from a SELECT statement.  pTab is the
++** left-most table in the FROM clause of that same SELECT statement and
++** the table has a cursor number of "base".
++**
++** This routine attempts to find an index for pTab that generates the
++** correct record sequence for the given ORDER BY clause.  The return value
++** is a pointer to an index that does the job.  NULL is returned if the
++** table has no index that will generate the correct sort order.
++**
++** If there are two or more indices that generate the correct sort order
++** and pPreferredIdx is one of those indices, then return pPreferredIdx.
++**
++** nEqCol is the number of columns of pPreferredIdx that are used as
++** equality constraints.  Any index returned must have exactly this same
++** set of columns.  The ORDER BY clause only matches index columns beyond the
++** the first nEqCol columns.
++**
++** All terms of the ORDER BY clause must be either ASC or DESC.  The
++** *pbRev value is set to 1 if the ORDER BY clause is all DESC and it is
++** set to 0 if the ORDER BY clause is all ASC.
++*/
++static Index *findSortingIndex(
++  Table *pTab,            /* The table to be sorted */
++  int base,               /* Cursor number for pTab */
++  ExprList *pOrderBy,     /* The ORDER BY clause */
++  Index *pPreferredIdx,   /* Use this index, if possible and not NULL */
++  int nEqCol,             /* Number of index columns used with == constraints */
++  int *pbRev              /* Set to 1 if ORDER BY is DESC */
++){
++  int i, j;
++  Index *pMatch;
++  Index *pIdx;
++  int sortOrder;
++
++  assert( pOrderBy!=0 );
++  assert( pOrderBy->nExpr>0 );
++  sortOrder = pOrderBy->a[0].sortOrder & SQLITE_SO_DIRMASK;
++  for(i=0; i<pOrderBy->nExpr; i++){
++    Expr *p;
++    if( (pOrderBy->a[i].sortOrder & SQLITE_SO_DIRMASK)!=sortOrder ){
++      /* Indices can only be used if all ORDER BY terms are either
++      ** DESC or ASC.  Indices cannot be used on a mixture. */
++      return 0;
++    }
++    if( (pOrderBy->a[i].sortOrder & SQLITE_SO_TYPEMASK)!=SQLITE_SO_UNK ){
++      /* Do not sort by index if there is a COLLATE clause */
++      return 0;
++    }
++    p = pOrderBy->a[i].pExpr;
++    if( p->op!=TK_COLUMN || p->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;
++    }
++  }
++  
++  /* If we get this far, it means the ORDER BY clause consists only of
++  ** ascending columns in the left-most table of the FROM clause.  Now
++  ** check for a matching index.
++  */
++  pMatch = 0;
++  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
++    int nExpr = pOrderBy->nExpr;
++    if( pIdx->nColumn < nEqCol || pIdx->nColumn < nExpr ) continue;
++    for(i=j=0; i<nEqCol; i++){
++      if( pPreferredIdx->aiColumn[i]!=pIdx->aiColumn[i] ) break;
++      if( j<nExpr && pOrderBy->a[j].pExpr->iColumn==pIdx->aiColumn[i] ){ j++; }
++    }
++    if( i<nEqCol ) continue;
++    for(i=0; i+j<nExpr; i++){
++      if( pOrderBy->a[i+j].pExpr->iColumn!=pIdx->aiColumn[i+nEqCol] ) break;
++    }
++    if( i+j>=nExpr ){
++      pMatch = pIdx;
++      if( pIdx==pPreferredIdx ) break;
++    }
++  }
++  if( pMatch && pbRev ){
++    *pbRev = sortOrder==SQLITE_SO_DESC;
++  }
++  return pMatch;
++}
++
++/*
++** Disable a term in the WHERE clause.  Except, do not disable the term
++** if it controls a LEFT OUTER JOIN and it did not originate in the ON
++** or USING clause of that join.
++**
++** Consider the term t2.z='ok' in the following queries:
++**
++**   (1)  SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x WHERE t2.z='ok'
++**   (2)  SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x AND t2.z='ok'
++**   (3)  SELECT * FROM t1, t2 WHERE t1.a=t2.x AND t2.z='ok'
++**
++** The t2.z='ok' is disabled in the in (2) because it did not originate
++** in the ON clause.  The term is disabled in (3) because it is not part
++** of a LEFT OUTER JOIN.  In (1), the term is not disabled.
++**
++** Disabling a term causes that term to not be tested in the inner loop
++** of the join.  Disabling is an optimization.  We would get the correct
++** results if nothing were ever disabled, but joins might run a little
++** slower.  The trick is to disable as much as we can without disabling
++** too much.  If we disabled in (1), we'd get the wrong answer.
++** See ticket #813.
++*/
++static void disableTerm(WhereLevel *pLevel, Expr **ppExpr){
++  Expr *pExpr = *ppExpr;
++  if( pLevel->iLeftJoin==0 || ExprHasProperty(pExpr, EP_FromJoin) ){
++    *ppExpr = 0;
++  }
++}
++
++/*
++** Generate the beginning of the loop used for WHERE clause processing.
++** The return value is a pointer to an (opaque) structure that contains
++** information needed to terminate the loop.  Later, the calling routine
++** should invoke sqliteWhereEnd() with the return value of this function
++** in order to complete the WHERE clause processing.
++**
++** If an error occurs, this routine returns NULL.
++**
++** The basic idea is to do a nested loop, one loop for each table in
++** the FROM clause of a select.  (INSERT and UPDATE statements are the
++** same as a SELECT with only a single table in the FROM clause.)  For
++** example, if the SQL is this:
++**
++**       SELECT * FROM t1, t2, t3 WHERE ...;
++**
++** Then the code generated is conceptually like the following:
++**
++**      foreach row1 in t1 do       \    Code generated
++**        foreach row2 in t2 do      |-- by sqliteWhereBegin()
++**          foreach row3 in t3 do   /
++**            ...
++**          end                     \    Code generated
++**        end                        |-- by sqliteWhereEnd()
++**      end                         /
++**
++** There are Btree cursors associated with each table.  t1 uses cursor
++** number pTabList->a[0].iCursor.  t2 uses the cursor pTabList->a[1].iCursor.
++** And so forth.  This routine generates code to open those VDBE cursors
++** and sqliteWhereEnd() generates the code to close them.
++**
++** If the WHERE clause is empty, the foreach loops must each scan their
++** entire tables.  Thus a three-way join is an O(N^3) operation.  But if
++** the tables have indices and there are terms in the WHERE clause that
++** refer to those indices, a complete table scan can be avoided and the
++** code will run much faster.  Most of the work of this routine is checking
++** to see if there are indices that can be used to speed up the loop.
++**
++** Terms of the WHERE clause are also used to limit which rows actually
++** make it to the "..." in the middle of the loop.  After each "foreach",
++** terms of the WHERE clause that use only terms in that loop and outer
++** loops are evaluated and if false a jump is made around all subsequent
++** inner loops (or around the "..." if the test occurs within the inner-
++** most loop)
++**
++** OUTER JOINS
++**
++** An outer join of tables t1 and t2 is conceptally coded as follows:
++**
++**    foreach row1 in t1 do
++**      flag = 0
++**      foreach row2 in t2 do
++**        start:
++**          ...
++**          flag = 1
++**      end
++**      if flag==0 then
++**        move the row2 cursor to a null row
++**        goto start
++**      fi
++**    end
++**
++** ORDER BY CLAUSE PROCESSING
++**
++** *ppOrderBy is a pointer to the ORDER BY clause of a SELECT statement,
++** if there is one.  If there is no ORDER BY clause or if this routine
++** is called from an UPDATE or DELETE statement, then ppOrderBy is NULL.
++**
++** If an index can be used so that the natural output order of the table
++** scan is correct for the ORDER BY clause, then that index is used and
++** *ppOrderBy is set to NULL.  This is an optimization that prevents an
++** unnecessary sort of the result set if an index appropriate for the
++** ORDER BY clause already exists.
++**
++** If the where clause loops cannot be arranged to provide the correct
++** output order, then the *ppOrderBy is unchanged.
++*/
++WhereInfo *sqliteWhereBegin(
++  Parse *pParse,       /* The parser context */
++  SrcList *pTabList,   /* A list of all tables to be scanned */
++  Expr *pWhere,        /* The WHERE clause */
++  int pushKey,         /* If TRUE, leave the table key on the stack */
++  ExprList **ppOrderBy /* An ORDER BY clause, or NULL */
++){
++  int i;                     /* Loop counter */
++  WhereInfo *pWInfo;         /* Will become the return value of this function */
++  Vdbe *v = pParse->pVdbe;   /* The virtual database engine */
++  int brk, cont = 0;         /* Addresses used during code generation */
++  int nExpr;           /* Number of subexpressions in the WHERE clause */
++  int loopMask;        /* One bit set for each outer loop */
++  int haveKey;         /* True if KEY is on the stack */
++  ExprMaskSet maskSet; /* The expression mask set */
++  int iDirectEq[32];   /* Term of the form ROWID==X for the N-th table */
++  int iDirectLt[32];   /* Term of the form ROWID<X or ROWID<=X */
++  int iDirectGt[32];   /* Term of the form ROWID>X or ROWID>=X */
++  ExprInfo aExpr[101]; /* The WHERE clause is divided into these expressions */
++
++  /* pushKey is only allowed if there is a single table (as in an INSERT or
++  ** UPDATE statement)
++  */
++  assert( pushKey==0 || pTabList->nSrc==1 );
++
++  /* Split the WHERE clause into separate subexpressions where each
++  ** subexpression is separated by an AND operator.  If the aExpr[]
++  ** array fills up, the last entry might point to an expression which
++  ** contains additional unfactored AND operators.
++  */
++  initMaskSet(&maskSet);
++  memset(aExpr, 0, sizeof(aExpr));
++  nExpr = exprSplit(ARRAYSIZE(aExpr), aExpr, pWhere);
++  if( nExpr==ARRAYSIZE(aExpr) ){
++    sqliteErrorMsg(pParse, "WHERE clause too complex - no more "
++       "than %d terms allowed", (int)ARRAYSIZE(aExpr)-1);
++    return 0;
++  }
++  
++  /* Allocate and initialize the WhereInfo structure that will become the
++  ** return value.
++  */
++  pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));
++  if( sqlite_malloc_failed ){
++    sqliteFree(pWInfo);
++    return 0;
++  }
++  pWInfo->pParse = pParse;
++  pWInfo->pTabList = pTabList;
++  pWInfo->peakNTab = pWInfo->savedNTab = pParse->nTab;
++  pWInfo->iBreak = sqliteVdbeMakeLabel(v);
++
++  /* 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 || sqliteExprIsConstant(pWhere)) ){
++    sqliteExprIfFalse(pParse, pWhere, pWInfo->iBreak, 1);
++    pWhere = 0;
++  }
++
++  /* Analyze all of the subexpressions.
++  */
++  for(i=0; i<nExpr; i++){
++    exprAnalyze(&maskSet, &aExpr[i]);
++
++    /* If we are executing a trigger body, remove all references to
++    ** new.* and old.* tables from the prerequisite masks.
++    */
++    if( pParse->trigStack ){
++      int x;
++      if( (x = pParse->trigStack->newIdx) >= 0 ){
++        int mask = ~getMask(&maskSet, x);
++        aExpr[i].prereqRight &= mask;
++        aExpr[i].prereqLeft &= mask;
++        aExpr[i].prereqAll &= mask;
++      }
++      if( (x = pParse->trigStack->oldIdx) >= 0 ){
++        int mask = ~getMask(&maskSet, x);
++        aExpr[i].prereqRight &= mask;
++        aExpr[i].prereqLeft &= mask;
++        aExpr[i].prereqAll &= mask;
++      }
++    }
++  }
++
++  /* Figure out what index to use (if any) for each nested loop.
++  ** Make pWInfo->a[i].pIdx point to the index to use for the i-th nested
++  ** loop where i==0 is the outer loop and i==pTabList->nSrc-1 is the inner
++  ** loop. 
++  **
++  ** If terms exist that use the ROWID of any table, then set the
++  ** iDirectEq[], iDirectLt[], or iDirectGt[] elements for that table
++  ** to the index of the term containing the ROWID.  We always prefer
++  ** to use a ROWID which can directly access a table rather than an
++  ** index which requires reading an index first to get the rowid then
++  ** doing a second read of the actual database table.
++  **
++  ** Actually, if there are more than 32 tables in the join, only the
++  ** first 32 tables are candidates for indices.  This is (again) due
++  ** to the limit of 32 bits in an integer bitmask.
++  */
++  loopMask = 0;
++  for(i=0; i<pTabList->nSrc && i<ARRAYSIZE(iDirectEq); i++){
++    int j;
++    int iCur = pTabList->a[i].iCursor;    /* The cursor for this table */
++    int mask = getMask(&maskSet, iCur);   /* Cursor mask for this table */
++    Table *pTab = pTabList->a[i].pTab;
++    Index *pIdx;
++    Index *pBestIdx = 0;
++    int bestScore = 0;
++
++    /* Check to see if there is an expression that uses only the
++    ** ROWID field of this table.  For terms of the form ROWID==expr
++    ** set iDirectEq[i] to the index of the term.  For terms of the
++    ** form ROWID<expr or ROWID<=expr set iDirectLt[i] to the term index.
++    ** For terms like ROWID>expr or ROWID>=expr set iDirectGt[i].
++    **
++    ** (Added:) Treat ROWID IN expr like ROWID=expr.
++    */
++    pWInfo->a[i].iCur = -1;
++    iDirectEq[i] = -1;
++    iDirectLt[i] = -1;
++    iDirectGt[i] = -1;
++    for(j=0; j<nExpr; j++){
++      if( aExpr[j].idxLeft==iCur && aExpr[j].p->pLeft->iColumn<0
++            && (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
++        switch( aExpr[j].p->op ){
++          case TK_IN:
++          case TK_EQ: iDirectEq[i] = j; break;
++          case TK_LE:
++          case TK_LT: iDirectLt[i] = j; break;
++          case TK_GE:
++          case TK_GT: iDirectGt[i] = j;  break;
++        }
++      }
++      if( aExpr[j].idxRight==iCur && aExpr[j].p->pRight->iColumn<0
++            && (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ){
++        switch( aExpr[j].p->op ){
++          case TK_EQ: iDirectEq[i] = j;  break;
++          case TK_LE:
++          case TK_LT: iDirectGt[i] = j;  break;
++          case TK_GE:
++          case TK_GT: iDirectLt[i] = j;  break;
++        }
++      }
++    }
++    if( iDirectEq[i]>=0 ){
++      loopMask |= mask;
++      pWInfo->a[i].pIdx = 0;
++      continue;
++    }
++
++    /* Do a search for usable indices.  Leave pBestIdx pointing to
++    ** the "best" index.  pBestIdx is left set to NULL if no indices
++    ** are usable.
++    **
++    ** The best index is determined as follows.  For each of the
++    ** left-most terms that is fixed by an equality operator, add
++    ** 8 to the score.  The right-most term of the index may be
++    ** constrained by an inequality.  Add 1 if for an "x<..." constraint
++    ** and add 2 for an "x>..." constraint.  Chose the index that
++    ** gives the best score.
++    **
++    ** This scoring system is designed so that the score can later be
++    ** used to determine how the index is used.  If the score&7 is 0
++    ** then all constraints are equalities.  If score&1 is not 0 then
++    ** there is an inequality used as a termination key.  (ex: "x<...")
++    ** If score&2 is not 0 then there is an inequality used as the
++    ** start key.  (ex: "x>...").  A score or 4 is the special case
++    ** of an IN operator constraint.  (ex:  "x IN ...").
++    **
++    ** The IN operator (as in "<expr> IN (...)") is treated the same as
++    ** an equality comparison except that it can only be used on the
++    ** left-most column of an index and other terms of the WHERE clause
++    ** cannot be used in conjunction with the IN operator to help satisfy
++    ** other columns of the index.
++    */
++    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
++      int eqMask = 0;  /* Index columns covered by an x=... term */
++      int ltMask = 0;  /* Index columns covered by an x<... term */
++      int gtMask = 0;  /* Index columns covered by an x>... term */
++      int inMask = 0;  /* Index columns covered by an x IN .. term */
++      int nEq, m, score;
++
++      if( pIdx->nColumn>32 ) continue;  /* Ignore indices too many columns */
++      for(j=0; j<nExpr; j++){
++        if( aExpr[j].idxLeft==iCur 
++             && (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
++          int iColumn = aExpr[j].p->pLeft->iColumn;
++          int k;
++          for(k=0; k<pIdx->nColumn; k++){
++            if( pIdx->aiColumn[k]==iColumn ){
++              switch( aExpr[j].p->op ){
++                case TK_IN: {
++                  if( k==0 ) inMask |= 1;
++                  break;
++                }
++                case TK_EQ: {
++                  eqMask |= 1<<k;
++                  break;
++                }
++                case TK_LE:
++                case TK_LT: {
++                  ltMask |= 1<<k;
++                  break;
++                }
++                case TK_GE:
++                case TK_GT: {
++                  gtMask |= 1<<k;
++                  break;
++                }
++                default: {
++                  /* CANT_HAPPEN */
++                  assert( 0 );
++                  break;
++                }
++              }
++              break;
++            }
++          }
++        }
++        if( aExpr[j].idxRight==iCur 
++             && (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ){
++          int iColumn = aExpr[j].p->pRight->iColumn;
++          int k;
++          for(k=0; k<pIdx->nColumn; k++){
++            if( pIdx->aiColumn[k]==iColumn ){
++              switch( aExpr[j].p->op ){
++                case TK_EQ: {
++                  eqMask |= 1<<k;
++                  break;
++                }
++                case TK_LE:
++                case TK_LT: {
++                  gtMask |= 1<<k;
++                  break;
++                }
++                case TK_GE:
++                case TK_GT: {
++                  ltMask |= 1<<k;
++                  break;
++                }
++                default: {
++                  /* CANT_HAPPEN */
++                  assert( 0 );
++                  break;
++                }
++              }
++              break;
++            }
++          }
++        }
++      }
++
++      /* The following loop ends with nEq set to the number of columns
++      ** on the left of the index with == constraints.
++      */
++      for(nEq=0; nEq<pIdx->nColumn; nEq++){
++        m = (1<<(nEq+1))-1;
++        if( (m & eqMask)!=m ) break;
++      }
++      score = nEq*8;   /* Base score is 8 times number of == constraints */
++      m = 1<<nEq;
++      if( m & ltMask ) score++;    /* Increase score for a < constraint */
++      if( m & gtMask ) score+=2;   /* Increase score for a > constraint */
++      if( score==0 && inMask ) score = 4;  /* Default score for IN constraint */
++      if( score>bestScore ){
++        pBestIdx = pIdx;
++        bestScore = score;
++      }
++    }
++    pWInfo->a[i].pIdx = pBestIdx;
++    pWInfo->a[i].score = bestScore;
++    pWInfo->a[i].bRev = 0;
++    loopMask |= mask;
++    if( pBestIdx ){
++      pWInfo->a[i].iCur = pParse->nTab++;
++      pWInfo->peakNTab = pParse->nTab;
++    }
++  }
++
++  /* Check to see if the ORDER BY clause is or can be satisfied by the
++  ** use of an index on the first table.
++  */
++  if( ppOrderBy && *ppOrderBy && pTabList->nSrc>0 ){
++     Index *pSortIdx;
++     Index *pIdx;
++     Table *pTab;
++     int bRev = 0;
++
++     pTab = pTabList->a[0].pTab;
++     pIdx = pWInfo->a[0].pIdx;
++     if( pIdx && pWInfo->a[0].score==4 ){
++       /* If there is already an IN index on the left-most table,
++       ** it will not give the correct sort order.
++       ** So, pretend that no suitable index is found.
++       */
++       pSortIdx = 0;
++     }else if( iDirectEq[0]>=0 || iDirectLt[0]>=0 || iDirectGt[0]>=0 ){
++       /* If the left-most column is accessed using its ROWID, then do
++       ** not try to sort by index.
++       */
++       pSortIdx = 0;
++     }else{
++       int nEqCol = (pWInfo->a[0].score+4)/8;
++       pSortIdx = findSortingIndex(pTab, pTabList->a[0].iCursor, 
++                                   *ppOrderBy, pIdx, nEqCol, &bRev);
++     }
++     if( pSortIdx && (pIdx==0 || pIdx==pSortIdx) ){
++       if( pIdx==0 ){
++         pWInfo->a[0].pIdx = pSortIdx;
++         pWInfo->a[0].iCur = pParse->nTab++;
++         pWInfo->peakNTab = pParse->nTab;
++       }
++       pWInfo->a[0].bRev = bRev;
++       *ppOrderBy = 0;
++     }
++  }
++
++  /* Open all tables in the pTabList and all indices used by those tables.
++  */
++  for(i=0; i<pTabList->nSrc; i++){
++    Table *pTab;
++    Index *pIx;
++
++    pTab = pTabList->a[i].pTab;
++    if( pTab->isTransient || pTab->pSelect ) continue;
++    sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
++    sqliteVdbeOp3(v, OP_OpenRead, pTabList->a[i].iCursor, pTab->tnum,
++                     pTab->zName, P3_STATIC);
++    sqliteCodeVerifySchema(pParse, pTab->iDb);
++    if( (pIx = pWInfo->a[i].pIdx)!=0 ){
++      sqliteVdbeAddOp(v, OP_Integer, pIx->iDb, 0);
++      sqliteVdbeOp3(v, OP_OpenRead, pWInfo->a[i].iCur, pIx->tnum, pIx->zName,0);
++    }
++  }
++
++  /* Generate the code to do the search
++  */
++  loopMask = 0;
++  for(i=0; i<pTabList->nSrc; i++){
++    int j, k;
++    int iCur = pTabList->a[i].iCursor;
++    Index *pIdx;
++    WhereLevel *pLevel = &pWInfo->a[i];
++
++    /* 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( i>0 && (pTabList->a[i-1].jointype & JT_LEFT)!=0 ){
++      if( !pParse->nMem ) pParse->nMem++;
++      pLevel->iLeftJoin = pParse->nMem++;
++      sqliteVdbeAddOp(v, OP_String, 0, 0);
++      sqliteVdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);
++    }
++
++    pIdx = pLevel->pIdx;
++    pLevel->inOp = OP_Noop;
++    if( i<ARRAYSIZE(iDirectEq) && iDirectEq[i]>=0 ){
++      /* Case 1:  We can directly reference a single row using an
++      **          equality comparison against the ROWID field.  Or
++      **          we reference multiple rows using a "rowid IN (...)"
++      **          construct.
++      */
++      k = iDirectEq[i];
++      assert( k<nExpr );
++      assert( aExpr[k].p!=0 );
++      assert( aExpr[k].idxLeft==iCur || aExpr[k].idxRight==iCur );
++      brk = pLevel->brk = sqliteVdbeMakeLabel(v);
++      if( aExpr[k].idxLeft==iCur ){
++        Expr *pX = aExpr[k].p;
++        if( pX->op!=TK_IN ){
++          sqliteExprCode(pParse, aExpr[k].p->pRight);
++        }else if( pX->pList ){
++          sqliteVdbeAddOp(v, OP_SetFirst, pX->iTable, brk);
++          pLevel->inOp = OP_SetNext;
++          pLevel->inP1 = pX->iTable;
++          pLevel->inP2 = sqliteVdbeCurrentAddr(v);
++        }else{
++          assert( pX->pSelect );
++          sqliteVdbeAddOp(v, OP_Rewind, pX->iTable, brk);
++          sqliteVdbeAddOp(v, OP_KeyAsData, pX->iTable, 1);
++          pLevel->inP2 = sqliteVdbeAddOp(v, OP_FullKey, pX->iTable, 0);
++          pLevel->inOp = OP_Next;
++          pLevel->inP1 = pX->iTable;
++        }
++      }else{
++        sqliteExprCode(pParse, aExpr[k].p->pLeft);
++      }
++      disableTerm(pLevel, &aExpr[k].p);
++      cont = pLevel->cont = sqliteVdbeMakeLabel(v);
++      sqliteVdbeAddOp(v, OP_MustBeInt, 1, brk);
++      haveKey = 0;
++      sqliteVdbeAddOp(v, OP_NotExists, iCur, brk);
++      pLevel->op = OP_Noop;
++    }else if( pIdx!=0 && pLevel->score>0 && pLevel->score%4==0 ){
++      /* Case 2:  There is an index and all terms of the WHERE clause that
++      **          refer to the index use the "==" or "IN" operators.
++      */
++      int start;
++      int testOp;
++      int nColumn = (pLevel->score+4)/8;
++      brk = pLevel->brk = sqliteVdbeMakeLabel(v);
++      for(j=0; j<nColumn; j++){
++        for(k=0; k<nExpr; k++){
++          Expr *pX = aExpr[k].p;
++          if( pX==0 ) continue;
++          if( aExpr[k].idxLeft==iCur
++             && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight 
++             && pX->pLeft->iColumn==pIdx->aiColumn[j]
++          ){
++            if( pX->op==TK_EQ ){
++              sqliteExprCode(pParse, pX->pRight);
++              disableTerm(pLevel, &aExpr[k].p);
++              break;
++            }
++            if( pX->op==TK_IN && nColumn==1 ){
++              if( pX->pList ){
++                sqliteVdbeAddOp(v, OP_SetFirst, pX->iTable, brk);
++                pLevel->inOp = OP_SetNext;
++                pLevel->inP1 = pX->iTable;
++                pLevel->inP2 = sqliteVdbeCurrentAddr(v);
++              }else{
++                assert( pX->pSelect );
++                sqliteVdbeAddOp(v, OP_Rewind, pX->iTable, brk);
++                sqliteVdbeAddOp(v, OP_KeyAsData, pX->iTable, 1);
++                pLevel->inP2 = sqliteVdbeAddOp(v, OP_FullKey, pX->iTable, 0);
++                pLevel->inOp = OP_Next;
++                pLevel->inP1 = pX->iTable;
++              }
++              disableTerm(pLevel, &aExpr[k].p);
++              break;
++            }
++          }
++          if( aExpr[k].idxRight==iCur
++             && aExpr[k].p->op==TK_EQ
++             && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
++             && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j]
++          ){
++            sqliteExprCode(pParse, aExpr[k].p->pLeft);
++            disableTerm(pLevel, &aExpr[k].p);
++            break;
++          }
++        }
++      }
++      pLevel->iMem = pParse->nMem++;
++      cont = pLevel->cont = sqliteVdbeMakeLabel(v);
++      sqliteVdbeAddOp(v, OP_NotNull, -nColumn, sqliteVdbeCurrentAddr(v)+3);
++      sqliteVdbeAddOp(v, OP_Pop, nColumn, 0);
++      sqliteVdbeAddOp(v, OP_Goto, 0, brk);
++      sqliteVdbeAddOp(v, OP_MakeKey, nColumn, 0);
++      sqliteAddIdxKeyType(v, pIdx);
++      if( nColumn==pIdx->nColumn || pLevel->bRev ){
++        sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
++        testOp = OP_IdxGT;
++      }else{
++        sqliteVdbeAddOp(v, OP_Dup, 0, 0);
++        sqliteVdbeAddOp(v, OP_IncrKey, 0, 0);
++        sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
++        testOp = OP_IdxGE;
++      }
++      if( pLevel->bRev ){
++        /* Scan in reverse order */
++        sqliteVdbeAddOp(v, OP_IncrKey, 0, 0);
++        sqliteVdbeAddOp(v, OP_MoveLt, pLevel->iCur, brk);
++        start = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
++        sqliteVdbeAddOp(v, OP_IdxLT, pLevel->iCur, brk);
++        pLevel->op = OP_Prev;
++      }else{
++        /* Scan in the forward order */
++        sqliteVdbeAddOp(v, OP_MoveTo, pLevel->iCur, brk);
++        start = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
++        sqliteVdbeAddOp(v, testOp, pLevel->iCur, brk);
++        pLevel->op = OP_Next;
++      }
++      sqliteVdbeAddOp(v, OP_RowKey, pLevel->iCur, 0);
++      sqliteVdbeAddOp(v, OP_IdxIsNull, nColumn, cont);
++      sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
++      if( i==pTabList->nSrc-1 && pushKey ){
++        haveKey = 1;
++      }else{
++        sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
++        haveKey = 0;
++      }
++      pLevel->p1 = pLevel->iCur;
++      pLevel->p2 = start;
++    }else if( i<ARRAYSIZE(iDirectLt) && (iDirectLt[i]>=0 || iDirectGt[i]>=0) ){
++      /* Case 3:  We have an inequality comparison against the ROWID field.
++      */
++      int testOp = OP_Noop;
++      int start;
++
++      brk = pLevel->brk = sqliteVdbeMakeLabel(v);
++      cont = pLevel->cont = sqliteVdbeMakeLabel(v);
++      if( iDirectGt[i]>=0 ){
++        k = iDirectGt[i];
++        assert( k<nExpr );
++        assert( aExpr[k].p!=0 );
++        assert( aExpr[k].idxLeft==iCur || aExpr[k].idxRight==iCur );
++        if( aExpr[k].idxLeft==iCur ){
++          sqliteExprCode(pParse, aExpr[k].p->pRight);
++        }else{
++          sqliteExprCode(pParse, aExpr[k].p->pLeft);
++        }
++        sqliteVdbeAddOp(v, OP_ForceInt,
++          aExpr[k].p->op==TK_LT || aExpr[k].p->op==TK_GT, brk);
++        sqliteVdbeAddOp(v, OP_MoveTo, iCur, brk);
++        disableTerm(pLevel, &aExpr[k].p);
++      }else{
++        sqliteVdbeAddOp(v, OP_Rewind, iCur, brk);
++      }
++      if( iDirectLt[i]>=0 ){
++        k = iDirectLt[i];
++        assert( k<nExpr );
++        assert( aExpr[k].p!=0 );
++        assert( aExpr[k].idxLeft==iCur || aExpr[k].idxRight==iCur );
++        if( aExpr[k].idxLeft==iCur ){
++          sqliteExprCode(pParse, aExpr[k].p->pRight);
++        }else{
++          sqliteExprCode(pParse, aExpr[k].p->pLeft);
++        }
++        /* sqliteVdbeAddOp(v, OP_MustBeInt, 0, sqliteVdbeCurrentAddr(v)+1); */
++        pLevel->iMem = pParse->nMem++;
++        sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
++        if( aExpr[k].p->op==TK_LT || aExpr[k].p->op==TK_GT ){
++          testOp = OP_Ge;
++        }else{
++          testOp = OP_Gt;
++        }
++        disableTerm(pLevel, &aExpr[k].p);
++      }
++      start = sqliteVdbeCurrentAddr(v);
++      pLevel->op = OP_Next;
++      pLevel->p1 = iCur;
++      pLevel->p2 = start;
++      if( testOp!=OP_Noop ){
++        sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
++        sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
++        sqliteVdbeAddOp(v, testOp, 0, brk);
++      }
++      haveKey = 0;
++    }else if( pIdx==0 ){
++      /* Case 4:  There is no usable index.  We must do a complete
++      **          scan of the entire database table.
++      */
++      int start;
++
++      brk = pLevel->brk = sqliteVdbeMakeLabel(v);
++      cont = pLevel->cont = sqliteVdbeMakeLabel(v);
++      sqliteVdbeAddOp(v, OP_Rewind, iCur, brk);
++      start = sqliteVdbeCurrentAddr(v);
++      pLevel->op = OP_Next;
++      pLevel->p1 = iCur;
++      pLevel->p2 = start;
++      haveKey = 0;
++    }else{
++      /* Case 5: The WHERE clause term that refers to the right-most
++      **         column of the index is an inequality.  For example, if
++      **         the index is on (x,y,z) and the WHERE clause is of the
++      **         form "x=5 AND y<10" then this case is used.  Only the
++      **         right-most column can be an inequality - the rest must
++      **         use the "==" operator.
++      **
++      **         This case is also used when there are no WHERE clause
++      **         constraints but an index is selected anyway, in order
++      **         to force the output order to conform to an ORDER BY.
++      */
++      int score = pLevel->score;
++      int nEqColumn = score/8;
++      int start;
++      int leFlag, geFlag;
++      int testOp;
++
++      /* Evaluate the equality constraints
++      */
++      for(j=0; j<nEqColumn; j++){
++        for(k=0; k<nExpr; k++){
++          if( aExpr[k].p==0 ) continue;
++          if( aExpr[k].idxLeft==iCur
++             && aExpr[k].p->op==TK_EQ
++             && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight 
++             && aExpr[k].p->pLeft->iColumn==pIdx->aiColumn[j]
++          ){
++            sqliteExprCode(pParse, aExpr[k].p->pRight);
++            disableTerm(pLevel, &aExpr[k].p);
++            break;
++          }
++          if( aExpr[k].idxRight==iCur
++             && aExpr[k].p->op==TK_EQ
++             && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
++             && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j]
++          ){
++            sqliteExprCode(pParse, aExpr[k].p->pLeft);
++            disableTerm(pLevel, &aExpr[k].p);
++            break;
++          }
++        }
++      }
++
++      /* 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<nEqColumn; j++){
++        sqliteVdbeAddOp(v, OP_Dup, nEqColumn-1, 0);
++      }
++
++      /* Labels for the beginning and end of the loop
++      */
++      cont = pLevel->cont = sqliteVdbeMakeLabel(v);
++      brk = pLevel->brk = sqliteVdbeMakeLabel(v);
++
++      /* 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.
++      **
++      ** 2002-Dec-04: On a reverse-order scan, the so-called "termination"
++      ** key computed here really ends up being the start key.
++      */
++      if( (score & 1)!=0 ){
++        for(k=0; k<nExpr; k++){
++          Expr *pExpr = aExpr[k].p;
++          if( pExpr==0 ) continue;
++          if( aExpr[k].idxLeft==iCur
++             && (pExpr->op==TK_LT || pExpr->op==TK_LE)
++             && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight 
++             && pExpr->pLeft->iColumn==pIdx->aiColumn[j]
++          ){
++            sqliteExprCode(pParse, pExpr->pRight);
++            leFlag = pExpr->op==TK_LE;
++            disableTerm(pLevel, &aExpr[k].p);
++            break;
++          }
++          if( aExpr[k].idxRight==iCur
++             && (pExpr->op==TK_GT || pExpr->op==TK_GE)
++             && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
++             && pExpr->pRight->iColumn==pIdx->aiColumn[j]
++          ){
++            sqliteExprCode(pParse, pExpr->pLeft);
++            leFlag = pExpr->op==TK_GE;
++            disableTerm(pLevel, &aExpr[k].p);
++            break;
++          }
++        }
++        testOp = OP_IdxGE;
++      }else{
++        testOp = nEqColumn>0 ? OP_IdxGE : OP_Noop;
++        leFlag = 1;
++      }
++      if( testOp!=OP_Noop ){
++        int nCol = nEqColumn + (score & 1);
++        pLevel->iMem = pParse->nMem++;
++        sqliteVdbeAddOp(v, OP_NotNull, -nCol, sqliteVdbeCurrentAddr(v)+3);
++        sqliteVdbeAddOp(v, OP_Pop, nCol, 0);
++        sqliteVdbeAddOp(v, OP_Goto, 0, brk);
++        sqliteVdbeAddOp(v, OP_MakeKey, nCol, 0);
++        sqliteAddIdxKeyType(v, pIdx);
++        if( leFlag ){
++          sqliteVdbeAddOp(v, OP_IncrKey, 0, 0);
++        }
++        if( pLevel->bRev ){
++          sqliteVdbeAddOp(v, OP_MoveLt, pLevel->iCur, brk);
++        }else{
++          sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
++        }
++      }else if( pLevel->bRev ){
++        sqliteVdbeAddOp(v, OP_Last, pLevel->iCur, 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
++      ** that case, generate a "Rewind" instruction in place of the
++      ** start key search.
++      **
++      ** 2002-Dec-04: In the case of a reverse-order search, the so-called
++      ** "start" key really ends up being used as the termination key.
++      */
++      if( (score & 2)!=0 ){
++        for(k=0; k<nExpr; k++){
++          Expr *pExpr = aExpr[k].p;
++          if( pExpr==0 ) continue;
++          if( aExpr[k].idxLeft==iCur
++             && (pExpr->op==TK_GT || pExpr->op==TK_GE)
++             && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight 
++             && pExpr->pLeft->iColumn==pIdx->aiColumn[j]
++          ){
++            sqliteExprCode(pParse, pExpr->pRight);
++            geFlag = pExpr->op==TK_GE;
++            disableTerm(pLevel, &aExpr[k].p);
++            break;
++          }
++          if( aExpr[k].idxRight==iCur
++             && (pExpr->op==TK_LT || pExpr->op==TK_LE)
++             && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
++             && pExpr->pRight->iColumn==pIdx->aiColumn[j]
++          ){
++            sqliteExprCode(pParse, pExpr->pLeft);
++            geFlag = pExpr->op==TK_LE;
++            disableTerm(pLevel, &aExpr[k].p);
++            break;
++          }
++        }
++      }else{
++        geFlag = 1;
++      }
++      if( nEqColumn>0 || (score&2)!=0 ){
++        int nCol = nEqColumn + ((score&2)!=0);
++        sqliteVdbeAddOp(v, OP_NotNull, -nCol, sqliteVdbeCurrentAddr(v)+3);
++        sqliteVdbeAddOp(v, OP_Pop, nCol, 0);
++        sqliteVdbeAddOp(v, OP_Goto, 0, brk);
++        sqliteVdbeAddOp(v, OP_MakeKey, nCol, 0);
++        sqliteAddIdxKeyType(v, pIdx);
++        if( !geFlag ){
++          sqliteVdbeAddOp(v, OP_IncrKey, 0, 0);
++        }
++        if( pLevel->bRev ){
++          pLevel->iMem = pParse->nMem++;
++          sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
++          testOp = OP_IdxLT;
++        }else{
++          sqliteVdbeAddOp(v, OP_MoveTo, pLevel->iCur, brk);
++        }
++      }else if( pLevel->bRev ){
++        testOp = OP_Noop;
++      }else{
++        sqliteVdbeAddOp(v, OP_Rewind, pLevel->iCur, brk);
++      }
++
++      /* Generate the the top of the loop.  If there is a termination
++      ** key we have to test for that key and abort at the top of the
++      ** loop.
++      */
++      start = sqliteVdbeCurrentAddr(v);
++      if( testOp!=OP_Noop ){
++        sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
++        sqliteVdbeAddOp(v, testOp, pLevel->iCur, brk);
++      }
++      sqliteVdbeAddOp(v, OP_RowKey, pLevel->iCur, 0);
++      sqliteVdbeAddOp(v, OP_IdxIsNull, nEqColumn + (score & 1), cont);
++      sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
++      if( i==pTabList->nSrc-1 && pushKey ){
++        haveKey = 1;
++      }else{
++        sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
++        haveKey = 0;
++      }
++
++      /* Record the instruction used to terminate the loop.
++      */
++      pLevel->op = pLevel->bRev ? OP_Prev : OP_Next;
++      pLevel->p1 = pLevel->iCur;
++      pLevel->p2 = start;
++    }
++    loopMask |= getMask(&maskSet, iCur);
++
++    /* Insert code to test every subexpression that can be completely
++    ** computed using the current set of tables.
++    */
++    for(j=0; j<nExpr; j++){
++      if( aExpr[j].p==0 ) continue;
++      if( (aExpr[j].prereqAll & loopMask)!=aExpr[j].prereqAll ) continue;
++      if( pLevel->iLeftJoin && !ExprHasProperty(aExpr[j].p,EP_FromJoin) ){
++        continue;
++      }
++      if( haveKey ){
++        haveKey = 0;
++        sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
++      }
++      sqliteExprIfFalse(pParse, aExpr[j].p, cont, 1);
++      aExpr[j].p = 0;
++    }
++    brk = cont;
++
++    /* For a LEFT OUTER JOIN, generate code that will record the fact that
++    ** at least one row of the right table has matched the left table.  
++    */
++    if( pLevel->iLeftJoin ){
++      pLevel->top = sqliteVdbeCurrentAddr(v);
++      sqliteVdbeAddOp(v, OP_Integer, 1, 0);
++      sqliteVdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);
++      for(j=0; j<nExpr; j++){
++        if( aExpr[j].p==0 ) continue;
++        if( (aExpr[j].prereqAll & loopMask)!=aExpr[j].prereqAll ) continue;
++        if( haveKey ){
++          /* Cannot happen.  "haveKey" can only be true if pushKey is true
++          ** an pushKey can only be true for DELETE and UPDATE and there are
++          ** no outer joins with DELETE and UPDATE.
++          */
++          haveKey = 0;
++          sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
++        }
++        sqliteExprIfFalse(pParse, aExpr[j].p, cont, 1);
++        aExpr[j].p = 0;
++      }
++    }
++  }
++  pWInfo->iContinue = cont;
++  if( pushKey && !haveKey ){
++    sqliteVdbeAddOp(v, OP_Recno, pTabList->a[0].iCursor, 0);
++  }
++  freeMaskSet(&maskSet);
++  return pWInfo;
++}
++
++/*
++** Generate the end of the WHERE loop.  See comments on 
++** sqliteWhereBegin() for additional information.
++*/
++void sqliteWhereEnd(WhereInfo *pWInfo){
++  Vdbe *v = pWInfo->pParse->pVdbe;
++  int i;
++  WhereLevel *pLevel;
++  SrcList *pTabList = pWInfo->pTabList;
++
++  for(i=pTabList->nSrc-1; i>=0; i--){
++    pLevel = &pWInfo->a[i];
++    sqliteVdbeResolveLabel(v, pLevel->cont);
++    if( pLevel->op!=OP_Noop ){
++      sqliteVdbeAddOp(v, pLevel->op, pLevel->p1, pLevel->p2);
++    }
++    sqliteVdbeResolveLabel(v, pLevel->brk);
++    if( pLevel->inOp!=OP_Noop ){
++      sqliteVdbeAddOp(v, pLevel->inOp, pLevel->inP1, pLevel->inP2);
++    }
++    if( pLevel->iLeftJoin ){
++      int addr;
++      addr = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iLeftJoin, 0);
++      sqliteVdbeAddOp(v, OP_NotNull, 1, addr+4 + (pLevel->iCur>=0));
++      sqliteVdbeAddOp(v, OP_NullRow, pTabList->a[i].iCursor, 0);
++      if( pLevel->iCur>=0 ){
++        sqliteVdbeAddOp(v, OP_NullRow, pLevel->iCur, 0);
++      }
++      sqliteVdbeAddOp(v, OP_Goto, 0, pLevel->top);
++    }
++  }
++  sqliteVdbeResolveLabel(v, pWInfo->iBreak);
++  for(i=0; i<pTabList->nSrc; i++){
++    Table *pTab = pTabList->a[i].pTab;
++    assert( pTab!=0 );
++    if( pTab->isTransient || pTab->pSelect ) continue;
++    pLevel = &pWInfo->a[i];
++    sqliteVdbeAddOp(v, OP_Close, pTabList->a[i].iCursor, 0);
++    if( pLevel->pIdx!=0 ){
++      sqliteVdbeAddOp(v, OP_Close, pLevel->iCur, 0);
++    }
++  }
++#if 0  /* Never reuse a cursor */
++  if( pWInfo->pParse->nTab==pWInfo->peakNTab ){
++    pWInfo->pParse->nTab = pWInfo->savedNTab;
++  }
++#endif
++  sqliteFree(pWInfo);
++  return;
++}
+--- /dev/null
++++ b/ext/sqlite/libsqlite/VERSION
+@@ -0,0 +1 @@
++2.8.17
+--- /dev/null
++++ b/ext/sqlite/Makefile.frag
+@@ -0,0 +1,2 @@
++$(srcdir)/libsqlite/src/parse.c: $(srcdir)/libsqlite/src/parse.y
++      @$(LEMON) $(srcdir)/libsqlite/src/parse.y 
+--- /dev/null
++++ b/ext/sqlite/package.xml
+@@ -0,0 +1,136 @@
++<?xml version="1.0" encoding="ISO-8859-1" ?>
++<!DOCTYPE package SYSTEM "../pear/package.dtd">
++<package>
++ <name>SQLite</name>
++ <summary>SQLite database bindings</summary>
++ <maintainers>
++  <maintainer>
++   <user>wez</user>
++   <name>Wez Furlong</name>
++   <email>wez@php.net</email>
++   <role>lead</role>
++  </maintainer>
++  <maintainer>
++   <user>tal</user>
++   <name>Tal Peer</name>
++   <email>tal@php.net</email>
++   <role>developer</role>
++  </maintainer>
++  <maintainer>
++   <user>helly</user>
++   <name>Marcus Börger</name>
++   <email>helly@php.net</email>
++   <role>lead</role>
++  </maintainer>
++  <maintainer>
++   <user>iliaa</user>
++   <name>Ilia Alshanetsky</name>
++   <email>ilia@php.net</email>
++   <role>developer</role>
++  </maintainer>
++ </maintainers>
++ <description>
++SQLite is a C library that implements an embeddable SQL database engine.
++Programs that link with the SQLite library can have SQL database access
++without running a separate RDBMS process.
++This extension allows you to access SQLite databases from within PHP.
++
++Windows binary available from:
++http://snaps.php.net/win32/PECL_STABLE/php_sqlite.dll
++ </description>
++ <license>PHP</license>
++ <release>
++  <state>stable</state>
++  <version>2.0-dev</version>
++  <date>TBA</date>
++  <notes>
++   Added:
++   OO API (Marcus).
++  </notes>
++  <filelist>
++   <file role="src" name="config.m4"/>
++   <file role="src" name="config.w32"/>
++   <file role="src" name="sqlite.c"/>
++   <file role="src" name="sqlite.dsp"/>
++   <file role="src" name="php_sqlite.h"/>
++   <file role="src" name="php_sqlite.def"/>
++   <file role="doc" name="CREDITS"/>
++   <file role="doc" name="README"/>
++   <file role="doc" name="TODO"/>
++   <file role="doc" name="sqlite.php"/>
++   <file role="test" name="tests/sqlite_001.phpt"/>
++   <file role="test" name="tests/sqlite_002.phpt"/>
++   <file role="test" name="tests/sqlite_003.phpt"/>
++   <file role="test" name="tests/sqlite_004.phpt"/>
++   <file role="test" name="tests/sqlite_005.phpt"/>
++   <file role="test" name="tests/sqlite_006.phpt"/>
++   <file role="test" name="tests/sqlite_007.phpt"/>
++   <file role="test" name="tests/sqlite_008.phpt"/>
++   <file role="test" name="tests/sqlite_009.phpt"/>
++   <file role="test" name="tests/sqlite_010.phpt"/>
++   <file role="test" name="tests/sqlite_011.phpt"/>
++   <file role="test" name="tests/sqlite_012.phpt"/>
++   <file role="test" name="tests/sqlite_013.phpt"/>
++   <file role="test" name="tests/sqlite_014.phpt"/>
++   <file role="test" name="tests/sqlite_015.phpt"/>
++   <file role="test" name="tests/sqlite_016.phpt"/>
++   <file role="test" name="tests/sqlite_017.phpt"/>
++   <file role="test" name="tests/blankdb.inc"/>
++
++   <dir name="libsqlite">
++    <file role="doc" name="README"/>
++    <file role="src" name="VERSION"/>
++
++    <dir name="src">
++     <file role="src" name="attach.c"/>
++     <file role="src" name="auth.c"/>
++     <file role="src" name="btree.c"/>
++     <file role="src" name="btree_rb.c"/>
++     <file role="src" name="build.c"/>
++     <file role="src" name="copy.c"/>
++     <file role="src" name="delete.c"/>
++     <file role="src" name="encode.c"/>
++     <file role="src" name="expr.c"/>
++     <file role="src" name="func.c"/>
++     <file role="src" name="hash.c"/>
++     <file role="src" name="insert.c"/>
++     <file role="src" name="main.c"/>
++     <file role="src" name="opcodes.c"/>
++     <file role="src" name="os.c"/>
++     <file role="src" name="pager.c"/>
++     <file role="src" name="parse.c"/>
++     <file role="src" name="parse.y"/>
++     <file role="src" name="pragma.c"/>
++     <file role="src" name="printf.c"/>
++     <file role="src" name="random.c"/>
++     <file role="src" name="select.c"/>
++     <file role="src" name="table.c"/>
++     <file role="src" name="tokenize.c"/>
++     <file role="src" name="trigger.c"/>
++     <file role="src" name="update.c"/>
++     <file role="src" name="util.c"/>
++     <file role="src" name="vacuum.c"/>
++     <file role="src" name="vdbe.c"/>
++     <file role="src" name="where.c"/>
++     <file role="src" name="btree.h"/>
++     <file role="src" name="hash.h"/>
++     <file role="src" name="opcodes.h"/>
++     <file role="src" name="os.h"/>
++     <file role="src" name="pager.h"/>
++     <file role="src" name="parse.h"/>
++     <file role="src" name="sqlite_config.w32.h"/>
++     <file role="src" name="sqlite.h.in"/>
++     <file role="src" name="sqliteInt.h"/>
++     <file role="src" name="sqlite.w32.h"/>
++     <file role="src" name="vdbe.h"/>
++    </dir>
++   </dir>
++  </filelist>
++  <deps>
++   <dep type="php" rel="ge" version="5" />
++  </deps>
++ </release>
++</package>
++<!--
++vim:et:ts=1:sw=1
++-->
+--- /dev/null
++++ b/ext/sqlite/pdo_sqlite2.c
+@@ -0,0 +1,638 @@
++/*
++  +----------------------------------------------------------------------+
++  | PHP Version 5                                                        |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 1997-2012 The PHP Group                                |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP license,      |
++  | that is bundled with this package in the file LICENSE, and is        |
++  | available through the world-wide-web at the following url:           |
++  | http://www.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Author: Wez Furlong <wez@php.net>                                    |
++  +----------------------------------------------------------------------+
++*/
++
++/* $Id$ */
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++#include "php.h"
++
++#ifdef PHP_SQLITE2_HAVE_PDO
++#include "sqlite.h"
++#include "pdo/php_pdo.h"
++#include "pdo/php_pdo_driver.h"
++#include "zend_exceptions.h"
++
++#define php_sqlite_encode_binary(in, n, out) sqlite_encode_binary((const unsigned char *)in, n, (unsigned char *)out)
++#define php_sqlite_decode_binary(in, out)    sqlite_decode_binary((const unsigned char *)in, (unsigned char *)out)
++
++
++typedef struct {
++      const char *file;
++      int line;
++      unsigned int errcode;
++      char *errmsg;
++} pdo_sqlite2_error_info;
++
++typedef struct {
++      sqlite *db;
++      pdo_sqlite2_error_info einfo;
++} pdo_sqlite2_db_handle;
++
++typedef struct {
++      pdo_sqlite2_db_handle   *H;
++      sqlite_vm *vm;
++      const char **rowdata, **colnames;
++      int ncols;
++      unsigned pre_fetched:1;
++      unsigned done:1;
++      pdo_sqlite2_error_info einfo;
++} pdo_sqlite2_stmt;
++
++extern int _pdo_sqlite2_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, char *errmsg, const char *file, int line TSRMLS_DC);
++#define pdo_sqlite2_error(msg, s) _pdo_sqlite2_error(s, NULL, msg, __FILE__, __LINE__ TSRMLS_CC)
++#define pdo_sqlite2_error_stmt(msg, s) _pdo_sqlite2_error(stmt->dbh, stmt, msg, __FILE__, __LINE__ TSRMLS_CC)
++
++extern struct pdo_stmt_methods sqlite2_stmt_methods;
++
++static int pdo_sqlite2_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
++{
++      pdo_sqlite2_stmt *S = (pdo_sqlite2_stmt*)stmt->driver_data;
++
++      if (S->vm) {
++              char *errmsg = NULL;
++              sqlite_finalize(S->vm, &errmsg);
++              if (errmsg) {
++                      sqlite_freemem(errmsg);
++              }
++              S->vm = NULL;
++      }
++      if (S->einfo.errmsg) {
++              pefree(S->einfo.errmsg, stmt->dbh->is_persistent);
++      }
++      efree(S);
++      return 1;
++}
++
++static int pdo_sqlite2_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
++{
++      pdo_sqlite2_stmt *S = (pdo_sqlite2_stmt*)stmt->driver_data;
++      char *errmsg = NULL;
++      const char *tail;
++
++      if (stmt->executed && !S->done) {
++              sqlite_finalize(S->vm, &errmsg);
++              pdo_sqlite2_error_stmt(errmsg, stmt);
++              errmsg = NULL;
++              S->vm = NULL;
++      }
++
++      S->einfo.errcode = sqlite_compile(S->H->db, stmt->active_query_string, &tail, &S->vm, &errmsg);
++      if (S->einfo.errcode != SQLITE_OK) {
++              pdo_sqlite2_error_stmt(errmsg, stmt);
++              return 0;
++      }
++
++      S->done = 0;
++      S->einfo.errcode = sqlite_step(S->vm, &S->ncols, &S->rowdata, &S->colnames);
++      switch (S->einfo.errcode) {
++              case SQLITE_ROW:
++                      S->pre_fetched = 1;
++                      stmt->column_count = S->ncols;
++                      return 1;
++
++              case SQLITE_DONE:
++                      stmt->column_count = S->ncols;
++                      stmt->row_count = sqlite_changes(S->H->db);
++                      S->einfo.errcode = sqlite_reset(S->vm, &errmsg);
++                      if (S->einfo.errcode != SQLITE_OK) {
++                              pdo_sqlite2_error_stmt(errmsg, stmt);
++                      }
++                      S->done = 1;
++                      return 1;
++
++              case SQLITE_ERROR:
++              case SQLITE_MISUSE:
++              case SQLITE_BUSY:
++              default:
++                      pdo_sqlite2_error_stmt(errmsg, stmt);
++                      return 0;
++      }
++}
++
++static int pdo_sqlite2_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
++              enum pdo_param_event event_type TSRMLS_DC)
++{
++      return 1;
++}
++
++static int pdo_sqlite2_stmt_fetch(pdo_stmt_t *stmt,
++      enum pdo_fetch_orientation ori, long offset TSRMLS_DC)
++{
++      pdo_sqlite2_stmt *S = (pdo_sqlite2_stmt*)stmt->driver_data;
++      char *errmsg = NULL;
++
++      if (!S->vm) {
++              return 0;       
++      }
++      if (S->pre_fetched) {
++              S->pre_fetched = 0;
++              return 1;
++      }
++      if (S->done) {
++              return 0;
++      }
++
++      S->einfo.errcode = sqlite_step(S->vm, &S->ncols, &S->rowdata, &S->colnames);
++      switch (S->einfo.errcode) {
++              case SQLITE_ROW:
++                      return 1;
++
++              case SQLITE_DONE:
++                      S->done = 1;
++                      S->einfo.errcode = sqlite_reset(S->vm, &errmsg);
++                      if (S->einfo.errcode != SQLITE_OK) {
++                              pdo_sqlite2_error_stmt(errmsg, stmt);
++                              errmsg = NULL;
++                      }
++                      return 0;
++
++              default:
++                      pdo_sqlite2_error_stmt(errmsg, stmt);
++                      return 0;
++      }
++}
++
++static int pdo_sqlite2_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
++{
++      pdo_sqlite2_stmt *S = (pdo_sqlite2_stmt*)stmt->driver_data;
++
++      if(colno >= S->ncols) {
++              /* error invalid column */
++              pdo_sqlite2_error_stmt(NULL, stmt);
++              return 0;
++      }
++
++      stmt->columns[colno].name = estrdup(S->colnames[colno]);
++      stmt->columns[colno].namelen = strlen(stmt->columns[colno].name);
++      stmt->columns[colno].maxlen = 0xffffffff;
++      stmt->columns[colno].precision = 0;
++      stmt->columns[colno].param_type = PDO_PARAM_STR;
++
++      return 1;
++}
++
++static int pdo_sqlite2_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC)
++{
++      pdo_sqlite2_stmt *S = (pdo_sqlite2_stmt*)stmt->driver_data;
++      if (!S->vm) {
++              return 0;
++      }
++      if(colno >= S->ncols) {
++              /* error invalid column */
++              pdo_sqlite2_error_stmt(NULL, stmt);
++              return 0;
++      }
++      if (S->rowdata[colno]) {
++              if (S->rowdata[colno][0] == '\x01') {
++                      /* encoded */
++                      *caller_frees = 1;
++                      *ptr = emalloc(strlen(S->rowdata[colno]));
++                      *len = php_sqlite_decode_binary(S->rowdata[colno]+1, *ptr);
++                      (*(char**)ptr)[*len] = '\0';
++              } else {
++                      *ptr = (char*)S->rowdata[colno];
++                      *len = strlen(*ptr);
++              }
++      } else {
++              *ptr = NULL;
++              *len = 0;
++      }
++      return 1;
++}
++
++struct pdo_stmt_methods sqlite2_stmt_methods = {
++      pdo_sqlite2_stmt_dtor,
++      pdo_sqlite2_stmt_execute,
++      pdo_sqlite2_stmt_fetch,
++      pdo_sqlite2_stmt_describe,
++      pdo_sqlite2_stmt_get_col,
++      pdo_sqlite2_stmt_param_hook,
++      NULL, /* set_attr */
++      NULL, /* get_attr */
++      NULL
++};
++
++
++int _pdo_sqlite2_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, char *errmsg, const char *file, int line TSRMLS_DC) /* {{{ */
++{
++      pdo_sqlite2_db_handle *H = (pdo_sqlite2_db_handle *)dbh->driver_data;
++      pdo_error_type *pdo_err = stmt ? &stmt->error_code : &dbh->error_code;
++      pdo_sqlite2_error_info *einfo = &H->einfo;
++      pdo_sqlite2_stmt *S;
++
++      if (stmt) {
++              S = stmt->driver_data;
++              einfo = &S->einfo;
++      }
++
++      einfo->file = file;
++      einfo->line = line;
++
++      if (einfo->errmsg) {
++              pefree(einfo->errmsg, dbh->is_persistent);
++              einfo->errmsg = NULL;
++      }
++
++      if (einfo->errcode != SQLITE_OK) {
++              if (errmsg) {
++                      einfo->errmsg = pestrdup(errmsg, dbh->is_persistent);
++                      sqlite_freemem(errmsg);
++              } else {
++                      einfo->errmsg = pestrdup(sqlite_error_string(einfo->errcode), dbh->is_persistent);
++              }
++      } else { /* no error */
++              strcpy(*pdo_err, PDO_ERR_NONE);
++              return 0;
++      }
++      switch (einfo->errcode) {
++              case SQLITE_NOTFOUND:
++                      strcpy(*pdo_err, "42S02");
++                      break;  
++
++              case SQLITE_INTERRUPT:
++                      strcpy(*pdo_err, "01002");
++                      break;
++
++              case SQLITE_NOLFS:
++                      strcpy(*pdo_err, "HYC00");
++                      break;
++
++              case SQLITE_TOOBIG:
++                      strcpy(*pdo_err, "22001");
++                      break;
++
++              case SQLITE_CONSTRAINT:
++                      strcpy(*pdo_err, "23000");
++                      break;
++
++              case SQLITE_ERROR:
++              default:
++                      strcpy(*pdo_err, "HY000");
++                      break;
++      }
++
++      if (!dbh->methods) {
++              zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "SQLSTATE[%s] [%d] %s",
++                              *pdo_err, einfo->errcode, einfo->errmsg);
++      }
++
++      return einfo->errcode;
++}
++/* }}} */
++
++static int pdo_sqlite2_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC)
++{
++      pdo_sqlite2_db_handle *H = (pdo_sqlite2_db_handle *)dbh->driver_data;
++      pdo_sqlite2_error_info *einfo = &H->einfo;
++      pdo_sqlite2_stmt *S;
++
++      if (stmt) {
++              S = stmt->driver_data;
++              einfo = &S->einfo;
++      }
++
++      if (einfo->errcode) {
++              add_next_index_long(info, einfo->errcode);
++              if (einfo->errmsg) {
++                      add_next_index_string(info, einfo->errmsg, 1);
++              }
++      }
++
++      return 1;
++}
++
++static int sqlite2_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
++{
++      pdo_sqlite2_db_handle *H = (pdo_sqlite2_db_handle *)dbh->driver_data;
++      
++      if (H) {
++              if (H->db) {
++                      sqlite_close(H->db);
++                      H->db = NULL;
++              }
++              if (H->einfo.errmsg) {
++                      pefree(H->einfo.errmsg, dbh->is_persistent);
++                      H->einfo.errmsg = NULL;
++              }
++              pefree(H, dbh->is_persistent);
++              dbh->driver_data = NULL;
++      }
++      return 0;
++}
++/* }}} */
++
++static int sqlite2_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC)
++{
++      pdo_sqlite2_db_handle *H = (pdo_sqlite2_db_handle *)dbh->driver_data;
++      pdo_sqlite2_stmt *S = ecalloc(1, sizeof(pdo_sqlite2_stmt));
++
++      S->H = H;
++      stmt->driver_data = S;
++      stmt->methods = &sqlite2_stmt_methods;
++      stmt->supports_placeholders = PDO_PLACEHOLDER_NONE;
++
++      if (PDO_CURSOR_FWDONLY != pdo_attr_lval(driver_options, PDO_ATTR_CURSOR, PDO_CURSOR_FWDONLY TSRMLS_CC)) {
++              H->einfo.errcode = SQLITE_ERROR;
++              pdo_sqlite2_error(NULL, dbh);
++              return 0;
++      }
++
++      return 1;
++}
++
++static long sqlite2_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC)
++{
++      pdo_sqlite2_db_handle *H = (pdo_sqlite2_db_handle *)dbh->driver_data;
++      char *errmsg = NULL;
++
++      if ((H->einfo.errcode = sqlite_exec(H->db, sql, NULL, NULL, &errmsg)) != SQLITE_OK) {
++              pdo_sqlite2_error(errmsg, dbh);
++              return -1;
++      } else {
++              return sqlite_changes(H->db);
++      }
++}
++
++static char *pdo_sqlite2_last_insert_id(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC)
++{
++      pdo_sqlite2_db_handle *H = (pdo_sqlite2_db_handle *)dbh->driver_data;
++      char *id;
++      
++      id = php_pdo_int64_to_str(sqlite_last_insert_rowid(H->db) TSRMLS_CC);
++      *len = strlen(id);
++      return id;
++}
++
++static int sqlite2_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype  TSRMLS_DC)
++{
++      char *ret;
++
++      if (unquotedlen && (unquoted[0] == '\x01' || memchr(unquoted, '\0', unquotedlen) != NULL)) {
++              /* binary string */
++              int len;
++              ret = safe_emalloc(1 + unquotedlen / 254, 257, 5);
++              ret[0] = '\'';
++              ret[1] = '\x01';
++              len = php_sqlite_encode_binary(unquoted, unquotedlen, ret+2);
++              ret[len + 2] = '\'';
++              ret[len + 3] = '\0';
++              *quoted = ret;
++              *quotedlen = len + 3;
++              /* fprintf(stderr, "Quoting:%d:%.*s:\n", *quotedlen, *quotedlen, *quoted); */
++              return 1;
++      } else if (unquotedlen) {
++              ret = sqlite_mprintf("'%q'", unquoted);
++              if (ret) {
++                      *quoted = estrdup(ret);
++                      *quotedlen = strlen(ret);
++                      sqlite_freemem(ret);
++                      return 1;
++              }
++              return 0;
++      } else {
++              *quoted = estrdup("''");
++              *quotedlen = 2;
++              return 1;
++      }
++}
++
++static int sqlite2_handle_begin(pdo_dbh_t *dbh TSRMLS_DC)
++{
++      pdo_sqlite2_db_handle *H = (pdo_sqlite2_db_handle *)dbh->driver_data;
++      char *errmsg = NULL;
++
++      if (sqlite_exec(H->db, "BEGIN", NULL, NULL, &errmsg) != SQLITE_OK) {
++              pdo_sqlite2_error(errmsg, dbh);
++              return 0;
++      }
++      return 1;
++}
++
++static int sqlite2_handle_commit(pdo_dbh_t *dbh TSRMLS_DC)
++{
++      pdo_sqlite2_db_handle *H = (pdo_sqlite2_db_handle *)dbh->driver_data;
++      char *errmsg = NULL;
++
++      if (sqlite_exec(H->db, "COMMIT", NULL, NULL, &errmsg) != SQLITE_OK) {
++              pdo_sqlite2_error(errmsg, dbh);
++              return 0;
++      }
++      return 1;
++}
++
++static int sqlite2_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
++{
++      pdo_sqlite2_db_handle *H = (pdo_sqlite2_db_handle *)dbh->driver_data;
++      char *errmsg = NULL;
++
++      if (sqlite_exec(H->db, "ROLLBACK", NULL, NULL, &errmsg) != SQLITE_OK) {
++              pdo_sqlite2_error(errmsg, dbh);
++              return 0;
++      }
++      return 1;
++}
++
++static int pdo_sqlite2_get_attribute(pdo_dbh_t *dbh, long attr, zval *return_value TSRMLS_DC)
++{
++      switch (attr) {
++              case PDO_ATTR_CLIENT_VERSION:
++              case PDO_ATTR_SERVER_VERSION:
++                      ZVAL_STRING(return_value, (char *)sqlite_libversion(), 1);
++                      break;
++              
++              default:
++                      return 0;       
++      }
++
++      return 1;
++}
++
++static int pdo_sqlite2_set_attr(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC)
++{
++      pdo_sqlite2_db_handle *H = (pdo_sqlite2_db_handle *)dbh->driver_data;
++
++      switch (attr) {
++              case PDO_ATTR_TIMEOUT:
++                      convert_to_long(val);
++                      sqlite_busy_timeout(H->db, Z_LVAL_P(val) * 1000);
++                      return 1;
++      }
++      return 0;
++}
++
++static PHP_FUNCTION(sqlite2_create_function)
++{
++      /* TODO: implement this stuff */
++}
++
++static const zend_function_entry dbh_methods[] = {
++      PHP_FE(sqlite2_create_function, NULL)
++      {NULL, NULL, NULL}
++};
++
++static const zend_function_entry *get_driver_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC)
++{
++      switch (kind) {
++              case PDO_DBH_DRIVER_METHOD_KIND_DBH:
++                      return dbh_methods;
++
++              default:
++                      return NULL;
++      }
++}
++
++static struct pdo_dbh_methods sqlite2_methods = {
++      sqlite2_handle_closer,
++      sqlite2_handle_preparer,
++      sqlite2_handle_doer,
++      sqlite2_handle_quoter,
++      sqlite2_handle_begin,
++      sqlite2_handle_commit,
++      sqlite2_handle_rollback,
++      pdo_sqlite2_set_attr,
++      pdo_sqlite2_last_insert_id,
++      pdo_sqlite2_fetch_error_func,
++      pdo_sqlite2_get_attribute,
++      NULL,   /* check_liveness: not needed */
++      get_driver_methods
++};
++
++static char *make_filename_safe(const char *filename TSRMLS_DC)
++{
++      if (*filename && strncmp(filename, ":memory:", sizeof(":memory:")-1)) {
++              char *fullpath = expand_filepath(filename, NULL TSRMLS_CC);
++
++              if (!fullpath) {
++                      return NULL;
++              }
++
++              if (PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
++                      efree(fullpath);
++                      return NULL;
++              }
++
++              if (php_check_open_basedir(fullpath TSRMLS_CC)) {
++                      efree(fullpath);
++                      return NULL;
++              }
++              return fullpath;
++      }
++      return estrdup(filename);
++}
++
++static int authorizer(void *autharg, int access_type, const char *arg3, const char *arg4,
++              const char *arg5, const char *arg6)
++{
++      char *filename;
++      switch (access_type) {
++              case SQLITE_COPY: {
++                      TSRMLS_FETCH();
++                      filename = make_filename_safe(arg4 TSRMLS_CC);
++                      if (!filename) {
++                              return SQLITE_DENY;
++                      }
++                      efree(filename);
++                      return SQLITE_OK;
++              }
++
++              case SQLITE_ATTACH: {
++                      TSRMLS_FETCH();
++                      filename = make_filename_safe(arg3 TSRMLS_CC);
++                      if (!filename) {
++                              return SQLITE_DENY;
++                      }
++                      efree(filename);
++                      return SQLITE_OK;
++              }
++
++              default:
++                      /* access allowed */
++                      return SQLITE_OK;
++      }
++}
++
++static int pdo_sqlite2_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
++{
++      pdo_sqlite2_db_handle *H;
++      int ret = 0;
++      long timeout = 60;
++      char *filename;
++      char *errmsg = NULL;
++
++      H = pecalloc(1, sizeof(pdo_sqlite2_db_handle), dbh->is_persistent);
++
++      H->einfo.errcode = 0;
++      H->einfo.errmsg = NULL;
++      dbh->driver_data = H;
++
++      filename = make_filename_safe(dbh->data_source TSRMLS_CC);
++
++      if (!filename) {
++              zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC,
++                              "safe_mode/open_basedir prohibits opening %s",
++                              dbh->data_source);
++              goto cleanup;
++      }
++
++      H->db = sqlite_open(filename, 0666, &errmsg);
++      efree(filename);
++
++      if (!H->db) {
++              H->einfo.errcode = SQLITE_ERROR;
++              pdo_sqlite2_error(errmsg, dbh);
++              goto cleanup;
++      }
++
++      sqlite_set_authorizer(H->db, authorizer, NULL);
++
++      if (driver_options) {
++              timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, timeout TSRMLS_CC);
++      }
++      sqlite_busy_timeout(H->db, timeout * 1000);
++
++      dbh->alloc_own_columns = 1;
++      dbh->max_escaped_char_length = 2;
++
++      ret = 1;
++
++cleanup:
++      dbh->methods = &sqlite2_methods;
++
++      return ret;
++}
++/* }}} */
++
++pdo_driver_t pdo_sqlite2_driver = {
++      PDO_DRIVER_HEADER(sqlite2),
++      pdo_sqlite2_handle_factory
++};
++
++
++
++#endif
++
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: noet sw=4 ts=4 fdm=marker
++ * vim<600: noet sw=4 ts=4
++ */
+--- /dev/null
++++ b/ext/sqlite/php_sqlite.def
+@@ -0,0 +1,43 @@
++EXPORTS
++sqlite_open
++sqlite_close
++sqlite_exec
++sqlite_last_insert_rowid
++sqlite_changes
++sqlite_error_string
++sqlite_interrupt
++sqlite_complete
++sqlite_busy_handler
++sqlite_busy_timeout
++sqlite_get_table
++sqlite_free_table
++sqlite_exec_printf
++sqlite_exec_vprintf
++sqlite_get_table_printf
++sqlite_get_table_vprintf
++sqlite_mprintf
++sqlite_vmprintf
++sqlite_freemem
++sqlite_libversion
++sqlite_libencoding
++sqlite_create_function
++sqlite_create_aggregate
++sqlite_function_type
++sqlite_set_result_string
++sqlite_set_result_int
++sqlite_set_result_double
++sqlite_set_result_error
++sqlite_user_data
++sqlite_aggregate_context
++sqlite_aggregate_count
++sqlite_set_authorizer
++sqlite_trace
++sqlite_compile
++sqlite_step
++sqlite_finalize
++; some experimental stuff
++sqlite_last_statement_changes
++sqlite_reset
++sqlite_bind
++sqlite_progress_handler
++sqlite_commit_hook
+--- /dev/null
++++ b/ext/sqlite/php_sqlite.h
+@@ -0,0 +1,107 @@
++/*
++   +----------------------------------------------------------------------+
++   | PHP Version 5                                                        |
++   +----------------------------------------------------------------------+
++   | Copyright (c) 1997-2012 The PHP Group                                |
++   +----------------------------------------------------------------------+
++   | This source file is subject to version 3.01 of the PHP license,      |
++   | that is bundled with this package in the file LICENSE, and is        |
++   | available through the world-wide-web at the following url:           |
++   | http://www.php.net/license/3_01.txt                                  |
++   | If you did not receive a copy of the PHP license and are unable to   |
++   | obtain it through the world-wide-web, please send a note to          |
++   | license@php.net so we can mail you a copy immediately.               |
++   +----------------------------------------------------------------------+
++   | Authors: Wez Furlong <wez@thebrainroom.com>                          |
++   |          Tal Peer <tal@php.net>                                      |
++   |          Marcus Boerger <helly@php.net>                              |
++   +----------------------------------------------------------------------+
++
++   $Id$ 
++*/
++
++#ifndef PHP_SQLITE_H
++#define PHP_SQLITE_H
++
++extern zend_module_entry sqlite_module_entry;
++#define phpext_sqlite_ptr &sqlite_module_entry
++
++#ifdef ZTS
++#include "TSRM.h"
++#endif
++
++PHP_MINIT_FUNCTION(sqlite);
++PHP_MSHUTDOWN_FUNCTION(sqlite);
++PHP_RSHUTDOWN_FUNCTION(sqlite);
++PHP_MINFO_FUNCTION(sqlite);
++
++PHP_FUNCTION(sqlite_open);
++PHP_FUNCTION(sqlite_popen);
++PHP_FUNCTION(sqlite_close);
++PHP_FUNCTION(sqlite_query);
++PHP_FUNCTION(sqlite_exec);
++PHP_FUNCTION(sqlite_unbuffered_query);
++PHP_FUNCTION(sqlite_array_query);
++PHP_FUNCTION(sqlite_single_query);
++
++PHP_FUNCTION(sqlite_fetch_array);
++PHP_FUNCTION(sqlite_fetch_object);
++PHP_FUNCTION(sqlite_fetch_single);
++PHP_FUNCTION(sqlite_fetch_all);
++PHP_FUNCTION(sqlite_current);
++PHP_FUNCTION(sqlite_column);
++
++PHP_FUNCTION(sqlite_num_rows);
++PHP_FUNCTION(sqlite_num_fields);
++PHP_FUNCTION(sqlite_field_name);
++PHP_FUNCTION(sqlite_seek);
++PHP_FUNCTION(sqlite_rewind);
++PHP_FUNCTION(sqlite_next);
++PHP_FUNCTION(sqlite_prev);
++PHP_FUNCTION(sqlite_key);
++
++PHP_FUNCTION(sqlite_valid);
++PHP_FUNCTION(sqlite_has_prev);
++
++PHP_FUNCTION(sqlite_libversion);
++PHP_FUNCTION(sqlite_libencoding);
++
++PHP_FUNCTION(sqlite_changes);
++PHP_FUNCTION(sqlite_last_insert_rowid);
++
++PHP_FUNCTION(sqlite_escape_string);
++
++PHP_FUNCTION(sqlite_busy_timeout);
++
++PHP_FUNCTION(sqlite_last_error);
++PHP_FUNCTION(sqlite_error_string);
++
++PHP_FUNCTION(sqlite_create_aggregate);
++PHP_FUNCTION(sqlite_create_function);
++PHP_FUNCTION(sqlite_udf_decode_binary);
++PHP_FUNCTION(sqlite_udf_encode_binary);
++
++PHP_FUNCTION(sqlite_factory);
++
++PHP_FUNCTION(sqlite_fetch_column_types);
++
++ZEND_BEGIN_MODULE_GLOBALS(sqlite)
++       long assoc_case;
++ZEND_END_MODULE_GLOBALS(sqlite)
++
++#ifdef ZTS
++#define SQLITE_G(v) TSRMG(sqlite_globals_id, zend_sqlite_globals *, v)
++#else
++#define SQLITE_G(v) (sqlite_globals.v)
++#endif
++
++#endif
++
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * indent-tabs-mode: t
++ * End:
++ */
+--- /dev/null
++++ b/ext/sqlite/README
+@@ -0,0 +1,14 @@
++This is an extension for the SQLite Embeddable SQL Database Engine.
++http://www.sqlite.org/
++
++SQLite is a C library that implements an embeddable SQL database engine.
++Programs that link with the SQLite library can have SQL database access
++without running a separate RDBMS process.
++
++SQLite is not a client library used to connect to a big database server.
++SQLite is the server. The SQLite library reads and writes directly to and from
++the database files on disk
++
++
++
++vim:tw=78:et
+--- /dev/null
++++ b/ext/sqlite/sess_sqlite.c
+@@ -0,0 +1,201 @@
++/* 
++   +----------------------------------------------------------------------+
++   | PHP Version 5                                                        |
++   +----------------------------------------------------------------------+
++   | Copyright (c) 1997-2012 The PHP Group                                |
++   +----------------------------------------------------------------------+
++   | This source file is subject to version 3.01 of the PHP license,      |
++   | that is bundled with this package in the file LICENSE, and is        |
++   | available through the world-wide-web at the following url:           |
++   | http://www.php.net/license/3_01.txt                                  |
++   | If you did not receive a copy of the PHP license and are unable to   |
++   | obtain it through the world-wide-web, please send a note to          |
++   | license@php.net so we can mail you a copy immediately.               |
++   +----------------------------------------------------------------------+
++   | Authors: John Coggeshall <john@php.net>                              |
++   |          Wez Furlong <wez@thebrainroom.com>                          |
++   +----------------------------------------------------------------------+
++ */
++
++/* $Id$ */
++
++#include "php.h"
++
++#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
++
++#include "ext/session/php_session.h"
++#include "ext/standard/php_lcg.h"
++#include <sqlite.h>
++#define SQLITE_RETVAL(__r) ((__r) == SQLITE_OK ? SUCCESS : FAILURE)
++#define PS_SQLITE_DATA sqlite *db = (sqlite*)PS_GET_MOD_DATA()
++extern int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out);
++extern int sqlite_decode_binary(const unsigned char *in, unsigned char *out);
++
++PS_FUNCS(sqlite);
++
++ps_module ps_mod_sqlite = {
++      PS_MOD(sqlite)
++};
++
++PS_OPEN_FUNC(sqlite) 
++{
++      char *errmsg = NULL;
++      sqlite *db;
++
++      /* TODO: do we need a safe_mode check here? */
++      db = sqlite_open(save_path, 0666, &errmsg);
++      if (db == NULL) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, 
++                              "SQLite: failed to open/create session database `%s' - %s", save_path, errmsg);
++              sqlite_freemem(errmsg);
++              return FAILURE;
++      }
++
++      /* allow up to 1 minute when busy */
++      sqlite_busy_timeout(db, 60000);
++
++      sqlite_exec(db, "PRAGMA default_synchronous = OFF", NULL, NULL, NULL);
++      sqlite_exec(db, "PRAGMA count_changes = OFF", NULL, NULL, NULL);
++
++      /* This will fail if the table already exists, but that's not a big problem. I'm
++         unclear as to how to check for a table's existence in SQLite -- that would be better here. */
++      sqlite_exec(db, 
++          "CREATE TABLE session_data ("
++          "    sess_id PRIMARY KEY," 
++          "    value TEXT, "
++          "    updated INTEGER "
++          ")", NULL, NULL, NULL);
++
++      PS_SET_MOD_DATA(db);
++
++      return SUCCESS;
++}
++
++PS_CLOSE_FUNC(sqlite) 
++{
++      PS_SQLITE_DATA;
++
++      sqlite_close(db);
++
++      return SUCCESS;
++}
++
++PS_READ_FUNC(sqlite) 
++{
++      PS_SQLITE_DATA;
++      char *query;
++      const char *tail;
++      sqlite_vm *vm;
++      int colcount, result;
++      const char **rowdata, **colnames;
++      char *error;
++
++      *val = NULL;
++      *vallen = 0;
++      
++      query = sqlite_mprintf("SELECT value FROM session_data WHERE sess_id='%q' LIMIT 1", key);
++      if (query == NULL) {
++              /* no memory */
++              return FAILURE;
++      }
++
++      if (sqlite_compile(db, query, &tail, &vm, &error) != SQLITE_OK) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLite: Could not compile session read query: %s", error);
++              sqlite_freemem(error);
++              sqlite_freemem(query);
++              return FAILURE;
++      }
++
++      switch ((result = sqlite_step(vm, &colcount, &rowdata, &colnames))) {
++              case SQLITE_ROW:
++                      if (rowdata[0] != NULL) {
++                              *vallen = strlen(rowdata[0]);
++                              if (*vallen) {
++                                      *val = emalloc(*vallen);
++                                      *vallen = sqlite_decode_binary(rowdata[0], *val);
++                                      (*val)[*vallen] = '\0';
++                              } else {
++                                      *val = STR_EMPTY_ALLOC();
++                              }
++                      }
++                      break;
++              default:
++                      sqlite_freemem(error);
++                      error = NULL;
++      }
++      
++      if (SQLITE_OK != sqlite_finalize(vm, &error)) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLite: session read: error %s", error);
++              sqlite_freemem(error);
++              error = NULL;
++      }
++
++      sqlite_freemem(query);
++      
++      return *val == NULL ? FAILURE : SUCCESS;
++}
++
++PS_WRITE_FUNC(sqlite) 
++{
++      PS_SQLITE_DATA;
++      char *error;
++      time_t t;
++      char *binary;
++      int binlen;
++      int rv;
++      
++      t = time(NULL);
++
++      binary = safe_emalloc(1 + vallen / 254, 257, 3);
++      binlen = sqlite_encode_binary((const unsigned char*)val, vallen, binary);
++      
++      rv = sqlite_exec_printf(db, "REPLACE INTO session_data VALUES('%q', '%q', %d)", NULL, NULL, &error, key, binary, t);
++      if (rv != SQLITE_OK) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "SQLite: session write query failed: %s", error);
++              sqlite_freemem(error);
++      }
++      efree(binary);
++
++      return SQLITE_RETVAL(rv);
++}
++
++PS_DESTROY_FUNC(sqlite) 
++{
++      int rv;
++      PS_SQLITE_DATA;
++
++      rv = sqlite_exec_printf(db, "DELETE FROM session_data WHERE sess_id='%q'", NULL, NULL, NULL, key);
++      
++      return SQLITE_RETVAL(rv);
++}
++
++PS_GC_FUNC(sqlite) 
++{
++      PS_SQLITE_DATA;
++      int rv;
++      time_t t = time(NULL);
++
++      rv = sqlite_exec_printf(db, 
++                      "DELETE FROM session_data WHERE (%d - updated) > %d", 
++                      NULL, NULL, NULL, t, maxlifetime);
++
++      /* because SQLite does not actually clear the deleted data from the database 
++       * we need to occassionaly do so manually to prevent the sessions database 
++       * from growing endlessly.
++       */
++      if ((int) ((float) PS(gc_divisor) * PS(gc_divisor) * php_combined_lcg(TSRMLS_C)) < PS(gc_probability)) {
++              rv = sqlite_exec_printf(db, "VACUUM", NULL, NULL, NULL);
++      }
++      return SQLITE_RETVAL(rv);
++}
++
++#endif /* HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION) */
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: sw=4 ts=4 fdm=marker
++ * vim<600: sw=4 ts=4
++ */
+--- /dev/null
++++ b/ext/sqlite/sqlite.c
+@@ -0,0 +1,3448 @@
++/*
++   +----------------------------------------------------------------------+
++   | PHP Version 5                                                        |
++   +----------------------------------------------------------------------+
++   | Copyright (c) 1997-2012 The PHP Group                                |
++   +----------------------------------------------------------------------+
++   | This source file is subject to version 3.01 of the PHP license,      |
++   | that is bundled with this package in the file LICENSE, and is        |
++   | available through the world-wide-web at the following url:           |
++   | http://www.php.net/license/3_01.txt                                  |
++   | If you did not receive a copy of the PHP license and are unable to   |
++   | obtain it through the world-wide-web, please send a note to          |
++   | license@php.net so we can mail you a copy immediately.               |
++   +----------------------------------------------------------------------+
++   | Authors: Wez Furlong <wez@thebrainroom.com>                          |
++   |          Tal Peer <tal@php.net>                                      |
++   |          Marcus Boerger <helly@php.net>                              |
++   +----------------------------------------------------------------------+
++
++   $Id$
++*/
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#define PHP_SQLITE_MODULE_VERSION     "2.0-dev"
++
++#include "php.h"
++#include "php_ini.h"
++#include "ext/standard/info.h"
++#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
++#include "ext/session/php_session.h"
++#endif
++#include "php_sqlite.h"
++
++#if HAVE_TIME_H
++# include <time.h>
++#endif
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++#include <sqlite.h>
++
++#include "zend_exceptions.h"
++#include "zend_interfaces.h"
++
++#if defined(HAVE_SPL) && ((PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1))
++extern PHPAPI zend_class_entry *spl_ce_RuntimeException;
++extern PHPAPI zend_class_entry *spl_ce_Countable;
++#endif
++
++#if PHP_SQLITE2_HAVE_PDO
++# include "pdo/php_pdo.h"
++# include "pdo/php_pdo_driver.h"
++extern pdo_driver_t pdo_sqlite2_driver;
++#endif
++
++#ifndef safe_emalloc
++# define safe_emalloc(a,b,c) emalloc((a)*(b)+(c))
++#endif
++
++ZEND_DECLARE_MODULE_GLOBALS(sqlite)
++static PHP_GINIT_FUNCTION(sqlite);
++
++#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
++extern ps_module ps_mod_sqlite;
++#define ps_sqlite_ptr &ps_mod_sqlite
++#endif
++
++extern int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out);
++extern int sqlite_decode_binary(const unsigned char *in, unsigned char *out);
++
++#define php_sqlite_encode_binary(in, n, out) sqlite_encode_binary((const unsigned char *)in, n, (unsigned char *)out)
++#define php_sqlite_decode_binary(in, out) in && *in ? sqlite_decode_binary((const unsigned char *)in, (unsigned char *)out) : 0
++
++static int sqlite_count_elements(zval *object, long *count TSRMLS_DC);
++
++static int le_sqlite_db, le_sqlite_result, le_sqlite_pdb;
++
++static inline void php_sqlite_strtoupper(char *s)
++{
++      while (*s!='\0') {
++              *s = toupper(*s);
++              s++;
++      }
++}
++
++static inline void php_sqlite_strtolower(char *s)
++{
++      while (*s!='\0') {
++              *s = tolower(*s);
++              s++;
++      }
++}
++
++/* {{{ PHP_INI
++ */
++PHP_INI_BEGIN()
++STD_PHP_INI_ENTRY_EX("sqlite.assoc_case", "0", PHP_INI_ALL, OnUpdateLong, assoc_case, zend_sqlite_globals, sqlite_globals, display_link_numbers)
++PHP_INI_END()
++/* }}} */
++
++#define DB_FROM_ZVAL(db, zv)  ZEND_FETCH_RESOURCE2(db, struct php_sqlite_db *, zv, -1, "sqlite database", le_sqlite_db, le_sqlite_pdb)
++
++#define DB_FROM_OBJECT(db, object) \
++      { \
++              sqlite_object *obj = (sqlite_object*) zend_object_store_get_object(object TSRMLS_CC); \
++              db = obj->u.db; \
++              if (!db) { \
++                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "The database wasn't opened"); \
++                      RETURN_NULL(); \
++              } \
++      }
++
++#define RES_FROM_OBJECT_RESTORE_ERH(res, object, error_handling) \
++      { \
++              sqlite_object *obj = (sqlite_object*) zend_object_store_get_object(object TSRMLS_CC); \
++              res = obj->u.res; \
++              if (!res) { \
++                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "No result set available"); \
++                      if (error_handling) \
++                              zend_restore_error_handling(error_handling TSRMLS_CC); \
++                      RETURN_NULL(); \
++              } \
++      }
++
++#define RES_FROM_OBJECT(res, object) RES_FROM_OBJECT_RESTORE_ERH(res, object, NULL)
++
++#define PHP_SQLITE_EMPTY_QUERY \
++      if (!sql_len || !*sql) { \
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot execute empty query."); \
++              RETURN_FALSE; \
++      }
++
++struct php_sqlite_result {
++      struct php_sqlite_db *db;
++      sqlite_vm *vm;
++      int buffered;
++      int ncolumns;
++      int nrows;
++      int curr_row;
++      char **col_names;
++      int alloc_rows;
++      int mode;
++      char **table;
++};
++
++struct php_sqlite_db {
++      sqlite *db;
++      int last_err_code;
++      zend_bool is_persistent;
++      long rsrc_id;
++
++      HashTable callbacks;
++};
++
++struct php_sqlite_agg_functions {
++      struct php_sqlite_db *db;
++      int is_valid;
++      zval *step;
++      zval *fini;
++};
++
++static void php_sqlite_fetch_array(struct php_sqlite_result *res, int mode, zend_bool decode_binary, int move_next, zval *return_value TSRMLS_DC);
++static int php_sqlite_fetch(struct php_sqlite_result *rres TSRMLS_DC);
++
++enum { PHPSQLITE_ASSOC = 1, PHPSQLITE_NUM = 2, PHPSQLITE_BOTH = PHPSQLITE_ASSOC|PHPSQLITE_NUM };
++
++/* {{{ arginfo */
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_popen, 0, 0, 1)
++      ZEND_ARG_INFO(0, filename)
++      ZEND_ARG_INFO(0, mode)
++      ZEND_ARG_INFO(1, error_message)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_open, 0, 0, 1)
++      ZEND_ARG_INFO(0, filename)
++      ZEND_ARG_INFO(0, mode)
++      ZEND_ARG_INFO(1, error_message)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_factory, 0, 0, 1)
++      ZEND_ARG_INFO(0, filename)
++      ZEND_ARG_INFO(0, mode)
++      ZEND_ARG_INFO(1, error_message)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_busy_timeout, 0, 0, 2)
++      ZEND_ARG_INFO(0, db)
++      ZEND_ARG_INFO(0, ms)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_busy_timeout, 0, 0, 1)
++      ZEND_ARG_INFO(0, ms)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_close, 0, 0, 1)
++      ZEND_ARG_INFO(0, db)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_unbuffered_query, 0, 0, 2)
++      ZEND_ARG_INFO(0, query)
++      ZEND_ARG_INFO(0, db)
++      ZEND_ARG_INFO(0, result_type)
++      ZEND_ARG_INFO(1, error_message)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_unbuffered_query, 0, 0, 1)
++      ZEND_ARG_INFO(0, query)
++      ZEND_ARG_INFO(0, result_type)
++      ZEND_ARG_INFO(1, error_message)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_fetch_column_types, 0, 0, 2)
++      ZEND_ARG_INFO(0, table_name)
++      ZEND_ARG_INFO(0, db)
++      ZEND_ARG_INFO(0, result_type)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_fetch_column_types, 0, 0, 1)
++      ZEND_ARG_INFO(0, table_name)
++      ZEND_ARG_INFO(0, result_type)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_query, 0, 0, 2)
++      ZEND_ARG_INFO(0, query)
++      ZEND_ARG_INFO(0, db)
++      ZEND_ARG_INFO(0, result_type)
++      ZEND_ARG_INFO(1, error_message)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_query, 0, 0, 1)
++      ZEND_ARG_INFO(0, query)
++      ZEND_ARG_INFO(0, result_type)
++      ZEND_ARG_INFO(1, error_message)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_exec, 0, 0, 2)
++      ZEND_ARG_INFO(0, query)
++      ZEND_ARG_INFO(0, db)
++      ZEND_ARG_INFO(1, error_message)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_exec, 0, 0, 1)
++      ZEND_ARG_INFO(0, query)
++      ZEND_ARG_INFO(1, error_message)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_fetch_all, 0, 0, 1)
++      ZEND_ARG_INFO(0, result)
++      ZEND_ARG_INFO(0, result_type)
++      ZEND_ARG_INFO(0, decode_binary)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_fetch_all, 0, 0, 0)
++      ZEND_ARG_INFO(0, result_type)
++      ZEND_ARG_INFO(0, decode_binary)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_fetch_array, 0, 0, 1)
++      ZEND_ARG_INFO(0, result)
++      ZEND_ARG_INFO(0, result_type)
++      ZEND_ARG_INFO(0, decode_binary)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_fetch_array, 0, 0, 0)
++      ZEND_ARG_INFO(0, result_type)
++      ZEND_ARG_INFO(0, decode_binary)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_fetch_object, 0, 0, 1)
++      ZEND_ARG_INFO(0, result)
++      ZEND_ARG_INFO(0, class_name)
++      ZEND_ARG_INFO(0, ctor_params)
++      ZEND_ARG_INFO(0, decode_binary)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_fetch_object, 0, 0, 0)
++      ZEND_ARG_INFO(0, class_name)
++      ZEND_ARG_INFO(0, ctor_params)
++      ZEND_ARG_INFO(0, decode_binary)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_array_query, 0, 0, 2)
++      ZEND_ARG_INFO(0, db)
++      ZEND_ARG_INFO(0, query)
++      ZEND_ARG_INFO(0, result_type)
++      ZEND_ARG_INFO(0, decode_binary)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_array_query, 0, 0, 1)
++      ZEND_ARG_INFO(0, query)
++      ZEND_ARG_INFO(0, result_type)
++      ZEND_ARG_INFO(0, decode_binary)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_single_query, 0, 0, 2)
++      ZEND_ARG_INFO(0, db)
++      ZEND_ARG_INFO(0, query)
++      ZEND_ARG_INFO(0, first_row_only)
++      ZEND_ARG_INFO(0, decode_binary)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_single_query, 0, 0, 1)
++      ZEND_ARG_INFO(0, query)
++      ZEND_ARG_INFO(0, first_row_only)
++      ZEND_ARG_INFO(0, decode_binary)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_fetch_single, 0, 0, 1)
++      ZEND_ARG_INFO(0, result)
++      ZEND_ARG_INFO(0, decode_binary)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_fetch_single, 0, 0, 0)
++      ZEND_ARG_INFO(0, decode_binary)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_current, 0, 0, 1)
++      ZEND_ARG_INFO(0, result)
++      ZEND_ARG_INFO(0, result_type)
++      ZEND_ARG_INFO(0, decode_binary)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_current, 0, 0, 0)
++      ZEND_ARG_INFO(0, result_type)
++      ZEND_ARG_INFO(0, decode_binary)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_column, 0, 0, 2)
++      ZEND_ARG_INFO(0, result)
++      ZEND_ARG_INFO(0, index_or_name)
++      ZEND_ARG_INFO(0, decode_binary)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_column, 0, 0, 1)
++      ZEND_ARG_INFO(0, index_or_name)
++      ZEND_ARG_INFO(0, decode_binary)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO(arginfo_sqlite_libversion, 0)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO(arginfo_sqlite_libencoding, 0)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_changes, 0, 0, 1)
++      ZEND_ARG_INFO(0, db)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO(arginfo_sqlite_method_changes, 0)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_last_insert_rowid, 0, 0, 1)
++      ZEND_ARG_INFO(0, db)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO(arginfo_sqlite_method_last_insert_rowid, 0)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_num_rows, 0, 0, 1)
++      ZEND_ARG_INFO(0, result)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO(arginfo_sqlite_method_num_rows, 0)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_valid, 0, 0, 1)
++      ZEND_ARG_INFO(0, result)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO(arginfo_sqlite_method_valid, 0)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_has_prev, 0, 0, 1)
++      ZEND_ARG_INFO(0, result)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO(arginfo_sqlite_method_has_prev, 0)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_num_fields, 0, 0, 1)
++      ZEND_ARG_INFO(0, result)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO(arginfo_sqlite_method_num_fields, 0)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_field_name, 0, 0, 2)
++      ZEND_ARG_INFO(0, result)
++      ZEND_ARG_INFO(0, field_index)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_field_name, 0, 0, 1)
++      ZEND_ARG_INFO(0, field_index)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_seek, 0, 0, 2)
++      ZEND_ARG_INFO(0, result)
++      ZEND_ARG_INFO(0, row)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_seek, 0, 0, 1)
++      ZEND_ARG_INFO(0, row)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_rewind, 0, 0, 1)
++      ZEND_ARG_INFO(0, result)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO(arginfo_sqlite_method_rewind, 0)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_next, 0, 0, 1)
++      ZEND_ARG_INFO(0, result)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO(arginfo_sqlite_method_next, 0)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_key, 0, 0, 1)
++      ZEND_ARG_INFO(0, result)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO(arginfo_sqlite_method_key, 0)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_prev, 0, 0, 1)
++      ZEND_ARG_INFO(0, result)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO(arginfo_sqlite_method_prev, 0)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_escape_string, 0, 0, 1)
++      ZEND_ARG_INFO(0, item)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_last_error, 0, 0, 1)
++      ZEND_ARG_INFO(0, db)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO(arginfo_sqlite_method_last_error, 0)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_error_string, 0, 0, 1)
++      ZEND_ARG_INFO(0, error_code)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_create_aggregate, 0, 0, 4)
++      ZEND_ARG_INFO(0, db)
++      ZEND_ARG_INFO(0, funcname)
++      ZEND_ARG_INFO(0, step_func)
++      ZEND_ARG_INFO(0, finalize_func)
++      ZEND_ARG_INFO(0, num_args)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_create_aggregate, 0, 0, 3)
++      ZEND_ARG_INFO(0, funcname)
++      ZEND_ARG_INFO(0, step_func)
++      ZEND_ARG_INFO(0, finalize_func)
++      ZEND_ARG_INFO(0, num_args)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_create_function, 0, 0, 3)
++      ZEND_ARG_INFO(0, db)
++      ZEND_ARG_INFO(0, funcname)
++      ZEND_ARG_INFO(0, callback)
++      ZEND_ARG_INFO(0, num_args)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_method_create_function, 0, 0, 2)
++      ZEND_ARG_INFO(0, funcname)
++      ZEND_ARG_INFO(0, callback)
++      ZEND_ARG_INFO(0, num_args)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_udf_encode_binary, 0, 0, 1)
++      ZEND_ARG_INFO(0, data)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite_udf_decode_binary, 0, 0, 1)
++      ZEND_ARG_INFO(0, data)
++ZEND_END_ARG_INFO()
++/* }}} */
++
++const zend_function_entry sqlite_functions[] = {
++      PHP_FE(sqlite_open,                             arginfo_sqlite_open)
++      PHP_FE(sqlite_popen,                            arginfo_sqlite_popen)
++      PHP_FE(sqlite_close,                            arginfo_sqlite_close)
++      PHP_FE(sqlite_query,                            arginfo_sqlite_query)
++      PHP_FE(sqlite_exec,                             arginfo_sqlite_exec)
++      PHP_FE(sqlite_array_query,                      arginfo_sqlite_array_query)
++      PHP_FE(sqlite_single_query,             arginfo_sqlite_single_query)
++      PHP_FE(sqlite_fetch_array,                      arginfo_sqlite_fetch_array)
++      PHP_FE(sqlite_fetch_object,             arginfo_sqlite_fetch_object)
++      PHP_FE(sqlite_fetch_single,             arginfo_sqlite_fetch_single)
++      PHP_FALIAS(sqlite_fetch_string, sqlite_fetch_single, arginfo_sqlite_fetch_single)
++      PHP_FE(sqlite_fetch_all,                        arginfo_sqlite_fetch_all)
++      PHP_FE(sqlite_current,                          arginfo_sqlite_current)
++      PHP_FE(sqlite_column,                           arginfo_sqlite_column)
++      PHP_FE(sqlite_libversion,                       arginfo_sqlite_libversion)
++      PHP_FE(sqlite_libencoding,                      arginfo_sqlite_libencoding)
++      PHP_FE(sqlite_changes,                          arginfo_sqlite_changes)
++      PHP_FE(sqlite_last_insert_rowid,        arginfo_sqlite_last_insert_rowid)
++      PHP_FE(sqlite_num_rows,                         arginfo_sqlite_num_rows)
++      PHP_FE(sqlite_num_fields,                       arginfo_sqlite_num_fields)
++      PHP_FE(sqlite_field_name,                       arginfo_sqlite_field_name)
++      PHP_FE(sqlite_seek,                             arginfo_sqlite_seek)
++      PHP_FE(sqlite_rewind,                           arginfo_sqlite_rewind)
++      PHP_FE(sqlite_next,                             arginfo_sqlite_next)
++      PHP_FE(sqlite_prev,                             arginfo_sqlite_prev)
++      PHP_FE(sqlite_valid,                            arginfo_sqlite_valid)
++      PHP_FALIAS(sqlite_has_more, sqlite_valid, arginfo_sqlite_valid)
++      PHP_FE(sqlite_has_prev,                         arginfo_sqlite_has_prev)
++      PHP_FE(sqlite_escape_string,            arginfo_sqlite_escape_string)
++      PHP_FE(sqlite_busy_timeout,             arginfo_sqlite_busy_timeout)
++      PHP_FE(sqlite_last_error,                       arginfo_sqlite_last_error)
++      PHP_FE(sqlite_error_string,             arginfo_sqlite_error_string)
++      PHP_FE(sqlite_unbuffered_query,         arginfo_sqlite_unbuffered_query)
++      PHP_FE(sqlite_create_aggregate,         arginfo_sqlite_create_aggregate)
++      PHP_FE(sqlite_create_function,          arginfo_sqlite_create_function)
++      PHP_FE(sqlite_factory,                          arginfo_sqlite_factory)
++      PHP_FE(sqlite_udf_encode_binary,        arginfo_sqlite_udf_encode_binary)
++      PHP_FE(sqlite_udf_decode_binary,        arginfo_sqlite_udf_decode_binary)
++      PHP_FE(sqlite_fetch_column_types,       arginfo_sqlite_fetch_column_types)
++      {NULL, NULL, NULL}
++};
++
++const zend_function_entry sqlite_funcs_db[] = {
++      PHP_ME_MAPPING(__construct, sqlite_open, arginfo_sqlite_open, 0)
++/*    PHP_ME_MAPPING(close, sqlite_close, NULL, 0)*/
++      PHP_ME_MAPPING(query, sqlite_query, arginfo_sqlite_method_query, 0)
++      PHP_ME_MAPPING(queryExec, sqlite_exec, arginfo_sqlite_method_exec, 0)
++      PHP_ME_MAPPING(arrayQuery, sqlite_array_query, arginfo_sqlite_method_array_query, 0)
++      PHP_ME_MAPPING(singleQuery, sqlite_single_query, arginfo_sqlite_method_single_query, 0)
++      PHP_ME_MAPPING(unbufferedQuery, sqlite_unbuffered_query, arginfo_sqlite_method_unbuffered_query, 0)
++      PHP_ME_MAPPING(lastInsertRowid, sqlite_last_insert_rowid, arginfo_sqlite_method_last_insert_rowid, 0)
++      PHP_ME_MAPPING(changes, sqlite_changes, arginfo_sqlite_method_changes, 0)
++      PHP_ME_MAPPING(createAggregate, sqlite_create_aggregate, arginfo_sqlite_method_create_aggregate, 0)
++      PHP_ME_MAPPING(createFunction, sqlite_create_function, arginfo_sqlite_method_create_function, 0)
++      PHP_ME_MAPPING(busyTimeout, sqlite_busy_timeout, arginfo_sqlite_method_busy_timeout, 0)
++      PHP_ME_MAPPING(lastError, sqlite_last_error, arginfo_sqlite_method_last_error, 0)
++      PHP_ME_MAPPING(fetchColumnTypes, sqlite_fetch_column_types, arginfo_sqlite_method_fetch_column_types, 0)
++/*    PHP_ME_MAPPING(error_string, sqlite_error_string, NULL, 0) static */
++/*    PHP_ME_MAPPING(escape_string, sqlite_escape_string, NULL, 0) static */
++      {NULL, NULL, NULL}
++};
++
++const zend_function_entry sqlite_funcs_query[] = {
++      PHP_ME_MAPPING(fetch, sqlite_fetch_array, arginfo_sqlite_method_fetch_array, 0)
++      PHP_ME_MAPPING(fetchObject, sqlite_fetch_object, arginfo_sqlite_method_fetch_object, 0)
++      PHP_ME_MAPPING(fetchSingle, sqlite_fetch_single, arginfo_sqlite_method_fetch_single, 0)
++      PHP_ME_MAPPING(fetchAll, sqlite_fetch_all, arginfo_sqlite_method_fetch_all, 0)
++      PHP_ME_MAPPING(column, sqlite_column, arginfo_sqlite_method_column, 0)
++      PHP_ME_MAPPING(numFields, sqlite_num_fields, arginfo_sqlite_method_num_fields, 0)
++      PHP_ME_MAPPING(fieldName, sqlite_field_name, arginfo_sqlite_method_field_name, 0)
++      /* iterator */
++      PHP_ME_MAPPING(current, sqlite_current, arginfo_sqlite_method_current, 0)
++      PHP_ME_MAPPING(key, sqlite_key, arginfo_sqlite_method_key, 0)
++      PHP_ME_MAPPING(next, sqlite_next, arginfo_sqlite_method_next, 0)
++      PHP_ME_MAPPING(valid, sqlite_valid, arginfo_sqlite_method_valid, 0)
++      PHP_ME_MAPPING(rewind, sqlite_rewind, arginfo_sqlite_method_rewind, 0)
++      /* countable */
++      PHP_ME_MAPPING(count, sqlite_num_rows, arginfo_sqlite_method_num_rows, 0)
++      /* additional */
++      PHP_ME_MAPPING(prev, sqlite_prev, arginfo_sqlite_method_prev, 0)
++      PHP_ME_MAPPING(hasPrev, sqlite_has_prev, arginfo_sqlite_method_has_prev, 0)
++      PHP_ME_MAPPING(numRows, sqlite_num_rows, arginfo_sqlite_method_num_rows, 0)
++      PHP_ME_MAPPING(seek, sqlite_seek, arginfo_sqlite_method_seek, 0)
++      {NULL, NULL, NULL}
++};
++
++const zend_function_entry sqlite_funcs_ub_query[] = {
++      PHP_ME_MAPPING(fetch, sqlite_fetch_array, arginfo_sqlite_method_fetch_array, 0)
++      PHP_ME_MAPPING(fetchObject, sqlite_fetch_object, arginfo_sqlite_method_fetch_object, 0)
++      PHP_ME_MAPPING(fetchSingle, sqlite_fetch_single, arginfo_sqlite_method_fetch_single, 0)
++      PHP_ME_MAPPING(fetchAll, sqlite_fetch_all, arginfo_sqlite_method_fetch_all, 0)
++      PHP_ME_MAPPING(column, sqlite_column, arginfo_sqlite_method_column, 0)
++      PHP_ME_MAPPING(numFields, sqlite_num_fields, arginfo_sqlite_method_num_fields, 0)
++      PHP_ME_MAPPING(fieldName, sqlite_field_name, arginfo_sqlite_method_field_name, 0)
++      /* iterator */
++      PHP_ME_MAPPING(current, sqlite_current, arginfo_sqlite_method_current, 0)
++      PHP_ME_MAPPING(next, sqlite_next, arginfo_sqlite_method_next, 0)
++      PHP_ME_MAPPING(valid, sqlite_valid, arginfo_sqlite_method_valid, 0)
++      {NULL, NULL, NULL}
++};
++
++const zend_function_entry sqlite_funcs_exception[] = {
++      {NULL, NULL, NULL}
++};
++
++/* Dependancies */
++static const zend_module_dep sqlite_deps[] = {
++#if defined(HAVE_SPL) && ((PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1))
++      ZEND_MOD_REQUIRED("spl")
++#endif
++#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
++      ZEND_MOD_REQUIRED("session")
++#endif
++#ifdef PHP_SQLITE2_HAVE_PDO
++      ZEND_MOD_REQUIRED("pdo")
++#endif
++      {NULL, NULL, NULL}
++};
++
++zend_module_entry sqlite_module_entry = {
++#if ZEND_MODULE_API_NO >= 20050922
++      STANDARD_MODULE_HEADER_EX, NULL,
++      sqlite_deps,
++#elif ZEND_MODULE_API_NO >= 20010901
++      STANDARD_MODULE_HEADER,
++#endif
++      "SQLite",
++      sqlite_functions,
++      PHP_MINIT(sqlite),
++      PHP_MSHUTDOWN(sqlite),
++      NULL,
++      PHP_RSHUTDOWN(sqlite),
++      PHP_MINFO(sqlite),
++#if ZEND_MODULE_API_NO >= 20010901
++      PHP_SQLITE_MODULE_VERSION,
++#endif
++#if ZEND_MODULE_API_NO >= 20060613
++      PHP_MODULE_GLOBALS(sqlite),
++      PHP_GINIT(sqlite),
++      NULL,
++      NULL,
++      STANDARD_MODULE_PROPERTIES_EX
++#else
++      STANDARD_MODULE_PROPERTIES
++#endif
++};
++
++
++#ifdef COMPILE_DL_SQLITE
++ZEND_GET_MODULE(sqlite)
++#endif
++
++static int php_sqlite_callback_invalidator(struct php_sqlite_agg_functions *funcs TSRMLS_DC)
++{
++      if (!funcs->is_valid) {
++              return 0;
++      }
++
++      if (funcs->step) {
++              zval_ptr_dtor(&funcs->step);
++              funcs->step = NULL;
++      }
++
++      if (funcs->fini) {
++              zval_ptr_dtor(&funcs->fini);
++              funcs->fini = NULL;
++      }
++
++      funcs->is_valid = 0;
++
++      return 0;
++}
++
++
++static void php_sqlite_callback_dtor(void *pDest)
++{
++      struct php_sqlite_agg_functions *funcs = (struct php_sqlite_agg_functions*)pDest;
++
++      if (funcs->is_valid) {
++              TSRMLS_FETCH();
++
++              php_sqlite_callback_invalidator(funcs TSRMLS_CC);
++      }
++}
++
++static ZEND_RSRC_DTOR_FUNC(php_sqlite_db_dtor)
++{
++      if (rsrc->ptr) {
++              struct php_sqlite_db *db = (struct php_sqlite_db*)rsrc->ptr;
++
++              sqlite_close(db->db);
++
++              zend_hash_destroy(&db->callbacks);
++
++              pefree(db, db->is_persistent);
++
++              rsrc->ptr = NULL;
++      }
++}
++
++static void real_result_dtor(struct php_sqlite_result *res TSRMLS_DC)
++{
++      int i, j, base;
++
++      if (res->vm) {
++              sqlite_finalize(res->vm, NULL);
++      }
++
++      if (res->table) {
++              if (!res->buffered && res->nrows) {
++                      res->nrows = 1; /* only one row is stored */
++              }
++              for (i = 0; i < res->nrows; i++) {
++                      base = i * res->ncolumns;
++                      for (j = 0; j < res->ncolumns; j++) {
++                              if (res->table[base + j] != NULL) {
++                                      efree(res->table[base + j]);
++                              }
++                      }
++              }
++              efree(res->table);
++      }
++      if (res->col_names) {
++              for (j = 0; j < res->ncolumns; j++) {
++                      efree(res->col_names[j]);
++              }
++              efree(res->col_names);
++      }
++
++      if (res->db) {
++              zend_list_delete(res->db->rsrc_id);
++      }
++      efree(res);
++}
++
++static int _clean_unfinished_results(zend_rsrc_list_entry *le, void *db TSRMLS_DC)
++{
++      if (Z_TYPE_P(le) == le_sqlite_result) {
++              struct php_sqlite_result *res = (struct php_sqlite_result *)le->ptr;
++              if (res->db->rsrc_id == ((struct php_sqlite_db*)db)->rsrc_id) {
++                      return ZEND_HASH_APPLY_REMOVE;
++              }
++      }
++      return ZEND_HASH_APPLY_KEEP;
++}
++
++static ZEND_RSRC_DTOR_FUNC(php_sqlite_result_dtor)
++{
++      struct php_sqlite_result *res = (struct php_sqlite_result *)rsrc->ptr;
++      real_result_dtor(res TSRMLS_CC);
++}
++
++static int php_sqlite_forget_persistent_id_numbers(zend_rsrc_list_entry *rsrc TSRMLS_DC)
++{
++      struct php_sqlite_db *db = (struct php_sqlite_db*)rsrc->ptr;
++
++      if (Z_TYPE_P(rsrc) != le_sqlite_pdb) {
++              return 0;
++      }
++
++      /* prevent bad mojo if someone tries to use a previously registered function in the next request */
++      zend_hash_apply(&db->callbacks, (apply_func_t)php_sqlite_callback_invalidator TSRMLS_CC);
++
++      db->rsrc_id = FAILURE;
++
++      /* don't leave pending commits hanging around */
++      sqlite_exec(db->db, "ROLLBACK", NULL, NULL, NULL);
++
++      return 0;
++}
++
++PHP_RSHUTDOWN_FUNCTION(sqlite)
++{
++      zend_hash_apply(&EG(persistent_list), (apply_func_t)php_sqlite_forget_persistent_id_numbers TSRMLS_CC);
++      return SUCCESS;
++}
++
++/* {{{ PHP Function interface */
++static void php_sqlite_generic_function_callback(sqlite_func *func, int argc, const char **argv)
++{
++      zval *retval = NULL;
++      zval ***zargs = NULL;
++      zval funcname;
++      int i, res;
++      char *callable = NULL, *errbuf=NULL;
++      TSRMLS_FETCH();
++
++      /* sanity check the args */
++      if (argc == 0) {
++              sqlite_set_result_error(func, "not enough parameters", -1);
++              return;
++      }
++
++      ZVAL_STRING(&funcname, (char*)argv[0], 1);
++
++      if (!zend_make_callable(&funcname, &callable TSRMLS_CC)) {
++              spprintf(&errbuf, 0, "function `%s' is not a function name", callable);
++              sqlite_set_result_error(func, errbuf, -1);
++              efree(errbuf);
++              efree(callable);
++              zval_dtor(&funcname);
++              return;
++      }
++
++      if (argc > 1) {
++              zargs = (zval ***)safe_emalloc((argc - 1), sizeof(zval **), 0);
++
++              for (i = 0; i < argc-1; i++) {
++                      zargs[i] = emalloc(sizeof(zval *));
++                      MAKE_STD_ZVAL(*zargs[i]);
++                      ZVAL_STRING(*zargs[i], (char*)argv[i+1], 1);
++              }
++      }
++
++      res = call_user_function_ex(EG(function_table),
++                      NULL,
++                      &funcname,
++                      &retval,
++                      argc-1,
++                      zargs,
++                      0, NULL TSRMLS_CC);
++
++      zval_dtor(&funcname);
++
++      if (res == SUCCESS) {
++              if (retval == NULL) {
++                      sqlite_set_result_string(func, NULL, 0);
++              } else {
++                      switch (Z_TYPE_P(retval)) {
++                              case IS_STRING:
++                                      sqlite_set_result_string(func, Z_STRVAL_P(retval), Z_STRLEN_P(retval));
++                                      break;
++                              case IS_LONG:
++                              case IS_BOOL:
++                                      sqlite_set_result_int(func, Z_LVAL_P(retval));
++                                      break;
++                              case IS_DOUBLE:
++                                      sqlite_set_result_double(func, Z_DVAL_P(retval));
++                                      break;
++                              case IS_NULL:
++                              default:
++                                      sqlite_set_result_string(func, NULL, 0);
++                      }
++              }
++      } else {
++              char *errbuf;
++              spprintf(&errbuf, 0, "call_user_function_ex failed for function %s()", callable);
++              sqlite_set_result_error(func, errbuf, -1);
++              efree(errbuf);
++      }
++
++      efree(callable);
++
++      if (retval) {
++              zval_ptr_dtor(&retval);
++      }
++
++      if (zargs) {
++              for (i = 0; i < argc-1; i++) {
++                      zval_ptr_dtor(zargs[i]);
++                      efree(zargs[i]);
++              }
++              efree(zargs);
++      }
++}
++/* }}} */
++
++/* {{{ callback for sqlite_create_function */
++static void php_sqlite_function_callback(sqlite_func *func, int argc, const char **argv)
++{
++      zval *retval = NULL;
++      zval ***zargs = NULL;
++      int i, res;
++      struct php_sqlite_agg_functions *funcs = sqlite_user_data(func);
++      TSRMLS_FETCH();
++
++      if (!funcs->is_valid) {
++              sqlite_set_result_error(func, "this function has not been correctly defined for this request", -1);
++              return;
++      }
++
++      if (argc > 0) {
++              zargs = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
++
++              for (i = 0; i < argc; i++) {
++                      zargs[i] = emalloc(sizeof(zval *));
++                      MAKE_STD_ZVAL(*zargs[i]);
++
++                      if (argv[i] == NULL) {
++                              ZVAL_NULL(*zargs[i]);
++                      } else {
++                              ZVAL_STRING(*zargs[i], (char*)argv[i], 1);
++                      }
++              }
++      }
++
++      res = call_user_function_ex(EG(function_table),
++                      NULL,
++                      funcs->step,
++                      &retval,
++                      argc,
++                      zargs,
++                      0, NULL TSRMLS_CC);
++
++      if (res == SUCCESS) {
++              if (retval == NULL) {
++                      sqlite_set_result_string(func, NULL, 0);
++              } else {
++                      switch (Z_TYPE_P(retval)) {
++                              case IS_STRING:
++                                      /* TODO: for binary results, need to encode the string */
++                                      sqlite_set_result_string(func, Z_STRVAL_P(retval), Z_STRLEN_P(retval));
++                                      break;
++                              case IS_LONG:
++                              case IS_BOOL:
++                                      sqlite_set_result_int(func, Z_LVAL_P(retval));
++                                      break;
++                              case IS_DOUBLE:
++                                      sqlite_set_result_double(func, Z_DVAL_P(retval));
++                                      break;
++                              case IS_NULL:
++                              default:
++                                      sqlite_set_result_string(func, NULL, 0);
++                      }
++              }
++      } else {
++              sqlite_set_result_error(func, "call_user_function_ex failed", -1);
++      }
++
++      if (retval) {
++              zval_ptr_dtor(&retval);
++      }
++
++      if (zargs) {
++              for (i = 0; i < argc; i++) {
++                      zval_ptr_dtor(zargs[i]);
++                      efree(zargs[i]);
++              }
++              efree(zargs);
++      }
++}
++/* }}} */
++
++/* {{{ callback for sqlite_create_aggregate: step function */
++static void php_sqlite_agg_step_function_callback(sqlite_func *func, int argc, const char **argv)
++{
++      zval *retval = NULL;
++      zval ***zargs;
++      zval **context_p;
++      int i, res, zargc;
++      struct php_sqlite_agg_functions *funcs = sqlite_user_data(func);
++      TSRMLS_FETCH();
++
++      if (!funcs->is_valid) {
++              sqlite_set_result_error(func, "this function has not been correctly defined for this request", -1);
++              return;
++      }
++
++      /* sanity check the args */
++      if (argc < 1) {
++              return;
++      }
++
++      zargc = argc + 1;
++      zargs = (zval ***)safe_emalloc(zargc, sizeof(zval **), 0);
++
++      /* first arg is always the context zval */
++      context_p = (zval **)sqlite_aggregate_context(func, sizeof(*context_p));
++
++      if (*context_p == NULL) {
++              MAKE_STD_ZVAL(*context_p);
++              Z_SET_ISREF_PP(context_p);
++              Z_TYPE_PP(context_p) = IS_NULL;
++      }
++
++      zargs[0] = context_p;
++
++      /* copy the other args */
++      for (i = 0; i < argc; i++) {
++              zargs[i+1] = emalloc(sizeof(zval *));
++              MAKE_STD_ZVAL(*zargs[i+1]);
++              if (argv[i] == NULL) {
++                      ZVAL_NULL(*zargs[i+1]);
++              } else {
++                      ZVAL_STRING(*zargs[i+1], (char*)argv[i], 1);
++              }
++      }
++
++      res = call_user_function_ex(EG(function_table),
++                      NULL,
++                      funcs->step,
++                      &retval,
++                      zargc,
++                      zargs,
++                      0, NULL TSRMLS_CC);
++
++      if (res != SUCCESS) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "call_user_function_ex failed");
++      }
++
++      if (retval) {
++              zval_ptr_dtor(&retval);
++      }
++
++      if (zargs) {
++              for (i = 1; i < zargc; i++) {
++                      zval_ptr_dtor(zargs[i]);
++                      efree(zargs[i]);
++              }
++              efree(zargs);
++      }
++}
++/* }}} */
++
++/* {{{ callback for sqlite_create_aggregate: finalize function */
++static void php_sqlite_agg_fini_function_callback(sqlite_func *func)
++{
++      zval *retval = NULL;
++      int res;
++      struct php_sqlite_agg_functions *funcs = sqlite_user_data(func);
++      zval **context_p;
++      TSRMLS_FETCH();
++
++      if (!funcs->is_valid) {
++              sqlite_set_result_error(func, "this function has not been correctly defined for this request", -1);
++              return;
++      }
++
++      context_p = (zval **)sqlite_aggregate_context(func, sizeof(*context_p));
++
++      res = call_user_function_ex(EG(function_table),
++                      NULL,
++                      funcs->fini,
++                      &retval,
++                      1,
++                      &context_p,
++                      0, NULL TSRMLS_CC);
++
++      if (res == SUCCESS) {
++              if (retval == NULL) {
++                      sqlite_set_result_string(func, NULL, 0);
++              } else {
++                      switch (Z_TYPE_P(retval)) {
++                              case IS_STRING:
++                                      /* TODO: for binary results, need to encode the string */
++                                      sqlite_set_result_string(func, Z_STRVAL_P(retval), Z_STRLEN_P(retval));
++                                      break;
++                              case IS_LONG:
++                              case IS_BOOL:
++                                      sqlite_set_result_int(func, Z_LVAL_P(retval));
++                                      break;
++                              case IS_DOUBLE:
++                                      sqlite_set_result_double(func, Z_DVAL_P(retval));
++                                      break;
++                              case IS_NULL:
++                              default:
++                                      sqlite_set_result_string(func, NULL, 0);
++                      }
++              }
++      } else {
++              sqlite_set_result_error(func, "call_user_function_ex failed", -1);
++      }
++
++      if (retval) {
++              zval_ptr_dtor(&retval);
++      }
++
++      zval_ptr_dtor(context_p);
++}
++/* }}} */
++
++/* {{{ Authorization Callback */
++static int php_sqlite_authorizer(void *autharg, int access_type, const char *arg3, const char *arg4,
++              const char *arg5, const char *arg6)
++{
++      switch (access_type) {
++              case SQLITE_COPY:
++                      if (strncmp(arg4, ":memory:", sizeof(":memory:") - 1)) {
++                              TSRMLS_FETCH();
++                              if (PG(safe_mode) && (!php_checkuid(arg4, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
++                                      return SQLITE_DENY;
++                              }
++
++                              if (php_check_open_basedir(arg4 TSRMLS_CC)) {
++                                      return SQLITE_DENY;
++                              }
++                      }
++                      return SQLITE_OK;
++#ifdef SQLITE_ATTACH
++              case SQLITE_ATTACH:
++                      if (strncmp(arg3, ":memory:", sizeof(":memory:") - 1)) {
++                              TSRMLS_FETCH();
++                              if (PG(safe_mode) && (!php_checkuid(arg3, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
++                                      return SQLITE_DENY;
++                              }
++
++                              if (php_check_open_basedir(arg3 TSRMLS_CC)) {
++                                      return SQLITE_DENY;
++                              }
++                      }
++                      return SQLITE_OK;
++#endif
++
++              default:
++                      /* access allowed */
++                      return SQLITE_OK;
++      }
++}
++/* }}} */
++
++/* {{{ OO init/structure stuff */
++#define REGISTER_SQLITE_CLASS(name, c_name, parent) \
++      { \
++              zend_class_entry ce; \
++              INIT_CLASS_ENTRY(ce, "SQLite" # name, sqlite_funcs_ ## c_name); \
++              ce.create_object = sqlite_object_new_ ## c_name; \
++              sqlite_ce_ ## c_name = zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); \
++              memcpy(&sqlite_object_handlers_ ## c_name, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); \
++              sqlite_object_handlers_ ## c_name.clone_obj = NULL; \
++              sqlite_ce_ ## c_name->ce_flags |= ZEND_ACC_FINAL_CLASS; \
++      }
++
++zend_class_entry *sqlite_ce_db, *sqlite_ce_exception;
++zend_class_entry *sqlite_ce_query, *sqlite_ce_ub_query;
++
++static zend_object_handlers sqlite_object_handlers_db;
++static zend_object_handlers sqlite_object_handlers_query;
++static zend_object_handlers sqlite_object_handlers_ub_query;
++static zend_object_handlers sqlite_object_handlers_exception;
++
++typedef enum {
++      is_db,
++      is_result
++} sqlite_obj_type;
++
++typedef struct _sqlite_object {
++      zend_object       std;
++      sqlite_obj_type   type;
++      union {
++              struct php_sqlite_db     *db;
++              struct php_sqlite_result *res;
++              void *ptr;
++      } u;
++} sqlite_object;
++
++static int sqlite_free_persistent(zend_rsrc_list_entry *le, void *ptr TSRMLS_DC)
++{
++      return le->ptr == ptr ? ZEND_HASH_APPLY_REMOVE : ZEND_HASH_APPLY_KEEP;
++}
++
++static void sqlite_object_free_storage(void *object TSRMLS_DC)
++{
++      sqlite_object *intern = (sqlite_object *)object;
++
++      zend_object_std_dtor(&intern->std TSRMLS_CC);
++
++      if (intern->u.ptr) {
++              if (intern->type == is_db) {
++                      if (intern->u.db->rsrc_id) {
++                              zend_list_delete(intern->u.db->rsrc_id);
++                              zend_hash_apply_with_argument(&EG(persistent_list), (apply_func_arg_t) sqlite_free_persistent, &intern->u.ptr TSRMLS_CC);
++                      }
++              } else {
++                      real_result_dtor(intern->u.res TSRMLS_CC);
++              }
++      }
++
++      efree(object);
++}
++
++static void sqlite_object_new(zend_class_entry *class_type, zend_object_handlers *handlers, zend_object_value *retval TSRMLS_DC)
++{
++      sqlite_object *intern;
++      zval *tmp;
++
++      intern = emalloc(sizeof(sqlite_object));
++      memset(intern, 0, sizeof(sqlite_object));
++
++      zend_object_std_init(&intern->std, class_type TSRMLS_CC);
++      zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
++
++      retval->handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) sqlite_object_free_storage, NULL TSRMLS_CC);
++      retval->handlers = handlers;
++}
++
++static zend_object_value sqlite_object_new_db(zend_class_entry *class_type TSRMLS_DC)
++{
++      zend_object_value retval;
++
++      sqlite_object_new(class_type, &sqlite_object_handlers_db, &retval TSRMLS_CC);
++      return retval;
++}
++
++static zend_object_value sqlite_object_new_query(zend_class_entry *class_type TSRMLS_DC)
++{
++      zend_object_value retval;
++
++      sqlite_object_new(class_type, &sqlite_object_handlers_query, &retval TSRMLS_CC);
++      return retval;
++}
++
++static zend_object_value sqlite_object_new_ub_query(zend_class_entry *class_type TSRMLS_DC)
++{
++      zend_object_value retval;
++
++      sqlite_object_new(class_type, &sqlite_object_handlers_ub_query, &retval TSRMLS_CC);
++      return retval;
++}
++
++static zend_object_value sqlite_object_new_exception(zend_class_entry *class_type TSRMLS_DC)
++{
++      zend_object_value retval;
++
++      sqlite_object_new(class_type, &sqlite_object_handlers_exception, &retval TSRMLS_CC);
++      return retval;
++}
++
++#define SQLITE_REGISTER_OBJECT(_type, _object, _ptr) \
++      { \
++              sqlite_object *obj; \
++              obj = (sqlite_object*)zend_object_store_get_object(_object TSRMLS_CC); \
++              obj->type = is_ ## _type; \
++              obj->u._type = _ptr; \
++      }
++
++static zend_class_entry *sqlite_get_ce_query(const zval *object TSRMLS_DC)
++{
++      return sqlite_ce_query;
++}
++
++static zend_class_entry *sqlite_get_ce_ub_query(const zval *object TSRMLS_DC)
++{
++      return sqlite_ce_ub_query;
++}
++
++static zval * sqlite_instanciate(zend_class_entry *pce, zval *object TSRMLS_DC)
++{
++      if (!object) {
++              ALLOC_ZVAL(object);
++      }
++      Z_TYPE_P(object) = IS_OBJECT;
++      object_init_ex(object, pce);
++      Z_SET_REFCOUNT_P(object, 1);
++      Z_SET_ISREF_P(object);
++      return object;
++}
++
++typedef struct _sqlite_object_iterator {
++      zend_object_iterator     it;
++      struct php_sqlite_result *res;
++      zval *value;
++} sqlite_object_iterator;
++
++void sqlite_iterator_dtor(zend_object_iterator *iter TSRMLS_DC)
++{
++      zval *object = (zval*)((sqlite_object_iterator*)iter)->it.data;
++
++      if (((sqlite_object_iterator*)iter)->value) {
++              zval_ptr_dtor(&((sqlite_object_iterator*)iter)->value);
++              ((sqlite_object_iterator*)iter)->value = NULL;
++      }
++      zval_ptr_dtor(&object);
++      efree(iter);
++}
++
++void sqlite_iterator_rewind(zend_object_iterator *iter TSRMLS_DC)
++{
++      struct php_sqlite_result *res = ((sqlite_object_iterator*)iter)->res;
++
++      if (((sqlite_object_iterator*)iter)->value) {
++              zval_ptr_dtor(&((sqlite_object_iterator*)iter)->value);
++              ((sqlite_object_iterator*)iter)->value = NULL;
++      }
++      if (res) {
++              res->curr_row = 0;
++      }
++}
++
++int sqlite_iterator_valid(zend_object_iterator *iter TSRMLS_DC)
++{
++      struct php_sqlite_result *res = ((sqlite_object_iterator*)iter)->res;
++
++      if (res && res->curr_row < res->nrows && res->nrows) { /* curr_row may be -1 */
++              return SUCCESS;
++      } else {
++              return FAILURE;
++      }
++}
++
++void sqlite_iterator_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
++{
++      struct php_sqlite_result *res = ((sqlite_object_iterator*)iter)->res;
++
++      *data = &((sqlite_object_iterator*)iter)->value;
++      if (res && !**data) {
++              MAKE_STD_ZVAL(**data);
++              php_sqlite_fetch_array(res, res->mode, 1, 0, **data TSRMLS_CC);
++      }
++
++}
++
++int sqlite_iterator_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
++{
++      struct php_sqlite_result *res = ((sqlite_object_iterator*)iter)->res;
++
++      *str_key = NULL;
++      *str_key_len = 0;
++      *int_key = res ? res->curr_row : 0;
++      return HASH_KEY_IS_LONG;
++}
++
++void sqlite_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC)
++{
++      struct php_sqlite_result *res = ((sqlite_object_iterator*)iter)->res;
++
++      if (((sqlite_object_iterator*)iter)->value) {
++              zval_ptr_dtor(&((sqlite_object_iterator*)iter)->value);
++              ((sqlite_object_iterator*)iter)->value = NULL;
++      }
++      if (res) {
++              if (!res->buffered && res->vm) {
++                      php_sqlite_fetch(res TSRMLS_CC);
++              }
++              if (res->curr_row >= res->nrows) {
++                      /* php_error_docref(NULL TSRMLS_CC, E_WARNING, "no more rows available"); */
++                      return;
++              }
++
++              res->curr_row++;
++      }
++}
++
++zend_object_iterator_funcs sqlite_ub_query_iterator_funcs = {
++      sqlite_iterator_dtor,
++      sqlite_iterator_valid,
++      sqlite_iterator_get_current_data,
++      sqlite_iterator_get_current_key,
++      sqlite_iterator_move_forward,
++      NULL
++};
++
++zend_object_iterator_funcs sqlite_query_iterator_funcs = {
++      sqlite_iterator_dtor,
++      sqlite_iterator_valid,
++      sqlite_iterator_get_current_data,
++      sqlite_iterator_get_current_key,
++      sqlite_iterator_move_forward,
++      sqlite_iterator_rewind
++};
++
++zend_object_iterator *sqlite_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
++{
++      sqlite_object_iterator *iterator = emalloc(sizeof(sqlite_object_iterator));
++
++      sqlite_object *obj = (sqlite_object*) zend_object_store_get_object(object TSRMLS_CC);
++
++      if (by_ref) {
++              zend_error(E_RECOVERABLE_ERROR, "An iterator cannot be used with foreach by reference");
++      }
++      Z_ADDREF_P(object);
++      iterator->it.data = (void*)object;
++      iterator->it.funcs = ce->iterator_funcs.funcs;
++      iterator->res = obj->u.res;
++      iterator->value = NULL;
++      return (zend_object_iterator*)iterator;
++}
++/* }}} */
++
++static PHP_GINIT_FUNCTION(sqlite)
++{
++      sqlite_globals->assoc_case = 0;
++}
++
++PHP_MINIT_FUNCTION(sqlite)
++{
++      REGISTER_SQLITE_CLASS(Database,   db,        NULL);
++      REGISTER_SQLITE_CLASS(Result,     query,     NULL);
++      REGISTER_SQLITE_CLASS(Unbuffered, ub_query,  NULL);
++#if defined(HAVE_SPL) && ((PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1))
++      REGISTER_SQLITE_CLASS(Exception,  exception, spl_ce_RuntimeException);
++#else
++      REGISTER_SQLITE_CLASS(Exception,  exception, zend_exception_get_default(TSRMLS_C));
++#endif
++
++      sqlite_ce_db->ce_flags &= ~ZEND_ACC_FINAL_CLASS;
++      sqlite_ce_db->constructor->common.fn_flags |= ZEND_ACC_FINAL;
++
++      sqlite_object_handlers_query.get_class_entry = sqlite_get_ce_query;
++      sqlite_object_handlers_ub_query.get_class_entry = sqlite_get_ce_ub_query;
++      sqlite_object_handlers_ub_query.count_elements = sqlite_count_elements;
++
++      sqlite_ce_ub_query->get_iterator = sqlite_get_iterator;
++      sqlite_ce_ub_query->iterator_funcs.funcs = &sqlite_ub_query_iterator_funcs;
++
++#if defined(HAVE_SPL) && ((PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1))
++      zend_class_implements(sqlite_ce_query TSRMLS_CC, 2, zend_ce_iterator, spl_ce_Countable);
++#else
++      zend_class_implements(sqlite_ce_query TSRMLS_CC, 1, zend_ce_iterator);
++#endif
++      sqlite_ce_query->get_iterator = sqlite_get_iterator;
++      sqlite_ce_query->iterator_funcs.funcs = &sqlite_query_iterator_funcs;
++
++      REGISTER_INI_ENTRIES();
++
++#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
++      php_session_register_module(ps_sqlite_ptr);
++#endif
++
++      le_sqlite_db = zend_register_list_destructors_ex(php_sqlite_db_dtor, NULL, "sqlite database", module_number);
++      le_sqlite_pdb = zend_register_list_destructors_ex(NULL, php_sqlite_db_dtor, "sqlite database (persistent)", module_number);
++      le_sqlite_result = zend_register_list_destructors_ex(php_sqlite_result_dtor, NULL, "sqlite result", module_number);
++
++      REGISTER_LONG_CONSTANT("SQLITE_BOTH",   PHPSQLITE_BOTH, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_NUM",    PHPSQLITE_NUM, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_ASSOC",  PHPSQLITE_ASSOC, CONST_CS|CONST_PERSISTENT);
++
++      REGISTER_LONG_CONSTANT("SQLITE_OK",                             SQLITE_OK, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_ERROR",                  SQLITE_ERROR, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_INTERNAL",               SQLITE_INTERNAL, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_PERM",                   SQLITE_PERM, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_ABORT",                  SQLITE_ABORT, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_BUSY",                   SQLITE_BUSY, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_LOCKED",                 SQLITE_LOCKED, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_NOMEM",                  SQLITE_NOMEM, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_READONLY",               SQLITE_READONLY, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_INTERRUPT",              SQLITE_INTERRUPT, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_IOERR",                  SQLITE_IOERR, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_CORRUPT",                SQLITE_CORRUPT, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_NOTFOUND",               SQLITE_NOTFOUND, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_FULL",                   SQLITE_FULL, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_CANTOPEN",               SQLITE_CANTOPEN, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_PROTOCOL",               SQLITE_PROTOCOL, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_EMPTY",                  SQLITE_EMPTY, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_SCHEMA",                 SQLITE_SCHEMA, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_TOOBIG",                 SQLITE_TOOBIG, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_CONSTRAINT",             SQLITE_CONSTRAINT, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_MISMATCH",               SQLITE_MISMATCH, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_MISUSE",                 SQLITE_MISUSE, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_NOLFS",                  SQLITE_NOLFS, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_AUTH",                   SQLITE_AUTH, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_NOTADB",                 SQLITE_NOTADB, CONST_CS|CONST_PERSISTENT);
++#ifdef SQLITE_FORMAT
++      REGISTER_LONG_CONSTANT("SQLITE_FORMAT",                 SQLITE_FORMAT, CONST_CS|CONST_PERSISTENT);
++#endif
++      REGISTER_LONG_CONSTANT("SQLITE_ROW",                    SQLITE_ROW, CONST_CS|CONST_PERSISTENT);
++      REGISTER_LONG_CONSTANT("SQLITE_DONE",                   SQLITE_DONE, CONST_CS|CONST_PERSISTENT);
++
++#ifdef PHP_SQLITE2_HAVE_PDO
++    if (FAILURE == php_pdo_register_driver(&pdo_sqlite2_driver)) {
++      return FAILURE;
++    }
++#endif
++
++      return SUCCESS;
++}
++
++PHP_MSHUTDOWN_FUNCTION(sqlite)
++{
++      UNREGISTER_INI_ENTRIES();
++
++#ifdef PHP_SQLITE2_HAVE_PDO
++    php_pdo_unregister_driver(&pdo_sqlite2_driver);
++#endif
++
++      return SUCCESS;
++}
++
++PHP_MINFO_FUNCTION(sqlite)
++{
++      php_info_print_table_start();
++      php_info_print_table_header(2, "SQLite support", "enabled");
++      php_info_print_table_row(2, "PECL Module version", PHP_SQLITE_MODULE_VERSION " $Id$");
++      php_info_print_table_row(2, "SQLite Library", sqlite_libversion());
++      php_info_print_table_row(2, "SQLite Encoding", sqlite_libencoding());
++      php_info_print_table_end();
++
++      DISPLAY_INI_ENTRIES();
++}
++
++static struct php_sqlite_db *php_sqlite_open(char *filename, int mode, char *persistent_id, zval *return_value, zval *errmsg, zval *object TSRMLS_DC)
++{
++      char *errtext = NULL;
++      sqlite *sdb = NULL;
++      struct php_sqlite_db *db = NULL;
++
++      sdb = sqlite_open(filename, mode, &errtext);
++
++      if (sdb == NULL) {
++
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errtext);
++
++              if (errmsg) {
++                      ZVAL_STRING(errmsg, errtext, 1);
++              }
++
++              sqlite_freemem(errtext);
++
++              /* if object is not an object then we're called from the factory() function */
++              if (object && Z_TYPE_P(object) != IS_OBJECT) {
++                      RETVAL_NULL();
++              } else {
++                      RETVAL_FALSE;
++              }
++              return NULL;
++      }
++
++      db = (struct php_sqlite_db *)pemalloc(sizeof(struct php_sqlite_db), persistent_id ? 1 : 0);
++      db->is_persistent = persistent_id ? 1 : 0;
++      db->last_err_code = SQLITE_OK;
++      db->db = sdb;
++
++      zend_hash_init(&db->callbacks, 0, NULL, php_sqlite_callback_dtor, db->is_persistent);
++
++      /* register the PHP functions */
++      sqlite_create_function(sdb, "php", -1, php_sqlite_generic_function_callback, 0);
++
++      /* set default busy handler; keep retrying up until 1 minute has passed,
++       * then fail with a busy status code */
++      sqlite_busy_timeout(sdb, 60000);
++
++      /* authorizer hook so we can enforce safe mode
++       * Note: the declaration of php_sqlite_authorizer is correct for 2.8.2 of libsqlite,
++       * and IS backwards binary compatible with earlier versions */
++      if (PG(safe_mode) || (PG(open_basedir) && *PG(open_basedir))) {
++              sqlite_set_authorizer(sdb, php_sqlite_authorizer, NULL);
++      }
++
++      db->rsrc_id = ZEND_REGISTER_RESOURCE(object ? NULL : return_value, db, persistent_id ? le_sqlite_pdb : le_sqlite_db);
++      if (object) {
++              /* if object is not an object then we're called from the factory() function */
++              if (Z_TYPE_P(object) != IS_OBJECT) {
++                      sqlite_instanciate(sqlite_ce_db, object TSRMLS_CC);
++              }
++              /* and now register the object */
++              SQLITE_REGISTER_OBJECT(db, object, db)
++      }
++
++      if (persistent_id) {
++              zend_rsrc_list_entry le;
++
++              Z_TYPE(le) = le_sqlite_pdb;
++              le.ptr = db;
++
++              if (FAILURE == zend_hash_update(&EG(persistent_list), persistent_id,
++                                      strlen(persistent_id)+1,
++                                      (void *)&le, sizeof(le), NULL)) {
++                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to register persistent resource");
++              }
++      }
++
++      return db;
++}
++
++/* {{{ proto resource sqlite_popen(string filename [, int mode [, string &error_message]])
++   Opens a persistent handle to a SQLite database. Will create the database if it does not exist. */
++PHP_FUNCTION(sqlite_popen)
++{
++      long mode = 0666;
++      char *filename, *fullpath, *hashkey;
++      int filename_len, hashkeylen;
++      zval *errmsg = NULL;
++      struct php_sqlite_db *db = NULL;
++      zend_rsrc_list_entry *le;
++
++      if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lz/",
++                              &filename, &filename_len, &mode, &errmsg)) {
++              return;
++      }
++      if (errmsg) {
++              zval_dtor(errmsg);
++              ZVAL_NULL(errmsg);
++      }
++
++      if (strlen(filename) != filename_len) {
++              RETURN_FALSE;
++      }
++      if (strncmp(filename, ":memory:", sizeof(":memory:") - 1)) {
++              /* resolve the fully-qualified path name to use as the hash key */
++              if (!(fullpath = expand_filepath(filename, NULL TSRMLS_CC))) {
++                      RETURN_FALSE;
++              }
++
++              if ((PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || 
++                              php_check_open_basedir(fullpath TSRMLS_CC)) {
++                      efree(fullpath);
++                      RETURN_FALSE;
++              }
++      } else {
++              fullpath = estrndup(filename, filename_len);
++      }
++
++      hashkeylen = spprintf(&hashkey, 0, "sqlite_pdb_%s:%ld", fullpath, mode);
++
++      /* do we have an existing persistent connection ? */
++      if (SUCCESS == zend_hash_find(&EG(persistent_list), hashkey, hashkeylen+1, (void*)&le)) {
++              if (Z_TYPE_P(le) == le_sqlite_pdb) {
++                      db = (struct php_sqlite_db*)le->ptr;
++
++                      if (db->rsrc_id == FAILURE) {
++                              /* give it a valid resource id for this request */
++                              db->rsrc_id = ZEND_REGISTER_RESOURCE(return_value, db, le_sqlite_pdb);
++                      } else {
++                              int type;
++                              /* sanity check to ensure that the resource is still a valid regular resource
++                               * number */
++                              if (zend_list_find(db->rsrc_id, &type) == db) {
++                                      /* already accessed this request; map it */
++                                      zend_list_addref(db->rsrc_id);
++                                      ZVAL_RESOURCE(return_value, db->rsrc_id);
++                              } else {
++                                      db->rsrc_id = ZEND_REGISTER_RESOURCE(return_value, db, le_sqlite_pdb);
++                              }
++                      }
++
++                      /* all set */
++                      goto done;
++              }
++
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Some other type of persistent resource is using this hash key!?");
++              RETVAL_FALSE;
++              goto done;
++      }
++
++      /* now we need to open the database */
++      php_sqlite_open(fullpath, (int)mode, hashkey, return_value, errmsg, NULL TSRMLS_CC);
++done:
++      efree(fullpath);
++      efree(hashkey);
++}
++/* }}} */
++
++/* {{{ proto resource sqlite_open(string filename [, int mode [, string &error_message]])
++   Opens a SQLite database. Will create the database if it does not exist. */
++PHP_FUNCTION(sqlite_open)
++{
++      long mode = 0666;
++      char *filename, *fullpath = NULL;
++      int filename_len;
++      zval *errmsg = NULL;
++      zval *object = getThis();
++      zend_error_handling error_handling;
++
++      zend_replace_error_handling(object ? EH_THROW : EH_NORMAL, sqlite_ce_exception, &error_handling TSRMLS_CC);
++      if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lz/",
++                              &filename, &filename_len, &mode, &errmsg)) {
++              zend_restore_error_handling(&error_handling TSRMLS_CC);
++              return;
++      }
++      if (errmsg) {
++              zval_dtor(errmsg);
++              ZVAL_NULL(errmsg);
++      }
++
++      if (strlen(filename) != filename_len) {
++              zend_restore_error_handling(&error_handling TSRMLS_CC);
++              RETURN_FALSE;
++      }
++
++      if (strncmp(filename, ":memory:", sizeof(":memory:") - 1)) {
++              /* resolve the fully-qualified path name to use as the hash key */
++              if (!(fullpath = expand_filepath(filename, NULL TSRMLS_CC))) {
++                      zend_restore_error_handling(&error_handling TSRMLS_CC);
++                      if (object) {
++                              RETURN_NULL();
++                      } else {
++                              RETURN_FALSE;
++                      }
++              }
++
++              if ((PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) ||
++                              php_check_open_basedir(fullpath TSRMLS_CC)) {
++                      efree(fullpath);
++                      zend_restore_error_handling(&error_handling TSRMLS_CC);
++                      if (object) {
++                              RETURN_NULL();
++                      } else {
++                              RETURN_FALSE;
++                      }
++              }
++      }
++
++      php_sqlite_open(fullpath ? fullpath : filename, (int)mode, NULL, return_value, errmsg, object TSRMLS_CC);
++
++      if (fullpath) {
++              efree(fullpath);
++      }
++      zend_restore_error_handling(&error_handling TSRMLS_CC);
++}
++/* }}} */
++
++/* {{{ proto object sqlite_factory(string filename [, int mode [, string &error_message]])
++   Opens a SQLite database and creates an object for it. Will create the database if it does not exist. */
++PHP_FUNCTION(sqlite_factory)
++{
++      long mode = 0666;
++      char *filename, *fullpath = NULL;
++      int filename_len;
++      zval *errmsg = NULL;
++      zend_error_handling error_handling;
++
++      zend_replace_error_handling(EH_THROW, sqlite_ce_exception, &error_handling TSRMLS_CC);
++      if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lz/",
++                              &filename, &filename_len, &mode, &errmsg)) {
++              zend_restore_error_handling(&error_handling TSRMLS_CC);
++              RETURN_NULL();
++      }
++      if (errmsg) {
++              zval_dtor(errmsg);
++              ZVAL_NULL(errmsg);
++      }
++
++      if (strlen(filename) != filename_len) {
++              zend_restore_error_handling(&error_handling TSRMLS_CC);
++              RETURN_FALSE;
++      }
++
++      if (strncmp(filename, ":memory:", sizeof(":memory:") - 1)) {
++              /* resolve the fully-qualified path name to use as the hash key */
++              if (!(fullpath = expand_filepath(filename, NULL TSRMLS_CC))) {
++                      zend_restore_error_handling(&error_handling TSRMLS_CC);
++                      RETURN_NULL();
++              }
++
++              if ((PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) ||
++                              php_check_open_basedir(fullpath TSRMLS_CC)) {
++                      efree(fullpath);
++                      zend_restore_error_handling(&error_handling TSRMLS_CC);
++                      RETURN_NULL();
++              }
++      }
++
++      php_sqlite_open(fullpath ? fullpath : filename, (int)mode, NULL, return_value, errmsg, return_value TSRMLS_CC);
++      if (fullpath) {
++              efree(fullpath);
++      }
++      zend_restore_error_handling(&error_handling TSRMLS_CC);
++}
++/* }}} */
++
++/* {{{ proto void sqlite_busy_timeout(resource db, int ms)
++   Set busy timeout duration. If ms <= 0, all busy handlers are disabled. */
++PHP_FUNCTION(sqlite_busy_timeout)
++{
++      zval *zdb;
++      struct php_sqlite_db *db;
++      long ms;
++      zval *object = getThis();
++
++      if (object) {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &ms)) {
++                      return;
++              }
++              DB_FROM_OBJECT(db, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zdb, &ms)) {
++                      return;
++              }
++              DB_FROM_ZVAL(db, &zdb);
++      }
++
++      sqlite_busy_timeout(db->db, ms);
++}
++/* }}} */
++
++/* {{{ proto void sqlite_close(resource db)
++   Closes an open sqlite database. */
++PHP_FUNCTION(sqlite_close)
++{
++      zval *zdb;
++      struct php_sqlite_db *db;
++      zval *object = getThis();
++
++      if (object) {
++              php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Ignored, you must destruct the object instead");
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zdb)) {
++                      return;
++              }
++              DB_FROM_ZVAL(db, &zdb);
++      }
++
++      zend_hash_apply_with_argument(&EG(regular_list),
++              (apply_func_arg_t) _clean_unfinished_results,
++              db TSRMLS_CC);
++
++      zend_list_delete(Z_RESVAL_P(zdb));
++}
++/* }}} */
++
++/* {{{ php_sqlite_fetch */
++static int php_sqlite_fetch(struct php_sqlite_result *rres TSRMLS_DC)
++{
++      const char **rowdata, **colnames;
++      int ret, i, base;
++      char *errtext = NULL;
++
++next_row:
++      ret = sqlite_step(rres->vm, &rres->ncolumns, &rowdata, &colnames);
++      if (!rres->nrows) {
++              /* first row - lets copy the column names */
++              rres->col_names = safe_emalloc(rres->ncolumns, sizeof(char *), 0);
++              for (i = 0; i < rres->ncolumns; i++) {
++                      rres->col_names[i] = estrdup((char*)colnames[i]);
++
++                      if (SQLITE_G(assoc_case) == 1) {
++                              php_sqlite_strtoupper(rres->col_names[i]);
++                      } else if (SQLITE_G(assoc_case) == 2) {
++                              php_sqlite_strtolower(rres->col_names[i]);
++                      }
++              }
++              if (!rres->buffered) {
++                      /* non buffered mode - also fetch memory for on single row */
++                      rres->table = safe_emalloc(rres->ncolumns, sizeof(char *), 0);
++              }
++      }
++
++      switch (ret) {
++              case SQLITE_ROW:
++                      if (rres->buffered) {
++                              /* add the row to our collection */
++                              if (rres->nrows + 1 >= rres->alloc_rows) {
++                                      rres->alloc_rows = rres->alloc_rows ? rres->alloc_rows * 2 : 16;
++                                      rres->table = safe_erealloc(rres->table, rres->alloc_rows, rres->ncolumns*sizeof(char *), 0);
++                              }
++                              base = rres->nrows * rres->ncolumns;
++                              for (i = 0; i < rres->ncolumns; i++) {
++                                      if (rowdata[i]) {
++                                              rres->table[base + i] = estrdup(rowdata[i]);
++                                      } else {
++                                              rres->table[base + i] = NULL;
++                                      }
++                              }
++                              rres->nrows++;
++                              goto next_row;
++                      } else {
++                              /* non buffered: only fetch one row but first free data if not first row */
++                              if (rres->nrows++) {
++                                      for (i = 0; i < rres->ncolumns; i++) {
++                                              if (rres->table[i]) {
++                                                      efree(rres->table[i]);
++                                              }
++                                      }
++                              }
++                              for (i = 0; i < rres->ncolumns; i++) {
++                                      if (rowdata[i]) {
++                                              rres->table[i] = estrdup(rowdata[i]);
++                                      } else {
++                                              rres->table[i] = NULL;
++                                      }
++                              }
++                      }
++                      ret = SQLITE_OK;
++                      break;
++
++              case SQLITE_BUSY:
++              case SQLITE_ERROR:
++              case SQLITE_MISUSE:
++              case SQLITE_DONE:
++              default:
++                      if (rres->vm) {
++                              ret = sqlite_finalize(rres->vm, &errtext);
++                      }
++                      rres->vm = NULL;
++                      if (ret != SQLITE_OK) {
++                              php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errtext);
++                              sqlite_freemem(errtext);
++                      }
++                      break;
++      }
++      rres->db->last_err_code = ret;
++
++      return ret;
++}
++/* }}} */
++
++/* {{{ sqlite_query */
++void sqlite_query(zval *object, struct php_sqlite_db *db, char *sql, long sql_len, int mode, int buffered, zval *return_value, struct php_sqlite_result **prres, zval *errmsg TSRMLS_DC)
++{
++      struct php_sqlite_result res, *rres;
++      int ret;
++      char *errtext = NULL;
++      const char *tail;
++
++      memset(&res, 0, sizeof(res));
++      res.buffered = buffered;
++      res.mode = mode;
++
++      ret = sqlite_compile(db->db, sql, &tail, &res.vm, &errtext);
++      db->last_err_code = ret;
++
++      if (ret != SQLITE_OK) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errtext);
++              if (errmsg) {
++                      ZVAL_STRING(errmsg, errtext, 1);
++              }
++              sqlite_freemem(errtext);
++              goto terminate;
++      } else if (!res.vm) { /* empty query */
++terminate:
++              if (return_value) {
++                      RETURN_FALSE;
++              } else {
++                      return;
++              }
++      }
++
++      if (!prres) {
++              rres = NULL;
++              prres = &rres;
++      }
++      if (!*prres) {
++              *prres = (struct php_sqlite_result*)emalloc(sizeof(**prres));
++      }
++      memcpy(*prres, &res, sizeof(**prres));
++      (*prres)->db = db;
++      zend_list_addref(db->rsrc_id);
++
++
++      /* now the result set is ready for stepping: get first row */
++      if (php_sqlite_fetch((*prres) TSRMLS_CC) != SQLITE_OK) {
++              real_result_dtor((*prres) TSRMLS_CC);
++              *prres = NULL;
++              if (return_value) {
++                      RETURN_FALSE;
++              } else {
++                      return;
++              }
++      }
++
++      (*prres)->curr_row = 0;
++
++      if (object) {
++              sqlite_object *obj;
++              if (buffered) {
++                      sqlite_instanciate(sqlite_ce_query, return_value TSRMLS_CC);
++              } else {
++                      sqlite_instanciate(sqlite_ce_ub_query, return_value TSRMLS_CC);
++              }
++              obj = (sqlite_object *) zend_object_store_get_object(return_value TSRMLS_CC);
++              obj->type = is_result;
++              obj->u.res = (*prres);
++      } else if (return_value) {
++              ZEND_REGISTER_RESOURCE(object ? NULL : return_value, (*prres), le_sqlite_result);
++      }
++}
++/* }}} */
++
++/* {{{ proto resource sqlite_unbuffered_query(string query, resource db [ , int result_type [, string &error_message]])
++   Executes a query that does not prefetch and buffer all data. */
++PHP_FUNCTION(sqlite_unbuffered_query)
++{
++      zval *zdb;
++      struct php_sqlite_db *db;
++      char *sql;
++      int sql_len;
++      long mode = PHPSQLITE_BOTH;
++      char *errtext = NULL;
++      zval *errmsg = NULL;
++      zval *object = getThis();
++
++      if (object) {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lz/", &sql, &sql_len, &mode, &errmsg)) {
++                      return;
++              }
++              DB_FROM_OBJECT(db, object);
++      } else {
++              if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
++                              ZEND_NUM_ARGS() TSRMLS_CC, "sr|lz/", &sql, &sql_len, &zdb, &mode, &errmsg) &&
++                      FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|lz/", &zdb, &sql, &sql_len, &mode, &errmsg)) {
++                      return;
++              }
++              DB_FROM_ZVAL(db, &zdb);
++      }
++
++      if (errmsg) {
++              zval_dtor(errmsg);
++              ZVAL_NULL(errmsg);
++      }
++
++      PHP_SQLITE_EMPTY_QUERY;
++
++      /* avoid doing work if we can */
++      if (!return_value_used) {
++              db->last_err_code = sqlite_exec(db->db, sql, NULL, NULL, &errtext);
++
++              if (db->last_err_code != SQLITE_OK) {
++                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errtext);
++                      if (errmsg) {
++                              ZVAL_STRING(errmsg, errtext, 1);
++                      }
++                      sqlite_freemem(errtext);
++              }
++              return;
++      }
++
++      sqlite_query(object, db, sql, sql_len, (int)mode, 0, return_value, NULL, errmsg TSRMLS_CC);
++}
++/* }}} */
++
++/* {{{ proto resource sqlite_fetch_column_types(string table_name, resource db [, int result_type])
++   Return an array of column types from a particular table. */
++PHP_FUNCTION(sqlite_fetch_column_types)
++{
++      zval *zdb;
++      struct php_sqlite_db *db;
++      char *tbl, *sql;
++      int tbl_len;
++      char *errtext = NULL;
++      zval *object = getThis();
++      struct php_sqlite_result res;
++      const char **rowdata, **colnames, *tail;
++      int i, ncols;
++      long result_type = PHPSQLITE_ASSOC;
++
++      if (object) {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &tbl, &tbl_len, &result_type)) {
++                      return;
++              }
++              DB_FROM_OBJECT(db, object);
++      } else {
++              if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
++                              ZEND_NUM_ARGS() TSRMLS_CC, "sr|l", &tbl, &tbl_len, &zdb, &result_type) &&
++                      FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &zdb, &tbl, &tbl_len, &result_type)) {
++                      return;
++              }
++              DB_FROM_ZVAL(db, &zdb);
++      }
++
++      if (!(sql = sqlite_mprintf("SELECT * FROM '%q' LIMIT 1", tbl))) {
++              RETURN_FALSE;
++      }
++
++      sqlite_exec(db->db, "PRAGMA show_datatypes = ON", NULL, NULL, NULL);
++
++      db->last_err_code = sqlite_compile(db->db, sql, &tail, &res.vm, &errtext);
++
++      sqlite_freemem(sql);
++
++      if (db->last_err_code != SQLITE_OK) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errtext);
++              sqlite_freemem(errtext);
++              RETVAL_FALSE;
++              goto done;
++      }
++
++      sqlite_step(res.vm, &ncols, &rowdata, &colnames);
++
++      array_init(return_value);
++
++      for (i = 0; i < ncols; i++) {
++              if (result_type == PHPSQLITE_ASSOC) {
++                      char *colname = estrdup((char *)colnames[i]);
++
++                      if (SQLITE_G(assoc_case) == 1) {
++                              php_sqlite_strtoupper(colname);
++                      } else if (SQLITE_G(assoc_case) == 2) {
++                              php_sqlite_strtolower(colname);
++                      }
++
++                      add_assoc_string(return_value, colname, colnames[ncols + i] ? (char *)colnames[ncols + i] : "", 1);
++                      efree(colname);
++              }
++              if (result_type == PHPSQLITE_NUM) {
++                      add_index_string(return_value, i, colnames[ncols + i] ? (char *)colnames[ncols + i] : "", 1);
++              }
++      }
++      if (res.vm) {
++              sqlite_finalize(res.vm, NULL);
++      }
++done:
++      sqlite_exec(db->db, "PRAGMA show_datatypes = OFF", NULL, NULL, NULL);
++}
++/* }}} */
++
++/* {{{ proto resource sqlite_query(string query, resource db [, int result_type [, string &error_message]])
++   Executes a query against a given database and returns a result handle. */
++PHP_FUNCTION(sqlite_query)
++{
++      zval *zdb;
++      struct php_sqlite_db *db;
++      char *sql;
++      int sql_len;
++      long mode = PHPSQLITE_BOTH;
++      char *errtext = NULL;
++      zval *errmsg = NULL;
++      zval *object = getThis();
++
++      if (object) {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lz/", &sql, &sql_len, &mode, &errmsg)) {
++                      return;
++              }
++              DB_FROM_OBJECT(db, object);
++      } else {
++              if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
++                              ZEND_NUM_ARGS() TSRMLS_CC, "sr|lz/", &sql, &sql_len, &zdb, &mode, &errmsg) &&
++                      FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|lz/", &zdb, &sql, &sql_len, &mode, &errmsg)) {
++                      return;
++              }
++              DB_FROM_ZVAL(db, &zdb);
++      }
++
++      if (errmsg) {
++              zval_dtor(errmsg);
++              ZVAL_NULL(errmsg);
++      }
++
++      PHP_SQLITE_EMPTY_QUERY;
++
++      /* avoid doing work if we can */
++      if (!return_value_used) {
++              db->last_err_code = sqlite_exec(db->db, sql, NULL, NULL, &errtext);
++
++              if (db->last_err_code != SQLITE_OK) {
++                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errtext);
++                      if (errmsg) {
++                              ZVAL_STRING(errmsg, errtext, 1);
++                      }
++                      sqlite_freemem(errtext);
++              }
++              return;
++      }
++
++      sqlite_query(object, db, sql, sql_len, (int)mode, 1, return_value, NULL, errmsg TSRMLS_CC);
++}
++/* }}} */
++
++/* {{{ proto boolean sqlite_exec(string query, resource db[, string &error_message])
++   Executes a result-less query against a given database */
++PHP_FUNCTION(sqlite_exec)
++{
++      zval *zdb;
++      struct php_sqlite_db *db;
++      char *sql;
++      int sql_len;
++      char *errtext = NULL;
++      zval *errmsg = NULL;
++      zval *object = getThis();
++
++      if (object) {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z/", &sql, &sql_len, &errmsg)) {
++                      return;
++              }
++              DB_FROM_OBJECT(db, object);
++      } else {
++              if(FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
++                      ZEND_NUM_ARGS() TSRMLS_CC, "sr", &sql, &sql_len, &zdb) &&
++                 FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|z/", &zdb, &sql, &sql_len, &errmsg)) {
++                      return;
++              }
++              DB_FROM_ZVAL(db, &zdb);
++      }
++
++      if (errmsg) {
++              zval_dtor(errmsg);
++              ZVAL_NULL(errmsg);
++      }
++
++      PHP_SQLITE_EMPTY_QUERY;
++
++      db->last_err_code = sqlite_exec(db->db, sql, NULL, NULL, &errtext);
++
++      if (db->last_err_code != SQLITE_OK) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errtext);
++              if (errmsg) {
++                      ZVAL_STRING(errmsg, errtext, 1);
++              }
++              sqlite_freemem(errtext);
++              RETURN_FALSE;
++      }
++
++      RETURN_TRUE;
++}
++/* }}} */
++
++/* {{{ php_sqlite_fetch_array */
++static void php_sqlite_fetch_array(struct php_sqlite_result *res, int mode, zend_bool decode_binary, int move_next, zval *return_value TSRMLS_DC)
++{
++      int j, n = res->ncolumns, buffered = res->buffered;
++      const char **rowdata, **colnames;
++
++      /* check range of the row */
++      if (res->curr_row >= res->nrows) {
++              /* no more */
++              RETURN_FALSE;
++      }
++      colnames = (const char**)res->col_names;
++      if (res->buffered) {
++              rowdata = (const char**)&res->table[res->curr_row * res->ncolumns];
++      } else {
++              rowdata = (const char**)res->table;
++      }
++
++      /* now populate the result */
++      array_init(return_value);
++
++      for (j = 0; j < n; j++) {
++              zval *decoded;
++              MAKE_STD_ZVAL(decoded);
++
++              if (rowdata[j] == NULL) {
++                      ZVAL_NULL(decoded);
++              } else if (decode_binary && rowdata[j][0] == '\x01') {
++                      Z_STRVAL_P(decoded) = emalloc(strlen(rowdata[j]));
++                      Z_STRLEN_P(decoded) = php_sqlite_decode_binary(rowdata[j]+1, Z_STRVAL_P(decoded));
++                      Z_STRVAL_P(decoded)[Z_STRLEN_P(decoded)] = '\0';
++                      Z_TYPE_P(decoded) = IS_STRING;
++                      if (!buffered) {
++                              efree((char*)rowdata[j]);
++                              rowdata[j] = NULL;
++                      }
++              } else {
++                      ZVAL_STRING(decoded, (char*)rowdata[j], buffered);
++                      if (!buffered) {
++                              rowdata[j] = NULL;
++                      }
++              }
++
++              if (mode & PHPSQLITE_NUM) {
++                      if (mode & PHPSQLITE_ASSOC) {
++                              add_index_zval(return_value, j, decoded);
++                              Z_ADDREF_P(decoded);
++                              add_assoc_zval(return_value, (char*)colnames[j], decoded);
++                      } else {
++                              add_next_index_zval(return_value, decoded);
++                      }
++              } else {
++                      add_assoc_zval(return_value, (char*)colnames[j], decoded);
++              }
++      }
++
++      if (move_next) {
++              if (!res->buffered) {
++                      /* non buffered: fetch next row */
++                      php_sqlite_fetch(res TSRMLS_CC);
++              }
++              /* advance the row pointer */
++              res->curr_row++;
++      }
++}
++/* }}} */
++
++/* {{{ php_sqlite_fetch_column */
++static void php_sqlite_fetch_column(struct php_sqlite_result *res, zval *which, zend_bool decode_binary, zval *return_value TSRMLS_DC)
++{
++      int j;
++      const char **rowdata, **colnames;
++
++      /* check range of the row */
++      if (res->curr_row >= res->nrows) {
++              /* no more */
++              RETURN_FALSE;
++      }
++      colnames = (const char**)res->col_names;
++
++      if (Z_TYPE_P(which) == IS_LONG) {
++              j = Z_LVAL_P(which);
++      } else {
++              convert_to_string_ex(&which);
++              for (j = 0; j < res->ncolumns; j++) {
++                      if (!strcasecmp((char*)colnames[j], Z_STRVAL_P(which))) {
++                              break;
++                      }
++              }
++      }
++      if (j < 0 || j >= res->ncolumns) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such column %d", j);
++              RETURN_FALSE;
++      }
++
++      if (res->buffered) {
++              rowdata = (const char**)&res->table[res->curr_row * res->ncolumns];
++      } else {
++              rowdata = (const char**)res->table;
++      }
++
++      if (rowdata[j] == NULL) {
++              RETURN_NULL();
++      } else if (decode_binary && rowdata[j] != NULL && rowdata[j][0] == '\x01') {
++              int l = strlen(rowdata[j]);
++              char *decoded = emalloc(l);
++              l = php_sqlite_decode_binary(rowdata[j]+1, decoded);
++              decoded[l] = '\0';
++              RETVAL_STRINGL(decoded, l, 0);
++              if (!res->buffered) {
++                      efree((char*)rowdata[j]);
++                      rowdata[j] = NULL;
++              }
++      } else {
++              RETVAL_STRING((char*)rowdata[j], res->buffered);
++              if (!res->buffered) {
++                      rowdata[j] = NULL;
++              }
++      }
++}
++/* }}} */
++
++/* {{{ proto array sqlite_fetch_all(resource result [, int result_type [, bool decode_binary]])
++   Fetches all rows from a result set as an array of arrays. */
++PHP_FUNCTION(sqlite_fetch_all)
++{
++      zval *zres, *ent;
++      long mode = PHPSQLITE_BOTH;
++      zend_bool decode_binary = 1;
++      struct php_sqlite_result *res;
++      zval *object = getThis();
++
++      if (object) {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lb", &mode, &decode_binary)) {
++                      return;
++              }
++              RES_FROM_OBJECT(res, object);
++              if (!ZEND_NUM_ARGS()) {
++                      mode = res->mode;
++              }
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|lb", &zres, &mode, &decode_binary)) {
++                      return;
++              }
++              ZEND_FETCH_RESOURCE(res, struct php_sqlite_result *, &zres, -1, "sqlite result", le_sqlite_result);
++              if (ZEND_NUM_ARGS() < 2) {
++                      mode = res->mode;
++              }
++      }
++
++      if (res->curr_row >= res->nrows && res->nrows) {
++              if (!res->buffered) {
++                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "One or more rowsets were already returned; returning NULL this time");
++              } else {
++                      res->curr_row = 0;
++              }
++      }
++
++      array_init(return_value);
++
++      while (res->curr_row < res->nrows) {
++              MAKE_STD_ZVAL(ent);
++              php_sqlite_fetch_array(res, mode, decode_binary, 1, ent TSRMLS_CC);
++              add_next_index_zval(return_value, ent);
++      }
++}
++/* }}} */
++
++/* {{{ proto array sqlite_fetch_array(resource result [, int result_type [, bool decode_binary]])
++   Fetches the next row from a result set as an array. */
++PHP_FUNCTION(sqlite_fetch_array)
++{
++      zval *zres;
++      long mode = PHPSQLITE_BOTH;
++      zend_bool decode_binary = 1;
++      struct php_sqlite_result *res;
++      zval *object = getThis();
++
++      if (object) {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lb", &mode, &decode_binary)) {
++                      return;
++              }
++              RES_FROM_OBJECT(res, object);
++              if (!ZEND_NUM_ARGS()) {
++                      mode = res->mode;
++              }
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|lb", &zres, &mode, &decode_binary)) {
++                      return;
++              }
++              ZEND_FETCH_RESOURCE(res, struct php_sqlite_result *, &zres, -1, "sqlite result", le_sqlite_result);
++              if (ZEND_NUM_ARGS() < 2) {
++                      mode = res->mode;
++              }
++      }
++
++      php_sqlite_fetch_array(res, mode, decode_binary, 1, return_value TSRMLS_CC);
++}
++/* }}} */
++
++/* {{{ proto object sqlite_fetch_object(resource result [, string class_name [, NULL|array ctor_params [, bool decode_binary]]])
++   Fetches the next row from a result set as an object. */
++   /* note that you can do array(&$val) for param ctor_params */
++PHP_FUNCTION(sqlite_fetch_object)
++{
++      zval *zres;
++      zend_bool decode_binary = 1;
++      struct php_sqlite_result *res;
++      zval *object = getThis();
++      char *class_name = NULL;
++      int class_name_len;
++      zend_class_entry *ce;
++      zval dataset;
++      zend_fcall_info fci;
++      zend_fcall_info_cache fcc;
++      zval *retval_ptr;
++      zval *ctor_params = NULL;
++      zend_error_handling error_handling;
++
++      zend_replace_error_handling(object ? EH_THROW : EH_NORMAL, sqlite_ce_exception, &error_handling TSRMLS_CC);
++      if (object) {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|szb", &class_name, &class_name_len, &ctor_params, &decode_binary)) {
++                      zend_restore_error_handling(&error_handling TSRMLS_CC);
++                      return;
++              }
++              RES_FROM_OBJECT_RESTORE_ERH(res, object, &error_handling);
++              if (!class_name) {
++                      ce = zend_standard_class_def;
++              } else {
++                      ce = zend_fetch_class(class_name, class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
++              }
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|szb", &zres, &class_name, &class_name_len, &ctor_params, &decode_binary)) {
++                      zend_restore_error_handling(&error_handling TSRMLS_CC);
++                      return;
++              }
++              ZEND_FETCH_RESOURCE(res, struct php_sqlite_result *, &zres, -1, "sqlite result", le_sqlite_result);
++              if (!class_name) {
++                      ce = zend_standard_class_def;
++              } else {
++                      ce = zend_fetch_class(class_name, class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
++              }
++      }
++
++      if (!ce) {
++              zend_throw_exception_ex(sqlite_ce_exception, 0 TSRMLS_CC, "Could not find class '%s'", class_name);
++              zend_restore_error_handling(&error_handling TSRMLS_CC);
++              return;
++      }
++
++      if (res->curr_row < res->nrows) {
++              php_sqlite_fetch_array(res, PHPSQLITE_ASSOC, decode_binary, 1, &dataset TSRMLS_CC);
++      } else {
++              zend_restore_error_handling(&error_handling TSRMLS_CC);
++              RETURN_FALSE;
++      }
++
++      object_and_properties_init(return_value, ce, NULL);
++      zend_merge_properties(return_value, Z_ARRVAL(dataset), 1 TSRMLS_CC);
++
++      zend_restore_error_handling(&error_handling TSRMLS_CC);
++
++      if (ce->constructor) {
++              fci.size = sizeof(fci);
++              fci.function_table = &ce->function_table;
++              fci.function_name = NULL;
++              fci.symbol_table = NULL;
++              fci.object_ptr = return_value;
++              fci.retval_ptr_ptr = &retval_ptr;
++              if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) {
++                      if (Z_TYPE_P(ctor_params) == IS_ARRAY) {
++                              HashTable *ht = Z_ARRVAL_P(ctor_params);
++                              Bucket *p;
++
++                              fci.param_count = 0;
++                              fci.params = safe_emalloc(sizeof(zval*), ht->nNumOfElements, 0);
++                              p = ht->pListHead;
++                              while (p != NULL) {
++                                      fci.params[fci.param_count++] = (zval**)p->pData;
++                                      p = p->pListNext;
++                              }
++                      } else {
++                              /* Two problems why we throw exceptions here: PHP is typeless
++                               * and hence passing one argument that's not an array could be
++                               * by mistake and the other way round is possible, too. The
++                               * single value is an array. Also we'd have to make that one
++                               * argument passed by reference.
++                               */
++                              zend_throw_exception(sqlite_ce_exception, "Parameter ctor_params must be an array", 0 TSRMLS_CC);
++                              return;
++                      }
++              } else {
++                      fci.param_count = 0;
++                      fci.params = NULL;
++              }
++              fci.no_separation = 1;
++
++              fcc.initialized = 1;
++              fcc.function_handler = ce->constructor;
++              fcc.calling_scope = EG(scope);
++              fcc.called_scope = Z_OBJCE_P(return_value);
++              fcc.object_ptr = return_value;
++
++              if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
++                      zend_throw_exception_ex(sqlite_ce_exception, 0 TSRMLS_CC, "Could not execute %s::%s()", class_name, ce->constructor->common.function_name);
++              } else {
++                      if (retval_ptr) {
++                              zval_ptr_dtor(&retval_ptr);
++                      }
++              }
++              if (fci.params) {
++                      efree(fci.params);
++              }
++      } else if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) {
++              zend_throw_exception_ex(sqlite_ce_exception, 0 TSRMLS_CC, "Class %s does not have a constructor, use NULL for parameter ctor_params or omit it", class_name);
++      }
++}
++/* }}} */
++
++/* {{{ proto array sqlite_array_query(resource db, string query [ , int result_type [, bool decode_binary]])
++   Executes a query against a given database and returns an array of arrays. */
++PHP_FUNCTION(sqlite_array_query)
++{
++      zval *zdb, *ent;
++      struct php_sqlite_db *db;
++      struct php_sqlite_result *rres;
++      char *sql;
++      int sql_len;
++      long mode = PHPSQLITE_BOTH;
++      char *errtext = NULL;
++      zend_bool decode_binary = 1;
++      zval *object = getThis();
++
++      if (object) {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lb", &sql, &sql_len, &mode, &decode_binary)) {
++                      return;
++              }
++              DB_FROM_OBJECT(db, object);
++      } else {
++              if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
++                              ZEND_NUM_ARGS() TSRMLS_CC, "sr|lb", &sql, &sql_len, &zdb, &mode, &decode_binary) &&
++                      FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|lb", &zdb, &sql, &sql_len, &mode, &decode_binary)) {
++                      return;
++              }
++              DB_FROM_ZVAL(db, &zdb);
++      }
++
++      PHP_SQLITE_EMPTY_QUERY;
++
++      /* avoid doing work if we can */
++      if (!return_value_used) {
++              db->last_err_code = sqlite_exec(db->db, sql, NULL, NULL, &errtext);
++
++              if (db->last_err_code != SQLITE_OK) {
++                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errtext);
++                      sqlite_freemem(errtext);
++              }
++              return;
++      }
++
++      rres = (struct php_sqlite_result *)ecalloc(1, sizeof(*rres));
++      sqlite_query(NULL, db, sql, sql_len, (int)mode, 0, NULL, &rres, NULL TSRMLS_CC);
++      if (db->last_err_code != SQLITE_OK) {
++              if (rres) {
++                      efree(rres);
++              }
++              RETURN_FALSE;
++      }
++
++      array_init(return_value);
++
++      while (rres->curr_row < rres->nrows) {
++              MAKE_STD_ZVAL(ent);
++              php_sqlite_fetch_array(rres, mode, decode_binary, 1, ent TSRMLS_CC);
++              add_next_index_zval(return_value, ent);
++      }
++      real_result_dtor(rres TSRMLS_CC);
++}
++/* }}} */
++
++/* {{{ php_sqlite_fetch_single */
++static void php_sqlite_fetch_single(struct php_sqlite_result *res, zend_bool decode_binary, zval *return_value TSRMLS_DC)
++{
++      const char **rowdata;
++      char *decoded;
++      int decoded_len;
++
++      /* check range of the row */
++      if (res->curr_row >= res->nrows) {
++              /* no more */
++              RETURN_FALSE;
++      }
++
++      if (res->buffered) {
++              rowdata = (const char**)&res->table[res->curr_row * res->ncolumns];
++      } else {
++              rowdata = (const char**)res->table;
++      }
++
++      if (decode_binary && rowdata[0] != NULL && rowdata[0][0] == '\x01') {
++              decoded = emalloc(strlen(rowdata[0]));
++              decoded_len = php_sqlite_decode_binary(rowdata[0]+1, decoded);
++              if (!res->buffered) {
++                      efree((char*)rowdata[0]);
++                      rowdata[0] = NULL;
++              }
++      } else if (rowdata[0]) {
++              decoded_len = strlen((char*)rowdata[0]);
++              if (res->buffered) {
++                      decoded = estrndup((char*)rowdata[0], decoded_len);
++              } else {
++                      decoded = (char*)rowdata[0];
++                      rowdata[0] = NULL;
++              }
++      } else {
++              decoded = NULL;
++              decoded_len = 0;
++      }
++
++      if (!res->buffered) {
++              /* non buffered: fetch next row */
++              php_sqlite_fetch(res TSRMLS_CC);
++      }
++      /* advance the row pointer */
++      res->curr_row++;
++
++      if (decoded == NULL) {
++              RETURN_NULL();
++      } else {
++              RETURN_STRINGL(decoded, decoded_len, 0);
++      }
++}
++/* }}} */
++
++
++/* {{{ proto array sqlite_single_query(resource db, string query [, bool first_row_only [, bool decode_binary]])
++   Executes a query and returns either an array for one single column or the value of the first row. */
++PHP_FUNCTION(sqlite_single_query)
++{
++      zval *zdb, *ent;
++      struct php_sqlite_db *db;
++      struct php_sqlite_result *rres;
++      char *sql;
++      int sql_len;
++      char *errtext = NULL;
++      zend_bool decode_binary = 1;
++      zend_bool srow = 1;
++      zval *object = getThis();
++
++      if (object) {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bb", &sql, &sql_len, &srow, &decode_binary)) {
++                      return;
++              }
++              RES_FROM_OBJECT(db, object);
++      } else {
++              if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
++                              ZEND_NUM_ARGS() TSRMLS_CC, "sr|bb", &sql, &sql_len, &zdb, &srow, &decode_binary) &&
++                      FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|bb", &zdb, &sql, &sql_len, &srow, &decode_binary)) {
++                      return;
++              }
++              DB_FROM_ZVAL(db, &zdb);
++      }
++
++      PHP_SQLITE_EMPTY_QUERY;
++
++      /* avoid doing work if we can */
++      if (!return_value_used) {
++              db->last_err_code = sqlite_exec(db->db, sql, NULL, NULL, &errtext);
++
++              if (db->last_err_code != SQLITE_OK) {
++                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errtext);
++                      sqlite_freemem(errtext);
++              }
++              return;
++      }
++
++      rres = (struct php_sqlite_result *)ecalloc(1, sizeof(*rres));
++      sqlite_query(NULL, db, sql, sql_len, PHPSQLITE_NUM, 0, NULL, &rres, NULL TSRMLS_CC);
++      if (db->last_err_code != SQLITE_OK) {
++              if (rres) {
++                      efree(rres);
++              }
++              RETURN_FALSE;
++      }
++
++      if (!srow) {
++              array_init(return_value);
++      }
++
++      while (rres->curr_row < rres->nrows) {
++              MAKE_STD_ZVAL(ent);
++              php_sqlite_fetch_single(rres, decode_binary, ent TSRMLS_CC);
++
++              /* if set and we only have 1 row in the result set, return the result as a string. */
++              if (srow) {
++                      if (rres->curr_row == 1 && rres->curr_row >= rres->nrows) {
++                              *return_value = *ent;
++                              zval_copy_ctor(return_value);
++                              zval_dtor(ent);
++                              FREE_ZVAL(ent);
++                              break;
++                      } else {
++                              srow = 0;
++                              array_init(return_value);
++                      }
++              }
++              add_next_index_zval(return_value, ent);
++      }
++
++      real_result_dtor(rres TSRMLS_CC);
++}
++/* }}} */
++
++
++/* {{{ proto string sqlite_fetch_single(resource result [, bool decode_binary])
++   Fetches the first column of a result set as a string. */
++PHP_FUNCTION(sqlite_fetch_single)
++{
++      zval *zres;
++      zend_bool decode_binary = 1;
++      struct php_sqlite_result *res;
++      zval *object = getThis();
++
++      if (object) {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &decode_binary)) {
++                      return;
++              }
++              RES_FROM_OBJECT(res, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|b", &zres, &decode_binary)) {
++                      return;
++              }
++              ZEND_FETCH_RESOURCE(res, struct php_sqlite_result *, &zres, -1, "sqlite result", le_sqlite_result);
++      }
++
++      php_sqlite_fetch_single(res, decode_binary, return_value TSRMLS_CC);
++}
++/* }}} */
++
++/* {{{ proto array sqlite_current(resource result [, int result_type [, bool decode_binary]])
++   Fetches the current row from a result set as an array. */
++PHP_FUNCTION(sqlite_current)
++{
++      zval *zres;
++      long mode = PHPSQLITE_BOTH;
++      zend_bool decode_binary = 1;
++      struct php_sqlite_result *res;
++      zval *object = getThis();
++
++      if (object) {
++              if (ZEND_NUM_ARGS() && FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lb", &mode, &decode_binary)) {
++                      return;
++              }
++              RES_FROM_OBJECT(res, object);
++              if (!ZEND_NUM_ARGS()) {
++                      mode = res->mode;
++              }
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|lb", &zres, &mode, &decode_binary)) {
++                      return;
++              }
++              ZEND_FETCH_RESOURCE(res, struct php_sqlite_result *, &zres, -1, "sqlite result", le_sqlite_result);
++              if (ZEND_NUM_ARGS() < 2) {
++                      mode = res->mode;
++              }
++      }
++
++      php_sqlite_fetch_array(res, mode, decode_binary, 0, return_value TSRMLS_CC);
++}
++/* }}} */
++
++/* {{{ proto mixed sqlite_column(resource result, mixed index_or_name [, bool decode_binary])
++   Fetches a column from the current row of a result set. */
++PHP_FUNCTION(sqlite_column)
++{
++      zval *zres;
++      zval *which;
++      zend_bool decode_binary = 1;
++      struct php_sqlite_result *res;
++      zval *object = getThis();
++
++      if (object) {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &which, &decode_binary)) {
++                      return;
++              }
++              RES_FROM_OBJECT(res, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|b", &zres, &which, &decode_binary)) {
++                      return;
++              }
++              ZEND_FETCH_RESOURCE(res, struct php_sqlite_result *, &zres, -1, "sqlite result", le_sqlite_result);
++      }
++
++      php_sqlite_fetch_column(res, which, decode_binary, return_value TSRMLS_CC);
++}
++/* }}} */
++
++/* {{{ proto string sqlite_libversion()
++   Returns the version of the linked SQLite library. */
++PHP_FUNCTION(sqlite_libversion)
++{
++      if (zend_parse_parameters_none() == FAILURE) {
++              return;
++      }
++      RETURN_STRING((char*)sqlite_libversion(), 1);
++}
++/* }}} */
++
++/* {{{ proto string sqlite_libencoding()
++   Returns the encoding (iso8859 or UTF-8) of the linked SQLite library. */
++PHP_FUNCTION(sqlite_libencoding)
++{
++      if (zend_parse_parameters_none() == FAILURE) {
++              return;
++      }
++      RETURN_STRING((char*)sqlite_libencoding(), 1);
++}
++/* }}} */
++
++/* {{{ proto int sqlite_changes(resource db)
++   Returns the number of rows that were changed by the most recent SQL statement. */
++PHP_FUNCTION(sqlite_changes)
++{
++      zval *zdb;
++      struct php_sqlite_db *db;
++      zval *object = getThis();
++
++      if (object) {
++              if (zend_parse_parameters_none() == FAILURE) {
++                      return;
++              }
++              DB_FROM_OBJECT(db, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zdb)) {
++                      return;
++              }
++              DB_FROM_ZVAL(db, &zdb);
++      }
++
++      RETURN_LONG(sqlite_changes(db->db));
++}
++/* }}} */
++
++/* {{{ proto int sqlite_last_insert_rowid(resource db)
++   Returns the rowid of the most recently inserted row. */
++PHP_FUNCTION(sqlite_last_insert_rowid)
++{
++      zval *zdb;
++      struct php_sqlite_db *db;
++      zval *object = getThis();
++
++      if (object) {
++              if (zend_parse_parameters_none() == FAILURE) {
++                      return;
++              }
++              DB_FROM_OBJECT(db, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zdb)) {
++                      return;
++              }
++              DB_FROM_ZVAL(db, &zdb);
++      }
++
++      RETURN_LONG(sqlite_last_insert_rowid(db->db));
++}
++/* }}} */
++
++static int sqlite_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
++{
++      sqlite_object *obj = (sqlite_object*) zend_object_store_get_object(object TSRMLS_CC);
++
++      if (obj->u.res == NULL) {
++              zend_throw_exception(sqlite_ce_exception, "Row count is not available for this query", 0 TSRMLS_CC);
++              return FAILURE;
++      }
++
++      if (obj->u.res->buffered) {
++              * count = obj->u.res->nrows;
++              return SUCCESS;
++      } else {
++              zend_throw_exception(sqlite_ce_exception, "Row count is not available for unbuffered queries", 0 TSRMLS_CC);
++              return FAILURE;
++      }
++} /* }}} */
++
++/* {{{ proto int sqlite_num_rows(resource result)
++   Returns the number of rows in a buffered result set. */
++PHP_FUNCTION(sqlite_num_rows)
++{
++      zval *zres;
++      struct php_sqlite_result *res;
++      zval *object = getThis();
++
++      if (object) {
++              if (zend_parse_parameters_none() == FAILURE) {
++                      return;
++              }
++              RES_FROM_OBJECT(res, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres)) {
++                      return;
++              }
++              ZEND_FETCH_RESOURCE(res, struct php_sqlite_result *, &zres, -1, "sqlite result", le_sqlite_result);
++      }
++
++      if (res->buffered) {
++              RETURN_LONG(res->nrows);
++      } else {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Row count is not available for unbuffered queries");
++              RETURN_FALSE;
++      }
++}
++/* }}} */
++
++/* {{{ proto bool sqlite_valid(resource result)
++   Returns whether more rows are available. */
++PHP_FUNCTION(sqlite_valid)
++{
++      zval *zres;
++      struct php_sqlite_result *res;
++      zval *object = getThis();
++
++      if (object) {
++              if (zend_parse_parameters_none() == FAILURE) {
++                      return;
++              }
++              RES_FROM_OBJECT(res, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres)) {
++                      return;
++              }
++              ZEND_FETCH_RESOURCE(res, struct php_sqlite_result *, &zres, -1, "sqlite result", le_sqlite_result);
++      }
++
++      RETURN_BOOL(res->curr_row < res->nrows && res->nrows); /* curr_row may be -1 */
++}
++/* }}} */
++
++/* {{{ proto bool sqlite_has_prev(resource result)
++ * Returns whether a previous row is available. */
++PHP_FUNCTION(sqlite_has_prev)
++{
++      zval *zres;
++      struct php_sqlite_result *res;
++      zval *object = getThis();
++
++      if (object) {
++              if (zend_parse_parameters_none() == FAILURE) {
++                      return;
++              }
++              RES_FROM_OBJECT(res, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres)) {
++                      return;
++              }
++              ZEND_FETCH_RESOURCE(res, struct php_sqlite_result *, &zres, -1, "sqlite result", le_sqlite_result);
++      }
++
++      if(!res->buffered) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "you cannot use sqlite_has_prev on unbuffered querys");
++              RETURN_FALSE;
++      }
++
++      RETURN_BOOL(res->curr_row);
++}
++/* }}} */
++
++/* {{{ proto int sqlite_num_fields(resource result)
++   Returns the number of fields in a result set. */
++PHP_FUNCTION(sqlite_num_fields)
++{
++      zval *zres;
++      struct php_sqlite_result *res;
++      zval *object = getThis();
++
++      if (object) {
++              if (zend_parse_parameters_none() == FAILURE) {
++                      return;
++              }
++              RES_FROM_OBJECT(res, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres)) {
++                      return;
++              }
++              ZEND_FETCH_RESOURCE(res, struct php_sqlite_result *, &zres, -1, "sqlite result", le_sqlite_result);
++      }
++
++      RETURN_LONG(res->ncolumns);
++}
++/* }}} */
++
++/* {{{ proto string sqlite_field_name(resource result, int field_index)
++   Returns the name of a particular field of a result set. */
++PHP_FUNCTION(sqlite_field_name)
++{
++      zval *zres;
++      struct php_sqlite_result *res;
++      long field;
++      zval *object = getThis();
++
++      if (object) {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &field)) {
++                      return;
++              }
++              RES_FROM_OBJECT(res, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zres, &field)) {
++                      return;
++              }
++              ZEND_FETCH_RESOURCE(res, struct php_sqlite_result *, &zres, -1, "sqlite result", le_sqlite_result);
++      }
++
++      if (field < 0 || field >= res->ncolumns) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "field %ld out of range", field);
++              RETURN_FALSE;
++      }
++
++      RETURN_STRING(res->col_names[field], 1);
++}
++/* }}} */
++
++/* {{{ proto bool sqlite_seek(resource result, int row)
++   Seek to a particular row number of a buffered result set. */
++PHP_FUNCTION(sqlite_seek)
++{
++      zval *zres;
++      struct php_sqlite_result *res;
++      long row;
++      zval *object = getThis();
++
++      if (object) {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &row)) {
++                      return;
++              }
++              RES_FROM_OBJECT(res, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zres, &row)) {
++                      return;
++              }
++              ZEND_FETCH_RESOURCE(res, struct php_sqlite_result *, &zres, -1, "sqlite result", le_sqlite_result);
++      }
++
++      if (!res->buffered) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot seek an unbuffered result set");
++              RETURN_FALSE;
++      }
++
++      if (row < 0 || row >= res->nrows) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "row %ld out of range", row);
++              RETURN_FALSE;
++      }
++
++      res->curr_row = row;
++      RETURN_TRUE;
++}
++/* }}} */
++
++/* {{{ proto bool sqlite_rewind(resource result)
++   Seek to the first row number of a buffered result set. */
++PHP_FUNCTION(sqlite_rewind)
++{
++      zval *zres;
++      struct php_sqlite_result *res;
++      zval *object = getThis();
++
++      if (object) {
++              if (zend_parse_parameters_none() == FAILURE) {
++                      return;
++              }
++              RES_FROM_OBJECT(res, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres)) {
++                      return;
++              }
++              ZEND_FETCH_RESOURCE(res, struct php_sqlite_result *, &zres, -1, "sqlite result", le_sqlite_result);
++      }
++
++      if (!res->buffered) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot rewind an unbuffered result set");
++              RETURN_FALSE;
++      }
++
++      if (!res->nrows) {
++              php_error_docref(NULL TSRMLS_CC, E_NOTICE, "no rows received");
++              RETURN_FALSE;
++      }
++
++      res->curr_row = 0;
++      RETURN_TRUE;
++}
++/* }}} */
++
++/* {{{ proto bool sqlite_next(resource result)
++   Seek to the next row number of a result set. */
++PHP_FUNCTION(sqlite_next)
++{
++      zval *zres;
++      struct php_sqlite_result *res;
++      zval *object = getThis();
++
++      if (object) {
++              if (zend_parse_parameters_none() == FAILURE) {
++                      return;
++              }
++              RES_FROM_OBJECT(res, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres)) {
++                      return;
++              }
++              ZEND_FETCH_RESOURCE(res, struct php_sqlite_result *, &zres, -1, "sqlite result", le_sqlite_result);
++      }
++
++      if (!res->buffered && res->vm) {
++              php_sqlite_fetch(res TSRMLS_CC);
++      }
++
++      if (res->curr_row >= res->nrows) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "no more rows available");
++              RETURN_FALSE;
++      }
++
++      res->curr_row++;
++
++      RETURN_TRUE;
++}
++/* }}} */
++
++/* {{{ proto int sqlite_key(resource result)
++   Return the current row index of a buffered result. */
++PHP_FUNCTION(sqlite_key)
++{
++      zval *zres;
++      struct php_sqlite_result *res;
++      zval *object = getThis();
++
++      if (object) {
++              if (zend_parse_parameters_none() == FAILURE) {
++                      return;
++              }
++              RES_FROM_OBJECT(res, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres)) {
++                      return;
++              }
++              ZEND_FETCH_RESOURCE(res, struct php_sqlite_result *, &zres, -1, "sqlite result", le_sqlite_result);
++      }
++
++      RETURN_LONG(res->curr_row);
++}
++/* }}} */
++
++/* {{{ proto bool sqlite_prev(resource result)
++ * Seek to the previous row number of a result set. */
++PHP_FUNCTION(sqlite_prev)
++{
++      zval *zres;
++      struct php_sqlite_result *res;
++      zval *object = getThis();
++
++      if (object) {
++              if (zend_parse_parameters_none() == FAILURE) {
++                      return;
++              }
++              RES_FROM_OBJECT(res, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres)) {
++                      return;
++              }
++              ZEND_FETCH_RESOURCE(res, struct php_sqlite_result *, &zres, -1, "sqlite result", le_sqlite_result);
++      }
++
++      if (!res->buffered) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "you cannot use sqlite_prev on unbuffered querys");
++              RETURN_FALSE;
++      }
++
++      if (res->curr_row <= 0) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "no previous row available");
++              RETURN_FALSE;
++      }
++
++      res->curr_row--;
++
++      RETURN_TRUE;
++}
++/* }}} */
++
++/* {{{ proto string sqlite_escape_string(string item)
++   Escapes a string for use as a query parameter. */
++PHP_FUNCTION(sqlite_escape_string)
++{
++      char *string = NULL;
++      int stringlen;
++      char *ret;
++
++      if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &string, &stringlen)) {
++              return;
++      }
++
++      if (stringlen && (string[0] == '\x01' || memchr(string, '\0', stringlen) != NULL)) {
++              /* binary string */
++              int enclen;
++
++              ret = safe_emalloc(1 + stringlen / 254, 257, 3);
++              ret[0] = '\x01';
++              enclen = php_sqlite_encode_binary(string, stringlen, ret+1);
++              RETVAL_STRINGL(ret, enclen+1, 0);
++
++      } else if (stringlen) {
++              ret = sqlite_mprintf("%q", string);
++              if (ret) {
++                      RETVAL_STRING(ret, 1);
++                      sqlite_freemem(ret);
++              }
++      } else {
++              RETURN_EMPTY_STRING();
++      }
++}
++/* }}} */
++
++/* {{{ proto int sqlite_last_error(resource db)
++   Returns the error code of the last error for a database. */
++PHP_FUNCTION(sqlite_last_error)
++{
++      zval *zdb;
++      struct php_sqlite_db *db;
++      zval *object = getThis();
++
++      if (object) {
++              if (zend_parse_parameters_none() == FAILURE) {
++                      return;
++              }
++              DB_FROM_OBJECT(db, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zdb)) {
++                      return;
++              }
++              DB_FROM_ZVAL(db, &zdb);
++      }
++
++      RETURN_LONG(db->last_err_code);
++}
++/* }}} */
++
++/* {{{ proto string sqlite_error_string(int error_code)
++   Returns the textual description of an error code. */
++PHP_FUNCTION(sqlite_error_string)
++{
++      long code;
++      const char *msg;
++
++      if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) {
++              return;
++      }
++
++      msg = sqlite_error_string(code);
++
++      if (msg) {
++              RETURN_STRING((char*)msg, 1);
++      } else {
++              RETURN_NULL();
++      }
++}
++/* }}} */
++
++/* manages duplicate registrations of a particular function, and
++ * also handles the case where the db is using a persistent connection */
++enum callback_prep_t { DO_REG, SKIP_REG, ERR };
++
++static enum callback_prep_t prep_callback_struct(struct php_sqlite_db *db, int is_agg,
++              char *funcname,
++              zval *step, zval *fini, struct php_sqlite_agg_functions **funcs)
++{
++      struct php_sqlite_agg_functions *alloc_funcs, func_tmp;
++      char *hashkey;
++      int hashkeylen;
++      enum callback_prep_t ret;
++
++      hashkeylen = spprintf(&hashkey, 0, "%s-%s", is_agg ? "agg" : "reg", funcname);
++
++      /* is it already registered ? */
++      if (SUCCESS == zend_hash_find(&db->callbacks, hashkey, hashkeylen+1, (void*)&alloc_funcs)) {
++              /* override the previous definition */
++
++              if (alloc_funcs->is_valid) {
++                      /* release these */
++
++                      if (alloc_funcs->step) {
++                              zval_ptr_dtor(&alloc_funcs->step);
++                              alloc_funcs->step = NULL;
++                      }
++
++                      if (alloc_funcs->fini) {
++                              zval_ptr_dtor(&alloc_funcs->fini);
++                              alloc_funcs->fini = NULL;
++                      }
++              }
++
++              ret = SKIP_REG;
++      } else {
++              /* add a new one */
++              func_tmp.db = db;
++
++              ret = SUCCESS == zend_hash_update(&db->callbacks, hashkey, hashkeylen+1,
++                              (void*)&func_tmp, sizeof(func_tmp), (void**)&alloc_funcs) ? DO_REG : ERR;
++      }
++
++      efree(hashkey);
++
++      MAKE_STD_ZVAL(alloc_funcs->step);
++      *(alloc_funcs->step)  = *step;
++      zval_copy_ctor(alloc_funcs->step);
++      INIT_PZVAL(alloc_funcs->step);
++
++      if (is_agg) {
++              MAKE_STD_ZVAL(alloc_funcs->fini);
++              *(alloc_funcs->fini) = *fini;
++              zval_copy_ctor(alloc_funcs->fini);
++              INIT_PZVAL(alloc_funcs->fini);
++      } else {
++              alloc_funcs->fini = NULL;
++      }
++      alloc_funcs->is_valid = 1;
++      *funcs = alloc_funcs;
++
++      return ret;
++}
++
++
++/* {{{ proto bool sqlite_create_aggregate(resource db, string funcname, mixed step_func, mixed finalize_func[, long num_args])
++    Registers an aggregate function for queries. */
++PHP_FUNCTION(sqlite_create_aggregate)
++{
++      char *funcname = NULL;
++      int funcname_len;
++      zval *zstep, *zfinal, *zdb;
++      struct php_sqlite_db *db;
++      struct php_sqlite_agg_functions *funcs;
++      char *callable = NULL;
++      long num_args = -1;
++      zval *object = getThis();
++
++      if (object) {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szz|l", &funcname, &funcname_len, &zstep, &zfinal, &num_args)) {
++                      return;
++              }
++              DB_FROM_OBJECT(db, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rszz|l", &zdb, &funcname, &funcname_len, &zstep, &zfinal, &num_args)) {
++                      return;
++              }
++              DB_FROM_ZVAL(db, &zdb);
++      }
++
++      if (!zend_is_callable(zstep, 0, &callable TSRMLS_CC)) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "step function `%s' is not callable", callable);
++              efree(callable);
++              return;
++      }
++      efree(callable);
++
++      if (!zend_is_callable(zfinal, 0, &callable TSRMLS_CC)) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "finalize function `%s' is not callable", callable);
++              efree(callable);
++              return;
++      }
++      efree(callable);
++
++
++      if (prep_callback_struct(db, 1, funcname, zstep, zfinal, &funcs) == DO_REG) {
++              sqlite_create_aggregate(db->db, funcname, num_args,
++                              php_sqlite_agg_step_function_callback,
++                              php_sqlite_agg_fini_function_callback, funcs);
++      }
++
++
++}
++/* }}} */
++
++/* {{{ proto bool sqlite_create_function(resource db, string funcname, mixed callback[, long num_args])
++    Registers a "regular" function for queries. */
++PHP_FUNCTION(sqlite_create_function)
++{
++      char *funcname = NULL;
++      int funcname_len;
++      zval *zcall, *zdb;
++      struct php_sqlite_db *db;
++      struct php_sqlite_agg_functions *funcs;
++      char *callable = NULL;
++      long num_args = -1;
++
++      zval *object = getThis();
++
++      if (object) {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &funcname, &funcname_len, &zcall, &num_args)) {
++                      return;
++              }
++              DB_FROM_OBJECT(db, object);
++      } else {
++              if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsz|l", &zdb, &funcname, &funcname_len, &zcall, &num_args)) {
++                      return;
++              }
++              DB_FROM_ZVAL(db, &zdb);
++      }
++
++      if (!zend_is_callable(zcall, 0, &callable TSRMLS_CC)) {
++              php_error_docref(NULL TSRMLS_CC, E_WARNING, "function `%s' is not callable", callable);
++              efree(callable);
++              return;
++      }
++      efree(callable);
++
++      if (prep_callback_struct(db, 0, funcname, zcall, NULL, &funcs) == DO_REG) {
++              sqlite_create_function(db->db, funcname, num_args, php_sqlite_function_callback, funcs);
++      }
++}
++/* }}} */
++
++/* {{{ proto string sqlite_udf_encode_binary(string data)
++   Apply binary encoding (if required) to a string to return from an UDF. */
++PHP_FUNCTION(sqlite_udf_encode_binary)
++{
++      char *data = NULL;
++      int datalen;
++
++      if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!", &data, &datalen)) {
++              return;
++      }
++
++      if (data == NULL) {
++              RETURN_NULL();
++      }
++      if (datalen && (data[0] == '\x01' || memchr(data, '\0', datalen) != NULL)) {
++              /* binary string */
++              int enclen;
++              char *ret;
++
++              ret = safe_emalloc(1 + datalen / 254, 257, 3);
++              ret[0] = '\x01';
++              enclen = php_sqlite_encode_binary(data, datalen, ret+1);
++              RETVAL_STRINGL(ret, enclen+1, 0);
++      } else {
++              RETVAL_STRINGL(data, datalen, 1);
++      }
++}
++/* }}} */
++
++/* {{{ proto string sqlite_udf_decode_binary(string data)
++   Decode binary encoding on a string parameter passed to an UDF. */
++PHP_FUNCTION(sqlite_udf_decode_binary)
++{
++      char *data = NULL;
++      int datalen;
++
++      if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!", &data, &datalen)) {
++              return;
++      }
++
++      if (data == NULL) {
++              RETURN_NULL();
++      }
++      if (datalen && data[0] == '\x01') {
++              /* encoded string */
++              int enclen;
++              char *ret;
++
++              ret = emalloc(datalen);
++              enclen = php_sqlite_decode_binary(data+1, ret);
++              ret[enclen] = '\0';
++              RETVAL_STRINGL(ret, enclen, 0);
++      } else {
++              RETVAL_STRINGL(data, datalen, 1);
++      }
++}
++/* }}} */
++
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: sw=4 ts=4 fdm=marker
++ * vim<600: sw=4 ts=4
++ */
+--- /dev/null
++++ b/ext/sqlite/sqlite.dsp
+@@ -0,0 +1,339 @@
++# Microsoft Developer Studio Project File - Name="sqlite" - Package Owner=<4>\r
++# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
++# ** DO NOT EDIT **\r
++\r
++# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
++\r
++CFG=sqlite - Win32 Debug_TS\r
++!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
++!MESSAGE use the Export Makefile command and run\r
++!MESSAGE \r
++!MESSAGE NMAKE /f "sqlite.mak".\r
++!MESSAGE \r
++!MESSAGE You can specify a configuration when running NMAKE\r
++!MESSAGE by defining the macro CFG on the command line. For example:\r
++!MESSAGE \r
++!MESSAGE NMAKE /f "sqlite.mak" CFG="sqlite - Win32 Debug_TS"\r
++!MESSAGE \r
++!MESSAGE Possible choices for configuration are:\r
++!MESSAGE \r
++!MESSAGE "sqlite - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")\r
++!MESSAGE "sqlite - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")\r
++!MESSAGE \r
++\r
++# Begin Project\r
++# PROP AllowPerConfigDependencies 0\r
++# PROP Scc_ProjName ""\r
++# PROP Scc_LocalPath ""\r
++CPP=cl.exe\r
++MTL=midl.exe\r
++RSC=rc.exe\r
++\r
++!IF  "$(CFG)" == "sqlite - Win32 Release_TS"\r
++\r
++# PROP BASE Use_MFC 0\r
++# PROP BASE Use_Debug_Libraries 0\r
++# PROP BASE Output_Dir "Release_TS"\r
++# PROP BASE Intermediate_Dir "Release_TS"\r
++# PROP BASE Ignore_Export_Lib 0\r
++# PROP BASE Target_Dir ""\r
++# PROP Use_MFC 0\r
++# PROP Use_Debug_Libraries 0\r
++# PROP Output_Dir "Release_TS"\r
++# PROP Intermediate_Dir "Release_TS"\r
++# PROP Ignore_Export_Lib 0\r
++# PROP Target_Dir ""\r
++# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SQLITE_EXPORTS" /YX /FD /c\r
++# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "..\..\win32" /I "..\..\..\php_build" /D ZEND_DEBUG=0 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "COMPILE_DL_SQLITE" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_SQLITE=1 /D "PHP_SQLITE_EXPORTS" /FR /YX /FD /c\r
++# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
++# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
++# ADD BASE RSC /l 0x407 /d "NDEBUG"\r
++# ADD RSC /l 0x407 /d "NDEBUG"\r
++BSC32=bscmake.exe\r
++# ADD BASE BSC32 /nologo\r
++# ADD BSC32 /nologo\r
++LINK32=link.exe\r
++# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386\r
++# ADD LINK32 php5ts.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS\php_sqlite.dll" /libpath:"..\..\Release_TS" /libpath:"..\..\Release_TS_Inline" /libpath:"..\..\..\php_build\release"\r
++\r
++!ELSEIF  "$(CFG)" == "sqlite - Win32 Debug_TS"\r
++\r
++# PROP BASE Use_MFC 0\r
++# PROP BASE Use_Debug_Libraries 1\r
++# PROP BASE Output_Dir "Debug_TS"\r
++# PROP BASE Intermediate_Dir "Debug_TS"\r
++# PROP BASE Target_Dir ""\r
++# PROP Use_MFC 0\r
++# PROP Use_Debug_Libraries 1\r
++# PROP Output_Dir "Debug_TS"\r
++# PROP Intermediate_Dir "Debug_TS"\r
++# PROP Ignore_Export_Lib 0\r
++# PROP Target_Dir ""\r
++# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SQLITE_EXPORTS" /YX /FD /GZ /c\r
++# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "..\..\win32" /I "..\..\..\php_build" /D ZEND_DEBUG=1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "COMPILE_DL_SQLITE" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_SQLITE=1 /D "PHP_SQLITE_EXPORTS" /YX /FD /GZ /c\r
++# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
++# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
++# ADD BASE RSC /l 0x407 /d "_DEBUG"\r
++# ADD RSC /l 0x407 /d "_DEBUG"\r
++BSC32=bscmake.exe\r
++# ADD BASE BSC32 /nologo\r
++# ADD BSC32 /nologo\r
++LINK32=link.exe\r
++# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept\r
++# ADD LINK32 php5ts_debug.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS\php_sqlite.dll" /pdbtype:sept /libpath:"..\..\Debug_TS" /libpath:"..\..\..\php_build\release"\r
++\r
++!ENDIF \r
++\r
++# Begin Target\r
++\r
++# Name "sqlite - Win32 Release_TS"\r
++# Name "sqlite - Win32 Debug_TS"\r
++# Begin Group "Source Files"\r
++\r
++# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
++# Begin Group "libsqlite"\r
++\r
++# PROP Default_Filter ""\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\attach.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\auth.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\btree.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\btree.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\btree_rb.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\build.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\config.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\copy.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\date.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\delete.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\encode.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\expr.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\func.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\hash.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\hash.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\insert.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\main.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\opcodes.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\opcodes.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\os.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\os.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\pager.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\pager.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\parse.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\parse.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\pragma.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\printf.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\random.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\select.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\sqlite.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\sqlite.w32.h\r
++\r
++!IF  "$(CFG)" == "sqlite - Win32 Release_TS"\r
++\r
++# Begin Custom Build\r
++InputDir=.\libsqlite\src\r
++InputPath=.\libsqlite\src\sqlite.w32.h\r
++\r
++"$(InputDir)\sqlite.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
++      copy $(InputPath) $(InputDir)\sqlite.h\r
++\r
++# End Custom Build\r
++\r
++!ELSEIF  "$(CFG)" == "sqlite - Win32 Debug_TS"\r
++\r
++# Begin Custom Build\r
++InputDir=.\libsqlite\src\r
++InputPath=.\libsqlite\src\sqlite.w32.h\r
++\r
++"$(InputDir)\sqlite.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
++      copy $(InputPath) $(InputDir)\sqlite.h\r
++\r
++# End Custom Build\r
++\r
++!ENDIF \r
++\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\sqlite_config.w32.h\r
++\r
++!IF  "$(CFG)" == "sqlite - Win32 Release_TS"\r
++\r
++# Begin Custom Build\r
++InputDir=.\libsqlite\src\r
++InputPath=.\libsqlite\src\sqlite_config.w32.h\r
++\r
++"$(InputDir)\config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
++      copy $(InputPath) $(InputDir)\config.h\r
++\r
++# End Custom Build\r
++\r
++!ELSEIF  "$(CFG)" == "sqlite - Win32 Debug_TS"\r
++\r
++# Begin Custom Build\r
++InputDir=.\libsqlite\src\r
++InputPath=.\libsqlite\src\sqlite_config.w32.h\r
++\r
++"$(InputDir)\config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
++      copy $(InputPath) $(InputDir)\config.h\r
++\r
++# End Custom Build\r
++\r
++!ENDIF \r
++\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\sqliteInt.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\table.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\tokenize.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\trigger.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\update.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\util.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\vacuum.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\vdbe.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\vdbe.h\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\vdbeaux.c\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\libsqlite\src\where.c\r
++# End Source File\r
++# End Group\r
++# Begin Source File\r
++\r
++SOURCE=.\php_sqlite.def\r
++# End Source File\r
++# Begin Source File\r
++\r
++SOURCE=.\sqlite.c\r
++# ADD CPP /I "libsqlite\src"\r
++# End Source File\r
++# End Group\r
++# Begin Group "Header Files"\r
++\r
++# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
++# Begin Source File\r
++\r
++SOURCE=.\php_sqlite.h\r
++# End Source File\r
++# End Group\r
++# End Target\r
++# End Project\r
+--- /dev/null
++++ b/ext/sqlite/sqlite.php
+@@ -0,0 +1,36 @@
++<?php
++if (!extension_loaded("sqlite")) {
++      dl("sqlite.so");
++      if (!extension_loaded("sqlite")) {
++              exit("Please enable SQLite support\n");
++      }
++}
++
++debug_zval_dump(sqlite_libversion());
++debug_zval_dump(sqlite_libencoding());
++
++$s = sqlite_open("weztest.sqlite", 0666, $err);
++
++debug_zval_dump($err);
++debug_zval_dump($s);
++
++$r = sqlite_query("create table foo (a INTEGER PRIMARY KEY, b INTEGER )", $s);
++debug_zval_dump(sqlite_last_error($s));
++debug_zval_dump(sqlite_error_string(sqlite_last_error($s)));
++
++$r = sqlite_query("select *, php('md5', sql) as o from sqlite_master", $s);
++debug_zval_dump($r);
++debug_zval_dump(sqlite_num_rows($r));
++debug_zval_dump(sqlite_num_fields($r));
++
++for ($j = 0; $j < sqlite_num_fields($r); $j++) {
++      echo "Field $j is " . sqlite_field_name($r, $j) . "\n";
++}
++
++while ($row = sqlite_fetch_array($r, SQLITE_ASSOC)) {
++      print_r($row);
++}
++
++sqlite_close($s);
++
++?>
+--- /dev/null
++++ b/ext/sqlite/tests/blankdb.inc
+@@ -0,0 +1,3 @@
++<?php #vim:ft=php
++$db = sqlite_open(":memory:");
++?>
+--- /dev/null
++++ b/ext/sqlite/tests/blankdb_oo.inc
+@@ -0,0 +1,3 @@
++<?php #vim:ft=php
++$db = new SQLiteDatabase(":memory:");
++?>
+--- /dev/null
++++ b/ext/sqlite/tests/bug26911.phpt
+@@ -0,0 +1,12 @@
++--TEST--
++Bug #26911 (crash when fetching data from empty queries)
++--SKIPIF--
++<?php if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php
++      $db = sqlite_open(":memory:");
++      $a = sqlite_query($db, "  ");
++      echo "I am ok\n";
++?>
++--EXPECT--
++I am ok
+--- /dev/null
++++ b/ext/sqlite/tests/bug28112.phpt
+@@ -0,0 +1,16 @@
++--TEST--
++Bug #28112 (sqlite_query() crashing apache on malformed query)
++--SKIPIF--
++<?php if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php
++
++if (!($db = sqlite_open(":memory:", 666, $error))) die ("Couldn't open the database");
++sqlite_query($db, "create table frob (foo INTEGER PRIMARY KEY, bar text);");
++$res = @sqlite_array_query($db, "");
++
++?>
++===DONE===
++<?php exit(0); ?>
++--EXPECTF--
++===DONE===
+--- /dev/null
++++ b/ext/sqlite/tests/bug35248.phpt
+@@ -0,0 +1,15 @@
++--TEST--
++Bug #35248 (sqlite_query does not return parse error message)
++--SKIPIF--
++<?php if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php
++      $db = sqlite_open(":memory:");
++      $res = @sqlite_query($db, "asdfesdfa", SQLITE_NUM, $err);
++      var_dump($err);
++      $res = @sqlite_unbuffered_query($db, "asdfesdfa", SQLITE_NUM, $err);
++      var_dump($err);
++?>
++--EXPECT--
++string(30) "near "asdfesdfa": syntax error"
++string(30) "near "asdfesdfa": syntax error"
+--- /dev/null
++++ b/ext/sqlite/tests/bug38759.phpt
+@@ -0,0 +1,18 @@
++--TEST--
++Bug #38759 (sqlite2 empty query causes segfault)
++--SKIPIF--
++<?php 
++if (!extension_loaded("pdo")) print "skip"; 
++if (!extension_loaded("sqlite")) print "skip"; 
++?>
++--FILE--
++<?php
++
++$dbh = new PDO('sqlite2::memory:');
++var_dump($dbh->query(" "));
++
++echo "Done\n";
++?>
++--EXPECTF--   
++bool(false)
++Done
+--- /dev/null
++++ b/ext/sqlite/tests/bug48679.phpt
+@@ -0,0 +1,20 @@
++--TEST--
++Bug #48679 (sqlite2 count on unbuffered query causes segfault)
++--SKIPIF--
++<?php 
++if (!extension_loaded("sqlite")) print "skip"; 
++?>
++--FILE--
++<?php
++
++try {
++      $x = new sqliteunbuffered;
++      count($x);
++} catch (SQLiteException $e) {
++      var_dump($e->getMessage());
++}
++echo "Done\n";
++?>
++--EXPECT--    
++string(41) "Row count is not available for this query"
++Done
+--- /dev/null
++++ b/ext/sqlite/tests/pdo/common.phpt
+@@ -0,0 +1,12 @@
++--TEST--
++SQLite2
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded('pdo') || !extension_loaded('sqlite')) print 'skip'; ?>
++--REDIRECTTEST--
++return array(
++      'ENV' => array(
++                      'PDOTEST_DSN' => 'sqlite2::memory:'
++              ),
++      'TESTS' => 'ext/pdo/tests'
++      );
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_001.phpt
+@@ -0,0 +1,16 @@
++--TEST--
++sqlite: sqlite_open/close
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++require_once('blankdb.inc');
++echo "$db\n";
++sqlite_close($db);
++echo "Done\n";
++?>
++--EXPECTF--
++Resource id #%d
++Done
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_002.phpt
+@@ -0,0 +1,32 @@
++--TEST--
++sqlite: Simple insert/select
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++sqlite_query("CREATE TABLE foo(c1 date, c2 time, c3 varchar(64))", $db);
++sqlite_query("INSERT INTO foo VALUES ('2002-01-02', '12:49:00', NULL)", $db);
++$r = sqlite_query("SELECT * from foo", $db);
++var_dump(sqlite_fetch_array($r));
++sqlite_close($db);
++?>
++--EXPECT--
++array(6) {
++  [0]=>
++  string(10) "2002-01-02"
++  ["c1"]=>
++  string(10) "2002-01-02"
++  [1]=>
++  string(8) "12:49:00"
++  ["c2"]=>
++  string(8) "12:49:00"
++  [2]=>
++  NULL
++  ["c3"]=>
++  NULL
++}
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_003.phpt
+@@ -0,0 +1,52 @@
++--TEST--
++sqlite: Simple insert/select, different result represenatation
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++sqlite_query("CREATE TABLE foo(c1 date, c2 time, c3 varchar(64))", $db);
++sqlite_query("INSERT INTO foo VALUES ('2002-01-02', '12:49:00', NULL)", $db);
++$r = sqlite_query("SELECT * from foo", $db);
++var_dump(sqlite_fetch_array($r, SQLITE_BOTH));
++$r = sqlite_query("SELECT * from foo", $db);
++var_dump(sqlite_fetch_array($r, SQLITE_NUM));
++$r = sqlite_query("SELECT * from foo", $db);
++var_dump(sqlite_fetch_array($r, SQLITE_ASSOC));
++sqlite_close($db);
++?>
++--EXPECT--
++array(6) {
++  [0]=>
++  string(10) "2002-01-02"
++  ["c1"]=>
++  string(10) "2002-01-02"
++  [1]=>
++  string(8) "12:49:00"
++  ["c2"]=>
++  string(8) "12:49:00"
++  [2]=>
++  NULL
++  ["c3"]=>
++  NULL
++}
++array(3) {
++  [0]=>
++  string(10) "2002-01-02"
++  [1]=>
++  string(8) "12:49:00"
++  [2]=>
++  NULL
++}
++array(3) {
++  ["c1"]=>
++  string(10) "2002-01-02"
++  ["c2"]=>
++  string(8) "12:49:00"
++  ["c3"]=>
++  NULL
++}
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_004.phpt
+@@ -0,0 +1,49 @@
++--TEST--
++sqlite: binary encoding
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++$strings = array(
++      "hello",
++      "hello\x01o",
++      "\x01hello there",
++      "hello\x00there",
++      ""
++);
++
++sqlite_query("CREATE TABLE strings(a)", $db);
++
++foreach ($strings as $str) {
++      sqlite_query("INSERT INTO strings VALUES('" . sqlite_escape_string($str) . "')", $db);
++}
++
++$i = 0;
++$r = sqlite_query("SELECT * from strings", $db);
++while ($row = sqlite_fetch_array($r, SQLITE_NUM)) {
++      if ($row[0] !== $strings[$i]) {
++              echo "FAIL!\n";
++              var_dump($row[0]);
++              var_dump($strings[$i]);
++      } else {
++              echo "OK!\n";
++      }
++      $i++;
++}
++
++sqlite_close($db);
++
++echo "DONE!\n";
++?>
++--EXPECT--
++OK!
++OK!
++OK!
++OK!
++OK!
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_005.phpt
+@@ -0,0 +1,50 @@
++--TEST--
++sqlite: aggregate functions
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++sqlite_query("CREATE TABLE strings(a)", $db);
++
++foreach ($data as $str) {
++      sqlite_query("INSERT INTO strings VALUES('" . sqlite_escape_string($str) . "')", $db);
++}
++
++function cat_step(&$context, $string)
++{
++      $context .= $string;
++}
++
++function cat_fin(&$context)
++{
++      return $context;
++}
++
++sqlite_create_aggregate($db, "cat", "cat_step", "cat_fin");
++
++$r = sqlite_query("SELECT cat(a) from strings", $db);
++while ($row = sqlite_fetch_array($r, SQLITE_NUM)) {
++      var_dump($row);
++}
++
++sqlite_close($db);
++
++echo "DONE!\n";
++?>
++--EXPECT--
++array(1) {
++  [0]=>
++  string(11) "onetwothree"
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_006.phpt
+@@ -0,0 +1,55 @@
++--TEST--
++sqlite: regular functions
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++$data = array(
++      array("one", "uno"),
++      array("two", "dos"),
++      array("three", "tres"),
++      );
++
++sqlite_query("CREATE TABLE strings(a,b)", $db);
++
++function implode_args()
++{
++      $args = func_get_args();
++      $sep = array_shift($args);
++      return implode($sep, $args);
++}
++
++foreach ($data as $row) {
++      sqlite_query("INSERT INTO strings VALUES('" . sqlite_escape_string($row[0]) . "','" . sqlite_escape_string($row[1]) . "')", $db);
++}
++
++sqlite_create_function($db, "implode", "implode_args");
++
++$r = sqlite_query("SELECT implode('-', a, b) from strings", $db);
++while ($row = sqlite_fetch_array($r, SQLITE_NUM)) {
++      var_dump($row);
++}
++
++sqlite_close($db);
++
++echo "DONE!\n";
++?>
++--EXPECT--
++array(1) {
++  [0]=>
++  string(7) "one-uno"
++}
++array(1) {
++  [0]=>
++  string(7) "two-dos"
++}
++array(1) {
++  [0]=>
++  string(10) "three-tres"
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_007.phpt
+@@ -0,0 +1,52 @@
++--TEST--
++sqlite: Simple insert/select (unbuffered)
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++sqlite_query("CREATE TABLE foo(c1 date, c2 time, c3 varchar(64))", $db);
++sqlite_query("INSERT INTO foo VALUES ('2002-01-02', '12:49:00', NULL)", $db);
++$r = sqlite_unbuffered_query("SELECT * from foo", $db);
++var_dump(sqlite_fetch_array($r, SQLITE_BOTH));
++$r = sqlite_unbuffered_query("SELECT * from foo", $db);
++var_dump(sqlite_fetch_array($r, SQLITE_NUM));
++$r = sqlite_unbuffered_query("SELECT * from foo", $db);
++var_dump(sqlite_fetch_array($r, SQLITE_ASSOC));
++sqlite_close($db);
++?>
++--EXPECT--
++array(6) {
++  [0]=>
++  string(10) "2002-01-02"
++  ["c1"]=>
++  string(10) "2002-01-02"
++  [1]=>
++  string(8) "12:49:00"
++  ["c2"]=>
++  string(8) "12:49:00"
++  [2]=>
++  NULL
++  ["c3"]=>
++  NULL
++}
++array(3) {
++  [0]=>
++  string(10) "2002-01-02"
++  [1]=>
++  string(8) "12:49:00"
++  [2]=>
++  NULL
++}
++array(3) {
++  ["c1"]=>
++  string(10) "2002-01-02"
++  ["c2"]=>
++  string(8) "12:49:00"
++  ["c3"]=>
++  NULL
++}
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_008.phpt
+@@ -0,0 +1,46 @@
++--TEST--
++sqlite: fetch all (buffered)
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++sqlite_query("CREATE TABLE strings(a VARCHAR)", $db);
++
++foreach ($data as $str) {
++      sqlite_query("INSERT INTO strings VALUES('$str')", $db);
++}
++
++$r = sqlite_query("SELECT a from strings", $db);
++while ($row = sqlite_fetch_array($r, SQLITE_NUM)) {
++      var_dump($row);
++}
++
++sqlite_close($db);
++
++echo "DONE!\n";
++?>
++--EXPECT--
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_009.phpt
+@@ -0,0 +1,46 @@
++--TEST--
++sqlite: fetch all (unbuffered)
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++sqlite_query("CREATE TABLE strings(a VARCHAR)", $db);
++
++foreach ($data as $str) {
++      sqlite_query("INSERT INTO strings VALUES('$str')", $db);
++}
++
++$r = sqlite_unbuffered_query("SELECT a from strings", $db);
++while ($row = sqlite_fetch_array($r, SQLITE_NUM)) {
++      var_dump($row);
++}
++
++sqlite_close($db);
++
++echo "DONE!\n";
++?>
++--EXPECT--
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_010.phpt
+@@ -0,0 +1,81 @@
++--TEST--
++sqlite: fetch all (iterator)
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++sqlite_query("CREATE TABLE strings(a VARCHAR)", $db);
++
++foreach ($data as $str) {
++      sqlite_query("INSERT INTO strings VALUES('$str')", $db);
++}
++
++$r = sqlite_unbuffered_query("SELECT a from strings", $db);
++while (sqlite_valid($r)) {
++      var_dump(sqlite_current($r, SQLITE_NUM));
++      sqlite_next($r);
++}
++$r = sqlite_query("SELECT a from strings", $db);
++while (sqlite_valid($r)) {
++      var_dump(sqlite_current($r, SQLITE_NUM));
++      sqlite_next($r);
++}
++sqlite_rewind($r);
++while (sqlite_valid($r)) {
++      var_dump(sqlite_current($r, SQLITE_NUM));
++      sqlite_next($r);
++}
++
++sqlite_close($db);
++
++echo "DONE!\n";
++?>
++--EXPECT--
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_011.phpt
+@@ -0,0 +1,34 @@
++--TEST--
++sqlite: returned associative column names
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++sqlite_query("CREATE TABLE foo (c1 char, c2 char, c3 char)", $db);
++sqlite_query("CREATE TABLE bar (c1 char, c2 char, c3 char)", $db);
++sqlite_query("INSERT INTO foo VALUES ('1', '2', '3')", $db);
++sqlite_query("INSERT INTO bar VALUES ('4', '5', '6')", $db);
++$r = sqlite_query("SELECT * from foo, bar", $db, SQLITE_ASSOC);
++var_dump(sqlite_fetch_array($r));
++sqlite_close($db);
++?>
++--EXPECT--
++array(6) {
++  ["foo.c1"]=>
++  string(1) "1"
++  ["foo.c2"]=>
++  string(1) "2"
++  ["foo.c3"]=>
++  string(1) "3"
++  ["bar.c1"]=>
++  string(1) "4"
++  ["bar.c2"]=>
++  string(1) "5"
++  ["bar.c3"]=>
++  string(1) "6"
++}
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_012.phpt
+@@ -0,0 +1,38 @@
++--TEST--
++sqlite: read field names
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++sqlite_query("CREATE TABLE strings(foo VARCHAR, bar VARCHAR, baz VARCHAR)", $db);
++
++echo "Buffered\n";
++$r = sqlite_query("SELECT * from strings", $db);
++for($i=0; $i<sqlite_num_fields($r); $i++) {
++      var_dump(sqlite_field_name($r, $i));
++}
++echo "Unbuffered\n";
++$r = sqlite_unbuffered_query("SELECT * from strings", $db);
++for($i=0; $i<sqlite_num_fields($r); $i++) {
++      var_dump(sqlite_field_name($r, $i));
++}
++
++sqlite_close($db);
++
++echo "DONE!\n";
++?>
++--EXPECT--
++Buffered
++string(3) "foo"
++string(3) "bar"
++string(3) "baz"
++Unbuffered
++string(3) "foo"
++string(3) "bar"
++string(3) "baz"
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_013.phpt
+@@ -0,0 +1,78 @@
++--TEST--
++sqlite: fetch column
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++$data = array(
++      array (0 => 'one', 1 => 'two'),
++      array (0 => 'three', 1 => 'four')
++      );
++
++sqlite_query("CREATE TABLE strings(a VARCHAR, b VARCHAR)", $db);
++
++foreach ($data as $str) {
++      sqlite_query("INSERT INTO strings VALUES('${str[0]}','${str[1]}')", $db);
++}
++
++echo "====BUFFERED====\n";
++$r = sqlite_query("SELECT a, b from strings", $db);
++while (sqlite_valid($r)) {
++      var_dump(sqlite_current($r, SQLITE_NUM));
++      var_dump(sqlite_column($r, 0));
++      var_dump(sqlite_column($r, 1));
++      var_dump(sqlite_column($r, 'a'));
++      var_dump(sqlite_column($r, 'b'));
++      sqlite_next($r);
++}
++echo "====UNBUFFERED====\n";
++$r = sqlite_unbuffered_query("SELECT a, b from strings", $db);
++while (sqlite_valid($r)) {
++      var_dump(sqlite_column($r, 0));
++      var_dump(sqlite_column($r, 'b'));
++      var_dump(sqlite_column($r, 1));
++      var_dump(sqlite_column($r, 'a'));
++      sqlite_next($r);
++}
++
++sqlite_close($db);
++
++echo "DONE!\n";
++?>
++--EXPECT--
++====BUFFERED====
++array(2) {
++  [0]=>
++  string(3) "one"
++  [1]=>
++  string(3) "two"
++}
++string(3) "one"
++string(3) "two"
++string(3) "one"
++string(3) "two"
++array(2) {
++  [0]=>
++  string(5) "three"
++  [1]=>
++  string(4) "four"
++}
++string(5) "three"
++string(4) "four"
++string(5) "three"
++string(4) "four"
++====UNBUFFERED====
++string(3) "one"
++string(3) "two"
++NULL
++NULL
++string(5) "three"
++string(4) "four"
++NULL
++NULL
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_014.phpt
+@@ -0,0 +1,120 @@
++--TEST--
++sqlite: fetch all (fetch_all)
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++sqlite_query("CREATE TABLE strings(a VARCHAR)", $db);
++
++foreach ($data as $str) {
++      sqlite_query("INSERT INTO strings VALUES('$str')", $db);
++}
++
++echo "unbuffered twice\n";
++$r = sqlite_unbuffered_query("SELECT a from strings", $db, SQLITE_NUM);
++var_dump(sqlite_fetch_all($r));
++var_dump(sqlite_fetch_all($r));
++
++echo "unbuffered with fetch_array\n";
++$r = sqlite_unbuffered_query("SELECT a from strings", $db, SQLITE_NUM);
++var_dump(sqlite_fetch_array($r));
++var_dump(sqlite_fetch_all($r));
++
++echo "buffered\n";
++$r = sqlite_query("SELECT a from strings", $db, SQLITE_NUM);
++var_dump(sqlite_fetch_all($r));
++var_dump(sqlite_fetch_array($r));
++var_dump(sqlite_fetch_all($r));
++
++sqlite_close($db);
++
++echo "DONE!\n";
++?>
++--EXPECTF--
++unbuffered twice
++array(3) {
++  [0]=>
++  array(1) {
++    [0]=>
++    string(3) "one"
++  }
++  [1]=>
++  array(1) {
++    [0]=>
++    string(3) "two"
++  }
++  [2]=>
++  array(1) {
++    [0]=>
++    string(5) "three"
++  }
++}
++
++Warning: sqlite_fetch_all(): One or more rowsets were already returned; returning NULL this time in %ssqlite_014.php on line %d
++array(0) {
++}
++unbuffered with fetch_array
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++array(2) {
++  [0]=>
++  array(1) {
++    [0]=>
++    string(3) "two"
++  }
++  [1]=>
++  array(1) {
++    [0]=>
++    string(5) "three"
++  }
++}
++buffered
++array(3) {
++  [0]=>
++  array(1) {
++    [0]=>
++    string(3) "one"
++  }
++  [1]=>
++  array(1) {
++    [0]=>
++    string(3) "two"
++  }
++  [2]=>
++  array(1) {
++    [0]=>
++    string(5) "three"
++  }
++}
++bool(false)
++array(3) {
++  [0]=>
++  array(1) {
++    [0]=>
++    string(3) "one"
++  }
++  [1]=>
++  array(1) {
++    [0]=>
++    string(3) "two"
++  }
++  [2]=>
++  array(1) {
++    [0]=>
++    string(5) "three"
++  }
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_015.phpt
+@@ -0,0 +1,49 @@
++--TEST--
++sqlite: fetch all (array_query)
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++sqlite_query("CREATE TABLE strings(a VARCHAR)", $db);
++
++foreach ($data as $str) {
++      sqlite_query("INSERT INTO strings VALUES('$str')", $db);
++}
++
++$res = sqlite_array_query("SELECT a from strings", $db, SQLITE_NUM);
++var_dump($res);
++
++$db = null;
++
++echo "DONE!\n";
++?>
++--EXPECTF--
++array(3) {
++  [0]=>
++  array(1) {
++    [0]=>
++    string(3) "one"
++  }
++  [1]=>
++  array(1) {
++    [0]=>
++    string(3) "two"
++  }
++  [2]=>
++  array(1) {
++    [0]=>
++    string(5) "three"
++  }
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_016.phpt
+@@ -0,0 +1,45 @@
++--TEST--
++sqlite: fetch single
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++$data = array(
++      array (0 => 'one', 1 => 'two'),
++      array (0 => 'three', 1 => 'four')
++      );
++
++sqlite_query("CREATE TABLE strings(a VARCHAR, b VARCHAR)", $db);
++
++foreach ($data as $str) {
++      sqlite_query("INSERT INTO strings VALUES('${str[0]}','${str[1]}')", $db);
++}
++
++echo "====BUFFERED====\n";
++$r = sqlite_query("SELECT a, b from strings", $db);
++while (sqlite_valid($r)) {
++      var_dump(sqlite_fetch_single($r));
++}
++echo "====UNBUFFERED====\n";
++$r = sqlite_unbuffered_query("SELECT a, b from strings", $db);
++while (sqlite_valid($r)) {
++      var_dump(sqlite_fetch_single($r));
++}
++
++sqlite_close($db);
++
++echo "DONE!\n";
++?>
++--EXPECT--
++====BUFFERED====
++string(3) "one"
++string(5) "three"
++====UNBUFFERED====
++string(3) "one"
++string(5) "three"
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_017.phpt
+@@ -0,0 +1,33 @@
++--TEST--
++sqlite: UDF binary handling functions
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++
++$data = array(
++      "hello there",
++      "this has a \x00 char in the middle",
++      "\x01 this has an 0x01 at the start",
++      "this has \x01 in the middle"
++      );
++
++foreach ($data as $item) {
++      $coded = sqlite_udf_encode_binary($item);
++      echo bin2hex($coded) . "\n";
++      $decoded = sqlite_udf_decode_binary($coded);
++      if ($item != $decoded) {
++              echo "FAIL! $item decoded is $decoded\n";
++      }
++}
++
++echo "OK!\n";
++
++?>
++--EXPECT--
++68656c6c6f207468657265
++0101736768721f6760721f601fff1f626760711f686d1f7367641f6c6863636b64
++0102ff1e726667711e665f711e5f6c1e2e762e2f1e5f721e7266631e71725f7072
++7468697320686173200120696e20746865206d6964646c65
++OK!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_018.phpt
+@@ -0,0 +1,14 @@
++--TEST--
++sqlite: crash on bad queries inside sqlite_array_query()
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php
++include "blankdb.inc";
++
++sqlite_array_query($db, "SELECT foo FROM foobar");
++sqlite_close($db);
++?>
++--EXPECTF--
++Warning: sqlite_array_query(): no such table: foobar in %s on line %d
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_019.phpt
+@@ -0,0 +1,47 @@
++--TEST--
++sqlite: single query
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php
++include "blankdb.inc";
++      
++sqlite_query($db, "CREATE TABLE test_db ( id INTEGER PRIMARY KEY, data VARCHAR(100) )");
++for ($i = 0; $i < 10; $i++) {
++      sqlite_query($db, "INSERT INTO test_db (data) VALUES('{$i}data')");
++}
++sqlite_query($db, "INSERT INTO test_db (data) VALUES(NULL)");
++                                               
++var_dump(sqlite_single_query($db, "SELECT id FROM test_db WHERE id=5"));
++var_dump(sqlite_single_query($db, "SELECT * FROM test_db WHERE id=4"));
++var_dump(sqlite_single_query($db, "SELECT data FROM test_db WHERE id=6"));
++var_dump(sqlite_single_query($db, "SELECT * FROM test_db WHERE id < 5"));
++var_dump(sqlite_single_query($db, "SELECT * FROM test db WHERE id < 4"));
++var_dump(sqlite_single_query($db, "SELECT * FROM test_db WHERE id=999999"));
++var_dump(sqlite_single_query($db, "SELECT id FROM test_db WHERE id=5", FALSE));
++
++sqlite_close($db);
++?>
++--EXPECTF--
++string(1) "5"
++string(1) "4"
++string(5) "5data"
++array(4) {
++  [0]=>
++  string(1) "1"
++  [1]=>
++  string(1) "2"
++  [2]=>
++  string(1) "3"
++  [3]=>
++  string(1) "4"
++}
++
++Warning: sqlite_single_query(): no such table: test in %s on line %d
++bool(false)
++NULL
++array(1) {
++  [0]=>
++  string(1) "5"
++}
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_022.phpt
+@@ -0,0 +1,101 @@
++--TEST--
++sqlite: sqlite_seek
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++sqlite_query("CREATE TABLE strings(a)", $db);
++
++foreach ($data as $str) {
++      sqlite_query("INSERT INTO strings VALUES('$str')", $db);
++}
++
++$res = sqlite_query("SELECT a FROM strings", $db, SQLITE_NUM);
++for ($idx = -1; $idx < 4; $idx++) {
++      echo "====SEEK:$idx====\n";
++      sqlite_seek($res, $idx);
++      var_dump(sqlite_current($res));
++}
++echo "====AGAIN====\n";
++for ($idx = -1; $idx < 4; $idx++) {
++      echo "====SEEK:$idx====\n";
++      sqlite_seek($res, $idx);
++      var_dump(sqlite_current($res));
++}
++
++sqlite_close($db);
++
++echo "====DONE!====\n";
++?>
++--EXPECTF--
++====SEEK:-1====
++
++Warning: sqlite_seek(): row -1 out of range in %ssqlite_022.php on line %d
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++====SEEK:0====
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++====SEEK:1====
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++====SEEK:2====
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++====SEEK:3====
++
++Warning: sqlite_seek(): row 3 out of range in %ssqlite_022.php on line %d
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++====AGAIN====
++====SEEK:-1====
++
++Warning: sqlite_seek(): row -1 out of range in %ssqlite_022.php on line %d
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++====SEEK:0====
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++====SEEK:1====
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++====SEEK:2====
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++====SEEK:3====
++
++Warning: sqlite_seek(): row 3 out of range in %ssqlite_022.php on line %d
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++====DONE!====
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_023.phpt
+@@ -0,0 +1,105 @@
++--TEST--
++sqlite: sqlite_[has_]prev
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php
++include "blankdb.inc";
++
++$data = array(
++              "one",
++              "two",
++              "three"
++              );
++
++sqlite_query("CREATE TABLE strings(a)", $db);
++
++foreach ($data as $str) {
++  sqlite_query("INSERT INTO strings VALUES('$str')", $db);
++}
++
++$r = sqlite_query("SELECT a FROM strings", $db, SQLITE_NUM);
++
++echo "====TRAVERSE====\n";
++for(sqlite_rewind($r); sqlite_valid($r); sqlite_next($r)) {
++  var_dump(sqlite_current($r));
++
++}
++echo "====REVERSE====\n";
++do {
++  sqlite_prev($r);
++  var_dump(sqlite_current($r));
++} while(sqlite_has_prev($r));
++
++echo "====UNBUFFERED====\n";
++
++$r = sqlite_unbuffered_query("SELECT a FROM strings", $db, SQLITE_NUM);
++
++echo "====TRAVERSE====\n";
++for(sqlite_rewind($r); sqlite_valid($r); sqlite_next($r)) {
++  var_dump(sqlite_current($r));
++
++}
++echo "====REVERSE====\n";
++do {
++  sqlite_prev($r);
++  var_dump(sqlite_current($r));
++} while(sqlite_has_prev($r));
++
++sqlite_close($db);
++
++echo "====DONE!====\n";
++?>
++--EXPECTF--
++====TRAVERSE====
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++====REVERSE====
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++====UNBUFFERED====
++====TRAVERSE====
++
++Warning: sqlite_rewind(): Cannot rewind an unbuffered result set in %ssqlite_023.php on line %d
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++====REVERSE====
++
++Warning: sqlite_prev(): you cannot use sqlite_prev on unbuffered querys in %ssqlite_023.php on line %d
++bool(false)
++
++Warning: sqlite_has_prev(): you cannot use sqlite_has_prev on unbuffered querys in %ssqlite_023.php on line %d
++====DONE!====
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_024.phpt
+@@ -0,0 +1,76 @@
++--TEST--
++sqlite: sqlite_fetch_object
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++class class24 {
++      function __construct() {
++              echo __METHOD__ . "\n";
++      }
++}
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++sqlite_query($db, "CREATE TABLE strings(a)");
++
++foreach ($data as $str) {
++      sqlite_query($db, "INSERT INTO strings VALUES('$str')");
++}
++
++echo "====class24====\n";
++$res = sqlite_query($db, "SELECT a FROM strings", SQLITE_ASSOC);
++while (sqlite_valid($res)) {
++      var_dump(sqlite_fetch_object($res, 'class24'));
++}
++
++echo "====stdclass====\n";
++$res = sqlite_query($db, "SELECT a FROM strings", SQLITE_ASSOC);
++while (sqlite_valid($res)) {
++      var_dump(sqlite_fetch_object($res));
++}
++
++sqlite_close($db);
++
++echo "====DONE!====\n";
++?>
++--EXPECTF--
++====class24====
++class24::__construct
++object(class24)#%d (1) {
++  ["a"]=>
++  string(3) "one"
++}
++class24::__construct
++object(class24)#%d (1) {
++  ["a"]=>
++  string(3) "two"
++}
++class24::__construct
++object(class24)#%d (1) {
++  ["a"]=>
++  string(5) "three"
++}
++====stdclass====
++object(stdClass)#%d (1) {
++  ["a"]=>
++  string(3) "one"
++}
++object(stdClass)#%d (1) {
++  ["a"]=>
++  string(3) "two"
++}
++object(stdClass)#%d (1) {
++  ["a"]=>
++  string(5) "three"
++}
++====DONE!====
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_025.phpt
+@@ -0,0 +1,38 @@
++--TEST--
++sqlite: sqlite_fetch_object in a loop
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++sqlite_query($db, "CREATE TABLE strings(a)");
++
++foreach (array("one", "two", "three") as $str) {
++      sqlite_query($db, "INSERT INTO strings VALUES('$str')");
++}
++
++$res = sqlite_query("SELECT * FROM strings", $db);
++
++while (($obj = sqlite_fetch_object($res))) {
++      var_dump($obj);
++}
++
++sqlite_close($db);
++?>
++--EXPECTF--
++object(stdClass)#1 (1) {
++  ["a"]=>
++  string(3) "one"
++}
++object(stdClass)#2 (1) {
++  ["a"]=>
++  string(3) "two"
++}
++object(stdClass)#1 (1) {
++  ["a"]=>
++  string(5) "three"
++}
+\ No newline at end of file
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_026.phpt
+@@ -0,0 +1,27 @@
++--TEST--
++sqlite: sqlite_fetch_column_types
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++sqlite_query($db, "CREATE TABLE strings(a, b INTEGER, c VARCHAR(10), d)");
++sqlite_query($db, "INSERT INTO strings VALUES('1', '2', '3', 'abc')");
++
++var_dump(sqlite_fetch_column_types($db, "strings"));
++
++sqlite_close($db);
++?>
++--EXPECT--
++array(4) {
++  ["a"]=>
++  string(0) ""
++  ["b"]=>
++  string(7) "INTEGER"
++  ["c"]=>
++  string(11) "VARCHAR(10)"
++  ["d"]=>
++  string(0) ""
++}
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_027.phpt
+@@ -0,0 +1,15 @@
++--TEST--
++sqlite: crash inside sqlite_escape_string() & sqlite_udf_encode_binary
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--INI--
++memory_limit=-1
++--FILE--
++<?php
++      var_dump(strlen(sqlite_escape_string(str_repeat("\0", 20000000))));
++      var_dump(strlen(sqlite_udf_encode_binary(str_repeat("\0", 20000000))));
++?>
++--EXPECT--
++int(20000002)
++int(20000002)
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_closures_001.phpt
+@@ -0,0 +1,54 @@
++--TEST--
++sqlite: aggregate functions with closures
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++sqlite_query("CREATE TABLE strings(a)", $db);
++
++foreach ($data as $str) {
++      sqlite_query("INSERT INTO strings VALUES('" . sqlite_escape_string($str) . "')", $db);
++}
++
++function cat_step(&$context, $string)
++{
++      $context .= $string;
++}
++
++function cat_fin(&$context)
++{
++      return $context;
++}
++
++sqlite_create_aggregate($db, "cat", function (&$context, $string) {
++      $context .= $string;
++}, function (&$context) {
++      return $context;
++});
++
++$r = sqlite_query("SELECT cat(a) from strings", $db);
++while ($row = sqlite_fetch_array($r, SQLITE_NUM)) {
++      var_dump($row);
++}
++
++sqlite_close($db);
++
++echo "DONE!\n";
++?>
++--EXPECT--
++array(1) {
++  [0]=>
++  string(11) "onetwothree"
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_closures_002.phpt
+@@ -0,0 +1,52 @@
++--TEST--
++sqlite: regular functions with closures
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb.inc";
++
++$data = array(
++      array("one", "uno"),
++      array("two", "dos"),
++      array("three", "tres"),
++      );
++
++sqlite_query("CREATE TABLE strings(a,b)", $db);
++
++foreach ($data as $row) {
++      sqlite_query("INSERT INTO strings VALUES('" . sqlite_escape_string($row[0]) . "','" . sqlite_escape_string($row[1]) . "')", $db);
++}
++
++sqlite_create_function($db, "implode", function () {
++      $args = func_get_args();
++      $sep = array_shift($args);
++      return implode($sep, $args);
++});
++
++$r = sqlite_query("SELECT implode('-', a, b) from strings", $db);
++while ($row = sqlite_fetch_array($r, SQLITE_NUM)) {
++      var_dump($row);
++}
++
++sqlite_close($db);
++
++echo "DONE!\n";
++?>
++--EXPECT--
++array(1) {
++  [0]=>
++  string(7) "one-uno"
++}
++array(1) {
++  [0]=>
++  string(7) "two-dos"
++}
++array(1) {
++  [0]=>
++  string(10) "three-tres"
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlitedatabase_arrayquery.phpt
+@@ -0,0 +1,23 @@
++--TEST--
++Testing SQLiteDatabase::ArrayQuery with NULL-byte string
++--SKIPIF--
++<?php
++if (!extension_loaded("sqlite")) print "skip";
++?>
++--FILE--
++<?php
++
++$method = new ReflectionMethod('sqlitedatabase::arrayquery');
++
++$class = $method->getDeclaringClass()->newInstanceArgs(array(':memory:'));
++
++$p = "\0";
++
++$method->invokeArgs($class, array_fill(0, 2, $p));
++$method->invokeArgs($class, array_fill(0, 1, $p));
++
++?>
++--EXPECTF--
++Warning: SQLiteDatabase::arrayQuery() expects parameter 2 to be long, string given in %s on line %d
++
++Warning: SQLiteDatabase::arrayQuery(): Cannot execute empty query. in %s on line %d
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_exec_basic.phpt
+@@ -0,0 +1,34 @@
++--TEST--
++Test sqlite_exec() function : basic functionality 
++--SKIPIF--
++<?php if (!extension_loaded("sqlite")) print "skip sqlite extension not loaded"; ?>
++--FILE--
++<?php
++/* Prototype  : boolean sqlite_exec(string query, resource db[, string &error_message])
++ * Description: Executes a result-less query against a given database 
++ * Source code: ext/sqlite/sqlite.c
++ * Alias to functions: 
++ */
++
++echo "*** Testing sqlite_exec() : basic functionality ***\n";
++
++// set up variables
++$query = 'CREATE TABLE foobar (id INTEGER PRIMARY KEY, name CHAR(255));';
++$error_message = null;
++
++// procedural
++$db = sqlite_open(':memory:');
++var_dump( sqlite_exec($db, $query) );
++sqlite_close($db);
++
++// oo-style
++$db = new SQLiteDatabase(':memory:');
++var_dump( $db->queryExec($query, $error_message) );
++
++?>
++===DONE===
++--EXPECTF--
++*** Testing sqlite_exec() : basic functionality ***
++bool(true)
++bool(true)
++===DONE===
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_exec_error.phpt
+@@ -0,0 +1,44 @@
++--TEST--
++Test sqlite_exec() function : error behaviour and functionality 
++--SKIPIF--
++<?php if (!extension_loaded("sqlite")) print "skip sqlite extension not loaded"; ?>
++--FILE--
++<?php
++/* Prototype  : boolean sqlite_exec(string query, resource db[, string &error_message])
++ * Description: Executes a result-less query against a given database 
++ * Source code: ext/sqlite/sqlite.c
++ * Alias to functions: 
++ */
++
++echo "*** Testing sqlite_exec() : error functionality ***\n";
++
++// set up variables
++$fail = 'CRE ATE TABLE';
++$error_message = null;
++
++// procedural
++$db = sqlite_open(':memory:');
++var_dump( sqlite_exec($db, $fail, $error_message) );
++var_dump( $error_message );
++var_dump( sqlite_exec($db) );
++sqlite_close($db);
++
++// oo-style
++$db = new SQLiteDatabase(':memory:');
++var_dump( $db->queryExec($fail, $error_message, 'fooparam') );
++
++?>
++===DONE===
++--EXPECTF--
++*** Testing sqlite_exec() : error functionality ***
++
++Warning: sqlite_exec(): near "CRE": syntax error in %s on line %d
++bool(false)
++%string|unicode%(24) "near "CRE": syntax error"
++
++Warning: sqlite_exec() expects at least 2 parameters, 1 given in %s on line %d
++NULL
++
++Warning: SQLiteDatabase::queryExec() expects at most 2 parameters, 3 given in %s on line %d
++NULL
++===DONE===
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_last_error_basic.phpt
+@@ -0,0 +1,48 @@
++--TEST--
++Test sqlite_last_error() function : basic functionality 
++--SKIPIF--
++<?php if (!extension_loaded("sqlite")) print "skip sqlite extension not loaded"; ?>
++--FILE--
++<?php
++/* Prototype  : int sqlite_last_error(resource db)
++ * Description: Returns the error code of the last error for a database. 
++ * Source code: ext/sqlite/sqlite.c
++ * Alias to functions: 
++ */
++
++echo "*** Testing sqlite_last_error() : basic functionality ***\n";
++
++// set up variables
++$query = 'CREATE TAB LE foobar (id INTEGER PRIMARY KEY, name CHAR(255));';
++$query_ok = 'CREATE TABLE foobar (id INTEGER, name CHAR(255));';
++
++// procedural
++$db = sqlite_open(':memory:');
++var_dump( sqlite_last_error($db) === SQLITE_OK );
++sqlite_exec($db, $query);
++var_dump( sqlite_last_error($db) === SQLITE_ERROR );
++sqlite_exec($db, $query_ok);
++var_dump( sqlite_last_error($db) === SQLITE_OK );
++sqlite_close($db);
++
++// oo-style
++$db = new SQLiteDatabase(':memory:');
++$db->queryExec($query);
++var_dump( $db->lastError() === SQLITE_ERROR );
++$db->queryExec($query_ok);
++var_dump( $db->lastError() === SQLITE_OK );
++
++?>
++===DONE===
++--EXPECTF--
++*** Testing sqlite_last_error() : basic functionality ***
++bool(true)
++
++Warning: sqlite_exec(): near "TAB": syntax error in %s on line %d
++bool(true)
++bool(true)
++
++Warning: SQLiteDatabase::queryExec(): near "TAB": syntax error in %s on line %d
++bool(true)
++bool(true)
++===DONE===
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_last_error_error.phpt
+@@ -0,0 +1,47 @@
++--TEST--
++Test sqlite_last_error() function : error conditions 
++--SKIPIF--
++<?php if (!extension_loaded("sqlite")) print "skip sqlite extension not loaded"; ?>
++--FILE--
++<?php
++/* Prototype  : int sqlite_last_error(resource db)
++ * Description: Returns the error code of the last error for a database. 
++ * Source code: ext/sqlite/sqlite.c
++ * Alias to functions: 
++ */
++
++echo "*** Testing sqlite_last_error() : error conditions ***\n";
++
++// Zero arguments
++echo "\n-- Testing sqlite_last_error() function with Zero arguments --\n";
++var_dump( sqlite_last_error() );
++
++//Test sqlite_last_error with one more than the expected number of arguments
++echo "\n-- Testing sqlite_last_error() function with more than expected no. of arguments --\n";
++
++$db = sqlite_open(':memory:');
++$extra_arg = 10;
++var_dump( sqlite_last_error($db, $extra_arg) );
++sqlite_close($db);
++
++$db = new SQLiteDatabase(':memory:');
++var_dump( $db->lastError($extra_arg) );
++
++?>
++===DONE===
++--EXPECTF--
++*** Testing sqlite_last_error() : error conditions ***
++
++-- Testing sqlite_last_error() function with Zero arguments --
++
++Warning: sqlite_last_error() expects exactly 1 parameter, 0 given in %s on line %d
++NULL
++
++-- Testing sqlite_last_error() function with more than expected no. of arguments --
++
++Warning: sqlite_last_error() expects exactly 1 parameter, 2 given in %s on line %d
++NULL
++
++Warning: SQLiteDatabase::lastError() expects exactly 0 parameters, 1 given in %s on line %d
++NULL
++===DONE===
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_001.phpt
+@@ -0,0 +1,17 @@
++--TEST--
++sqlite-oo: sqlite_open/close
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++require_once('blankdb_oo.inc');
++var_dump($db);
++$db = NULL;
++echo "Done\n";
++?>
++--EXPECTF--
++object(SQLiteDatabase)#%d (0) {
++}
++Done
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_002.phpt
+@@ -0,0 +1,41 @@
++--TEST--
++sqlite-oo: Simple insert/select
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++require_once('blankdb_oo.inc');
++var_dump($db);
++
++var_dump($db->query("CREATE TABLE foo(c1 date, c2 time, c3 varchar(64))"));
++var_dump($db->query("INSERT INTO foo VALUES ('2002-01-02', '12:49:00', NULL)"));
++$r = $db->query("SELECT * from foo");
++var_dump($r);
++var_dump($r->fetch());
++?>
++--EXPECTF--
++object(SQLiteDatabase)#%d (0) {
++}
++object(SQLiteResult)#%d (0) {
++}
++object(SQLiteResult)#%d (0) {
++}
++object(SQLiteResult)#%d (0) {
++}
++array(6) {
++  [0]=>
++  string(10) "2002-01-02"
++  ["c1"]=>
++  string(10) "2002-01-02"
++  [1]=>
++  string(8) "12:49:00"
++  ["c2"]=>
++  string(8) "12:49:00"
++  [2]=>
++  NULL
++  ["c3"]=>
++  NULL
++}
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_003.phpt
+@@ -0,0 +1,51 @@
++--TEST--
++sqlite-oo: Simple insert/select, different result representation
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++$db->query("CREATE TABLE foo(c1 date, c2 time, c3 varchar(64))");
++$db->query("INSERT INTO foo VALUES ('2002-01-02', '12:49:00', NULL)");
++$r = $db->query("SELECT * from foo");
++var_dump($r->fetch(SQLITE_BOTH));
++$r = $db->query("SELECT * from foo");
++var_dump($r->fetch(SQLITE_NUM));
++$r = $db->query("SELECT * from foo");
++var_dump($r->fetch(SQLITE_ASSOC));
++?>
++--EXPECT--
++array(6) {
++  [0]=>
++  string(10) "2002-01-02"
++  ["c1"]=>
++  string(10) "2002-01-02"
++  [1]=>
++  string(8) "12:49:00"
++  ["c2"]=>
++  string(8) "12:49:00"
++  [2]=>
++  NULL
++  ["c3"]=>
++  NULL
++}
++array(3) {
++  [0]=>
++  string(10) "2002-01-02"
++  [1]=>
++  string(8) "12:49:00"
++  [2]=>
++  NULL
++}
++array(3) {
++  ["c1"]=>
++  string(10) "2002-01-02"
++  ["c2"]=>
++  string(8) "12:49:00"
++  ["c3"]=>
++  NULL
++}
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_008.phpt
+@@ -0,0 +1,43 @@
++--TEST--
++sqlite-oo: fetch all (buffered)
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++$db->query("CREATE TABLE strings(a VARCHAR)");
++
++foreach ($data as $str) {
++      $db->query("INSERT INTO strings VALUES('$str')");
++}
++
++$r = $db->query("SELECT a from strings");
++while ($row = $r->fetch(SQLITE_NUM)) {
++      var_dump($row);
++}
++echo "DONE!\n";
++?>
++--EXPECT--
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_009.phpt
+@@ -0,0 +1,43 @@
++--TEST--
++sqlite-oo: fetch all (unbuffered)
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++$db->query("CREATE TABLE strings(a VARCHAR)");
++
++foreach ($data as $str) {
++      $db->query("INSERT INTO strings VALUES('$str')");
++}
++
++$r = $db->unbufferedQuery("SELECT a from strings");
++while ($row = $r->fetch(SQLITE_NUM)) {
++      var_dump($row);
++}
++echo "DONE!\n";
++?>
++--EXPECT--
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_010.phpt
+@@ -0,0 +1,44 @@
++--TEST--
++sqlite-oo: fetch all (iterator)
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++$db->query("CREATE TABLE strings(a VARCHAR)");
++
++foreach ($data as $str) {
++      $db->query("INSERT INTO strings VALUES('$str')");
++}
++
++$r = $db->unbufferedQuery("SELECT a from strings", SQLITE_NUM);
++while ($row = $r->valid()) {
++      var_dump($r->current());
++      $r->next();
++}
++echo "DONE!\n";
++?>
++--EXPECT--
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_011.phpt
+@@ -0,0 +1,33 @@
++--TEST--
++sqlite-oo: returned associative column names
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++$db->query("CREATE TABLE foo (c1 char, c2 char, c3 char)");
++$db->query("CREATE TABLE bar (c1 char, c2 char, c3 char)");
++$db->query("INSERT INTO foo VALUES ('1', '2', '3')");
++$db->query("INSERT INTO bar VALUES ('4', '5', '6')");
++$r = $db->query("SELECT * from foo, bar", SQLITE_ASSOC);
++var_dump($r->fetch());
++?>
++--EXPECT--
++array(6) {
++  ["foo.c1"]=>
++  string(1) "1"
++  ["foo.c2"]=>
++  string(1) "2"
++  ["foo.c3"]=>
++  string(1) "3"
++  ["bar.c1"]=>
++  string(1) "4"
++  ["bar.c2"]=>
++  string(1) "5"
++  ["bar.c3"]=>
++  string(1) "6"
++}
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_012.phpt
+@@ -0,0 +1,35 @@
++--TEST--
++sqlite-oo: read field names
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++$db->query("CREATE TABLE strings(foo VARCHAR, bar VARCHAR, baz VARCHAR)");
++
++echo "Buffered\n";
++$r = $db->query("SELECT * from strings");
++for($i=0; $i<$r->numFields(); $i++) {
++      var_dump($r->fieldName($i));
++}
++echo "Unbuffered\n";
++$r = $db->unbufferedQuery("SELECT * from strings");
++for($i=0; $i<$r->numFields(); $i++) {
++      var_dump($r->fieldName($i));
++}
++echo "DONE!\n";
++?>
++--EXPECT--
++Buffered
++string(3) "foo"
++string(3) "bar"
++string(3) "baz"
++Unbuffered
++string(3) "foo"
++string(3) "bar"
++string(3) "baz"
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_013.phpt
+@@ -0,0 +1,75 @@
++--TEST--
++sqlite-oo: fetch column
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++$data = array(
++      array (0 => 'one', 1 => 'two'),
++      array (0 => 'three', 1 => 'four')
++      );
++
++$db->query("CREATE TABLE strings(a VARCHAR, b VARCHAR)");
++
++foreach ($data as $str) {
++      $db->query("INSERT INTO strings VALUES('${str[0]}','${str[1]}')");
++}
++
++echo "====BUFFERED====\n";
++$r = $db->query("SELECT a, b from strings");
++while ($r->valid()) {
++      var_dump($r->current(SQLITE_NUM));
++      var_dump($r->column(0));
++      var_dump($r->column(1));
++      var_dump($r->column('a'));
++      var_dump($r->column('b'));
++      $r->next();
++}
++echo "====UNBUFFERED====\n";
++$r = $db->unbufferedQuery("SELECT a, b from strings");
++while ($r->valid()) {
++      var_dump($r->column(0));
++      var_dump($r->column('b'));
++      var_dump($r->column(1));
++      var_dump($r->column('a'));
++      $r->next();
++}
++echo "DONE!\n";
++?>
++--EXPECT--
++====BUFFERED====
++array(2) {
++  [0]=>
++  string(3) "one"
++  [1]=>
++  string(3) "two"
++}
++string(3) "one"
++string(3) "two"
++string(3) "one"
++string(3) "two"
++array(2) {
++  [0]=>
++  string(5) "three"
++  [1]=>
++  string(4) "four"
++}
++string(5) "three"
++string(4) "four"
++string(5) "three"
++string(4) "four"
++====UNBUFFERED====
++string(3) "one"
++string(3) "two"
++NULL
++NULL
++string(5) "three"
++string(4) "four"
++NULL
++NULL
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_014.phpt
+@@ -0,0 +1,118 @@
++--TEST--
++sqlite-oo: fetch all
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++$db->query("CREATE TABLE strings(a VARCHAR)");
++
++foreach ($data as $str) {
++      $db->query("INSERT INTO strings VALUES('$str')");
++}
++
++echo "unbuffered twice\n";
++$r = $db->unbufferedQuery("SELECT a from strings", SQLITE_NUM);
++var_dump($r->fetchAll());
++var_dump($r->fetchAll());
++
++echo "unbuffered with fetch_array\n";
++$r = $db->unbufferedQuery("SELECT a from strings", SQLITE_NUM);
++var_dump($r->fetch());
++var_dump($r->fetchAll());
++
++echo "buffered\n";
++$r = $db->query("SELECT a from strings", SQLITE_NUM);
++var_dump($r->fetchAll());
++var_dump($r->fetch());
++var_dump($r->fetchAll());
++
++echo "DONE!\n";
++?>
++--EXPECTF--
++unbuffered twice
++array(3) {
++  [0]=>
++  array(1) {
++    [0]=>
++    string(3) "one"
++  }
++  [1]=>
++  array(1) {
++    [0]=>
++    string(3) "two"
++  }
++  [2]=>
++  array(1) {
++    [0]=>
++    string(5) "three"
++  }
++}
++
++Warning: SQLiteUnbuffered::fetchAll(): One or more rowsets were already returned; returning NULL this time in %ssqlite_oo_014.php on line %d
++array(0) {
++}
++unbuffered with fetch_array
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++array(2) {
++  [0]=>
++  array(1) {
++    [0]=>
++    string(3) "two"
++  }
++  [1]=>
++  array(1) {
++    [0]=>
++    string(5) "three"
++  }
++}
++buffered
++array(3) {
++  [0]=>
++  array(1) {
++    [0]=>
++    string(3) "one"
++  }
++  [1]=>
++  array(1) {
++    [0]=>
++    string(3) "two"
++  }
++  [2]=>
++  array(1) {
++    [0]=>
++    string(5) "three"
++  }
++}
++bool(false)
++array(3) {
++  [0]=>
++  array(1) {
++    [0]=>
++    string(3) "one"
++  }
++  [1]=>
++  array(1) {
++    [0]=>
++    string(3) "two"
++  }
++  [2]=>
++  array(1) {
++    [0]=>
++    string(5) "three"
++  }
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_015.phpt
+@@ -0,0 +1,47 @@
++--TEST--
++sqlite-oo: array_query
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++$db->query("CREATE TABLE strings(a VARCHAR)");
++
++foreach ($data as $str) {
++      $db->query("INSERT INTO strings VALUES('$str')");
++}
++
++$res = $db->arrayQuery("SELECT a from strings", SQLITE_NUM);
++var_dump($res);
++
++echo "DONE!\n";
++?>
++--EXPECTF--
++array(3) {
++  [0]=>
++  array(1) {
++    [0]=>
++    string(3) "one"
++  }
++  [1]=>
++  array(1) {
++    [0]=>
++    string(3) "two"
++  }
++  [2]=>
++  array(1) {
++    [0]=>
++    string(5) "three"
++  }
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_016.phpt
+@@ -0,0 +1,42 @@
++--TEST--
++sqlite-oo: fetch single
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++$data = array(
++      array (0 => 'one', 1 => 'two'),
++      array (0 => 'three', 1 => 'four')
++      );
++
++$db->query("CREATE TABLE strings(a VARCHAR, b VARCHAR)");
++
++foreach ($data as $str) {
++      $db->query("INSERT INTO strings VALUES('${str[0]}','${str[1]}')");
++}
++
++echo "====BUFFERED====\n";
++$r = $db->query("SELECT a, b from strings");
++while ($r->valid()) {
++      var_dump($r->fetchSingle());
++}
++echo "====UNBUFFERED====\n";
++$r = $db->unbufferedQuery("SELECT a, b from strings");
++while ($r->valid()) {
++      var_dump($r->fetchSingle());
++}
++echo "DONE!\n";
++?>
++--EXPECT--
++====BUFFERED====
++string(3) "one"
++string(5) "three"
++====UNBUFFERED====
++string(3) "one"
++string(5) "three"
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_020.phpt
+@@ -0,0 +1,66 @@
++--TEST--
++sqlite-oo: factory and exception
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++$dbname = tempnam(dirname(__FILE__), "phpsql");
++function cleanup() {
++      global $db, $dbname;
++
++      $db = NULL;
++      unlink($dbname);
++}
++register_shutdown_function("cleanup");
++
++try {
++      $db = sqlite_factory();
++} catch(SQLiteException $err) {
++      echo "Message: ".$err->getMessage()."\n";
++      echo "File: ".$err->getFile()."\n";
++      //echo "Line: ".$err->getLine()."\n";
++      //print_r($err->getTrace());
++      //echo "BackTrace: ".$err->getTraceAsString()."\n";
++}
++
++$db = sqlite_factory($dbname);
++
++$data = array(
++      array (0 => 'one', 1 => 'two'),
++      array (0 => 'three', 1 => 'four')
++      );
++
++$db->query("CREATE TABLE strings(a VARCHAR, b VARCHAR)");
++
++foreach ($data as $str) {
++      $db->query("INSERT INTO strings VALUES('${str[0]}','${str[1]}')");
++}
++
++$r = $db->unbufferedQuery("SELECT a, b from strings");
++while ($r->valid()) {
++      var_dump($r->current(SQLITE_NUM));
++      $r->next();
++}
++$r = null;
++$db = null;
++echo "DONE!\n";
++?>
++--EXPECTF--
++Message: sqlite_factory() expects at least 1 parameter, 0 given
++File: %ssqlite_oo_020.php
++array(2) {
++  [0]=>
++  string(3) "one"
++  [1]=>
++  string(3) "two"
++}
++array(2) {
++  [0]=>
++  string(5) "three"
++  [1]=>
++  string(4) "four"
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_021.phpt
+@@ -0,0 +1,48 @@
++--TEST--
++sqlite-oo: single query
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++$db->query("CREATE TABLE test_db ( id INTEGER PRIMARY KEY, data VARCHAR(100) )");
++for ($i = 0; $i < 10; $i++) {
++      $db->query("INSERT INTO test_db (data) VALUES('{$i}data')");
++}
++$db->query("INSERT INTO test_db (data) VALUES(NULL)");
++
++var_dump($db->singleQuery("SELECT id FROM test_db WHERE id=5"));
++var_dump($db->singleQuery("SELECT * FROM test_db WHERE id=4"));
++var_dump($db->singleQuery("SELECT data FROM test_db WHERE id=6"));
++var_dump($db->singleQuery("SELECT * FROM test_db WHERE id < 5"));
++var_dump($db->singleQuery("SELECT * FROM test db WHERE id < 4"));
++var_dump($db->singleQuery("SELECT * FROM test_db WHERE id=999999"));
++var_dump($db->singleQuery("SELECT id FROM test_db WHERE id=5", FALSE));
++
++echo "DONE!\n";
++?>
++--EXPECTF--
++string(1) "5"
++string(1) "4"
++string(5) "5data"
++array(4) {
++  [0]=>
++  string(1) "1"
++  [1]=>
++  string(1) "2"
++  [2]=>
++  string(1) "3"
++  [3]=>
++  string(1) "4"
++}
++
++Warning: SQLiteDatabase::singleQuery(): no such table: test in %s on line %d
++bool(false)
++NULL
++array(1) {
++  [0]=>
++  string(1) "5"
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_022.phpt
+@@ -0,0 +1,98 @@
++--TEST--
++sqlite-oo: sqlite::seek
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++$db->query("CREATE TABLE strings(a)");
++
++foreach ($data as $str) {
++      $db->query("INSERT INTO strings VALUES('$str')");
++}
++
++$res = $db->query("SELECT a FROM strings", SQLITE_NUM);
++for ($idx = -1; $idx < 4; $idx++) {
++      echo "====SEEK:$idx====\n";
++      $res->seek($idx);
++      var_dump($res->current());
++}
++echo "====AGAIN====\n";
++for ($idx = -1; $idx < 4; $idx++) {
++      echo "====SEEK:$idx====\n";
++      $res->seek($idx);
++      var_dump($res->current());
++}
++echo "====DONE!====\n";
++?>
++--EXPECTF--
++====SEEK:-1====
++
++Warning: SQLiteResult::seek(): row -1 out of range in %ssqlite_oo_022.php on line %d
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++====SEEK:0====
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++====SEEK:1====
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++====SEEK:2====
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++====SEEK:3====
++
++Warning: SQLiteResult::seek(): row 3 out of range in %ssqlite_oo_022.php on line %d
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++====AGAIN====
++====SEEK:-1====
++
++Warning: SQLiteResult::seek(): row -1 out of range in %ssqlite_oo_022.php on line %d
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++====SEEK:0====
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++====SEEK:1====
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++====SEEK:2====
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++====SEEK:3====
++
++Warning: SQLiteResult::seek(): row 3 out of range in %ssqlite_oo_022.php on line %d
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++====DONE!====
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_024.phpt
+@@ -0,0 +1,74 @@
++--TEST--
++sqlite-oo: sqlite::fetch_object
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++class class24 {
++      function __construct() {
++              echo __METHOD__ . "\n";
++      }
++}
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++$db->query("CREATE TABLE strings(a)");
++
++foreach ($data as $str) {
++      $db->query("INSERT INTO strings VALUES('$str')");
++}
++
++echo "====class24====\n";
++$res = $db->query("SELECT a FROM strings", SQLITE_ASSOC);
++while ($res->valid()) {
++      var_dump($res->fetchObject('class24'));
++}
++
++echo "====stdclass====\n";
++$res = $db->query("SELECT a FROM strings", SQLITE_ASSOC);
++while ($res->valid()) {
++      var_dump($res->fetchObject());
++}
++
++echo "====DONE!====\n";
++?>
++--EXPECTF--
++====class24====
++class24::__construct
++object(class24)#%d (1) {
++  ["a"]=>
++  string(3) "one"
++}
++class24::__construct
++object(class24)#%d (1) {
++  ["a"]=>
++  string(3) "two"
++}
++class24::__construct
++object(class24)#%d (1) {
++  ["a"]=>
++  string(5) "three"
++}
++====stdclass====
++object(stdClass)#%d (1) {
++  ["a"]=>
++  string(3) "one"
++}
++object(stdClass)#%d (1) {
++  ["a"]=>
++  string(3) "two"
++}
++object(stdClass)#%d (1) {
++  ["a"]=>
++  string(5) "three"
++}
++====DONE!====
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_025.phpt
+@@ -0,0 +1,103 @@
++--TEST--
++sqlite-oo: sqlite / foreach
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; 
++?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++$db->query("CREATE TABLE strings(a VARCHAR)");
++
++foreach ($data as $str) {
++      $db->query("INSERT INTO strings VALUES('$str')");
++}
++
++echo "====UNBUFFERED====\n";
++$r = $db->unbufferedQuery("SELECT a from strings", SQLITE_NUM);
++//var_dump(class_implements($r));
++foreach($r as $row) {
++      var_dump($row);
++}
++echo "====NO-MORE====\n";
++foreach($r as $row) {
++      var_dump($row);
++}
++echo "====DIRECT====\n";
++foreach($db->unbufferedQuery("SELECT a from strings", SQLITE_NUM) as $row) {
++      var_dump($row);
++}
++echo "====BUFFERED====\n";
++$r = $db->query("SELECT a from strings", SQLITE_NUM);
++//var_dump(class_implements($r));
++foreach($r as $row) {
++      var_dump($row);
++}
++foreach($r as $row) {
++      var_dump($row);
++}
++echo "DONE!\n";
++?>
++--EXPECT--
++====UNBUFFERED====
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++====NO-MORE====
++====DIRECT====
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++====BUFFERED====
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++array(1) {
++  [0]=>
++  string(3) "one"
++}
++array(1) {
++  [0]=>
++  string(3) "two"
++}
++array(1) {
++  [0]=>
++  string(5) "three"
++}
++DONE!
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_026.phpt
+@@ -0,0 +1,56 @@
++--TEST--
++sqlite-oo: unbuffered
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; 
++?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++$data = array(
++      "one",
++      "two",
++      "three"
++      );
++
++$db->query("CREATE TABLE strings(a VARCHAR)");
++
++foreach ($data as $str) {
++      $db->query("INSERT INTO strings VALUES('$str')");
++}
++
++echo "====FOREACH====\n";
++$r = $db->unbufferedQuery("SELECT a from strings", SQLITE_NUM);
++foreach($r as $idx => $row) {
++      var_dump($row[0]);
++      var_dump($row[0]);
++}
++echo "====FOR====\n";
++$r = $db->unbufferedQuery("SELECT a from strings", SQLITE_NUM);
++for(;$r->valid(); $r->next()) {
++      $v = $r->column(0);
++      var_dump($v);
++      $c = $r->column(0);
++      var_dump(is_null($c) || $c==$v);
++}
++echo "===DONE===\n";
++?>
++--EXPECT--
++====FOREACH====
++string(3) "one"
++string(3) "one"
++string(3) "two"
++string(3) "two"
++string(5) "three"
++string(5) "three"
++====FOR====
++string(3) "one"
++bool(true)
++string(3) "two"
++bool(true)
++string(5) "three"
++bool(true)
++===DONE===
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_027.phpt
+@@ -0,0 +1,42 @@
++--TEST--
++sqlite-oo: changes
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; 
++?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++$data = array("one", "two", "three");
++
++$db->query("CREATE TABLE strings(a VARCHAR)");
++
++foreach ($data as $str) {
++      $db->query("INSERT INTO strings VALUES('$str')");
++      echo $db->changes() . "\n";
++}
++
++$db->query("UPDATE strings SET a='foo' WHERE a!='two'");
++echo $db->changes() . "\n";
++
++$db->query("DELETE FROM strings WHERE 1");
++echo $db->changes() . "\n";
++
++$str = '';
++foreach ($data as $s) {
++      $str .= "INSERT INTO strings VALUES('".$s."');";
++}
++$db->query($str);
++echo $db->changes() . "\n";
++
++?>
++--EXPECT--
++1
++1
++1
++2
++3
++3
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_028.phpt
+@@ -0,0 +1,25 @@
++--TEST--
++sqlite-oo: sqlite_fetch_column_types
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php 
++include "blankdb_oo.inc";
++
++$db->query("CREATE TABLE strings(a, b INTEGER, c VARCHAR(10), d)");
++$db->query("INSERT INTO strings VALUES('1', '2', '3', 'abc')");
++
++var_dump($db->fetchColumnTypes("strings"));
++?>
++--EXPECT--
++array(4) {
++  ["a"]=>
++  string(0) ""
++  ["b"]=>
++  string(7) "INTEGER"
++  ["c"]=>
++  string(11) "VARCHAR(10)"
++  ["d"]=>
++  string(0) ""
++}
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_029.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++sqlite-oo: call method with $this
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; 
++?>
++--FILE--
++<?php
++include "blankdb_oo.inc";
++
++$db->query("CREATE TABLE strings(key VARCHAR(10), var VARCHAR(10))");
++$db->query("INSERT INTO strings VALUES('foo', 'foo')");
++
++class sqlite_help
++{
++      function __construct($db){
++              $this->db = $db;
++              $this->db->createFunction('link_keywords', array(&$this, 'linkers'), 1);
++      }
++
++      function getSingle($key)
++      {
++              return $this->db->singleQuery('SELECT link_keywords(var) FROM strings WHERE key=\''.$key.'\'', 1);
++      }
++
++      function linkers($str)
++      {
++              $str = str_replace('foo', 'bar', $str);
++              return $str;
++      }
++
++      function free()
++      {
++              unset($this->db);
++      }
++
++      function __destruct()
++      {
++              echo "DESTRUCTED\n";
++      }
++}
++
++$obj = new sqlite_help($db);
++echo $obj->getSingle('foo')."\n";
++$obj->free();
++unset($obj);
++
++?>
++===DONE===
++--EXPECT--
++bar
++===DONE===
++DESTRUCTED
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_oo_030.phpt
+@@ -0,0 +1,44 @@
++--TEST--
++sqlite-oo: calling static methods
++--INI--
++sqlite.assoc_case=0
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; 
++?>
++--FILE--
++<?php
++
++require_once('blankdb_oo.inc'); 
++
++class foo {
++    static function bar($param = NULL) {
++              return $param;
++    }
++}
++
++function baz($param = NULL) {
++      return $param;
++}
++
++var_dump($db->singleQuery("select php('baz')", 1));
++var_dump($db->singleQuery("select php('baz', 1)", 1));
++var_dump($db->singleQuery("select php('baz', \"PHP\")", 1));
++var_dump($db->singleQuery("select php('foo::bar')", 1));
++var_dump($db->singleQuery("select php('foo::bar', 1)", 1));
++var_dump($db->singleQuery("select php('foo::bar', \"PHP\")", 1));
++var_dump($db->singleQuery("select php('foo::bar(\"PHP\")')", 1));
++
++?>
++===DONE===
++--EXPECTF--
++NULL
++string(1) "1"
++string(3) "PHP"
++NULL
++string(1) "1"
++string(3) "PHP"
++
++Warning: SQLiteDatabase::singleQuery(): function `foo::bar("PHP")' is not a function name in %ssqlite_oo_030.php on line %d
++bool(false)
++===DONE===
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_popen_basic.phpt
+@@ -0,0 +1,27 @@
++--TEST--
++SQLite: sqlite_popen() basic tests
++--SKIPIF--
++<?php if (!extension_loaded("sqlite")) print "skip"; ?>
++--FILE--
++<?php
++/* Prototype  : resource sqlite_popen(string filename [, int mode [, string &error_message]])
++ * Description: Opens a persistent handle to a SQLite database. Will create the database if it does not exist.
++ * Source code: ext/sqlite/sqlite.c
++ * Alias to functions:
++*/
++
++      $db1 = sqlite_popen(":memory:");
++      $db2 = sqlite_popen(":memory:");
++
++      var_dump($db1);
++      var_dump($db2);
++
++      list($resourceId1) = sscanf((string) $db1, "resource(%d) of type (sqlite database (persistent))");
++      list($resourceId2) = sscanf((string) $db2, "resource(%d) of type (sqlite database (persistent))");
++
++      var_dump($resourceId1 === $resourceId2);
++?>
++--EXPECTF--
++resource(%d) of type (sqlite database (persistent))
++resource(%d) of type (sqlite database (persistent))
++bool(true)
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_popen_error.phpt
+@@ -0,0 +1,34 @@
++--TEST--
++Test sqlite_popen() function : error conditions 
++--SKIPIF--
++<?php if (!extension_loaded("sqlite")) print "skip sqlite extension not loaded"; ?>
++--FILE--
++<?php
++/* Prototype  : resource sqlite_popen(string filename [, int mode [, string &error_message]])
++ * Description: Opens a persistent handle to a SQLite database. Will create the database if it does not exist. 
++ * Source code: ext/sqlite/sqlite.c
++ * Alias to functions: 
++ */
++
++$message = '';
++
++echo "*** Testing sqlite_popen() : error conditions ***\n";
++
++var_dump( sqlite_popen() );
++var_dump( sqlite_popen(":memory:", 0666, $message, 'foobar') );
++var_dump( sqlite_popen("", 0666, $message) );
++var_dump( $message );
++
++?>
++===DONE===
++--EXPECTF--
++*** Testing sqlite_popen() : error conditions ***
++
++Warning: sqlite_popen() expects at least 1 parameter, 0 given in %s on line %d
++NULL
++
++Warning: sqlite_popen() expects at most 3 parameters, 4 given in %s on line %d
++NULL
++bool(false)
++NULL
++===DONE===
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_session_001.phpt
+@@ -0,0 +1,46 @@
++--TEST--
++sqlite, session storage test
++--CREDITS--
++Mats Lindh <mats at lindh.no>
++#Testfest php.no
++--INI--
++session.save_handler = sqlite
++--SKIPIF--
++if (!extension_loaded("session"))
++{
++      die("skip Session module not loaded");
++}
++if (!extension_loaded("sqlite"))
++{
++      die("skip Session module not loaded");
++}
++--FILE--
++<?php
++/* Description: Tests that sqlite can be used as a session save handler
++* Source code: ext/sqlite/sess_sqlite.c
++*/
++
++ob_start();
++session_save_path(__DIR__ . "/sessiondb.sdb");
++
++// create the session and set a session value
++session_start();
++$_SESSION["test"] = "foo_bar";
++
++// close the session and unset the value
++session_write_close();
++unset($_SESSION["test"]);
++var_dump(isset($_SESSION["test"]));
++
++// start the session again and check that we have the proper value
++session_start();
++var_dump($_SESSION["test"]);
++ob_end_flush();
++?>
++--EXPECTF--
++bool(false)
++%unicode|string%(7) "foo_bar"
++--CLEAN--
++<?php
++      unlink(__DIR__ . "/sessiondb.sdb")
++?>
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_session_002.phpt
+@@ -0,0 +1,54 @@
++--TEST--
++sqlite, session destroy test
++--CREDITS--
++Mats Lindh <mats at lindh.no>
++#Testfest php.no
++--INI--
++session.save_handler = sqlite
++--SKIPIF--
++if (!extension_loaded("session"))
++{
++      die("skip Session module not loaded");
++}
++if (!extension_loaded("sqlite"))
++{
++      die("skip sqlite module not loaded");
++}
++--FILE--
++<?php
++/* Description: Tests that sqlite will destroy a session when used as a session handler
++* Source code: ext/sqlite/sess_sqlite.c
++*/
++ob_start();
++session_save_path(__DIR__ . "/sessiondb.sdb");
++
++// start a session and save a value to it before commiting the session to the database
++session_start();
++$_SESSION["test"] = "foo_bar";
++session_write_close();
++
++// remove the session value
++unset($_SESSION["test"]);
++var_dump(isset($_SESSION["test"]));
++
++// start the session again and destroy it
++session_start();
++var_dump($_SESSION["test"]);
++session_destroy();
++session_write_close();
++
++unset($_SESSION["test"]);
++
++// check that the session has been destroyed
++session_start();
++var_dump(isset($_SESSION["test"]));
++ob_end_flush();
++?>
++--EXPECTF--
++bool(false)
++%unicode|string%(7) "foo_bar"
++bool(false)
++--CLEAN--
++<?php
++      unlink(__DIR__ . "/sessiondb.sdb")
++?>
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_spl_001.phpt
+@@ -0,0 +1,125 @@
++--TEST--
++sqlite-spl: Iteration
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; 
++if (!extension_loaded("spl")) print "skip SPL is not present"; 
++?>
++--FILE--
++<?php
++include "blankdb_oo.inc";
++
++$db->query("CREATE TABLE menu(id_l int PRIMARY KEY, id_r int UNIQUE, key VARCHAR(10))");
++$db->query("INSERT INTO menu VALUES( 1, 12, 'A')"); 
++$db->query("INSERT INTO menu VALUES( 2,  9, 'B')"); 
++$db->query("INSERT INTO menu VALUES(10, 11, 'F')"); 
++$db->query("INSERT INTO menu VALUES( 3,  6, 'C')"); 
++$db->query("INSERT INTO menu VALUES( 7,  8, 'E')"); 
++$db->query("INSERT INTO menu VALUES( 4,  5, 'D')"); 
++
++class SqliteNestedsetElement
++{
++      protected $id_l;
++      protected $id_r;
++      protected $key;
++
++      function __construct($db)
++      {
++              $this->db = $db;
++      }
++      
++      function getLeft()
++      {
++              return $this->id_l;
++      }
++      
++      function getRight()
++      {
++              return $this->id_r;
++      }
++      
++      function __toString()
++      {
++              return $this->key;
++      }
++
++      function key()
++      {
++              return $this->key;
++      }
++}
++
++class SqliteNestedset implements RecursiveIterator
++{
++      protected $id;
++      protected $id_l;
++      protected $id_r;
++      protected $entry;
++
++      function __construct($db, $id_l = 1)
++      {
++              $this->db = $db;
++              $this->id_l = $id_l;
++              $this->id_r = $this->db->singleQuery('SELECT id_r FROM menu WHERE id_l='.$id_l, 1);
++              $this->id = $id_l;
++      }
++      
++      function rewind()
++      {
++              $this->id = $this->id_l;
++              $this->fetch();
++      }
++
++      function valid()
++      {
++              return is_object($this->entry);
++      }
++      
++      function current()
++      {
++              return $this->entry->__toString();
++      }
++      
++      function key()
++      {
++              return $this->entry->key();;
++      }
++      
++      function next()
++      {
++              $this->id = $this->entry->getRight() + 1;
++              $this->fetch();
++      }
++
++      protected function fetch()
++      {
++              $res = $this->db->unbufferedQuery('SELECT * FROM menu WHERE id_l='.$this->id);
++              $this->entry = $res->fetchObject('SqliteNestedsetElement', array(&$this->db));
++              unset($res);
++      }
++      
++      function hasChildren()
++      {
++              return $this->entry->getLeft() + 1 < $this->entry->getRight();
++      }
++      
++      function getChildren()
++      {
++              return new SqliteNestedset($this->db, $this->entry->getLeft() + 1, $this->entry->getRight() - 1);
++      }
++}
++
++$menu_iterator = new RecursiveIteratorIterator(new SqliteNestedset($db), RecursiveIteratorIterator::SELF_FIRST);
++foreach($menu_iterator as $entry) {
++      echo $menu_iterator->getDepth() . $entry . "\n";
++}
++?>
++===DONE===
++--EXPECT--
++0A
++1B
++2C
++3D
++2E
++1F
++===DONE===
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_spl_002.phpt
+@@ -0,0 +1,29 @@
++--TEST--
++sqlite-spl: Countable
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; 
++if (!extension_loaded("spl")) print "skip SPL is not present"; 
++?>
++--FILE--
++<?php
++include "blankdb_oo.inc";
++
++$db->query("CREATE TABLE menu(id_l int PRIMARY KEY, id_r int UNIQUE, key VARCHAR(10))");
++$db->query("INSERT INTO menu VALUES( 1, 12, 'A')"); 
++$db->query("INSERT INTO menu VALUES( 2,  9, 'B')"); 
++$db->query("INSERT INTO menu VALUES(10, 11, 'F')"); 
++$db->query("INSERT INTO menu VALUES( 3,  6, 'C')"); 
++$db->query("INSERT INTO menu VALUES( 7,  8, 'E')"); 
++$db->query("INSERT INTO menu VALUES( 4,  5, 'D')"); 
++
++$res = $db->query("SELECT * from menu");
++
++var_dump($res->count());
++var_dump(count($res));
++?>
++===DONE===
++--EXPECT--
++int(6)
++int(6)
++===DONE===
+--- /dev/null
++++ b/ext/sqlite/tests/sqlite_spl_003.phpt
+@@ -0,0 +1,28 @@
++--TEST--
++sqlite-spl: Exception
++--SKIPIF--
++<?php # vim:ft=php
++if (!extension_loaded("sqlite")) print "skip"; 
++if (!extension_loaded("spl")) print "skip SPL is not present"; 
++?>
++--FILE--
++<?php
++
++try
++{
++      $db = sqlite_factory();
++}
++catch(SQLiteException $e)
++{
++      $parents = class_parents($e);
++      if (array_key_exists('RuntimeException', $parents))
++      {
++              echo "GOOD\n";
++      }
++}
++
++?>
++===DONE===
++--EXPECT--
++GOOD
++===DONE===
+--- /dev/null
++++ b/ext/sqlite/TODO
+@@ -0,0 +1,19 @@
++- Implement a PDO driver, called sqlite2
++
++- Transparent binary encoding of return values from PHP callback functions.
++
++- Add user-space callback for the authorizer function (this is potentially
++  very slow, so it needs to be implemented carefully).
++
++- Add user-space callback to handle busy databases.
++
++  o Test how robust we are when a user-space function is registered as
++    a callback for a persistent connection in script A, then script B is
++      called that doesn't register the callback but does make use of the
++      function in an SQL query.
++      --> Our test suite doesn't allow us to test persistent connections
++          at this time :/
++
++- Use later version of built-in library
++
++vim:tw=78
diff --git a/lang/php5/patches/091-fix-sqlite2.patch b/lang/php5/patches/091-fix-sqlite2.patch
new file mode 100644 (file)
index 0000000..fcbfb23
--- /dev/null
@@ -0,0 +1,101 @@
+--- a/ext/sqlite/pdo_sqlite2.c
++++ b/ext/sqlite/pdo_sqlite2.c
+@@ -522,11 +522,6 @@ static char *make_filename_safe(const ch
+                       return NULL;
+               }
+-              if (PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
+-                      efree(fullpath);
+-                      return NULL;
+-              }
+-
+               if (php_check_open_basedir(fullpath TSRMLS_CC)) {
+                       efree(fullpath);
+                       return NULL;
+@@ -585,7 +580,7 @@ static int pdo_sqlite2_handle_factory(pd
+       if (!filename) {
+               zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC,
+-                              "safe_mode/open_basedir prohibits opening %s",
++                              "open_basedir prohibits opening %s",
+                               dbh->data_source);
+               goto cleanup;
+       }
+--- a/ext/sqlite/sqlite.c
++++ b/ext/sqlite/sqlite.c
+@@ -1066,10 +1066,6 @@ static int php_sqlite_authorizer(void *a
+               case SQLITE_COPY:
+                       if (strncmp(arg4, ":memory:", sizeof(":memory:") - 1)) {
+                               TSRMLS_FETCH();
+-                              if (PG(safe_mode) && (!php_checkuid(arg4, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
+-                                      return SQLITE_DENY;
+-                              }
+-
+                               if (php_check_open_basedir(arg4 TSRMLS_CC)) {
+                                       return SQLITE_DENY;
+                               }
+@@ -1079,10 +1075,6 @@ static int php_sqlite_authorizer(void *a
+               case SQLITE_ATTACH:
+                       if (strncmp(arg3, ":memory:", sizeof(":memory:") - 1)) {
+                               TSRMLS_FETCH();
+-                              if (PG(safe_mode) && (!php_checkuid(arg3, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
+-                                      return SQLITE_DENY;
+-                              }
+-
+                               if (php_check_open_basedir(arg3 TSRMLS_CC)) {
+                                       return SQLITE_DENY;
+                               }
+@@ -1160,13 +1152,12 @@ static void sqlite_object_free_storage(v
+ static void sqlite_object_new(zend_class_entry *class_type, zend_object_handlers *handlers, zend_object_value *retval TSRMLS_DC)
+ {
+       sqlite_object *intern;
+-      zval *tmp;
+       intern = emalloc(sizeof(sqlite_object));
+       memset(intern, 0, sizeof(sqlite_object));
+       zend_object_std_init(&intern->std, class_type TSRMLS_CC);
+-      zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
++      object_properties_init(&intern->std, class_type);
+       retval->handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) sqlite_object_free_storage, NULL TSRMLS_CC);
+       retval->handlers = handlers;
+@@ -1510,7 +1501,7 @@ static struct php_sqlite_db *php_sqlite_
+       /* authorizer hook so we can enforce safe mode
+        * Note: the declaration of php_sqlite_authorizer is correct for 2.8.2 of libsqlite,
+        * and IS backwards binary compatible with earlier versions */
+-      if (PG(safe_mode) || (PG(open_basedir) && *PG(open_basedir))) {
++      if (PG(open_basedir) && *PG(open_basedir)) {
+               sqlite_set_authorizer(sdb, php_sqlite_authorizer, NULL);
+       }
+@@ -1569,8 +1560,7 @@ PHP_FUNCTION(sqlite_popen)
+                       RETURN_FALSE;
+               }
+-              if ((PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || 
+-                              php_check_open_basedir(fullpath TSRMLS_CC)) {
++              if (php_check_open_basedir(fullpath TSRMLS_CC)) {
+                       efree(fullpath);
+                       RETURN_FALSE;
+               }
+@@ -1656,8 +1646,7 @@ PHP_FUNCTION(sqlite_open)
+                       }
+               }
+-              if ((PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) ||
+-                              php_check_open_basedir(fullpath TSRMLS_CC)) {
++              if (php_check_open_basedir(fullpath TSRMLS_CC)) {
+                       efree(fullpath);
+                       zend_restore_error_handling(&error_handling TSRMLS_CC);
+                       if (object) {
+@@ -1710,8 +1699,7 @@ PHP_FUNCTION(sqlite_factory)
+                       RETURN_NULL();
+               }
+-              if ((PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) ||
+-                              php_check_open_basedir(fullpath TSRMLS_CC)) {
++              if (php_check_open_basedir(fullpath TSRMLS_CC)) {
+                       efree(fullpath);
+                       zend_restore_error_handling(&error_handling TSRMLS_CC);
+                       RETURN_NULL();
diff --git a/lang/php5/patches/101-fix_membar_producer_link_error_gcc3x.patch b/lang/php5/patches/101-fix_membar_producer_link_error_gcc3x.patch
new file mode 100644 (file)
index 0000000..3e81dd6
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/ext/standard/php_crypt_r.c
++++ b/ext/standard/php_crypt_r.c
+@@ -96,6 +96,8 @@ void _crypt_extended_init_r(void)
+               InterlockedIncrement(&initialized);
+ #elif defined(HAVE_SYNC_FETCH_AND_ADD)
+               __sync_fetch_and_add(&initialized, 1);
++#elif (defined(__GNUC__) && (__GNUC__ == 3))
++              initialized = 1;
+ #elif defined(HAVE_ATOMIC_H) /* Solaris 10 defines atomic API within */
+               membar_producer();
+               atomic_add_int(&initialized, 1);
diff --git a/lang/php5/patches/102-debian_patches_use_embedded_timezonedb.patch b/lang/php5/patches/102-debian_patches_use_embedded_timezonedb.patch
new file mode 100644 (file)
index 0000000..438274a
--- /dev/null
@@ -0,0 +1,620 @@
+
+Add support for use of the system timezone database, rather
+than embedding a copy.  Discussed upstream but was not desired.
+
+History:
+r9: fix another compile error without --with-system-tzdata configured
+r8: fix compile error without --with-system-tzdata configured
+r7: improve check for valid timezone id to exclude directories
+r6: fix fd leak in r5, fix country code/BC flag use in 
+    timezone_identifiers_list() using system db,
+    fix use of PECL timezonedb to override system db,
+r5: reverts addition of "System/Localtime" fake tzname.
+    updated for 5.3.0, parses zone.tab to pick up mapping between
+    timezone name, country code and long/lat coords
+r4: added "System/Localtime" tzname which uses /etc/localtime
+r3: fix a crash if /usr/share/zoneinfo doesn't exist (Raphael Geissert)
+r2: add filesystem trawl to set up name alias index
+r1: initial revision
+
+--- a/ext/date/lib/parse_tz.c
++++ b/ext/date/lib/parse_tz.c
+@@ -20,6 +20,16 @@
+ #include "timelib.h"
++#ifdef HAVE_SYSTEM_TZDATA
++#include <sys/mman.h>
++#include <sys/stat.h>
++#include <limits.h>
++#include <fcntl.h>
++#include <unistd.h>
++
++#include "php_scandir.h"
++#endif
++
+ #include <stdio.h>
+ #ifdef HAVE_LOCALE_H
+@@ -31,7 +41,12 @@
+ #else
+ #include <strings.h>
+ #endif
++
++#ifndef HAVE_SYSTEM_TZDATA
+ #include "timezonedb.h"
++#endif
++
++#include <ctype.h>
+ #if (defined(__APPLE__) || defined(__APPLE_CC__)) && (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__))
+ # if defined(__LITTLE_ENDIAN__)
+@@ -51,9 +66,14 @@
+ static void read_preamble(const unsigned char **tzf, timelib_tzinfo *tz)
+ {
+-      /* skip ID */
+-      *tzf += 4;
+-      
++        if (memcmp(tzf, "TZif", 4) == 0) {
++                *tzf += 20;
++                return;
++        }
++        
++        /* skip ID */
++        *tzf += 4;
++                
+       /* read BC flag */
+       tz->bc = (**tzf == '\1');
+       *tzf += 1;
+@@ -256,7 +276,397 @@ void timelib_dump_tzinfo(timelib_tzinfo
+       }
+ }
+-static int seek_to_tz_position(const unsigned char **tzf, char *timezone, const timelib_tzdb *tzdb)
++#ifdef HAVE_SYSTEM_TZDATA
++
++#ifdef HAVE_SYSTEM_TZDATA_PREFIX
++#define ZONEINFO_PREFIX HAVE_SYSTEM_TZDATA_PREFIX
++#else
++#define ZONEINFO_PREFIX "/usr/share/zoneinfo"
++#endif
++
++/* System timezone database pointer. */
++static const timelib_tzdb *timezonedb_system = NULL;
++
++/* Hash table entry for the cache of the zone.tab mapping table. */
++struct location_info {
++        char code[2];
++        double latitude, longitude;
++        char name[64];
++        char *comment;
++        struct location_info *next;
++};
++
++/* Cache of zone.tab. */
++static struct location_info **system_location_table;
++
++/* Size of the zone.tab hash table; a random-ish prime big enough to
++ * prevent too many collisions. */
++#define LOCINFO_HASH_SIZE (1021)
++
++static uint32_t tz_hash(const char *str)
++{
++    const unsigned char *p = (const unsigned char *)str;
++    uint32_t hash = 5381;
++    int c;
++    
++    while ((c = *p++) != '\0') {
++        hash = (hash << 5) ^ hash ^ c;
++    }
++    
++    return hash % LOCINFO_HASH_SIZE;
++}
++
++/* Parse an ISO-6709 date as used in zone.tab. Returns end of the
++ * parsed string on success, or NULL on parse error.  On success,
++ * writes the parsed number to *result. */
++static char *parse_iso6709(char *p, double *result)
++{
++    double v, sign;
++    char *pend;
++    size_t len;
++
++    if (*p == '+')
++        sign = 1.0;
++    else if (*p == '-')
++        sign = -1.0;
++    else
++        return NULL;
++
++    p++;
++    for (pend = p; *pend >= '0' && *pend <= '9'; pend++)
++        ;;
++
++    /* Annoying encoding used by zone.tab has no decimal point, so use
++     * the length to determine the format:
++     * 
++     * 4 = DDMM
++     * 5 = DDDMM
++     * 6 = DDMMSS
++     * 7 = DDDMMSS
++     */
++    len = pend - p;
++    if (len < 4 || len > 7) {
++        return NULL;
++    }
++
++    /* p => [D]DD */
++    v = (p[0] - '0') * 10.0 + (p[1] - '0');
++    p += 2;
++    if (len == 5 || len == 7)
++        v = v * 10.0 + (*p++ - '0');
++    /* p => MM[SS] */
++    v += (10.0 * (p[0] - '0')
++          + p[1] - '0') / 60.0;
++    p += 2;
++    /* p => [SS] */
++    if (len > 5) {
++        v += (10.0 * (p[0] - '0')
++              + p[1] - '0') / 3600.0;
++        p += 2;
++    }
++
++    /* Round to five decimal place, not because it's a good idea,
++     * but, because the builtin data uses rounded data, so, match
++     * that. */
++    *result = round(v * sign * 100000.0) / 100000.0;
++
++    return p;
++}
++
++/* This function parses the zone.tab file to build up the mapping of
++ * timezone to country code and geographic location, and returns a
++ * hash table.  The hash table is indexed by the function:
++ *
++ *   tz_hash(timezone-name)
++ */
++static struct location_info **create_location_table(void)
++{
++    struct location_info **li, *i;
++    char zone_tab[PATH_MAX];
++    char line[512];
++    FILE *fp;
++
++    strncpy(zone_tab, ZONEINFO_PREFIX "/zone.tab", sizeof zone_tab);
++
++    fp = fopen(zone_tab, "r");
++    if (!fp) {
++        return NULL;
++    }
++
++    li = calloc(LOCINFO_HASH_SIZE, sizeof *li);
++
++    while (fgets(line, sizeof line, fp)) {
++        char *p = line, *code, *name, *comment;
++        uint32_t hash;
++        double latitude, longitude;
++
++        while (isspace(*p))
++            p++;
++
++        if (*p == '#' || *p == '\0' || *p == '\n')
++            continue;
++        
++        if (!isalpha(p[0]) || !isalpha(p[1]) || p[2] != '\t')
++            continue;
++        
++        /* code => AA */
++        code = p;
++        p[2] = 0;
++        p += 3;
++
++        /* coords => [+-][D]DDMM[SS][+-][D]DDMM[SS] */
++        p = parse_iso6709(p, &latitude);
++        if (!p) {
++            continue;
++        }
++        p = parse_iso6709(p, &longitude);
++        if (!p) {
++            continue;
++        }
++
++        if (!p || *p != '\t') {
++            continue;
++        }
++
++        /* name = string */
++        name = ++p;
++        while (*p != '\t' && *p && *p != '\n')
++            p++;
++
++        *p++ = '\0';
++
++        /* comment = string */
++        comment = p;
++        while (*p != '\t' && *p && *p != '\n')
++            p++;
++
++        if (*p == '\n' || *p == '\t')
++            *p = '\0';
++        
++        hash = tz_hash(name);
++        i = malloc(sizeof *i);
++        memcpy(i->code, code, 2);
++        strncpy(i->name, name, sizeof i->name);
++        i->comment = strdup(comment);
++        i->longitude = longitude;
++        i->latitude = latitude;
++        i->next = li[hash];
++        li[hash] = i;
++        /* printf("%s [%u, %f, %f]\n", name, hash, latitude, longitude); */
++    }
++
++    fclose(fp);
++
++    return li;
++}
++
++/* Return location info from hash table, using given timezone name.
++ * Returns NULL if the name could not be found. */
++const struct location_info *find_zone_info(struct location_info **li, 
++                                           const char *name)
++{
++    uint32_t hash = tz_hash(name);
++    const struct location_info *l;
++
++    if (!li) {
++        return NULL;
++    }
++
++    for (l = li[hash]; l; l = l->next) {
++        if (strcasecmp(l->name, name) == 0)
++            return l;
++    }
++
++    return NULL;
++}    
++
++/* Filter out some non-tzdata files and the posix/right databases, if
++ * present. */
++static int index_filter(const struct dirent *ent)
++{
++      return strcmp(ent->d_name, ".") != 0
++              && strcmp(ent->d_name, "..") != 0
++              && strcmp(ent->d_name, "posix") != 0
++              && strcmp(ent->d_name, "posixrules") != 0
++              && strcmp(ent->d_name, "right") != 0
++              && strstr(ent->d_name, ".tab") == NULL;
++}
++
++static int sysdbcmp(const void *first, const void *second)
++{
++        const timelib_tzdb_index_entry *alpha = first, *beta = second;
++
++        return strcmp(alpha->id, beta->id);
++}
++
++
++/* Create the zone identifier index by trawling the filesystem. */
++static void create_zone_index(timelib_tzdb *db)
++{
++      size_t dirstack_size,  dirstack_top;
++      size_t index_size, index_next;
++      timelib_tzdb_index_entry *db_index;
++      char **dirstack;
++
++      /* LIFO stack to hold directory entries to scan; each slot is a
++       * directory name relative to the zoneinfo prefix. */
++      dirstack_size = 32;
++      dirstack = malloc(dirstack_size * sizeof *dirstack);
++      dirstack_top = 1;
++      dirstack[0] = strdup("");
++      
++      /* Index array. */
++      index_size = 64;
++      db_index = malloc(index_size * sizeof *db_index);
++      index_next = 0;
++
++      do {
++              struct dirent **ents;
++              char name[PATH_MAX], *top;
++              int count;
++
++              /* Pop the top stack entry, and iterate through its contents. */
++              top = dirstack[--dirstack_top];
++              snprintf(name, sizeof name, ZONEINFO_PREFIX "/%s", top);
++
++              count = php_scandir(name, &ents, index_filter, php_alphasort);
++
++              while (count > 0) {
++                      struct stat st;
++                      const char *leaf = ents[count - 1]->d_name;
++
++                      snprintf(name, sizeof name, ZONEINFO_PREFIX "/%s/%s", 
++                               top, leaf);
++                      
++                      if (strlen(name) && stat(name, &st) == 0) {
++                              /* Name, relative to the zoneinfo prefix. */
++                              const char *root = top;
++
++                              if (root[0] == '/') root++;
++
++                              snprintf(name, sizeof name, "%s%s%s", root, 
++                                       *root ? "/": "", leaf);
++
++                              if (S_ISDIR(st.st_mode)) {
++                                      if (dirstack_top == dirstack_size) {
++                                              dirstack_size *= 2;
++                                              dirstack = realloc(dirstack, 
++                                                                 dirstack_size * sizeof *dirstack);
++                                      }
++                                      dirstack[dirstack_top++] = strdup(name);
++                              }
++                              else {
++                                      if (index_next == index_size) {
++                                              index_size *= 2;
++                                              db_index = realloc(db_index,
++                                                                 index_size * sizeof *db_index);
++                                      }
++
++                                      db_index[index_next++].id = strdup(name);
++                              }
++                      }
++
++                      free(ents[--count]);
++              }
++              
++              if (count != -1) free(ents);
++              free(top);
++      } while (dirstack_top);
++
++        qsort(db_index, index_next, sizeof *db_index, sysdbcmp);
++
++      db->index = db_index;
++      db->index_size = index_next;
++
++      free(dirstack);
++}
++
++#define FAKE_HEADER "1234\0??\1??"
++#define FAKE_UTC_POS (7 - 4)
++
++/* Create a fake data segment for database 'sysdb'. */
++static void fake_data_segment(timelib_tzdb *sysdb,
++                              struct location_info **info)
++{
++        size_t n;
++        char *data, *p;
++        
++        data = malloc(3 * sysdb->index_size + 7);
++
++        p = mempcpy(data, FAKE_HEADER, sizeof(FAKE_HEADER) - 1);
++
++        for (n = 0; n < sysdb->index_size; n++) {
++                const struct location_info *li;
++                timelib_tzdb_index_entry *ent;
++
++                ent = (timelib_tzdb_index_entry *)&sysdb->index[n];
++
++                /* Lookup the timezone name in the hash table. */
++                if (strcmp(ent->id, "UTC") == 0) {
++                        ent->pos = FAKE_UTC_POS;
++                        continue;
++                }
++
++                li = find_zone_info(info, ent->id);
++                if (li) {
++                        /* If found, append the BC byte and the
++                         * country code; set the position for this
++                         * section of timezone data.  */
++                        ent->pos = (p - data) - 4;
++                        *p++ = '\1';
++                        *p++ = li->code[0];
++                        *p++ = li->code[1];
++                }
++                else {
++                        /* If not found, the timezone data can
++                         * point at the header. */
++                        ent->pos = 0;
++                }
++        }
++        
++        sysdb->data = (unsigned char *)data;
++}
++
++/* Returns true if the passed-in stat structure describes a
++ * probably-valid timezone file. */
++static int is_valid_tzfile(const struct stat *st)
++{
++      return S_ISREG(st->st_mode) && st->st_size > 20;
++}
++
++/* Return the mmap()ed tzfile if found, else NULL.  On success, the
++ * length of the mapped data is placed in *length. */
++static char *map_tzfile(const char *timezone, size_t *length)
++{
++      char fname[PATH_MAX];
++      struct stat st;
++      char *p;
++      int fd;
++      
++      if (timezone[0] == '\0' || strstr(timezone, "..") != NULL) {
++              return NULL;
++      }
++
++      snprintf(fname, sizeof fname, ZONEINFO_PREFIX "/%s", timezone);
++      
++      fd = open(fname, O_RDONLY);
++      if (fd == -1) {
++              return NULL;
++      } else if (fstat(fd, &st) != 0 || !is_valid_tzfile(&st)) {
++              close(fd);
++              return NULL;
++      }
++
++      *length = st.st_size;
++      p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
++      close(fd);
++      
++      return p != MAP_FAILED ? p : NULL;
++}
++
++#endif
++
++static int inmem_seek_to_tz_position(const unsigned char **tzf, char *timezone, const timelib_tzdb *tzdb)
+ {
+       int left = 0, right = tzdb->index_size - 1;
+ #ifdef HAVE_SETLOCALE
+@@ -295,36 +705,128 @@ static int seek_to_tz_position(const uns
+       return 0;
+ }
++static int seek_to_tz_position(const unsigned char **tzf, char *timezone, 
++                             char **map, size_t *maplen,
++                             const timelib_tzdb *tzdb)
++{
++#ifdef HAVE_SYSTEM_TZDATA
++      if (tzdb == timezonedb_system) {
++              char *orig;
++
++              orig = map_tzfile(timezone, maplen);
++              if (orig == NULL) {
++                      return 0;
++              }
++              
++              (*tzf) = (unsigned char *)orig ;
++              *map = orig;
++                
++                return 1;
++      }
++      else
++#endif
++      {
++              return inmem_seek_to_tz_position(tzf, timezone, tzdb);
++      }
++}
++
+ const timelib_tzdb *timelib_builtin_db(void)
+ {
++#ifdef HAVE_SYSTEM_TZDATA
++      if (timezonedb_system == NULL) {
++              timelib_tzdb *tmp = malloc(sizeof *tmp);
++
++              tmp->version = "0.system";
++              tmp->data = NULL;
++              create_zone_index(tmp);
++              system_location_table = create_location_table();
++                fake_data_segment(tmp, system_location_table);
++              timezonedb_system = tmp;
++      }
++
++                      
++      return timezonedb_system;
++#else
+       return &timezonedb_builtin;
++#endif
+ }
+ const timelib_tzdb_index_entry *timelib_timezone_builtin_identifiers_list(int *count)
+ {
++#ifdef HAVE_SYSTEM_TZDATA
++      *count = timezonedb_system->index_size;
++      return timezonedb_system->index;
++#else
+       *count = sizeof(timezonedb_idx_builtin) / sizeof(*timezonedb_idx_builtin);
+       return timezonedb_idx_builtin;
++#endif
+ }
+ int timelib_timezone_id_is_valid(char *timezone, const timelib_tzdb *tzdb)
+ {
+       const unsigned char *tzf;
+-      return (seek_to_tz_position(&tzf, timezone, tzdb));
++
++#ifdef HAVE_SYSTEM_TZDATA
++        if (tzdb == timezonedb_system) {
++            char fname[PATH_MAX];
++            struct stat st;
++
++            if (timezone[0] == '\0' || strstr(timezone, "..") != NULL) {
++              return 0;
++            }
++            
++            snprintf(fname, sizeof fname, ZONEINFO_PREFIX "/%s", timezone);
++            
++            return stat(fname, &st) == 0 && is_valid_tzfile(&st);
++        }
++#endif
++
++      return (inmem_seek_to_tz_position(&tzf, timezone, tzdb));
+ }
+ timelib_tzinfo *timelib_parse_tzfile(char *timezone, const timelib_tzdb *tzdb)
+ {
+       const unsigned char *tzf;
++      char *memmap = NULL;
++      size_t maplen;
+       timelib_tzinfo *tmp;
+-      if (seek_to_tz_position(&tzf, timezone, tzdb)) {
++      if (seek_to_tz_position(&tzf, timezone, &memmap, &maplen, tzdb)) {
+               tmp = timelib_tzinfo_ctor(timezone);
+               read_preamble(&tzf, tmp);
+               read_header(&tzf, tmp);
+               read_transistions(&tzf, tmp);
+               read_types(&tzf, tmp);
+-              read_location(&tzf, tmp);
++
++#ifdef HAVE_SYSTEM_TZDATA
++              if (memmap) {
++                      const struct location_info *li;
++
++                      /* TZif-style - grok the location info from the system database,
++                       * if possible. */
++
++                      if ((li = find_zone_info(system_location_table, timezone)) != NULL) {
++                              tmp->location.comments = strdup(li->comment);
++                                strncpy(tmp->location.country_code, li->code, 2);
++                              tmp->location.longitude = li->longitude;
++                              tmp->location.latitude = li->latitude;
++                              tmp->bc = 1;
++                      }
++                      else {
++                              strcpy(tmp->location.country_code, "??");
++                              tmp->bc = 0;
++                              tmp->location.comments = strdup("");
++                      }
++
++                      /* Now done with the mmap segment - discard it. */
++                      munmap(memmap, maplen);
++              } else
++#endif
++              {
++                      /* PHP-style - use the embedded info. */
++                      read_location(&tzf, tmp);
++              }
+       } else {
+               tmp = NULL;
+       }
+--- a/ext/date/lib/timelib.m4
++++ b/ext/date/lib/timelib.m4
+@@ -78,3 +78,17 @@ stdlib.h
+ dnl Check for strtoll, atoll
+ AC_CHECK_FUNCS(strtoll atoll strftime)
++
++PHP_ARG_WITH(system-tzdata, for use of system timezone data,
++[  --with-system-tzdata[=DIR]      to specify use of system timezone data],
++no, no)
++
++if test "$PHP_SYSTEM_TZDATA" != "no"; then
++   AC_DEFINE(HAVE_SYSTEM_TZDATA, 1, [Define if system timezone data is used])
++
++   if test "$PHP_SYSTEM_TZDATA" != "yes"; then
++      AC_DEFINE_UNQUOTED(HAVE_SYSTEM_TZDATA_PREFIX, "$PHP_SYSTEM_TZDATA",
++                         [Define for location of system timezone data])
++   fi
++fi
++
diff --git a/lang/php5/patches/103-debian_patches_use_embedded_timezonedb.patch b/lang/php5/patches/103-debian_patches_use_embedded_timezonedb.patch
new file mode 100644 (file)
index 0000000..ae8d182
--- /dev/null
@@ -0,0 +1,19 @@
+Author: Sean Finney <seanius@debian.org>
+Forwarded: no (upstream doesn't want it)
+Description: Silence warnings about using the default system timezone info
+ In vanilla upstream php, this is considered an error (i.e. the user must
+ set the timezone explicitly), though with our use of the system timezonedb
+ patch, we actually feel quite comfortable using the default timezone info.
+Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=571762
+--- a/ext/date/tests/date_default_timezone_set-1.phpt
++++ b/ext/date/tests/date_default_timezone_set-1.phpt
+@@ -22,9 +22,6 @@ date.timezone=
+       echo date(DATE_ISO8601, $date4), "\n";
+ ?>
+ --EXPECTF--
+-Warning: strtotime(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in %sdate_default_timezone_set-1.php on line 3
+-
+-Warning: strtotime(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in %sdate_default_timezone_set-1.php on line 4
+ America/Indiana/Knox
+ 2005-01-12T03:00:00-0500
+ 2005-07-12T03:00:00-0500
diff --git a/lang/php5/patches/950-Fix-dl-cross-compiling-issue.patch b/lang/php5/patches/950-Fix-dl-cross-compiling-issue.patch
new file mode 100644 (file)
index 0000000..216a518
--- /dev/null
@@ -0,0 +1,14 @@
+--- a/configure.in
++++ b/configure.in
+@@ -453,7 +453,10 @@ PHP_CHECK_FUNC(gethostname, nsl)
+ PHP_CHECK_FUNC(gethostbyaddr, nsl)
+ PHP_CHECK_FUNC(yp_get_default_domain, nsl)
+-PHP_CHECK_FUNC(dlopen, dl)
++PHP_ADD_LIBRARY(dl)
++PHP_DEF_HAVE(dlopen)
++PHP_DEF_HAVE(libdl)
++ac_cv_func_dlopen=yes
+ if test "$ac_cv_func_dlopen" = "yes"; then
+   AC_DEFINE(HAVE_LIBDL, 1, [ ])
+ fi
diff --git a/lang/php5/pecl.mk b/lang/php5/pecl.mk
new file mode 100644 (file)
index 0000000..e1b9819
--- /dev/null
@@ -0,0 +1,47 @@
+#
+# Copyright (C) 2011-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Package/php5-pecl/Default
+  SUBMENU:=PHP
+  SECTION:=lang
+  CATEGORY:=Languages
+  URL:=http://pecl.php.net/
+  MAINTAINER:=Michael Heimpold <mhei@heimpold.de>
+  DEPENDS:=php5
+endef
+
+define Build/Configure
+       ( cd $(PKG_BUILD_DIR); $(STAGING_DIR_HOST)/usr/bin/phpize )
+       $(Build/Configure/Default)
+endef
+
+CONFIGURE_ARGS+= \
+       --with-php-config=$(STAGING_DIR_HOST)/usr/bin/php-config
+
+define PECLPackage
+
+  define Package/php5-pecl-$(1)
+    $(call Package/php5-pecl/Default)
+    TITLE:=$(2)
+
+    ifneq ($(3),)
+      DEPENDS+=$(3)
+    endif
+  endef
+
+  define Package/php5-pecl-$(1)/install
+       $(INSTALL_DIR) $$(1)/usr/lib/php
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/modules/$(subst -,_,$(1)).so $$(1)/usr/lib/php/
+       $(INSTALL_DIR) $$(1)/etc/php5
+    ifeq ($(4),zend)
+       echo "zend_extension=/usr/lib/php/$(subst -,_,$(1)).so" > $$(1)/etc/php5/$(subst -,_,$(1)).ini
+    else
+       echo "extension=$(subst -,_,$(1)).so" > $$(1)/etc/php5/$(subst -,_,$(1)).ini
+    endif
+  endef
+
+endef