taskwarrior: moved to github
taskwarrior: moved to github

Signed-off-by: Luka Perkov <luka@openwrt.org>

git-svn-id: svn://svn.openwrt.org/openwrt/packages@43822 3c298f89-4303-0410-b956-a3cf2f4a3e73

file:a/admin/sudo/Makefile (deleted)
#  
# Copyright (C) 2006-2011 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:=sudo  
PKG_VERSION:=1.7.10p8  
PKG_RELEASE:=1  
 
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz  
PKG_SOURCE_URL:=http://www.sudo.ws/sudo/dist  
PKG_MD5SUM:=4620e31c28b387dd9582dfd42e930cfb  
 
PKG_INSTALL:=1  
 
include $(INCLUDE_DIR)/package.mk  
 
define Package/sudo  
SECTION:=admin  
CATEGORY:=Administration  
TITLE:=Delegate authority to run commands  
URL:=http://www.sudo.ws/  
endef  
 
define Package/sudo/description  
Sudo (su "do") allows a system administrator to delegate authority to  
give certain users (or groups of users) the ability to run some (or  
all) commands as root or another user while providing an audit trail of  
the commands and their arguments.  
endef  
 
define Package/sudo/conffiles  
/etc/sudoers  
endef  
 
CONFIGURE_ARGS+= \  
--without-pam \  
--disable-pam-session \  
--with-editor=/bin/vi \  
--without-lecture \  
--disable-zlib  
 
CONFIGURE_VARS+= \  
sudo_cv_uid_t_len=10 \  
sudo_cv_func_unsetenv_void=no  
 
define Package/sudo/install  
$(INSTALL_DIR) $(1)/usr/bin  
$(CP) $(PKG_INSTALL_DIR)/usr/bin/sudo $(1)/usr/bin/  
chmod 4755 $(1)/usr/bin/sudo  
$(INSTALL_DIR) $(1)/usr/sbin  
$(CP) $(PKG_INSTALL_DIR)/usr/sbin/visudo $(1)/usr/sbin/  
$(INSTALL_DIR) $(1)/etc  
$(CP) $(PKG_INSTALL_DIR)/etc/sudoers $(1)/etc/  
chmod 0440 $(1)/etc/sudoers  
$(INSTALL_DIR) $(1)/etc/sudoers.d  
$(INSTALL_DIR) $(1)/usr/lib  
$(CP) $(PKG_INSTALL_DIR)/usr/lib/sudo_noexec.so $(1)/usr/lib/  
$(INSTALL_DIR) $(1)/etc/init.d  
$(INSTALL_BIN) ./files/sudo.init $(1)/etc/init.d/sudo  
endef  
 
define Package/sudo/postinst  
#!/bin/sh  
 
[ -n "$$IPKG_INSTROOT" ] || {  
/etc/init.d/sudo enable  
/etc/init.d/sudo start  
}  
endef  
 
$(eval $(call BuildPackage,sudo))  
 
#!/bin/sh /etc/rc.common  
# Copyright (C) 2011 OpenWrt.org  
 
START=99  
 
start() {  
[ -d /var/lib/sudo ] || {  
mkdir -m 0755 -p /var/lib/sudo  
chmod 0700 /var/lib/sudo  
}  
}  
 
#  
# Copyright (C) 2008-2012 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:=diffutils  
PKG_VERSION:=3.0  
PKG_RELEASE:=3  
 
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz  
PKG_SOURCE_URL:=@GNU/diffutils  
PKG_MD5SUM:=684aaba1baab743a2a90e52162ff07da  
 
PKG_INSTALL:=1  
 
include $(INCLUDE_DIR)/package.mk  
 
define Package/diffutils  
SECTION:=devel  
CATEGORY:=Development  
DEPENDS:=+USE_EGLIBC:librt  
TITLE:=diffutils  
URL:=http://www.gnu.org/software/diffutils/  
endef  
 
define Package/diffutils/description  
The Diffutils package contains programs that show the differences between  
files or directories.  
endef  
 
CONFIGURE_VARS += \  
ac_cv_func_mempcpy=n \  
 
define Package/diffutils/install  
$(INSTALL_DIR) $(1)/usr/bin  
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/{sdiff,diff3,diff,cmp} $(1)/usr/bin/  
endef  
 
define Package/diffutils/preinst  
#!/bin/sh  
for x in sdiff diff3 diff cmp; do  
[ -L "$${IPKG_INSTROOT}/usr/bin/$$x" ] && rm -f "$${IPKG_INSTROOT}/usr/bin/$$x"  
done  
exit 0  
endef  
 
