[libgda/gtk3] Merged master



commit dd43c86bb9a49eefe3a36f6adce4a2e27bc40045
Author: Vivien Malerba <malerba gnome-db org>
Date:   Tue Sep 14 20:50:40 2010 +0200

    Merged master

 INSTALL                                            |  200 ++-
 configure.ac                                       |   17 +
 doc/C/libgda-sections.txt                          |    1 +
 doc/C/prov-notes.xml                               |   51 +
 doc/C/tmpl/gda-set.sgml                            |    9 +
 libgda/gda-set.c                                   |   16 +-
 libgda/gda-set.h                                   |    2 +-
 libgda/libgda.symbols                              |    1 +
 libgda/sqlite/Makefile.am                          |   44 +-
 libgda/sqlite/gda-sqlite-blob-op.c                 |    6 +-
 libgda/sqlite/gda-sqlite-handler-bin.c             |    6 +-
 libgda/sqlite/gda-sqlite-handler-boolean.c         |    6 +-
 libgda/sqlite/gda-sqlite-provider.c                |  110 +-
 libgda/sqlite/gda-sqlite-pstmt.c                   |    6 +-
 libgda/sqlite/gda-sqlite-recordset.c               |    6 +-
 libgda/sqlite/gda-sqlite.h                         |   21 +-
 libgda/sqlite/gda-symbols-util.c                   |    4 +
 libgda/sqlite/gda-symbols-util.h                   |    3 +
 po/POTFILES.in                                     |   13 +
 po/POTFILES.skip                                   |    1 +
 providers/Makefile.am                              |    7 +-
 providers/bdb/gda-bdb-provider.c                   |    6 +-
 providers/mysql/mysql_specs_create_db.xml.in       |    2 +-
 providers/mysql/mysql_specs_create_table.xml.in    |    2 +-
 providers/mysql/mysql_specs_drop_db.xml.in         |    2 +-
 providers/postgres/postgres_specs_create_db.xml.in |    2 +-
 providers/postgres/postgres_specs_drop_db.xml.in   |    2 +-
 providers/sqlcipher/.gitignore                     |    2 +
 providers/sqlcipher/COPYING.sqlcipher              |   28 +
 providers/sqlcipher/Makefile.am                    |   57 +
 providers/sqlcipher/NOTE_for_new_SQLCipher_version |   17 +
 providers/sqlcipher/libgda-sqlcipher-5.0.pc.in     |    9 +
 providers/sqlcipher/libmain.c                      |  105 +
 providers/sqlcipher/sqlcipher.patch                | 2483 ++++++++++++++++++++
 .../sqlcipher/sqlcipher_specs_add_column.xml.in    |    1 +
 providers/sqlcipher/sqlcipher_specs_auth.xml.in    |    6 +
 .../sqlcipher/sqlcipher_specs_create_db.xml.in     |    9 +
 .../sqlcipher/sqlcipher_specs_create_index.xml.in  |    1 +
 .../sqlcipher/sqlcipher_specs_create_table.xml.in  |    1 +
 .../sqlcipher/sqlcipher_specs_create_view.xml.in   |    1 +
 providers/sqlcipher/sqlcipher_specs_drop_db.xml.in |    1 +
 .../sqlcipher/sqlcipher_specs_drop_index.xml.in    |    1 +
 .../sqlcipher/sqlcipher_specs_drop_table.xml.in    |    1 +
 .../sqlcipher/sqlcipher_specs_drop_view.xml.in     |    1 +
 providers/sqlcipher/sqlcipher_specs_dsn.xml.in     |    1 +
 .../sqlcipher/sqlcipher_specs_rename_table.xml.in  |    1 +
 providers/web/web_specs_auth.xml.in                |    2 +-
 tests/Makefile.am                                  |    9 +-
 48 files changed, 3154 insertions(+), 129 deletions(-)
---
diff --git a/INSTALL b/INSTALL
index d3c5b40..7d1c323 100644
--- a/INSTALL
+++ b/INSTALL
@@ -2,18 +2,24 @@ Installation Instructions
 *************************
 
 Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
-2006, 2007 Free Software Foundation, Inc.
+2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
-This file is free documentation; the Free Software Foundation gives
-unlimited permission to copy, distribute and modify it.
+   Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.  This file is offered as-is,
+without warranty of any kind.
 
 Basic Installation
 ==================
 
-Briefly, the shell commands `./configure; make; make install' should
+   Briefly, the shell commands `./configure; make; make install' should
 configure, build, and install this package.  The following
 more-detailed instructions are generic; see the `README' file for
-instructions specific to this package.
+instructions specific to this package.  Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below.  The lack of an optional feature in a given package is not
+necessarily a bug.  More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
 
    The `configure' shell script attempts to guess correct values for
 various system-dependent variables used during compilation.  It uses
@@ -42,7 +48,7 @@ may remove or edit it.
 you want to change it or regenerate `configure' using a newer version
 of `autoconf'.
 
-The simplest way to compile this package is:
+   The simplest way to compile this package is:
 
   1. `cd' to the directory containing the package's source code and type
      `./configure' to configure the package for your system.
@@ -53,12 +59,22 @@ The simplest way to compile this package is:
   2. Type `make' to compile the package.
 
   3. Optionally, type `make check' to run any self-tests that come with
-     the package.
+     the package, generally using the just-built uninstalled binaries.
 
   4. Type `make install' to install the programs and any data files and
-     documentation.
-
-  5. You can remove the program binaries and object files from the
+     documentation.  When installing into a prefix owned by root, it is
+     recommended that the package be configured and built as a regular
+     user, and only the `make install' phase executed with root
+     privileges.
+
+  5. Optionally, type `make installcheck' to repeat any self-tests, but
+     this time using the binaries in their final installed location.
+     This target does not install anything.  Running this target as a
+     regular user, particularly if the prior `make install' required
+     root privileges, verifies that the installation completed
+     correctly.
+
+  6. You can remove the program binaries and object files from the
      source code directory by typing `make clean'.  To also remove the
      files that `configure' created (so you can compile the package for
      a different kind of computer), type `make distclean'.  There is
@@ -67,15 +83,22 @@ The simplest way to compile this package is:
      all sorts of other programs in order to regenerate files that came
      with the distribution.
 
-  6. Often, you can also type `make uninstall' to remove the installed
-     files again.
+  7. Often, you can also type `make uninstall' to remove the installed
+     files again.  In practice, not all packages have tested that
+     uninstallation works correctly, even though it is required by the
+     GNU Coding Standards.
+
+  8. Some packages, particularly those that use Automake, provide `make
+     distcheck', which can by used by developers to test that all other
+     targets like `make install' and `make uninstall' work correctly.
+     This target is generally not run by end users.
 
 Compilers and Options
 =====================
 
-Some systems require unusual options for compilation or linking that the
-`configure' script does not know about.  Run `./configure --help' for
-details on some of the pertinent environment variables.
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  Run `./configure --help'
+for details on some of the pertinent environment variables.
 
    You can give `configure' initial values for configuration parameters
 by setting variables in the command line or in the environment.  Here
@@ -88,25 +111,41 @@ is an example:
 Compiling For Multiple Architectures
 ====================================
 
-You can compile the package for more than one kind of computer at the
+   You can compile the package for more than one kind of computer at the
 same time, by placing the object files for each architecture in their
 own directory.  To do this, you can use GNU `make'.  `cd' to the
 directory where you want the object files and executables to go and run
 the `configure' script.  `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'.
+source code in the directory that `configure' is in and in `..'.  This
+is known as a "VPATH" build.
 
    With a non-GNU `make', it is safer to compile the package for one
 architecture at a time in the source code directory.  After you have
 installed the package for one architecture, use `make distclean' before
 reconfiguring for another architecture.
 
+   On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor.  Like
+this:
+
+     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CPP="gcc -E" CXXCPP="g++ -E"
+
+   This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
 Installation Names
 ==================
 
-By default, `make install' installs the package's commands under
+   By default, `make install' installs the package's commands under
 `/usr/local/bin', include files under `/usr/local/include', etc.  You
 can specify an installation prefix other than `/usr/local' by giving
-`configure' the option `--prefix=PREFIX'.
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
 
    You can specify separate installation prefixes for
 architecture-specific files and architecture-independent files.  If you
@@ -117,16 +156,47 @@ Documentation and other data files still use the regular prefix.
    In addition, if you use an unusual directory layout you can give
 options like `--bindir=DIR' to specify different values for particular
 kinds of files.  Run `configure --help' for a list of the directories
-you can set and what kinds of files go in them.
+you can set and what kinds of files go in them.  In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+   The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+   The first method involves providing an override variable for each
+affected directory.  For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'.  Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated.  The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+   The second method involves providing the `DESTDIR' variable.  For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names.  The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters.  On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
 
    If the package supports it, you can cause programs to be installed
 with an extra prefix or suffix on their names by giving `configure' the
 option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
 
-Optional Features
-=================
-
-Some packages pay attention to `--enable-FEATURE' options to
+   Some packages pay attention to `--enable-FEATURE' options to
 `configure', where FEATURE indicates an optional part of the package.
 They may also pay attention to `--with-PACKAGE' options, where PACKAGE
 is something like `gnu-as' or `x' (for the X Window System).  The
@@ -138,14 +208,53 @@ find the X include and library files automatically, but if it doesn't,
 you can use the `configure' options `--x-includes=DIR' and
 `--x-libraries=DIR' to specify their locations.
 
+   Some packages offer the ability to configure how verbose the
+execution of `make' will be.  For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+     ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file.  The option `-nodtk' can be used as
+a workaround.  If GNU CC is not installed, it is therefore recommended
+to try
+
+     ./configure CC="cc"
+
+and if that doesn't work, try
+
+     ./configure CC="cc -nodtk"
+
+   On Solaris, don't put `/usr/ucb' early in your `PATH'.  This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'.  So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+   On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'.  It is recommended to use the following options:
+
+     ./configure --prefix=/boot/common
+
 Specifying the System Type
 ==========================
 
-There may be some features `configure' cannot figure out automatically,
-but needs to determine by the type of machine the package will run on.
-Usually, assuming the package is built to be run on the _same_
-architectures, `configure' can figure that out, but if it prints a
-message saying it cannot guess the machine type, give it the
+   There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
 `--build=TYPE' option.  TYPE can either be a short name for the system
 type, such as `sun4', or a canonical name which has the form:
 
@@ -153,7 +262,8 @@ type, such as `sun4', or a canonical name which has the form:
 
 where SYSTEM can have one of these forms:
 
-     OS KERNEL-OS
+     OS
+     KERNEL-OS
 
    See the file `config.sub' for the possible values of each field.  If
 `config.sub' isn't included in this package, then this package doesn't
@@ -171,9 +281,9 @@ eventually be run) with `--host=TYPE'.
 Sharing Defaults
 ================
 
-If you want to set default values for `configure' scripts to share, you
-can create a site shell script called `config.site' that gives default
-values for variables like `CC', `cache_file', and `prefix'.
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
 `configure' looks for `PREFIX/share/config.site' if it exists, then
 `PREFIX/etc/config.site' if it exists.  Or, you can set the
 `CONFIG_SITE' environment variable to the location of the site script.
@@ -182,7 +292,7 @@ A warning: not all `configure' scripts look for a site script.
 Defining Variables
 ==================
 
-Variables not defined in a site shell script can be set in the
+   Variables not defined in a site shell script can be set in the
 environment passed to `configure'.  However, some packages may run
 configure again during the build, and the customized values of these
 variables may be lost.  In order to avoid this problem, you should set
@@ -201,11 +311,19 @@ an Autoconf bug.  Until the bug is fixed you can use this workaround:
 `configure' Invocation
 ======================
 
-`configure' recognizes the following options to control how it operates.
+   `configure' recognizes the following options to control how it
+operates.
 
 `--help'
 `-h'
-     Print a summary of the options to `configure', and exit.
+     Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+     Print a summary of the options unique to this package's
+     `configure', and exit.  The `short' variant lists options used
+     only in the top level, while the `recursive' variant lists options
+     also present in any nested packages.
 
 `--version'
 `-V'
@@ -232,6 +350,16 @@ an Autoconf bug.  Until the bug is fixed you can use this workaround:
      Look for the package's source code in directory DIR.  Usually
      `configure' can determine that directory automatically.
 
