]> granicus.if.org Git - php/commitdiff
Update libsqlite to 3.6.6
authorScott MacVicar <scottmac@php.net>
Sat, 22 Nov 2008 11:04:26 +0000 (11:04 +0000)
committerScott MacVicar <scottmac@php.net>
Sat, 22 Nov 2008 11:04:26 +0000 (11:04 +0000)
ext/sqlite3/libsqlite/sqlite3.c
ext/sqlite3/libsqlite/sqlite3.h

index 0c3d63b453a0a2fdcc7bceb491f6e461f9151888..2aaf123798024278f9d8eab1b04ce58139cb0602 100644 (file)
@@ -4,7 +4,7 @@
 
 /******************************************************************************
 ** This file is an amalgamation of many separate C source files from SQLite
-** version 3.6.5.  By combining all the individual C code files into this 
+** version 3.6.6.  By combining all the individual C code files into this 
 ** single large file, the entire code can be compiled as a one translation
 ** unit.  This allows many compilers to do optimizations that would not be
 ** possible if the files were compiled separately.  Performance improvements
 ** programs, you need this file and the "sqlite3.h" header file that defines
 ** the programming interface to the SQLite library.  (If you do not have 
 ** the "sqlite3.h" header file at hand, you will find a copy in the first
-** 6569 lines past this header comment.)  Additional code files may be
+** 6728 lines past this header comment.)  Additional code files may be
 ** needed if you want a wrapper to interface SQLite with your choice of
 ** programming language.  The code for the "sqlite3" command-line shell
 ** is also in a separate file.  This file contains only code for the core
 ** SQLite library.
 **
-** This amalgamation was generated on 2008-11-12 15:36:10 UTC.
+** This amalgamation was generated on 2008-11-19 21:08:14 UTC.
 */
 #define SQLITE_CORE 1
 #define SQLITE_AMALGAMATION 1
@@ -568,8 +568,8 @@ extern "C" {
 **          with the value (X*1000000 + Y*1000 + Z) where X, Y, and Z
 **          are the major version, minor version, and release number.
 */
-#define SQLITE_VERSION         "3.6.5"
-#define SQLITE_VERSION_NUMBER  3006005
+#define SQLITE_VERSION         "3.6.6"
+#define SQLITE_VERSION_NUMBER  3006006
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers {H10020} <S60100>
@@ -1735,7 +1735,10 @@ struct sqlite3_mem_methods {
 **
 ** <dt>SQLITE_CONFIG_PAGECACHE</dt>
 ** <dd>This option specifies a static memory buffer that SQLite can use for
-** the database page cache.  There are three arguments: A pointer to the
+** the database page cache with the default page cache implemenation.  
+** This configuration should not be used if an application-define page
+** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option.
+** There are three arguments to this option: A pointer to the
 ** memory, the size of each page buffer (sz), and the number of pages (N).
 ** The sz argument must be a power of two between 512 and 32768.  The first
 ** argument should point to an allocation of at least sz*N bytes of memory.
@@ -1780,6 +1783,17 @@ struct sqlite3_mem_methods {
 ** size of each lookaside buffer slot and the second is the number of
 ** slots allocated to each database connection.</dd>
 **
+** <dt>SQLITE_CONFIG_PCACHE</dt>
+** <dd>This option takes a single argument which is a pointer to
+** an [sqlite3_pcache_methods] object.  This object specifies the interface
+** to a custom page cache implementation.  SQLite makes a copy of the
+** object and uses it for page cache memory allocations.</dd>
+**
+** <dt>SQLITE_CONFIG_GETPCACHE</dt>
+** <dd>This option takes a single argument which is a pointer to an
+** [sqlite3_pcache_methods] object.  SQLite copies of the current
+** page cache implementation into that object.</dd>
+**
 ** </dl>
 */
 #define SQLITE_CONFIG_SINGLETHREAD  1  /* nil */
@@ -1795,6 +1809,8 @@ struct sqlite3_mem_methods {
 #define SQLITE_CONFIG_GETMUTEX     11  /* sqlite3_mutex_methods* */
 /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ 
 #define SQLITE_CONFIG_LOOKASIDE    13  /* int int */
+#define SQLITE_CONFIG_PCACHE       14  /* sqlite3_pcache_methods* */
+#define SQLITE_CONFIG_GETPCACHE    15  /* sqlite3_pcache_methods* */
 
 /*
 ** CAPI3REF: Configuration Options {H10170} <S20000>
@@ -7016,6 +7032,149 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_stmt_status(sqlite3_stmt*, int op,int
 #define SQLITE_STMTSTATUS_FULLSCAN_STEP     1
 #define SQLITE_STMTSTATUS_SORT              2
 
+/*
+** CAPI3REF: Custom Page Cache Object
+** EXPERIMENTAL
+**
+** The sqlite3_pcache type is opaque.  It is implemented by
+** the pluggable module.  The SQLite core has no knowledge of
+** its size or internal structure and never deals with the
+** sqlite3_pcache object except by holding and passing pointers
+** to the object.
+**
+** See [sqlite3_pcache_methods] for additional information.
+*/
+typedef struct sqlite3_pcache sqlite3_pcache;
+
+/*
+** CAPI3REF: Application Defined Page Cache.
+** EXPERIMENTAL
+**
+** The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can
+** register an alternative page cache implementation by passing in an 
+** instance of the sqlite3_pcache_methods structure. The majority of the 
+** heap memory used by sqlite is used by the page cache to cache data read 
+** from, or ready to be written to, the database file. By implementing a 
+** custom page cache using this API, an application can control more 
+** precisely the amount of memory consumed by sqlite, the way in which 
+** said memory is allocated and released, and the policies used to 
+** determine exactly which parts of a database file are cached and for 
+** how long.
+**
+** The contents of the structure are copied to an internal buffer by sqlite
+** within the call to [sqlite3_config].
+**
+** The xInit() method is called once for each call to [sqlite3_initialize()]
+** (usually only once during the lifetime of the process). It is passed
+** a copy of the sqlite3_pcache_methods.pArg value. It can be used to set
+** up global structures and mutexes required by the custom page cache 
+** implementation. The xShutdown() method is called from within 
+** [sqlite3_shutdown()], if the application invokes this API. It can be used
+** to clean up any outstanding resources before process shutdown, if required.
+**
+** The xCreate() method is used to construct a new cache instance. The
+** first parameter, szPage, is the size in bytes of the pages that must
+** be allocated by the cache. szPage will not be a power of two. The
+** second argument, bPurgeable, is true if the cache being created will
+** be used to cache database pages read from a file stored on disk, or
+** false if it is used for an in-memory database. The cache implementation
+** does not have to do anything special based on the value of bPurgeable,
+** it is purely advisory. 
+**
+** The xCachesize() method may be called at any time by SQLite to set the
+** suggested maximum cache-size (number of pages stored by) the cache
+** instance passed as the first argument. This is the value configured using
+** the SQLite "[PRAGMA cache_size]" command. As with the bPurgeable parameter,
+** the implementation is not required to do anything special with this
+** value, it is advisory only.
+**
+** The xPagecount() method should return the number of pages currently
+** stored in the cache supplied as an argument.
+** 
+** The xFetch() method is used to fetch a page and return a pointer to it. 
+** A 'page', in this context, is a buffer of szPage bytes aligned at an
+** 8-byte boundary. The page to be fetched is determined by the key. The
+** mimimum key value is 1. After it has been retrieved using xFetch, the page 
+** is considered to be pinned.
+**
+** If the requested page is already in the page cache, then a pointer to
+** the cached buffer should be returned with its contents intact. If the
+** page is not already in the cache, then the expected behaviour of the
+** cache is determined by the value of the createFlag parameter passed
+** to xFetch, according to the following table:
+**
+** <table border=1 width=85% align=center>
+**   <tr><th>createFlag<th>Expected Behaviour
+**   <tr><td>0<td>NULL should be returned. No new cache entry is created.
+**   <tr><td>1<td>If createFlag is set to 1, this indicates that 
+**                SQLite is holding pinned pages that can be unpinned
+**                by writing their contents to the database file (a
+**                relatively expensive operation). In this situation the
+**                cache implementation has two choices: it can return NULL,
+**                in which case SQLite will attempt to unpin one or more 
+**                pages before re-requesting the same page, or it can
+**                allocate a new page and return a pointer to it. If a new
+**                page is allocated, then it must be completely zeroed before 
+**                it is returned.
+**   <tr><td>2<td>If createFlag is set to 2, then SQLite is not holding any
+**                pinned pages associated with the specific cache passed
+**                as the first argument to xFetch() that can be unpinned. The
+**                cache implementation should attempt to allocate a new
+**                cache entry and return a pointer to it. Again, the new
+**                page should be zeroed before it is returned. If the xFetch()
+**                method returns NULL when createFlag==2, SQLite assumes that
+**                a memory allocation failed and returns SQLITE_NOMEM to the
+**                user.
+** </table>
+**
+** xUnpin() is called by SQLite with a pointer to a currently pinned page
+** as its second argument. If the third parameter, discard, is non-zero,
+** then the page should be evicted from the cache. In this case SQLite 
+** assumes that the next time the page is retrieved from the cache using
+** the xFetch() method, it will be zeroed. If the discard parameter is
+** zero, then the page is considered to be unpinned. The cache implementation
+** may choose to reclaim (free or recycle) unpinned pages at any time.
+** SQLite assumes that next time the page is retrieved from the cache
+** it will either be zeroed, or contain the same data that it did when it
+** was unpinned.
+**
+** The cache is not required to perform any reference counting. A single 
+** call to xUnpin() unpins the page regardless of the number of prior calls 
+** to xFetch().
+**
+** The xRekey() method is used to change the key value associated with the
+** page passed as the second argument from oldKey to newKey. If the cache
+** previously contains an entry associated with newKey, it should be
+** discarded. Any prior cache entry associated with newKey is guaranteed not
+** to be pinned.
+**
+** When SQLite calls the xTruncate() method, the cache must discard all
+** existing cache entries with page numbers (keys) greater than or equal
+** to the value of the iLimit parameter passed to xTruncate(). If any
+** of these pages are pinned, they are implicitly unpinned, meaning that
+** they can be safely discarded.
+**
+** The xDestroy() method is used to delete a cache allocated by xCreate().
+** All resources associated with the specified cache should be freed. After
+** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*]
+** handle invalid, and will not use it with any other sqlite3_pcache_methods
+** functions.
+*/
+typedef struct sqlite3_pcache_methods sqlite3_pcache_methods;
+struct sqlite3_pcache_methods {
+  void *pArg;
+  int (*xInit)(void*);
+  void (*xShutdown)(void*);
+  sqlite3_pcache *(*xCreate)(int szPage, int bPurgeable);
+  void (*xCachesize)(sqlite3_pcache*, int nCachesize);
+  int (*xPagecount)(sqlite3_pcache*);
+  void *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);
+  void (*xUnpin)(sqlite3_pcache*, void*, int discard);
+  void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey);
+  void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);
+  void (*xDestroy)(sqlite3_pcache*);
+};
+
 /*
 ** Undo the hack that converts floating point types to integer for
 ** builds on processors without floating point support.
@@ -7485,7 +7644,7 @@ struct BusyHandler {
 ** A convenience macro that returns the number of elements in
 ** an array.
 */
-#define ArraySize(X)    (sizeof(X)/sizeof(X[0]))
+#define ArraySize(X)    ((int)(sizeof(X)/sizeof(X[0])))
 
 /*
 ** The following value as a destructor means to use sqlite3DbFree().
@@ -7519,6 +7678,25 @@ SQLITE_API   void *sqlite3_wsd_find(void *K, int L);
   #define sqlite3GlobalConfig sqlite3Config
 #endif
 
+/*
+** The following macros are used to suppress compiler warnings and to
+** make it clear to human readers when a function parameter is deliberately 
+** left unused within the body of a function. This usually happens when
+** a function is called via a function pointer. For example the 
+** implementation of an SQL aggregate step callback may not use the
+** parameter indicating the number of arguments passed to the aggregate,
+** if it knows that this is enforced elsewhere.
+**
+** When a function parameter is not used at all within the body of a function,
+** it is generally named "NotUsed" or "NotUsed2" to make things even clearer.
+** However, these macros may also be used to suppress warnings related to
+** parameters that may or may not be used depending on compilation options.
+** For example those parameters only used in assert() statements. In these
+** cases the parameters are named as per the usual conventions.
+*/
+#define UNUSED_PARAMETER(x) (void)(x)
+#define UNUSED_PARAMETER2(x,y) UNUSED_PARAMETER(x),UNUSED_PARAMETER(y)
+
 /*
 ** Forward references to structures
 */
@@ -8261,7 +8439,7 @@ typedef struct PgHdr DbPage;
 ** routines:
 */
 SQLITE_PRIVATE int sqlite3PagerOpen(sqlite3_vfs *, Pager **ppPager, const char*, int,int,int);
-SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager*, BusyHandler *pBusyHandler);
+SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
 SQLITE_PRIVATE void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*));
 SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u16*);
 SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
@@ -8369,6 +8547,7 @@ struct PgHdr {
   u32 pageHash;                  /* Hash of page content */
 #endif
   u16 flags;                     /* PGHDR flags defined below */
+
   /**********************************************************************
   ** Elements above are public.  All that follows is private to pcache.c
   ** and should not be accessed by other modules.
@@ -8376,18 +8555,11 @@ struct PgHdr {
   i16 nRef;                      /* Number of users of this page */
   PCache *pCache;                /* Cache that owns this page */
 
-  /**********************************************************************
-  ** Elements above are accessible at any time by the owner of the cache
-  ** without the need for a mutex.  The elements that follow can only be
-  ** accessed while holding the SQLITE_MUTEX_STATIC_LRU mutex.
-  */
-  PgHdr *pNextHash, *pPrevHash;  /* Hash collision chain for PgHdr.pgno */
-  PgHdr *pNext, *pPrev;          /* List of clean or dirty pages */
-  PgHdr *pNextLru, *pPrevLru;    /* Part of global LRU list */
+  PgHdr *pDirtyNext;             /* Next element in list of dirty pages */
+  PgHdr *pDirtyPrev;             /* Previous element in list of dirty pages */
 };
 
 /* Bit values for PgHdr.flags */
-#define PGHDR_IN_JOURNAL        0x001  /* Page is in rollback journal */
 #define PGHDR_DIRTY             0x002  /* Page has changed */
 #define PGHDR_NEED_SYNC         0x004  /* Fsync the rollback journal before
                                        ** writing this page to the database */
@@ -8403,8 +8575,6 @@ SQLITE_PRIVATE void sqlite3PcacheShutdown(void);
 ** These routines implement SQLITE_CONFIG_PAGECACHE.
 */
 SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *, int sz, int n);
-SQLITE_PRIVATE void *sqlite3PCacheMalloc(int sz);
-SQLITE_PRIVATE void sqlite3PCacheFree(void*);
 
 /* Create a new pager cache.
 ** Under memory stress, invoke xStress to try to make pages clean.
@@ -8451,17 +8621,7 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache*);
 SQLITE_PRIVATE void sqlite3PcacheClose(PCache*);
 
 /* Clear flags from pages of the page cache */
-SQLITE_PRIVATE void sqlite3PcacheClearFlags(PCache*, int mask);
-
-/* Assert flags settings on all pages.  Debugging only */
-#ifndef NDEBUG
-SQLITE_PRIVATE   void sqlite3PcacheAssertFlags(PCache*, int trueMask, int falseMask);
-#else
-# define sqlite3PcacheAssertFlags(A,B,C)
-#endif
-
-/* Return true if the number of dirty pages is 0 or 1 */
-SQLITE_PRIVATE int sqlite3PcacheZeroOrOneDirtyPages(PCache*);
+SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *);
 
 /* Discard the contents of the cache */
 SQLITE_PRIVATE int sqlite3PcacheClear(PCache*);
@@ -8478,11 +8638,11 @@ SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr*);
 SQLITE_PRIVATE int sqlite3PcachePagecount(PCache*);
 
 #ifdef SQLITE_CHECK_PAGES
-/* Iterate through all pages currently stored in the cache. This interface
-** is only available if SQLITE_CHECK_PAGES is defined when the library is 
-** built.
+/* Iterate through all dirty pages currently stored in the cache. This
+** interface is only available if SQLITE_CHECK_PAGES is defined when the 
+** library is built.
 */
-SQLITE_PRIVATE void sqlite3PcacheIterate(PCache *pCache, void (*xIter)(PgHdr *));
+SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *));
 #endif
 
 /* Set and get the suggested cache-size for the specified pager-cache.
@@ -8491,8 +8651,10 @@ SQLITE_PRIVATE void sqlite3PcacheIterate(PCache *pCache, void (*xIter)(PgHdr *))
 ** the total number of pages cached by purgeable pager-caches to the sum
 ** of the suggested cache-sizes.
 */
-SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *);
 SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *, int);
+#ifdef SQLITE_TEST
+SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *);
+#endif
 
 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
 /* Try to return memory used by the pcache module to the main memory heap */
@@ -8503,6 +8665,8 @@ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int);
 SQLITE_PRIVATE void sqlite3PcacheStats(int*,int*,int*,int*);
 #endif
 
+SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
+
 #endif /* _PCACHE_H_ */
 
 /************** End of pcache.h **********************************************/
@@ -9023,7 +9187,7 @@ struct sqlite3 {
   CollSeq *pDfltColl;           /* The default collating sequence (BINARY) */
   i64 lastRowid;                /* ROWID of most recent insert (see above) */
   i64 priorNewRowid;            /* Last randomly generated ROWID */
-  int magic;                    /* Magic number for detect library misuse */
+  u32 magic;                    /* Magic number for detect library misuse */
   int nChange;                  /* Value returned by sqlite3_changes() */
   int nTotalChange;             /* Value returned by sqlite3_total_changes() */
   sqlite3_mutex *mutex;         /* Connection mutex */
@@ -9186,13 +9350,13 @@ struct FuncDef {
 **     parameter.
 */
 #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
-  {nArg, SQLITE_UTF8, bNC*8, SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName}
+  {nArg, SQLITE_UTF8, bNC*8, SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0}
 #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
-  {nArg, SQLITE_UTF8, bNC*8, pArg, 0, xFunc, 0, 0, #zName}
+  {nArg, SQLITE_UTF8, bNC*8, pArg, 0, xFunc, 0, 0, #zName, 0}
 #define LIKEFUNC(zName, nArg, arg, flags) \
-  {nArg, SQLITE_UTF8, flags, (void *)arg, 0, likeFunc, 0, 0, #zName}
+  {nArg, SQLITE_UTF8, flags, (void *)arg, 0, likeFunc, 0, 0, #zName, 0}
 #define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
-  {nArg, SQLITE_UTF8, nc*8, SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal, #zName}
+  {nArg, SQLITE_UTF8, nc*8, SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0}
 
 
 /*
@@ -9761,6 +9925,11 @@ struct IdList {
 */
 typedef u64 Bitmask;
 
+/*
+** The number of bits in a Bitmask.  "BMS" means "BitMask Size".
+*/
+#define BMS  ((int)(sizeof(Bitmask)*8))
+
 /*
 ** The following structure describes the FROM clause of a SELECT statement.
 ** Each table or subquery in the FROM clause is a separate element of
@@ -10296,6 +10465,7 @@ struct Sqlite3Config {
   int nLookaside;                   /* Default lookaside buffer count */
   sqlite3_mem_methods m;            /* Low-level memory allocation interface */
   sqlite3_mutex_methods mutex;      /* Low-level mutex interface */
+  sqlite3_pcache_methods pcache;    /* Low-level page-cache interface */
   void *pHeap;                      /* Heap storage space */
   int nHeap;                        /* Size of pHeap[] */
   int mnReq, mxReq;                 /* Min and max heap requests sizes */
@@ -10392,11 +10562,17 @@ SQLITE_PRIVATE void sqlite3ScratchFree(void*);
 SQLITE_PRIVATE void *sqlite3PageMalloc(int);
 SQLITE_PRIVATE void sqlite3PageFree(void*);
 SQLITE_PRIVATE void sqlite3MemSetDefault(void);
-SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
-SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void);
 SQLITE_PRIVATE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));
 SQLITE_PRIVATE int sqlite3MemoryAlarm(void (*)(void*, sqlite3_int64, int), void*, sqlite3_int64);
 
+#ifdef SQLITE_ENABLE_MEMSYS3
+SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
+#endif
+#ifdef SQLITE_ENABLE_MEMSYS5
+SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void);
+#endif
+
+
 #ifndef SQLITE_MUTEX_OMIT
 SQLITE_PRIVATE   sqlite3_mutex_methods *sqlite3DefaultMutex(void);
 SQLITE_PRIVATE   sqlite3_mutex *sqlite3MutexAlloc(int);
@@ -10555,7 +10731,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int*);
 SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int);
 SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
                                      int*,int,int,int,int);
-SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*,int,int,int,int);
+SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int);
 SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
 SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int);
 SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,Expr*);
@@ -10569,7 +10745,6 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,int)
 SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3*);
 SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void);
 SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void);
-SQLITE_PRIVATE int sqlite3GetBuiltinFunction(const char *, int, FuncDef **);
 #ifdef SQLITE_DEBUG
 SQLITE_PRIVATE   int sqlite3SafetyOn(sqlite3*);
 SQLITE_PRIVATE   int sqlite3SafetyOff(sqlite3*);
@@ -10591,7 +10766,7 @@ SQLITE_PRIVATE   void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,
 SQLITE_PRIVATE   void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
 SQLITE_PRIVATE   void sqlite3DropTrigger(Parse*, SrcList*, int);
 SQLITE_PRIVATE   void sqlite3DropTriggerPtr(Parse*, Trigger*);
-SQLITE_PRIVATE   int sqlite3TriggersExist(Parse*, Table*, int, ExprList*);
+SQLITE_PRIVATE   int sqlite3TriggersExist(Table*, int, ExprList*);
 SQLITE_PRIVATE   int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int, 
                            int, int, u32*, u32*);
   void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
@@ -10604,7 +10779,7 @@ SQLITE_PRIVATE   TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*);
 SQLITE_PRIVATE   void sqlite3DeleteTrigger(sqlite3*, Trigger*);
 SQLITE_PRIVATE   void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
 #else
-# define sqlite3TriggersExist(A,B,C,D,E,F) 0
+# define sqlite3TriggersExist(B,C,D,E,F) 0
 # define sqlite3DeleteTrigger(A,B)
 # define sqlite3DropTriggerPtr(A,B)
 # define sqlite3UnlinkAndDeleteTrigger(A,B,C)
@@ -10672,8 +10847,8 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 v);
 **     x = putVarint32( A, B );
 **
 */
-#define getVarint32(A,B)  ((*(A)<(unsigned char)0x80) ? ((B) = (u32)*(A)),1 : sqlite3GetVarint32((A), &(B)))
-#define putVarint32(A,B)  (((B)<(u32)0x80) ? (*(A) = (unsigned char)(B)),1 : sqlite3PutVarint32((A), (B)))
+#define getVarint32(A,B)  ((*(A)<(unsigned char)0x80) ? ((B) = (u32)*(A)),1 : sqlite3GetVarint32((A), (u32 *)&(B)))
+#define putVarint32(A,B)  (((u32)(B)<(u32)0x80) ? (*(A) = (unsigned char)(B)),1 : sqlite3PutVarint32((A), (B)))
 #define getVarint    sqlite3GetVarint
 #define putVarint    sqlite3PutVarint
 
@@ -10784,11 +10959,13 @@ SQLITE_PRIVATE   int sqlite3Utf8To8(unsigned char*);
 #  define sqlite3VtabSync(X,Y) SQLITE_OK
 #  define sqlite3VtabRollback(X)
 #  define sqlite3VtabCommit(X)
+#  define sqlite3VtabInSync(db) 0
 #else
 SQLITE_PRIVATE    void sqlite3VtabClear(Table*);
 SQLITE_PRIVATE    int sqlite3VtabSync(sqlite3 *db, char **);
 SQLITE_PRIVATE    int sqlite3VtabRollback(sqlite3 *db);
 SQLITE_PRIVATE    int sqlite3VtabCommit(sqlite3 *db);
+#  define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
 #endif
 SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*);
 SQLITE_PRIVATE void sqlite3VtabLock(sqlite3_vtab*);