define Package/diffutils/postrm  
#!/bin/sh  
for x in sdiff diff3 diff cmp; do  
/bin/busybox $$x -h 2>&1 | grep -q BusyBox && ln -sf ../../bin/busybox /usr/bin/$$x  
done  
exit 0  
endef  
 
$(eval $(call BuildPackage,diffutils))  
 
file:a/devel/perf/Makefile (deleted)
#  
# Copyright (C) 2011-2013 OpenWrt.org  
#  
# This is free software, licensed under the GNU General Public License v2.  
# See /LICENSE for more information.  
#  
 
include $(TOPDIR)/rules.mk  
include $(INCLUDE_DIR)/kernel.mk  
 
PKG_NAME:=perf  
PKG_VERSION:=$(LINUX_VERSION)  
PKG_RELEASE:=2  
 
PKG_USE_MIPS16:=0  
 
include $(INCLUDE_DIR)/package.mk  
 
define Package/perf  
SECTION:=devel  
CATEGORY:=Development  
DEPENDS:= +libelf1 +libdw +libpthread +librt +binutils  
TITLE:=Linux performance monitoring tool  
VERSION:=$(LINUX_VERSION)-$(PKG_RELEASE)  
URL:=http://www.kernel.org  
endef  
 
define Package/perf/description  
perf is the Linux performance monitoring tool  
endef  
 
# Perf's makefile and headers are not relocatable and must be built from the  
# Linux sources directory  
define Build/Prepare  
$(RM) -r $(PKG_BUILD_DIR)  
ln -s $(LINUX_DIR)/tools/perf $(PKG_BUILD_DIR)  
endef  
 
# MAKE_FLAGS should be passed again upon cleaning because Perf's makefile  
# always performs checks before processing any rule  
define Build/Clean  
-$(MAKE) -C $(PKG_BUILD_DIR) \  
NO_DWARF=1 \  
$(MAKE_FLAGS) \  
clean  
endef  
 
MAKE_FLAGS = \  
ARCH="$(LINUX_KARCH)" \  
NO_LIBPERL=1 \  
NO_LIBPYTHON=1 \  
NO_NEWT=1 \  
CROSS_COMPILE="$(TARGET_CROSS)" \  
CC="$(TARGET_CC)" \  
LD="$(TARGET_CROSS)ld" \  
CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \  
LDFLAGS="$(TARGET_LDFLAGS)" \  
V=1 \  
prefix=/usr  
 
define Package/perf/install  
$(INSTALL_DIR) $(1)/usr/bin  
$(INSTALL_BIN) $(LINUX_DIR)/tools/perf/perf $(1)/usr/bin/  
endef  
 
$(eval $(call BuildPackage,perf))  
 
file:a/lang/luasoap/Makefile (deleted)
#  
# Copyright (C) 2011 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:=luasoap  
PKG_VERSION:=2.0.2  
PKG_RELEASE:=2  
 
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz  
PKG_SOURCE_URL:=https://github.com/downloads/tomasguisasola/luasoap/  
PKG_MD5SUM:=3aafa06f3a65e65f4ee08e12b89ec583  
 
include $(INCLUDE_DIR)/package.mk  
 
define Package/luasoap  
SUBMENU:=Lua  
SECTION:=lang  
CATEGORY:=Languages  
TITLE:=LuaSOAP  
URL:=https://github.com/tomasguisasola/luasoap  
DEPENDS:=+lua +luaexpat +luasec +luasocket  
endef  
 
define Package/luasoap/description  
LuaSOAP is a library of functions to deal with SOAP.  
endef  
 
define Build/Configure  
endef  
 
define Build/Compile  
endef  
 
define Package/luasoap/install  
$(INSTALL_DIR) $(1)/usr/lib/lua  
$(INSTALL_DATA) $(PKG_BUILD_DIR)/src/soap.lua $(1)/usr/lib/lua/  
$(INSTALL_DIR) $(1)/usr/lib/lua/soap  
$(INSTALL_DATA) $(PKG_BUILD_DIR)/src/{client,server}.lua $(1)/usr/lib/lua/soap/  
$(INSTALL_DIR) $(1)/usr/lib/lua/soap/client  
$(INSTALL_DATA) $(PKG_BUILD_DIR)/src/client/https.lua $(1)/usr/lib/lua/soap/client/  
$(INSTALL_DIR) $(1)/usr/lib/lua/soap/tests  
$(INSTALL_DATA) $(PKG_BUILD_DIR)/tests/test{,-http,-server}.lua $(1)/usr/lib/lua/soap/tests/  
endef  
 
$(eval $(call BuildPackage,luasoap))  
 
