hdparm: moved to github
hdparm: moved to github

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

#  
# 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/lang/erlang/Makefile (deleted)
#  
# Copyright (C) 2009-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:=erlang  
PKG_VERSION:=R16B02  
PKG_RELEASE:=1  
 
PKG_SOURCE:=otp_src_$(PKG_VERSION).tar.gz  
PKG_SOURCE_URL:= http://www.erlang.org/download/ \  
http://erlang.mirror.su.se/  
PKG_MD5SUM:= ca63bcde0e5ae0f2df9457f97b3115a4  
 
PKG_BUILD_DEPENDS:=erlang/host openssl  
 
HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/otp_src_$(PKG_VERSION)  
PKG_BUILD_DIR:=$(BUILD_DIR)/otp_src_$(PKG_VERSION)  
 
include $(INCLUDE_DIR)/host-build.mk  
include $(INCLUDE_DIR)/package.mk  
 
define Package/erlang/Default  
SUBMENU:=Erlang  
SECTION:=lang  
CATEGORY:=Languages  
TITLE:=Erlang/OTP programming language  
URL:=http://www.erlang.org/  
endef  
 
define Package/erlang/Default/description  
Erlang/OTP is a general-purpose programming language and runtime  
environment. Erlang has built-in support for concurrency, distribution  
and fault tolerance.  
endef  
 
define Package/erlang  
$(call Package/erlang/Default)  
DEPENDS+= +libncurses +librt +zlib  
PROVIDES:= erlang-erts=5.10.3 erlang-kernel=2.16.3 erlang-sasl=2.3.3 erlang-stdlib=1.19.3  
endef  
 
define Package/erlang/description  
$(call Package/erlang/Default/description)  
.  
This package contains the runtime implementation and a minimal set of  
modules (erts, kernel, sasl & stdlib).  
endef  
 
 
define Package/erlang-asn1  
$(call Package/erlang/Default)  
TITLE:=Abstract Syntax Notation One (ASN.1) support  
VERSION:=2.0.3  
DEPENDS+= +erlang +erlang-syntax-tools  
endef  
 
define Package/erlang-asn1/description  
$(call Package/erlang/Default/description)  
.  
This Erlang/OTP package provides Abstract Syntax Notation One (ASN.1)  
support.  
endef  
 
 
define Package/erlang-compiler  
$(call Package/erlang/Default)  
TITLE:=Byte code compiler  
VERSION:=4.9.3  
DEPENDS+= +erlang +erlang-hipe  
endef  
 
define Package/erlang-compiler/description  
$(call Package/erlang/Default/description)  
.  
This Erlang/OTP package provides a byte code compiler for Erlang which  
produces highly compact code.  
endef  
 
 
define Package/erlang-crypto  
$(call Package/erlang/Default)  
TITLE:=Cryptography support  
VERSION:=3.1  
DEPENDS+= +erlang +libopenssl  
endef  
 
define Package/erlang-crypto/description  
$(call Package/erlang/Default/description)  
.  
This Erlang/OTP package provides functions for computation of message  
digests, and encryption and decryption functions.  
endef  
 
 
define Package/erlang-hipe  
$(call Package/erlang/Default)  
TITLE:=High Performance Erlang  
VERSION:=3.10.2.1  
DEPENDS+= +erlang  
endef  
 
define Package/erlang-hipe/description  
$(call Package/erlang/Default/description)  
.  
This Erlang/OTP package provides HiPE (High Performance Erlang)  
support.  
endef  
 
 
define Package/erlang-inets  
$(call Package/erlang/Default)  
TITLE:=Internet clients and servers  
VERSION:=5.9.6  
DEPENDS+= +erlang  
endef  
 
define Package/erlang-inets/description  
$(call Package/erlang/Default/description)  
.  
This Erlang/OTP package provides a container for Internet clients and  
servers. Currently a FTP client, a HTTP client and server, and a tftp  
client and server have been incorporated in Inets.  
endef  
 
 
define Package/erlang-mnesia  
$(call Package/erlang/Default)  
TITLE:=Distributed database  
VERSION:=4.10  
DEPENDS+= +erlang  
endef  
 