+`--prefix=DIR'
+     Use DIR as the installation prefix.  *note Installation Names::
+     for more details, including other options available for fine-tuning
+     the installation locations.
+
+`--no-create'
+`-n'
+     Run the configure checks, but stop before creating any output
+     files.
+
 `configure' also accepts some other, not widely useful, options.  Run
 `configure --help' for more details.
 
diff --git a/configure.ac b/configure.ac
index 9f87eca..45f4cce 100644
--- a/configure.ac
+++ b/configure.ac
@@ -419,6 +419,20 @@ dnl *********************************
 GOBJECT_INTROSPECTION_CHECK([0.6.5])
 
 dnl ******************************
+dnl Checks for libcrypto
+dnl ******************************
+
+LIBCRYPTO_MODULES="libcrypto"
+PKG_CHECK_MODULES(LIBCRYPTO, $LIBCRYPTO_MODULES, have_crypto=yes, have_crypto=no)
+AM_CONDITIONAL(HAVE_LIBCRYPTO, test x"$have_crypto" = "xyes")
+if test x"$have_crypto" = "xyes"
+then
+        LIBCRYPTO_CFLAGS="$LIBCRYPTO_CFLAGS -DHAVE_LIBCRYPTO"
+fi
+AC_SUBST(LIBCRYPTO_CFLAGS)
+AC_SUBST(LIBCRYPTO_LIBS)
+
+dnl ******************************
 dnl Checks for libgcrypt
 dnl ******************************
 LIBGCRYPT_CFLAGS=""
@@ -1810,6 +1824,8 @@ providers/skel-implementation/capi/Makefile
 providers/skel-implementation/capi/libgda-capi-5.0.pc
 providers/skel-implementation/models/Makefile
 providers/skel-implementation/models/libgda-models-5.0.pc
+providers/sqlcipher/Makefile
+providers/sqlcipher/libgda-sqlcipher-5.0.pc
 libgda-report/Makefile
 libgda-report/engine/Makefile
 libgda-report/DocBook/Makefile
@@ -1895,6 +1911,7 @@ dnl echo "      ODBC = `if test x$odbcdir != x; then echo yes; else echo no; fi`
 echo "      Oracle = `if test x$oracledir != x; then echo yes; else echo no; fi`"
 echo "      PostgreSQL = `if test x$postgresdir != x; then echo yes; else echo no; fi`"
 echo "      SQLite = yes `if test x$have_sqlite = xyes; then echo '(from system installation)'; else echo '(embedded)'; fi`"
+echo "      SQLCipher = `if test x$have_crypto != xyes; then echo no; else echo yes; fi`"
 dnl echo "      Sybase = `if test x$sybasedir != x; then echo yes; else echo no; fi`"
 dnl echo "      xBase (dBase, Clipper, FoxPro) = `if test x$xbasedir != x; then echo yes; else echo no; fi`"
 dnl echo "      LDAP = `if test x$ldapdir != x; then echo yes; else echo no; fi`"
diff --git a/doc/C/libgda-sections.txt b/doc/C/libgda-sections.txt
index b8e65e2..378f50d 100644
--- a/doc/C/libgda-sections.txt
+++ b/doc/C/libgda-sections.txt
@@ -1034,6 +1034,7 @@ gda_holder_get_type
 <TITLE>GdaSet</TITLE>
 GdaSet
 gda_set_new
+gda_set_new_read_only
 gda_set_copy
 gda_set_new_inline
 gda_set_new_from_spec_string
diff --git a/doc/C/prov-notes.xml b/doc/C/prov-notes.xml
index 41be401..2d90032 100644
--- a/doc/C/prov-notes.xml
+++ b/doc/C/prov-notes.xml
@@ -40,5 +40,56 @@
       Also refer to the <link linkend="limitations_oracle">Oracle's provider's limitations</link>.
     </para>
   </sect1>
+
+  <sect1 id="provider_notes_sqlcipher"><title>For SQLCipher</title>
+  <para>
+    The SQLCipher database provider allows one to connect to a database encrypted using the
+    <ulink url="http://www.zetetic.net/code/sqlcipher";>SQLCipher</ulink> adaptations to the SQLite
+    database. This section deals about how to manage the passphrase associated with a database file, please
+    also consult the information <ulink url="http://www.zetetic.net/code/sqlcipher";>provided by SQLCipher</ulink>
+    before attempting to use this database provider.
+  </para>
+  <para>
+    The first noticeable point is that any SQLite database file can be opened using the SQLCipher and
+    will remain useable with the "standard" SQLite provider as long as it's not explicitely encrypted using
+    a passphrase.
+  </para>
+  <sect2>
+    <title>How to create and encrypted database</title>
+    <para>
+      To create an encrypted database, you can use the <application>gda-sql</application> and when prompted
+      enter the requested passphrase, as:
+      <programlisting><![CDATA[prompt> gda-sql-4.0 "SQLCipher://DB_NAME=testcrypt"
+Welcome to the GDA SQL console, version 4.1.11
+
+Type: .copyright to show usage and distribution terms
+      .? for help with internal commands
+      .q (or CTRL-D) to quit
+      (the '.' can be replaced by a '\')
+      or any query terminated by a semicolon
+
+Opening connection 'c0' for: SQLCipher://DB_NAME=testcrypt
+	Password for 'c0':]]></programlisting>
+    </para>
+  </sect2>
+  <sect2>
+    <title>How to encrypt an existing database</title>
+    <para>
+      To encrypt an existing database, connect to the database using the SQLCipher provider and execute the
+      following SQL command (replace the passphrase with the requested passphrase):
+      <programlisting>PRAGMA key = 'passphrase';</programlisting>
+      setting the requested passphrase which will be later required to reopen the database. This step
+      prevents opening the database file by the "standard" SQLite provider.
+    </para>
+  </sect2>
+  <sect2>
+    <title>How to change the passphrase of an encrypted database</title>
+    <para>
+      To change an encrypted database's passphrase, open a connection to the database and enter the following
+      SQL command (replace the passphrase with the requested new passphrase):
+      <programlisting>PRAGMA rekey = 'passphrase';</programlisting>
+    </para>
+  </sect2>
+  </sect1>
   
 </chapter>
diff --git a/doc/C/tmpl/gda-set.sgml b/doc/C/tmpl/gda-set.sgml
index b881580..811e423 100644
--- a/doc/C/tmpl/gda-set.sgml
+++ b/doc/C/tmpl/gda-set.sgml
@@ -125,6 +125,15 @@ Container for several values
 @Returns: 
 
 
+<!-- ##### FUNCTION gda_set_new_read_only ##### -->
+<para>
+
+</para>
+
+ holders: 
+ Returns: 
+
+
 <!-- ##### FUNCTION gda_set_copy ##### -->
 <para>
 
diff --git a/libgda/gda-set.c b/libgda/gda-set.c
index b232e6b..9d870f0 100644
--- a/libgda/gda-set.c
+++ b/libgda/gda-set.c
@@ -419,11 +419,19 @@ gda_set_new (GSList *holders)
 	return (GdaSet*) obj;
 }
 
-/*
- * _gda_set_new_read_only
+/**
+ * gda_set_new_read_only:
+ * @holders: (element-type GdaHolder) (transfer:none): a list of #GdaHolder objects
+ *
+ * Creates a new #GdaSet like gda_set_new(), but does not allow modifications to any of the #GdaHolder
+ * object in @holders. This function is used for Libgda's database providers' implementation.
+ *
+ * Returns: a new #GdaSet object
+ *
+ * Since: 4.2
  */
 GdaSet *
-_gda_set_new_read_only (GSList *holders)
+gda_set_new_read_only (GSList *holders)
 {
 	GObject *obj;
 
@@ -436,8 +444,6 @@ _gda_set_new_read_only (GSList *holders)
 	return (GdaSet*) obj;
 }
 
-
-
 /**
  * gda_set_copy:
  * @set: a #GdaSet object
diff --git a/libgda/gda-set.h b/libgda/gda-set.h
index 4fb136b..8ac4599 100644
--- a/libgda/gda-set.h
+++ b/libgda/gda-set.h
@@ -143,7 +143,7 @@ GdaSetGroup  *gda_set_get_group                (GdaSet *set, GdaHolder *holder);
 
 /* private */
 gboolean      _gda_set_validate                (GdaSet *set, GError **error);
-GdaSet *      _gda_set_new_read_only           (GSList *holders);
+GdaSet *      gda_set_new_read_only            (GSList *holders);
 
 
 G_END_DECLS
diff --git a/libgda/libgda.symbols b/libgda/libgda.symbols
index 3409237..c9f886e 100644
--- a/libgda/libgda.symbols
+++ b/libgda/libgda.symbols
@@ -566,6 +566,7 @@
 	gda_set_is_valid
 	gda_set_merge_with_set
 	gda_set_new
+	gda_set_new_read_only
 	gda_set_new_from_spec_node
 	gda_set_new_from_spec_string
 	gda_set_new_inline
diff --git a/libgda/sqlite/Makefile.am b/libgda/sqlite/Makefile.am
index d73b051..8f22590 100644
--- a/libgda/sqlite/Makefile.am
+++ b/libgda/sqlite/Makefile.am
@@ -10,7 +10,7 @@ sqliteinc= -I$(top_srcdir)/libgda/sqlite/sqlite-src \
 endif
 SUBDIRS+= virtual
 
-noinst_LTLIBRARIES = libgda-sqlite.la
+noinst_LTLIBRARIES = libgda-sqlite.la libgda-sqlcipher.la
 if BDBSQL
 noinst_LTLIBRARIES += libgda-bdbsqlite.la
 endif
@@ -36,10 +36,7 @@ xml_embedded.h: gen_emb_string$(EXEEXT_FOR_BUILD) $(top_srcdir)/providers/sqlite
 	./gen_emb_string$(EXEEXT_FOR_BUILD) $(top_srcdir)/providers/sqlite/*.xml.in > xml_embedded.h
 
 sqliteheaders = gda-sqlite-provider.h
-
-$(libgda_sqlite_la_OBJECTS): xml_embedded.h keywords_hash.c
-
-libgda_sqlite_la_SOURCES = \
+sqlitesources = \
 	$(sqliteheaders) \
 	gda-sqlite-blob-op.c \
 	gda-sqlite-blob-op.h \
@@ -63,41 +60,26 @@ libgda_sqlite_la_SOURCES = \
 	gda-symbols-util.h \
 	gda-symbols-util.c
 
-libgda_sqlite_la_CFLAGS = -DSEARCH_LIB_PATH=\""$(SQLITE_PATH)"\"
+$(libgda_sqlite_la_OBJECTS): xml_embedded.h keywords_hash.c
+
+libgda_sqlite_la_SOURCES = $(sqlitesources)
+libgda_sqlite_la_CFLAGS = -DPNAME=\""SQLite"\" -DCLASS_PREFIX=\""GdaSqlite"\" -DSEARCH_LIB_PATH=\""$(SQLITE_PATH)"\"
 libgda_sqlite_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED)
 libgda_sqlite_la_LIBADD = \
 	virtual/libgda-virtual-5.0.la \
 	$(sqlitelibs) \
 	$(LIBGDA_LIBS)
 
-libgda_bdbsqlite_la_SOURCES = \
-	$(sqliteheaders) \
-	gda-sqlite-blob-op.c \
-	gda-sqlite-blob-op.h \
-	gda-sqlite-ddl.c \
-	gda-sqlite-ddl.h \
-	gda-sqlite-handler-bin.c \
-	gda-sqlite-handler-bin.h \
-	gda-sqlite-handler-boolean.c \
-	gda-sqlite-handler-boolean.h \
-	gda-sqlite-meta.c \
-	gda-sqlite-meta.h \
-	gda-sqlite-provider.c \
-	gda-sqlite-pstmt.h \
-	gda-sqlite-pstmt.c \
-	gda-sqlite-recordset.c \
-	gda-sqlite-recordset.h \
-	gda-sqlite-util.c \
-	gda-sqlite-util.h \
-	gda-sqlite.h \
-	keywords_hash.h \
-	gda-symbols-util.h \
-	gda-symbols-util.c
-
-libgda_bdbsqlite_la_CFLAGS = $(BDBSQL_CFLAGS) -DWITH_BDBSQLITE -DSEARCH_LIB_PATH=\""$(BDBSQL_PATH)"\"
+libgda_bdbsqlite_la_SOURCES = $(sqlitesources)
+libgda_bdbsqlite_la_CFLAGS = $(BDBSQL_CFLAGS) -DPNAME=\""BDBSql"\" -DCLASS_PREFIX=\""GdaDBDSql"\" -DWITH_BDBSQLITE -DSEARCH_LIB_PATH=\""$(BDBSQL_PATH)"\"
 libgda_bdbsqlite_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED)
 libgda_bdbsqlite_la_LIBADD = 
 
+libgda_sqlcipher_la_SOURCES = $(sqlitesources)
+libgda_sqlcipher_la_CFLAGS = -DPNAME=\""SQLCipher"\" -DCLASS_PREFIX=\""GdaSQLCipher"\" -DSTATIC_SQLITE -DSQLITE_HAS_CODEC -DSEARCH_LIB_PATH=\"""\"
+libgda_sqlcipher_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED)
+libgda_sqlcipher_la_LIBADD = 
+
 gdaincludedir=$(includedir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/libgda/sqlite
 gdainclude_HEADERS=$(sqliteheaders)
 
diff --git a/libgda/sqlite/gda-sqlite-blob-op.c b/libgda/sqlite/gda-sqlite-blob-op.c
index 751ceeb..24d7b3f 100644
--- a/libgda/sqlite/gda-sqlite-blob-op.c
+++ b/libgda/sqlite/gda-sqlite-blob-op.c
@@ -65,11 +65,7 @@ _gda_sqlite_blob_op_get_type (void)
 		};
 		g_static_mutex_lock (&registering);
 		if (type == 0)
-#ifdef WITH_BDBSQLITE
-			type = g_type_register_static (GDA_TYPE_BLOB_OP, "GdaDBDSqlBlobOp", &info, 0);
-#else
-			type = g_type_register_static (GDA_TYPE_BLOB_OP, "GdaSqliteBlobOp", &info, 0);
-#endif
+			type = g_type_register_static (GDA_TYPE_BLOB_OP, CLASS_PREFIX "BlobOp", &info, 0);
 		g_static_mutex_unlock (&registering);
 	}
 	return type;
diff --git a/libgda/sqlite/gda-sqlite-handler-bin.c b/libgda/sqlite/gda-sqlite-handler-bin.c
index de9eaa0..ff0437b 100644
--- a/libgda/sqlite/gda-sqlite-handler-bin.c
+++ b/libgda/sqlite/gda-sqlite-handler-bin.c
@@ -76,11 +76,7 @@ _gda_sqlite_handler_bin_get_type (void)
 
 		g_static_mutex_lock (&registering);
 		if (type == 0) {
-#ifdef WITH_BDBSQLITE
-			type = g_type_register_static (G_TYPE_OBJECT, "GdaDBDSqlHandlerBin", &info, 0);
-#else
-			type = g_type_register_static (G_TYPE_OBJECT, "GdaSqliteHandlerBin", &info, 0);
-#endif
+			type = g_type_register_static (G_TYPE_OBJECT, CLASS_PREFIX "HandlerBin", &info, 0);
 			g_type_add_interface_static (type, GDA_TYPE_DATA_HANDLER, &data_entry_info);
 		}
 		g_static_mutex_unlock (&registering);
diff --git a/libgda/sqlite/gda-sqlite-handler-boolean.c b/libgda/sqlite/gda-sqlite-handler-boolean.c
index ecc6141..a644e4c 100644
--- a/libgda/sqlite/gda-sqlite-handler-boolean.c
+++ b/libgda/sqlite/gda-sqlite-handler-boolean.c
@@ -78,11 +78,7 @@ _gda_sqlite_handler_boolean_get_type (void)
 
 		g_static_mutex_lock (&registering);
 		if (type == 0) {
-#ifdef WITH_BDBSQLITE
-			type = g_type_register_static (G_TYPE_OBJECT, "GdaDBDSqlHandlerBoolean", &info, 0);
-#else
-			type = g_type_register_static (G_TYPE_OBJECT, "GdaSqliteHandlerBoolean", &info, 0);
-#endif
+			type = g_type_register_static (G_TYPE_OBJECT, CLASS_PREFIX "HandlerBoolean", &info, 0);
 			g_type_add_interface_static (type, GDA_TYPE_DATA_HANDLER, &data_entry_info);
 		}
 		g_static_mutex_unlock (&registering);
diff --git a/libgda/sqlite/gda-sqlite-provider.c b/libgda/sqlite/gda-sqlite-provider.c
index d394bd6..d22b6f6 100644
--- a/libgda/sqlite/gda-sqlite-provider.c
+++ b/libgda/sqlite/gda-sqlite-provider.c
@@ -496,20 +496,24 @@ gda_sqlite_provider_get_type (void)
 		g_static_mutex_lock (&registering);
 		if (type == 0) {
 #ifdef WITH_BDBSQLITE
-			type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, "GdaDBDSqlProvider", &info, 0);
+			type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, CLASS_PREFIX "Provider", &info, 0);
 #else
-  #ifdef HAVE_SQLITE
+  #ifdef STATIC_SQLITE
+			type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, CLASS_PREFIX "Provider", &info, 0);
+  #else
+    #ifdef HAVE_SQLITE
 			GModule *module2;
 			
 			module2 = find_sqlite_library ("libsqlite3");
 			if (module2)
 				load_symbols (module2);
 			if (s3r)
-				type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, "GdaSqliteProvider", &info, 0);
+				type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, CLASS_PREFIX "Provider", &info, 0);
 			else
 				g_warning (_("Can't find libsqlite3." G_MODULE_SUFFIX " file."));
-  #else
-			type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, "GdaSqliteProvider", &info, 0);
+    #else
+			type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, CLASS_PREFIX "Provider", &info, 0);
+    #endif
   #endif
 #endif
 		}
@@ -525,7 +529,7 @@ gda_sqlite_provider_get_type (void)
 static const gchar *
 gda_sqlite_provider_get_name (GdaServerProvider *provider)
 {
-	return "SQLite";
+	return PNAME;
 }
 
 /* 
@@ -552,6 +556,7 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
 	gint errmsg;
 	SqliteConnectionData *cdata;
 	gchar *dup = NULL;
+	const gchar *passphrase = NULL;
 
 	g_return_val_if_fail (GDA_IS_SQLITE_PROVIDER (provider), FALSE);
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
@@ -571,6 +576,8 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
 	is_virtual = gda_quark_list_find (params, "_IS_VIRTUAL");
 	with_fk = gda_quark_list_find (params, "FK");
 	use_extra_functions = gda_quark_list_find (params, "LOAD_GDA_FUNCTIONS");
+	if (auth)
+		passphrase = gda_quark_list_find (auth, "PASSWORD");
 
 	if (! is_virtual) {
 		if (!dbname) {
@@ -667,6 +674,18 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
 		return FALSE;
 	}
 
+#ifdef SQLITE_HAS_CODEC
+	if (passphrase && *passphrase && SQLITE3_CALL (sqlite3_key)) {
+		errmsg = SQLITE3_CALL (sqlite3_key) (cdata->connection, (void*) passphrase, strlen (passphrase));
+		if (errmsg != SQLITE_OK) {
+			gda_connection_add_event_string (cnc, _("Wrong encryption passphrase"));
+			gda_sqlite_free_cnc_data (cdata);
+			g_static_rec_mutex_unlock (&cnc_mutex);
+			return FALSE;
+		}
+	}
+#endif
+
 	gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_sqlite_free_cnc_data);
 
 	/* use extended result codes */
@@ -886,8 +905,8 @@ gda_sqlite_provider_create_operation (GdaServerProvider *provider, GdaConnection
         gchar *str;
 	gchar *dir;
 
-        file = g_utf8_strdown (gda_server_operation_op_type_to_string (type), -1);
-        str = g_strdup_printf ("sqlite_specs_%s.xml", file);
+        file = g_strdup_printf (PNAME "_specs_%s.xml", gda_server_operation_op_type_to_string (type));
+        str = g_utf8_strdown (file, -1);
         g_free (file);
 
 	dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
@@ -929,8 +948,9 @@ gda_sqlite_provider_render_operation (GdaServerProvider *provider, GdaConnection
 	gchar *dir;
 
 	/* test @op's validity */
-        file = g_utf8_strdown (gda_server_operation_op_type_to_string (gda_server_operation_get_op_type (op)), -1);
-        str = g_strdup_printf ("sqlite_specs_%s.xml", file);
+	file = g_strdup_printf (PNAME "_specs_%s.xml",
+				gda_server_operation_op_type_to_string (gda_server_operation_get_op_type (op)));
+        str = g_utf8_strdown (file, -1);
         g_free (file);
 
 	dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
@@ -1039,6 +1059,70 @@ gda_sqlite_provider_perform_operation (GdaServerProvider *provider, GdaConnectio
 			g_set_error (error, 0, 0, "%s", SQLITE3_CALL (sqlite3_errmsg) (cdata->connection)); 
 			retval = FALSE;
 		}
+
+#ifdef SQLITE_HAS_CODEC
+		value = gda_server_operation_get_value_at (op, "/DB_DEF_P/PASSWORD");
+		if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) &&
+		    g_value_get_string (value) &&
+		    *g_value_get_string (value) &&
+		    SQLITE3_CALL (sqlite3_key)) {
+			const gchar *passphrase = g_value_get_string (value);
+			errmsg = SQLITE3_CALL (sqlite3_key) (cdata->connection, (void*) passphrase,
+							     strlen (passphrase));
+			if (errmsg != SQLITE_OK) {
+				g_set_error (error, 0, 0, "%s", SQLITE3_CALL (sqlite3_errmsg) (cdata->connection)); 
+				retval = FALSE;
+			}
+			else {
+				/* create some contents */
+				int res;
+				sqlite3_stmt *pStmt;
+				res = SQLITE3_CALL (sqlite3_prepare) (cdata->connection,
+								      "CREATE TABLE data (id int)", -1,
+								      &pStmt, NULL);
+
+				if (res != SQLITE_OK) {
+					g_set_error (error, 0, 0, "%s",
+						     _("Error initializing database with passphrase"));
+					retval = FALSE;
+					goto outcontents;
+				}
+				res = SQLITE3_CALL (sqlite3_step) (pStmt);
+				SQLITE3_CALL (sqlite3_reset) (pStmt);
+				SQLITE3_CALL (sqlite3_finalize) (pStmt);
+				if (res != SQLITE_DONE) {
+					g_set_error (error, 0, 0, "%s",
+						     _("Error initializing database with passphrase"));
+					retval = FALSE;
+					goto outcontents;
+					/* end */
+				}
+
+				res = SQLITE3_CALL (sqlite3_prepare) (cdata->connection,
+								      "DROP TABLE data", -1,
+								      &pStmt, NULL);
+
+				if (res != SQLITE_OK) {
+					g_set_error (error, 0, 0, "%s",
+						     _("Error initializing database with passphrase"));
+					retval = FALSE;
+					goto outcontents;
+				}
+				res = SQLITE3_CALL (sqlite3_step) (pStmt);
+				SQLITE3_CALL (sqlite3_reset) (pStmt);
+				SQLITE3_CALL (sqlite3_finalize) (pStmt);
+				if (res != SQLITE_DONE) {
+					g_set_error (error, 0, 0, "%s",
+						     _("Error initializing database with passphrase"));
+					retval = FALSE;
+					goto outcontents;
+					/* end */
+				}
+			outcontents:
+				;
+			}
+		}
+#endif
 		gda_sqlite_free_cnc_data (cdata);
 
 		return retval;
@@ -2123,7 +2207,7 @@ make_last_inserted_set (GdaConnection *cnc, GdaStatement *stmt, sqlite3_int64 la
 
 		if (holders) {
 			holders = g_slist_reverse (holders);
-			set = _gda_set_new_read_only (holders);
+			set = gda_set_new_read_only (holders);
 			g_slist_foreach (holders, (GFunc) g_object_unref, NULL);
 			g_slist_free (holders);
 		}
@@ -2764,12 +2848,12 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 				g_value_set_int ((value = gda_value_new (G_TYPE_INT)), changes);
 				gda_holder_take_value (holder, value, NULL);
 				list = g_slist_append (NULL, holder);
-				set = (GObject*) _gda_set_new_read_only (list);
+				set = (GObject*) gda_set_new_read_only (list);
 				g_slist_free (list);
 				g_object_unref (holder);
 			}
 			else
-				set = (GObject*) _gda_set_new_read_only (NULL);
+				set = (GObject*) gda_set_new_read_only (NULL);
 
 			return set;
 		}
diff --git a/libgda/sqlite/gda-sqlite-pstmt.c b/libgda/sqlite/gda-sqlite-pstmt.c
index 2341fd5..20d0496 100644
--- a/libgda/sqlite/gda-sqlite-pstmt.c
+++ b/libgda/sqlite/gda-sqlite-pstmt.c
@@ -57,11 +57,7 @@ _gda_sqlite_pstmt_get_type (void)
 
 		g_static_mutex_lock (&registering);
 		if (type == 0)
-#ifdef WITH_BDBSQLITE
-			type = g_type_register_static (GDA_TYPE_PSTMT, "GdaDBDSqlPStmt", &info, 0);
-#else
-			type = g_type_register_static (GDA_TYPE_PSTMT, "GdaSqlitePStmt", &info, 0);
-#endif
+			type = g_type_register_static (GDA_TYPE_PSTMT, CLASS_PREFIX "PStmt", &info, 0);
 		g_static_mutex_unlock (&registering);
 	}
 	return type;
diff --git a/libgda/sqlite/gda-sqlite-recordset.c b/libgda/sqlite/gda-sqlite-recordset.c
index 6ae3fa6..8a19b13 100644
--- a/libgda/sqlite/gda-sqlite-recordset.c
+++ b/libgda/sqlite/gda-sqlite-recordset.c
@@ -132,11 +132,7 @@ _gda_sqlite_recordset_get_type (void)
 		};
 		g_static_mutex_lock (&registering);
 		if (type == 0)
-#ifdef WITH_BDBSQLITE
-			type = g_type_register_static (GDA_TYPE_DATA_SELECT, "GdaDBDSqlRecordset", &info, 0);
-#else
-			type = g_type_register_static (GDA_TYPE_DATA_SELECT, "GdaSqliteRecordset", &info, 0);
-#endif
+			type = g_type_register_static (GDA_TYPE_DATA_SELECT, CLASS_PREFIX "Recordset", &info, 0);
 		g_static_mutex_unlock (&registering);
 	}
 
diff --git a/libgda/sqlite/gda-sqlite.h b/libgda/sqlite/gda-sqlite.h
index 16b1a7a..3a7298d 100644
--- a/libgda/sqlite/gda-sqlite.h
+++ b/libgda/sqlite/gda-sqlite.h
@@ -33,16 +33,21 @@
   #include "gda-symbols-util.h"
   #define SQLITE3_CALL(x) (s3r->x)
 #else
-  #ifdef HAVE_SQLITE
-    #include <sqlite3.h>
-    #include "gda-symbols-util.h"
-    #define SQLITE3_CALL(x) (s3r->x)
-    #if (SQLITE_VERSION_NUMBER < 3005000)
-      typedef sqlite_int64 sqlite3_int64;
-    #endif
-  #else
+  #ifdef STATIC_SQLITE
     #include "sqlite-src/sqlite3.h"
     #define SQLITE3_CALL(x) (x)
+  #else
+    #ifdef HAVE_SQLITE
+      #include <sqlite3.h>
+      #include "gda-symbols-util.h"
+      #define SQLITE3_CALL(x) (s3r->x)
+      #if (SQLITE_VERSION_NUMBER < 3005000)
+        typedef sqlite_int64 sqlite3_int64;
+      #endif
+    #else
+      #include "sqlite-src/sqlite3.h"
+      #define SQLITE3_CALL(x) (x)
+    #endif
   #endif
 #endif
 
diff --git a/libgda/sqlite/gda-symbols-util.c b/libgda/sqlite/gda-symbols-util.c
index 1da7dcc..a043934 100644
--- a/libgda/sqlite/gda-symbols-util.c
+++ b/libgda/sqlite/gda-symbols-util.c
@@ -271,6 +271,10 @@ load_symbols (GModule *module)
 		goto onerror;
 	if (! g_module_symbol (module, "sqlite3_value_type", (gpointer*) &(s3r->sqlite3_value_type)))
 		goto onerror;
+	if (! g_module_symbol (module, "sqlite3_key", (gpointer*) &(s3r->sqlite3_key)))
+		s3r->sqlite3_key = NULL;
+	if (! g_module_symbol (module, "sqlite3_rekey", (gpointer*) &(s3r->sqlite3_key)))
+		s3r->sqlite3_rekey = NULL;
 	return;
 
  onerror:
diff --git a/libgda/sqlite/gda-symbols-util.h b/libgda/sqlite/gda-symbols-util.h
index 6f929e8..b543740 100644
--- a/libgda/sqlite/gda-symbols-util.h
+++ b/libgda/sqlite/gda-symbols-util.h
@@ -106,6 +106,9 @@ typedef struct {
 	int  (*sqlite3_value_int)(sqlite3_value*);
 	const unsigned char * (*sqlite3_value_text)(sqlite3_value*);
 	int  (*sqlite3_value_type)(sqlite3_value*);
+
+	int  (*sqlite3_key)(sqlite3 *, const void *, int);
+	int  (*sqlite3_rekey)(sqlite3 *, const void *, int);
 } Sqlite3ApiRoutines;
 
 extern Sqlite3ApiRoutines *s3r;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 6d82a0a..4f38cae 100755
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -203,6 +203,19 @@ providers/reuseable/mysql/gda-mysql-meta.c
 providers/reuseable/mysql/gda-mysql-reuseable.c
 providers/reuseable/postgres/gda-postgres-meta.c
 providers/reuseable/postgres/gda-postgres-reuseable.c
+providers/sqlcipher/libmain.c
+providers/sqlcipher/sqlcipher_specs_add_column.xml.in
+providers/sqlcipher/sqlcipher_specs_auth.xml.in
+providers/sqlcipher/sqlcipher_specs_create_db.xml.in
+providers/sqlcipher/sqlcipher_specs_create_index.xml.in
+providers/sqlcipher/sqlcipher_specs_create_table.xml.in
+providers/sqlcipher/sqlcipher_specs_create_view.xml.in
+providers/sqlcipher/sqlcipher_specs_drop_db.xml.in
+providers/sqlcipher/sqlcipher_specs_drop_index.xml.in
+providers/sqlcipher/sqlcipher_specs_drop_table.xml.in
+providers/sqlcipher/sqlcipher_specs_drop_view.xml.in
+providers/sqlcipher/sqlcipher_specs_dsn.xml.in
+providers/sqlcipher/sqlcipher_specs_rename_table.xml.in
 providers/sqlite/libmain.c
 providers/sqlite/sqlite_specs_add_column.xml.in
 providers/sqlite/sqlite_specs_create_db.xml.in
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index 3d3762d..84bab04 100755
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -49,6 +49,7 @@ providers/skel-implementation/capi/libmain.c
 providers/skel-implementation/models/gda-models-provider.c
 providers/skel-implementation/models/libmain.c
 providers/skel-implementation/models/models_specs_dsn.xml.in
+providers/sqlcipher/sqlite3.c
 providers/sybase/gda-sybase-provider.c
 providers/sybase/gda-sybase-recordset.c
 providers/sybase/gda-sybase-types.c
diff --git a/providers/Makefile.am b/providers/Makefile.am
index b5fce61..c783825 100644
--- a/providers/Makefile.am
+++ b/providers/Makefile.am
@@ -62,6 +62,10 @@ if LIBSOUP
 GDA_WEB_SERVER=web
 endif
 
+if HAVE_LIBCRYPTO
+GDA_SQLCIPHER_SERVER=sqlcipher
+endif
+
 SUBDIRS = \
 	reuseable \
 	sqlite \
@@ -73,7 +77,8 @@ SUBDIRS = \
 	$(GDA_MYSQL_SERVER) \
 	$(GDA_JAVA_SERVER) \
 	$(GDA_ORACLE_SERVER) \
-	$(GDA_WEB_SERVER)
+	$(GDA_WEB_SERVER) \
+	$(GDA_SQLCIPHER_SERVER)
 #	$(GDA_FREETDS_SERVER) \
 #	$(GDA_IBMDB2_SERVER) \
 #	$(GDA_FIREBIRD_SERVER) \
diff --git a/providers/bdb/gda-bdb-provider.c b/providers/bdb/gda-bdb-provider.c
index 2deeb4c..ee34b98 100644
--- a/providers/bdb/gda-bdb-provider.c
+++ b/providers/bdb/gda-bdb-provider.c
@@ -165,8 +165,10 @@ gda_bdb_provider_open_connection (GdaServerProvider *provider, GdaConnection *cn
 							"connection string."));
 		return FALSE;
 	}
-	if (bdb_db != NULL && *(g_strstrip (bdb_db)) == '\0')
+	if (bdb_db && (*(g_strstrip (bdb_db)) == '\0')) {
+		g_free (bdb_db);
 		bdb_db = NULL;
+	}
 
 	/* create GdaDataModelBdb object */
 	if (dirname) {
@@ -216,7 +218,7 @@ gda_bdb_provider_open_connection (GdaServerProvider *provider, GdaConnection *cn
 		/* set associated data */
 		cdata = g_new0 (BdbConnectionData, 1);
 		cdata->table_model = model;
-		cdata->dbname = g_strdup_printf ("%s (%s)", bdb_file,bdb_db ? bdb_db : _("-"));
+		cdata->dbname = g_strdup_printf ("%s (%s)", bdb_file, bdb_db ? bdb_db : _("-"));
 		gda_virtual_connection_internal_set_provider_data (GDA_VIRTUAL_CONNECTION (cnc), 
 								   cdata, (GDestroyNotify) gda_bdb_free_cnc_data);
 	}
diff --git a/providers/mysql/mysql_specs_create_db.xml.in b/providers/mysql/mysql_specs_create_db.xml.in
index f5330a9..3453887 100644
--- a/providers/mysql/mysql_specs_create_db.xml.in
+++ b/providers/mysql/mysql_specs_create_db.xml.in
@@ -6,7 +6,7 @@
     <parameter id="PORT" _name="Port" _descr="Database server port" gdatype="gint"/>
     <parameter id="UNIX_SOCKET" _name="UNIX Socket" _descr="Full path of the UNIX socket to use when connecting locally" gdatype="gchararray"/>
     <parameter id="ADM_LOGIN" _name="Administrator login" _descr="Login name (which has the rights to create databases)" gdatype="gchararray"/>
-    <parameter id="ADM_PASSWORD" _name="Administrator password" gdatype="gchararray"/>
+    <parameter id="ADM_PASSWORD" _name="Administrator password" gdatype="gchararray" plugin="string:HIDDEN=true"/>
     <parameter id="USE_SSL" _name="Require SSL" _descr="Whether or not to use SSL to establish the connection" gdatype="gboolean"/>
   </parameters>
 
diff --git a/providers/mysql/mysql_specs_create_table.xml.in b/providers/mysql/mysql_specs_create_table.xml.in
index 1df2064..c027e7b 100644
--- a/providers/mysql/mysql_specs_create_table.xml.in
+++ b/providers/mysql/mysql_specs_create_table.xml.in
@@ -77,7 +77,7 @@
     <parameter id="TABLE_MAX_ROWS" _name="Max rows" gdatype="gint"/>
     <parameter id="TABLE_PACK_KEYS" _name="Pack keys" gdatype="gchararray" source="pack_keys"/>
     <parameter id="TABLE_DELAY_KEY_WRITE" _name="Delay key write" gdatype="gboolean"/>
-    <parameter id="TABLE_PASSWORD" _name="Password" gdatype="gchararray"/>
+    <parameter id="TABLE_PASSWORD" _name="Password" gdatype="gchararray" plugin="string:HIDDEN=true"/>
     <parameter id="TABLE_ROW_FORMAT" _name="Row format" gdatype="gchararray" source="row_format:0"/>
     <parameter id="TABLE_UNION" _name="Union" _descr="tbl_name[,tbl_name]...: only with MERGE engine" gdatype="gchararray"/>
     <parameter id="TABLE_INSERT_METHOD" _name="Insert method" _descr="FIRST, LAST or NO: only with MERGE engine" gdatype="gchararray"/>
diff --git a/providers/mysql/mysql_specs_drop_db.xml.in b/providers/mysql/mysql_specs_drop_db.xml.in
index 5eea470..be10e2c 100644
--- a/providers/mysql/mysql_specs_drop_db.xml.in
+++ b/providers/mysql/mysql_specs_drop_db.xml.in
@@ -7,7 +7,7 @@
     <parameter id="UNIX_SOCKET" _name="UNIX Socket" _descr="Full path of the UNIX socket to use when connecting locally" gdatype="gchararray"/>
     <parameter id="USE_SSL" _name="Require SSL" _descr="Whether or not to use SSL to establish the connection" gdatype="gboolean"/>
     <parameter id="ADM_LOGIN" _name="Administrator login" _descr="Login name (which has the rights to create databases)" gdatype="gchararray"/>
-    <parameter id="ADM_PASSWORD" _name="Administrator password" gdatype="gchararray"/>
+    <parameter id="ADM_PASSWORD" _name="Administrator password" gdatype="gchararray" plugin="string:HIDDEN=true"/>
   </parameters>
 
     <!-- DSN parameters -->
diff --git a/providers/postgres/postgres_specs_create_db.xml.in b/providers/postgres/postgres_specs_create_db.xml.in
index dc2db74..b93def5 100644
--- a/providers/postgres/postgres_specs_create_db.xml.in
+++ b/providers/postgres/postgres_specs_create_db.xml.in
@@ -6,7 +6,7 @@
     <parameter id="PORT" _name="Port" _descr="Database server port (for servers running on unix domain sockets, enter the socket's file name extension (usually 5432), or leave this field empty)" gdatype="gint"/>
     <parameter id="OPTIONS" _name="Options" _descr="Extra connection options" gdatype="gchararray"/>
     <parameter id="ADM_LOGIN" _name="Administrator login" _descr="Login name (which has the rights to create databases)" gdatype="gchararray"/>
-    <parameter id="ADM_PASSWORD" _name="Administrator password" gdatype="gchararray"/>
+    <parameter id="ADM_PASSWORD" _name="Administrator password" gdatype="gchararray" plugin="string:HIDDEN=true"/>
     <parameter id="USE_SSL" _name="Require SSL" _descr="Whether to require SSL or not when connecting" gdatype="gboolean"/>
   </parameters>
 
diff --git a/providers/postgres/postgres_specs_drop_db.xml.in b/providers/postgres/postgres_specs_drop_db.xml.in
index 40e1d9d..e2dbc4c 100644
--- a/providers/postgres/postgres_specs_drop_db.xml.in
+++ b/providers/postgres/postgres_specs_drop_db.xml.in
@@ -6,7 +6,7 @@
     <parameter id="PORT" _name="Port" _descr="Database server port (for servers running on unix domain sockets, enter the socket's file name extension (usually 5432), or leave this field empty)" gdatype="gint"/>
     <parameter id="OPTIONS" _name="Options" _descr="Extra connection options" gdatype="gchararray"/>
     <parameter id="ADM_LOGIN" _name="Administrator login" _descr="Login name (which has the rights to create databases)" gdatype="gchararray"/>
-    <parameter id="ADM_PASSWORD" _name="Administrator password" gdatype="gchararray"/>
+    <parameter id="ADM_PASSWORD" _name="Administrator password" gdatype="gchararray" plugin="string:HIDDEN=true"/>
     <parameter id="USE_SSL" _name="Require SSL" _descr="Whether to require SSL or not when connecting" gdatype="gboolean"/>
   </parameters>
 
diff --git a/providers/sqlcipher/.gitignore b/providers/sqlcipher/.gitignore
new file mode 100644
index 0000000..c989ca2
--- /dev/null
+++ b/providers/sqlcipher/.gitignore
@@ -0,0 +1,2 @@
+sqlite3.c
+sqlite3.h
\ No newline at end of file
diff --git a/providers/sqlcipher/COPYING.sqlcipher b/providers/sqlcipher/COPYING.sqlcipher
new file mode 100644
index 0000000..b6e96ae
--- /dev/null
+++ b/providers/sqlcipher/COPYING.sqlcipher
@@ -0,0 +1,28 @@
+Please find below the licence under which SQLCipher is distributed
+------------------------------------------------------------------
+
+
+Copyright (c) 2008, ZETETIC LLC
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the ZETETIC LLC nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/providers/sqlcipher/Makefile.am b/providers/sqlcipher/Makefile.am
new file mode 100644
index 0000000..44d6bd6
--- /dev/null
+++ b/providers/sqlcipher/Makefile.am
@@ -0,0 +1,57 @@
+providerdir=$(libdir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/providers
+provider_LTLIBRARIES = libgda-sqlcipher.la
+
+AM_CPPFLAGS = \
+	-I$(top_srcdir) \
+	-I$(top_srcdir)/libgda \
+	-I$(top_srcdir)/libgda/sqlite \
+	-I$(top_builddir) \
+	$(LIBGDA_CFLAGS) \
+	$(LIBCRYPTO_CFLAGS) \
+	$(sqliteinc) \
+	-DSQLITE_HAS_CODEC -DSQLITE_API= -DSQLITE_PRIVATE= -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_THREADSAFE=1 -DSQLITE_OMIT_LOAD_EXTENSION=1
+
+sqlite_sources = sqlite3.c sqlite3.h
+$(sqlite_sources): sqlcipher.patch $(top_srcdir)/libgda/sqlite/sqlite-src/sqlite3.c $(top_srcdir)/libgda/sqlite/sqlite-src/sqlite3.h
+	cp $(top_srcdir)/libgda/sqlite/sqlite-src/sqlite3.c sqlite3.c
+	cp $(top_srcdir)/libgda/sqlite/sqlite-src/sqlite3.h sqlite3.h
+	patch -p 0 < sqlcipher.patch
+
+libgda_sqlcipher_la_SOURCES = \
+	$(sqlite_sources) \
+	libmain.c
+
+libgda_sqlcipher_la_LDFLAGS = -export-dynamic -module -avoid-version $(LIBTOOL_PROV_EXPORT_OPTIONS)
+libgda_sqlcipher_la_LIBADD = \
+	$(top_builddir)/libgda/sqlite/libgda-sqlcipher.la \
+	$(LIBCRYPTO_LIBS)
+
+xmldir   = $(datadir)/libgda-5.0
+xml_in_files = \
+	sqlcipher_specs_auth.xml.in \
+	sqlcipher_specs_dsn.xml.in \
+	sqlcipher_specs_create_db.xml.in \
+	sqlcipher_specs_drop_db.xml.in \
+	sqlcipher_specs_create_table.xml.in \
+	sqlcipher_specs_drop_table.xml.in \
+	sqlcipher_specs_create_index.xml.in \
+	sqlcipher_specs_drop_index.xml.in \
+	sqlcipher_specs_rename_table.xml.in \
+	sqlcipher_specs_add_column.xml.in \
+	sqlcipher_specs_create_view.xml.in \
+	sqlcipher_specs_drop_view.xml.in
+
+ INTLTOOL_XML_RULE@
+
+xml_DATA = $(xml_in_files:.xml.in=.xml)
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libgda-sqlcipher-5.0.pc
+
+EXTRA_DIST = $(xml_in_files) \
+	libgda-sqlcipher-5.0.pc.in \
+	sqlcipher.patch
+
+CLEANFILES = $(sqlite_sources)
+
+DISTCLEANFILES = $(xml_DATA)
diff --git a/providers/sqlcipher/NOTE_for_new_SQLCipher_version b/providers/sqlcipher/NOTE_for_new_SQLCipher_version
new file mode 100644
index 0000000..845bbb0
--- /dev/null
+++ b/providers/sqlcipher/NOTE_for_new_SQLCipher_version
@@ -0,0 +1,17 @@
+To upgrade SQLCipher version, all is needed is to create a patch against
+the sqlite3.c and sqlite3.h files in ${top_srcdir}/libgda/sqlite/sqlite-src
+and replace the sqlcipher.patch file:
+
+
+* define the LIBGDA_SOURCE_DIR to point to the top source directory where Libgda's files are
+* download the SQLCipher code source and extract (from http://www.zetetic.net/code/sqlcipher or
+  http://www.zetetic.net/code/sqlcipher)
+* into the extracted archive, run:
+  ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC"
+  make sqlite3.c
+  cp $LIBGDA_SOURCE_DIR/libgda/sqlite/sqlite-src/sqlite3.c sqlite3.c.sqlite
+  cp $LIBGDA_SOURCE_DIR/libgda/sqlite/sqlite-src/sqlite3.h sqlite3.h.sqlite
+  diff -u sqlite3.h.sqlite sqlite3.h > sqlcipher.patch
+  diff -u sqlite3.c.sqlite sqlite3.c >> sqlcipher.patch
+  mv sqlcipher.patch $LIBGDA_SOURCE_DIR/providers/sqlcipher/
+* you can now delete all these temporary files
\ No newline at end of file
diff --git a/providers/sqlcipher/libgda-sqlcipher-5.0.pc.in b/providers/sqlcipher/libgda-sqlcipher-5.0.pc.in
new file mode 100644
index 0000000..1b36b77
--- /dev/null
+++ b/providers/sqlcipher/libgda-sqlcipher-5.0.pc.in
@@ -0,0 +1,9 @@
+prefix= prefix@
+exec_prefix= exec_prefix@
+libdir= libdir@
+includedir= includedir@
+
+Name: libgda-sqlcipher- GDA_ABI_MAJOR_VERSION@  GDA_ABI_MINOR_VERSION@
+Description: GDA (GNOME Data Access) SQLCipher provider
+Requires: libgda- GDA_ABI_MAJOR_VERSION@  GDA_ABI_MINOR_VERSION@
+Version: @VERSION@
diff --git a/providers/sqlcipher/libmain.c b/providers/sqlcipher/libmain.c
new file mode 100644
index 0000000..3105c96
--- /dev/null
+++ b/providers/sqlcipher/libmain.c
@@ -0,0 +1,105 @@
+/* GDA
+ * Copyright (C) 2010 The GNOME Foundation
+ *
+ * AUTHORS:
+ *         Vivien Malerba <malerba gnome-db org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+#include <libgda/gda-config.h>
+#include "gda-sqlite-provider.h"
+#include <libgda/gda-server-provider-extra.h>
+#include <libgda/binreloc/gda-binreloc.h>
+#include <libgda/sqlite/gda-symbols-util.h>
+
+static gchar      *module_path = NULL;
+const gchar       *plugin_get_name (void);
+const gchar       *plugin_get_description (void);
+gchar             *plugin_get_dsn_spec (void);
+GdaServerProvider *plugin_create_provider (void);
+
+/*
+ * Functions executed when calling g_module_open() and g_module_close()
+ */
+const gchar *
+g_module_check_init (GModule *module)
+{
+        /*g_module_make_resident (module);*/
+        return NULL;
+}
+
+void
+g_module_unload (GModule *module)
+{
+        g_free (module_path);
+        module_path = NULL;
+}
+
+/*
+ * Normal plugin functions 
+ */
+void
+plugin_init (const gchar *real_path)
+{
+        if (real_path)
+                module_path = g_strdup (real_path);
+}
+
+const gchar *
+plugin_get_name (void)
+{
+	return "SQLCipher";
+}
+
+const gchar *
+plugin_get_description (void)
+{
+	return _("Provider for SQLCipher");
+}
+
+gchar *
+plugin_get_dsn_spec (void)
+{
+	gchar *ret, *dir;
+
+	dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
+	ret = gda_server_provider_load_file_contents (module_path, dir, "sqlcipher_specs_dsn.xml");
+	g_free (dir);
+	return ret;
+}
+
+gchar *
+plugin_get_auth_spec (void)
+{
+	gchar *ret, *dir;
+
+        dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
+        ret = gda_server_provider_load_file_contents (module_path, dir, "sqlcipher_specs_auth.xml");
+        g_free (dir);
+        return ret;
+}
+
+GdaServerProvider *
+plugin_create_provider (void)
+{
+	GdaServerProvider *prov;
+
+	prov = (GdaServerProvider*) g_object_new (GDA_TYPE_SQLITE_PROVIDER, NULL);
+        g_object_set_data ((GObject *) prov, "GDA_PROVIDER_DIR", module_path);
+        return prov;
+}
diff --git a/providers/sqlcipher/sqlcipher.patch b/providers/sqlcipher/sqlcipher.patch
new file mode 100644
index 0000000..77d2090
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher.patch
@@ -0,0 +1,2483 @@
+--- sqlite3.c.sqlite	2010-09-13 21:54:33.000000000 +0200
++++ sqlite3.c	2010-09-13 21:51:52.000000000 +0200
+@@ -10994,6 +10994,1320 @@
+ #endif /* _SQLITEINT_H_ */
+ 
+ /************** End of sqliteInt.h *******************************************/
++/************** Begin file crypto.c ******************************************/
++/* 
++** SQLCipher
++** crypto.c developed by Stephen Lombardo (Zetetic LLC) 
++** sjlombardo at zetetic dot net
++** http://zetetic.net
++** 
++** Copyright (c) 2009, ZETETIC LLC
++** All rights reserved.
++** 
++** Redistribution and use in source and binary forms, with or without
++** modification, are permitted provided that the following conditions are met:
++**     * Redistributions of source code must retain the above copyright
++**       notice, this list of conditions and the following disclaimer.
++**     * Redistributions in binary form must reproduce the above copyright
++**       notice, this list of conditions and the following disclaimer in the
++**       documentation and/or other materials provided with the distribution.
++**     * Neither the name of the ZETETIC LLC nor the
++**       names of its contributors may be used to endorse or promote products
++**       derived from this software without specific prior written permission.
++** 
++** THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
++** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
++** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++**  
++*/
++/* BEGIN CRYPTO */
++#ifdef SQLITE_HAS_CODEC
++
++#include <openssl/evp.h>
++#include <openssl/rand.h>
++#include <openssl/hmac.h>
++/************** Include btreeInt.h in the middle of crypto.c *****************/
++/************** Begin file btreeInt.h ****************************************/
++/*
++** 2004 April 6
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This file implements a external (disk-based) database using BTrees.
++** For a detailed discussion of BTrees, refer to
++**
++**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
++**     "Sorting And Searching", pages 473-480. Addison-Wesley
++**     Publishing Company, Reading, Massachusetts.
++**
++** The basic idea is that each page of the file contains N database
++** entries and N+1 pointers to subpages.
++**
++**   ----------------------------------------------------------------
++**   |  Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) |
++**   ----------------------------------------------------------------
++**
++** All of the keys on the page that Ptr(0) points to have values less
++** than Key(0).  All of the keys on page Ptr(1) and its subpages have
++** values greater than Key(0) and less than Key(1).  All of the keys
++** on Ptr(N) and its subpages have values greater than Key(N-1).  And
++** so forth.
++**
++** Finding a particular key requires reading O(log(M)) pages from the 
++** disk where M is the number of entries in the tree.
++**
++** In this implementation, a single file can hold one or more separate 
++** BTrees.  Each BTree is identified by the index of its root page.  The
++** key and data for any entry are combined to form the "payload".  A
++** fixed amount of payload can be carried directly on the database
++** page.  If the payload is larger than the preset amount then surplus
++** bytes are stored on overflow pages.  The payload for an entry
++** and the preceding pointer are combined to form a "Cell".  Each 
++** page has a small header which contains the Ptr(N) pointer and other
++** information such as the size of key and data.
++**
++** FORMAT DETAILS
++**
++** The file is divided into pages.  The first page is called page 1,
++** the second is page 2, and so forth.  A page number of zero indicates
++** "no such page".  The page size can be any power of 2 between 512 and 65536.
++** Each page can be either a btree page, a freelist page, an overflow
++** page, or a pointer-map page.
++**
++** The first page is always a btree page.  The first 100 bytes of the first
++** page contain a special header (the "file header") that describes the file.
++** The format of the file header is as follows:
++**
++**   OFFSET   SIZE    DESCRIPTION
++**      0      16     Header string: "SQLite format 3\000"
++**     16       2     Page size in bytes.  
++**     18       1     File format write version
++**     19       1     File format read version
++**     20       1     Bytes of unused space at the end of each page
++**     21       1     Max embedded payload fraction
++**     22       1     Min embedded payload fraction
++**     23       1     Min leaf payload fraction
++**     24       4     File change counter
++**     28       4     Reserved for future use
++**     32       4     First freelist page
++**     36       4     Number of freelist pages in the file
++**     40      60     15 4-byte meta values passed to higher layers
++**
++**     40       4     Schema cookie
++**     44       4     File format of schema layer
++**     48       4     Size of page cache
++**     52       4     Largest root-page (auto/incr_vacuum)
++**     56       4     1=UTF-8 2=UTF16le 3=UTF16be
++**     60       4     User version
++**     64       4     Incremental vacuum mode
++**     68       4     unused
++**     72       4     unused
++**     76       4     unused
++**
++** All of the integer values are big-endian (most significant byte first).
++**
++** The file change counter is incremented when the database is changed
++** This counter allows other processes to know when the file has changed
++** and thus when they need to flush their cache.
++**
++** The max embedded payload fraction is the amount of the total usable
++** space in a page that can be consumed by a single cell for standard
++** B-tree (non-LEAFDATA) tables.  A value of 255 means 100%.  The default
++** is to limit the maximum cell size so that at least 4 cells will fit
++** on one page.  Thus the default max embedded payload fraction is 64.
++**
++** If the payload for a cell is larger than the max payload, then extra
++** payload is spilled to overflow pages.  Once an overflow page is allocated,
++** as many bytes as possible are moved into the overflow pages without letting
++** the cell size drop below the min embedded payload fraction.
++**
++** The min leaf payload fraction is like the min embedded payload fraction
++** except that it applies to leaf nodes in a LEAFDATA tree.  The maximum
++** payload fraction for a LEAFDATA tree is always 100% (or 255) and it
++** not specified in the header.
++**
++** Each btree pages is divided into three sections:  The header, the
++** cell pointer array, and the cell content area.  Page 1 also has a 100-byte
++** file header that occurs before the page header.
++**
++**      |----------------|
++**      | file header    |   100 bytes.  Page 1 only.
++**      |----------------|
++**      | page header    |   8 bytes for leaves.  12 bytes for interior nodes
++**      |----------------|
++**      | cell pointer   |   |  2 bytes per cell.  Sorted order.
++**      | array          |   |  Grows downward
++**      |                |   v
++**      |----------------|
++**      | unallocated    |
++**      | space          |
++**      |----------------|   ^  Grows upwards
++**      | cell content   |   |  Arbitrary order interspersed with freeblocks.
++**      | area           |   |  and free space fragments.
++**      |----------------|
++**
++** The page headers looks like this:
++**
++**   OFFSET   SIZE     DESCRIPTION
++**      0       1      Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf
++**      1       2      byte offset to the first freeblock
++**      3       2      number of cells on this page
++**      5       2      first byte of the cell content area
++**      7       1      number of fragmented free bytes
++**      8       4      Right child (the Ptr(N) value).  Omitted on leaves.
++**
++** The flags define the format of this btree page.  The leaf flag means that
++** this page has no children.  The zerodata flag means that this page carries
++** only keys and no data.  The intkey flag means that the key is a integer
++** which is stored in the key size entry of the cell header rather than in
++** the payload area.
++**
++** The cell pointer array begins on the first byte after the page header.
++** The cell pointer array contains zero or more 2-byte numbers which are
++** offsets from the beginning of the page to the cell content in the cell
++** content area.  The cell pointers occur in sorted order.  The system strives
++** to keep free space after the last cell pointer so that new cells can
++** be easily added without having to defragment the page.
++**
++** Cell content is stored at the very end of the page and grows toward the
++** beginning of the page.
++**
++** Unused space within the cell content area is collected into a linked list of
++** freeblocks.  Each freeblock is at least 4 bytes in size.  The byte offset
++** to the first freeblock is given in the header.  Freeblocks occur in
++** increasing order.  Because a freeblock must be at least 4 bytes in size,
++** any group of 3 or fewer unused bytes in the cell content area cannot
++** exist on the freeblock chain.  A group of 3 or fewer free bytes is called
++** a fragment.  The total number of bytes in all fragments is recorded.
++** in the page header at offset 7.
++**
++**    SIZE    DESCRIPTION
++**      2     Byte offset of the next freeblock
++**      2     Bytes in this freeblock
++**
++** Cells are of variable length.  Cells are stored in the cell content area at
++** the end of the page.  Pointers to the cells are in the cell pointer array
++** that immediately follows the page header.  Cells is not necessarily
++** contiguous or in order, but cell pointers are contiguous and in order.
++**
++** Cell content makes use of variable length integers.  A variable
++** length integer is 1 to 9 bytes where the lower 7 bits of each 
++** byte are used.  The integer consists of all bytes that have bit 8 set and
++** the first byte with bit 8 clear.  The most significant byte of the integer
++** appears first.  A variable-length integer may not be more than 9 bytes long.
++** As a special case, all 8 bytes of the 9th byte are used as data.  This
++** allows a 64-bit integer to be encoded in 9 bytes.
++**
++**    0x00                      becomes  0x00000000
++**    0x7f                      becomes  0x0000007f
++**    0x81 0x00                 becomes  0x00000080
++**    0x82 0x00                 becomes  0x00000100
++**    0x80 0x7f                 becomes  0x0000007f
++**    0x8a 0x91 0xd1 0xac 0x78  becomes  0x12345678
++**    0x81 0x81 0x81 0x81 0x01  becomes  0x10204081
++**
++** Variable length integers are used for rowids and to hold the number of
++** bytes of key and data in a btree cell.
++**
++** The content of a cell looks like this:
++**
++**    SIZE    DESCRIPTION
++**      4     Page number of the left child. Omitted if leaf flag is set.
++**     var    Number of bytes of data. Omitted if the zerodata flag is set.
++**     var    Number of bytes of key. Or the key itself if intkey flag is set.
++**      *     Payload
++**      4     First page of the overflow chain.  Omitted if no overflow
++**
++** Overflow pages form a linked list.  Each page except the last is completely
++** filled with data (pagesize - 4 bytes).  The last page can have as little
++** as 1 byte of data.
++**
++**    SIZE    DESCRIPTION
++**      4     Page number of next overflow page
++**      *     Data
++**
++** Freelist pages come in two subtypes: trunk pages and leaf pages.  The
++** file header points to the first in a linked list of trunk page.  Each trunk
++** page points to multiple leaf pages.  The content of a leaf page is
++** unspecified.  A trunk page looks like this:
++**
++**    SIZE    DESCRIPTION
++**      4     Page number of next trunk page
++**      4     Number of leaf pointers on this page
++**      *     zero or more pages numbers of leaves
++*/
++
++
++/* The following value is the maximum cell size assuming a maximum page
++** size give above.
++*/
++#define MX_CELL_SIZE(pBt)  (pBt->pageSize-8)
++
++/* The maximum number of cells on a single page of the database.  This
++** assumes a minimum cell size of 6 bytes  (4 bytes for the cell itself
++** plus 2 bytes for the index to the cell in the page header).  Such
++** small cells will be rare, but they are possible.
++*/
++#define MX_CELL(pBt) ((pBt->pageSize-8)/6)
++
++/* Forward declarations */
++typedef struct MemPage MemPage;
++typedef struct BtLock BtLock;
++
++/*
++** This is a magic string that appears at the beginning of every
++** SQLite database in order to identify the file as a real database.
++**
++** You can change this value at compile-time by specifying a
++** -DSQLITE_FILE_HEADER="..." on the compiler command-line.  The
++** header must be exactly 16 bytes including the zero-terminator so
++** the string itself should be 15 characters long.  If you change
++** the header, then your custom library will not be able to read 
++** databases generated by the standard tools and the standard tools
++** will not be able to read databases created by your custom library.
++*/
++#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
++#  define SQLITE_FILE_HEADER "SQLite format 3"
++#endif
++
++/*
++** Page type flags.  An ORed combination of these flags appear as the
++** first byte of on-disk image of every BTree page.
++*/
++#define PTF_INTKEY    0x01
++#define PTF_ZERODATA  0x02
++#define PTF_LEAFDATA  0x04
++#define PTF_LEAF      0x08
++
++/*
++** As each page of the file is loaded into memory, an instance of the following
++** structure is appended and initialized to zero.  This structure stores
++** information about the page that is decoded from the raw file page.
++**
++** The pParent field points back to the parent page.  This allows us to
++** walk up the BTree from any leaf to the root.  Care must be taken to
++** unref() the parent page pointer when this page is no longer referenced.
++** The pageDestructor() routine handles that chore.
++**
++** Access to all fields of this structure is controlled by the mutex
++** stored in MemPage.pBt->mutex.
++*/
++struct MemPage {
++  u8 isInit;           /* True if previously initialized. MUST BE FIRST! */
++  u8 nOverflow;        /* Number of overflow cell bodies in aCell[] */
++  u8 intKey;           /* True if intkey flag is set */
++  u8 leaf;             /* True if leaf flag is set */
++  u8 hasData;          /* True if this page stores data */
++  u8 hdrOffset;        /* 100 for page 1.  0 otherwise */
++  u8 childPtrSize;     /* 0 if leaf==1.  4 if leaf==0 */
++  u16 maxLocal;        /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
++  u16 minLocal;        /* Copy of BtShared.minLocal or BtShared.minLeaf */
++  u16 cellOffset;      /* Index in aData of first cell pointer */
++  u16 nFree;           /* Number of free bytes on the page */
++  u16 nCell;           /* Number of cells on this page, local and ovfl */
++  u16 maskPage;        /* Mask for page offset */
++  struct _OvflCell {   /* Cells that will not fit on aData[] */
++    u8 *pCell;          /* Pointers to the body of the overflow cell */
++    u16 idx;            /* Insert this cell before idx-th non-overflow cell */
++  } aOvfl[5];
++  BtShared *pBt;       /* Pointer to BtShared that this page is part of */
++  u8 *aData;           /* Pointer to disk image of the page data */
++  DbPage *pDbPage;     /* Pager page handle */
++  Pgno pgno;           /* Page number for this page */
++};
++
++/*
++** The in-memory image of a disk page has the auxiliary information appended
++** to the end.  EXTRA_SIZE is the number of bytes of space needed to hold
++** that extra information.
++*/
++#define EXTRA_SIZE sizeof(MemPage)
++
++/*
++** A linked list of the following structures is stored at BtShared.pLock.
++** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor 
++** is opened on the table with root page BtShared.iTable. Locks are removed
++** from this list when a transaction is committed or rolled back, or when
++** a btree handle is closed.
++*/
++struct BtLock {
++  Btree *pBtree;        /* Btree handle holding this lock */
++  Pgno iTable;          /* Root page of table */
++  u8 eLock;             /* READ_LOCK or WRITE_LOCK */
++  BtLock *pNext;        /* Next in BtShared.pLock list */
++};
++
++/* Candidate values for BtLock.eLock */
++#define READ_LOCK     1
++#define WRITE_LOCK    2
++
++/* A Btree handle
++**
++** A database connection contains a pointer to an instance of
++** this object for every database file that it has open.  This structure
++** is opaque to the database connection.  The database connection cannot
++** see the internals of this structure and only deals with pointers to
++** this structure.
++**
++** For some database files, the same underlying database cache might be 
++** shared between multiple connections.  In that case, each connection
++** has it own instance of this object.  But each instance of this object
++** points to the same BtShared object.  The database cache and the
++** schema associated with the database file are all contained within
++** the BtShared object.
++**
++** All fields in this structure are accessed under sqlite3.mutex.
++** The pBt pointer itself may not be changed while there exists cursors 
++** in the referenced BtShared that point back to this Btree since those
++** cursors have to do go through this Btree to find their BtShared and
++** they often do so without holding sqlite3.mutex.
++*/
++struct Btree {
++  sqlite3 *db;       /* The database connection holding this btree */
++  BtShared *pBt;     /* Sharable content of this btree */
++  u8 inTrans;        /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
++  u8 sharable;       /* True if we can share pBt with another db */
++  u8 locked;         /* True if db currently has pBt locked */
++  int wantToLock;    /* Number of nested calls to sqlite3BtreeEnter() */
++  int nBackup;       /* Number of backup operations reading this btree */
++  Btree *pNext;      /* List of other sharable Btrees from the same db */
++  Btree *pPrev;      /* Back pointer of the same list */
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  BtLock lock;       /* Object used to lock page 1 */
++#endif
++};
++
++/*
++** Btree.inTrans may take one of the following values.
++**
++** If the shared-data extension is enabled, there may be multiple users
++** of the Btree structure. At most one of these may open a write transaction,
++** but any number may have active read transactions.
++*/
++#define TRANS_NONE  0
++#define TRANS_READ  1
++#define TRANS_WRITE 2
++
++/*
++** An instance of this object represents a single database file.
++** 
++** A single database file can be in use as the same time by two
++** or more database connections.  When two or more connections are
++** sharing the same database file, each connection has it own
++** private Btree object for the file and each of those Btrees points
++** to this one BtShared object.  BtShared.nRef is the number of
++** connections currently sharing this database file.
++**
++** Fields in this structure are accessed under the BtShared.mutex
++** mutex, except for nRef and pNext which are accessed under the
++** global SQLITE_MUTEX_STATIC_MASTER mutex.  The pPager field
++** may not be modified once it is initially set as long as nRef>0.
++** The pSchema field may be set once under BtShared.mutex and
++** thereafter is unchanged as long as nRef>0.
++**
++** isPending:
++**
++**   If a BtShared client fails to obtain a write-lock on a database
++**   table (because there exists one or more read-locks on the table),
++**   the shared-cache enters 'pending-lock' state and isPending is
++**   set to true.
++**
++**   The shared-cache leaves the 'pending lock' state when either of
++**   the following occur:
++**
++**     1) The current writer (BtShared.pWriter) concludes its transaction, OR
++**     2) The number of locks held by other connections drops to zero.
++**
++**   while in the 'pending-lock' state, no connection may start a new
++**   transaction.
++**
++**   This feature is included to help prevent writer-starvation.
++*/
++struct BtShared {
++  Pager *pPager;        /* The page cache */
++  sqlite3 *db;          /* Database connection currently using this Btree */
++  BtCursor *pCursor;    /* A list of all open cursors */
++  MemPage *pPage1;      /* First page of the database */
++  u8 readOnly;          /* True if the underlying file is readonly */
++  u8 pageSizeFixed;     /* True if the page size can no longer be changed */
++  u8 secureDelete;      /* True if secure_delete is enabled */
++  u8 initiallyEmpty;    /* Database is empty at start of transaction */
++#ifndef SQLITE_OMIT_AUTOVACUUM
++  u8 autoVacuum;        /* True if auto-vacuum is enabled */
++  u8 incrVacuum;        /* True if incr-vacuum is enabled */
++#endif
++  u16 maxLocal;         /* Maximum local payload in non-LEAFDATA tables */
++  u16 minLocal;         /* Minimum local payload in non-LEAFDATA tables */
++  u16 maxLeaf;          /* Maximum local payload in a LEAFDATA table */
++  u16 minLeaf;          /* Minimum local payload in a LEAFDATA table */
++  u8 inTransaction;     /* Transaction state */
++  u8 doNotUseWAL;       /* If true, do not open write-ahead-log file */
++  u32 pageSize;         /* Total number of bytes on a page */
++  u32 usableSize;       /* Number of usable bytes on each page */
++  int nTransaction;     /* Number of open transactions (read + write) */
++  u32 nPage;            /* Number of pages in the database */
++  void *pSchema;        /* Pointer to space allocated by sqlite3BtreeSchema() */
++  void (*xFreeSchema)(void*);  /* Destructor for BtShared.pSchema */
++  sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */
++  Bitvec *pHasContent;  /* Set of pages moved to free-list this transaction */
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  int nRef;             /* Number of references to this structure */
++  BtShared *pNext;      /* Next on a list of sharable BtShared structs */
++  BtLock *pLock;        /* List of locks held on this shared-btree struct */
++  Btree *pWriter;       /* Btree with currently open write transaction */
++  u8 isExclusive;       /* True if pWriter has an EXCLUSIVE lock on the db */
++  u8 isPending;         /* If waiting for read-locks to clear */
++#endif
++  u8 *pTmpSpace;        /* BtShared.pageSize bytes of space for tmp use */
++};
++
++/*
++** An instance of the following structure is used to hold information
++** about a cell.  The parseCellPtr() function fills in this structure
++** based on information extract from the raw disk page.
++*/
++typedef struct CellInfo CellInfo;
++struct CellInfo {
++  u8 *pCell;     /* Pointer to the start of cell content */
++  i64 nKey;      /* The key for INTKEY tables, or number of bytes in key */
++  u32 nData;     /* Number of bytes of data */
++  u32 nPayload;  /* Total amount of payload */
++  u16 nHeader;   /* Size of the cell content header in bytes */
++  u16 nLocal;    /* Amount of payload held locally */
++  u16 iOverflow; /* Offset to overflow page number.  Zero if no overflow */
++  u16 nSize;     /* Size of the cell content on the main b-tree page */
++};
++
++/*
++** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than
++** this will be declared corrupt. This value is calculated based on a
++** maximum database size of 2^31 pages a minimum fanout of 2 for a
++** root-node and 3 for all other internal nodes.
++**
++** If a tree that appears to be taller than this is encountered, it is
++** assumed that the database is corrupt.
++*/
++#define BTCURSOR_MAX_DEPTH 20
++
++/*
++** A cursor is a pointer to a particular entry within a particular
++** b-tree within a database file.
++**
++** The entry is identified by its MemPage and the index in
++** MemPage.aCell[] of the entry.
++**
++** A single database file can shared by two more database connections,
++** but cursors cannot be shared.  Each cursor is associated with a
++** particular database connection identified BtCursor.pBtree.db.
++**
++** Fields in this structure are accessed under the BtShared.mutex
++** found at self->pBt->mutex. 
++*/
++struct BtCursor {
++  Btree *pBtree;            /* The Btree to which this cursor belongs */
++  BtShared *pBt;            /* The BtShared this cursor points to */
++  BtCursor *pNext, *pPrev;  /* Forms a linked list of all cursors */
++  struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
++  Pgno pgnoRoot;            /* The root page of this tree */
++  sqlite3_int64 cachedRowid; /* Next rowid cache.  0 means not valid */
++  CellInfo info;            /* A parse of the cell we are pointing at */
++  u8 wrFlag;                /* True if writable */
++  u8 atLast;                /* Cursor pointing to the last entry */
++  u8 validNKey;             /* True if info.nKey is valid */
++  u8 eState;                /* One of the CURSOR_XXX constants (see below) */
++  void *pKey;      /* Saved key that was cursor's last known position */
++  i64 nKey;        /* Size of pKey, or last integer key */
++  int skipNext;    /* Prev() is noop if negative. Next() is noop if positive */
++#ifndef SQLITE_OMIT_INCRBLOB
++  u8 isIncrblobHandle;      /* True if this cursor is an incr. io handle */
++  Pgno *aOverflow;          /* Cache of overflow page locations */
++#endif
++  i16 iPage;                            /* Index of current page in apPage */
++  MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
++  u16 aiIdx[BTCURSOR_MAX_DEPTH];        /* Current index in apPage[i] */
++};
++
++/*
++** Potential values for BtCursor.eState.
++**
++** CURSOR_VALID:
++**   Cursor points to a valid entry. getPayload() etc. may be called.
++**
++** CURSOR_INVALID:
++**   Cursor does not point to a valid entry. This can happen (for example) 
++**   because the table is empty or because BtreeCursorFirst() has not been
++**   called.
++**
++** CURSOR_REQUIRESEEK:
++**   The table that this cursor was opened on still exists, but has been 
++**   modified since the cursor was last used. The cursor position is saved
++**   in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in 
++**   this state, restoreCursorPosition() can be called to attempt to
++**   seek the cursor to the saved position.
++**
++** CURSOR_FAULT:
++**   A unrecoverable error (an I/O error or a malloc failure) has occurred
++**   on a different connection that shares the BtShared cache with this
++**   cursor.  The error has left the cache in an inconsistent state.
++**   Do nothing else with this cursor.  Any attempt to use the cursor
++**   should return the error code stored in BtCursor.skip
++*/
++#define CURSOR_INVALID           0
++#define CURSOR_VALID             1
++#define CURSOR_REQUIRESEEK       2
++#define CURSOR_FAULT             3
++
++/* 
++** The database page the PENDING_BYTE occupies. This page is never used.
++*/
++# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
++
++/*
++** These macros define the location of the pointer-map entry for a 
++** database page. The first argument to each is the number of usable
++** bytes on each page of the database (often 1024). The second is the
++** page number to look up in the pointer map.
++**
++** PTRMAP_PAGENO returns the database page number of the pointer-map
++** page that stores the required pointer. PTRMAP_PTROFFSET returns
++** the offset of the requested map entry.
++**
++** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page,
++** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
++** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
++** this test.
++*/
++#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
++#define PTRMAP_PTROFFSET(pgptrmap, pgno) (5*(pgno-pgptrmap-1))
++#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
++
++/*
++** The pointer map is a lookup table that identifies the parent page for
++** each child page in the database file.  The parent page is the page that
++** contains a pointer to the child.  Every page in the database contains
++** 0 or 1 parent pages.  (In this context 'database page' refers
++** to any page that is not part of the pointer map itself.)  Each pointer map
++** entry consists of a single byte 'type' and a 4 byte parent page number.
++** The PTRMAP_XXX identifiers below are the valid types.
++**
++** The purpose of the pointer map is to facility moving pages from one
++** position in the file to another as part of autovacuum.  When a page
++** is moved, the pointer in its parent must be updated to point to the
++** new location.  The pointer map is used to locate the parent page quickly.
++**
++** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not
++**                  used in this case.
++**
++** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number 
++**                  is not used in this case.
++**
++** PTRMAP_OVERFLOW1: The database page is the first page in a list of 
++**                   overflow pages. The page number identifies the page that
++**                   contains the cell with a pointer to this overflow page.
++**
++** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of
++**                   overflow pages. The page-number identifies the previous
++**                   page in the overflow page list.
++**
++** PTRMAP_BTREE: The database page is a non-root btree page. The page number
++**               identifies the parent page in the btree.
++*/
++#define PTRMAP_ROOTPAGE 1
++#define PTRMAP_FREEPAGE 2
++#define PTRMAP_OVERFLOW1 3
++#define PTRMAP_OVERFLOW2 4
++#define PTRMAP_BTREE 5
++
++/* A bunch of assert() statements to check the transaction state variables
++** of handle p (type Btree*) are internally consistent.
++*/
++#define btreeIntegrity(p) \
++  assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
++  assert( p->pBt->inTransaction>=p->inTrans ); 
++
++
++/*
++** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
++** if the database supports auto-vacuum or not. Because it is used
++** within an expression that is an argument to another macro 
++** (sqliteMallocRaw), it is not possible to use conditional compilation.
++** So, this macro is defined instead.
++*/
++#ifndef SQLITE_OMIT_AUTOVACUUM
++#define ISAUTOVACUUM (pBt->autoVacuum)
++#else
++#define ISAUTOVACUUM 0
++#endif
++
++
++/*
++** This structure is passed around through all the sanity checking routines
++** in order to keep track of some global state information.
++*/
++typedef struct IntegrityCk IntegrityCk;
++struct IntegrityCk {
++  BtShared *pBt;    /* The tree being checked out */
++  Pager *pPager;    /* The associated pager.  Also accessible by pBt->pPager */
++  Pgno nPage;       /* Number of pages in the database */
++  int *anRef;       /* Number of times each page is referenced */
++  int mxErr;        /* Stop accumulating errors when this reaches zero */
++  int nErr;         /* Number of messages written to zErrMsg so far */
++  int mallocFailed; /* A memory allocation error has occurred */
++  StrAccum errMsg;  /* Accumulate the error message text here */
++};
++
++/*
++** Read or write a two- and four-byte big-endian integer values.
++*/
++#define get2byte(x)   ((x)[0]<<8 | (x)[1])
++#define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v))
++#define get4byte sqlite3Get4byte
++#define put4byte sqlite3Put4byte
++
++/************** End of btreeInt.h ********************************************/
++/************** Continuing where we left off in crypto.c *********************/
++/************** Include crypto.h in the middle of crypto.c *******************/
++/************** Begin file crypto.h ******************************************/
++/* 
++** SQLCipher
++** crypto.h developed by Stephen Lombardo (Zetetic LLC) 
++** sjlombardo at zetetic dot net
++** http://zetetic.net
++** 
++** Copyright (c) 2008, ZETETIC LLC
++** All rights reserved.
++** 
++** Redistribution and use in source and binary forms, with or without
++** modification, are permitted provided that the following conditions are met:
++**     * Redistributions of source code must retain the above copyright
++**       notice, this list of conditions and the following disclaimer.
++**     * Redistributions in binary form must reproduce the above copyright
++**       notice, this list of conditions and the following disclaimer in the
++**       documentation and/or other materials provided with the distribution.
++**     * Neither the name of the ZETETIC LLC nor the
++**       names of its contributors may be used to endorse or promote products
++**       derived from this software without specific prior written permission.
++** 
++** THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
++** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
++** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++**  
++*/
++/* BEGIN CRYPTO */
++#ifdef SQLITE_HAS_CODEC
++#ifndef CRYPTO_H
++#define CRYPTO_H
++
++#define FILE_HEADER_SZ 16
++
++#ifndef CIPHER
++#define CIPHER "aes-256-cbc"
++#endif
++
++#define CIPHER_DECRYPT 0
++#define CIPHER_ENCRYPT 1
++
++#ifndef PBKDF2_ITER
++#define PBKDF2_ITER 4000
++#endif
++
++SQLITE_PRIVATE void sqlite3pager_get_codec(Pager *pPager, void **ctx);
++SQLITE_PRIVATE int sqlite3pager_is_mj_pgno(Pager *pPager, Pgno pgno);
++SQLITE_PRIVATE sqlite3_file *sqlite3Pager_get_fd(Pager *pPager);
++SQLITE_PRIVATE void sqlite3pager_sqlite3PagerSetCodec(
++  Pager *pPager,
++  void *(*xCodec)(void*,void*,Pgno,int),
++  void (*xCodecSizeChng)(void*,int,int),
++  void (*xCodecFree)(void*),
++  void *pCodec
++);
++
++#endif
++#endif
++/* END CRYPTO */
++
++/************** End of crypto.h **********************************************/
++/************** Continuing where we left off in crypto.c *********************/
++
++#ifdef CODEC_DEBUG
++#define CODEC_TRACE(X)  {printf X;fflush(stdout);}
++#else
++#define CODEC_TRACE(X)
++#endif
++
++SQLITE_PRIVATE void sqlite3FreeCodecArg(void *pCodecArg);
++
++typedef struct {
++  int derive_key;
++  EVP_CIPHER *evp_cipher;
++  int kdf_iter;
++  int key_sz;
++  int iv_sz;
++  int pass_sz;
++  unsigned char *key;
++  char *pass;
++} cipher_ctx;
++
++typedef struct {
++  int kdf_salt_sz;
++  int mode_rekey;
++  unsigned char *kdf_salt;
++  unsigned char *buffer;
++  Btree *pBt;
++  cipher_ctx *read_ctx;
++  cipher_ctx *write_ctx;
++} codec_ctx;
++
++static void activate_openssl() {
++  sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++  if(EVP_get_cipherbyname(CIPHER) == NULL) {
++    OpenSSL_add_all_algorithms();
++  } 
++  sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++}
++
++/*
++**  Simple routines for converting hex char strings to binary data
++ */
++static int cipher_hex2int(char c) {
++  return (c>='0' && c<='9') ? (c)-'0' :
++         (c>='A' && c<='F') ? (c)-'A'+10 :
++         (c>='a' && c<='f') ? (c)-'a'+10 : 0;
++}
++
++static void cipher_hex2bin(const char *hex, int sz, unsigned char *out){
++  int i;
++  for(i = 0; i < sz; i += 2){
++    out[i/2] = (cipher_hex2int(hex[i])<<4) | cipher_hex2int(hex[i+1]);
++  }
++}
++
++
++/**
++  * Free and wipe memory
++  * If ptr is not null memory will be freed. 
++  * If sz is greater than zero, the memory will be overwritten with zero before it is freed
++  */
++static void codec_free(void *ptr, int sz) {
++  if(ptr) {
++    if(sz > 0) memset(ptr, 0, sz); // FIXME - require buffer size
++    sqlite3_free(ptr);
++  }
++}
++
++/**
++  * Set the raw password / key data for a cipher context
++  * 
++  * returns SQLITE_OK if assignment was successfull
++  * returns SQLITE_NOMEM if an error occured allocating memory
++  * returns SQLITE_ERROR if the key couldn't be set because the pass was null or size was zero
++  */
++static int cipher_ctx_set_pass(cipher_ctx *ctx, const void *zKey, int nKey) {
++  codec_free(ctx->pass, ctx->pass_sz);
++  ctx->pass_sz = nKey;
++  if(zKey && nKey) {
++    ctx->pass = sqlite3Malloc(nKey);
++    if(ctx->pass == NULL) return SQLITE_NOMEM;
++    memcpy(ctx->pass, zKey, nKey);
++    return SQLITE_OK;
++  }
++  return SQLITE_ERROR;
++}
++
++/**
++  * Initialize a a new cipher_ctx struct. This function will allocate memory
++  * for the cipher context and for the key
++  * 
++  * returns SQLITE_OK if initialization was successful
++  * returns SQLITE_NOMEM if an error occured allocating memory
++  */
++static int cipher_ctx_init(cipher_ctx **iCtx) {
++  cipher_ctx *ctx;
++  *iCtx = sqlite3Malloc(sizeof(cipher_ctx));
++  ctx = *iCtx;
++  if(ctx == NULL) return SQLITE_NOMEM;
++  memset(ctx, 0, sizeof(cipher_ctx)); 
++  ctx->key = sqlite3Malloc(EVP_MAX_KEY_LENGTH);
++  if(ctx->key == NULL) return SQLITE_NOMEM;
++  return SQLITE_OK;
++}
++
++/**
++  * Free and wipe memory associated with a cipher_ctx
++  */
++static void cipher_ctx_free(cipher_ctx **iCtx) {
++  cipher_ctx *ctx = *iCtx;
++  CODEC_TRACE(("cipher_ctx_free: entered iCtx=%d\n", iCtx));
++  codec_free(ctx->key, ctx->key_sz);
++  codec_free(ctx->pass, ctx->pass_sz);
++  codec_free(ctx, sizeof(cipher_ctx)); 
++}
++
++/**
++  * Copy one cipher_ctx to another. For instance, assuming that read_ctx is a 
++  * fully initialized context, you could copy it to write_ctx and all yet data
++  * and pass information across
++  *
++  * returns SQLITE_OK if initialization was successful
++  * returns SQLITE_NOMEM if an error occured allocating memory
++  */
++static int cipher_ctx_copy(cipher_ctx *target, cipher_ctx *source) {
++  void *key = target->key; 
++  CODEC_TRACE(("cipher_ctx_copy: entered target=%d, source=%d\n", target, source));
++  codec_free(target->pass, target->pass_sz); 
++  memcpy(target, source, sizeof(cipher_ctx));
++  
++  target->key = key; //restore pointer to previously allocated key data
++  memcpy(target->key, source->key, EVP_MAX_KEY_LENGTH);
++  target->pass = sqlite3Malloc(source->pass_sz);
++  if(target->pass == NULL) return SQLITE_NOMEM;
++  memcpy(target->pass, source->pass, source->pass_sz);
++  return SQLITE_OK;
++}
++
++/**
++  * Compare one cipher_ctx to another.
++  *
++  * returns 0 if all the parameters (except the derived key data) are the same
++  * returns 1 otherwise
++  */
++static int cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) {
++  CODEC_TRACE(("cipher_ctx_cmp: entered c1=%d c2=%d\n", c1, c2));
++
++  if(
++    c1->evp_cipher == c2->evp_cipher
++    && c1->iv_sz == c2->iv_sz
++    && c1->kdf_iter == c2->kdf_iter
++    && c1->key_sz == c2->key_sz
++    && c1->pass_sz == c2->pass_sz
++    && (
++      c1->pass == c2->pass
++      || !memcmp(c1->pass, c2->pass, c1->pass_sz)
++    ) 
++  ) return 0;
++  return 1;
++}
++
++/**
++  * Free and wipe memory associated with a cipher_ctx, including the allocated
++  * read_ctx and write_ctx.
++  */
++static void codec_ctx_free(codec_ctx **iCtx) {
++  codec_ctx *ctx = *iCtx;
++  CODEC_TRACE(("codec_ctx_free: entered iCtx=%d\n", iCtx));
++  codec_free(ctx->kdf_salt, ctx->kdf_salt_sz);
++  codec_free(ctx->buffer, 0);
++  cipher_ctx_free(&ctx->read_ctx);
++  cipher_ctx_free(&ctx->write_ctx);
++  codec_free(ctx, sizeof(codec_ctx)); 
++}
++
++/**
++  * Derive an encryption key for a cipher contex key based on the raw password.
++  *
++  * If the raw key data is formated as x'hex' and there are exactly enough hex chars to fill
++  * the key space (i.e 64 hex chars for a 256 bit key) then the key data will be used directly. 
++  * 
++  * Otherwise, a key data will be derived using PBKDF2
++  * 
++  * returns SQLITE_OK if initialization was successful
++  * returns SQLITE_NOMEM if the key could't be derived (for instance if pass is NULL or pass_sz is 0)
++  */
++static int codec_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) { 
++  CODEC_TRACE(("codec_key_derive: entered c_ctx->pass=%s, c_ctx->pass_sz=%d ctx->kdf_salt=%d ctx->kdf_salt_sz=%d c_ctx->kdf_iter=%d c_ctx->key_sz=%d\n", 
++    c_ctx->pass, c_ctx->pass_sz, ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->kdf_iter, c_ctx->key_sz));
++
++  if(c_ctx->pass && c_ctx->pass_sz) { // if pass is not null
++    if (c_ctx->pass_sz == ((c_ctx->key_sz*2)+3) && sqlite3StrNICmp(c_ctx->pass ,"x'", 2) == 0) { 
++      int n = c_ctx->pass_sz - 3; /* adjust for leading x' and tailing ' */
++      const char *z = c_ctx->pass + 2; /* adjust lead offset of x' */ 
++      CODEC_TRACE(("codec_key_derive: deriving key from hex\n")); 
++      cipher_hex2bin(z, n, c_ctx->key);
++    } else { 
++      CODEC_TRACE(("codec_key_derive: deriving key using PBKDF2\n")); 
++      PKCS5_PBKDF2_HMAC_SHA1(c_ctx->pass, c_ctx->pass_sz, ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->kdf_iter, c_ctx->key_sz, c_ctx->key);
++    }
++    return SQLITE_OK;
++  };
++  return SQLITE_ERROR;
++}
++
++/*
++ * ctx - codec context
++ * pgno - page number in database
++ * size - size in bytes of input and output buffers
++ * mode - 1 to encrypt, 0 to decrypt
++ * in - pointer to input bytes
++ * out - pouter to output bytes
++ */
++static int codec_cipher(cipher_ctx *ctx, Pgno pgno, int mode, int size, unsigned char *in, unsigned char *out) {
++  EVP_CIPHER_CTX ectx;
++  unsigned char *iv;
++  int tmp_csz, csz;
++
++  CODEC_TRACE(("codec_cipher:entered pgno=%d, mode=%d, size=%d\n", pgno, mode, size));
++
++  /* just copy raw data from in to out when key size is 0
++   * i.e. during a rekey of a plaintext database */ 
++  if(ctx->key_sz == 0) {
++    memcpy(out, in, size);
++    return SQLITE_OK;
++  } 
++
++  // FIXME - only run if using an IV
++  size = size - ctx->iv_sz; /* adjust size to useable size and memset reserve at end of page */
++  iv = out + size;
++  if(mode == CIPHER_ENCRYPT) {
++    RAND_pseudo_bytes(iv, ctx->iv_sz);
++  } else {
++    memcpy(iv, in+size, ctx->iv_sz);
++  } 
++  
++  EVP_CipherInit(&ectx, ctx->evp_cipher, NULL, NULL, mode);
++  EVP_CIPHER_CTX_set_padding(&ectx, 0);
++  EVP_CipherInit(&ectx, NULL, ctx->key, iv, mode);
++  EVP_CipherUpdate(&ectx, out, &tmp_csz, in, size);
++  csz = tmp_csz;  
++  out += tmp_csz;
++  EVP_CipherFinal(&ectx, out, &tmp_csz);
++  csz += tmp_csz;
++  EVP_CIPHER_CTX_cleanup(&ectx);
++  assert(size == csz);
++
++  return SQLITE_OK;
++}
++
++int codec_set_kdf_iter(sqlite3* db, int nDb, int kdf_iter, int for_ctx) {
++  struct Db *pDb = &db->aDb[nDb];
++  CODEC_TRACE(("codec_set_kdf_iter: entered db=%d nDb=%d kdf_iter=%d for_ctx=%d\n", db, nDb, kdf_iter, for_ctx));
++
++  if(pDb->pBt) {
++    codec_ctx *ctx;
++    cipher_ctx *c_ctx;
++    sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
++    c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
++
++    c_ctx->kdf_iter = kdf_iter;
++    c_ctx->derive_key = 1;
++
++    if(for_ctx == 2) cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx); 
++    return SQLITE_OK;
++  }
++  return SQLITE_ERROR;
++}
++
++/**
++  * 
++  * when for_ctx == 0 then it will change for read
++  * when for_ctx == 1 then it will change for write
++  * when for_ctx == 2 then it will change for both
++  */
++int codec_set_cipher_name(sqlite3* db, int nDb, const char *cipher_name, int for_ctx) {
++  struct Db *pDb = &db->aDb[nDb];
++  CODEC_TRACE(("codec_set_cipher_name: entered db=%d nDb=%d cipher_name=%s for_ctx=%d\n", db, nDb, cipher_name, for_ctx));
++
++  if(pDb->pBt) {
++    codec_ctx *ctx;
++    cipher_ctx *c_ctx;
++    sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
++    c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
++
++    c_ctx->evp_cipher = (EVP_CIPHER *) EVP_get_cipherbyname(cipher_name);
++    c_ctx->key_sz = EVP_CIPHER_key_length(c_ctx->evp_cipher);
++    c_ctx->iv_sz = EVP_CIPHER_iv_length(c_ctx->evp_cipher);
++    c_ctx->derive_key = 1;
++
++    if(for_ctx == 2) cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx); 
++    return SQLITE_OK;
++  }
++  return SQLITE_ERROR;
++}
++
++int codec_set_pass_key(sqlite3* db, int nDb, const void *zKey, int nKey, int for_ctx) {
++  struct Db *pDb = &db->aDb[nDb];
++  CODEC_TRACE(("codec_set_pass_key: entered db=%d nDb=%d cipher_name=%s nKey=%d for_ctx=%d\n", db, nDb, zKey, nKey, for_ctx));
++  if(pDb->pBt) {
++    codec_ctx *ctx;
++    cipher_ctx *c_ctx;
++    sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
++    c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
++  
++    cipher_ctx_set_pass(c_ctx, zKey, nKey);
++    c_ctx->derive_key = 1;
++
++    if(for_ctx == 2) cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx); 
++    return SQLITE_OK;
++  }
++  return SQLITE_ERROR;
++} 
++
++/*
++ * sqlite3Codec can be called in multiple modes.
++ * encrypt mode - expected to return a pointer to the 
++ *   encrypted data without altering pData.
++ * decrypt mode - expected to return a pointer to pData, with
++ *   the data decrypted in the input buffer
++ */
++void* sqlite3Codec(void *iCtx, void *data, Pgno pgno, int mode) {
++  codec_ctx *ctx = (codec_ctx *) iCtx;
++  int pg_sz = sqlite3BtreeGetPageSize(ctx->pBt);
++  int offset = 0;
++  unsigned char *pData = (unsigned char *) data;
++ 
++  CODEC_TRACE(("sqlite3Codec: entered pgno=%d, mode=%d, ctx->mode_rekey=%d, pg_sz=%d\n", pgno, mode, ctx->mode_rekey, pg_sz));
++
++  /* derive key on first use if necessary */
++  if(ctx->read_ctx->derive_key) {
++    codec_key_derive(ctx, ctx->read_ctx);
++    ctx->read_ctx->derive_key = 0;
++  }
++
++  if(ctx->write_ctx->derive_key) {
++    if(cipher_ctx_cmp(ctx->write_ctx, ctx->read_ctx) == 0) {
++      cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx); // the relevant parameters are the same, just copy read key
++    } else {
++      codec_key_derive(ctx, ctx->write_ctx);
++      ctx->write_ctx->derive_key = 0;
++    }
++  }
++
++
++  if(pgno == 1) offset = FILE_HEADER_SZ; /* adjust starting pointers in data page for header offset on first page*/
++
++  CODEC_TRACE(("sqlite3Codec: switch mode=%d offset=%d\n",  mode, offset));
++  switch(mode) {
++    case 0: /* decrypt */
++    case 2:
++    case 3:
++      if(pgno == 1) memcpy(ctx->buffer, SQLITE_FILE_HEADER, FILE_HEADER_SZ); /* copy file header to the first 16 bytes of the page */ 
++      codec_cipher(ctx->read_ctx, pgno, CIPHER_DECRYPT, pg_sz - offset, pData + offset, ctx->buffer + offset);
++      memcpy(pData, ctx->buffer, pg_sz); /* copy buffer data back to pData and return */
++      return pData;
++      break;
++    case 6: /* encrypt */
++      if(pgno == 1) memcpy(ctx->buffer, ctx->kdf_salt, FILE_HEADER_SZ); /* copy salt to output buffer */ 
++      codec_cipher(ctx->write_ctx, pgno, CIPHER_ENCRYPT, pg_sz - offset, pData + offset, ctx->buffer + offset);
++      return ctx->buffer; /* return persistent buffer data, pData remains intact */
++      break;
++    case 7:
++      if(pgno == 1) memcpy(ctx->buffer, ctx->kdf_salt, FILE_HEADER_SZ); /* copy salt to output buffer */ 
++      codec_cipher(ctx->read_ctx, pgno, CIPHER_ENCRYPT, pg_sz - offset, pData + offset, ctx->buffer + offset);
++      return ctx->buffer; /* return persistent buffer data, pData remains intact */
++      break;
++    default:
++      return pData;
++      break;
++  }
++}
++
++
++SQLITE_PRIVATE int sqlite3CodecAttach(sqlite3* db, int nDb, const void *zKey, int nKey) {
++  struct Db *pDb = &db->aDb[nDb];
++
++  CODEC_TRACE(("sqlite3CodecAttach: entered nDb=%d zKey=%s, nKey=%d\n", nDb, zKey, nKey));
++  activate_openssl();
++  
++  if(nKey && zKey && pDb->pBt) {
++    codec_ctx *ctx;
++    int rc;
++    Pager *pPager = pDb->pBt->pBt->pPager;
++    sqlite3_file *fd;
++
++    ctx = sqlite3Malloc(sizeof(codec_ctx));
++    if(ctx == NULL) return SQLITE_NOMEM;
++    memset(ctx, 0, sizeof(codec_ctx)); /* initialize all pointers and values to 0 */
++
++    ctx->pBt = pDb->pBt; /* assign pointer to database btree structure */
++
++    if((rc = cipher_ctx_init(&ctx->read_ctx)) != SQLITE_OK) return rc; 
++    if((rc = cipher_ctx_init(&ctx->write_ctx)) != SQLITE_OK) return rc; 
++    
++    /* pre-allocate a page buffer of PageSize bytes. This will
++       be used as a persistent buffer for encryption and decryption 
++       operations to avoid overhead of multiple memory allocations*/
++    ctx->buffer = sqlite3Malloc(sqlite3BtreeGetPageSize(ctx->pBt));
++    if(ctx->buffer == NULL) return SQLITE_NOMEM;
++     
++    /* allocate space for salt data. Then read the first 16 bytes 
++       directly off the database file. This is the salt for the
++       key derivation function. If we get a short read allocate
++       a new random salt value */
++    ctx->kdf_salt_sz = FILE_HEADER_SZ;
++    ctx->kdf_salt = sqlite3Malloc(ctx->kdf_salt_sz);
++    if(ctx->kdf_salt == NULL) return SQLITE_NOMEM;
++
++    fd = sqlite3Pager_get_fd(pPager);
++    if(fd == NULL || sqlite3OsRead(fd, ctx->kdf_salt, FILE_HEADER_SZ, 0) != SQLITE_OK) {
++      /* if unable to read the bytes, generate random salt */
++      RAND_pseudo_bytes(ctx->kdf_salt, FILE_HEADER_SZ);
++    }
++
++    sqlite3pager_sqlite3PagerSetCodec(sqlite3BtreePager(pDb->pBt), sqlite3Codec, NULL, sqlite3FreeCodecArg, (void *) ctx);
++
++    codec_set_cipher_name(db, nDb, CIPHER, 0);
++    codec_set_kdf_iter(db, nDb, PBKDF2_ITER, 0);
++    codec_set_pass_key(db, nDb, zKey, nKey, 0);
++    cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx);
++    
++    sqlite3BtreeSetPageSize(ctx->pBt, sqlite3BtreeGetPageSize(ctx->pBt), EVP_MAX_IV_LENGTH, 0);
++  }
++  return SQLITE_OK;
++}
++
++SQLITE_PRIVATE void sqlite3FreeCodecArg(void *pCodecArg) {
++  codec_ctx *ctx = (codec_ctx *) pCodecArg;
++  if(pCodecArg == NULL) return;
++  codec_ctx_free(&ctx); // wipe and free allocated memory for the context 
++}
++
++SQLITE_API void sqlite3_activate_see(const char* in) {
++  /* do nothing, security enhancements are always active */
++}
++
++SQLITE_API int sqlite3_key(sqlite3 *db, const void *pKey, int nKey) {
++  CODEC_TRACE(("sqlite3_key: entered db=%d pKey=%s nKey=%d\n", db, pKey, nKey));
++  /* attach key if db and pKey are not null and nKey is > 0 */
++  if(db && pKey && nKey) {
++    sqlite3CodecAttach(db, 0, pKey, nKey); // operate only on the main db 
++    return SQLITE_OK;
++  }
++  return SQLITE_ERROR;
++}
++
++/* sqlite3_rekey 
++** Given a database, this will reencrypt the database using a new key.
++** There are two possible modes of operation. The first is rekeying
++** an existing database that was not previously encrypted. The second
++** is to change the key on an existing database.
++** 
++** The proposed logic for this function follows:
++** 1. Determine if there is already a key present
++** 2. If there is NOT already a key present, create one and attach a codec (key would be null)
++** 3. Initialize a ctx->rekey parameter of the codec
++** 
++** Note: this will require modifications to the sqlite3Codec to support rekey
++**
++*/
++SQLITE_API int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) {
++  CODEC_TRACE(("sqlite3_rekey: entered db=%d pKey=%s, nKey=%d\n", db, pKey, nKey));
++  activate_openssl();
++  if(db && pKey && nKey) {
++    struct Db *pDb = &db->aDb[0];
++    CODEC_TRACE(("sqlite3_rekey: database pDb=%d\n", pDb));
++    if(pDb->pBt) {
++      codec_ctx *ctx;
++      int rc, page_count;
++      Pgno pgno;
++      PgHdr *page;
++      Pager *pPager = pDb->pBt->pBt->pPager;
++
++      sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
++     
++      if(ctx == NULL) { 
++        CODEC_TRACE(("sqlite3_rekey: no codec attached to db, attaching now\n"));
++        /* there was no codec attached to this database,so attach one now with a null password */
++        sqlite3CodecAttach(db, 0, pKey, nKey);
++        sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
++        
++        /* prepare this setup as if it had already been initialized */
++        RAND_pseudo_bytes(ctx->kdf_salt, ctx->kdf_salt_sz);
++        ctx->read_ctx->key_sz = ctx->read_ctx->iv_sz =  ctx->read_ctx->pass_sz = 0;
++      }
++
++      if(ctx->read_ctx->iv_sz != ctx->write_ctx->iv_sz) {
++        char *error;
++        CODEC_TRACE(("sqlite3_rekey: updating page size for iv_sz change from %d to %d\n", ctx->read_ctx->iv_sz, ctx->write_ctx->iv_sz));
++        db->nextPagesize = sqlite3BtreeGetPageSize(pDb->pBt);
++        pDb->pBt->pBt->pageSizeFixed = 0; /* required for sqlite3BtreeSetPageSize to modify pagesize setting */
++        sqlite3BtreeSetPageSize(pDb->pBt, db->nextPagesize, EVP_MAX_IV_LENGTH, 0);
++        sqlite3RunVacuum(&error, db);
++      }
++
++      codec_set_pass_key(db, 0, pKey, nKey, 1);
++      ctx->mode_rekey = 1; 
++    
++      /* do stuff here to rewrite the database 
++      ** 1. Create a transaction on the database
++      ** 2. Iterate through each page, reading it and then writing it.
++      ** 3. If that goes ok then commit and put ctx->rekey into ctx->key
++      **    note: don't deallocate rekey since it may be used in a subsequent iteration 
++      */
++      rc = sqlite3BtreeBeginTrans(pDb->pBt, 1); /* begin write transaction */
++      sqlite3PagerPagecount(pPager, &page_count);
++      for(pgno = 1; rc == SQLITE_OK && pgno <= page_count; pgno++) { /* pgno's start at 1 see pager.c:pagerAcquire */
++        if(!sqlite3pager_is_mj_pgno(pPager, pgno)) { /* skip this page (see pager.c:pagerAcquire for reasoning) */
++          rc = sqlite3PagerGet(pPager, pgno, &page);
++          if(rc == SQLITE_OK) { /* write page see pager_incr_changecounter for example */
++            rc = sqlite3PagerWrite(page);
++            //printf("sqlite3PagerWrite(%d)\n", pgno);
++            if(rc == SQLITE_OK) {
++              sqlite3PagerUnref(page);
++            } 
++          } 
++        } 
++      }
++
++      /* if commit was successful commit and copy the rekey data to current key, else rollback to release locks */
++      if(rc == SQLITE_OK) { 
++        CODEC_TRACE(("sqlite3_rekey: committing\n"));
++        db->nextPagesize = sqlite3BtreeGetPageSize(pDb->pBt);
++        rc = sqlite3BtreeCommit(pDb->pBt); 
++        cipher_ctx_copy(ctx->read_ctx, ctx->write_ctx);
++      } else {
++        CODEC_TRACE(("sqlite3_rekey: rollback\n"));
++        sqlite3BtreeRollback(pDb->pBt);
++      }
++
++      ctx->mode_rekey = 0;
++    }
++    return SQLITE_OK;
++  }
++  return SQLITE_ERROR;
++}
++
++SQLITE_PRIVATE void sqlite3CodecGetKey(sqlite3* db, int nDb, void **zKey, int *nKey) {
++  struct Db *pDb = &db->aDb[nDb];
++  CODEC_TRACE(("sqlite3CodecGetKey: entered db=%d, nDb=%d\n", db, nDb));
++  
++  if( pDb->pBt ) {
++    codec_ctx *ctx;
++    sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
++
++    if(ctx) { /* if the codec has an attached codec_context user the raw key data */
++      *zKey = ctx->read_ctx->pass;
++      *nKey = ctx->read_ctx->pass_sz;
++    } else {
++      *zKey = NULL;
++      *nKey = 0;
++    }
++  }
++}
++
++
++/* END CRYPTO */
++#endif
++
++/************** End of crypto.c **********************************************/
+ /************** Begin file global.c ******************************************/
+ /*
+ ** 2008 June 13
+@@ -40807,11 +42121,40 @@
+   CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
+   return aData;
+ }
+-#endif /* SQLITE_HAS_CODEC */
++#endif /* SQLITE_HAS_CODEC */
++
++#endif /* !SQLITE_OMIT_WAL */
++
++#endif /* SQLITE_OMIT_DISKIO */
++
++/* BEGIN CRYPTO */
++#ifdef SQLITE_HAS_CODEC
++SQLITE_PRIVATE void sqlite3pager_get_codec(Pager *pPager, void **ctx) {
++  *ctx = pPager->pCodec;
++}
++
++SQLITE_PRIVATE int sqlite3pager_is_mj_pgno(Pager *pPager, Pgno pgno) {
++  return (PAGER_MJ_PGNO(pPager) == pgno) ? 1 : 0;
++}
+ 
+-#endif /* !SQLITE_OMIT_WAL */
++SQLITE_PRIVATE sqlite3_file *sqlite3Pager_get_fd(Pager *pPager) {
++  return (isOpen(pPager->fd)) ? pPager->fd : NULL;
++}
++
++SQLITE_PRIVATE void sqlite3pager_sqlite3PagerSetCodec(
++  Pager *pPager,
++  void *(*xCodec)(void*,void*,Pgno,int),
++  void (*xCodecSizeChng)(void*,int,int),
++  void (*xCodecFree)(void*),
++  void *pCodec
++){
++  sqlite3PagerSetCodec(pPager, xCodec, xCodecSizeChng, xCodecFree, pCodec); 
++}
++
++
++#endif
++/* END CRYPTO */
+ 
+-#endif /* SQLITE_OMIT_DISKIO */
+ 
+ /************** End of pager.c ***********************************************/
+ /************** Begin file wal.c *********************************************/
+@@ -43340,854 +44683,208 @@
+ #if defined(SQLITE_HAS_CODEC)
+       if( (pData = sqlite3PagerCodec(pLast))==0 ) return SQLITE_NOMEM;
+ #else
+-      pData = pLast->pData;
+-#endif
+-      walEncodeFrame(pWal, pLast->pgno, nTruncate, pData, aFrame);
+-      /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
+-      rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
+-      if( rc!=SQLITE_OK ){
+-        return rc;
+-      }
+-      iOffset += WAL_FRAME_HDRSIZE;
+-      rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset); 
+-      if( rc!=SQLITE_OK ){
+-        return rc;
+-      }
+-      nLast++;
+-      iOffset += szPage;
+-    }
+-
+-    rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
+-  }
+-
+-  /* Append data to the wal-index. It is not necessary to lock the 
+-  ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index
+-  ** guarantees that there are no other writers, and no data that may
+-  ** be in use by existing readers is being overwritten.
+-  */
+-  iFrame = pWal->hdr.mxFrame;
+-  for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
+-    iFrame++;
+-    rc = walIndexAppend(pWal, iFrame, p->pgno);
+-  }
+-  while( nLast>0 && rc==SQLITE_OK ){
+-    iFrame++;
+-    nLast--;
+-    rc = walIndexAppend(pWal, iFrame, pLast->pgno);
+-  }
+-
+-  if( rc==SQLITE_OK ){
+-    /* Update the private copy of the header. */
+-    pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
+-    testcase( szPage<=32768 );
+-    testcase( szPage>=65536 );
+-    pWal->hdr.mxFrame = iFrame;
+-    if( isCommit ){
+-      pWal->hdr.iChange++;
+-      pWal->hdr.nPage = nTruncate;
+-    }
+-    /* If this is a commit, update the wal-index header too. */
+-    if( isCommit ){
+-      walIndexWriteHdr(pWal);
+-      pWal->iCallback = iFrame;
+-    }
+-  }
+-
+-  WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
+-  return rc;
+-}
+-
+-/* 
+-** This routine is called to implement sqlite3_wal_checkpoint() and
+-** related interfaces.
+-**
+-** Obtain a CHECKPOINT lock and then backfill as much information as
+-** we can from WAL into the database.
+-*/
+-SQLITE_PRIVATE int sqlite3WalCheckpoint(
+-  Wal *pWal,                      /* Wal connection */
+-  int sync_flags,                 /* Flags to sync db file with (or 0) */
+-  int nBuf,                       /* Size of temporary buffer */
+-  u8 *zBuf                        /* Temporary buffer to use */
+-){
+-  int rc;                         /* Return code */
+-  int isChanged = 0;              /* True if a new wal-index header is loaded */
+-
+-  assert( pWal->ckptLock==0 );
+-
+-  WALTRACE(("WAL%p: checkpoint begins\n", pWal));
+-  rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
+-  if( rc ){
+-    /* Usually this is SQLITE_BUSY meaning that another thread or process
+-    ** is already running a checkpoint, or maybe a recovery.  But it might
+-    ** also be SQLITE_IOERR. */
+-    return rc;
+-  }
+-  pWal->ckptLock = 1;
+-
+-  /* Copy data from the log to the database file. */
+-  rc = walIndexReadHdr(pWal, &isChanged);
+-  if( rc==SQLITE_OK ){
+-    rc = walCheckpoint(pWal, sync_flags, nBuf, zBuf);
+-  }
+-  if( isChanged ){
+-    /* If a new wal-index header was loaded before the checkpoint was 
+-    ** performed, then the pager-cache associated with pWal is now
+-    ** out of date. So zero the cached wal-index header to ensure that
+-    ** next time the pager opens a snapshot on this database it knows that
+-    ** the cache needs to be reset.
+-    */
+-    memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
+-  }
+-
+-  /* Release the locks. */
+-  walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
+-  pWal->ckptLock = 0;
+-  WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
+-  return rc;
+-}
+-
+-/* Return the value to pass to a sqlite3_wal_hook callback, the
+-** number of frames in the WAL at the point of the last commit since
+-** sqlite3WalCallback() was called.  If no commits have occurred since
+-** the last call, then return 0.
+-*/
+-SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
+-  u32 ret = 0;
+-  if( pWal ){
+-    ret = pWal->iCallback;
+-    pWal->iCallback = 0;
+-  }
+-  return (int)ret;
+-}
+-
+-/*
+-** This function is called to change the WAL subsystem into or out
+-** of locking_mode=EXCLUSIVE.
+-**
+-** If op is zero, then attempt to change from locking_mode=EXCLUSIVE
+-** into locking_mode=NORMAL.  This means that we must acquire a lock
+-** on the pWal->readLock byte.  If the WAL is already in locking_mode=NORMAL
+-** or if the acquisition of the lock fails, then return 0.  If the
+-** transition out of exclusive-mode is successful, return 1.  This
+-** operation must occur while the pager is still holding the exclusive
+-** lock on the main database file.
+-**
+-** If op is one, then change from locking_mode=NORMAL into 
+-** locking_mode=EXCLUSIVE.  This means that the pWal->readLock must
+-** be released.  Return 1 if the transition is made and 0 if the
+-** WAL is already in exclusive-locking mode - meaning that this
+-** routine is a no-op.  The pager must already hold the exclusive lock
+-** on the main database file before invoking this operation.
+-**
+-** If op is negative, then do a dry-run of the op==1 case but do
+-** not actually change anything.  The pager uses this to see if it
+-** should acquire the database exclusive lock prior to invoking
+-** the op==1 case.
+-*/
+-SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
+-  int rc;
+-  assert( pWal->writeLock==0 );
+-
+-  /* pWal->readLock is usually set, but might be -1 if there was a 
+-  ** prior error while attempting to acquire are read-lock. This cannot 
+-  ** happen if the connection is actually in exclusive mode (as no xShmLock
+-  ** locks are taken in this case). Nor should the pager attempt to
+-  ** upgrade to exclusive-mode following such an error.
+-  */
+-  assert( pWal->readLock>=0 || pWal->lockError );
+-  assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
+-
+-  if( op==0 ){
+-    if( pWal->exclusiveMode ){
+-      pWal->exclusiveMode = 0;
+-      if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){
+-        pWal->exclusiveMode = 1;
+-      }
+-      rc = pWal->exclusiveMode==0;
+-    }else{
+-      /* Already in locking_mode=NORMAL */
+-      rc = 0;
+-    }
+-  }else if( op>0 ){
+-    assert( pWal->exclusiveMode==0 );
+-    assert( pWal->readLock>=0 );
+-    walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
+-    pWal->exclusiveMode = 1;
+-    rc = 1;
+-  }else{
+-    rc = pWal->exclusiveMode==0;
+-  }
+-  return rc;
+-}
+-
+-#endif /* #ifndef SQLITE_OMIT_WAL */
+-
+-/************** End of wal.c *************************************************/
+-/************** Begin file btmutex.c *****************************************/
+-/*
+-** 2007 August 27
+-**
+-** The author disclaims copyright to this source code.  In place of
+-** a legal notice, here is a blessing:
+-**
+-**    May you do good and not evil.
+-**    May you find forgiveness for yourself and forgive others.
+-**    May you share freely, never taking more than you give.
+-**
+-*************************************************************************
+-**
+-** This file contains code used to implement mutexes on Btree objects.
+-** This code really belongs in btree.c.  But btree.c is getting too
+-** big and we want to break it down some.  This packaged seemed like
+-** a good breakout.
+-*/
+-/************** Include btreeInt.h in the middle of btmutex.c ****************/
+-/************** Begin file btreeInt.h ****************************************/
+-/*
+-** 2004 April 6
+-**
+-** The author disclaims copyright to this source code.  In place of
+-** a legal notice, here is a blessing:
+-**
+-**    May you do good and not evil.
+-**    May you find forgiveness for yourself and forgive others.
+-**    May you share freely, never taking more than you give.
+-**
+-*************************************************************************
+-** This file implements a external (disk-based) database using BTrees.
+-** For a detailed discussion of BTrees, refer to
+-**
+-**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
+-**     "Sorting And Searching", pages 473-480. Addison-Wesley
+-**     Publishing Company, Reading, Massachusetts.
+-**
+-** The basic idea is that each page of the file contains N database
+-** entries and N+1 pointers to subpages.
+-**
+-**   ----------------------------------------------------------------
+-**   |  Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) |
+-**   ----------------------------------------------------------------
+-**
+-** All of the keys on the page that Ptr(0) points to have values less
+-** than Key(0).  All of the keys on page Ptr(1) and its subpages have
+-** values greater than Key(0) and less than Key(1).  All of the keys
+-** on Ptr(N) and its subpages have values greater than Key(N-1).  And
+-** so forth.
+-**
+-** Finding a particular key requires reading O(log(M)) pages from the 
+-** disk where M is the number of entries in the tree.
+-**
+-** In this implementation, a single file can hold one or more separate 
+-** BTrees.  Each BTree is identified by the index of its root page.  The
+-** key and data for any entry are combined to form the "payload".  A
+-** fixed amount of payload can be carried directly on the database
+-** page.  If the payload is larger than the preset amount then surplus
+-** bytes are stored on overflow pages.  The payload for an entry
+-** and the preceding pointer are combined to form a "Cell".  Each 
+-** page has a small header which contains the Ptr(N) pointer and other
+-** information such as the size of key and data.
+-**
+-** FORMAT DETAILS
+-**
+-** The file is divided into pages.  The first page is called page 1,
+-** the second is page 2, and so forth.  A page number of zero indicates
+-** "no such page".  The page size can be any power of 2 between 512 and 65536.
+-** Each page can be either a btree page, a freelist page, an overflow
+-** page, or a pointer-map page.
+-**
+-** The first page is always a btree page.  The first 100 bytes of the first
+-** page contain a special header (the "file header") that describes the file.
+-** The format of the file header is as follows:
+-**
+-**   OFFSET   SIZE    DESCRIPTION
+-**      0      16     Header string: "SQLite format 3\000"
+-**     16       2     Page size in bytes.  
+-**     18       1     File format write version
+-**     19       1     File format read version
+-**     20       1     Bytes of unused space at the end of each page
+-**     21       1     Max embedded payload fraction
+-**     22       1     Min embedded payload fraction
+-**     23       1     Min leaf payload fraction
+-**     24       4     File change counter
+-**     28       4     Reserved for future use
+-**     32       4     First freelist page
+-**     36       4     Number of freelist pages in the file
+-**     40      60     15 4-byte meta values passed to higher layers
+-**
+-**     40       4     Schema cookie
+-**     44       4     File format of schema layer
+-**     48       4     Size of page cache
+-**     52       4     Largest root-page (auto/incr_vacuum)
+-**     56       4     1=UTF-8 2=UTF16le 3=UTF16be
+-**     60       4     User version
+-**     64       4     Incremental vacuum mode
+-**     68       4     unused
+-**     72       4     unused
+-**     76       4     unused
+-**
+-** All of the integer values are big-endian (most significant byte first).
+-**
+-** The file change counter is incremented when the database is changed
+-** This counter allows other processes to know when the file has changed
+-** and thus when they need to flush their cache.
+-**
+-** The max embedded payload fraction is the amount of the total usable
+-** space in a page that can be consumed by a single cell for standard
+-** B-tree (non-LEAFDATA) tables.  A value of 255 means 100%.  The default
+-** is to limit the maximum cell size so that at least 4 cells will fit
+-** on one page.  Thus the default max embedded payload fraction is 64.
+-**
+-** If the payload for a cell is larger than the max payload, then extra
+-** payload is spilled to overflow pages.  Once an overflow page is allocated,
+-** as many bytes as possible are moved into the overflow pages without letting
+-** the cell size drop below the min embedded payload fraction.
+-**
+-** The min leaf payload fraction is like the min embedded payload fraction
+-** except that it applies to leaf nodes in a LEAFDATA tree.  The maximum
+-** payload fraction for a LEAFDATA tree is always 100% (or 255) and it
+-** not specified in the header.
+-**
+-** Each btree pages is divided into three sections:  The header, the
+-** cell pointer array, and the cell content area.  Page 1 also has a 100-byte
+-** file header that occurs before the page header.
+-**
+-**      |----------------|
+-**      | file header    |   100 bytes.  Page 1 only.
+-**      |----------------|
+-**      | page header    |   8 bytes for leaves.  12 bytes for interior nodes
+-**      |----------------|
+-**      | cell pointer   |   |  2 bytes per cell.  Sorted order.
+-**      | array          |   |  Grows downward
+-**      |                |   v
+-**      |----------------|
+-**      | unallocated    |
+-**      | space          |
+-**      |----------------|   ^  Grows upwards
+-**      | cell content   |   |  Arbitrary order interspersed with freeblocks.
+-**      | area           |   |  and free space fragments.
+-**      |----------------|
+-**
+-** The page headers looks like this:
+-**
+-**   OFFSET   SIZE     DESCRIPTION
+-**      0       1      Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf
+-**      1       2      byte offset to the first freeblock
+-**      3       2      number of cells on this page
+-**      5       2      first byte of the cell content area
+-**      7       1      number of fragmented free bytes
+-**      8       4      Right child (the Ptr(N) value).  Omitted on leaves.
+-**
+-** The flags define the format of this btree page.  The leaf flag means that
+-** this page has no children.  The zerodata flag means that this page carries
+-** only keys and no data.  The intkey flag means that the key is a integer
+-** which is stored in the key size entry of the cell header rather than in
+-** the payload area.
+-**
+-** The cell pointer array begins on the first byte after the page header.
+-** The cell pointer array contains zero or more 2-byte numbers which are
+-** offsets from the beginning of the page to the cell content in the cell
+-** content area.  The cell pointers occur in sorted order.  The system strives
+-** to keep free space after the last cell pointer so that new cells can
+-** be easily added without having to defragment the page.
+-**
+-** Cell content is stored at the very end of the page and grows toward the
+-** beginning of the page.
+-**
+-** Unused space within the cell content area is collected into a linked list of
+-** freeblocks.  Each freeblock is at least 4 bytes in size.  The byte offset
+-** to the first freeblock is given in the header.  Freeblocks occur in
+-** increasing order.  Because a freeblock must be at least 4 bytes in size,
+-** any group of 3 or fewer unused bytes in the cell content area cannot
+-** exist on the freeblock chain.  A group of 3 or fewer free bytes is called
+-** a fragment.  The total number of bytes in all fragments is recorded.
+-** in the page header at offset 7.
+-**
+-**    SIZE    DESCRIPTION
+-**      2     Byte offset of the next freeblock
+-**      2     Bytes in this freeblock
+-**
+-** Cells are of variable length.  Cells are stored in the cell content area at
+-** the end of the page.  Pointers to the cells are in the cell pointer array
+-** that immediately follows the page header.  Cells is not necessarily
+-** contiguous or in order, but cell pointers are contiguous and in order.
+-**
+-** Cell content makes use of variable length integers.  A variable
+-** length integer is 1 to 9 bytes where the lower 7 bits of each 
+-** byte are used.  The integer consists of all bytes that have bit 8 set and
+-** the first byte with bit 8 clear.  The most significant byte of the integer
+-** appears first.  A variable-length integer may not be more than 9 bytes long.
+-** As a special case, all 8 bytes of the 9th byte are used as data.  This
+-** allows a 64-bit integer to be encoded in 9 bytes.
+-**
+-**    0x00                      becomes  0x00000000
+-**    0x7f                      becomes  0x0000007f
+-**    0x81 0x00                 becomes  0x00000080
+-**    0x82 0x00                 becomes  0x00000100
+-**    0x80 0x7f                 becomes  0x0000007f
+-**    0x8a 0x91 0xd1 0xac 0x78  becomes  0x12345678
+-**    0x81 0x81 0x81 0x81 0x01  becomes  0x10204081
+-**
+-** Variable length integers are used for rowids and to hold the number of
+-** bytes of key and data in a btree cell.
+-**
+-** The content of a cell looks like this:
+-**
+-**    SIZE    DESCRIPTION
+-**      4     Page number of the left child. Omitted if leaf flag is set.
+-**     var    Number of bytes of data. Omitted if the zerodata flag is set.
+-**     var    Number of bytes of key. Or the key itself if intkey flag is set.
+-**      *     Payload
+-**      4     First page of the overflow chain.  Omitted if no overflow
+-**
+-** Overflow pages form a linked list.  Each page except the last is completely
+-** filled with data (pagesize - 4 bytes).  The last page can have as little
+-** as 1 byte of data.
+-**
+-**    SIZE    DESCRIPTION
+-**      4     Page number of next overflow page
+-**      *     Data
+-**
+-** Freelist pages come in two subtypes: trunk pages and leaf pages.  The
+-** file header points to the first in a linked list of trunk page.  Each trunk
+-** page points to multiple leaf pages.  The content of a leaf page is
+-** unspecified.  A trunk page looks like this:
+-**
+-**    SIZE    DESCRIPTION
+-**      4     Page number of next trunk page
+-**      4     Number of leaf pointers on this page
+-**      *     zero or more pages numbers of leaves
+-*/
+-
+-
+-/* The following value is the maximum cell size assuming a maximum page
+-** size give above.
+-*/
+-#define MX_CELL_SIZE(pBt)  (pBt->pageSize-8)
+-
+-/* The maximum number of cells on a single page of the database.  This
+-** assumes a minimum cell size of 6 bytes  (4 bytes for the cell itself
+-** plus 2 bytes for the index to the cell in the page header).  Such
+-** small cells will be rare, but they are possible.
+-*/
+-#define MX_CELL(pBt) ((pBt->pageSize-8)/6)
+-
+-/* Forward declarations */
+-typedef struct MemPage MemPage;
+-typedef struct BtLock BtLock;
+-
+-/*
+-** This is a magic string that appears at the beginning of every
+-** SQLite database in order to identify the file as a real database.
+-**
+-** You can change this value at compile-time by specifying a
+-** -DSQLITE_FILE_HEADER="..." on the compiler command-line.  The
+-** header must be exactly 16 bytes including the zero-terminator so
+-** the string itself should be 15 characters long.  If you change
+-** the header, then your custom library will not be able to read 
+-** databases generated by the standard tools and the standard tools
+-** will not be able to read databases created by your custom library.
+-*/
+-#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
+-#  define SQLITE_FILE_HEADER "SQLite format 3"
+-#endif
+-
+-/*
+-** Page type flags.  An ORed combination of these flags appear as the
+-** first byte of on-disk image of every BTree page.
+-*/
+-#define PTF_INTKEY    0x01
+-#define PTF_ZERODATA  0x02
+-#define PTF_LEAFDATA  0x04
+-#define PTF_LEAF      0x08
+-
+-/*
+-** As each page of the file is loaded into memory, an instance of the following
+-** structure is appended and initialized to zero.  This structure stores
+-** information about the page that is decoded from the raw file page.
+-**
+-** The pParent field points back to the parent page.  This allows us to
+-** walk up the BTree from any leaf to the root.  Care must be taken to
+-** unref() the parent page pointer when this page is no longer referenced.
+-** The pageDestructor() routine handles that chore.
+-**
+-** Access to all fields of this structure is controlled by the mutex
+-** stored in MemPage.pBt->mutex.
+-*/
+-struct MemPage {
+-  u8 isInit;           /* True if previously initialized. MUST BE FIRST! */
+-  u8 nOverflow;        /* Number of overflow cell bodies in aCell[] */
+-  u8 intKey;           /* True if intkey flag is set */
+-  u8 leaf;             /* True if leaf flag is set */
+-  u8 hasData;          /* True if this page stores data */
+-  u8 hdrOffset;        /* 100 for page 1.  0 otherwise */
+-  u8 childPtrSize;     /* 0 if leaf==1.  4 if leaf==0 */
+-  u16 maxLocal;        /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
+-  u16 minLocal;        /* Copy of BtShared.minLocal or BtShared.minLeaf */
+-  u16 cellOffset;      /* Index in aData of first cell pointer */
+-  u16 nFree;           /* Number of free bytes on the page */
+-  u16 nCell;           /* Number of cells on this page, local and ovfl */
+-  u16 maskPage;        /* Mask for page offset */
+-  struct _OvflCell {   /* Cells that will not fit on aData[] */
+-    u8 *pCell;          /* Pointers to the body of the overflow cell */
+-    u16 idx;            /* Insert this cell before idx-th non-overflow cell */
+-  } aOvfl[5];
+-  BtShared *pBt;       /* Pointer to BtShared that this page is part of */
+-  u8 *aData;           /* Pointer to disk image of the page data */
+-  DbPage *pDbPage;     /* Pager page handle */
+-  Pgno pgno;           /* Page number for this page */
+-};
++      pData = pLast->pData;
++#endif
++      walEncodeFrame(pWal, pLast->pgno, nTruncate, pData, aFrame);
++      /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
++      rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
++      if( rc!=SQLITE_OK ){
++        return rc;
++      }
++      iOffset += WAL_FRAME_HDRSIZE;
++      rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset); 
++      if( rc!=SQLITE_OK ){
++        return rc;
++      }
++      nLast++;
++      iOffset += szPage;
++    }
+ 
+-/*
+-** 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)
++    rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
++  }
+ 
+-/*
+-** A linked list of the following structures is stored at BtShared.pLock.
+-** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor 
+-** is opened on the table with root page BtShared.iTable. Locks are removed
+-** from this list when a transaction is committed or rolled back, or when
+-** a btree handle is closed.
+-*/
+-struct BtLock {
+-  Btree *pBtree;        /* Btree handle holding this lock */
+-  Pgno iTable;          /* Root page of table */
+-  u8 eLock;             /* READ_LOCK or WRITE_LOCK */
+-  BtLock *pNext;        /* Next in BtShared.pLock list */
+-};
++  /* Append data to the wal-index. It is not necessary to lock the 
++  ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index
++  ** guarantees that there are no other writers, and no data that may
++  ** be in use by existing readers is being overwritten.
++  */
++  iFrame = pWal->hdr.mxFrame;
++  for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
++    iFrame++;
++    rc = walIndexAppend(pWal, iFrame, p->pgno);
++  }
++  while( nLast>0 && rc==SQLITE_OK ){
++    iFrame++;
++    nLast--;
++    rc = walIndexAppend(pWal, iFrame, pLast->pgno);
++  }
+ 
+-/* Candidate values for BtLock.eLock */
+-#define READ_LOCK     1
+-#define WRITE_LOCK    2
++  if( rc==SQLITE_OK ){
++    /* Update the private copy of the header. */
++    pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
++    testcase( szPage<=32768 );
++    testcase( szPage>=65536 );
++    pWal->hdr.mxFrame = iFrame;
++    if( isCommit ){
++      pWal->hdr.iChange++;
++      pWal->hdr.nPage = nTruncate;
++    }
++    /* If this is a commit, update the wal-index header too. */
++    if( isCommit ){
++      walIndexWriteHdr(pWal);
++      pWal->iCallback = iFrame;
++    }
++  }
+ 
+-/* A Btree handle
+-**
+-** A database connection contains a pointer to an instance of
+-** this object for every database file that it has open.  This structure
+-** is opaque to the database connection.  The database connection cannot
+-** see the internals of this structure and only deals with pointers to
+-** this structure.
+-**
+-** For some database files, the same underlying database cache might be 
+-** shared between multiple connections.  In that case, each connection
+-** has it own instance of this object.  But each instance of this object
+-** points to the same BtShared object.  The database cache and the
+-** schema associated with the database file are all contained within
+-** the BtShared object.
+-**
+-** All fields in this structure are accessed under sqlite3.mutex.
+-** The pBt pointer itself may not be changed while there exists cursors 
+-** in the referenced BtShared that point back to this Btree since those
+-** cursors have to do go through this Btree to find their BtShared and
+-** they often do so without holding sqlite3.mutex.
+-*/
+-struct Btree {
+-  sqlite3 *db;       /* The database connection holding this btree */
+-  BtShared *pBt;     /* Sharable content of this btree */
+-  u8 inTrans;        /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
+-  u8 sharable;       /* True if we can share pBt with another db */
+-  u8 locked;         /* True if db currently has pBt locked */
+-  int wantToLock;    /* Number of nested calls to sqlite3BtreeEnter() */
+-  int nBackup;       /* Number of backup operations reading this btree */
+-  Btree *pNext;      /* List of other sharable Btrees from the same db */
+-  Btree *pPrev;      /* Back pointer of the same list */
+-#ifndef SQLITE_OMIT_SHARED_CACHE
+-  BtLock lock;       /* Object used to lock page 1 */
+-#endif
+-};
++  WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
++  return rc;
++}
+ 
+-/*
+-** Btree.inTrans may take one of the following values.
++/* 
++** This routine is called to implement sqlite3_wal_checkpoint() and
++** related interfaces.
+ **
+-** If the shared-data extension is enabled, there may be multiple users
+-** of the Btree structure. At most one of these may open a write transaction,
+-** but any number may have active read transactions.
++** Obtain a CHECKPOINT lock and then backfill as much information as
++** we can from WAL into the database.
+ */
+-#define TRANS_NONE  0
+-#define TRANS_READ  1
+-#define TRANS_WRITE 2
++SQLITE_PRIVATE int sqlite3WalCheckpoint(
++  Wal *pWal,                      /* Wal connection */
++  int sync_flags,                 /* Flags to sync db file with (or 0) */
++  int nBuf,                       /* Size of temporary buffer */
++  u8 *zBuf                        /* Temporary buffer to use */
++){
++  int rc;                         /* Return code */
++  int isChanged = 0;              /* True if a new wal-index header is loaded */
+ 
+-/*
+-** An instance of this object represents a single database file.
+-** 
+-** A single database file can be in use as the same time by two
+-** or more database connections.  When two or more connections are
+-** sharing the same database file, each connection has it own
+-** private Btree object for the file and each of those Btrees points
+-** to this one BtShared object.  BtShared.nRef is the number of
+-** connections currently sharing this database file.
+-**
+-** Fields in this structure are accessed under the BtShared.mutex
+-** mutex, except for nRef and pNext which are accessed under the
+-** global SQLITE_MUTEX_STATIC_MASTER mutex.  The pPager field
+-** may not be modified once it is initially set as long as nRef>0.
+-** The pSchema field may be set once under BtShared.mutex and
+-** thereafter is unchanged as long as nRef>0.
+-**
+-** isPending:
+-**
+-**   If a BtShared client fails to obtain a write-lock on a database
+-**   table (because there exists one or more read-locks on the table),
+-**   the shared-cache enters 'pending-lock' state and isPending is
+-**   set to true.
+-**
+-**   The shared-cache leaves the 'pending lock' state when either of
+-**   the following occur:
+-**
+-**     1) The current writer (BtShared.pWriter) concludes its transaction, OR
+-**     2) The number of locks held by other connections drops to zero.
+-**
+-**   while in the 'pending-lock' state, no connection may start a new
+-**   transaction.
+-**
+-**   This feature is included to help prevent writer-starvation.
+-*/
+-struct BtShared {
+-  Pager *pPager;        /* The page cache */
+-  sqlite3 *db;          /* Database connection currently using this Btree */
+-  BtCursor *pCursor;    /* A list of all open cursors */
+-  MemPage *pPage1;      /* First page of the database */
+-  u8 readOnly;          /* True if the underlying file is readonly */
+-  u8 pageSizeFixed;     /* True if the page size can no longer be changed */
+-  u8 secureDelete;      /* True if secure_delete is enabled */
+-  u8 initiallyEmpty;    /* Database is empty at start of transaction */
+-#ifndef SQLITE_OMIT_AUTOVACUUM
+-  u8 autoVacuum;        /* True if auto-vacuum is enabled */
+-  u8 incrVacuum;        /* True if incr-vacuum is enabled */
+-#endif
+-  u16 maxLocal;         /* Maximum local payload in non-LEAFDATA tables */
+-  u16 minLocal;         /* Minimum local payload in non-LEAFDATA tables */
+-  u16 maxLeaf;          /* Maximum local payload in a LEAFDATA table */
+-  u16 minLeaf;          /* Minimum local payload in a LEAFDATA table */
+-  u8 inTransaction;     /* Transaction state */
+-  u8 doNotUseWAL;       /* If true, do not open write-ahead-log file */
+-  u32 pageSize;         /* Total number of bytes on a page */
+-  u32 usableSize;       /* Number of usable bytes on each page */
+-  int nTransaction;     /* Number of open transactions (read + write) */
+-  u32 nPage;            /* Number of pages in the database */
+-  void *pSchema;        /* Pointer to space allocated by sqlite3BtreeSchema() */
+-  void (*xFreeSchema)(void*);  /* Destructor for BtShared.pSchema */
+-  sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */
+-  Bitvec *pHasContent;  /* Set of pages moved to free-list this transaction */
+-#ifndef SQLITE_OMIT_SHARED_CACHE
+-  int nRef;             /* Number of references to this structure */
+-  BtShared *pNext;      /* Next on a list of sharable BtShared structs */
+-  BtLock *pLock;        /* List of locks held on this shared-btree struct */
+-  Btree *pWriter;       /* Btree with currently open write transaction */
+-  u8 isExclusive;       /* True if pWriter has an EXCLUSIVE lock on the db */
+-  u8 isPending;         /* If waiting for read-locks to clear */
+-#endif
+-  u8 *pTmpSpace;        /* BtShared.pageSize bytes of space for tmp use */
+-};
++  assert( pWal->ckptLock==0 );
+ 
+-/*
+-** An instance of the following structure is used to hold information
+-** about a cell.  The parseCellPtr() function fills in this structure
+-** based on information extract from the raw disk page.
+-*/
+-typedef struct CellInfo CellInfo;
+-struct CellInfo {
+-  u8 *pCell;     /* Pointer to the start of cell content */
+-  i64 nKey;      /* The key for INTKEY tables, or number of bytes in key */
+-  u32 nData;     /* Number of bytes of data */
+-  u32 nPayload;  /* Total amount of payload */
+-  u16 nHeader;   /* Size of the cell content header in bytes */
+-  u16 nLocal;    /* Amount of payload held locally */
+-  u16 iOverflow; /* Offset to overflow page number.  Zero if no overflow */
+-  u16 nSize;     /* Size of the cell content on the main b-tree page */
+-};
++  WALTRACE(("WAL%p: checkpoint begins\n", pWal));
++  rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
++  if( rc ){
++    /* Usually this is SQLITE_BUSY meaning that another thread or process
++    ** is already running a checkpoint, or maybe a recovery.  But it might
++    ** also be SQLITE_IOERR. */
++    return rc;
++  }
++  pWal->ckptLock = 1;
+ 
+-/*
+-** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than
+-** this will be declared corrupt. This value is calculated based on a
+-** maximum database size of 2^31 pages a minimum fanout of 2 for a
+-** root-node and 3 for all other internal nodes.
+-**
+-** If a tree that appears to be taller than this is encountered, it is
+-** assumed that the database is corrupt.
+-*/
+-#define BTCURSOR_MAX_DEPTH 20
++  /* Copy data from the log to the database file. */
++  rc = walIndexReadHdr(pWal, &isChanged);
++  if( rc==SQLITE_OK ){
++    rc = walCheckpoint(pWal, sync_flags, nBuf, zBuf);
++  }
++  if( isChanged ){
++    /* If a new wal-index header was loaded before the checkpoint was 
++    ** performed, then the pager-cache associated with pWal is now
++    ** out of date. So zero the cached wal-index header to ensure that
++    ** next time the pager opens a snapshot on this database it knows that
++    ** the cache needs to be reset.
++    */
++    memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
++  }
+ 
+-/*
+-** A cursor is a pointer to a particular entry within a particular
+-** b-tree within a database file.
+-**
+-** The entry is identified by its MemPage and the index in
+-** MemPage.aCell[] of the entry.
+-**
+-** A single database file can shared by two more database connections,
+-** but cursors cannot be shared.  Each cursor is associated with a
+-** particular database connection identified BtCursor.pBtree.db.
+-**
+-** Fields in this structure are accessed under the BtShared.mutex
+-** found at self->pBt->mutex. 
++  /* Release the locks. */
++  walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
++  pWal->ckptLock = 0;
++  WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
++  return rc;
++}
++
++/* Return the value to pass to a sqlite3_wal_hook callback, the
++** number of frames in the WAL at the point of the last commit since
++** sqlite3WalCallback() was called.  If no commits have occurred since
++** the last call, then return 0.
+ */
+-struct BtCursor {
+-  Btree *pBtree;            /* The Btree to which this cursor belongs */
+-  BtShared *pBt;            /* The BtShared this cursor points to */
+-  BtCursor *pNext, *pPrev;  /* Forms a linked list of all cursors */
+-  struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
+-  Pgno pgnoRoot;            /* The root page of this tree */
+-  sqlite3_int64 cachedRowid; /* Next rowid cache.  0 means not valid */
+-  CellInfo info;            /* A parse of the cell we are pointing at */
+-  u8 wrFlag;                /* True if writable */
+-  u8 atLast;                /* Cursor pointing to the last entry */
+-  u8 validNKey;             /* True if info.nKey is valid */
+-  u8 eState;                /* One of the CURSOR_XXX constants (see below) */
+-  void *pKey;      /* Saved key that was cursor's last known position */
+-  i64 nKey;        /* Size of pKey, or last integer key */
+-  int skipNext;    /* Prev() is noop if negative. Next() is noop if positive */
+-#ifndef SQLITE_OMIT_INCRBLOB
+-  u8 isIncrblobHandle;      /* True if this cursor is an incr. io handle */
+-  Pgno *aOverflow;          /* Cache of overflow page locations */
+-#endif
+-  i16 iPage;                            /* Index of current page in apPage */
+-  MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
+-  u16 aiIdx[BTCURSOR_MAX_DEPTH];        /* Current index in apPage[i] */
+-};
++SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
++  u32 ret = 0;
++  if( pWal ){
++    ret = pWal->iCallback;
++    pWal->iCallback = 0;
++  }
++  return (int)ret;
++}
+ 
+ /*
+-** Potential values for BtCursor.eState.
+-**
+-** CURSOR_VALID:
+-**   Cursor points to a valid entry. getPayload() etc. may be called.
++** This function is called to change the WAL subsystem into or out
++** of locking_mode=EXCLUSIVE.
+ **
+-** CURSOR_INVALID:
+-**   Cursor does not point to a valid entry. This can happen (for example) 
+-**   because the table is empty or because BtreeCursorFirst() has not been
+-**   called.
++** If op is zero, then attempt to change from locking_mode=EXCLUSIVE
++** into locking_mode=NORMAL.  This means that we must acquire a lock
++** on the pWal->readLock byte.  If the WAL is already in locking_mode=NORMAL
++** or if the acquisition of the lock fails, then return 0.  If the
++** transition out of exclusive-mode is successful, return 1.  This
++** operation must occur while the pager is still holding the exclusive
++** lock on the main database file.
+ **
+-** CURSOR_REQUIRESEEK:
+-**   The table that this cursor was opened on still exists, but has been 
+-**   modified since the cursor was last used. The cursor position is saved
+-**   in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in 
+-**   this state, restoreCursorPosition() can be called to attempt to
+-**   seek the cursor to the saved position.
++** If op is one, then change from locking_mode=NORMAL into 
++** locking_mode=EXCLUSIVE.  This means that the pWal->readLock must
++** be released.  Return 1 if the transition is made and 0 if the
++** WAL is already in exclusive-locking mode - meaning that this
++** routine is a no-op.  The pager must already hold the exclusive lock
++** on the main database file before invoking this operation.
+ **
+-** CURSOR_FAULT:
+-**   A unrecoverable error (an I/O error or a malloc failure) has occurred
+-**   on a different connection that shares the BtShared cache with this
+-**   cursor.  The error has left the cache in an inconsistent state.
+-**   Do nothing else with this cursor.  Any attempt to use the cursor
+-**   should return the error code stored in BtCursor.skip
++** If op is negative, then do a dry-run of the op==1 case but do
++** not actually change anything.  The pager uses this to see if it
++** should acquire the database exclusive lock prior to invoking
++** the op==1 case.
+ */
+-#define CURSOR_INVALID           0
+-#define CURSOR_VALID             1
+-#define CURSOR_REQUIRESEEK       2
+-#define CURSOR_FAULT             3
++SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
++  int rc;
++  assert( pWal->writeLock==0 );
+ 
+-/* 
+-** The database page the PENDING_BYTE occupies. This page is never used.
+-*/
+-# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
++  /* pWal->readLock is usually set, but might be -1 if there was a 
++  ** prior error while attempting to acquire are read-lock. This cannot 
++  ** happen if the connection is actually in exclusive mode (as no xShmLock
++  ** locks are taken in this case). Nor should the pager attempt to
++  ** upgrade to exclusive-mode following such an error.
++  */
++  assert( pWal->readLock>=0 || pWal->lockError );
++  assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
+ 
+-/*
+-** These macros define the location of the pointer-map entry for a 
+-** database page. The first argument to each is the number of usable
+-** bytes on each page of the database (often 1024). The second is the
+-** page number to look up in the pointer map.
+-**
+-** PTRMAP_PAGENO returns the database page number of the pointer-map
+-** page that stores the required pointer. PTRMAP_PTROFFSET returns
+-** the offset of the requested map entry.
+-**
+-** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page,
+-** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
+-** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
+-** this test.
+-*/
+-#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
+-#define PTRMAP_PTROFFSET(pgptrmap, pgno) (5*(pgno-pgptrmap-1))
+-#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
++  if( op==0 ){
++    if( pWal->exclusiveMode ){
++      pWal->exclusiveMode = 0;
++      if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){
++        pWal->exclusiveMode = 1;
++      }
++      rc = pWal->exclusiveMode==0;
++    }else{
++      /* Already in locking_mode=NORMAL */
++      rc = 0;
++    }
++  }else if( op>0 ){
++    assert( pWal->exclusiveMode==0 );
++    assert( pWal->readLock>=0 );
++    walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
++    pWal->exclusiveMode = 1;
++    rc = 1;
++  }else{
++    rc = pWal->exclusiveMode==0;
++  }
++  return rc;
++}
++
++#endif /* #ifndef SQLITE_OMIT_WAL */
+ 
++/************** End of wal.c *************************************************/
++/************** Begin file btmutex.c *****************************************/
+ /*
+-** The pointer map is a lookup table that identifies the parent page for
+-** each child page in the database file.  The parent page is the page that
+-** contains a pointer to the child.  Every page in the database contains
+-** 0 or 1 parent pages.  (In this context 'database page' refers
+-** to any page that is not part of the pointer map itself.)  Each pointer map
+-** entry consists of a single byte 'type' and a 4 byte parent page number.
+-** The PTRMAP_XXX identifiers below are the valid types.
+-**
+-** The purpose of the pointer map is to facility moving pages from one
+-** position in the file to another as part of autovacuum.  When a page
+-** is moved, the pointer in its parent must be updated to point to the
+-** new location.  The pointer map is used to locate the parent page quickly.
+-**
+-** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not
+-**                  used in this case.
++** 2007 August 27
+ **
+-** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number 
+-**                  is not used in this case.
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
+ **
+-** PTRMAP_OVERFLOW1: The database page is the first page in a list of 
+-**                   overflow pages. The page number identifies the page that
+-**                   contains the cell with a pointer to this overflow page.
++**    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.
+ **
+-** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of
+-**                   overflow pages. The page-number identifies the previous
+-**                   page in the overflow page list.
++*************************************************************************
+ **
+-** PTRMAP_BTREE: The database page is a non-root btree page. The page number
+-**               identifies the parent page in the btree.
+-*/
+-#define PTRMAP_ROOTPAGE 1
+-#define PTRMAP_FREEPAGE 2
+-#define PTRMAP_OVERFLOW1 3
+-#define PTRMAP_OVERFLOW2 4
+-#define PTRMAP_BTREE 5
+-
+-/* A bunch of assert() statements to check the transaction state variables
+-** of handle p (type Btree*) are internally consistent.
+-*/
+-#define btreeIntegrity(p) \
+-  assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
+-  assert( p->pBt->inTransaction>=p->inTrans ); 
+-
+-
+-/*
+-** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
+-** if the database supports auto-vacuum or not. Because it is used
+-** within an expression that is an argument to another macro 
+-** (sqliteMallocRaw), it is not possible to use conditional compilation.
+-** So, this macro is defined instead.
+-*/
+-#ifndef SQLITE_OMIT_AUTOVACUUM
+-#define ISAUTOVACUUM (pBt->autoVacuum)
+-#else
+-#define ISAUTOVACUUM 0
+-#endif
+-
+-
+-/*
+-** This structure is passed around through all the sanity checking routines
+-** in order to keep track of some global state information.
+-*/
+-typedef struct IntegrityCk IntegrityCk;
+-struct IntegrityCk {
+-  BtShared *pBt;    /* The tree being checked out */
+-  Pager *pPager;    /* The associated pager.  Also accessible by pBt->pPager */
+-  Pgno nPage;       /* Number of pages in the database */
+-  int *anRef;       /* Number of times each page is referenced */
+-  int mxErr;        /* Stop accumulating errors when this reaches zero */
+-  int nErr;         /* Number of messages written to zErrMsg so far */
+-  int mallocFailed; /* A memory allocation error has occurred */
+-  StrAccum errMsg;  /* Accumulate the error message text here */
+-};
+-
+-/*
+-** Read or write a two- and four-byte big-endian integer values.
++** This file contains code used to implement mutexes on Btree objects.
++** This code really belongs in btree.c.  But btree.c is getting too
++** big and we want to break it down some.  This packaged seemed like
++** a good breakout.
+ */
+-#define get2byte(x)   ((x)[0]<<8 | (x)[1])
+-#define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v))
+-#define get4byte sqlite3Get4byte
+-#define put4byte sqlite3Put4byte
+-
+-/************** End of btreeInt.h ********************************************/
+-/************** Continuing where we left off in btmutex.c ********************/
+ #ifndef SQLITE_OMIT_SHARED_CACHE
+ #if SQLITE_THREADSAFE
+ 
+@@ -85120,60 +85817,6 @@
+ 
+ #ifndef SQLITE_OMIT_SCHEMA_PRAGMAS
+   /*
+-  **   PRAGMA proc_list
+-  **
+-  ** Return a single row for each procedure, the returned data set are:
+-  **
+-  ** name:         Procedure name
+-  ** is_aggregate: True is procedure is an aggregate
+-  ** nargs:        Number of arguments of the procedure, or -1 if unlimited
+-  ** spe_name:     Specific name (unique procedure name)
+-  */
+-  if( sqlite3StrICmp(zLeft, "proc_list")==0 ){
+-    if( sqlite3ReadSchema(pParse) ) goto pragma_out;
+-
+-    sqlite3VdbeSetNumCols(v, 4);
+-    pParse->nMem = 4;
+-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "name", SQLITE_STATIC);
+-    sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "is_aggregate", SQLITE_STATIC);
+-    sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "nargs", SQLITE_STATIC);
+-    sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "spe_name", SQLITE_STATIC);
+-    int j;
+-    for(j=0; j<ArraySize(db->aFunc.a); j++){
+-      FuncDef *func;
+-      for (func =db->aFunc.a[j]; func; func = func->pNext) {
+-	char *sname;
+-	int size;
+-	size = strlen (func->zName) + 25;
+-	sname = sqlite3_malloc (sizeof (char) * size);
+-	snprintf (sname, size-1, "%s_%d_%d", func->zName, func->nArg, func->iPrefEnc);
+-	sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, func->zName, 0);
+-	sqlite3VdbeAddOp2(v, OP_Integer, func->xFinalize ? 1 : 0, 2);
+-	sqlite3VdbeAddOp2(v, OP_Integer, func->nArg, 3);
+-	sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, sname, 0);
+-	sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
+-	sqlite3_free (sname);
+-      }
+-    }
+-    for(j=0; j<ArraySize(sqlite3GlobalFunctions.a); j++){
+-      FuncDef *func;
+-      for (func =sqlite3GlobalFunctions.a[j]; func; func = func->pNext) {
+-	char *sname;
+-	int size;
+-	size = strlen (func->zName) + 25;
+-	sname = sqlite3_malloc (sizeof (char) * size);
+-	snprintf (sname, size-1, "%s_%d_%d", func->zName, func->nArg, func->iPrefEnc);
+-	sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, func->zName, 0);
+-	sqlite3VdbeAddOp2(v, OP_Integer, func->xFinalize ? 1 : 0, 2);
+-	sqlite3VdbeAddOp2(v, OP_Integer, func->nArg, 3);
+-	sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, sname, 0);
+-	sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
+-	sqlite3_free (sname);
+-      }
+-    }
+-  }else
+-
+- /*
+   **   PRAGMA table_info(<table>)
+   **
+   ** Return a single row for each column of the named table. The columns of
+@@ -85795,6 +86438,24 @@
+       sqlite3_rekey(db, zKey, i/2);
+     }
+   }else
++/** BEGIN CRYPTO **/
++  if( sqlite3StrICmp(zLeft, "cipher")==0 && zRight ){
++    extern int codec_set_cipher_name(sqlite3*, int, const char *, int);
++    codec_set_cipher_name(db,0,zRight,2); // change cipher for both
++  }else
++  if( sqlite3StrICmp(zLeft, "rekey_cipher")==0 && zRight ){
++    extern int codec_set_cipher_name(sqlite3*, int, const char *, int); 
++    codec_set_cipher_name(db,0,zRight,1); // change write cipher only
++  }else
++  if( sqlite3StrICmp(zLeft, "kdf_iter")==0 && zRight ){
++    extern int codec_set_kdf_iter(sqlite3*, int, int, int);
++    codec_set_kdf_iter(db,0,atoi(zRight),2); // change cipher for both
++  }else
++  if( sqlite3StrICmp(zLeft, "rekey_kdf_iter")==0 && zRight ){
++    extern int codec_set_kdf_iter(sqlite3*, int, int, int); 
++    codec_set_kdf_iter(db,0,atoi(zRight),1); // change write cipher only
++  }else
++/** END CRYPTO **/
+ #endif
+ #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
+   if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){
diff --git a/providers/sqlcipher/sqlcipher_specs_add_column.xml.in b/providers/sqlcipher/sqlcipher_specs_add_column.xml.in
new file mode 120000
index 0000000..a255afa
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_add_column.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_add_column.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_auth.xml.in b/providers/sqlcipher/sqlcipher_specs_auth.xml.in
new file mode 100644
index 0000000..bd7df0f
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_auth.xml.in
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<data-set-spec>
+  <parameters>
+    <parameter id="PASSWORD" _name="Passphrase" _descr="Encryption passphrase" gdatype="gchararray" nullok="TRUE" plugin="string:HIDDEN=true"/>
+  </parameters>
+</data-set-spec>
diff --git a/providers/sqlcipher/sqlcipher_specs_create_db.xml.in b/providers/sqlcipher/sqlcipher_specs_create_db.xml.in
new file mode 100644
index 0000000..dff5a78
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_create_db.xml.in
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<serv_op>
+  <!-- DSN parameters -->
+  <parameters id="DB_DEF_P" _name="Database's description">
+    <parameter id="DB_NAME" _name="Database name" _descr="The name of a database to create" gdatype="gchararray" nullok="FALSE"/>
+    <parameter id="DB_DIR" _name="Directory" _descr="Directory where the database file will be" gdatype="gchararray" nullok="FALSE" plugin="filesel:MODE=PICKFOLDER"/>
+    <parameter id="PASSWORD" _name="Passphrase" _descr="Encryption passphrase" gdatype="gchararray" nullok="TRUE" plugin="string:HIDDEN=true"/>
+  </parameters>
+</serv_op>
diff --git a/providers/sqlcipher/sqlcipher_specs_create_index.xml.in b/providers/sqlcipher/sqlcipher_specs_create_index.xml.in
new file mode 120000
index 0000000..6c95c53
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_create_index.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_create_index.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_create_table.xml.in b/providers/sqlcipher/sqlcipher_specs_create_table.xml.in
new file mode 120000
index 0000000..3cef9c3
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_create_table.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_create_table.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_create_view.xml.in b/providers/sqlcipher/sqlcipher_specs_create_view.xml.in
new file mode 120000
index 0000000..cdfeefc
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_create_view.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_create_view.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_drop_db.xml.in b/providers/sqlcipher/sqlcipher_specs_drop_db.xml.in
new file mode 120000
index 0000000..3a6f43d
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_drop_db.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_drop_db.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_drop_index.xml.in b/providers/sqlcipher/sqlcipher_specs_drop_index.xml.in
new file mode 120000
index 0000000..2c6daab
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_drop_index.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_drop_index.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_drop_table.xml.in b/providers/sqlcipher/sqlcipher_specs_drop_table.xml.in
new file mode 120000
index 0000000..57b73f4
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_drop_table.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_drop_table.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_drop_view.xml.in b/providers/sqlcipher/sqlcipher_specs_drop_view.xml.in
new file mode 120000
index 0000000..ba154ff
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_drop_view.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_drop_view.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_dsn.xml.in b/providers/sqlcipher/sqlcipher_specs_dsn.xml.in
new file mode 120000
index 0000000..5b59709
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_dsn.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_dsn.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_rename_table.xml.in b/providers/sqlcipher/sqlcipher_specs_rename_table.xml.in
new file mode 120000
index 0000000..63874b7
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_rename_table.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_rename_table.xml.in
\ No newline at end of file
diff --git a/providers/web/web_specs_auth.xml.in b/providers/web/web_specs_auth.xml.in
index cf7106f..133ed87 100644
--- a/providers/web/web_specs_auth.xml.in
+++ b/providers/web/web_specs_auth.xml.in
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <data-set-spec>
   <parameters>
-    <parameter id="PASSWORD" _name="Password" _descr="Connection password as defined on the web server" gdatype="gchararray" nullok="FALSE"/>
+    <parameter id="PASSWORD" _name="Password" _descr="Connection password as defined on the web server" gdatype="gchararray" nullok="FALSE" plugin="string:HIDDEN=true"/>
   </parameters>
 </data-set-spec>
diff --git a/tests/Makefile.am b/tests/Makefile.am
index bc2f0f6..8620159 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -75,4 +75,11 @@ test_connection_string_split_LDADD = \
         $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
-EXTRA_DIST = dbstruct.xml
\ No newline at end of file
+test_connection_string_split_SOURCES = \
+        test-connection-string-split.c
+
+test_connection_string_split_LDADD = \
+        $(top_builddir)/libgda/libgda-4.0.la \
+        $(LIBGDA_LIBS)
+
+EXTRA_DIST = dbstruct.xml



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]