file:a/lang/luasql/Makefile (deleted)
#  
# Copyright (C) 2010 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:=luasql  
PKG_VERSION:=2.1.1  
PKG_RELEASE:=1  
 
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz  
PKG_SOURCE_URL:=http://luaforge.net/frs/download.php/2686/  
PKG_MD5SUM:=63bdd57de4b9d1be336ba112d8cb69eb  
 
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)  
 
include $(INCLUDE_DIR)/package.mk  
 
define Package/luasql/Default  
SUBMENU:=Lua  
SECTION:=lang  
CATEGORY:=Languages  
TITLE:=Lua SQL binding  
URL:=http://www.keplerproject.org/luasql/  
DEPENDS:= +lua  
endef  
 
define Package/luasql/Default/description  
LuaSQL is a simple interface from Lua to a DBMS.  
endef  
 
 
define Package/luasql-mysql  
$(call Package/luasql/Default)  
TITLE+= for MySQL  
DEPENDS+= +libmysqlclient  
VARIANT:=mysql  
endef  
 
define Package/luasql-mysql/description  
$(call Package/luasql/Default/description)  
.  
This package contains the MySQL binding.  
endef  
 
 
define Package/luasql-pgsql  
$(call Package/luasql/Default)  
TITLE+= for PostgreSQL  
DEPENDS+= +libpq  
VARIANT:=postgres  
endef  
 
define Package/luasql-pgsql/description  
$(call Package/luasql/Default/description)  
.  
This package contains the PostgreSQL binding.  
endef  
 
 
define Package/luasql-sqlite3  
$(call Package/luasql/Default)  
TITLE+= for SQLite 3  
DEPENDS+= +libsqlite3  
VARIANT:=sqlite3  
endef  
 
define Package/luasql-sqlite3/description  
$(call Package/luasql/Default/description)  
.  
This package contains the SQLite 3 binding.  
endef  
 
 
TARGET_CFLAGS += $(FPIC) -std=gnu99  
TARGET_CPPFLAGS += -DLUA_USE_LINUX  
 
ifeq ($(BUILD_VARIANT),mysql)  
TARGET_CPPFLAGS += -I$(STAGING_DIR)/usr/include/mysql  
TARGET_LDFLAGS += -L$(STAGING_DIR)/usr/lib/mysql -lmysqlclient -lz  
endif  
 
ifeq ($(BUILD_VARIANT),postgres)  
TARGET_LDFLAGS += -lpq  
endif  
 
ifeq ($(BUILD_VARIANT),sqlite3)  
TARGET_LDFLAGS += -lsqlite3 -lpthread  
endif  
 
define Build/Compile  
$(MAKE) -C $(PKG_BUILD_DIR) \  
T="$(BUILD_VARIANT)" \  
PREFIX="$(STAGING_DIR)/usr" \  
LUA_LIBDIR="$(STAGING_DIR)/usr/lib/lua" \  
DRIVER_INCS="$(TARGET_CPPFLAGS)" \  
DRIVER_LIBS="$(TARGET_LDFLAGS)" \  
CC="$(TARGET_CROSS)gcc" \  
CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \  
lib  
$(MAKE) -C $(PKG_BUILD_DIR) \  
T="$(BUILD_VARIANT)" \  
LUA_LIBDIR="$(PKG_INSTALL_DIR)/usr/lib/lua" \  
install  
endef  
 
define Build/Install/Default  
$(INSTALL_DIR) $(1)/usr/lib/lua/luasql  
$(CP) $(PKG_INSTALL_DIR)/usr/lib/lua/luasql/*.so $(1)/usr/lib/lua/luasql/  
endef  
 
Package/luasql-mysql/install = $(Build/Install/Default)  
Package/luasql-pgsql/install = $(Build/Install/Default)  
Package/luasql-sqlite3/install = $(Build/Install/Default)  
 
$(eval $(call BuildPackage,luasql-mysql))  
$(eval $(call BuildPackage,luasql-pgsql))  
$(eval $(call BuildPackage,luasql-sqlite3))  
 
file:a/lang/php5/Makefile (deleted)
#  
# 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.27  
PKG_RELEASE:=1  
 
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2  
PKG_SOURCE_URL:=http://www.php.net/distributions/  
PKG_MD5SUM:=1c6e99187d25023411b663ea09f145ee  
 
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,sqlite,SQLite 2.x,+PACKAGE_php5-mod-sqlite:libsqlite2))  
$(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))  
 
file:a/lang/php5/files/php.ini (deleted)
[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=  
 
config php5-fastcgi  
option enabled 1  
option port '1026'  
 
#!/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  
}  
 
--- /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);