define Package/erlang-mnesia/description  
$(call Package/erlang/Default/description)  
.  
This Erlang/OTP package provides a distributed DataBase Management  
System (DBMS), appropriate for telecommunications applications and  
other Erlang applications which require continuous operation and  
exhibit soft real-time properties.  
endef  
 
 
define Package/erlang-runtime-tools  
$(call Package/erlang/Default)  
TITLE:=Low-profile debugging/tracing tools  
VERSION:=1.8.12  
DEPENDS+= +erlang  
endef  
 
define Package/erlang-runtime-tools/description  
$(call Package/erlang/Default/description)  
.  
This Erlang/OTP package provides low footprint tracing/debugging tools  
suitable for inclusion in a production system.  
endef  
 
 
define Package/erlang-snmp  
$(call Package/erlang/Default)  
TITLE:=Simple Network Management Protocol (SNMP) support  
VERSION:=4.24.2  
DEPENDS+= +erlang +erlang-asn1  
endef  
 
define Package/erlang-snmp/description  
$(call Package/erlang/Default/description)  
.  
This Erlang/OTP package provides Simple Network Management Protocol  
(SNMP) support including a MIB compiler and tools for creating SNMP  
agents.  
endef  
 
 
define Package/erlang-ssh  
$(call Package/erlang/Default)  
TITLE:=Secure Shell (SSH) support  
VERSION:=2.1.8  
DEPENDS+= +erlang +erlang-crypto  
endef  
 
define Package/erlang-ssh/description  
$(call Package/erlang/Default/description)  
.  
This Erlang/OTP package provides an implementation of the Secure Shell  
protocol, with SSH & SFTP support.  
endef  
 
 
define Package/erlang-ssl  
$(call Package/erlang/Default)  
TITLE:=Secure Sockets Layer (SSL) support  
VERSION:=5.3.1  
DEPENDS+= +erlang +erlang-crypto  
endef  
 
define Package/erlang-ssl/description  
$(call Package/erlang/Default/description)  
.  
This Erlang/OTP package provides support for secure communication over  
sockets.  
endef  
 
 
define Package/erlang-syntax-tools  
$(call Package/erlang/Default)  
TITLE:=Abstract Erlang syntax trees handling support  
VERSION:=1.6.11  
DEPENDS+= +erlang  
endef  
 
define Package/erlang-syntax-tools/description  
$(call Package/erlang/Default/description)  
.  
This Erlang/OTP package provides support for handling abstract Erlang  
syntax trees.  
endef  
 
 
# Host  
 
HOST_CONFIGURE_ARGS += \  
--disable-hipe \  
--disable-smp-support \  
--without-javac  
 
define Host/Compile  
$(MAKE) -C $(HOST_BUILD_DIR) all  
endef  
 
define Host/Install  
$(MAKE) -C $(HOST_BUILD_DIR) install  
endef  
 
 
# Target  
 
CONFIGURE_ARGS += \  
--disable-hipe \  
--disable-smp-support \  
--without-javac \  
--enable-dynamic-ssl-lib  
 
CONFIGURE_VARS += \  
SHLIB_LD="$(TARGET_CC)" \  
TARGET_ARCH="$(TARGET_ARCH)" \  
ac_cv_func_mmap_fixed_mapped=yes \  
ac_cv_path_WX_CONFIG_PATH=no \  
erl_xcomp_getaddrinfo=no \  
erl_xcomp_sysroot="$(STAGING_DIR)"  
 
EXTRA_LDFLAGS+=-lz  
 
define Build/Compile  
$(MAKE) -C $(PKG_BUILD_DIR) \  
noboot  
$(MAKE) -C $(PKG_BUILD_DIR) \  
INSTALL_PREFIX="$(PKG_INSTALL_DIR)" \  
install  
endef  
 