@@ -11615,7 +11792,7 @@ static int parseModifier(const char *zMod, DateTime *p){
   double r;
   char *z, zBuf[30];
   z = zBuf;
-  for(n=0; n<sizeof(zBuf)-1 && zMod[n]; n++){
+  for(n=0; n<ArraySize(zBuf)-1 && zMod[n]; n++){
     z[n] = tolower(zMod[n]);
   }
   z[n] = 0;
@@ -11983,7 +12160,7 @@ static void strftimeFunc(
   }
   if( n<sizeof(zBuf) ){
     z = zBuf;
-  }else if( n>db->aLimit[SQLITE_LIMIT_LENGTH] ){
+  }else if( n>(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ){
     sqlite3_result_error_toobig(context);
     return;
   }else{
@@ -12062,9 +12239,10 @@ static void strftimeFunc(
 */
 static void ctimeFunc(
   sqlite3_context *context,
-  int argc,
-  sqlite3_value **argv
+  int NotUsed,
+  sqlite3_value **NotUsed2
 ){
+  UNUSED_PARAMETER2(NotUsed, NotUsed2);
   timeFunc(context, 0, 0);
 }
 
@@ -12075,9 +12253,10 @@ static void ctimeFunc(
 */
 static void cdateFunc(
   sqlite3_context *context,
-  int argc,
-  sqlite3_value **argv
+  int NotUsed,
+  sqlite3_value **NotUsed2
 ){
+  UNUSED_PARAMETER2(NotUsed, NotUsed2);
   dateFunc(context, 0, 0);
 }
 
@@ -12088,9 +12267,10 @@ static void cdateFunc(
 */
 static void ctimestampFunc(
   sqlite3_context *context,
-  int argc,
-  sqlite3_value **argv
+  int NotUsed,
+  sqlite3_value **NotUsed2
 ){
+  UNUSED_PARAMETER2(NotUsed, NotUsed2);
   datetimeFunc(context, 0, 0);
 }
 #endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */
@@ -12721,6 +12901,7 @@ static int sqlite3MemRoundup(int n){
 ** Initialize this module.
 */
 static int sqlite3MemInit(void *NotUsed){
+  UNUSED_PARAMETER(NotUsed);
   return SQLITE_OK;
 }
 
@@ -12728,6 +12909,7 @@ static int sqlite3MemInit(void *NotUsed){
 ** Deinitialize this module.
 */
 static void sqlite3MemShutdown(void *NotUsed){
+  UNUSED_PARAMETER(NotUsed);
   return;
 }
 
@@ -13446,7 +13628,7 @@ static void memsys3OutOfMemory(int nByte){
 ** size parameters for check-out and return a pointer to the 
 ** user portion of the chunk.
 */
-static void *memsys3Checkout(u32 i, int nBlock){
+static void *memsys3Checkout(u32 i, u32 nBlock){
   u32 x;
   assert( sqlite3_mutex_held(mem3.mutex) );
   assert( i>=1 );
@@ -13464,7 +13646,7 @@ static void *memsys3Checkout(u32 i, int nBlock){
 ** Return a pointer to the new allocation.  Or, if the master chunk
 ** is not large enough, return 0.
 */
-static void *memsys3FromMaster(int nBlock){
+static void *memsys3FromMaster(u32 nBlock){
   assert( sqlite3_mutex_held(mem3.mutex) );
   assert( mem3.szMaster>=nBlock );
   if( nBlock>=mem3.szMaster-1 ){
@@ -13550,8 +13732,8 @@ static void memsys3Merge(u32 *pRoot){
 */
 static void *memsys3MallocUnsafe(int nByte){
   u32 i;
-  int nBlock;
-  int toFree;
+  u32 nBlock;
+  u32 toFree;
 
   assert( sqlite3_mutex_held(mem3.mutex) );
   assert( sizeof(Mem3Block)==8 );
@@ -13747,6 +13929,7 @@ void *memsys3Realloc(void *pPrior, int nBytes){
 ** Initialize this module.
 */
 static int memsys3Init(void *NotUsed){
+  UNUSED_PARAMETER(NotUsed);
   if( !sqlite3GlobalConfig.pHeap ){
     return SQLITE_ERROR;
   }
@@ -13771,6 +13954,7 @@ static int memsys3Init(void *NotUsed){
 ** Deinitialize this module.
 */
 static void memsys3Shutdown(void *NotUsed){
+  UNUSED_PARAMETER(NotUsed);
   return;
 }
 
@@ -13783,7 +13967,7 @@ static void memsys3Shutdown(void *NotUsed){
 SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){
 #ifdef SQLITE_DEBUG
   FILE *out;
-  int i, j;
+  u32 i, j;
   u32 size;
   if( zFilename==0 || zFilename[0]==0 ){
     out = stdout;
@@ -13848,6 +14032,8 @@ SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){
   }else{
     fclose(out);
   }
+#else
+  UNUSED_PARAMETER(zFilename);
 #endif
 }
 
@@ -14089,12 +14275,11 @@ static void *memsys5MallocUnsafe(int nByte){
 
   /* Keep track of the maximum allocation request.  Even unfulfilled
   ** requests are counted */
-  if( nByte>mem5.maxRequest ){
+  if( (u32)nByte>mem5.maxRequest ){
     mem5.maxRequest = nByte;
   }
 
   /* Round nByte up to the next valid power of two */
-  if( nByte>POW2_MAX ) return 0;
   for(iFullSz=mem5.nAtom, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}
 
   /* Make sure mem5.aiFreelist[iLogsize] contains at least one free
@@ -14146,12 +14331,12 @@ static void memsys5FreeUnsafe(void *pOld){
 
   iLogsize = mem5.aCtrl[iBlock] & CTRL_LOGSIZE;
   size = 1<<iLogsize;
-  assert( iBlock+size-1<mem5.nBlock );
+  assert( iBlock+size-1<(u32)mem5.nBlock );
 
   mem5.aCtrl[iBlock] |= CTRL_FREE;
   mem5.aCtrl[iBlock+size-1] |= CTRL_FREE;
   assert( mem5.currentCount>0 );
-  assert( mem5.currentOut>=0 );
+  assert( mem5.currentOut>=(size*mem5.nAtom) );
   mem5.currentCount--;
   mem5.currentOut -= size*mem5.nAtom;
   assert( mem5.currentOut>0 || mem5.currentCount==0 );
@@ -14261,13 +14446,15 @@ static int memsys5Init(void *NotUsed){
   int nMinLog;                 /* Log of minimum allocation size in bytes*/
   int iOffset;
 
+  UNUSED_PARAMETER(NotUsed);
+
   if( !zByte ){
     return SQLITE_ERROR;
   }
 
   nMinLog = memsys5Log(sqlite3GlobalConfig.mnReq);
   mem5.nAtom = (1<<nMinLog);
-  while( sizeof(Mem5Link)>mem5.nAtom ){
+  while( (int)sizeof(Mem5Link)>mem5.nAtom ){
     mem5.nAtom = mem5.nAtom << 1;
   }
 
@@ -14297,6 +14484,7 @@ static int memsys5Init(void *NotUsed){
 ** Deinitialize this module.
 */
 static void memsys5Shutdown(void *NotUsed){
+  UNUSED_PARAMETER(NotUsed);
   return;
 }
 
@@ -14340,6 +14528,8 @@ SQLITE_PRIVATE void sqlite3Memsys5Dump(const char *zFilename){
   }else{
     fclose(out);
   }
+#else
+  UNUSED_PARAMETER(zFilename);
 #endif
 }
 
@@ -15040,7 +15230,7 @@ struct sqlite3_mutex {
 ** make sure no assert() statements are evaluated and hence these
 ** routines are never called.
 */
-#ifndef NDEBUG
+#if !defined(NDEBUG) || defined(SQLITE_DEBUG)
 static int pthreadMutexHeld(sqlite3_mutex *p){
   return (p->nRef!=0 && pthread_equal(p->owner, pthread_self()));
 }
@@ -15136,7 +15326,7 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
     }
     default: {
       assert( iType-2 >= 0 );
-      assert( iType-2 < sizeof(staticMutexes)/sizeof(staticMutexes[0]) );
+      assert( iType-2 < ArraySize(staticMutexes) );
       p = &staticMutexes[iType-2];
       p->id = iType;
       break;
@@ -15582,9 +15772,10 @@ SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
 */
 static void softHeapLimitEnforcer(
   void *NotUsed, 
-  sqlite3_int64 inUse,
+  sqlite3_int64 NotUsed2,
   int allocSize
 ){
+  UNUSED_PARAMETER2(NotUsed, NotUsed2);
   sqlite3_release_memory(allocSize);
 }
 
@@ -15626,6 +15817,7 @@ SQLITE_API int sqlite3_release_memory(int n){
   nRet += sqlite3PcacheReleaseMemory(n-nRet);
   return nRet;
 #else
+  UNUSED_PARAMETER(n);
   return SQLITE_OK;
 #endif
 }
@@ -15659,7 +15851,7 @@ static SQLITE_WSD struct Mem0Global {
   */
   u32 *aScratchFree;
   u32 *aPageFree;
-} mem0 = { 62560955 };
+} mem0 = { 62560955, 0, 0, 0, 0, 0, 0, 0, 0 };
 
 #define mem0 GLOBAL(struct Mem0Global, mem0)
 
@@ -15944,7 +16136,7 @@ SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
       i /= sqlite3GlobalConfig.szScratch;
       assert( i>=0 && i<sqlite3GlobalConfig.nScratch );
       sqlite3_mutex_enter(mem0.mutex);
-      assert( mem0.nScratchFree<sqlite3GlobalConfig.nScratch );
+      assert( mem0.nScratchFree<(u32)sqlite3GlobalConfig.nScratch );
       mem0.aScratchFree[mem0.nScratchFree++] = i;
       sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, -1);
       sqlite3_mutex_leave(mem0.mutex);
@@ -16483,7 +16675,6 @@ static const et_info fmtinfo[] = {
   {  'S',  0, 2, etSRCLIST,    0,  0 },
   {  'r', 10, 3, etORDINAL,    0,  0 },
 };
-#define etNINFO  (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
 
 /*
 ** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point
@@ -16520,7 +16711,7 @@ static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
 */
 static void appendSpace(StrAccum *pAccum, int N){
   static const char zSpaces[] = "                             ";
-  while( N>=sizeof(zSpaces)-1 ){
+  while( N>=(int)sizeof(zSpaces)-1 ){
     sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1);
     N -= sizeof(zSpaces)-1;
   }
@@ -16683,7 +16874,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
     }
     /* Fetch the info entry for the field */
     infop = 0;
-    for(idx=0; idx<etNINFO; idx++){
+    for(idx=0; idx<ArraySize(fmtinfo); idx++){
       if( c==fmtinfo[idx].fmttype ){
         infop = &fmtinfo[idx];
         if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
@@ -17765,7 +17956,7 @@ struct Vdbe {
   Mem *aVar;          /* Values for the OP_Variable opcode. */
   char **azVar;       /* Name of variables */
   int okVar;          /* True if azVar[] has been initialized */
-  int magic;              /* Magic number for sanity checking */
+  u32 magic;              /* Magic number for sanity checking */
   int nMem;               /* Number of memory locations currently allocated */
   Mem *aMem;              /* The memory locations */
   int nCallback;          /* Number of callbacks invoked so far */
@@ -18445,7 +18636,7 @@ SQLITE_PRIVATE int sqlite3IsNaN(double x){
 SQLITE_PRIVATE int sqlite3Strlen(sqlite3 *db, const char *z){
   const char *z2 = z;
   int len;
-  size_t x;
+  int x;
   while( *z2 ){ z2++; }
   x = z2 - z;
   len = 0x7fffffff & x;
@@ -19322,7 +19513,7 @@ SQLITE_PRIVATE int sqlite3SafetyOff(sqlite3 *db){
 ** used as an argument to sqlite3_errmsg() or sqlite3_close().
 */
 SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3 *db){
-  int magic;
+  u32 magic;
   if( db==0 ) return 0;
   magic = db->magic;
   if( magic!=SQLITE_MAGIC_OPEN &&
@@ -19330,7 +19521,7 @@ SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3 *db){
   return 1;
 }
 SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
-  int magic;
+  u32 magic;
   if( db==0 ) return 0;
   magic = db->magic;
   if( magic!=SQLITE_MAGIC_SICK &&
@@ -20229,7 +20420,14 @@ static int os2Sync( sqlite3_file *id, int flags ){
   }
   sqlite3_sync_count++;
 #endif
+  /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
+  ** no-op
+  */
+#ifdef SQLITE_NO_SYNC
+  return SQLITE_OK;
+#else
   return DosResetBuffer( pFile->h ) == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
+#endif
 }
 
 /*
@@ -21174,7 +21372,8 @@ SQLITE_API int sqlite3_os_end(void){
 **   * No locking,
 **   * Dot-file locking,
 **   * flock() locking,
-**   * AFP locking (OSX only).
+**   * AFP locking (OSX only),
+**   * Named POSIX semaphores (VXWorks only).
 **
 ** SQLITE_ENABLE_LOCKING_STYLE only works on a Mac. It is turned on by
 ** default on a Mac and disabled on all other posix platforms.
@@ -21187,6 +21386,16 @@ SQLITE_API int sqlite3_os_end(void){
 #  endif
 #endif
 
+/*
+** Define the IS_VXWORKS pre-processor macro to 1 if building on 
+** vxworks, or 0 otherwise.
+*/
+#if defined(__RTP__) || defined(_WRS_KERNEL)
+#  define IS_VXWORKS 1
+#else
+#  define IS_VXWORKS 0
+#endif
+
 /*
 ** These #defines should enable >2GB file support on Posix if the
 ** underlying operating system supports it.  If the OS lacks
@@ -21219,9 +21428,15 @@ SQLITE_API int sqlite3_os_end(void){
 #include <errno.h>
 
 #if SQLITE_ENABLE_LOCKING_STYLE
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <sys/mount.h>
+# include <sys/ioctl.h>
+# if IS_VXWORKS
+#  define lstat stat
+#  include <semaphore.h>
+#  include <limits.h>
+# else
+#  include <sys/param.h>
+#  include <sys/mount.h>
+# endif
 #endif /* SQLITE_ENABLE_LOCKING_STYLE */
 
 /*
@@ -21270,6 +21485,10 @@ struct unixFile {
   pthread_t tid;            /* The thread that "owns" this unixFile */
 #endif
   int lastErrno;            /* The unix errno from the last I/O error */
+#if IS_VXWORKS
+  int isDelete;             /* Delete on close if true */
+  char *zRealpath;
+#endif
 };
 
 /*
@@ -21680,7 +21899,11 @@ SQLITE_API int sqlite3_open_file_count = 0;
 */
 struct lockKey {
   dev_t dev;       /* Device number */
+#if IS_VXWORKS
+  void *rnam;      /* Realname since inode unusable */
+#else
   ino_t ino;       /* Inode number */
+#endif
 #if SQLITE_THREADSAFE
   pthread_t tid;   /* Thread ID or zero if threads can override each other */
 #endif
@@ -21710,7 +21933,11 @@ struct lockInfo {
 */
 struct openKey {
   dev_t dev;   /* Device number */
+#if IS_VXWORKS
+  void *rnam;  /* Realname since inode unusable */
+#else
   ino_t ino;   /* Inode number */
+#endif
 };
 
 /*
@@ -21726,6 +21953,10 @@ struct openCnt {
   int nLock;            /* Number of outstanding locks */
   int nPending;         /* Number of pending close() operations */
   int *aPending;        /* Malloced space holding fd's awaiting a close() */
+#if IS_VXWORKS
+  sem_t *pSem;          /* Named POSIX semaphore */
+  char aSemName[MAX_PATHNAME+1];   /* Name of that semaphore */
+#endif
   struct openCnt *pNext, *pPrev;   /* List of all openCnt objects */
 };
 
@@ -21738,6 +21969,18 @@ struct openCnt {
 static struct lockInfo *lockList = 0;
 static struct openCnt *openList = 0;
 
+#if IS_VXWORKS
+/*
+** This hash table is used to bind the canonical file name to a
+** unixFile structure and use the hash key (= canonical name)
+** instead of the Inode number of the file to find the matching
+** lockInfo and openCnt structures. It also helps to make the
+** name of the semaphore when LOCKING_STYLE_NAMEDSEM is used
+** for the file.
+*/
+static Hash nameHash;
+#endif
+
 /*
 ** The locking styles are associated with the different file locking
 ** capabilities supported by different file systems.  
@@ -21750,6 +21993,8 @@ static struct openCnt *openList = 0;
 **   can be used on file systems that do not offer any reliable file locking
 ** NO locking means that no locking will be attempted, this is only used for
 **   read-only file systems currently
+** NAMEDSEM is similar to DOTLOCK but uses a named semaphore instead of an
+**   indicator file.
 ** UNSUPPORTED means that no locking will be attempted, this is only used for
 **   file systems that are known to be unsupported
 */
@@ -21758,6 +22003,7 @@ static struct openCnt *openList = 0;
 #define LOCKING_STYLE_DOTFILE      3
 #define LOCKING_STYLE_FLOCK        4
 #define LOCKING_STYLE_AFP          5
+#define LOCKING_STYLE_NAMEDSEM     6
 
 /*
 ** Only set the lastErrno if the error code is a real error and not 
@@ -21977,10 +22223,103 @@ static void releaseOpenCnt(struct openCnt *pOpen){
   }
 }
 
+#if IS_VXWORKS
+/*
+** Implementation of a realpath() like function for vxWorks
+** to determine canonical path name from given name. It does
+** not support symlinks. Neither does it handle volume prefixes.
+*/
+char *
+vxrealpath(const char *pathname, int dostat)
+{
+  struct stat sbuf;
+  int len;
+  char *where, *ptr, *last;
+  char *result, *curpath, *workpath, *namebuf;
+
+  len = pathconf(pathname, _PC_PATH_MAX);
+  if( len<0 ){
+    len = PATH_MAX;
+  }
+  result = sqlite3_malloc(len * 4);
+  if( !result ){
+    return 0;
+  }
+  curpath = result + len;
+  workpath = curpath + len;
+  namebuf = workpath + len;
+  strcpy(curpath, pathname);
+  if( *pathname!='/' ){
+    if( !getcwd(workpath, len) ){
+      sqlite3_free(result);
+      return 0;
+    }
+  }else{
+    *workpath = '\0';
+  }
+  where = curpath;
+  while( *where ){
+    if( !strcmp(where, ".") ){
+      where++;
+      continue;
+    }
+    if( !strncmp(where, "./", 2) ){
+      where += 2;
+      continue;
+    }
+    if( !strncmp(where, "../", 3) ){
+      where += 3;
+      ptr = last = workpath;
+      while( *ptr ){
+        if( *ptr=='/' ){
+          last = ptr;
+        }
+        ptr++;
+      }
+      *last = '\0';
+      continue;
+    }
+    ptr = strchr(where, '/');
+    if( !ptr ){
+      ptr = where + strlen(where) - 1;
+    }else{
+      *ptr = '\0';
+    }
+    strcpy(namebuf, workpath);
+    for( last = namebuf; *last; last++ ){
+      continue;
+    }
+    if( *--last!='/' ){
+      strcat(namebuf, "/");
+    }
+    strcat(namebuf, where);
+    where = ++ptr;
+    if( dostat ){
+      if( stat(namebuf, &sbuf)==-1 ){
+        sqlite3_free(result);
+        return 0;
+      }
+      if( (sbuf.st_mode & S_IFDIR)==S_IFDIR ){
+        strcpy(workpath, namebuf);
+        continue;
+      }
+      if( *where ){
+        sqlite3_free(result);
+        return 0;
+      }
+    }
+    strcpy(workpath, namebuf);
+  }
+  strcpy(result, workpath);
+  return result;
+}
+#endif
+
 #if SQLITE_ENABLE_LOCKING_STYLE
 /*
 ** Tests a byte-range locking query to see if byte range locks are 
 ** supported, if not we fall back to dotlockLockingStyle.
+** On vxWorks we fall back to namedsemLockingStyle.
 */
 static int testLockingStyle(int fd){
   struct flock lockInfo;
@@ -21997,9 +22336,10 @@ static int testLockingStyle(int fd){
   }
   
   /* Testing for flock() can give false positives.  So if if the above 
-  ** test fails, then we fall back to using dot-file style locking.
-  */  
-  return LOCKING_STYLE_DOTFILE;
+  ** test fails, then we fall back to using dot-file style locking (or
+  ** named-semaphore locking on vxworks).
+  */
+  return (IS_VXWORKS ? LOCKING_STYLE_NAMEDSEM : LOCKING_STYLE_DOTFILE);
 }
 #endif
 
@@ -22014,12 +22354,23 @@ static int testLockingStyle(int fd){
 ** If SQLITE_ENABLE_LOCKING_STYLE is not defined, this function always
 ** returns LOCKING_STYLE_POSIX.
 */
+#if SQLITE_ENABLE_LOCKING_STYLE
 static int detectLockingStyle(
   sqlite3_vfs *pVfs,
   const char *filePath, 
   int fd
 ){
-#if SQLITE_ENABLE_LOCKING_STYLE
+#if IS_VXWORKS
+  if( !filePath ){
+    return LOCKING_STYLE_NONE;
+  }
+  if( pVfs->pAppData ){
+    return SQLITE_PTR_TO_INT(pVfs->pAppData);
+  }
+  if (access(filePath, 0) != -1){
+    return testLockingStyle(fd);
+  }
+#else
   struct Mapping {
     const char *zFilesystem;
     int eLockingStyle;
@@ -22059,9 +22410,12 @@ static int detectLockingStyle(
 
   /* Default case. Handles, amongst others, "nfs". */
   return testLockingStyle(fd);  
-#endif
+#endif /* if IS_VXWORKS */
   return LOCKING_STYLE_POSIX;
 }
+#else
+  #define detectLockingStyle(x,y,z) LOCKING_STYLE_POSIX
+#endif /* ifdef SQLITE_ENABLE_LOCKING_STYLE */
 
 /*
 ** Given a file descriptor, locate lockInfo and openCnt structures that
@@ -22072,6 +22426,9 @@ static int detectLockingStyle(
 */
 static int findLockInfo(
   int fd,                      /* The file descriptor used in the key */
+#if IS_VXWORKS
+  void *rnam,                  /* vxWorks realname */
+#endif
   struct lockInfo **ppLock,    /* Return the lockInfo structure here */
   struct openCnt **ppOpen      /* Return the openCnt structure here */
 ){
@@ -22109,7 +22466,11 @@ static int findLockInfo(
 
   memset(&key1, 0, sizeof(key1));
   key1.dev = statbuf.st_dev;
+#if IS_VXWORKS
+  key1.rnam = rnam;
+#else
   key1.ino = statbuf.st_ino;
+#endif
 #if SQLITE_THREADSAFE
   if( threadsOverrideEachOthersLocks<0 ){
     testThreadLockingBehavior(fd);
@@ -22118,7 +22479,11 @@ static int findLockInfo(
 #endif
   memset(&key2, 0, sizeof(key2));
   key2.dev = statbuf.st_dev;
+#if IS_VXWORKS
+  key2.rnam = rnam;
+#else
   key2.ino = statbuf.st_ino;
+#endif
   pLock = lockList;
   while( pLock && memcmp(&key1, &pLock->key, sizeof(key1)) ){
     pLock = pLock->pNext;
@@ -22162,6 +22527,10 @@ static int findLockInfo(
       pOpen->pPrev = 0;
       if( openList ) openList->pPrev = pOpen;
       openList = pOpen;
+#if IS_VXWORKS
+      pOpen->pSem = NULL;
+      pOpen->aSemName[0] = '\0';
+#endif
     }else{
       pOpen->nRef++;
     }
@@ -22226,7 +22595,11 @@ static int transferOwnership(unixFile *pFile){
   pFile->tid = hSelf;
   if (pFile->pLock != NULL) {
     releaseLockInfo(pFile->pLock);
+#if IS_VXWORKS
+    rc = findLockInfo(pFile->h, pFile->zRealpath, &pFile->pLock, 0);
+#else
     rc = findLockInfo(pFile->h, &pFile->pLock, 0);
+#endif
     OSTRACE5("LOCK    %d is now %s(%s,%d)\n", pFile->h,
            locktypeName(pFile->locktype),
            locktypeName(pFile->pLock->locktype), pFile->pLock->cnt);
@@ -22396,6 +22769,20 @@ SQLITE_API int sqlite3_fullsync_count = 0;
 static int full_fsync(int fd, int fullSync, int dataOnly){
   int rc;
 
+  /* The following "ifdef/elif/else/" block has the same structure as
+  ** the one below. It is replicated here solely to avoid cluttering 
+  ** up the real code with the UNUSED_PARAMETER() macros.
+  */
+#ifdef SQLITE_NO_SYNC
+  UNUSED_PARAMETER(fd);
+  UNUSED_PARAMETER(fullSync);
+  UNUSED_PARAMETER(dataOnly);
+#elif HAVE_FULLFSYNC
+  UNUSED_PARAMETER(dataOnly);
+#else
+  UNUSED_PARAMETER(fullSync);
+#endif
+
   /* Record the number of times that we do a normal fsync() and 
   ** FULLSYNC.  This is used during testing to verify that this procedure
   ** gets called with the correct arguments.
@@ -22410,9 +22797,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
   */
 #ifdef SQLITE_NO_SYNC
   rc = SQLITE_OK;
-#else
-
-#if HAVE_FULLFSYNC
+#elif HAVE_FULLFSYNC
   if( fullSync ){
     rc = fcntl(fd, F_FULLFSYNC, 0);
   }else{
@@ -22431,12 +22816,17 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
 #else 
   if( dataOnly ){
     rc = fdatasync(fd);
+    if( IS_VXWORKS && rc==-1 && errno==ENOTSUP ){
+      rc = fsync(fd);
+    }
   }else{
     rc = fsync(fd);
   }
-#endif /* HAVE_FULLFSYNC */
-#endif /* defined(SQLITE_NO_SYNC) */
+#endif /* ifdef SQLITE_NO_SYNC elif HAVE_FULLFSYNC */
 
+  if( IS_VXWORKS && rc!= -1 ){
+    rc = 0;
+  }
   return rc;
 }
 
@@ -23025,6 +23415,25 @@ static int closeUnixFile(sqlite3_file *id){
     if( pFile->h>=0 ){
       close(pFile->h);
     }
+#if IS_VXWORKS
+    if( pFile->isDelete && pFile->zRealpath ){
+      unlink(pFile->zRealpath);
+    }
+    if( pFile->zRealpath ){
+      HashElem *pElem;
+      int n = strlen(pFile->zRealpath) + 1;
+      pElem = sqlite3HashFindElem(&nameHash, pFile->zRealpath, n);
+      if( pElem ){
+        long cnt = (long)pElem->data;
+        cnt--;
+        if( cnt==0 ){
+          sqlite3HashInsert(&nameHash, pFile->zRealpath, n, 0);
+        }else{
+          pElem->data = (void*)cnt;
+        }
+      }
+    }
+#endif
     OSTRACE2("CLOSE   %-3d\n", pFile->h);
     OpenCounter(-1);
     memset(pFile, 0, sizeof(unixFile));
@@ -23068,6 +23477,8 @@ static int unixClose(sqlite3_file *id){
 
 
 #if SQLITE_ENABLE_LOCKING_STYLE
+
+#if !IS_VXWORKS
 #pragma mark AFP Support
 
 /*
@@ -23515,6 +23926,8 @@ static int flockClose(sqlite3_file *id) {
   return closeUnixFile(id);
 }
 
+#endif /* !IS_VXWORKS */
+
 #pragma mark Old-School .lock file based locking
 
 /* Dotlock-style reserved lock checking following the behavior of 
@@ -23543,7 +23956,7 @@ static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) {
       reserved = 1;
     }else{
       /* file does not exist, we could have it if we want it */
-                       int tErrno = errno;
+      int tErrno = errno;
       if( ENOENT != tErrno ){
         rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
         pFile->lastErrno = tErrno;
@@ -23566,9 +23979,10 @@ static int dotlockLock(sqlite3_file *id, int locktype) {
   ** Just adjust level and punt on outta here. */
   if (pFile->locktype > NO_LOCK) {
     pFile->locktype = locktype;
-    
+#if !IS_VXWORKS
     /* Always update the timestamp on the old file */
     utimes(zLockFile, NULL);
+#endif
     rc = SQLITE_OK;
     goto dotlock_end_lock;
   }
@@ -23643,14 +24057,142 @@ static int dotlockUnlock(sqlite3_file *id, int locktype) {
  ** Close a file.
  */
 static int dotlockClose(sqlite3_file *id) {
+  int rc;
   if( id ){
     unixFile *pFile = (unixFile*)id;
     dotlockUnlock(id, NO_LOCK);
     sqlite3_free(pFile->lockingContext);
   }
-  return closeUnixFile(id);
+  if( IS_VXWORKS ) enterMutex();
+  rc = closeUnixFile(id);
+  if( IS_VXWORKS ) leaveMutex();
+  return rc;
+}
+
+#if IS_VXWORKS
+
+#pragma mark POSIX/vxWorks named semaphore based locking
+
+/* Namedsem-style reserved lock checking following the behavior of 
+** unixCheckReservedLock, see the unixCheckReservedLock function comments */
+static int namedsemCheckReservedLock(sqlite3_file *id, int *pResOut) {
+  int rc = SQLITE_OK;
+  int reserved = 0;
+  unixFile *pFile = (unixFile*)id;
+
+  SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
+  
+  assert( pFile );
+
+  /* Check if a thread in this process holds such a lock */
+  if( pFile->locktype>SHARED_LOCK ){
+    reserved = 1;
+  }
+  
+  /* Otherwise see if some other process holds it. */
+  if( !reserved ){
+    sem_t *pSem = pFile->pOpen->pSem;
+    struct stat statBuf;
+
+    if( sem_trywait(pSem)==-1 ){
+      int tErrno = errno;
+      if( EAGAIN != tErrno ){
+        rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
+        pFile->lastErrno = tErrno;
+      } else {
+       /* someone else has the lock when we are in NO_LOCK */
+       reserved = (pFile->locktype < SHARED_LOCK);
+      }
+    }else{
+      /* we could have it if we want it */
+      sem_post(pSem);
+    }
+  }
+  OSTRACE4("TEST WR-LOCK %d %d %d\n", pFile->h, rc, reserved);
+
+  *pResOut = reserved;
+  return rc;
+}
+
+static int namedsemLock(sqlite3_file *id, int locktype) {
+  unixFile *pFile = (unixFile*)id;
+  int fd;
+  sem_t *pSem = pFile->pOpen->pSem;
+  int rc = SQLITE_OK;
+
+  /* if we already have a lock, it is exclusive.  
+  ** Just adjust level and punt on outta here. */
+  if (pFile->locktype > NO_LOCK) {
+    pFile->locktype = locktype;
+    rc = SQLITE_OK;
+    goto namedsem_end_lock;
+  }
+  
+  /* lock semaphore now but bail out when already locked. */
+  if( sem_trywait(pSem)==-1 ){
+    rc = SQLITE_BUSY;
+    goto namedsem_end_lock;
+  }
+
+  /* got it, set the type and return ok */
+  pFile->locktype = locktype;
+
+ namedsem_end_lock:
+  return rc;
+}
+
+static int namedsemUnlock(sqlite3_file *id, int locktype) {
+  unixFile *pFile = (unixFile*)id;
+  sem_t *pSem = pFile->pOpen->pSem;
+
+  assert( pFile );
+  assert( pSem );
+  OSTRACE5("UNLOCK  %d %d was %d pid=%d\n", pFile->h, locktype,
+          pFile->locktype, getpid());
+  assert( locktype<=SHARED_LOCK );
+  
+  /* no-op if possible */
+  if( pFile->locktype==locktype ){
+    return SQLITE_OK;
+  }
+  
+  /* shared can just be set because we always have an exclusive */
+  if (locktype==SHARED_LOCK) {
+    pFile->locktype = locktype;
+    return SQLITE_OK;
+  }
+  
+  /* no, really unlock. */
+  if ( sem_post(pSem)==-1 ) {
+    int rc, tErrno = errno;
+    rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
+    if( IS_LOCK_ERROR(rc) ){
+      pFile->lastErrno = tErrno;
+    }
+    return rc; 
+  }
+  pFile->locktype = NO_LOCK;
+  return SQLITE_OK;
+}
+
+/*
+ ** Close a file.
+ */
+static int namedsemClose(sqlite3_file *id) {
+  if( id ){
+    unixFile *pFile = (unixFile*)id;
+    namedsemUnlock(id, NO_LOCK);
+    assert( pFile );
+    enterMutex();
+    releaseLockInfo(pFile->pLock);
+    releaseOpenCnt(pFile->pOpen);
+    closeUnixFile(id);
+    leaveMutex();
+  }
+  return SQLITE_OK;
 }
 
+#endif /* IS_VXWORKS */
 
 #endif /* SQLITE_ENABLE_LOCKING_STYLE */
 
@@ -23659,16 +24201,19 @@ static int dotlockClose(sqlite3_file *id) {
 */
 typedef void nolockLockingContext;
 
-static int nolockCheckReservedLock(sqlite3_file *id, int *pResOut) {
+static int nolockCheckReservedLock(sqlite3_file *NotUsed, int *pResOut){
+  UNUSED_PARAMETER(NotUsed);
   *pResOut = 0;
   return SQLITE_OK;
 }
 
-static int nolockLock(sqlite3_file *id, int locktype) {
+static int nolockLock(sqlite3_file *NotUsed, int NotUsed2){
+  UNUSED_PARAMETER2(NotUsed, NotUsed2);
   return SQLITE_OK;
 }
 
-static int nolockUnlock(sqlite3_file *id, int locktype) {
+static int nolockUnlock(sqlite3_file *NotUsed, int NotUsed2){
+  UNUSED_PARAMETER2(NotUsed, NotUsed2);
   return SQLITE_OK;
 }
 
@@ -23676,7 +24221,11 @@ static int nolockUnlock(sqlite3_file *id, int locktype) {
 ** Close a file.
 */
 static int nolockClose(sqlite3_file *id) {
-  return closeUnixFile(id);
+  int rc;
+  if( IS_VXWORKS ) enterMutex();
+  rc = closeUnixFile(id);
+  if( IS_VXWORKS ) leaveMutex();
+  return rc;
 }
 
 
@@ -23703,14 +24252,16 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
 ** a database and its journal file) that the sector size will be the
 ** same for both.
 */
-static int unixSectorSize(sqlite3_file *id){
+static int unixSectorSize(sqlite3_file *NotUsed){
+  UNUSED_PARAMETER(NotUsed);
   return SQLITE_DEFAULT_SECTOR_SIZE;
 }
 
 /*
-** Return the device characteristics for the file. This is always 0.
+** Return the device characteristics for the file. This is always 0 for unix.
 */
-static int unixDeviceCharacteristics(sqlite3_file *id){
+static int unixDeviceCharacteristics(sqlite3_file *NotUsed){
+  UNUSED_PARAMETER(NotUsed);
   return 0;
 }
 
@@ -23728,7 +24279,8 @@ static int fillInUnixFile(
   int dirfd,              /* Directory file descriptor */
   sqlite3_file *pId,      /* Write to the unixFile structure here */
   const char *zFilename,  /* Name of the file being opened */
-  int noLock              /* Omit locking if true */
+  int noLock,             /* Omit locking if true */
+  int isDelete            /* Delete on close if true */
 ){
   int eLockingStyle;
   unixFile *pNew = (unixFile *)pId;
@@ -23759,8 +24311,15 @@ static int fillInUnixFile(
    ,IOMETHODS(nolockClose, nolockLock, nolockUnlock, nolockCheckReservedLock)
 #if SQLITE_ENABLE_LOCKING_STYLE
    ,IOMETHODS(dotlockClose, dotlockLock, dotlockUnlock,dotlockCheckReservedLock)
+#if IS_VXWORKS
+   ,IOMETHODS(nolockClose, nolockLock, nolockUnlock, nolockCheckReservedLock)
+   ,IOMETHODS(nolockClose, nolockLock, nolockUnlock, nolockCheckReservedLock)
+   ,IOMETHODS(namedsemClose, namedsemLock, namedsemUnlock, namedsemCheckReservedLock)
+#else
    ,IOMETHODS(flockClose, flockLock, flockUnlock, flockCheckReservedLock)
    ,IOMETHODS(afpClose, afpLock, afpUnlock, afpCheckReservedLock)
+   ,IOMETHODS(nolockClose, nolockLock, nolockUnlock, nolockCheckReservedLock)
+#endif
 #endif
   };
   /* The order of the IOMETHODS macros above is important.  It must be the
@@ -23771,15 +24330,60 @@ static int fillInUnixFile(
   assert(LOCKING_STYLE_DOTFILE==3);
   assert(LOCKING_STYLE_FLOCK==4);
   assert(LOCKING_STYLE_AFP==5);
+  assert(LOCKING_STYLE_NAMEDSEM==6);
 
   assert( pNew->pLock==NULL );
   assert( pNew->pOpen==NULL );
 
+  /* Parameter isDelete is only used on vxworks. Parameter pVfs is only
+  ** used if ENABLE_LOCKING_STYLE is defined. Express this explicitly 
+  ** here to prevent compiler warnings about unused parameters.
+  */
+  if( !IS_VXWORKS ) UNUSED_PARAMETER(isDelete);
+  if( !SQLITE_ENABLE_LOCKING_STYLE ) UNUSED_PARAMETER(pVfs);
+  if( !IS_VXWORKS && !SQLITE_ENABLE_LOCKING_STYLE ) UNUSED_PARAMETER(zFilename);
+
   OSTRACE3("OPEN    %-3d %s\n", h, zFilename);    
   pNew->h = h;
   pNew->dirfd = dirfd;
   SET_THREADID(pNew);
 
+#if IS_VXWORKS
+  {
+    HashElem *pElem;
+    char *zRealname = vxrealpath(zFilename, 1);
+    int n;
+    pNew->zRealpath = 0;
+    if( !zRealname ){
+      rc = SQLITE_NOMEM;
+      eLockingStyle = LOCKING_STYLE_NONE;
+    }else{
+      n = strlen(zRealname) + 1;
+      enterMutex();
+      pElem = sqlite3HashFindElem(&nameHash, zRealname, n);
+      if( pElem ){
+        long cnt = (long)pElem->data;
+        cnt++;
+        pNew->zRealpath = pElem->pKey;
+        pElem->data = (void*)cnt;
+      }else{
+        if( sqlite3HashInsert(&nameHash, zRealname, n, (void*)1)==0 ){
+          pElem = sqlite3HashFindElem(&nameHash, zRealname, n);
+          if( pElem ){
+            pNew->zRealpath = pElem->pKey;
+          }else{
+            sqlite3HashInsert(&nameHash, zRealname, n, 0);
+            rc = SQLITE_NOMEM;
+            eLockingStyle = LOCKING_STYLE_NONE;
+          }
+        }
+      }
+      leaveMutex();
+      sqlite3_free(zRealname);
+    }
+  }
+#endif
+
   if( noLock ){
     eLockingStyle = LOCKING_STYLE_NONE;
   }else{
@@ -23790,12 +24394,18 @@ static int fillInUnixFile(
 
     case LOCKING_STYLE_POSIX: {
       enterMutex();
+#if IS_VXWORKS
+      rc = findLockInfo(h, pNew->zRealpath, &pNew->pLock, &pNew->pOpen);
+#else
       rc = findLockInfo(h, &pNew->pLock, &pNew->pOpen);
+#endif
       leaveMutex();
       break;
     }
 
 #if SQLITE_ENABLE_LOCKING_STYLE
+
+#if !IS_VXWORKS
     case LOCKING_STYLE_AFP: {
       /* AFP locking uses the file path so it needs to be included in
       ** the afpLockingContext.
@@ -23813,6 +24423,7 @@ static int fillInUnixFile(
       }
       break;
     }
+#endif
 
     case LOCKING_STYLE_DOTFILE: {
       /* Dotfile locking uses the file path so it needs to be included in
@@ -23831,6 +24442,30 @@ static int fillInUnixFile(
       break;
     }
 
+#if IS_VXWORKS
+    case LOCKING_STYLE_NAMEDSEM: {
+      /* Named semaphore locking uses the file path so it needs to be
+      ** included in the namedsemLockingContext
+      */
+      enterMutex();
+      rc = findLockInfo(h, pNew->zRealpath, &pNew->pLock, &pNew->pOpen);
+      if( (rc==SQLITE_OK) && (pNew->pOpen->pSem==NULL) ){
+        char *zSemName = pNew->pOpen->aSemName;
+        int n;
+        sqlite3_snprintf(MAX_PATHNAME, zSemName, "%s.sem", pNew->zRealpath);
+        for( n=0; zSemName[n]; n++ )
+          if( zSemName[n]=='/' ) zSemName[n] = '_';
+        pNew->pOpen->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
+        if( pNew->pOpen->pSem == SEM_FAILED ){
+          rc = SQLITE_NOMEM;
+          pNew->pOpen->aSemName[0] = '\0';
+        }
+      }
+      leaveMutex();
+      break;
+    }
+#endif
+
     case LOCKING_STYLE_FLOCK: 
     case LOCKING_STYLE_NONE: 
       break;
@@ -23838,6 +24473,13 @@ static int fillInUnixFile(
   }
   
   pNew->lastErrno = 0;
+#if IS_VXWORKS
+  if( rc!=SQLITE_OK ){
+    unlink(zFilename);
+    isDelete = 0;
+  }
+  pNew->isDelete = isDelete;
+#endif
   if( rc!=SQLITE_OK ){
     if( dirfd>=0 ) close(dirfd);
     close(h);
@@ -23907,7 +24549,7 @@ static int getTempname(int nBuf, char *zBuf){
   SimulateIOError( return SQLITE_IOERR );
 
   azDirs[0] = sqlite3_temp_directory;
-  for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
+  for(i=0; i<ArraySize(azDirs); i++){
     if( azDirs[i]==0 ) continue;
     if( stat(azDirs[i], &buf) ) continue;
     if( !S_ISDIR(buf.st_mode) ) continue;
@@ -23919,7 +24561,7 @@ static int getTempname(int nBuf, char *zBuf){
   /* Check that the output buffer is large enough for the temporary file 
   ** name. If it is not, return SQLITE_ERROR.
   */
-  if( (strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 17) >= nBuf ){
+  if( (strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 17) >= (size_t)nBuf ){
     return SQLITE_ERROR;
   }
 
@@ -24036,6 +24678,7 @@ static int unixOpen(
   oflags |= (O_LARGEFILE|O_BINARY);
 
   fd = open(zName, oflags, isDelete?0600:SQLITE_DEFAULT_FILE_PERMISSIONS);
+  OSTRACE4("OPENX   %-3d %s 0%o\n", fd, zName, oflags);
   if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
     /* Failed to open the file for read/write access. Try read-only. */
     flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
@@ -24046,7 +24689,11 @@ static int unixOpen(
     return SQLITE_CANTOPEN;
   }
   if( isDelete ){
+#if IS_VXWORKS
+    zPath = zName;
+#else
     unlink(zName);
+#endif
   }
   if( pOutFlags ){
     *pOutFlags = flags;
@@ -24066,15 +24713,16 @@ static int unixOpen(
 #endif
 
   noLock = eType!=SQLITE_OPEN_MAIN_DB;
-  return fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock);
+  return fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
 }
 
 /*
 ** Delete the file at zPath. If the dirSync argument is true, fsync()
 ** the directory after deleting the file.
 */
-static int unixDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+static int unixDelete(sqlite3_vfs *NotUsed, const char *zPath, int dirSync){
   int rc = SQLITE_OK;
+  UNUSED_PARAMETER(NotUsed);
   SimulateIOError(return SQLITE_IOERR_DELETE);
   unlink(zPath);
 #ifndef SQLITE_DISABLE_DIRSYNC
@@ -24082,7 +24730,12 @@ static int unixDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
     int fd;
     rc = openDirectory(zPath, &fd);
     if( rc==SQLITE_OK ){
-      if( fsync(fd) ){
+#if IS_VXWORKS
+      if( fsync(fd)==-1 )
+#else
+      if( fsync(fd) )
+#endif
+      {
         rc = SQLITE_IOERR_DIR_FSYNC;
       }
       close(fd);
@@ -24103,12 +24756,13 @@ static int unixDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
 ** Otherwise return 0.
 */
 static int unixAccess(
-  sqlite3_vfs *pVfs
+  sqlite3_vfs *NotUsed
   const char *zPath, 
   int flags, 
   int *pResOut
 ){
   int amode = 0;
+  UNUSED_PARAMETER(NotUsed);
   SimulateIOError( return SQLITE_IOERR_ACCESS; );
   switch( flags ){
     case SQLITE_ACCESS_EXISTS:
@@ -24153,6 +24807,20 @@ static int unixFullPathname(
   SimulateIOError( return SQLITE_ERROR );
 
   assert( pVfs->mxPathname==MAX_PATHNAME );
+  UNUSED_PARAMETER(pVfs);
+
+#if IS_VXWORKS
+  {
+    char *zRealname = vxrealpath(zPath, 0);
+    zOut[0] = '\0';
+    if( !zRealname ){
+      return SQLITE_CANTOPEN;
+    }
+    sqlite3_snprintf(nOut, zOut, "%s", zRealname);
+    sqlite3_free(zRealname);
+    return SQLITE_OK;
+  }
+#else
   zOut[nOut-1] = '\0';
   if( zPath[0]=='/' ){
     sqlite3_snprintf(nOut, zOut, "%s", zPath);
@@ -24191,6 +24859,7 @@ static int unixFullPathname(
     zFull[j] = 0;
   }
 #endif
+#endif
 }
 
 
@@ -24200,7 +24869,8 @@ static int unixFullPathname(
 ** within the shared library, and closing the shared library.
 */
 #include <dlfcn.h>
-static void *unixDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
+static void *unixDlOpen(sqlite3_vfs *NotUsed, const char *zFilename){
+  UNUSED_PARAMETER(NotUsed);
   return dlopen(zFilename, RTLD_NOW | RTLD_GLOBAL);
 }
 
@@ -24211,8 +24881,9 @@ static void *unixDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
 ** is available, zBufOut is left unmodified and SQLite uses a default
 ** error message.
 */
-static void unixDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
+static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){
   char *zErr;
+  UNUSED_PARAMETER(NotUsed);
   enterMutex();
   zErr = dlerror();
   if( zErr ){
@@ -24220,10 +24891,12 @@ static void unixDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
   }
   leaveMutex();
 }
-static void *unixDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
+static void *unixDlSym(sqlite3_vfs *NotUsed, void *pHandle, const char*zSymbol){
+  UNUSED_PARAMETER(NotUsed);
   return dlsym(pHandle, zSymbol);
 }
-static void unixDlClose(sqlite3_vfs *pVfs, void *pHandle){
+static void unixDlClose(sqlite3_vfs *NotUsed, void *pHandle){
+  UNUSED_PARAMETER(NotUsed);
   dlclose(pHandle);
 }
 #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
@@ -24236,9 +24909,9 @@ static void unixDlClose(sqlite3_vfs *pVfs, void *pHandle){
 /*
 ** Write nBuf bytes of random data to the supplied buffer zBuf.
 */
-static int unixRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
-
-  assert(nBuf>=(sizeof(time_t)+sizeof(int)));
+static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
+  UNUSED_PARAMETER(NotUsed);
+  assert((size_t)nBuf>=(sizeof(time_t)+sizeof(int)));
 
   /* We have to initialize zBuf to prevent valgrind from reporting
   ** errors.  The reports issued by valgrind are incorrect - we would
@@ -24263,7 +24936,7 @@ static int unixRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
       memcpy(zBuf, &t, sizeof(t));
       pid = getpid();
       memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid));
-      assert( sizeof(t)+sizeof(pid)<=nBuf );
+      assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf );
       nBuf = sizeof(t) + sizeof(pid);
     }else{
       nBuf = read(fd, zBuf, nBuf);
@@ -24283,8 +24956,15 @@ static int unixRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
 ** might be greater than or equal to the argument, but not less
 ** than the argument.
 */
-static int unixSleep(sqlite3_vfs *pVfs, int microseconds){
-#if defined(HAVE_USLEEP) && HAVE_USLEEP
+static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){
+#if IS_VXWORKS
+  struct timespec sp;
+
+  sp.tv_sec = microseconds / 1000000;
+  sp.tv_nsec = (microseconds % 1000000) * 1000;
+  nanosleep(&sp, NULL);
+  return microseconds;
+#elif defined(HAVE_USLEEP) && HAVE_USLEEP
   usleep(microseconds);
   return microseconds;
 #else
@@ -24292,6 +24972,7 @@ static int unixSleep(sqlite3_vfs *pVfs, int microseconds){
   sleep(seconds);
   return seconds*1000000;
 #endif
+  UNUSED_PARAMETER(NotUsed);
 }
 
 /*
@@ -24307,8 +24988,12 @@ SQLITE_API int sqlite3_current_time = 0;
 ** current time and date as a Julian Day number into *prNow and
 ** return 0.  Return 1 if the time and date cannot be found.
 */
-static int unixCurrentTime(sqlite3_vfs *pVfs, double *prNow){
-#ifdef NO_GETTOD
+static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
+#if IS_VXWORKS
+  struct timespec sNow;
+  clock_gettime(CLOCK_REALTIME, &sNow);
+  *prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_nsec/86400000000000.0;
+#elif defined(NO_GETTOD)
   time_t t;
   time(&t);
   *prNow = t/86400.0 + 2440587.5;
@@ -24317,15 +25002,20 @@ static int unixCurrentTime(sqlite3_vfs *pVfs, double *prNow){
   gettimeofday(&sNow, 0);
   *prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_usec/86400000000.0;
 #endif
+
 #ifdef SQLITE_TEST
   if( sqlite3_current_time ){
     *prNow = sqlite3_current_time/86400.0 + 2440587.5;
   }
 #endif
+  UNUSED_PARAMETER(NotUsed);
   return 0;
 }
 
-static int unixGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
+  UNUSED_PARAMETER(NotUsed);
+  UNUSED_PARAMETER(NotUsed2);
+  UNUSED_PARAMETER(NotUsed3);
   return 0;
 }
 
@@ -24367,11 +25057,15 @@ SQLITE_API int sqlite3_os_init(void){
     UNIXVFS("unix-afp",     LOCKING_STYLE_AFP), 
     UNIXVFS("unix-flock",   LOCKING_STYLE_FLOCK), 
     UNIXVFS("unix-dotfile", LOCKING_STYLE_DOTFILE), 
-    UNIXVFS("unix-none",    LOCKING_STYLE_NONE)
+    UNIXVFS("unix-none",    LOCKING_STYLE_NONE),
+    UNIXVFS("unix-namedsem",LOCKING_STYLE_NAMEDSEM),
   };
   for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
     sqlite3_vfs_register(&aVfs[i], 0);
   }
+#endif
+#if IS_VXWORKS
+  sqlite3HashInit(&nameHash, 1);
 #endif
   sqlite3_vfs_register(&unixVfs, 1);
   return SQLITE_OK; 
@@ -24873,7 +25567,7 @@ static char *unicodeToMbcs(const WCHAR *zWideFilename){
 ** Convert multibyte character string to UTF-8.  Space to hold the
 ** returned string is obtained from malloc().
 */
-static char *mbcsToUtf8(const char *zFilename){
+SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){
   char *zFilenameUtf8;
   WCHAR *zTmpWide;
 
@@ -25371,11 +26065,18 @@ static int winSync(sqlite3_file *id, int flags){
   }
   sqlite3_sync_count++;
 #endif
+  /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
+  ** no-op
+  */
+#ifdef SQLITE_NO_SYNC
+    return SQLITE_OK;
+#else
   if( FlushFileBuffers(pFile->h) ){
     return SQLITE_OK;
   }else{
     return SQLITE_IOERR;
   }
+#endif
 }
 
 /*
@@ -25753,7 +26454,7 @@ static int getTempname(int nBuf, char *zBuf){
     char *zUtf8;
     char zMbcsPath[MAX_PATH];
     GetTempPathA(MAX_PATH-30, zMbcsPath);
-    zUtf8 = mbcsToUtf8(zMbcsPath);
+    zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
     if( zUtf8 ){
       sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8);
       free(zUtf8);
@@ -26094,7 +26795,7 @@ static int winFullPathname(
     }
     GetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
     free(zConverted);
-    zOut = mbcsToUtf8(zTemp);
+    zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
     free(zTemp);
 #endif
   }
@@ -26348,17 +27049,38 @@ SQLITE_API int sqlite3_os_end(void){
 ** @(#) $Id$
 */
 
+/* Size of the Bitvec structure in bytes. */
 #define BITVEC_SZ        512
+
 /* Round the union size down to the nearest pointer boundary, since that's how 
 ** it will be aligned within the Bitvec struct. */
-#define BITVEC_USIZE     (((BITVEC_SZ-12)/sizeof(Bitvec*))*sizeof(Bitvec*))
-#define BITVEC_NCHAR     BITVEC_USIZE
-#define BITVEC_NBIT      (BITVEC_NCHAR*8)
-#define BITVEC_NINT      (BITVEC_USIZE/4)
+#define BITVEC_USIZE     (((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*))
+
+/* Type of the array "element" for the bitmap representation. 
+** Should be a power of 2, and ideally, evenly divide into BITVEC_USIZE. 
+** Setting this to the "natural word" size of your CPU may improve
+** performance. */
+#define BITVEC_TELEM     u8
+/* Size, in bits, of the bitmap element. */
+#define BITVEC_SZELEM    8
+/* Number of elements in a bitmap array. */
+#define BITVEC_NELEM     (BITVEC_USIZE/sizeof(BITVEC_TELEM))
+/* Number of bits in the bitmap array. */
+#define BITVEC_NBIT      (BITVEC_NELEM*BITVEC_SZELEM)
+
+/* Number of u32 values in hash table. */
+#define BITVEC_NINT      (BITVEC_USIZE/sizeof(u32))
+/* Maximum number of entries in hash table before 
+** sub-dividing and re-hashing. */
 #define BITVEC_MXHASH    (BITVEC_NINT/2)
+/* Hashing function for the aHash representation.
+** Empirical testing showed that the *37 multiplier 
+** (an arbitrary prime)in the hash function provided 
+** no fewer collisions than the no-op *1. */
+#define BITVEC_HASH(X)   (((X)*1)%BITVEC_NINT)
+
 #define BITVEC_NPTR      (BITVEC_USIZE/sizeof(Bitvec *))
 
-#define BITVEC_HASH(X)   (((X)*37)%BITVEC_NINT)
 
 /*
 ** A bitmap is an instance of the following structure.
@@ -26382,11 +27104,15 @@ SQLITE_API int sqlite3_os_end(void){
 ** to hold deal with values between 1 and iDivisor.
 */
 struct Bitvec {
-  u32 iSize;      /* Maximum bit index */
-  u32 nSet;       /* Number of bits that are set */
-  u32 iDivisor;   /* Number of bits handled by each apSub[] entry */
+  u32 iSize;      /* Maximum bit index.  Max iSize is 4,294,967,296. */
+  u32 nSet;       /* Number of bits that are set - only valid for aHash element */
+                  /* Max nSet is BITVEC_NINT.  For BITVEC_SZ of 512, this would be 125. */
+  u32 iDivisor;   /* Number of bits handled by each apSub[] entry. */
+                  /* Should >=0 for apSub element. */
+                  /* Max iDivisor is max(u32) / BITVEC_NPTR + 1.  */
+                  /* For a BITVEC_SZ of 512, this would be 34,359,739. */
   union {
-    u8 aBitmap[BITVEC_NCHAR];    /* Bitmap representation */
+    BITVEC_TELEM aBitmap[BITVEC_NELEM];    /* Bitmap representation */
     u32 aHash[BITVEC_NINT];      /* Hash table representation */
     Bitvec *apSub[BITVEC_NPTR];  /* Recursive representation */
   } u;
@@ -26415,16 +27141,19 @@ SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32 iSize){
 SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec *p, u32 i){
   if( p==0 ) return 0;
   if( i>p->iSize || i==0 ) return 0;
-  if( p->iSize<=BITVEC_NBIT ){
-    i--;
-    return (p->u.aBitmap[i/8] & (1<<(i&7)))!=0;
+  i--;
+  while( p->iDivisor ){
+    u32 bin = i/p->iDivisor;
+    i = i%p->iDivisor;
+    p = p->u.apSub[bin];
+    if (!p) {
+      return 0;
+    }
   }
-  if( p->iDivisor>0 ){
-    u32 bin = (i-1)/p->iDivisor;
-    i = (i-1)%p->iDivisor + 1;
-    return sqlite3BitvecTest(p->u.apSub[bin], i);
-  }else{
-    u32 h = BITVEC_HASH(i);
+  if( p->iSize<=BITVEC_NBIT ){
+    return (p->u.aBitmap[i/BITVEC_SZELEM] & (1<<(i&(BITVEC_SZELEM-1))))!=0;
+  } else{
+    u32 h = BITVEC_HASH(i++);
     while( p->u.aHash[h] ){
       if( p->u.aHash[h]==i ) return 1;
       h++;
@@ -26451,35 +27180,50 @@ SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec *p, u32 i){
   assert( p!=0 );
   assert( i>0 );
   assert( i<=p->iSize );
-  if( p->iSize<=BITVEC_NBIT ){
-    i--;
-    p->u.aBitmap[i/8] |= 1 << (i&7);
-    return SQLITE_OK;
-  }
-  if( p->iDivisor ){
-    u32 bin = (i-1)/p->iDivisor;
-    i = (i-1)%p->iDivisor + 1;
+  i--;
+  while((p->iSize > BITVEC_NBIT) && p->iDivisor) {
+    u32 bin = i/p->iDivisor;
+    i = i%p->iDivisor;
     if( p->u.apSub[bin]==0 ){
       sqlite3BeginBenignMalloc();
       p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor );
       sqlite3EndBenignMalloc();
       if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM;
     }
-    return sqlite3BitvecSet(p->u.apSub[bin], i);
+    p = p->u.apSub[bin];
+  }
+  if( p->iSize<=BITVEC_NBIT ){
+    p->u.aBitmap[i/BITVEC_SZELEM] |= 1 << (i&(BITVEC_SZELEM-1));
+    return SQLITE_OK;
   }
-  h = BITVEC_HASH(i);
-  while( p->u.aHash[h] ){
+  h = BITVEC_HASH(i++);
+  /* if there wasn't a hash collision, and this doesn't */
+  /* completely fill the hash, then just add it without */
+  /* worring about sub-dividing and re-hashing. */
+  if( !p->u.aHash[h] ){
+    if (p->nSet<(BITVEC_NINT-1)) {
+      goto bitvec_set_end;
+    } else {
+      goto bitvec_set_rehash;
+    }
+  }
+  /* there was a collision, check to see if it's already */
+  /* in hash, if not, try to find a spot for it */
+  do {
     if( p->u.aHash[h]==i ) return SQLITE_OK;
     h++;
-    if( h==BITVEC_NINT ) h = 0;
-  }
-  p->nSet++;
+    if( h>=BITVEC_NINT ) h = 0;
+  } while( p->u.aHash[h] );
+  /* we didn't find it in the hash.  h points to the first */
+  /* available free spot. check to see if this is going to */
+  /* make our hash too "full".  */
+bitvec_set_rehash:
   if( p->nSet>=BITVEC_MXHASH ){
     unsigned int j;
     int rc;
     u32 aiValues[BITVEC_NINT];
     memcpy(aiValues, p->u.aHash, sizeof(aiValues));
-    memset(p->u.apSub, 0, sizeof(p->u.apSub[0])*BITVEC_NPTR);
+    memset(p->u.apSub, 0, sizeof(aiValues));
     p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR;
     rc = sqlite3BitvecSet(p, i);
     for(j=0; j<BITVEC_NINT; j++){
@@ -26487,35 +27231,44 @@ SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec *p, u32 i){
     }
     return rc;
   }
+bitvec_set_end:
+  p->nSet++;
   p->u.aHash[h] = i;
   return SQLITE_OK;
 }
 
 /*
-** Clear the i-th bit.  Return 0 on success and an error code if
-** anything goes wrong.
+** Clear the i-th bit.
 */
 SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec *p, u32 i){
   assert( p!=0 );
   assert( i>0 );
-  if( p->iSize<=BITVEC_NBIT ){
-    i--;
-    p->u.aBitmap[i/8] &= ~(1 << (i&7));
-  }else if( p->iDivisor ){
-    u32 bin = (i-1)/p->iDivisor;
-    i = (i-1)%p->iDivisor + 1;
-    if( p->u.apSub[bin] ){
-      sqlite3BitvecClear(p->u.apSub[bin], i);
+  i--;
+  while( p->iDivisor ){
+    u32 bin = i/p->iDivisor;
+    i = i%p->iDivisor;
+    p = p->u.apSub[bin];
+    if (!p) {
+      return;
     }
+  }
+  if( p->iSize<=BITVEC_NBIT ){
+    p->u.aBitmap[i/BITVEC_SZELEM] &= ~(1 << (i&(BITVEC_SZELEM-1)));
   }else{
     unsigned int j;
     u32 aiValues[BITVEC_NINT];
     memcpy(aiValues, p->u.aHash, sizeof(aiValues));
-    memset(p->u.aHash, 0, sizeof(p->u.aHash[0])*BITVEC_NINT);
+    memset(p->u.aHash, 0, sizeof(aiValues));
     p->nSet = 0;
     for(j=0; j<BITVEC_NINT; j++){
-      if( aiValues[j] && aiValues[j]!=i ){
-        sqlite3BitvecSet(p, aiValues[j]);
+      if( aiValues[j] && aiValues[j]!=(i+1) ){
+        u32 h = BITVEC_HASH(aiValues[j]-1);
+        p->nSet++;
+        while( p->u.aHash[h] ){
+          h++;
+          if( h>=BITVEC_NINT ) h = 0;
+        }
+        p->u.aHash[h] = aiValues[j];
       }
     }
   }
@@ -26665,98 +27418,22 @@ bitvec_end:
 
 /*
 ** A complete page cache is an instance of this structure.
-**
-** A cache may only be deleted by its owner and while holding the
-** SQLITE_MUTEX_STATUS_LRU mutex.
 */
 struct PCache {
-  /*********************************************************************
-  ** The first group of elements may be read or written at any time by
-  ** the cache owner without holding the mutex.  No thread other than the
-  ** cache owner is permitted to access these elements at any time.
-  */
   PgHdr *pDirty, *pDirtyTail;         /* List of dirty pages in LRU order */
   PgHdr *pSynced;                     /* Last synced page in dirty page list */
-  int nRef;                           /* Number of pinned pages */
-  int nPinned;                        /* Number of pinned and/or dirty pages */
+  int nRef;                           /* Number of referenced pages */
   int nMax;                           /* Configured cache size */
   int nMin;                           /* Configured minimum cache size */
-  /**********************************************************************
-  ** The next group of elements are fixed when the cache is created and
-  ** may not be changed afterwards.  These elements can read at any time by
-  ** the cache owner or by any thread holding the the mutex.  Non-owner
-  ** threads must hold the mutex when reading these elements to prevent
-  ** the entire PCache object from being deleted during the read.
-  */
   int szPage;                         /* Size of every page in this cache */
   int szExtra;                        /* Size of extra space for each page */
   int bPurgeable;                     /* True if pages are on backing store */
   int (*xStress)(void*,PgHdr*);       /* Call to try make a page clean */
   void *pStress;                      /* Argument to xStress */
-  /**********************************************************************
-  ** The final group of elements can only be accessed while holding the
-  ** mutex.  Both the cache owner and any other thread must hold the mutex
-  ** to read or write any of these elements.
-  */
-  int nPage;                          /* Total number of pages in apHash */
-  int nHash;                          /* Number of slots in apHash[] */
-  PgHdr **apHash;                     /* Hash table for fast lookup by pgno */
-  PgHdr *pClean;                      /* List of clean pages in use */
-};
-
-/*
-** Free slots in the page block allocator
-*/
-typedef struct PgFreeslot PgFreeslot;
-struct PgFreeslot {
-  PgFreeslot *pNext;  /* Next free slot */
+  sqlite3_pcache *pCache;             /* Pluggable cache module */
+  PgHdr *pPage1;
 };
 
-/*
-** Global data for the page cache.
-*/
-static SQLITE_WSD struct PCacheGlobal {
-  int isInit;                         /* True when initialized */
-  sqlite3_mutex *mutex;               /* static mutex MUTEX_STATIC_LRU */
-
-  int nMaxPage;                       /* Sum of nMaxPage for purgeable caches */
-  int nMinPage;                       /* Sum of nMinPage for purgeable caches */
-  int nCurrentPage;                   /* Number of purgeable pages allocated */
-  PgHdr *pLruHead, *pLruTail;         /* LRU list of unused clean pgs */
-
-  /* Variables related to SQLITE_CONFIG_PAGECACHE settings. */
-  int szSlot;                         /* Size of each free slot */
-  void *pStart, *pEnd;                /* Bounds of pagecache malloc range */
-  PgFreeslot *pFree;                  /* Free page blocks */
-} pcache = {0};
-
-/*
-** All code in this file should access the global pcache structure via the
-** alias "pcache_g". This ensures that the WSD emulation is used when
-** compiling for systems that do not support real WSD.
-*/
-#define pcache_g (GLOBAL(struct PCacheGlobal, pcache))
-
-/*
-** All global variables used by this module (all of which are grouped 
-** together in global structure "pcache" above) are protected by the static 
-** SQLITE_MUTEX_STATIC_LRU mutex. A pointer to this mutex is stored in
-** variable "pcache.mutex".
-**
-** Some elements of the PCache and PgHdr structures are protected by the 
-** SQLITE_MUTEX_STATUS_LRU mutex and other are not.  The protected
-** elements are grouped at the end of the structures and are clearly
-** marked.
-**
-** Use the following macros must surround all access (read or write)
-** of protected elements.  The mutex is not recursive and may not be
-** entered more than once.  The pcacheMutexHeld() macro should only be
-** used within an assert() to verify that the mutex is being held.
-*/
-#define pcacheEnterMutex() sqlite3_mutex_enter(pcache_g.mutex)
-#define pcacheExitMutex()  sqlite3_mutex_leave(pcache_g.mutex)
-#define pcacheMutexHeld()  sqlite3_mutex_held(pcache_g.mutex)
-
 /*
 ** Some of the assert() macros in this code are too expensive to run
 ** even during normal debugging.  Use them only rarely on long-running
@@ -26771,48 +27448,6 @@ static SQLITE_WSD struct PCacheGlobal {
 
 /********************************** Linked List Management ********************/
 
-#if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT)
-/*
-** This routine verifies that the number of entries in the hash table
-** is pCache->nPage.  This routine is used within assert() statements
-** only and is therefore disabled during production builds.
-*/
-static int pcacheCheckHashCount(PCache *pCache){
-  int i;
-  int nPage = 0;
-  for(i=0; i<pCache->nHash; i++){
-    PgHdr *p;
-    for(p=pCache->apHash[i]; p; p=p->pNextHash){
-      nPage++;
-    }
-  }
-  assert( nPage==pCache->nPage );
-  return 1;
-}
-#endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */
-
-
-#if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT)
-/*
-** Based on the current value of PCache.nRef and the contents of the
-** PCache.pDirty list, return the expected value of the PCache.nPinned
-** counter. This is only used in debugging builds, as follows:
-**
-**   expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );
-*/
-static int pcachePinnedCount(PCache *pCache){
-  PgHdr *p;
-  int nPinned = pCache->nRef;
-  for(p=pCache->pDirty; p; p=p->pNext){
-    if( p->nRef==0 ){
-      nPinned++;
-    }
-  }
-  return nPinned;
-}
-#endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */
-
-
 #if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT)
 /*
 ** Check that the pCache->pSynced variable is set correctly. If it
@@ -26822,434 +27457,86 @@ static int pcachePinnedCount(PCache *pCache){
 **   expensive_assert( pcacheCheckSynced(pCache) );
 */
 static int pcacheCheckSynced(PCache *pCache){
-  PgHdr *p = pCache->pDirtyTail;
-  for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pPrev){
+  PgHdr *p;
+  for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pDirtyPrev){
     assert( p->nRef || (p->flags&PGHDR_NEED_SYNC) );
   }
   return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0);
 }
 #endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */
 
-
-
 /*
-** Remove a page from its hash table (PCache.apHash[]).
+** Remove page pPage from the list of dirty pages.
 */
-static void pcacheRemoveFromHash(PgHdr *pPage){
-  assert( pcacheMutexHeld() );
-  if( pPage->pPrevHash ){
-    pPage->pPrevHash->pNextHash = pPage->pNextHash;
-  }else{
-    PCache *pCache = pPage->pCache;
-    u32 h = pPage->pgno % pCache->nHash;
-    assert( pCache->apHash[h]==pPage );
-    pCache->apHash[h] = pPage->pNextHash;
-  }
-  if( pPage->pNextHash ){
-    pPage->pNextHash->pPrevHash = pPage->pPrevHash;
-  }
-  pPage->pCache->nPage--;
-  expensive_assert( pcacheCheckHashCount(pPage->pCache) );
-}
-
-/*
-** Insert a page into the hash table
-**
-** The mutex must be held by the caller.
-*/
-static void pcacheAddToHash(PgHdr *pPage){
-  PCache *pCache = pPage->pCache;
-  u32 h = pPage->pgno % pCache->nHash;
-  assert( pcacheMutexHeld() );
-  pPage->pNextHash = pCache->apHash[h];
-  pPage->pPrevHash = 0;
-  if( pCache->apHash[h] ){
-    pCache->apHash[h]->pPrevHash = pPage;
-  }
-  pCache->apHash[h] = pPage;
-  pCache->nPage++;
-  expensive_assert( pcacheCheckHashCount(pCache) );
-}
-
-/*
-** Attempt to increase the size the hash table to contain
-** at least nHash buckets.
-*/
-static int pcacheResizeHash(PCache *pCache, int nHash){
-  PgHdr *p;
-  PgHdr **pNew;
-  assert( pcacheMutexHeld() );
-#ifdef SQLITE_MALLOC_SOFT_LIMIT
-  if( nHash*sizeof(PgHdr*)>SQLITE_MALLOC_SOFT_LIMIT ){
-    nHash = SQLITE_MALLOC_SOFT_LIMIT/sizeof(PgHdr *);
-  }
-#endif
-  pcacheExitMutex();
-  pNew = (PgHdr **)sqlite3Malloc(sizeof(PgHdr*)*nHash);
-  pcacheEnterMutex();
-  if( !pNew ){
-    return SQLITE_NOMEM;
-  }
-  memset(pNew, 0, sizeof(PgHdr *)*nHash);
-  sqlite3_free(pCache->apHash);
-  pCache->apHash = pNew;
-  pCache->nHash = nHash;
-  pCache->nPage = 0;
-  for(p=pCache->pClean; p; p=p->pNext){
-    pcacheAddToHash(p);
-  }
-  for(p=pCache->pDirty; p; p=p->pNext){
-    pcacheAddToHash(p);
-  }
-  return SQLITE_OK;
-}
+static void pcacheRemoveFromDirtyList(PgHdr *pPage){
+  PCache *p = pPage->pCache;
 
-/*
-** Remove a page from a linked list that is headed by *ppHead.
-** *ppHead is either PCache.pClean or PCache.pDirty.
-*/
-static void pcacheRemoveFromList(PgHdr **ppHead, PgHdr *pPage){
-  int isDirtyList = (ppHead==&pPage->pCache->pDirty);
-  assert( ppHead==&pPage->pCache->pClean || ppHead==&pPage->pCache->pDirty );
-  assert( pcacheMutexHeld() || ppHead!=&pPage->pCache->pClean );
+  assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
+  assert( pPage->pDirtyPrev || pPage==p->pDirty );
 
-  if( pPage->pPrev ){
-    pPage->pPrev->pNext = pPage->pNext;
-  }else{
-    assert( *ppHead==pPage );
-    *ppHead = pPage->pNext;
-  }
-  if( pPage->pNext ){
-    pPage->pNext->pPrev = pPage->pPrev;
-  }
-
-  if( isDirtyList ){
-    PCache *pCache = pPage->pCache;
-    assert( pPage->pNext || pCache->pDirtyTail==pPage );
-    if( !pPage->pNext ){
-      pCache->pDirtyTail = pPage->pPrev;
-    }
-    if( pCache->pSynced==pPage ){
-      PgHdr *pSynced = pPage->pPrev;
-      while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
-        pSynced = pSynced->pPrev;
-      }
-      pCache->pSynced = pSynced;
+  /* Update the PCache1.pSynced variable if necessary. */
+  if( p->pSynced==pPage ){
+    PgHdr *pSynced = pPage->pDirtyPrev;
+    while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
+      pSynced = pSynced->pDirtyPrev;
     }
+    p->pSynced = pSynced;
   }
-}
-
-/*
-** Add a page from a linked list that is headed by *ppHead.
-** *ppHead is either PCache.pClean or PCache.pDirty.
-*/
-static void pcacheAddToList(PgHdr **ppHead, PgHdr *pPage){
-  int isDirtyList = (ppHead==&pPage->pCache->pDirty);
-  assert( ppHead==&pPage->pCache->pClean || ppHead==&pPage->pCache->pDirty );
-
-  if( (*ppHead) ){
-    (*ppHead)->pPrev = pPage;
-  }
-  pPage->pNext = *ppHead;
-  pPage->pPrev = 0;
-  *ppHead = pPage;
 
-  if( isDirtyList ){
-    PCache *pCache = pPage->pCache;
-    if( !pCache->pDirtyTail ){
-      assert( pPage->pNext==0 );
-      pCache->pDirtyTail = pPage;
-    }
-    if( !pCache->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
-      pCache->pSynced = pPage;
-    }
-  }
-}
-
-/*
-** Remove a page from the global LRU list
-*/
-static void pcacheRemoveFromLruList(PgHdr *pPage){
-  assert( sqlite3_mutex_held(pcache_g.mutex) );
-  assert( (pPage->flags&PGHDR_DIRTY)==0 );
-  if( pPage->pCache->bPurgeable==0 ) return;
-  if( pPage->pNextLru ){
-    assert( pcache_g.pLruTail!=pPage );
-    pPage->pNextLru->pPrevLru = pPage->pPrevLru;
+  if( pPage->pDirtyNext ){
+    pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
   }else{
-    assert( pcache_g.pLruTail==pPage );
-    pcache_g.pLruTail = pPage->pPrevLru;
+    assert( pPage==p->pDirtyTail );
+    p->pDirtyTail = pPage->pDirtyPrev;
   }
-  if( pPage->pPrevLru ){
-    assert( pcache_g.pLruHead!=pPage );
-    pPage->pPrevLru->pNextLru = pPage->pNextLru;
+  if( pPage->pDirtyPrev ){
+    pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
   }else{
-    assert( pcache_g.pLruHead==pPage );
-    pcache_g.pLruHead = pPage->pNextLru;
+    assert( pPage==p->pDirty );
+    p->pDirty = pPage->pDirtyNext;
   }
-}
+  pPage->pDirtyNext = 0;
+  pPage->pDirtyPrev = 0;
 
-/*
-** Add a page to the global LRU list.  The page is normally added
-** to the front of the list so that it will be the last page recycled.
-** However, if the PGHDR_REUSE_UNLIKELY bit is set, the page is added
-** to the end of the LRU list so that it will be the next to be recycled.
-*/
-static void pcacheAddToLruList(PgHdr *pPage){
-  assert( sqlite3_mutex_held(pcache_g.mutex) );
-  assert( (pPage->flags&PGHDR_DIRTY)==0 );
-  if( pPage->pCache->bPurgeable==0 ) return;
-  if( pcache_g.pLruTail && (pPage->flags & PGHDR_REUSE_UNLIKELY)!=0 ){
-    /* If reuse is unlikely.  Put the page at the end of the LRU list
-    ** where it will be recycled sooner rather than later. 
-    */
-    assert( pcache_g.pLruHead );
-    pPage->pNextLru = 0;
-    pPage->pPrevLru = pcache_g.pLruTail;
-    pcache_g.pLruTail->pNextLru = pPage;
-    pcache_g.pLruTail = pPage;
-    pPage->flags &= ~PGHDR_REUSE_UNLIKELY;
-  }else{
-    /* If reuse is possible. the page goes at the beginning of the LRU
-    ** list so that it will be the last to be recycled.
-    */
-    if( pcache_g.pLruHead ){
-      pcache_g.pLruHead->pPrevLru = pPage;
-    }
-    pPage->pNextLru = pcache_g.pLruHead;
-    pcache_g.pLruHead = pPage;
-    pPage->pPrevLru = 0;
-    if( pcache_g.pLruTail==0 ){
-      pcache_g.pLruTail = pPage;
-    }
-  }
-}
-
-/*********************************************** Memory Allocation ***********
-**
-** Initialize the page cache memory pool.
-**
-** This must be called at start-time when no page cache lines are
-** checked out. This function is not threadsafe.
-*/
-SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
-  PgFreeslot *p;
-  sz &= ~7;
-  pcache_g.szSlot = sz;
-  pcache_g.pStart = pBuf;
-  pcache_g.pFree = 0;
-  while( n-- ){
-    p = (PgFreeslot*)pBuf;
-    p->pNext = pcache_g.pFree;
-    pcache_g.pFree = p;
-    pBuf = (void*)&((char*)pBuf)[sz];
-  }
-  pcache_g.pEnd = pBuf;
+  expensive_assert( pcacheCheckSynced(p) );
 }
 
 /*
-** Allocate a page cache line.  Look in the page cache memory pool first
-** and use an element from it first if available.  If nothing is available
-** in the page cache memory pool, go to the general purpose memory allocator.
+** Add page pPage to the head of the dirty list (PCache1.pDirty is set to
+** pPage).
 */
-static void *pcacheMalloc(int sz, PCache *pCache){
-  assert( sqlite3_mutex_held(pcache_g.mutex) );
-  if( sz<=pcache_g.szSlot && pcache_g.pFree ){
-    PgFreeslot *p = pcache_g.pFree;
-    pcache_g.pFree = p->pNext;
-    sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, sz);
-    sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
-    return (void*)p;
-  }else{
-    void *p;
+static void pcacheAddToDirtyList(PgHdr *pPage){
+  PCache *p = pPage->pCache;
 
-    /* Allocate a new buffer using sqlite3Malloc. Before doing so, exit the
-    ** global pcache mutex and unlock the pager-cache object pCache. This is 
-    ** so that if the attempt to allocate a new buffer causes the the 
-    ** configured soft-heap-limit to be breached, it will be possible to
-    ** reclaim memory from this pager-cache.
-    */
-    pcacheExitMutex();
-    p = sqlite3Malloc(sz);
-    pcacheEnterMutex();
+  assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
 
-    if( p ){
-      sz = sqlite3MallocSize(p);
-      sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
-    }
-    return p;
+  pPage->pDirtyNext = p->pDirty;
+  if( pPage->pDirtyNext ){
+    assert( pPage->pDirtyNext->pDirtyPrev==0 );
+    pPage->pDirtyNext->pDirtyPrev = pPage;
   }
-}
-SQLITE_PRIVATE void *sqlite3PageMalloc(int sz){
-  void *p;
-  pcacheEnterMutex();
-  p = pcacheMalloc(sz, 0);
-  pcacheExitMutex();
-  return p;
-}
-
-/*
-** Release a pager memory allocation
-*/
-static void pcacheFree(void *p){
-  assert( sqlite3_mutex_held(pcache_g.mutex) );
-  if( p==0 ) return;
-  if( p>=pcache_g.pStart && p<pcache_g.pEnd ){
-    PgFreeslot *pSlot;
-    sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1);
-    pSlot = (PgFreeslot*)p;
-    pSlot->pNext = pcache_g.pFree;
-    pcache_g.pFree = pSlot;
-  }else{
-    int iSize = sqlite3MallocSize(p);
-    sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
-    sqlite3_free(p);
+  p->pDirty = pPage;
+  if( !p->pDirtyTail ){
+    p->pDirtyTail = pPage;
   }
-}
-SQLITE_PRIVATE void sqlite3PageFree(void *p){
-  pcacheEnterMutex();
-  pcacheFree(p);
-  pcacheExitMutex();
-}
-
-/*
-** Allocate a new page.
-*/
-static PgHdr *pcachePageAlloc(PCache *pCache){
-  PgHdr *p;
-  int sz = sizeof(*p) + pCache->szPage + pCache->szExtra;
-  assert( sqlite3_mutex_held(pcache_g.mutex) );
-  p = pcacheMalloc(sz, pCache);
-  if( p==0 ) return 0;
-  memset(p, 0, sizeof(PgHdr));
-  p->pData = (void*)&p[1];
-  p->pExtra = (void*)&((char*)p->pData)[pCache->szPage];
-  if( pCache->bPurgeable ){
-    pcache_g.nCurrentPage++;
-  }
-  return p;
-}
-
-/*
-** Deallocate a page
-*/
-static void pcachePageFree(PgHdr *p){
-  assert( sqlite3_mutex_held(pcache_g.mutex) );
-  if( p->pCache->bPurgeable ){
-    pcache_g.nCurrentPage--;
-  }
-  pcacheFree(p);
-}
-
-#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
-/*
-** Return the number of bytes that will be returned to the heap when
-** the argument is passed to pcachePageFree().
-*/
-static int pcachePageSize(PgHdr *p){
-  assert( sqlite3_mutex_held(pcache_g.mutex) );
-  assert( !pcache_g.pStart );
-  assert( p && p->pCache );
-  return sqlite3MallocSize(p);
-}
-#endif
-
-/*
-** Attempt to 'recycle' a page from the global LRU list. Only clean,
-** unreferenced pages from purgeable caches are eligible for recycling.
-**
-** This function removes page pcache.pLruTail from the global LRU list,
-** and from the hash-table and PCache.pClean list of the owner pcache.
-** There should be no other references to the page.
-**
-** A pointer to the recycled page is returned, or NULL if no page is
-** eligible for recycling.
-*/
-static PgHdr *pcacheRecyclePage(void){
-  PgHdr *p = 0;
-  assert( sqlite3_mutex_held(pcache_g.mutex) );
-
-  if( (p=pcache_g.pLruTail)!=0 ){
-    assert( (p->flags&PGHDR_DIRTY)==0 );
-    pcacheRemoveFromLruList(p);
-    pcacheRemoveFromHash(p);
-    pcacheRemoveFromList(&p->pCache->pClean, p);
+  if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
+    p->pSynced = pPage;
   }
-
-  return p;
+  expensive_assert( pcacheCheckSynced(p) );
 }
 
 /*
-** Obtain space for a page. Try to recycle an old page if the limit on the 
-** number of pages has been reached. If the limit has not been reached or
-** there are no pages eligible for recycling, allocate a new page.
-**
-** Return a pointer to the new page, or NULL if an OOM condition occurs.
+** Wrapper around the pluggable caches xUnpin method. If the cache is
+** being used for an in-memory database, this function is a no-op.
 */
-static int pcacheRecycleOrAlloc(PCache *pCache, PgHdr **ppPage){
-  PgHdr *p = 0;
-
-  int szPage = pCache->szPage;
-  int szExtra = pCache->szExtra;
-
-  assert( pcache_g.isInit );
-  assert( sqlite3_mutex_held(pcache_g.mutex) );
-
-  *ppPage = 0;
-
-  /* If we have reached either the global or the local limit for 
-  ** pinned+dirty pages, and there is at least one dirty page,
-  ** invoke the xStress callback to cause a page to become clean.
-  */
-  expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );
-  expensive_assert( pcacheCheckSynced(pCache) );
-  if( pCache->xStress
-   && pCache->pDirty
-   && (pCache->nPinned>=(pcache_g.nMaxPage+pCache->nMin-pcache_g.nMinPage)
-           || pCache->nPinned>=pCache->nMax)
-  ){
-    PgHdr *pPg;
-    assert(pCache->pDirtyTail);
-
-    for(pPg=pCache->pSynced; 
-        pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); 
-        pPg=pPg->pPrev
-    );
-    if( !pPg ){
-      for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pPrev);
-    }
-    if( pPg ){
-      int rc;
-      pcacheExitMutex();
-      rc = pCache->xStress(pCache->pStress, pPg);
-      pcacheEnterMutex();
-      if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
-        return rc;
-      }
+static void pcacheUnpin(PgHdr *p){
+  PCache *pCache = p->pCache;
+  if( pCache->bPurgeable ){
+    if( p->pgno==1 ){
+      pCache->pPage1 = 0;
     }
+    sqlite3GlobalConfig.pcache.xUnpin(pCache->pCache, p, 0);
   }
-
-  /* If either the local or the global page limit has been reached, 
-  ** try to recycle a page. 
-  */
-  if( pCache->bPurgeable && (pCache->nPage>=pCache->nMax-1 ||
-                             pcache_g.nCurrentPage>=pcache_g.nMaxPage) ){
-    p = pcacheRecyclePage();
-  }
-
-  /* If a page has been recycled but it is the wrong size, free it. */
-  if( p && (p->pCache->szPage!=szPage || p->pCache->szPage!=szExtra) ){
-    pcachePageFree(p);
-    p = 0;
-  }
-
-  if( !p ){
-    p = pcachePageAlloc(pCache);
-  }
-
-  *ppPage = p;
-  return (p?SQLITE_OK:SQLITE_NOMEM);
 }
 
 /*************************************************** General Interfaces ******
@@ -27258,19 +27545,15 @@ static int pcacheRecycleOrAlloc(PCache *pCache, PgHdr **ppPage){
 ** functions are threadsafe.
 */
 SQLITE_PRIVATE int sqlite3PcacheInitialize(void){
-  assert( pcache_g.isInit==0 );
-  memset(&pcache_g, 0, sizeof(pcache));
-  if( sqlite3GlobalConfig.bCoreMutex ){
-    /* No need to check the return value of sqlite3_mutex_alloc(). 
-    ** Allocating a static mutex cannot fail.
-    */
-    pcache_g.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
+  if( sqlite3GlobalConfig.pcache.xInit==0 ){
+    sqlite3PCacheSetDefault();
   }
-  pcache_g.isInit = 1;
-  return SQLITE_OK;
+  return sqlite3GlobalConfig.pcache.xInit(sqlite3GlobalConfig.pcache.pArg);
 }
 SQLITE_PRIVATE void sqlite3PcacheShutdown(void){
-  memset(&pcache_g, 0, sizeof(pcache));
+  if( sqlite3GlobalConfig.pcache.xShutdown ){
+    sqlite3GlobalConfig.pcache.xShutdown(sqlite3GlobalConfig.pcache.pArg);
+  }
 }
 
 /*
@@ -27279,8 +27562,10 @@ SQLITE_PRIVATE void sqlite3PcacheShutdown(void){
 SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); }
 
 /*
-** Create a new PCache object.  Storage space to hold the object
-** has already been allocated and is passed in as the p pointer.
+** Create a new PCache object. Storage space to hold the object
+** has already been allocated and is passed in as the p pointer. 
+** The caller discovers how much space needs to be allocated by 
+** calling sqlite3PcacheSize().
 */
 SQLITE_PRIVATE void sqlite3PcacheOpen(
   int szPage,                  /* Size of every page */
@@ -27290,7 +27575,6 @@ SQLITE_PRIVATE void sqlite3PcacheOpen(
   void *pStress,               /* Argument to xStress */
   PCache *p                    /* Preallocated space for the PCache */
 ){
-  assert( pcache_g.isInit );
   memset(p, 0, sizeof(PCache));
   p->szPage = szPage;
   p->szExtra = szExtra;
@@ -27299,22 +27583,18 @@ SQLITE_PRIVATE void sqlite3PcacheOpen(
   p->pStress = pStress;
   p->nMax = 100;
   p->nMin = 10;
-
-  pcacheEnterMutex();
-  if( bPurgeable ){
-    pcache_g.nMaxPage += p->nMax;
-    pcache_g.nMinPage += p->nMin;
-  }
-
-  pcacheExitMutex();
 }
 
 /*
-** Change the page size for PCache object.  This can only happen
-** when the cache is empty.
+** Change the page size for PCache object. The caller must ensure that there
+** are no outstanding page references when this function is called.
 */
 SQLITE_PRIVATE void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
-  assert(pCache->nPage==0);
+  assert( pCache->nRef==0 && pCache->pDirty==0 );
+  if( pCache->pCache ){
+    sqlite3GlobalConfig.pcache.xDestroy(pCache->pCache);
+    pCache->pCache = 0;
+  }
   pCache->szPage = szPage;
 }
 
@@ -27327,66 +27607,82 @@ SQLITE_PRIVATE int sqlite3PcacheFetch(
   int createFlag,       /* If true, create page if it does not exist already */
   PgHdr **ppPage        /* Write the page here */
 ){
-  int rc = SQLITE_OK;
   PgHdr *pPage = 0;
+  int eCreate;
 
-  assert( pcache_g.isInit );
   assert( pCache!=0 );
   assert( pgno>0 );
-  expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );
-
-  pcacheEnterMutex();
-
-  /* Search the hash table for the requested page. Exit early if it is found. */
-  if( pCache->apHash ){
-    u32 h = pgno % pCache->nHash;
-    for(pPage=pCache->apHash[h]; pPage; pPage=pPage->pNextHash){
-      if( pPage->pgno==pgno ){
-        if( pPage->nRef==0 ){
-          if( 0==(pPage->flags&PGHDR_DIRTY) ){
-            pcacheRemoveFromLruList(pPage);
-            pCache->nPinned++;
-          }
-          pCache->nRef++;
-        }
-        pPage->nRef++;
-        break;
-      }
+
+  /* If the pluggable cache (sqlite3_pcache*) has not been allocated,
+  ** allocate it now.
+  */
+  if( !pCache->pCache && createFlag ){
+    sqlite3_pcache *p;
+    int nByte;
+    nByte = pCache->szPage + pCache->szExtra + sizeof(PgHdr);
+    p = sqlite3GlobalConfig.pcache.xCreate(nByte, pCache->bPurgeable);
+    if( !p ){
+      return SQLITE_NOMEM;
     }
+    sqlite3GlobalConfig.pcache.xCachesize(p, pCache->nMax);
+    pCache->pCache = p;
+  }
+
+  eCreate = createFlag ? 1 : 0;
+  if( eCreate && (!pCache->bPurgeable || !pCache->pDirty) ){
+    eCreate = 2;
   }
+  if( pCache->pCache ){
+    pPage = sqlite3GlobalConfig.pcache.xFetch(pCache->pCache, pgno, eCreate);
+  }
+
+  if( !pPage && eCreate==1 ){
+    PgHdr *pPg;
 
-  if( !pPage && createFlag ){
-    if( pCache->nHash<=pCache->nPage ){
-      rc = pcacheResizeHash(pCache, pCache->nHash<256 ? 256 : pCache->nHash*2);
+    /* Find a dirty page to write-out and recycle. First try to find a 
+    ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
+    ** cleared), but if that is not possible settle for any other 
+    ** unreferenced dirty page.
+    */
+    expensive_assert( pcacheCheckSynced(pCache) );
+    for(pPg=pCache->pSynced; 
+        pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); 
+        pPg=pPg->pDirtyPrev
+    );
+    if( !pPg ){
+      for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
     }
-    if( rc==SQLITE_OK ){
-      rc = pcacheRecycleOrAlloc(pCache, &pPage);
+    if( pPg ){
+      int rc;
+      rc = pCache->xStress(pCache->pStress, pPg);
+      if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
+        return rc;
+      }
     }
-    if( rc==SQLITE_OK ){
-      pPage->pPager = 0;
-      pPage->flags = 0;
-      pPage->pDirty = 0;
-      pPage->pgno = pgno;
-      pPage->pCache = pCache;
-      pPage->nRef = 1;
+
+    pPage = sqlite3GlobalConfig.pcache.xFetch(pCache->pCache, pgno, 2);
+  }
+
+  if( pPage ){
+    if( 0==pPage->nRef ){
       pCache->nRef++;
-      pCache->nPinned++;
-      pcacheAddToList(&pCache->pClean, pPage);
-      pcacheAddToHash(pPage);
+    }
+    pPage->nRef++;
+    pPage->pData = (void*)&pPage[1];
+    pPage->pExtra = (void*)&((char*)pPage->pData)[pCache->szPage];
+    pPage->pCache = pCache;
+    pPage->pgno = pgno;
+    if( pgno==1 ){
+      pCache->pPage1 = pPage;
     }
   }
-
-  pcacheExitMutex();
-
   *ppPage = pPage;
-  expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );
-  assert( pPage || !createFlag || rc!=SQLITE_OK );
-  return rc;
+  return (pPage==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK;
 }
 
 /*
-** Dereference a page.  When the reference count reaches zero,
-** move the page to the LRU list if it is clean.
+** Decrement the reference count on a page. If the page is clean and the
+** reference count drops to 0, then it is made elible for recycling.
 */
 SQLITE_PRIVATE void sqlite3PcacheRelease(PgHdr *p){
   assert( p->nRef>0 );
@@ -27395,24 +27691,18 @@ SQLITE_PRIVATE void sqlite3PcacheRelease(PgHdr *p){
     PCache *pCache = p->pCache;
     pCache->nRef--;
     if( (p->flags&PGHDR_DIRTY)==0 ){
-      pCache->nPinned--;
-      pcacheEnterMutex();
-      if( pcache_g.nCurrentPage>pcache_g.nMaxPage ){
-        pcacheRemoveFromList(&pCache->pClean, p);
-        pcacheRemoveFromHash(p);
-        pcachePageFree(p);
-      }else{
-        pcacheAddToLruList(p);
-      }
-      pcacheExitMutex();
+      pcacheUnpin(p);
     }else{
-      /* Move the page to the head of the caches dirty list. */
-      pcacheRemoveFromList(&pCache->pDirty, p);
-      pcacheAddToList(&pCache->pDirty, p);
+      /* Move the page to the head of the dirty list. */
+      pcacheRemoveFromDirtyList(p);
+      pcacheAddToDirtyList(p);
     }
   }
 }
 
+/*
+** Increase the reference count of a supplied page by 1.
+*/
 SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){
   assert(p->nRef>0);
   p->nRef++;
@@ -27426,57 +27716,43 @@ SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){
 SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){
   PCache *pCache;
   assert( p->nRef==1 );
-  assert( 0==(p->flags&PGHDR_DIRTY) );
+  if( p->flags&PGHDR_DIRTY ){
+    pcacheRemoveFromDirtyList(p);
+  }
   pCache = p->pCache;
   pCache->nRef--;
-  pCache->nPinned--;
-  pcacheEnterMutex();
-  pcacheRemoveFromList(&pCache->pClean, p);
-  pcacheRemoveFromHash(p);
-  pcachePageFree(p);
-  pcacheExitMutex();
+  if( p->pgno==1 ){
+    pCache->pPage1 = 0;
+  }
+  sqlite3GlobalConfig.pcache.xUnpin(pCache->pCache, p, 1);
 }
 
 /*
-** Make sure the page is marked as dirty.  If it isn't dirty already,
+** Make sure the page is marked as dirty. If it isn't dirty already,
 ** make it so.
 */
 SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
   PCache *pCache;
   p->flags &= ~PGHDR_DONT_WRITE;
-  if( p->flags & PGHDR_DIRTY ) return;
-  assert( (p->flags & PGHDR_DIRTY)==0 );
   assert( p->nRef>0 );
-  pCache = p->pCache;
-  pcacheEnterMutex();
-  pcacheRemoveFromList(&pCache->pClean, p);
-  pcacheAddToList(&pCache->pDirty, p);
-  pcacheExitMutex();
-  p->flags |= PGHDR_DIRTY;
-}
-
-static void pcacheMakeClean(PgHdr *p){
-  PCache *pCache = p->pCache;
-  assert( p->flags & PGHDR_DIRTY );
-  pcacheRemoveFromList(&pCache->pDirty, p);
-  pcacheAddToList(&pCache->pClean, p);
-  p->flags &= ~PGHDR_DIRTY;
-  if( p->nRef==0 ){
-    pcacheAddToLruList(p);
-    pCache->nPinned--;
+  if( 0==(p->flags & PGHDR_DIRTY) ){
+    pCache = p->pCache;
+    p->flags |= PGHDR_DIRTY;
+    pcacheAddToDirtyList( p);
   }
-  expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );
 }
 
 /*
-** Make sure the page is marked as clean.  If it isn't clean already,
+** Make sure the page is marked as clean. If it isn't clean already,
 ** make it so.
 */
 SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){
   if( (p->flags & PGHDR_DIRTY) ){
-    pcacheEnterMutex();
-    pcacheMakeClean(p);
-    pcacheExitMutex();
+    pcacheRemoveFromDirtyList(p);
+    p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC);
+    if( p->nRef==0 ){
+      pcacheUnpin(p);
+    }
   }
 }
 
@@ -27485,110 +27761,62 @@ SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){
 */
 SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache *pCache){
   PgHdr *p;
-  pcacheEnterMutex();
   while( (p = pCache->pDirty)!=0 ){
-    pcacheRemoveFromList(&pCache->pDirty, p);
-    p->flags &= ~PGHDR_DIRTY;
-    pcacheAddToList(&pCache->pClean, p);
-    if( p->nRef==0 ){
-      pcacheAddToLruList(p);
-      pCache->nPinned--;
-    }
+    sqlite3PcacheMakeClean(p);
   }
-  sqlite3PcacheAssertFlags(pCache, 0, PGHDR_DIRTY);
-  expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );
-  pcacheExitMutex();
 }
 
 /*
-** Change the page number of page p to newPgno. If newPgno is 0, then the
-** page object is added to the clean-list and the PGHDR_REUSE_UNLIKELY 
-** flag set.
+** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
 */
-SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
-  assert( p->nRef>0 );
-  pcacheEnterMutex();
-  pcacheRemoveFromHash(p);
-  p->pgno = newPgno;
-  if( newPgno==0 ){
-    if( (p->flags & PGHDR_DIRTY) ){
-      pcacheMakeClean(p);
-    }
-    p->flags = PGHDR_REUSE_UNLIKELY;
+SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){
+  PgHdr *p;
+  for(p=pCache->pDirty; p; p=p->pDirtyNext){
+    p->flags &= ~PGHDR_NEED_SYNC;
   }
-  pcacheAddToHash(p);
-  pcacheExitMutex();
+  pCache->pSynced = pCache->pDirtyTail;
 }
 
 /*
-** Remove all content from a page cache
+** Change the page number of page p to newPgno. 
 */
-static void pcacheClear(PCache *pCache){
-  PgHdr *p, *pNext;
-  assert( sqlite3_mutex_held(pcache_g.mutex) );
-  for(p=pCache->pClean; p; p=pNext){
-    pNext = p->pNext;
-    pcacheRemoveFromLruList(p);
-    pcachePageFree(p);
-  }
-  for(p=pCache->pDirty; p; p=pNext){
-    pNext = p->pNext;
-    pcachePageFree(p);
+SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
+  PCache *pCache = p->pCache;
+  assert( p->nRef>0 );
+  assert( newPgno>0 );
+  sqlite3GlobalConfig.pcache.xRekey(pCache->pCache, p, p->pgno, newPgno);
+  p->pgno = newPgno;
+  if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
+    pcacheRemoveFromDirtyList(p);
+    pcacheAddToDirtyList(p);
   }
-  pCache->pClean = 0;
-  pCache->pDirty = 0;
-  pCache->pDirtyTail = 0;
-  pCache->nPage = 0;
-  pCache->nPinned = 0;
-  memset(pCache->apHash, 0, pCache->nHash*sizeof(pCache->apHash[0]));
 }
 
-
 /*
-** Drop every cache entry whose page number is greater than "pgno".
+** Drop every cache entry whose page number is greater than "pgno". The
+** caller must ensure that there are no outstanding references to any pages
+** other than page 1 with a page number greater than pgno.
+**
+** If there is a reference to page 1 and the pgno parameter passed to this
+** function is 0, then the data area associated with page 1 is zeroed, but
+** the page object is not dropped.
 */
 SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
-  PgHdr *p, *pNext;
-  PgHdr *pDirty = pCache->pDirty;
-  pcacheEnterMutex();
-  for(p=pCache->pClean; p||pDirty; p=pNext){
-    if( !p ){
-      p = pDirty;
-      pDirty = 0;
-    }
-    pNext = p->pNext;
-    if( p->pgno>pgno ){
-      if( p->nRef==0 ){
-        pcacheRemoveFromHash(p);
-        if( p->flags&PGHDR_DIRTY ){
-          pcacheRemoveFromList(&pCache->pDirty, p);
-          pCache->nPinned--;
-        }else{
-          pcacheRemoveFromList(&pCache->pClean, p);
-          pcacheRemoveFromLruList(p);
-        }
-        pcachePageFree(p);
-      }else{
-        /* If there are references to the page, it cannot be freed. In this
-        ** case, zero the page content instead.
-        */
-        memset(p->pData, 0, pCache->szPage);
+  if( pCache->pCache ){
+    PgHdr *p;
+    PgHdr *pNext;
+    for(p=pCache->pDirty; p; p=pNext){
+      pNext = p->pDirtyNext;
+      if( p->pgno>pgno ){
+        assert( p->flags&PGHDR_DIRTY );
+        sqlite3PcacheMakeClean(p);
       }
     }
-  }
-  pcacheExitMutex();
-}
-
-/*
-** If there are currently more than pcache.nMaxPage pages allocated, try
-** to recycle pages to reduce the number allocated to pcache.nMaxPage.
-*/
-static void pcacheEnforceMaxPage(void){
-  PgHdr *p;
-  assert( sqlite3_mutex_held(pcache_g.mutex) );
-  while( pcache_g.nCurrentPage>pcache_g.nMaxPage
-             && (p = pcacheRecyclePage())!=0 ){
-    pcachePageFree(p);
+    if( pgno==0 && pCache->pPage1 ){
+      memset(pCache->pPage1->pData, 0, pCache->szPage);
+      pgno = 1;
+    }
+    sqlite3GlobalConfig.pcache.xTruncate(pCache->pCache, pgno+1);
   }
 }
 
@@ -27596,51 +27824,22 @@ static void pcacheEnforceMaxPage(void){
 ** Close a cache.
 */
 SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){
-  pcacheEnterMutex();
-
-  /* Free all the pages used by this pager and remove them from the LRU list. */
-  pcacheClear(pCache);
-  if( pCache->bPurgeable ){
-    pcache_g.nMaxPage -= pCache->nMax;
-    pcache_g.nMinPage -= pCache->nMin;
-    pcacheEnforceMaxPage();
-  }
-  sqlite3_free(pCache->apHash);
-  pcacheExitMutex();
-}
-
-
-#ifndef NDEBUG
-/* 
-** Assert flags settings on all pages.  Debugging only.
-*/
-SQLITE_PRIVATE void sqlite3PcacheAssertFlags(PCache *pCache, int trueMask, int falseMask){
-  PgHdr *p;
-  for(p=pCache->pDirty; p; p=p->pNext){
-    assert( (p->flags&trueMask)==trueMask );
-    assert( (p->flags&falseMask)==0 );
-  }
-  for(p=pCache->pClean; p; p=p->pNext){
-    assert( (p->flags&trueMask)==trueMask );
-    assert( (p->flags&falseMask)==0 );
+  if( pCache->pCache ){
+    sqlite3GlobalConfig.pcache.xDestroy(pCache->pCache);
   }
 }
-#endif
 
 /* 
 ** Discard the contents of the cache.
 */
 SQLITE_PRIVATE int sqlite3PcacheClear(PCache *pCache){
-  assert(pCache->nRef==0);
-  pcacheEnterMutex();
-  pcacheClear(pCache);
-  pcacheExitMutex();
+  sqlite3PcacheTruncate(pCache, 0);
   return SQLITE_OK;
 }
 
 /*
 ** Merge two lists of pages connected by pDirty and in pgno order.
-** Do not both fixing the pPrevDirty pointers.
+** Do not both fixing the pDirtyPrev pointers.
 */
 static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
   PgHdr result, *pTail;
@@ -27668,7 +27867,7 @@ static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
 
 /*
 ** Sort the list of pages in accending order by pgno.  Pages are
-** connected by pDirty pointers.  The pPrevDirty pointers are
+** connected by pDirty pointers.  The pDirtyPrev pointers are
 ** corrupted by this sort.
 */
 #define N_SORT_BUCKET_ALLOC 25
@@ -27717,19 +27916,22 @@ static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
 */
 SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
   PgHdr *p;
-  for(p=pCache->pDirty; p; p=p->pNext){
-    p->pDirty = p->pNext;
+  for(p=pCache->pDirty; p; p=p->pDirtyNext){
+    p->pDirty = p->pDirtyNext;
   }
   return pcacheSortDirtyList(pCache->pDirty);
 }
 
 /* 
-** Return the total number of outstanding page references.
+** Return the total number of referenced pages held by the cache.
 */
 SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache *pCache){
   return pCache->nRef;
 }
 
+/*
+** Return the number of references to the page supplied as an argument.
+*/
 SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){
   return p->nRef;
 }
@@ -27738,76 +27940,734 @@ SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){
 ** Return the total number of pages in the cache.
 */
 SQLITE_PRIVATE int sqlite3PcachePagecount(PCache *pCache){
-  assert( pCache->nPage>=0 );
-  return pCache->nPage;
+  int nPage = 0;
+  if( pCache->pCache ){
+    nPage = sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache);
+  }
+  return nPage;
 }
 
-#ifdef SQLITE_CHECK_PAGES
+#ifdef SQLITE_TEST
 /*
-** This function is used by the pager.c module to iterate through all 
-** pages in the cache. At present, this is only required if the
-** SQLITE_CHECK_PAGES macro (used for debugging) is specified.
+** Get the suggested cache-size value.
 */
-SQLITE_PRIVATE void sqlite3PcacheIterate(PCache *pCache, void (*xIter)(PgHdr *)){
-  PgHdr *p;
-  for(p=pCache->pClean; p; p=p->pNext){
-    xIter(p);
+SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *pCache){
+  return pCache->nMax;
+}
+#endif
+
+/*
+** Set the suggested cache-size value.
+*/
+SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
+  pCache->nMax = mxPage;
+  if( pCache->pCache ){
+    sqlite3GlobalConfig.pcache.xCachesize(pCache->pCache, mxPage);
   }
-  for(p=pCache->pDirty; p; p=p->pNext){
-    xIter(p);
+}
+
+#ifdef SQLITE_CHECK_PAGES
+/*
+** For all dirty pages currently in the cache, invoke the specified
+** callback. This is only used if the SQLITE_CHECK_PAGES macro is
+** defined.
+*/
+SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){
+  PgHdr *pDirty;
+  for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext){
+    xIter(pDirty);
   }
 }
 #endif
 
-/* 
-** Set flags on all pages in the page cache 
+
+/************** End of pcache.c **********************************************/
+/************** Begin file pcache1.c *****************************************/
+/*
+** 2008 November 05
+**
+** 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 the default page cache implementation (the
+** sqlite3_pcache interface). It also contains part of the implementation
+** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features.
+** If the default page cache implementation is overriden, then neither of
+** these two features are available.
+**
+** @(#) $Id$
 */
-SQLITE_PRIVATE void sqlite3PcacheClearFlags(PCache *pCache, int mask){
-  PgHdr *p;
 
-  /* Obtain the global mutex before modifying any PgHdr.flags variables 
-  ** or traversing the LRU list.
-  */ 
-  pcacheEnterMutex();
 
-  mask = ~mask;
-  for(p=pCache->pDirty; p; p=p->pNext){
-    p->flags &= mask;
+typedef struct PCache1 PCache1;
+typedef struct PgHdr1 PgHdr1;
+typedef struct PgFreeslot PgFreeslot;
+
+/* Pointers to structures of this type are cast and returned as 
+** opaque sqlite3_pcache* handles
+*/
+struct PCache1 {
+  /* Cache configuration parameters. Page size (szPage) and the purgeable
+  ** flag (bPurgeable) are set when the cache is created. nMax may be 
+  ** modified at any time by a call to the pcache1CacheSize() method.
+  ** The global mutex must be held when accessing nMax.
+  */
+  int szPage;                         /* Size of allocated pages in bytes */
+  int bPurgeable;                     /* True if cache is purgeable */
+  unsigned int nMin;                  /* Minimum number of pages reserved */
+  unsigned int nMax;                  /* Configured "cache_size" value */
+
+  /* Hash table of all pages. The following variables may only be accessed
+  ** when the accessor is holding the global mutex (see pcache1EnterMutex() 
+  ** and pcache1LeaveMutex()).
+  */
+  unsigned int nRecyclable;           /* Number of pages in the LRU list */
+  unsigned int nPage;                 /* Total number of pages in apHash */
+  unsigned int nHash;                 /* Number of slots in apHash[] */
+  PgHdr1 **apHash;                    /* Hash table for fast lookup by key */
+};
+
+/*
+** Each cache entry is represented by an instance of the following 
+** structure. A buffer of PgHdr1.pCache->szPage bytes is allocated 
+** directly after the structure in memory (see the PGHDR1_TO_PAGE() 
+** macro below).
+*/
+struct PgHdr1 {
+  unsigned int iKey;             /* Key value (page number) */
+  PgHdr1 *pNext;                 /* Next in hash table chain */
+  PCache1 *pCache;               /* Cache that currently owns this page */
+  PgHdr1 *pLruNext;              /* Next in LRU list of unpinned pages */
+  PgHdr1 *pLruPrev;              /* Previous in LRU list of unpinned pages */
+};
+
+/*
+** Free slots in the allocator used to divide up the buffer provided using
+** the SQLITE_CONFIG_PAGECACHE mechanism.
+*/
+struct PgFreeslot {
+  PgFreeslot *pNext;  /* Next free slot */
+};
+
+/*
+** Global data used by this cache.
+*/
+static SQLITE_WSD struct PCacheGlobal {
+  sqlite3_mutex *mutex;               /* static mutex MUTEX_STATIC_LRU */
+
+  int nMaxPage;                       /* Sum of nMaxPage for purgeable caches */
+  int nMinPage;                       /* Sum of nMinPage for purgeable caches */
+  int nCurrentPage;                   /* Number of purgeable pages allocated */
+  PgHdr1 *pLruHead, *pLruTail;        /* LRU list of unpinned pages */
+
+  /* Variables related to SQLITE_CONFIG_PAGECACHE settings. */
+  int szSlot;                         /* Size of each free slot */
+  void *pStart, *pEnd;                /* Bounds of pagecache malloc range */
+  PgFreeslot *pFree;                  /* Free page blocks */
+} pcache1_g;
+
+/*
+** All code in this file should access the global structure above via the
+** alias "pcache1". This ensures that the WSD emulation is used when
+** compiling for systems that do not support real WSD.
+*/
+#define pcache1 (GLOBAL(struct PCacheGlobal, pcache1_g))
+
+/*
+** When a PgHdr1 structure is allocated, the associated PCache1.szPage
+** bytes of data are located directly after it in memory (i.e. the total
+** size of the allocation is sizeof(PgHdr1)+PCache1.szPage byte). The
+** PGHDR1_TO_PAGE() macro takes a pointer to a PgHdr1 structure as
+** an argument and returns a pointer to the associated block of szPage
+** bytes. The PAGE_TO_PGHDR1() macro does the opposite: its argument is
+** a pointer to a block of szPage bytes of data and the return value is
+** a pointer to the associated PgHdr1 structure.
+**
+**   assert( PGHDR1_TO_PAGE(PAGE_TO_PGHDR1(X))==X );
+*/
+#define PGHDR1_TO_PAGE(p) (void *)(&((unsigned char *)p)[sizeof(PgHdr1)])
+#define PAGE_TO_PGHDR1(p) (PgHdr1 *)(&((unsigned char *)p)[-1*sizeof(PgHdr1)])
+
+/*
+** Macros to enter and leave the global LRU mutex.
+*/
+#define pcache1EnterMutex() sqlite3_mutex_enter(pcache1.mutex)
+#define pcache1LeaveMutex() sqlite3_mutex_leave(pcache1.mutex)
+
+/******************************************************************************/
+/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
+
+/*
+** This function is called during initialization if a static buffer is 
+** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE
+** verb to sqlite3_config(). Parameter pBuf points to an allocation large
+** enough to contain 'n' buffers of 'sz' bytes each.
+*/
+SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
+  PgFreeslot *p;
+  sz &= ~7;
+  pcache1.szSlot = sz;
+  pcache1.pStart = pBuf;
+  pcache1.pFree = 0;
+  while( n-- ){
+    p = (PgFreeslot*)pBuf;
+    p->pNext = pcache1.pFree;
+    pcache1.pFree = p;
+    pBuf = (void*)&((char*)pBuf)[sz];
+  }
+  pcache1.pEnd = pBuf;
+}
+
+/*
+** Malloc function used within this file to allocate space from the buffer
+** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no 
+** such buffer exists or there is no space left in it, this function falls 
+** back to sqlite3Malloc().
+*/
+static void *pcache1Alloc(int nByte){
+  void *p;
+  assert( sqlite3_mutex_held(pcache1.mutex) );
+  if( nByte<=pcache1.szSlot && pcache1.pFree ){
+    p = (PgHdr1 *)pcache1.pFree;
+    pcache1.pFree = pcache1.pFree->pNext;
+    sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
+    sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
+  }else{
+
+    /* Allocate a new buffer using sqlite3Malloc. Before doing so, exit the
+    ** global pcache mutex and unlock the pager-cache object pCache. This is 
+    ** so that if the attempt to allocate a new buffer causes the the 
+    ** configured soft-heap-limit to be breached, it will be possible to
+    ** reclaim memory from this pager-cache.
+    */
+    pcache1LeaveMutex();
+    p = sqlite3Malloc(nByte);
+    pcache1EnterMutex();
+    if( p ){
+      int sz = sqlite3MallocSize(p);
+      sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
+    }
+  }
+  return p;
+}
+
+/*
+** Free an allocated buffer obtained from pcache1Alloc().
+*/
+static void pcache1Free(void *p){
+  assert( sqlite3_mutex_held(pcache1.mutex) );
+  if( p==0 ) return;
+  if( p>=pcache1.pStart && p<pcache1.pEnd ){
+    PgFreeslot *pSlot;
+    sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1);
+    pSlot = (PgFreeslot*)p;
+    pSlot->pNext = pcache1.pFree;
+    pcache1.pFree = pSlot;
+  }else{
+    int iSize = sqlite3MallocSize(p);
+    sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
+    sqlite3_free(p);
   }
-  for(p=pCache->pClean; p; p=p->pNext){
-    p->flags &= mask;
+}
+
+/*
+** Allocate a new page object initially associated with cache pCache.
+*/
+static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
+  int nByte = sizeof(PgHdr1) + pCache->szPage;
+  PgHdr1 *p = (PgHdr1 *)pcache1Alloc(nByte);
+  if( p ){
+    memset(p, 0, nByte);
+    if( pCache->bPurgeable ){
+      pcache1.nCurrentPage++;
+    }
   }
+  return p;
+}
 
-  if( 0==(mask&PGHDR_NEED_SYNC) ){
-    pCache->pSynced = pCache->pDirtyTail;
-    assert( !pCache->pSynced || (pCache->pSynced->flags&PGHDR_NEED_SYNC)==0 );
+/*
+** Free a page object allocated by pcache1AllocPage().
+*/
+static void pcache1FreePage(PgHdr1 *p){
+  if( p ){
+    if( p->pCache->bPurgeable ){
+      pcache1.nCurrentPage--;
+    }
+    pcache1Free(p);
   }
+}
 
-  pcacheExitMutex();
+/*
+** Malloc function used by SQLite to obtain space from the buffer configured
+** using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no such buffer
+** exists, this function falls back to sqlite3Malloc().
+*/
+SQLITE_PRIVATE void *sqlite3PageMalloc(int sz){
+  void *p;
+  pcache1EnterMutex();
+  p = pcache1Alloc(sz);
+  pcache1LeaveMutex();
+  return p;
 }
 
 /*
-** Set the suggested cache-size value.
+** Free an allocated buffer obtained from sqlite3PageMalloc().
 */
-SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *pCache){
-  return pCache->nMax;
+SQLITE_PRIVATE void sqlite3PageFree(void *p){
+  pcache1EnterMutex();
+  pcache1Free(p);
+  pcache1LeaveMutex();
 }
 
+/******************************************************************************/
+/******** General Implementation Functions ************************************/
+
 /*
-** Set the suggested cache-size value.
+** This function is used to resize the hash table used by the cache passed
+** as the first argument.
+**
+** The global mutex must be held when this function is called.
 */
-SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
-  if( mxPage<10 ){
-    mxPage = 10;
+static int pcache1ResizeHash(PCache1 *p){
+  PgHdr1 **apNew;
+  unsigned int nNew;
+  unsigned int i;
+
+  assert( sqlite3_mutex_held(pcache1.mutex) );
+
+  nNew = p->nHash*2;
+  if( nNew<256 ){
+    nNew = 256;
+  }
+
+  pcache1LeaveMutex();
+  apNew = (PgHdr1 **)sqlite3_malloc(sizeof(PgHdr1 *)*nNew);
+  pcache1EnterMutex();
+  if( apNew ){
+    memset(apNew, 0, sizeof(PgHdr1 *)*nNew);
+    for(i=0; i<p->nHash; i++){
+      PgHdr1 *pPage;
+      PgHdr1 *pNext = p->apHash[i];
+      while( (pPage = pNext) ){
+        unsigned int h = pPage->iKey % nNew;
+        pNext = pPage->pNext;
+        pPage->pNext = apNew[h];
+        apNew[h] = pPage;
+      }
+    }
+    sqlite3_free(p->apHash);
+    p->apHash = apNew;
+    p->nHash = nNew;
   }
+
+  return (p->apHash ? SQLITE_OK : SQLITE_NOMEM);
+}
+
+/*
+** This function is used internally to remove the page pPage from the 
+** global LRU list, if is part of it. If pPage is not part of the global
+** LRU list, then this function is a no-op.
+**
+** The global mutex must be held when this function is called.
+*/
+static void pcache1PinPage(PgHdr1 *pPage){
+  assert( sqlite3_mutex_held(pcache1.mutex) );
+  if( pPage && (pPage->pLruNext || pPage==pcache1.pLruTail) ){
+    if( pPage->pLruPrev ){
+      pPage->pLruPrev->pLruNext = pPage->pLruNext;
+    }
+    if( pPage->pLruNext ){
+      pPage->pLruNext->pLruPrev = pPage->pLruPrev;
+    }
+    if( pcache1.pLruHead==pPage ){
+      pcache1.pLruHead = pPage->pLruNext;
+    }
+    if( pcache1.pLruTail==pPage ){
+      pcache1.pLruTail = pPage->pLruPrev;
+    }
+    pPage->pLruNext = 0;
+    pPage->pLruPrev = 0;
+    pPage->pCache->nRecyclable--;
+  }
+}
+
+
+/*
+** Remove the page supplied as an argument from the hash table 
+** (PCache1.apHash structure) that it is currently stored in.
+**
+** The global mutex must be held when this function is called.
+*/
+static void pcache1RemoveFromHash(PgHdr1 *pPage){
+  unsigned int h;
+  PCache1 *pCache = pPage->pCache;
+  PgHdr1 **pp;
+
+  h = pPage->iKey % pCache->nHash;
+  for(pp=&pCache->apHash[h]; (*pp)!=pPage; pp=&(*pp)->pNext);
+  *pp = (*pp)->pNext;
+
+  pCache->nPage--;
+}
+
+/*
+** If there are currently more than pcache.nMaxPage pages allocated, try
+** to recycle pages to reduce the number allocated to pcache.nMaxPage.
+*/
+static void pcache1EnforceMaxPage(void){
+  assert( sqlite3_mutex_held(pcache1.mutex) );
+  while( pcache1.nCurrentPage>pcache1.nMaxPage && pcache1.pLruTail ){
+    PgHdr1 *p = pcache1.pLruTail;
+    pcache1PinPage(p);
+    pcache1RemoveFromHash(p);
+    pcache1FreePage(p);
+  }
+}
+
+/*
+** Discard all pages from cache pCache with a page number (key value) 
+** greater than or equal to iLimit. Any pinned pages that meet this 
+** criteria are unpinned before they are discarded.
+**
+** The global mutex must be held when this function is called.
+*/
+static void pcache1TruncateUnsafe(
+  PCache1 *pCache, 
+  unsigned int iLimit 
+){
+  unsigned int h;
+  assert( sqlite3_mutex_held(pcache1.mutex) );
+  for(h=0; h<pCache->nHash; h++){
+    PgHdr1 **pp = &pCache->apHash[h]; 
+    PgHdr1 *pPage;
+    while( (pPage = *pp) ){
+      if( pPage->iKey>=iLimit ){
+        pcache1PinPage(pPage);
+        *pp = pPage->pNext;
+        pcache1FreePage(pPage);
+      }else{
+        pp = &pPage->pNext;
+      }
+    }
+  }
+}
+
+/******************************************************************************/
+/******** sqlite3_pcache Methods **********************************************/
+
+/*
+** Implementation of the sqlite3_pcache.xInit method.
+*/
+static int pcache1Init(void *NotUsed){
+  UNUSED_PARAMETER(NotUsed);
+  memset(&pcache1, 0, sizeof(pcache1));
+  if( sqlite3GlobalConfig.bCoreMutex ){
+    pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
+  }
+  return SQLITE_OK;
+}
+
+/*
+** Implementation of the sqlite3_pcache.xShutdown method.
+*/
+static void pcache1Shutdown(void *NotUsed){
+  UNUSED_PARAMETER(NotUsed);
+  /* no-op */
+}
+
+/*
+** Implementation of the sqlite3_pcache.xCreate method.
+**
+** Allocate a new cache.
+*/
+static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
+  PCache1 *pCache;
+
+  pCache = (PCache1 *)sqlite3_malloc(sizeof(PCache1));
+  if( pCache ){
+    memset(pCache, 0, sizeof(PCache1));
+    pCache->szPage = szPage;
+    pCache->bPurgeable = (bPurgeable ? 1 : 0);
+    if( bPurgeable ){
+      pCache->nMin = 10;
+      pcache1EnterMutex();
+      pcache1.nMinPage += pCache->nMin;
+      pcache1LeaveMutex();
+    }
+  }
+  return (sqlite3_pcache *)pCache;
+}
+
+/*
+** Implementation of the sqlite3_pcache.xCachesize method. 
+**
+** Configure the cache_size limit for a cache.
+*/
+static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
+  PCache1 *pCache = (PCache1 *)p;
   if( pCache->bPurgeable ){
-    pcacheEnterMutex();
-    pcache_g.nMaxPage -= pCache->nMax;
-    pcache_g.nMaxPage += mxPage;
-    pcacheEnforceMaxPage();
-    pcacheExitMutex();
+    pcache1EnterMutex();
+    pcache1.nMaxPage += (nMax - pCache->nMax);
+    pCache->nMax = nMax;
+    pcache1EnforceMaxPage();
+    pcache1LeaveMutex();
   }
-  pCache->nMax = mxPage;
+}
+
+/*
+** Implementation of the sqlite3_pcache.xPagecount method. 
+*/
+static int pcache1Pagecount(sqlite3_pcache *p){
+  int n;
+  pcache1EnterMutex();
+  n = ((PCache1 *)p)->nPage;
+  pcache1LeaveMutex();
+  return n;
+}
+
+/*
+** Implementation of the sqlite3_pcache.xFetch method. 
+**
+** Fetch a page by key value.
+**
+** Whether or not a new page may be allocated by this function depends on
+** the value of the createFlag argument.
+**
+** There are three different approaches to obtaining space for a page,
+** depending on the value of parameter createFlag (which may be 0, 1 or 2).
+**
+**   1. Regardless of the value of createFlag, the cache is searched for a 
+**      copy of the requested page. If one is found, it is returned.
+**
+**   2. If createFlag==0 and the page is not already in the cache, NULL is
+**      returned.
+**
+**   3. If createFlag is 1, the cache is marked as purgeable and the page is 
+**      not already in the cache, and if either of the following are true, 
+**      return NULL:
+**
+**       (a) the number of pages pinned by the cache is greater than
+**           PCache1.nMax, or
+**       (b) the number of pages pinned by the cache is greater than
+**           the sum of nMax for all purgeable caches, less the sum of 
+**           nMin for all other purgeable caches. 
+**
+**   4. If none of the first three conditions apply and the cache is marked
+**      as purgeable, and if one of the following is true:
+**
+**       (a) The number of pages allocated for the cache is already 
+**           PCache1.nMax, or
+**
+**       (b) The number of pages allocated for all purgeable caches is
+**           already equal to or greater than the sum of nMax for all
+**           purgeable caches,
+**
+**      then attempt to recycle a page from the LRU list. If it is the right
+**      size, return the recycled buffer. Otherwise, free the buffer and
+**      proceed to step 5. 
+**
+**   5. Otherwise, allocate and return a new page buffer.
+*/
+static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
+  unsigned int nPinned;
+  PCache1 *pCache = (PCache1 *)p;
+  PgHdr1 *pPage = 0;
+
+  pcache1EnterMutex();
+  if( createFlag==1 ) sqlite3BeginBenignMalloc();
+
+  /* Search the hash table for an existing entry. */
+  if( pCache->nHash>0 ){
+    unsigned int h = iKey % pCache->nHash;
+    for(pPage=pCache->apHash[h]; pPage&&pPage->iKey!=iKey; pPage=pPage->pNext);
+  }
+
+  if( pPage || createFlag==0 ){
+    pcache1PinPage(pPage);
+    goto fetch_out;
+  }
+
+  /* Step 3 of header comment. */
+  nPinned = pCache->nPage - pCache->nRecyclable;
+  if( createFlag==1 && pCache->bPurgeable && (
+        nPinned>=(pcache1.nMaxPage+pCache->nMin-pcache1.nMinPage)
+     || nPinned>=(pCache->nMax)
+  )){
+    goto fetch_out;
+  }
+
+  if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){
+    goto fetch_out;
+  }
+
+  /* Step 4. Try to recycle a page buffer if appropriate. */
+  if( pCache->bPurgeable && pcache1.pLruTail && (
+      pCache->nPage>=pCache->nMax-1 || pcache1.nCurrentPage>=pcache1.nMaxPage
+  )){
+    pPage = pcache1.pLruTail;
+    pcache1RemoveFromHash(pPage);
+    pcache1PinPage(pPage);
+    if( pPage->pCache->szPage!=pCache->szPage ){
+      pcache1FreePage(pPage);
+      pPage = 0;
+    }else{
+      pcache1.nCurrentPage -= (pPage->pCache->bPurgeable - pCache->bPurgeable);
+    }
+  }
+
+  /* Step 5. If a usable page buffer has still not been found, 
+  ** attempt to allocate a new one. 
+  */
+  if( !pPage ){
+    pPage = pcache1AllocPage(pCache);
+  }
+
+  if( pPage ){
+    unsigned int h = iKey % pCache->nHash;
+    memset(pPage, 0, pCache->szPage + sizeof(PgHdr1));
+    pCache->nPage++;
+    pPage->iKey = iKey;
+    pPage->pNext = pCache->apHash[h];
+    pPage->pCache = pCache;
+    pCache->apHash[h] = pPage;
+  }
+
+fetch_out:
+  if( createFlag==1 ) sqlite3EndBenignMalloc();
+  pcache1LeaveMutex();
+  return (pPage ? PGHDR1_TO_PAGE(pPage) : 0);
+}
+
+
+/*
+** Implementation of the sqlite3_pcache.xUnpin method.
+**
+** Mark a page as unpinned (eligible for asynchronous recycling).
+*/
+static void pcache1Unpin(sqlite3_pcache *p, void *pPg, int reuseUnlikely){
+  PCache1 *pCache = (PCache1 *)p;
+  PgHdr1 *pPage = PAGE_TO_PGHDR1(pPg);
+
+  pcache1EnterMutex();
+
+  /* It is an error to call this function if the page is already 
+  ** part of the global LRU list.
+  */
+  assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
+  assert( pcache1.pLruHead!=pPage && pcache1.pLruTail!=pPage );
+
+  if( reuseUnlikely || pcache1.nCurrentPage>pcache1.nMaxPage ){
+    pcache1RemoveFromHash(pPage);
+    pcache1FreePage(pPage);
+  }else{
+    /* Add the page to the global LRU list. Normally, the page is added to
+    ** the head of the list (last page to be recycled). However, if the 
+    ** reuseUnlikely flag passed to this function is true, the page is added
+    ** to the tail of the list (first page to be recycled).
+    */
+    if( pcache1.pLruHead ){
+      pcache1.pLruHead->pLruPrev = pPage;
+      pPage->pLruNext = pcache1.pLruHead;
+      pcache1.pLruHead = pPage;
+    }else{
+      pcache1.pLruTail = pPage;
+      pcache1.pLruHead = pPage;
+    }
+    pCache->nRecyclable++;
+  }
+
+  pcache1LeaveMutex();
+}
+
+/*
+** Implementation of the sqlite3_pcache.xRekey method. 
+*/
+static void pcache1Rekey(
+  sqlite3_pcache *p,
+  void *pPg,
+  unsigned int iOld,
+  unsigned int iNew
+){
+  PCache1 *pCache = (PCache1 *)p;
+  PgHdr1 *pPage = PAGE_TO_PGHDR1(pPg);
+  PgHdr1 **pp;
+  unsigned int h; 
+  assert( pPage->iKey==iOld );
+
+  pcache1EnterMutex();
+
+  h = iOld%pCache->nHash;
+  pp = &pCache->apHash[h];
+  while( (*pp)!=pPage ){
+    pp = &(*pp)->pNext;
+  }
+  *pp = pPage->pNext;
+
+  h = iNew%pCache->nHash;
+  pPage->iKey = iNew;
+  pPage->pNext = pCache->apHash[h];
+  pCache->apHash[h] = pPage;
+
+  pcache1LeaveMutex();
+}
+
+/*
+** Implementation of the sqlite3_pcache.xTruncate method. 
+**
+** Discard all unpinned pages in the cache with a page number equal to
+** or greater than parameter iLimit. Any pinned pages with a page number
+** equal to or greater than iLimit are implicitly unpinned.
+*/
+static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){
+  PCache1 *pCache = (PCache1 *)p;
+  pcache1EnterMutex();
+  pcache1TruncateUnsafe(pCache, iLimit);
+  pcache1LeaveMutex();
+}
+
+/*
+** Implementation of the sqlite3_pcache.xDestroy method. 
+**
+** Destroy a cache allocated using pcache1Create().
+*/
+static void pcache1Destroy(sqlite3_pcache *p){
+  PCache1 *pCache = (PCache1 *)p;
+  pcache1EnterMutex();
+  pcache1TruncateUnsafe(pCache, 0);
+  pcache1.nMaxPage -= pCache->nMax;
+  pcache1.nMinPage -= pCache->nMin;
+  pcache1EnforceMaxPage();
+  pcache1LeaveMutex();
+  sqlite3_free(pCache->apHash);
+  sqlite3_free(pCache);
+}
+
+/*
+** This function is called during initialization (sqlite3_initialize()) to
+** install the default pluggable cache module, assuming the user has not
+** already provided an alternative.
+*/
+SQLITE_PRIVATE void sqlite3PCacheSetDefault(void){
+  static sqlite3_pcache_methods defaultMethods = {
+    0,                       /* pArg */
+    pcache1Init,             /* xInit */
+    pcache1Shutdown,         /* xShutdown */
+    pcache1Create,           /* xCreate */
+    pcache1Cachesize,        /* xCachesize */
+    pcache1Pagecount,        /* xPagecount */
+    pcache1Fetch,            /* xFetch */
+    pcache1Unpin,            /* xUnpin */
+    pcache1Rekey,            /* xRekey */
+    pcache1Truncate,         /* xTruncate */
+    pcache1Destroy           /* xDestroy */
+  };
+  sqlite3_config(SQLITE_CONFIG_PCACHE, &defaultMethods);
 }
 
 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
@@ -27822,40 +28682,45 @@ SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
 */
 SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
   int nFree = 0;
-  if( pcache_g.pStart==0 ){
-    PgHdr *p;
-    pcacheEnterMutex();
-    while( (nReq<0 || nFree<nReq) && (p=pcacheRecyclePage()) ){
-      nFree += pcachePageSize(p);
-      pcachePageFree(p);
+  if( pcache1.pStart==0 ){
+    PgHdr1 *p;
+    pcache1EnterMutex();
+    while( (nReq<0 || nFree<nReq) && (p=pcache1.pLruTail) ){
+      nFree += sqlite3MallocSize(p);
+      pcache1PinPage(p);
+      pcache1RemoveFromHash(p);
+      pcache1FreePage(p);
     }
-    pcacheExitMutex();
+    pcache1LeaveMutex();
   }
   return nFree;
 }
 #endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
 
 #ifdef SQLITE_TEST
+/*
+** This function is used by test procedures to inspect the internal state
+** of the global cache.
+*/
 SQLITE_PRIVATE void sqlite3PcacheStats(
-  int *pnCurrent,
-  int *pnMax,
-  int *pnMin,
-  int *pnRecyclable
+  int *pnCurrent,      /* OUT: Total number of pages cached */
+  int *pnMax,          /* OUT: Global maximum cache size */
+  int *pnMin,          /* OUT: Sum of PCache1.nMin for purgeable caches */
+  int *pnRecyclable    /* OUT: Total number of pages available for recycling */
 ){
-  PgHdr *p;
+  PgHdr1 *p;
   int nRecyclable = 0;
-  for(p=pcache_g.pLruHead; p; p=p->pNextLru){
+  for(p=pcache1.pLruHead; p; p=p->pLruNext){
     nRecyclable++;
   }
-
-  *pnCurrent = pcache_g.nCurrentPage;
-  *pnMax = pcache_g.nMaxPage;
-  *pnMin = pcache_g.nMinPage;
+  *pnCurrent = pcache1.nCurrentPage;
+  *pnMax = pcache1.nMaxPage;
+  *pnMin = pcache1.nMinPage;
   *pnRecyclable = nRecyclable;
 }
 #endif
 
-/************** End of pcache.c **********************************************/
+/************** End of pcache1.c *********************************************/
 /************** Begin file pager.c *******************************************/
 /*
 ** 2001 September 15
@@ -28034,11 +28899,12 @@ struct Pager {
   u8 journalMode;             /* On of the PAGER_JOURNALMODE_* values */
   u8 dbModified;              /* True if there are any changes to the Db */
   u8 changeCountDone;         /* Set after incrementing the change-counter */
+  u8 dbSizeValid;             /* Set when dbSize is correct */
   u32 vfsFlags;               /* Flags for sqlite3_vfs.xOpen() */
   int errCode;                /* One of several kinds of errors */
-  int dbSize;                 /* Number of pages in the file */
-  int origDbSize;             /* dbSize before the current change */
-  int stmtSize;               /* Size of database (in pages) at stmt_begin() */
+  Pgno dbSize;                /* Number of pages in the file */
+  Pgno origDbSize;            /* dbSize before the current change */
+  Pgno stmtSize;              /* Size of database (in pages) at stmt_begin() */
   int nRec;                   /* Number of pages written to the journal */
   u32 cksumInit;              /* Quasi-random value added to every checksum */
   int stmtNRec;               /* Number of records in stmt subjournal */
@@ -28055,7 +28921,8 @@ struct Pager {
   char *zDirectory;           /* Directory hold database and journal files */
   sqlite3_file *fd, *jfd;     /* File descriptors for database and journal */
   sqlite3_file *stfd;         /* File descriptor for the statement subjournal*/
-  BusyHandler *pBusyHandler;  /* Pointer to sqlite.busyHandler */
+  int (*xBusyHandler)(void*); /* Function to call when busy */
+  void *pBusyHandlerArg;      /* Context argument for xBusyHandler */
   i64 journalOff;             /* Current byte offset in the journal file */
   i64 journalHdr;             /* Byte offset to previous journal header */
   i64 stmtHdrOff;             /* First journal header written this statement */
@@ -28153,7 +29020,7 @@ static const unsigned char aJournalMagic[] = {
 ** roll back. See comments for function writeMasterJournal() for details.
 */
 /* #define PAGER_MJ_PGNO(x) (PENDING_BYTE/((x)->pageSize)) */
-#define PAGER_MJ_PGNO(x) ((PENDING_BYTE/((x)->pageSize))+1)
+#define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1))
 
 /*
 ** The maximum legal page number is (2^31 - 1).
@@ -28170,6 +29037,10 @@ static int pageInStatement(PgHdr *pPg){
   return sqlite3BitvecTest(pPager->pInStmt, pPg->pgno);
 }
 
+static int pageInJournal(PgHdr *pPg){
+  return sqlite3BitvecTest(pPg->pPager->pInJournal, pPg->pgno);
+}
+
 /*
 ** Read a 32-bit integer from the given file descriptor.  Store the integer
 ** that is read in *pRes.  Return SQLITE_OK if everything worked, or an
@@ -28312,7 +29183,7 @@ static u32 pager_datahash(int nByte, unsigned char *pData){
 static u32 pager_pagehash(PgHdr *pPage){
   return pager_datahash(pPage->pPager->pageSize, (unsigned char *)pPage->pData);
 }
-static u32 pager_set_pagehash(PgHdr *pPage){
+static void pager_set_pagehash(PgHdr *pPage){
   pPage->pageHash = pager_pagehash(pPage);
 }
 
@@ -28349,7 +29220,7 @@ static void checkPage(PgHdr *pPg){
 ** If no master journal file name is present zMaster[0] is set to 0 and
 ** SQLITE_OK returned.
 */
-static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, int nMaster){
+static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
   int rc;
   u32 len;
   i64 szJ;
@@ -28481,8 +29352,8 @@ static int zeroJournalHdr(Pager *pPager, int doTruncate){
 static int writeJournalHdr(Pager *pPager){
   int rc = SQLITE_OK;
   char *zHeader = pPager->pTmpSpace;
-  int nHeader = pPager->pageSize;
-  int nWrite;
+  u32 nHeader = pPager->pageSize;
+  u32 nWrite;
 
   if( nHeader>JOURNAL_HDR_SZ(pPager) ){
     nHeader = JOURNAL_HDR_SZ(pPager);
@@ -28741,7 +29612,7 @@ static void pager_unlock(Pager *pPager){
   if( !pPager->exclusiveMode ){
     int rc = osUnlock(pPager->fd, NO_LOCK);
     if( rc ) pPager->errCode = rc;
-    pPager->dbSize = -1;
+    pPager->dbSizeValid = 0;
     IOTRACE(("UNLOCK %p\n", pPager))
 
     /* Always close the journal file when dropping the database lock.
@@ -28855,13 +29726,10 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
     pPager->pInJournal = 0;
     sqlite3BitvecDestroy(pPager->pAlwaysRollback);
     pPager->pAlwaysRollback = 0;
-    sqlite3PcacheCleanAll(pPager->pPCache);
 #ifdef SQLITE_CHECK_PAGES
-    sqlite3PcacheIterate(pPager->pPCache, pager_set_pagehash);
+    sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash);
 #endif
-    sqlite3PcacheClearFlags(pPager->pPCache,
-       PGHDR_IN_JOURNAL | PGHDR_NEED_SYNC
-    );
+    sqlite3PcacheCleanAll(pPager->pPCache);
     pPager->dirtyCache = 0;
     pPager->nRec = 0;
   }else{
@@ -28879,7 +29747,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
   pPager->needSync = 0;
   /* lruListSetFirstSynced(pPager); */
   if( !MEMDB ){
-    pPager->dbSize = -1;
+    pPager->dbSizeValid = 0;
   }
   pPager->dbModified = 0;
 
@@ -29167,7 +30035,7 @@ static void pager_truncate_cache(Pager *pPager);
 ** so detect this case and write a single zero byte to the end of the new
 ** file instead.
 */
-static int pager_truncate(Pager *pPager, int nPage){
+static int pager_truncate(Pager *pPager, Pgno nPage){
   int rc = SQLITE_OK;
   if( pPager->state>=PAGER_EXCLUSIVE && pPager->fd->pMethods ){
     i64 currentSize, newSize;
@@ -29676,7 +30544,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
   /* Open the pager file.
   */
   if( zFilename && zFilename[0] && !memDb ){
-    if( nPathname>(pVfs->mxPathname - sizeof("-journal")) ){
+    if( nPathname>(pVfs->mxPathname - (int)sizeof("-journal")) ){
       rc = SQLITE_CANTOPEN;
     }else{
       int fout = 0;
@@ -29767,7 +30635,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
   /* pPager->stmtOpen = 0; */
   /* pPager->stmtInUse = 0; */
   /* pPager->nRef = 0; */
-  pPager->dbSize = memDb-1;
+  pPager->dbSizeValid = memDb;
   pPager->pageSize = szPageDflt;
   /* pPager->stmtSize = 0; */
   /* pPager->stmtJSize = 0; */
@@ -29798,7 +30666,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
   if( memDb ){
     pPager->journalMode = PAGER_JOURNALMODE_MEMORY;
   }
-  /* pPager->pBusyHandler = 0; */
+  /* pPager->xBusyHandler = 0; */
+  /* pPager->pBusyHandlerArg = 0; */
   /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
   *ppPager = pPager;
   return SQLITE_OK;
@@ -29807,8 +30676,13 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
 /*
 ** Set the busy handler function.
 */
-SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager *pPager, BusyHandler *pBusyHandler){
-  pPager->pBusyHandler = pBusyHandler;
+SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(
+  Pager *pPager, 
+  int (*xBusyHandler)(void *),
+  void *pBusyHandlerArg
+){  
+  pPager->xBusyHandler = xBusyHandler;
+  pPager->pBusyHandlerArg = pBusyHandlerArg;
 }
 
 /*
@@ -29945,7 +30819,7 @@ SQLITE_PRIVATE int sqlite3PagerPagecount(Pager *pPager, int *pnPage){
     rc = pPager->errCode;
     return rc;
   }
-  if( pPager->dbSize>=0 ){
+  if( pPager->dbSizeValid ){
     n = pPager->dbSize;
   } else {
     assert(pPager->fd->pMethods||pPager->tempFile);
@@ -29961,6 +30835,7 @@ SQLITE_PRIVATE int sqlite3PagerPagecount(Pager *pPager, int *pnPage){
     }
     if( pPager->state!=PAGER_UNLOCK ){
       pPager->dbSize = n;
+      pPager->dbSizeValid = 1;
     }
   }
   if( n==(PENDING_BYTE/pPager->pageSize) ){
@@ -30013,15 +30888,14 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
   assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK );
 
   /* If the file is currently unlocked then the size must be unknown */
-  assert( pPager->state>=PAGER_SHARED || pPager->dbSize<0 );
+  assert( pPager->state>=PAGER_SHARED || pPager->dbSizeValid==0 );
 
   if( pPager->state>=locktype ){
     rc = SQLITE_OK;
   }else{
-    if( pPager->pBusyHandler ) pPager->pBusyHandler->nBusy = 0;
     do {
       rc = sqlite3OsLock(pPager->fd, locktype);
-    }while( rc==SQLITE_BUSY && sqlite3InvokeBusyHandler(pPager->pBusyHandler) );
+    }while( rc==SQLITE_BUSY && pPager->xBusyHandler(pPager->pBusyHandlerArg) );
     if( rc==SQLITE_OK ){
       pPager->state = locktype;
       IOTRACE(("LOCK %p %d\n", pPager, locktype))
@@ -30040,7 +30914,7 @@ SQLITE_PRIVATE int sqlite3PagerTruncate(Pager *pPager, Pgno nPage){
   sqlite3PagerPagecount(pPager, 0);
   if( pPager->errCode ){
     rc = pPager->errCode;
-  }else if( nPage<(unsigned)pPager->dbSize ){
+  }else if( nPage<pPager->dbSize ){
     rc = syncJournal(pPager);
     if( rc==SQLITE_OK ){
       /* Get an exclusive lock on the database before truncating. */
@@ -30197,19 +31071,9 @@ static int syncJournal(Pager *pPager){
 
     /* Erase the needSync flag from every page.
     */
-    sqlite3PcacheClearFlags(pPager->pPCache, PGHDR_NEED_SYNC);
+    sqlite3PcacheClearSyncFlags(pPager->pPCache);
   }
 
-#ifndef NDEBUG
-  /* If the Pager.needSync flag is clear then the PgHdr.needSync
-  ** flag must also be clear for all pages.  Verify that this
-  ** invariant is true.
-  */
-  else{
-    sqlite3PcacheAssertFlags(pPager->pPCache, 0, PGHDR_NEED_SYNC);
-  }
-#endif
-
   return rc;
 }
 
@@ -30560,6 +31424,7 @@ static int pagerSharedLock(Pager *pPager){
         goto failed;
       }
 
+      assert( pPager->dbSizeValid );
       if( pPager->dbSize>0 ){
         IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
         rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
@@ -30710,9 +31575,6 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
     int nMax;
     PAGER_INCR(pPager->nMiss);
     pPg->pPager = pPager;
-    if( sqlite3BitvecTest(pPager->pInJournal, pgno) ){
-      pPg->flags |= PGHDR_IN_JOURNAL;
-    }
     memset(pPg->pExtra, 0, pPager->nExtra);
 
     rc = sqlite3PagerPagecount(pPager, &nMax);
@@ -30916,7 +31778,6 @@ SQLITE_PRIVATE int sqlite3PagerBegin(DbPage *pPg, int exFlag){
   if( pPager->state==PAGER_SHARED ){
     assert( pPager->pInJournal==0 );
     assert( !MEMDB );
-    sqlite3PcacheAssertFlags(pPager->pPCache, 0, PGHDR_IN_JOURNAL);
     rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK);
     if( rc==SQLITE_OK ){
       pPager->state = PAGER_RESERVED;
@@ -31025,9 +31886,7 @@ static int pager_write(PgHdr *pPg){
   ** to the journal then we can return right away.
   */
   makeDirty(pPg);
-  if( (pPg->flags&PGHDR_IN_JOURNAL)
-   && (pageInStatement(pPg) || pPager->stmtInUse==0) 
-  ){
+  if( pageInJournal(pPg) && (pageInStatement(pPg) || pPager->stmtInUse==0) ){
     pPager->dirtyCache = 1;
     pPager->dbModified = 1;
   }else{
@@ -31057,8 +31916,8 @@ static int pager_write(PgHdr *pPg){
     ** EXCLUSIVE lock on the main database file.  Write the current page to
     ** the transaction journal if it is not there already.
     */
-    if( !(pPg->flags&PGHDR_IN_JOURNAL) && pPager->journalOpen ){
-      if( (int)pPg->pgno <= pPager->origDbSize ){
+    if( !pageInJournal(pPg) && pPager->journalOpen ){
+      if( pPg->pgno<=pPager->origDbSize ){
         u32 cksum;
         char *pData2;
 
@@ -31112,7 +31971,6 @@ static int pager_write(PgHdr *pPg){
       if( pPg->flags&PGHDR_NEED_SYNC ){
         pPager->needSync = 1;
       }
-      pPg->flags |= PGHDR_IN_JOURNAL;
     }
   
     /* If the statement journal is open and the page is not in it,
@@ -31122,12 +31980,11 @@ static int pager_write(PgHdr *pPg){
     */
     if( pPager->stmtInUse 
      && !pageInStatement(pPg) 
-     && (int)pPg->pgno<=pPager->stmtSize 
+     && pPg->pgno<=pPager->stmtSize 
     ){
       i64 offset = pPager->stmtNRec*(4+pPager->pageSize);
       char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7);
-      assert( (pPg->flags&PGHDR_IN_JOURNAL) 
-                 || (int)pPg->pgno>pPager->origDbSize );
+      assert( pageInJournal(pPg) || pPg->pgno>pPager->origDbSize );
       rc = write32bits(pPager->stfd, offset, pPg->pgno);
       if( rc==SQLITE_OK ){
         rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize, offset+4);
@@ -31145,9 +32002,9 @@ static int pager_write(PgHdr *pPg){
   /* Update the database size and return.
   */
   assert( pPager->state>=PAGER_SHARED );
-  if( pPager->dbSize<(int)pPg->pgno ){
+  if( pPager->dbSize<pPg->pgno ){
     pPager->dbSize = pPg->pgno;
-    if( pPager->dbSize==PENDING_BYTE/pPager->pageSize ){
+    if( pPager->dbSize==(PAGER_MJ_PGNO(pPager)-1) ){
       pPager->dbSize++;
     }
   }
@@ -31305,7 +32162,7 @@ SQLITE_PRIVATE int sqlite3PagerDontWrite(DbPage *pDbPage){
 
   if( rc==SQLITE_OK && (pPg->flags&PGHDR_DIRTY) && !pPager->stmtInUse ){
     assert( pPager->state>=PAGER_SHARED );
-    if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSize<pPager->dbSize ){
+    if( pPager->dbSize==pPg->pgno && pPager->origDbSize<pPager->dbSize ){
       /* If this pages is the last page in the file and the file has grown
       ** during the current transaction, then do NOT mark the page as clean.
       ** When the database file grows, we must make sure that the last page
@@ -31354,7 +32211,8 @@ SQLITE_PRIVATE void sqlite3PagerDontRollback(DbPage *pPg){
   }
 
 #ifdef SQLITE_SECURE_DELETE
-  if( (pPg->flags & PGHDR_IN_JOURNAL)!=0 || (int)pPg->pgno>pPager->origDbSize ){
+  if( sqlite3BitvecTest(pPager->pInJournal, pPg->pgno)!=0
+   || pPg->pgno>pPager->origDbSize ){
     return;
   }
 #endif
@@ -31373,7 +32231,6 @@ SQLITE_PRIVATE void sqlite3PagerDontRollback(DbPage *pPg){
 
   assert( pPager->pInJournal!=0 );
   sqlite3BitvecSet(pPager->pInJournal, pPg->pgno);
-  pPg->flags |= PGHDR_IN_JOURNAL;
   pPg->flags &= ~PGHDR_NEED_READ;
   if( pPager->stmtInUse ){
     assert( pPager->stmtSize >= pPager->origDbSize );
@@ -31554,7 +32411,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
           ** file.
           */
           Pgno i;
-          int iSkip = PAGER_MJ_PGNO(pPager);
+          Pgno iSkip = PAGER_MJ_PGNO(pPager);
           for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){
             if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){
               rc = sqlite3PagerGet(pPager, i, &pPg);
@@ -31684,7 +32541,7 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
     }
 
     if( !MEMDB ){
-      pPager->dbSize = -1;
+      pPager->dbSizeValid = 0;
     }
 
     /* If an error occurs during a ROLLBACK, we can no longer trust the pager
@@ -31727,7 +32584,7 @@ SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){
   a[0] = sqlite3PcacheRefCount(pPager->pPCache);
   a[1] = sqlite3PcachePagecount(pPager->pPCache);
   a[2] = sqlite3PcacheGetCachesize(pPager->pPCache);
-  a[3] = pPager->dbSize;
+  a[3] = pPager->dbSizeValid ? (int) pPager->dbSize : -1;
   a[4] = pPager->state;
   a[5] = pPager->errCode;
   a[6] = pPager->nHit;
@@ -31753,7 +32610,7 @@ static int pagerStmtBegin(Pager *pPager){
   int rc;
   assert( !pPager->stmtInUse );
   assert( pPager->state>=PAGER_SHARED );
-  assert( pPager->dbSize>=0 );
+  assert( pPager->dbSizeValid );
   PAGERTRACE2("STMT-BEGIN %d\n", PAGERID(pPager));
   if( !pPager->journalOpen ){
     pPager->stmtAutoopen = 1;
@@ -31935,7 +32792,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
   */
   if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){
     needSyncPgno = pPg->pgno;
-    assert( (pPg->flags&PGHDR_IN_JOURNAL) || (int)pgno>pPager->origDbSize );
+    assert( pageInJournal(pPg) || pgno>pPager->origDbSize );
     assert( pPg->flags&PGHDR_DIRTY );
     assert( pPager->needSync );
   }
@@ -31945,20 +32802,16 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
   ** page pgno before the 'move' operation, it needs to be retained 
   ** for the page moved there.
   */
-  pPg->flags &= ~(PGHDR_NEED_SYNC|PGHDR_IN_JOURNAL);
+  pPg->flags &= ~PGHDR_NEED_SYNC;
   pPgOld = pager_lookup(pPager, pgno);
   assert( !pPgOld || pPgOld->nRef==1 );
   if( pPgOld ){
     pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
   }
-  if( sqlite3BitvecTest(pPager->pInJournal, pgno) ){
-    pPg->flags |= PGHDR_IN_JOURNAL;
-  }
 
   sqlite3PcacheMove(pPg, pgno);
   if( pPgOld ){
-    sqlite3PcacheMove(pPgOld, 0);
-    sqlite3PcacheRelease(pPgOld);
+    sqlite3PcacheDrop(pPgOld);
   }
 
   makeDirty(pPg);
@@ -31988,7 +32841,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
     assert( pPager->needSync );
     rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr);
     if( rc!=SQLITE_OK ){
-      if( pPager->pInJournal && (int)needSyncPgno<=pPager->origDbSize ){
+      if( pPager->pInJournal && needSyncPgno<=pPager->origDbSize ){
         sqlite3BitvecClear(pPager->pInJournal, needSyncPgno);
       }
       return rc;
@@ -31996,7 +32849,6 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
     pPager->needSync = 1;
     assert( pPager->noSync==0 && !MEMDB );
     pPgHdr->flags |= PGHDR_NEED_SYNC;
-    pPgHdr->flags |= PGHDR_IN_JOURNAL;
     makeDirty(pPgHdr);
     sqlite3PagerUnref(pPgHdr);
   }
@@ -32493,7 +33345,6 @@ struct BtShared {
   void *pSchema;        /* Pointer to space allocated by sqlite3BtreeSchema() */
   void (*xFreeSchema)(void*);  /* Destructor for BtShared.pSchema */
   sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */
-  BusyHandler busyHdr;  /* The busy handler for this btree */
 #ifndef SQLITE_OMIT_SHARED_CACHE
   int nRef;             /* Number of references to this structure */
   BtShared *pNext;      /* Next on a list of sharable BtShared structs */
@@ -32611,7 +33462,7 @@ struct BtCursor {
 #ifdef SQLITE_OMIT_DISKIO
 # define PENDING_BYTE_PAGE(pBt)  0x7fffffff
 #else
-# define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1)
+# define PENDING_BYTE_PAGE(pBt) ((Pgno)((PENDING_BYTE/(pBt)->pageSize)+1))
 #endif
 
 /*
@@ -32718,7 +33569,7 @@ typedef struct IntegrityCk IntegrityCk;
 struct IntegrityCk {
   BtShared *pBt;    /* The tree being checked out */
   Pager *pPager;    /* The associated pager.  Also accessible by pBt->pPager */
-  int nPage;        /* Number of pages in the database */
+  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 */
@@ -32978,7 +33829,7 @@ SQLITE_PRIVATE void sqlite3BtreeMutexArrayInsert(BtreeMutexArray *pArray, Btree
   }
 #endif
   assert( pArray->nMutex>=0 );
-  assert( pArray->nMutex<sizeof(pArray->aBtree)/sizeof(pArray->aBtree[0])-1 );
+  assert( pArray->nMutex<ArraySize(pArray->aBtree)-1 );
   pBt = pBtree->pBt;
   for(i=0; i<pArray->nMutex; i++){
     assert( pArray->aBtree[i]!=pBtree );
@@ -33482,7 +34333,8 @@ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){
 ** input page number.
 */
 static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){
-  int nPagesPerMapPage, iPtrMap, ret;
+  int nPagesPerMapPage;
+  Pgno iPtrMap, ret;
   assert( sqlite3_mutex_held(pBt->mutex) );
   nPagesPerMapPage = (pBt->usableSize/5)+1;
   iPtrMap = (pgno-2)/nPagesPerMapPage;
@@ -33781,14 +34633,15 @@ static int defragmentPage(MemPage *pPage){
     u8 *pAddr;     /* The i-th cell pointer */
     pAddr = &data[cellOffset + i*2];
     pc = get2byte(pAddr);
-    if (pc >= pPage->pBt->usableSize) {
+    if( pc>=usableSize ){
       return SQLITE_CORRUPT_BKPT;
     }
     size = cellSizePtr(pPage, &temp[pc]);
     cbrk -= size;
-    if ((cbrk < cellOffset+2*nCell) || (cbrk+size>pPage->pBt->usableSize)) {
+    if( cbrk<cellOffset+2*nCell || pc+size>usableSize ){
       return SQLITE_CORRUPT_BKPT;
     }
+    assert( cbrk+size<=usableSize && cbrk>=0 );
     memcpy(&data[cbrk], &temp[pc], size);
     put2byte(pAddr, cbrk);
   }
@@ -33881,7 +34734,7 @@ static int allocateSpace(MemPage *pPage, int nByte){
 ** Most of the effort here is involved in coalesing adjacent
 ** free blocks into a single big free block.
 */
-static void freeSpace(MemPage *pPage, int start, int size){
+static int freeSpace(MemPage *pPage, int start, int size){
   int addr, pbegin, hdr;
   unsigned char *data = pPage->aData;
 
@@ -33903,10 +34756,14 @@ static void freeSpace(MemPage *pPage, int start, int size){
   addr = hdr + 1;
   while( (pbegin = get2byte(&data[addr]))<start && pbegin>0 ){
     assert( pbegin<=pPage->pBt->usableSize-4 );
-    assert( pbegin>addr );
+    if( pbegin<=addr ) {
+      return SQLITE_CORRUPT_BKPT;
+    }
     addr = pbegin;
   }
-  assert( pbegin<=pPage->pBt->usableSize-4 );
+  if ( pbegin>pPage->pBt->usableSize-4 ) {
+    return SQLITE_CORRUPT_BKPT;
+  }
   assert( pbegin>addr || pbegin==0 );
   put2byte(&data[addr], start);
   put2byte(&data[start], pbegin);
@@ -33923,7 +34780,9 @@ static void freeSpace(MemPage *pPage, int start, int size){
     psize = get2byte(&data[pbegin+2]);
     if( pbegin + psize + 3 >= pnext && pnext>0 ){
       int frag = pnext - (pbegin+psize);
-      assert( frag<=data[pPage->hdrOffset+7] );
+      if( (frag<0) || (frag>data[pPage->hdrOffset+7]) ){
+        return SQLITE_CORRUPT_BKPT;
+      }
       data[pPage->hdrOffset+7] -= frag;
       put2byte(&data[pbegin], get2byte(&data[pnext]));
       put2byte(&data[pbegin+2], pnext+get2byte(&data[pnext+2])-pbegin);
@@ -33940,6 +34799,7 @@ static void freeSpace(MemPage *pPage, int start, int size){
     top = get2byte(&data[hdr+5]);
     put2byte(&data[hdr+5], top + get2byte(&data[pbegin+2]));
   }
+  return SQLITE_OK;
 }
 
 /*
@@ -34147,14 +35007,16 @@ SQLITE_PRIVATE int sqlite3BtreeGetPage(
 }
 
 /*
-** Return the size of the database file in pages.  Or return -1 if
-** there is any kind of error.
+** Return the size of the database file in pages. If there is any kind of
+** error, return ((unsigned int)-1).
 */
-static int pagerPagecount(Pager *pPager){
+static Pgno pagerPagecount(BtShared *pBt){
+  int nPage = -1;
   int rc;
-  int nPage;
-  rc = sqlite3PagerPagecount(pPager, &nPage);
-  return (rc==SQLITE_OK?nPage:-1);
+  assert( pBt->pPage1 );
+  rc = sqlite3PagerPagecount(pBt->pPager, &nPage);
+  assert( rc==SQLITE_OK || nPage==-1 );
+  return (Pgno)nPage;
 }
 
 /*
@@ -34188,7 +35050,7 @@ static int getAndInitPage(
     rc = SQLITE_OK;
   }else{
     /* Page not in cache.  Acquire it. */
-    if( pgno>pagerPagecount(pBt->pPager) ){
+    if( pgno>pagerPagecount(pBt) ){
       return SQLITE_CORRUPT_BKPT; 
     }
     rc = sqlite3BtreeGetPage(pBt, pgno, ppPage, 0);
@@ -34243,7 +35105,7 @@ static void pageReinit(DbPage *pData){
 /*
 ** Invoke the busy handler for a btree.
 */
-static int sqlite3BtreeInvokeBusyHandler(void *pArg, int n){
+static int btreeInvokeBusyHandler(void *pArg){
   BtShared *pBt = (BtShared*)pArg;
   assert( pBt->db );
   assert( sqlite3_mutex_held(pBt->db->mutex) );
@@ -34360,8 +35222,6 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
       rc = SQLITE_NOMEM;
       goto btree_open_out;
     }
-    pBt->busyHdr.xFunc = sqlite3BtreeInvokeBusyHandler;
-    pBt->busyHdr.pArg = pBt;
     rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename,
                           EXTRA_SIZE, flags, vfsFlags);
     if( rc==SQLITE_OK ){
@@ -34370,7 +35230,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
     if( rc!=SQLITE_OK ){
       goto btree_open_out;
     }
-    sqlite3PagerSetBusyhandler(pBt->pPager, &pBt->busyHdr);
+    sqlite3PagerSetBusyhandler(pBt->pPager, btreeInvokeBusyHandler, pBt);
     p->pBt = pBt;
   
     sqlite3PagerSetReiniter(pBt->pPager, pageReinit);
@@ -35068,7 +35928,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
       unlockBtreeIfUnused(pBt);
     }
   }while( rc==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
-          sqlite3BtreeInvokeBusyHandler(pBt, 0) );
+          btreeInvokeBusyHandler(pBt) );
 
   if( rc==SQLITE_OK ){
     if( p->inTrans==TRANS_NONE ){
@@ -35306,7 +36166,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin){
   assert( sqlite3_mutex_held(pBt->mutex) );
   iLastPg = pBt->nTrunc;
   if( iLastPg==0 ){
-    iLastPg = pagerPagecount(pBt->pPager);
+    iLastPg = pagerPagecount(pBt);
   }
 
   if( !PTRMAP_ISPAGE(pBt, iLastPg) && iLastPg!=PENDING_BYTE_PAGE(pBt) ){
@@ -35437,7 +36297,7 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *pnTrunc){
       Pgno nFree;
       Pgno nPtrmap;
       const int pgsz = pBt->pageSize;
-      int nOrig = pagerPagecount(pBt->pPager);
+      Pgno nOrig = pagerPagecount(pBt);
 
       if( PTRMAP_ISPAGE(pBt, nOrig) ){
         return SQLITE_CORRUPT_BKPT;
@@ -35649,9 +36509,14 @@ SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){
   BtCursor *p;
   sqlite3BtreeEnter(pBtree);
   for(p=pBtree->pBt->pCursor; p; p=p->pNext){
+    int i;
     sqlite3BtreeClearCursor(p);
     p->eState = CURSOR_FAULT;
     p->skip = errCode;
+    for(i=0; i<=p->iPage; i++){
+      releasePage(p->apPage[i]);
+      p->apPage[i] = 0;
+    }
   }
   sqlite3BtreeLeave(pBtree);
 }
@@ -35838,6 +36703,7 @@ static int btreeCursor(
   BtCursor *pCur                         /* Space for new cursor */
 ){
   int rc;
+  Pgno nPage;
   BtShared *pBt = p->pBt;
 
   assert( sqlite3BtreeHoldsMutex(p) );
@@ -35860,7 +36726,11 @@ static int btreeCursor(
     }
   }
   pCur->pgnoRoot = (Pgno)iTable;
-  if( iTable==1 && pagerPagecount(pBt->pPager)==0 ){
+  rc = sqlite3PagerPagecount(pBt->pPager, (int *)&nPage); 
+  if( rc!=SQLITE_OK ){
+    return rc;
+  }
+  if( iTable==1 && nPage==0 ){
     rc = SQLITE_EMPTY;
     goto create_cursor_exception;
   }
@@ -36121,7 +36991,7 @@ static int getOverflowPage(
       iGuess++;
     }
 
-    if( iGuess<=pagerPagecount(pBt->pPager) ){
+    if( iGuess<=pagerPagecount(pBt) ){
       rc = ptrmapGet(pBt, iGuess, &eType, &pgno);
       if( rc!=SQLITE_OK ){
         return rc;
@@ -36217,8 +37087,8 @@ static int copyPayload(
 */
 static int accessPayload(
   BtCursor *pCur,      /* Cursor pointing to entry to read from */
-  int offset,          /* Begin reading this far into payload */
-  int amt,             /* Read this many bytes */
+  u32 offset,          /* Begin reading this far into payload */
+  u32 amt,             /* Read this many bytes */
   unsigned char *pBuf, /* Write the bytes into this buffer */ 
   int skipKey,         /* offset begins at data if this is true */
   int eOp              /* zero to read. non-zero to write. */
@@ -36228,12 +37098,11 @@ static int accessPayload(
   u32 nKey;
   int iIdx = 0;
   MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
-  BtShared *pBt;                              /* Btree this cursor belongs to */
+  BtShared *pBt = pCur->pBt;                  /* Btree this cursor belongs to */
 
   assert( pPage );
   assert( pCur->eState==CURSOR_VALID );
   assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
-  assert( offset>=0 );
   assert( cursorHoldsMutex(pCur) );
 
   getCellInfo(pCur);
@@ -36243,7 +37112,9 @@ static int accessPayload(
   if( skipKey ){
     offset += nKey;
   }
-  if( offset+amt > nKey+pCur->info.nData ){
+  if( offset+amt > nKey+pCur->info.nData 
+   || &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
+  ){
     /* Trying to read or write past the end of the data is an error */
     return SQLITE_CORRUPT_BKPT;
   }
@@ -36262,9 +37133,8 @@ static int accessPayload(
     offset -= pCur->info.nLocal;
   }
 
-  pBt = pCur->pBt;
   if( rc==SQLITE_OK && amt>0 ){
-    const int ovflSize = pBt->usableSize - 4;  /* Bytes content per ovfl page */
+    const u32 ovflSize = pBt->usableSize - 4;  /* Bytes content per ovfl page */
     Pgno nextPage;
 
     nextPage = get4byte(&aPayload[pCur->info.nLocal]);
@@ -36431,7 +37301,7 @@ static const unsigned char *fetchPayload(
   unsigned char *aPayload;
   MemPage *pPage;
   u32 nKey;
-  int nLocal;
+  u32 nLocal;
 
   assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
   assert( pCur->eState==CURSOR_VALID );
@@ -37121,7 +37991,7 @@ static int allocateBtreePage(
     ** the entire-list will be searched for that page.
     */
 #ifndef SQLITE_OMIT_AUTOVACUUM
-    if( exact && nearby<=pagerPagecount(pBt->pPager) ){
+    if( exact && nearby<=pagerPagecount(pBt) ){
       u8 eType;
       assert( nearby>0 );
       assert( pBt->autoVacuum );
@@ -37256,9 +38126,9 @@ static int allocateBtreePage(
 
         iPage = get4byte(&aData[8+closest*4]);
         if( !searchList || iPage==nearby ){
-          int nPage;
+          Pgno nPage;
           *pPgno = iPage;
-          nPage = pagerPagecount(pBt->pPager);
+          nPage = pagerPagecount(pBt);
           if( *pPgno>nPage ){
             /* Free page off the end of the file */
             rc = SQLITE_CORRUPT_BKPT;
@@ -37288,7 +38158,7 @@ static int allocateBtreePage(
   }else{
     /* There are no pages on the freelist, so create a new page at the
     ** end of the file */
-    int nPage = pagerPagecount(pBt->pPager);
+    int nPage = pagerPagecount(pBt);
     *pPgno = nPage + 1;
 
 #ifndef SQLITE_OMIT_AUTOVACUUM
@@ -37455,7 +38325,7 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
   assert( ovflPgno==0 || nOvfl>0 );
   while( nOvfl-- ){
     MemPage *pOvfl;
-    if( ovflPgno==0 || ovflPgno>pagerPagecount(pBt->pPager) ){
+    if( ovflPgno==0 || ovflPgno>pagerPagecount(pBt) ){
       return SQLITE_CORRUPT_BKPT;
     }
 
@@ -37517,7 +38387,7 @@ static int fillInCell(
   sqlite3BtreeParseCellPtr(pPage, pCell, &info);
   assert( info.nHeader==nHeader );
   assert( info.nKey==nKey );
-  assert( info.nData==nData+nZero );
+  assert( info.nData==(u32)(nData+nZero) );
   
   /* Fill in the payload */
   nPayload = nData + nZero;
@@ -37619,6 +38489,7 @@ static int dropCell(MemPage *pPage, int idx, int sz){
   int pc;         /* Offset to cell content of cell being deleted */
   u8 *data;       /* pPage->aData */
   u8 *ptr;        /* Used to move bytes around within data[] */
+  int rc;         /* The return code */
 
   assert( idx>=0 && idx<pPage->nCell );
   assert( sz==cellSize(pPage, idx) );
@@ -37627,10 +38498,13 @@ static int dropCell(MemPage *pPage, int idx, int sz){
   data = pPage->aData;
   ptr = &data[pPage->cellOffset + 2*idx];
   pc = get2byte(ptr);
-  if ( pc<=10 || pc+sz>pPage->pBt->usableSize ) {
+  if ( (pc<pPage->hdrOffset+6+(pPage->leaf?0:4)) || (pc+sz>pPage->pBt->usableSize) ) {
     return SQLITE_CORRUPT_BKPT;
   }
-  freeSpace(pPage, pc, sz);
+  rc = freeSpace(pPage, pc, sz);
+  if( rc!=SQLITE_OK ){
+    return rc;
+  }
   for(i=idx+1; i<pPage->nCell; i++, ptr+=2){
     ptr[0] = ptr[2];
     ptr[1] = ptr[3];
@@ -37685,7 +38559,7 @@ static int insertCell(
       pCell = pTemp;
     }
     j = pPage->nOverflow++;
-    assert( j<sizeof(pPage->aOvfl)/sizeof(pPage->aOvfl[0]) );
+    assert( j<(int)(sizeof(pPage->aOvfl)/sizeof(pPage->aOvfl[0])) );
     pPage->aOvfl[j].pCell = pCell;
     pPage->aOvfl[j].idx = i;
     pPage->nFree = 0;
@@ -38572,7 +39446,7 @@ static int balance_shallower(BtCursor *pCur){
     VVA_ONLY( pCur->pagesShuffled = 1 );
     pgnoChild = get4byte(&pPage->aData[pPage->hdrOffset+8]);
     assert( pgnoChild>0 );
-    assert( pgnoChild<=pagerPagecount(pPage->pBt->pPager) );
+    assert( pgnoChild<=pagerPagecount(pPage->pBt) );
     rc = sqlite3BtreeGetPage(pPage->pBt, pgnoChild, &pChild, 0);
     if( rc ) goto end_shallow_balance;
     if( pPage->pgno==1 ){
@@ -38660,7 +39534,8 @@ static int balance_deeper(BtCursor *pCur){
   cdata = pChild->aData;
   memcpy(cdata, &data[hdr], pPage->cellOffset+2*pPage->nCell-hdr);
   memcpy(&cdata[cbrk], &data[cbrk], usableSize-cbrk);
-  
+
+  assert( pChild->isInit==0 );
   rc = sqlite3BtreeInitPage(pChild);
   if( rc==SQLITE_OK ){
     int nCopy = pPage->nOverflow*sizeof(pPage->aOvfl[0]);
@@ -39090,8 +39965,10 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
   }else{
     TRACE(("DELETE: table=%d delete from leaf %d\n",
        pCur->pgnoRoot, pPage->pgno));
-    dropCell(pPage, idx, cellSizePtr(pPage, pCell));
-    rc = balance(pCur, 0);
+    rc = dropCell(pPage, idx, cellSizePtr(pPage, pCell));
+    if( rc==SQLITE_OK ){
+      rc = balance(pCur, 0);
+    }
   }
   if( rc==SQLITE_OK ){
     moveToRoot(pCur);
@@ -39257,7 +40134,6 @@ SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
 static int clearDatabasePage(
   BtShared *pBt,           /* The BTree that contains the table */
   Pgno pgno,            /* Page number to clear */
-  MemPage *pParent,     /* Parent page.  NULL for the root */
   int freePageFlag,     /* Deallocate page if true */
   int *pnChange
 ){
@@ -39267,7 +40143,7 @@ static int clearDatabasePage(
   int i;
 
   assert( sqlite3_mutex_held(pBt->mutex) );
-  if( pgno>pagerPagecount(pBt->pPager) ){
+  if( pgno>pagerPagecount(pBt) ){
     return SQLITE_CORRUPT_BKPT;
   }
 
@@ -39276,14 +40152,14 @@ static int clearDatabasePage(
   for(i=0; i<pPage->nCell; i++){
     pCell = findCell(pPage, i);
     if( !pPage->leaf ){
-      rc = clearDatabasePage(pBt, get4byte(pCell), pPage, 1, pnChange);
+      rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange);
       if( rc ) goto cleardatabasepage_out;
     }
     rc = clearCell(pPage, pCell);
     if( rc ) goto cleardatabasepage_out;
   }
   if( !pPage->leaf ){
-    rc = clearDatabasePage(pBt, get4byte(&pPage->aData[8]), pPage, 1, pnChange);
+    rc = clearDatabasePage(pBt, get4byte(&pPage->aData[8]), 1, pnChange);
     if( rc ) goto cleardatabasepage_out;
   }else if( pnChange ){
     assert( pPage->intKey );
@@ -39325,7 +40201,7 @@ SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
   }else if( SQLITE_OK!=(rc = saveAllCursors(pBt, iTable, 0)) ){
     /* nothing to do */
   }else{
-    rc = clearDatabasePage(pBt, (Pgno)iTable, 0, 0, pnChange);
+    rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
   }
   sqlite3BtreeLeave(p);
   return rc;
@@ -39351,7 +40227,7 @@ SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
 ** The last root page is recorded in meta[3] and the value of
 ** meta[3] is updated by this procedure.
 */
-static int btreeDropTable(Btree *p, int iTable, int *piMoved){
+static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
   int rc;
   MemPage *pPage = 0;
   BtShared *pBt = p->pBt;
@@ -39634,9 +40510,9 @@ static void checkAppendMsg(
 **
 ** Also check that the page number is in bounds.
 */
-static int checkRef(IntegrityCk *pCheck, int iPage, char *zContext){
+static int checkRef(IntegrityCk *pCheck, Pgno iPage, char *zContext){
   if( iPage==0 ) return 1;
-  if( iPage>pCheck->nPage || iPage<0 ){
+  if( iPage>pCheck->nPage ){
     checkAppendMsg(pCheck, zContext, "invalid page number %d", iPage);
     return 1;
   }
@@ -39771,7 +40647,6 @@ static void checkList(
 static int checkTreePage(
   IntegrityCk *pCheck,  /* Context for the sanity check */
   int iPage,            /* Page number of the page to check */
-  MemPage *pParent,     /* Parent page */
   char *zParentContext  /* Parent context */
 ){
   MemPage *pPage;
@@ -39809,7 +40684,7 @@ static int checkTreePage(
   depth = 0;
   for(i=0; i<pPage->nCell && pCheck->mxErr; i++){
     u8 *pCell;
-    int sz;
+    u32 sz;
     CellInfo info;
 
     /* Check payload overflow pages
@@ -39841,7 +40716,7 @@ static int checkTreePage(
         checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, zContext);
       }
 #endif
-      d2 = checkTreePage(pCheck,pgno,pPage,zContext);
+      d2 = checkTreePage(pCheck, pgno, zContext);
       if( i>0 && d2!=depth ){
         checkAppendMsg(pCheck, zContext, "Child page depth differs");
       }
@@ -39857,7 +40732,7 @@ static int checkTreePage(
       checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, 0);
     }
 #endif
-    checkTreePage(pCheck, pgno, pPage, zContext);
+    checkTreePage(pCheck, pgno, zContext);
   }
  
   /* Check for complete coverage of the page
@@ -39945,7 +40820,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
   int mxErr,    /* Stop reporting errors after this many */
   int *pnErr    /* Write number of errors seen to this variable */
 ){
-  int i;
+  Pgno i;
   int nRef;
   IntegrityCk sCheck;
   BtShared *pBt = p->pBt;
@@ -39961,7 +40836,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
   }
   sCheck.pBt = pBt;
   sCheck.pPager = pBt->pPager;
-  sCheck.nPage = pagerPagecount(sCheck.pPager);
+  sCheck.nPage = pagerPagecount(sCheck.pBt);
   sCheck.mxErr = mxErr;
   sCheck.nErr = 0;
   sCheck.mallocFailed = 0;
@@ -39997,14 +40872,14 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
 
   /* Check all the tables.
   */
-  for(i=0; i<nRoot && sCheck.mxErr; i++){
+  for(i=0; (int)i<nRoot && sCheck.mxErr; i++){
     if( aRoot[i]==0 ) continue;
 #ifndef SQLITE_OMIT_AUTOVACUUM
     if( pBt->autoVacuum && aRoot[i]>1 ){
       checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0, 0);
     }
 #endif
-    checkTreePage(&sCheck, aRoot[i], 0, "List of tree roots: ");
+    checkTreePage(&sCheck, aRoot[i], "List of tree roots: ");
   }
 
   /* Make sure every page in the file is referenced
@@ -40128,8 +41003,8 @@ static int btreeCopyFile(Btree *pTo, Btree *pFrom){
     return SQLITE_BUSY;
   }
 
-  nToPage = pagerPagecount(pBtTo->pPager);
-  nFromPage = pagerPagecount(pBtFrom->pPager);
+  nToPage = pagerPagecount(pBtTo);
+  nFromPage = pagerPagecount(pBtFrom);
   iSkip = PENDING_BYTE_PAGE(pBtTo);
 
   /* Variable nNewPage is the number of pages required to store the
@@ -40487,9 +41362,9 @@ SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *pCur){
 */
 #define FIFOSIZE_FIRST (((128-sizeof(FifoPage))/8)+1)
 #ifdef SQLITE_MALLOC_SOFT_LIMIT
-# define FIFOSIZE_MAX   (((SQLITE_MALLOC_SOFT_LIMIT-sizeof(FifoPage))/8)+1)
+# define FIFOSIZE_MAX   (int)(((SQLITE_MALLOC_SOFT_LIMIT-sizeof(FifoPage))/8)+1)
 #else
-# define FIFOSIZE_MAX   (((262144-sizeof(FifoPage))/8)+1)
+# define FIFOSIZE_MAX   (int)(((262144-sizeof(FifoPage))/8)+1)
 #endif
 
 /*
@@ -41740,21 +42615,23 @@ SQLITE_PRIVATE void sqlite3VdbeTrace(Vdbe *p, FILE *trace){
 #endif
 
 /*
-** Resize the Vdbe.aOp array so that it contains at least N
-** elements.
+** Resize the Vdbe.aOp array so that it is at least one op larger than 
+** it was.
 **
-** If an out-of-memory error occurs while resizing the array,
-** Vdbe.aOp and Vdbe.nOpAlloc remain unchanged (this is so that
-** any opcodes already allocated can be correctly deallocated
-** along with the rest of the Vdbe).
+** If an out-of-memory error occurs while resizing the array, return
+** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain 
+** unchanged (this is so that any opcodes already allocated can be 
+** correctly deallocated along with the rest of the Vdbe).
 */
-static void resizeOpArray(Vdbe *p, int N){
+static int growOpArray(Vdbe *p){
   VdbeOp *pNew;
-  pNew = sqlite3DbRealloc(p->db, p->aOp, N*sizeof(Op));
+  int nNew = (p->nOpAlloc ? p->nOpAlloc*2 : (int)(1024/sizeof(Op)));
+  pNew = sqlite3DbRealloc(p->db, p->aOp, nNew*sizeof(Op));
   if( pNew ){
-    p->nOpAlloc = N;
+    p->nOpAlloc = nNew;
     p->aOp = pNew;
   }
+  return (pNew ? SQLITE_OK : SQLITE_NOMEM);
 }
 
 /*
@@ -41780,8 +42657,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
   i = p->nOp;
   assert( p->magic==VDBE_MAGIC_INIT );
   if( p->nOpAlloc<=i ){
-    resizeOpArray(p, p->nOpAlloc ? p->nOpAlloc*2 : 1024/sizeof(Op));
-    if( p->db->mallocFailed ){
+    if( growOpArray(p) ){
       return 0;
     }
   }
@@ -41982,11 +42858,7 @@ SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){
 SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
   int addr;
   assert( p->magic==VDBE_MAGIC_INIT );
-  if( p->nOp + nOp > p->nOpAlloc ){
-    resizeOpArray(p, p->nOpAlloc ? p->nOpAlloc*2 : 1024/sizeof(Op));
-    assert( p->nOp+nOp<=p->nOpAlloc || p->db->mallocFailed );
-  }
-  if( p->db->mallocFailed ){
+  if( p->nOp + nOp > p->nOpAlloc && growOpArray(p) ){
     return 0;
   }
   addr = p->nOp;
@@ -42371,7 +43243,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
 SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){
   int mask;
   assert( i>=0 && i<p->db->nDb );
-  assert( i<sizeof(p->btreeMask)*8 );
+  assert( i<(int)sizeof(p->btreeMask)*8 );
   mask = 1<<i;
   if( (p->btreeMask & mask)==0 ){
     p->btreeMask |= mask;
@@ -42657,11 +43529,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
   */
   assert( p->nOp>0 );
 
-  /* Set the magic to VDBE_MAGIC_RUN sooner rather than later. This
-   * is because the call to resizeOpArray() below may shrink the
-   * p->aOp[] array to save memory if called when in VDBE_MAGIC_RUN 
-   * state.
-   */
+  /* Set the magic to VDBE_MAGIC_RUN sooner rather than later. */
   p->magic = VDBE_MAGIC_RUN;
 
   /* For each cursor required, also allocate a memory cell. Memory
@@ -42681,7 +43549,6 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
   if( p->aMem==0 ){
     int nArg;       /* Maximum number of args passed to a user function. */
     resolveP2Values(p, &nArg);
-    /*resizeOpArray(p, p->nOp);*/
     assert( nVar>=0 );
     if( isExplain && nMem<10 ){
       nMem = 10;
@@ -43225,7 +44092,10 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
     ** Note: This block also runs if one of the special errors handled 
     ** above has occurred. 
     */
-    if( db->autoCommit && db->writeVdbeCnt==(p->readOnly==0) ){
+    if( !sqlite3VtabInSync(db) 
+     && db->autoCommit 
+     && db->writeVdbeCnt==(p->readOnly==0) 
+    ){
       if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
         /* The auto-commit flag is true, and the vdbe program was 
         ** successful or hit an 'OR FAIL' constraint. This means a commit 
@@ -43852,8 +44722,8 @@ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeRecordUnpack(
 ){
   const unsigned char *aKey = (const unsigned char *)pKey;
   UnpackedRecord *p;
-  int nByte;
-  int idx, d;
+  int nByte, d;
+  u32 idx;
   u16 u;                 /* Unsigned loop counter */
   u32 szHdr;
   Mem *pMem;
@@ -43877,7 +44747,7 @@ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeRecordUnpack(
   while( idx<szHdr && u<p->nField ){
     u32 serial_type;
 
-    idx += getVarint32( aKey+idx, serial_type);
+    idx += getVarint32(&aKey[idx], serial_type);
     if( d>=nKey && sqlite3VdbeSerialTypeLen(serial_type)>0 ) break;
     pMem->enc = pKeyInfo->enc;
     pMem->db = pKeyInfo->db;
@@ -43942,7 +44812,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
   int nKey1, const void *pKey1, /* Left key */
   UnpackedRecord *pPKey2        /* Right key */
 ){
-  u32 d1;            /* Offset into aKey[] of next data element */
+  int d1;            /* Offset into aKey[] of next data element */
   u32 idx1;          /* Offset into aKey[] of next header element */
   u32 szHdr1;        /* Number of bytes in header */
   int i = 0;
@@ -44731,11 +45601,12 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
 */
 SQLITE_PRIVATE void sqlite3InvalidFunction(
   sqlite3_context *context,  /* The function calling context */
-  int argc,                  /* Number of arguments to the function */
-  sqlite3_value **argv       /* Value of each argument */
+  int NotUsed,               /* Number of arguments to the function */
+  sqlite3_value **NotUsed2   /* Value of each argument */
 ){
   const char *zName = context->pFunc->zName;
   char *zErr;
+  UNUSED_PARAMETER2(NotUsed, NotUsed2);
   zErr = sqlite3MPrintf(0,
       "unable to use function %s in the requested context", zName);
   sqlite3_result_error(context, zErr, -1);
@@ -45615,7 +46486,7 @@ static const unsigned char opcodeProperty[] = OPFLG_INITIALIZER;
 ** specified by mask.
 */
 SQLITE_PRIVATE int sqlite3VdbeOpcodeHasProperty(int opcode, int mask){
-  assert( opcode>0 && opcode<sizeof(opcodeProperty) );
+  assert( opcode>0 && opcode<(int)sizeof(opcodeProperty) );
   return (opcodeProperty[opcode]&mask)!=0;
 }
 
@@ -46081,7 +46952,6 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
 #endif
   UnpackedRecord aTempRec[16]; /* Space to hold a transient UnpackedRecord */
 
-
   assert( p->magic==VDBE_MAGIC_RUN );  /* sqlite3_step() verifies this */
   assert( db->magic==SQLITE_MAGIC_BUSY );
   sqlite3BtreeMutexArrayEnter(&p->aMutex);
@@ -47493,7 +48363,7 @@ case OP_SetNumColumns: {
 ** the result.
 */
 case OP_Column: {
-  u32 payloadSize;   /* Number of bytes in the record */
+  int payloadSize;   /* Number of bytes in the record */
   int p1 = pOp->p1;  /* P1 value of the opcode */
   int p2 = pOp->p2;  /* column number to retrieve */
   VdbeCursor *pC = 0;/* The VDBE cursor */
@@ -47501,7 +48371,7 @@ case OP_Column: {
   BtCursor *pCrsr;   /* The BTree cursor */
   u32 *aType;        /* aType[i] holds the numeric type of the i-th column */
   u32 *aOffset;      /* aOffset[i] is offset to start of data for i-th column */
-  u32 nField;        /* number of fields in the record */
+  int nField;        /* number of fields in the record */
   int len;           /* The length of the serialized data for the column */
   int i;             /* Loop counter */
   char *zData;       /* Part of the record being decoded */
@@ -47549,7 +48419,7 @@ case OP_Column: {
       sqlite3BtreeKeySize(pCrsr, &payloadSize64);
       payloadSize = payloadSize64;
     }else{
-      sqlite3BtreeDataSize(pCrsr, &payloadSize);
+      sqlite3BtreeDataSize(pCrsr, (u32 *)&payloadSize);
     }
     nField = pC->nField;
   }else{
@@ -47583,7 +48453,7 @@ case OP_Column: {
   }else{
     u8 *zIdx;        /* Index into header */
     u8 *zEndHdr;     /* Pointer to first byte after the header */
-    u32 offset;      /* Offset into the data */
+    int offset;      /* Offset into the data */
     int szHdrSz;     /* Size of the header size field at start of record */
     int avail;       /* Number of bytes of available data */
 
@@ -47784,7 +48654,7 @@ case OP_MakeRecord: {
   Mem *pRec;             /* The new record */
   u64 nData = 0;         /* Number of bytes of data space */
   int nHdr = 0;          /* Number of bytes of header space */
-  u64 nByte = 0;         /* Data space required for this record */
+  i64 nByte = 0;         /* Data space required for this record */
   int nZero = 0;         /* Number of zero bytes at the end of the record */
   int nVarint;           /* Number of bytes in a varint */
   u32 serial_type;       /* Type field */
@@ -48227,7 +49097,10 @@ case OP_OpenWrite: {
     pIn2 = &p->aMem[p2];
     sqlite3VdbeMemIntegerify(pIn2);
     p2 = pIn2->u.i;
-    assert( p2>=2 );
+    if( p2<2 ) {
+      rc = SQLITE_CORRUPT_BKPT;
+      goto abort_due_to_error;
+    }
   }
   assert( i>=0 );
   pCur = allocateCursor(p, i, &pOp[-1], iDb, 1);
@@ -48854,7 +49727,7 @@ case OP_NewRowid: {           /* out2-prerelease */
     ** Others complain about 0x7ffffffffffffffffLL.  The following macro seems
     ** to provide the constant while making all compilers happy.
     */
-#   define MAX_ROWID  ( (((u64)0x7fffffff)<<32) | (u64)0xffffffff )
+#   define MAX_ROWID  (i64)( (((u64)0x7fffffff)<<32) | (u64)0xffffffff )
 #endif
 
     if( !pC->useRandomRowid ){
@@ -49160,7 +50033,7 @@ case OP_RowData: {
     n = n64;
   }else{
     sqlite3BtreeDataSize(pCrsr, &n);
-    if( n>db->aLimit[SQLITE_LIMIT_LENGTH] ){
+    if( (int)n>db->aLimit[SQLITE_LIMIT_LENGTH] ){
       goto too_big;
     }
   }
@@ -51382,6 +52255,7 @@ static int memjrnlWrite(
   ** access writes are not required by sqlite.
   */
   assert(iOfst==p->endpoint.iOffset);
+  UNUSED_PARAMETER(iOfst);
 
   while( nWrite>0 ){
     FileChunk *pChunk = p->endpoint.pChunk;
@@ -51421,6 +52295,7 @@ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
   MemJournal *p = (MemJournal *)pJfd;
   FileChunk *pChunk;
   assert(size==0);
+  UNUSED_PARAMETER(size);
   pChunk = p->pFirst;
   while( pChunk ){
     FileChunk *pTmp = pChunk;
@@ -51443,7 +52318,8 @@ static int memjrnlClose(sqlite3_file *pJfd){
 /*
 ** Sync the file.
 */
-static int memjrnlSync(sqlite3_file *pJfd, int flags){
+static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){
+  UNUSED_PARAMETER2(NotUsed, NotUsed2);
   return SQLITE_OK;
 }
 
@@ -51984,9 +52860,9 @@ static int lookupName(
   */
   if( pExpr->iColumn>=0 && pMatch!=0 ){
     int n = pExpr->iColumn;
-    testcase( n==sizeof(Bitmask)*8-1 );
-    if( n>=sizeof(Bitmask)*8 ){
-      n = sizeof(Bitmask)*8-1;
+    testcase( n==BMS-1 );
+    if( n>=BMS ){
+      n = BMS-1;
     }
     assert( pMatch->iCursor==pExpr->iTable );
     pMatch->colUsed |= ((Bitmask)1)<<n;
@@ -53744,7 +54620,8 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
       return WRC_Continue;
   }
 }
-static int selectNodeIsConstant(Walker *pWalker, Select *pSelect){
+static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){
+  UNUSED_PARAMETER(NotUsed);
   pWalker->u.i = 0;
   return WRC_Abort;
 }
@@ -54264,10 +55141,11 @@ static char *dup8bytes(Vdbe *v, const char *in){
 */
 static void codeReal(Vdbe *v, const char *z, int n, int negateFlag, int iMem){
   assert( z || v==0 || sqlite3VdbeDb(v)->mallocFailed );
+  assert( !z || !isdigit(z[n]) );
+  UNUSED_PARAMETER(n);
   if( z ){
     double value;
     char *zV;
-    assert( !isdigit(z[n]) );
     sqlite3AtoF(z, &value);
     if( sqlite3IsNaN(value) ){
       sqlite3VdbeAddOp2(v, OP_Null, 0, iMem);
@@ -55944,7 +56822,7 @@ SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
 */
 static void renameTableFunc(
   sqlite3_context *context,
-  int argc,
+  int NotUsed,
   sqlite3_value **argv
 ){
   unsigned char const *zSql = sqlite3_value_text(argv[0]);
@@ -55958,6 +56836,8 @@ static void renameTableFunc(
 
   sqlite3 *db = sqlite3_context_db_handle(context);
 
+  UNUSED_PARAMETER(NotUsed);
+
   /* The principle used to locate the table name in the CREATE TABLE 
   ** statement is that the table name is the first non-space token that
   ** is immediately followed by a TK_LP or TK_USING token.
@@ -55999,7 +56879,7 @@ static void renameTableFunc(
 */
 static void renameTriggerFunc(
   sqlite3_context *context,
-  int argc,
+  int NotUsed,
   sqlite3_value **argv
 ){
   unsigned char const *zSql = sqlite3_value_text(argv[0]);
@@ -56011,9 +56891,10 @@ static void renameTriggerFunc(
   unsigned char const *zCsr = zSql;
   int len = 0;
   char *zRet;
-
   sqlite3 *db = sqlite3_context_db_handle(context);
 
+  UNUSED_PARAMETER(NotUsed);
+
   /* The principle used to locate the table name in the CREATE TRIGGER 
   ** statement is that the table name is the first token that is immediatedly
   ** preceded by either TK_ON or TK_DOT and immediatedly followed by one
@@ -56884,7 +57765,7 @@ struct analysisInfo {
 **     argv[0] = name of the index
 **     argv[1] = results of analysis - on integer for each column
 */
-static int analysisLoader(void *pData, int argc, char **argv, char **azNotUsed){
+static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
   analysisInfo *pInfo = (analysisInfo*)pData;
   Index *pIndex;
   int i, c;
@@ -56892,6 +57773,8 @@ static int analysisLoader(void *pData, int argc, char **argv, char **azNotUsed){
   const char *z;
 
   assert( argc==2 );
+  UNUSED_PARAMETER2(NotUsed, argc);
+
   if( argv==0 || argv[0]==0 || argv[1]==0 ){
     return 0;
   }
@@ -57019,7 +57902,7 @@ static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
 */
 static void attachFunc(
   sqlite3_context *context,
-  int argc,
+  int NotUsed,
   sqlite3_value **argv
 ){
   int i;
@@ -57031,6 +57914,8 @@ static void attachFunc(
   char *zErrDyn = 0;
   char zErr[128];
 
+  UNUSED_PARAMETER(NotUsed);
+
   zFile = (const char *)sqlite3_value_text(argv[0]);
   zName = (const char *)sqlite3_value_text(argv[1]);
   if( zFile==0 ) zFile = "";
@@ -57187,7 +58072,7 @@ attach_error:
 */
 static void detachFunc(
   sqlite3_context *context,
-  int argc,
+  int NotUsed,
   sqlite3_value **argv
 ){
   const char *zName = (const char *)sqlite3_value_text(argv[0]);
@@ -57196,6 +58081,8 @@ static void detachFunc(
   Db *pDb = 0;
   char zErr[128];
 
+  UNUSED_PARAMETER(NotUsed);
+
   if( zName==0 ) zName = "";
   for(i=0; i<db->nDb; i++){
     pDb = &db->aDb[i];
@@ -58352,7 +59239,7 @@ SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *p, int iDb){
 */
 SQLITE_PRIVATE int sqlite3FindDb(sqlite3 *db, Token *pName){
   int i = -1;    /* Database number */
-  int n;         /* Number of characters in the name */
+  size_t n;      /* Number of characters in the name */
   Db *pDb;       /* A database whose name space is being searched */
   char *zName;   /* Name we are searching for */
 
@@ -58396,7 +59283,11 @@ SQLITE_PRIVATE int sqlite3TwoPartName(
   sqlite3 *db = pParse->db;
 
   if( pName2 && pName2->n>0 ){
-    assert( !db->init.busy );
+    if( db->init.busy ) {
+      sqlite3ErrorMsg(pParse, "corrupt database");
+      pParse->nErr++;
+      return -1;
+    }
     *pUnqual = pName2;
     iDb = sqlite3FindDb(db, pName1);
     if( iDb<0 ){
@@ -59118,7 +60009,7 @@ static char *createTableStmt(sqlite3 *db, Table *p, int isTemp){
     identPut(zStmt, &k, pCol->zName);
     if( (z = pCol->zType)!=0 ){
       zStmt[k++] = ' ';
-      assert( strlen(z)+k+1<=n );
+      assert( (int)(strlen(z)+k+1)<=n );
       sqlite3_snprintf(n-k, &zStmt[k], "%s", z);
       k += strlen(z);
     }
@@ -62022,7 +62913,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
   ** deleted from is a view
   */
 #ifndef SQLITE_OMIT_TRIGGER
-  triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0);
+  triggers_exist = sqlite3TriggersExist(pTab, TK_DELETE, 0);
   isView = pTab->pSelect!=0;
 #else
 # define triggers_exist 0
@@ -62455,10 +63346,11 @@ static void minmaxFunc(
 */
 static void typeofFunc(
   sqlite3_context *context,
-  int argc,
+  int NotUsed,
   sqlite3_value **argv
 ){
   const char *z = 0;
+  UNUSED_PARAMETER(NotUsed);
   switch( sqlite3_value_type(argv[0]) ){
     case SQLITE_NULL:    z = "null";    break;
     case SQLITE_INTEGER: z = "integer"; break;
@@ -62481,6 +63373,7 @@ static void lengthFunc(
   int len;
 
   assert( argc==1 );
+  UNUSED_PARAMETER(argc);
   switch( sqlite3_value_type(argv[0]) ){
     case SQLITE_BLOB:
     case SQLITE_INTEGER:
@@ -62511,6 +63404,7 @@ static void lengthFunc(
 */
 static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
   assert( argc==1 );
+  UNUSED_PARAMETER(argc);
   switch( sqlite3_value_type(argv[0]) ){
     case SQLITE_INTEGER: {
       i64 iVal = sqlite3_value_int64(argv[0]);
@@ -62714,10 +63608,11 @@ static void ifnullFunc(
 */
 static void randomFunc(
   sqlite3_context *context,
-  int argc,
-  sqlite3_value **argv
+  int NotUsed,
+  sqlite3_value **NotUsed2
 ){
   sqlite_int64 r;
+  UNUSED_PARAMETER2(NotUsed, NotUsed2);
   sqlite3_randomness(sizeof(r), &r);
   if( (r<<1)==0 ) r = 0;  /* Prevent 0x8000.... as the result so that we */
                           /* can always do abs() of the result */
@@ -62736,6 +63631,7 @@ static void randomBlob(
   int n;
   unsigned char *p;
   assert( argc==1 );
+  UNUSED_PARAMETER(argc);
   n = sqlite3_value_int(argv[0]);
   if( n<1 ){
     n = 1;
@@ -62753,10 +63649,11 @@ static void randomBlob(
 */
 static void last_insert_rowid(
   sqlite3_context *context, 
-  int arg
-  sqlite3_value **argv
+  int NotUsed
+  sqlite3_value **NotUsed2
 ){
   sqlite3 *db = sqlite3_context_db_handle(context);
+  UNUSED_PARAMETER2(NotUsed, NotUsed2);
   sqlite3_result_int64(context, sqlite3_last_insert_rowid(db));
 }
 
@@ -62766,10 +63663,11 @@ static void last_insert_rowid(
 */
 static void changes(
   sqlite3_context *context,
-  int arg,
-  sqlite3_value **argv
+  int NotUsed,
+  sqlite3_value **NotUsed2
 ){
   sqlite3 *db = sqlite3_context_db_handle(context);
+  UNUSED_PARAMETER2(NotUsed, NotUsed2);
   sqlite3_result_int(context, sqlite3_changes(db));
 }
 
@@ -62779,10 +63677,11 @@ static void changes(
 */
 static void total_changes(
   sqlite3_context *context,
-  int arg,
-  sqlite3_value **argv
+  int NotUsed,
+  sqlite3_value **NotUsed2
 ){
   sqlite3 *db = sqlite3_context_db_handle(context);
+  UNUSED_PARAMETER2(NotUsed, NotUsed2);
   sqlite3_result_int(context, sqlite3_total_changes(db));
 }
 
@@ -63027,10 +63926,11 @@ static void likeFunc(
 */
 static void nullifFunc(
   sqlite3_context *context,
-  int argc,
+  int NotUsed,
   sqlite3_value **argv
 ){
   CollSeq *pColl = sqlite3GetFuncCollSeq(context);
+  UNUSED_PARAMETER(NotUsed);
   if( sqlite3MemCompare(argv[0], argv[1], pColl)!=0 ){
     sqlite3_result_value(context, argv[0]);
   }
@@ -63042,9 +63942,10 @@ static void nullifFunc(
 */
 static void versionFunc(
   sqlite3_context *context,
-  int argc,
-  sqlite3_value **argv
+  int NotUsed,
+  sqlite3_value **NotUsed2
 ){
+  UNUSED_PARAMETER2(NotUsed, NotUsed2);
   sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
 }
 
@@ -63137,6 +64038,7 @@ static void hexFunc(
   const unsigned char *pBlob;
   char *zHex, *z;
   assert( argc==1 );
+  UNUSED_PARAMETER(argc);
   pBlob = sqlite3_value_blob(argv[0]);
   n = sqlite3_value_bytes(argv[0]);
   assert( pBlob==sqlite3_value_blob(argv[0]) );  /* No encoding change */
@@ -63162,6 +64064,7 @@ static void zeroblobFunc(
 ){
   i64 n;
   assert( argc==1 );
+  UNUSED_PARAMETER(argc);
   n = sqlite3_value_int64(argv[0]);
   if( n>SQLITE_MAX_LENGTH ){
     sqlite3_result_error_toobig(context);
@@ -63193,6 +64096,7 @@ static void replaceFunc(
   int i, j;                /* Loop counters */
 
   assert( argc==3 );
+  UNUSED_PARAMETER(argc);
   zStr = sqlite3_value_text(argv[0]);
   if( zStr==0 ) return;
   nStr = sqlite3_value_bytes(argv[0]);
@@ -63430,6 +64334,7 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
   SumCtx *p;
   int type;
   assert( argc==1 );
+  UNUSED_PARAMETER(argc);
   p = sqlite3_aggregate_context(context, sizeof(*p));
   type = sqlite3_value_numeric_type(argv[0]);
   if( p && type!=SQLITE_NULL ){
@@ -63505,9 +64410,14 @@ static void countFinalize(sqlite3_context *context){
 /*
 ** Routines to implement min() and max() aggregate functions.
 */
-static void minmaxStep(sqlite3_context *context, int argc, sqlite3_value **argv){
+static void minmaxStep(
+  sqlite3_context *context, 
+  int NotUsed, 
+  sqlite3_value **argv
+){
   Mem *pArg  = (Mem *)argv[0];
   Mem *pBest;
+  UNUSED_PARAMETER(NotUsed);
 
   if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
   pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest));
@@ -64204,7 +65114,7 @@ SQLITE_PRIVATE void sqlite3Insert(
   ** inserted into is a view
   */
 #ifndef SQLITE_OMIT_TRIGGER
-  triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0);
+  triggers_exist = sqlite3TriggersExist(pTab, TK_INSERT, 0);
   isView = pTab->pSelect!=0;
 #else
 # define triggers_exist 0
@@ -64710,7 +65620,6 @@ SQLITE_PRIVATE void sqlite3Insert(
           regIns,
           aRegIdx,
           0,
-          0,
           (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1,
           appendFlag
        );
@@ -65046,26 +65955,26 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
       case OE_Fail: {
         int j, n1, n2;
         char zErrMsg[200];
-        sqlite3_snprintf(sizeof(zErrMsg), zErrMsg,
+        sqlite3_snprintf(ArraySize(zErrMsg), zErrMsg,
                          pIdx->nColumn>1 ? "columns " : "column ");
         n1 = strlen(zErrMsg);
-        for(j=0; j<pIdx->nColumn && n1<sizeof(zErrMsg)-30; j++){
+        for(j=0; j<pIdx->nColumn && n1<ArraySize(zErrMsg)-30; j++){
           char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
           n2 = strlen(zCol);
           if( j>0 ){
-            sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], ", ");
+            sqlite3_snprintf(ArraySize(zErrMsg)-n1, &zErrMsg[n1], ", ");
             n1 += 2;
           }
-          if( n1+n2>sizeof(zErrMsg)-30 ){
-            sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], "...");
+          if( n1+n2>ArraySize(zErrMsg)-30 ){
+            sqlite3_snprintf(ArraySize(zErrMsg)-n1, &zErrMsg[n1], "...");
             n1 += 3;
             break;
           }else{
-            sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], "%s", zCol);
+            sqlite3_snprintf(ArraySize(zErrMsg)-n1, &zErrMsg[n1], "%s", zCol);
             n1 += n2;
           }
         }
-        sqlite3_snprintf(sizeof(zErrMsg)-n1, &zErrMsg[n1], 
+        sqlite3_snprintf(ArraySize(zErrMsg)-n1, &zErrMsg[n1], 
             pIdx->nColumn>1 ? " are not unique" : " is not unique");
         sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, zErrMsg,0);
         break;
@@ -65102,7 +66011,6 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
   int baseCur,        /* Index of a read/write cursor pointing at pTab */
   int regRowid,       /* Range of content */
   int *aRegIdx,       /* Register used by each index.  0 for unused indices */
-  int rowidChng,      /* True if the record number will change */
   int isUpdate,       /* True for UPDATE, False for INSERT */
   int newIdx,         /* Index of NEW table for triggers.  -1 if none */
   int appendBias      /* True if this is likely to be an append */
@@ -66688,7 +67596,7 @@ static int getSafetyLevel(const char *z){
     return atoi(z);
   }
   n = strlen(z);
-  for(i=0; i<sizeof(iLength); i++){
+  for(i=0; i<ArraySize(iLength); i++){
     if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0 ){
       return iValue[i];
     }
@@ -66838,7 +67746,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
   };
   int i;
   const struct sPragmaType *p;
-  for(i=0, p=aPragma; i<sizeof(aPragma)/sizeof(aPragma[0]); i++, p++){
+  for(i=0, p=aPragma; i<ArraySize(aPragma); i++, p++){
     if( sqlite3StrICmp(zLeft, p->zName)==0 ){
       sqlite3 *db = pParse->db;
       Vdbe *v;
@@ -68054,11 +68962,13 @@ static void corruptSchema(
 **     argv[2] = SQL text for the CREATE statement.
 **
 */
-SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
+SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
   InitData *pData = (InitData*)pInit;
   sqlite3 *db = pData->db;
   int iDb = pData->iDb;
 
+  assert( argc==3 );
+  UNUSED_PARAMETER2(NotUsed, argc);
   assert( sqlite3_mutex_held(db->mutex) );
   DbClearProperty(db, iDb, DB_Empty);
   if( db->mallocFailed ){
@@ -68066,7 +68976,6 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
     return SQLITE_NOMEM;
   }
 
-  assert( argc==3 );
   assert( iDb>=0 && iDb<db->nDb );
   if( argv==0 ) return 0;   /* Might happen if EMPTY_RESULT_CALLBACKS are on */
   if( argv[1]==0 ){
@@ -68246,7 +69155,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
   */
   if( rc==SQLITE_OK ){
     int i;
-    for(i=0; i<sizeof(meta)/sizeof(meta[0]); i++){
+    for(i=0; i<ArraySize(meta); i++){
       rc = sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]);
       if( rc ){
         sqlite3SetString(pzErrMsg, db, "%s", sqlite3ErrStr(rc));
@@ -68959,14 +69868,14 @@ SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *p
   apAll[2] = pC;
   for(i=0; i<3 && apAll[i]; i++){
     p = apAll[i];
-    for(j=0; j<sizeof(keywords)/sizeof(keywords[0]); j++){
+    for(j=0; j<ArraySize(keywords); j++){
       if( p->n==keywords[j].nChar 
           && sqlite3StrNICmp((char*)p->z, keywords[j].zKeyword, p->n)==0 ){
         jointype |= keywords[j].code;
         break;
       }
     }
-    if( j>=sizeof(keywords)/sizeof(keywords[0]) ){
+    if( j>=ArraySize(keywords) ){
       jointype |= JT_ERROR;
       break;
     }
@@ -71736,7 +72645,7 @@ static int flattenSubquery(
 **   2. There is a single expression in the result set, and it is
 **      either min(x) or max(x), where x is a column reference.
 */
-static int minMaxQuery(Parse *pParse, Select *p){
+static int minMaxQuery(Select *p){
   Expr *pExpr;
   ExprList *pEList = p->pEList;
 
@@ -72036,7 +72945,8 @@ static int selectExpander(Walker *pWalker, Select *p){
 ** Walker.xSelectCallback is set to do something useful for every 
 ** subquery in the parser tree.
 */
-static int exprWalkNoop(Walker *pWalker, Expr *pExpr){
+static int exprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
+  UNUSED_PARAMETER2(NotUsed, NotUsed2);
   return WRC_Continue;
 }
 
@@ -72827,7 +73737,7 @@ SQLITE_PRIVATE int sqlite3Select(
       **     satisfying the 'ORDER BY' clause than it does in other cases.
       **     Refer to code and comments in where.c for details.
       */
-      flag = minMaxQuery(pParse, p);
+      flag = minMaxQuery(p);
       if( flag ){
         pDel = pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->pList);
         if( pMinMax && !db->mallocFailed ){
@@ -73801,7 +74711,6 @@ static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
 ** TRIGGER_AFTER.
 */
 SQLITE_PRIVATE int sqlite3TriggersExist(
-  Parse *pParse,          /* Used to check for recursive triggers */
   Table *pTab,            /* The table the contains the triggers */
   int op,                 /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
   ExprList *pChanges      /* Columns that change in an UPDATE statement */
@@ -74194,7 +75103,7 @@ SQLITE_PRIVATE void sqlite3Update(
   ** updated is a view
   */
 #ifndef SQLITE_OMIT_TRIGGER
-  triggers_exist = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges);
+  triggers_exist = sqlite3TriggersExist(pTab, TK_UPDATE, pChanges);
   isView = pTab->pSelect!=0;
 #else
 # define triggers_exist 0
@@ -74577,7 +75486,7 @@ SQLITE_PRIVATE void sqlite3Update(
     /* Create the new index entries and the new record.
     */
     sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, 
-                             aRegIdx, chngRowid, 1, -1, 0);
+                             aRegIdx, 1, -1, 0);
   }
 
   /* Increment the row counter 
@@ -74985,7 +75894,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
     assert( 1==sqlite3BtreeIsInTrans(pMain) );
 
     /* Copy Btree meta values */
-    for(i=0; i<sizeof(aCopy)/sizeof(aCopy[0]); i+=2){
+    for(i=0; i<ArraySize(aCopy); i+=2){
       rc = sqlite3BtreeGetMeta(pMain, aCopy[i], &meta);
       if( rc!=SQLITE_OK ) goto end_of_vacuum;
       rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], meta+aCopy[i+1]);
@@ -75082,6 +75991,8 @@ static int createModule(
       db->mallocFailed = 1;
     }
     sqlite3ResetInternalSchema(db, 0);
+  }else if( xDestroy ){
+    xDestroy(pAux);
   }
   rc = sqlite3ApiExit(db, SQLITE_OK);
   sqlite3_mutex_leave(db->mutex);
@@ -75746,7 +76657,7 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
   ** virtual module xSync() callback. It is illegal to write to 
   ** virtual module tables in this case, so return SQLITE_LOCKED.
   */
-  if( 0==db->aVTrans && db->nVTrans>0 ){
+  if( sqlite3VtabInSync(db) ){
     return SQLITE_LOCKED;
   }
   if( !pVtab ){
@@ -75897,11 +76808,6 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
 ** $Id$
 */
 
-/*
-** The number of bits in a Bitmask.  "BMS" means "BitMask Size".
-*/
-#define BMS  (sizeof(Bitmask)*8)
-
 /*
 ** Trace output macros
 */
@@ -76016,7 +76922,7 @@ struct WhereClause {
 */
 struct ExprMaskSet {
   int n;                        /* Number of assigned cursor values */
-  int ix[sizeof(Bitmask)*8];    /* Cursor assigned to each bit */
+  int ix[BMS];                  /* Cursor assigned to each bit */
 };
 
 
@@ -78197,7 +79103,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
     if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){
       int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead;
       sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op);
-      if( !pWInfo->okOnePass && pTab->nCol<(sizeof(Bitmask)*8) ){
+      if( !pWInfo->okOnePass && pTab->nCol<BMS ){
         Bitmask b = pTabItem->colUsed;
         int n = 0;
         for(; b; b=b>>1, n++){}
@@ -80078,6 +80984,8 @@ SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(size_t)){
     pParser->yyidxMax = 0;
 #endif
 #if YYSTACKDEPTH<=0
+    pParser->yystack = NULL;
+    pParser->yystksz = 0;
     yyGrowStack(pParser);
 #endif
   }
@@ -83308,6 +84216,20 @@ SQLITE_API int sqlite3_config(int op, ...){
       break;
     }
 
+    case SQLITE_CONFIG_PCACHE: {
+      /* Specify an alternative malloc implementation */
+      sqlite3GlobalConfig.pcache = *va_arg(ap, sqlite3_pcache_methods*);
+      break;
+    }
+
+    case SQLITE_CONFIG_GETPCACHE: {
+      if( sqlite3GlobalConfig.pcache.xInit==0 ){
+        sqlite3PCacheSetDefault();
+      }
+      *va_arg(ap, sqlite3_pcache_methods*) = sqlite3GlobalConfig.pcache;
+      break;
+    }
+
 #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
     case SQLITE_CONFIG_HEAP: {
       /* Designate a buffer for heap memory space */
@@ -83500,6 +84422,7 @@ static int nocaseCollatingFunc(
 ){
   int r = sqlite3StrNICmp(
       (const char *)pKey1, (const char *)pKey2, (nKey1<nKey2)?nKey1:nKey2);
+  UNUSED_PARAMETER(NotUsed);
   if( 0==r ){
     r = nKey1-nKey2;
   }
@@ -92911,6 +93834,13 @@ SQLITE_PRIVATE void *sqlite3Fts3HashInsert(
     return old_data;
   }
   if( data==0 ) return 0;
+  if( pH->htsize==0 ){
+    fts3Rehash(pH,8);
+    if( pH->htsize==0 ){
+      pH->count = 0;
+      return data;
+    }
+  }
   new_elem = (fts3HashElem*)fts3HashMalloc( sizeof(fts3HashElem) );
   if( new_elem==0 ) return data;
   if( pH->copyKey && pKey!=0 ){
@@ -92925,14 +93855,6 @@ SQLITE_PRIVATE void *sqlite3Fts3HashInsert(
   }
   new_elem->nKey = nKey;
   pH->count++;
-  if( pH->htsize==0 ){
-    fts3Rehash(pH,8);
-    if( pH->htsize==0 ){
-      pH->count = 0;
-      fts3HashFree(new_elem);
-      return data;
-    }
-  }
   if( pH->count > pH->htsize ){
     fts3Rehash(pH,pH->htsize*2);
   }
@@ -97795,7 +98717,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */
 
 /************** End of fts3_icu.c ********************************************/
+
 #if defined(_MSC_VER) && _MSC_VER < 1300
 #pragma optimize("", on)
 #endif
-
index e9ce422f4249704bd44048ce8db0736e896375b1..5b2c55c853b82d0e4e57ef17d41efa33b2581224 100644 (file)
@@ -107,8 +107,8 @@ extern "C" {
 **          with the value (X*1000000 + Y*1000 + Z) where X, Y, and Z
 **          are the major version, minor version, and release number.
 */
-#define SQLITE_VERSION         "3.6.5"
-#define SQLITE_VERSION_NUMBER  3006005
+#define SQLITE_VERSION         "3.6.6"
+#define SQLITE_VERSION_NUMBER  3006006
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers {H10020} <S60100>
@@ -1274,7 +1274,10 @@ struct sqlite3_mem_methods {
 **
 ** <dt>SQLITE_CONFIG_PAGECACHE</dt>
 ** <dd>This option specifies a static memory buffer that SQLite can use for
-** the database page cache.  There are three arguments: A pointer to the
+** the database page cache with the default page cache implemenation.  
+** This configuration should not be used if an application-define page
+** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option.
+** There are three arguments to this option: A pointer to the
 ** memory, the size of each page buffer (sz), and the number of pages (N).
 ** The sz argument must be a power of two between 512 and 32768.  The first
 ** argument should point to an allocation of at least sz*N bytes of memory.
@@ -1319,6 +1322,17 @@ struct sqlite3_mem_methods {
 ** size of each lookaside buffer slot and the second is the number of
 ** slots allocated to each database connection.</dd>
 **
+** <dt>SQLITE_CONFIG_PCACHE</dt>
+** <dd>This option takes a single argument which is a pointer to
+** an [sqlite3_pcache_methods] object.  This object specifies the interface
+** to a custom page cache implementation.  SQLite makes a copy of the
+** object and uses it for page cache memory allocations.</dd>
+**
+** <dt>SQLITE_CONFIG_GETPCACHE</dt>
+** <dd>This option takes a single argument which is a pointer to an
+** [sqlite3_pcache_methods] object.  SQLite copies of the current
+** page cache implementation into that object.</dd>
+**
 ** </dl>
 */
 #define SQLITE_CONFIG_SINGLETHREAD  1  /* nil */
@@ -1334,6 +1348,8 @@ struct sqlite3_mem_methods {
 #define SQLITE_CONFIG_GETMUTEX     11  /* sqlite3_mutex_methods* */
 /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ 
 #define SQLITE_CONFIG_LOOKASIDE    13  /* int int */
+#define SQLITE_CONFIG_PCACHE       14  /* sqlite3_pcache_methods* */
+#define SQLITE_CONFIG_GETPCACHE    15  /* sqlite3_pcache_methods* */
 
 /*
 ** CAPI3REF: Configuration Options {H10170} <S20000>
@@ -6555,6 +6571,149 @@ SQLITE_EXPERIMENTAL int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
 #define SQLITE_STMTSTATUS_FULLSCAN_STEP     1
 #define SQLITE_STMTSTATUS_SORT              2
 
+/*
+** CAPI3REF: Custom Page Cache Object
+** EXPERIMENTAL
+**
+** The sqlite3_pcache type is opaque.  It is implemented by
+** the pluggable module.  The SQLite core has no knowledge of
+** its size or internal structure and never deals with the
+** sqlite3_pcache object except by holding and passing pointers
+** to the object.
+**
+** See [sqlite3_pcache_methods] for additional information.
+*/
+typedef struct sqlite3_pcache sqlite3_pcache;
+
+/*
+** CAPI3REF: Application Defined Page Cache.
+** EXPERIMENTAL
+**
+** The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can
+** register an alternative page cache implementation by passing in an 
+** instance of the sqlite3_pcache_methods structure. The majority of the 
+** heap memory used by sqlite is used by the page cache to cache data read 
+** from, or ready to be written to, the database file. By implementing a 
+** custom page cache using this API, an application can control more 
+** precisely the amount of memory consumed by sqlite, the way in which 
+** said memory is allocated and released, and the policies used to 
+** determine exactly which parts of a database file are cached and for 
+** how long.
+**
+** The contents of the structure are copied to an internal buffer by sqlite
+** within the call to [sqlite3_config].
+**
+** The xInit() method is called once for each call to [sqlite3_initialize()]
+** (usually only once during the lifetime of the process). It is passed
+** a copy of the sqlite3_pcache_methods.pArg value. It can be used to set
+** up global structures and mutexes required by the custom page cache 
+** implementation. The xShutdown() method is called from within 
+** [sqlite3_shutdown()], if the application invokes this API. It can be used
+** to clean up any outstanding resources before process shutdown, if required.
+**
+** The xCreate() method is used to construct a new cache instance. The
+** first parameter, szPage, is the size in bytes of the pages that must
+** be allocated by the cache. szPage will not be a power of two. The
+** second argument, bPurgeable, is true if the cache being created will
+** be used to cache database pages read from a file stored on disk, or
+** false if it is used for an in-memory database. The cache implementation
+** does not have to do anything special based on the value of bPurgeable,
+** it is purely advisory. 
+**
+** The xCachesize() method may be called at any time by SQLite to set the
+** suggested maximum cache-size (number of pages stored by) the cache
+** instance passed as the first argument. This is the value configured using
+** the SQLite "[PRAGMA cache_size]" command. As with the bPurgeable parameter,
+** the implementation is not required to do anything special with this
+** value, it is advisory only.
+**
+** The xPagecount() method should return the number of pages currently
+** stored in the cache supplied as an argument.
+** 
+** The xFetch() method is used to fetch a page and return a pointer to it. 
+** A 'page', in this context, is a buffer of szPage bytes aligned at an
+** 8-byte boundary. The page to be fetched is determined by the key. The
+** mimimum key value is 1. After it has been retrieved using xFetch, the page 
+** is considered to be pinned.
+**
+** If the requested page is already in the page cache, then a pointer to
+** the cached buffer should be returned with its contents intact. If the
+** page is not already in the cache, then the expected behaviour of the
+** cache is determined by the value of the createFlag parameter passed
+** to xFetch, according to the following table:
+**
+** <table border=1 width=85% align=center>
+**   <tr><th>createFlag<th>Expected Behaviour
+**   <tr><td>0<td>NULL should be returned. No new cache entry is created.
+**   <tr><td>1<td>If createFlag is set to 1, this indicates that 
+**                SQLite is holding pinned pages that can be unpinned
+**                by writing their contents to the database file (a
+**                relatively expensive operation). In this situation the
+**                cache implementation has two choices: it can return NULL,
+**                in which case SQLite will attempt to unpin one or more 
+**                pages before re-requesting the same page, or it can
+**                allocate a new page and return a pointer to it. If a new
+**                page is allocated, then it must be completely zeroed before 
+**                it is returned.
+**   <tr><td>2<td>If createFlag is set to 2, then SQLite is not holding any
+**                pinned pages associated with the specific cache passed
+**                as the first argument to xFetch() that can be unpinned. The
+**                cache implementation should attempt to allocate a new
+**                cache entry and return a pointer to it. Again, the new
+**                page should be zeroed before it is returned. If the xFetch()
+**                method returns NULL when createFlag==2, SQLite assumes that
+**                a memory allocation failed and returns SQLITE_NOMEM to the
+**                user.
+** </table>
+**
+** xUnpin() is called by SQLite with a pointer to a currently pinned page
+** as its second argument. If the third parameter, discard, is non-zero,
+** then the page should be evicted from the cache. In this case SQLite 
+** assumes that the next time the page is retrieved from the cache using
+** the xFetch() method, it will be zeroed. If the discard parameter is
+** zero, then the page is considered to be unpinned. The cache implementation
+** may choose to reclaim (free or recycle) unpinned pages at any time.
+** SQLite assumes that next time the page is retrieved from the cache
+** it will either be zeroed, or contain the same data that it did when it
+** was unpinned.
+**
+** The cache is not required to perform any reference counting. A single 
+** call to xUnpin() unpins the page regardless of the number of prior calls 
+** to xFetch().
+**
+** The xRekey() method is used to change the key value associated with the
+** page passed as the second argument from oldKey to newKey. If the cache
+** previously contains an entry associated with newKey, it should be
+** discarded. Any prior cache entry associated with newKey is guaranteed not
+** to be pinned.
+**
+** When SQLite calls the xTruncate() method, the cache must discard all
+** existing cache entries with page numbers (keys) greater than or equal
+** to the value of the iLimit parameter passed to xTruncate(). If any
+** of these pages are pinned, they are implicitly unpinned, meaning that
+** they can be safely discarded.
+**
+** The xDestroy() method is used to delete a cache allocated by xCreate().
+** All resources associated with the specified cache should be freed. After
+** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*]
+** handle invalid, and will not use it with any other sqlite3_pcache_methods
+** functions.
+*/
+typedef struct sqlite3_pcache_methods sqlite3_pcache_methods;
+struct sqlite3_pcache_methods {
+  void *pArg;
+  int (*xInit)(void*);
+  void (*xShutdown)(void*);
+  sqlite3_pcache *(*xCreate)(int szPage, int bPurgeable);
+  void (*xCachesize)(sqlite3_pcache*, int nCachesize);
+  int (*xPagecount)(sqlite3_pcache*);
+  void *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);
+  void (*xUnpin)(sqlite3_pcache*, void*, int discard);
+  void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey);
+  void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);
+  void (*xDestroy)(sqlite3_pcache*);
+};
+
 /*
 ** Undo the hack that converts floating point types to integer for
 ** builds on processors without floating point support.