define Package/erlang/install  
$(INSTALL_DIR) $(1)/usr/bin  
for f in epmd erl erlc escript run_erl; do \  
$(CP) $(PKG_INSTALL_DIR)/usr/bin/$$$$f $(1)/usr/bin/ ; \  
done  
$(INSTALL_DIR) $(1)/usr/lib/erlang/bin  
for f in erl erlc escript run_erl start start.boot start.script start_clean.boot start_erl start_sasl.boot to_erl; do \  
$(CP) $(PKG_INSTALL_DIR)/usr/lib/erlang/bin/$$$$f $(1)/usr/lib/erlang/bin/ ; \  
done  
$(INSTALL_DIR) $(1)/usr/lib/erlang/lib  
for m in erts kernel sasl stdlib; do \  
$(CP) $(PKG_INSTALL_DIR)/usr/lib/erlang/lib/$$$$m-* $(1)/usr/lib/erlang/lib/ ; \  
rm -rf $(1)/usr/lib/erlang/lib/$$$$m-*/examples ; \  
rm -rf $(1)/usr/lib/erlang/lib/$$$$m-*/src ; \  
done  
$(INSTALL_DIR) $(1)/usr/lib/erlang  
$(CP) $(PKG_INSTALL_DIR)/usr/lib/erlang/erts-* $(1)/usr/lib/erlang/  
rm -rf $(1)/usr/lib/erlang/erts-*/{doc,include,lib,man,src}  
rm -rf $(1)/usr/lib/erlang/erts-*/bin/*.src  
$(INSTALL_DIR) $(1)/usr/lib/erlang/releases  
$(CP) $(PKG_INSTALL_DIR)/usr/lib/erlang/releases/* $(1)/usr/lib/erlang/releases/  
$(SED) 's,%ERL_ROOT%,/usr/lib/erlang,g' \  
$(1)/usr/lib/erlang/releases/RELEASES.src  
mv -f $(1)/usr/lib/erlang/releases/RELEASES.src \  
$(1)/usr/lib/erlang/releases/RELEASES  
for f in bin/erl bin/start erts-*/bin/erl erts-*/bin/start; do \  
$(SED) 's,^\(ROOTDIR\)=.*,\1=/usr/lib/erlang,g' \  
$(1)/usr/lib/erlang/$$$$f ; \  
done  
endef  
 
define Build/InstallDev  
$(INSTALL_DIR) $(1)/usr/lib  
$(CP) $(PKG_BUILD_DIR)/lib/erl_interface/obj/*/*.a $(1)/usr/lib  
$(INSTALL_DIR) $(1)/usr/include  
$(CP) $(PKG_BUILD_DIR)/lib/erl_interface/include/*.h $(1)/usr/include  
endef  
 
define BuildModule  
 
define Package/erlang-$(1)/install  
$(INSTALL_DIR) $$(1)/usr/lib/erlang/lib  
for m in $(2); do \  
$(CP) $(PKG_INSTALL_DIR)/usr/lib/erlang/lib/$$$$$$$$m-* $$(1)/usr/lib/erlang/lib/ ; \  
rm -rf $$(1)/usr/lib/erlang/lib/$$$$$$$$m-*/{examples,priv/obj,src} ; \  
done  
endef  
 
$$(eval $$(call BuildPackage,erlang-$(1)))  
 
endef  
 
 
$(eval $(call HostBuild))  
$(eval $(call BuildPackage,erlang))  
$(eval $(call BuildModule,asn1,asn1))  
$(eval $(call BuildModule,compiler,compiler))  
$(eval $(call BuildModule,crypto,crypto))  
$(eval $(call BuildModule,hipe,hipe))  
$(eval $(call BuildModule,inets,inets))  
$(eval $(call BuildModule,mnesia,mnesia))  
$(eval $(call BuildModule,runtime-tools,runtime_tools))  
$(eval $(call BuildModule,snmp,snmp))  
$(eval $(call BuildModule,ssh,ssh))  
$(eval $(call BuildModule,ssl,ssl))  
$(eval $(call BuildModule,syntax-tools,syntax_tools))  
 
--- a/erts/emulator/Makefile.in  
+++ b/erts/emulator/Makefile.in  
@@ -591,7 +591,7 @@ endif  
 
 
$(OBJDIR)/%.o: beam/%.c  
- $(V_CC) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@  
+ $(V_CC) $(INCLUDES) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) -c $< -o $@  
 
else  
 
 
--- a/lib/tools/Makefile  
+++ b/lib/tools/Makefile  
@@ -23,7 +23,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk  
# Macros  
# ----------------------------------------------------  
 
-SUB_DIRECTORIES = c_src src doc/src examples priv emacs  
+SUB_DIRECTORIES = c_src src doc/src examples priv  
 
include vsn.mk  
VSN = $(TOOLS_VSN)  
 
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 ){