diff options
Diffstat (limited to 'ext/sqlite3/libsqlite/sqlite3.c')
| -rw-r--r-- | ext/sqlite3/libsqlite/sqlite3.c | 3382 | 
1 files changed, 2152 insertions, 1230 deletions
| diff --git a/ext/sqlite3/libsqlite/sqlite3.c b/ext/sqlite3/libsqlite/sqlite3.c index 0c3d63b453..2aaf123798 100644 --- a/ext/sqlite3/libsqlite/sqlite3.c +++ b/ext/sqlite3/libsqlite/sqlite3.c @@ -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 @@ -15,13 +15,13 @@  ** 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> @@ -7017,6 +7033,149 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_stmt_status(sqlite3_stmt*, int op,int  #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(). @@ -7520,6 +7679,25 @@ SQLITE_API   void *sqlite3_wsd_find(void *K, int L);  #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  */  typedef struct AggInfo AggInfo; @@ -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}  /* @@ -9762,6 +9926,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  ** the SrcList.a[] array. @@ -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. @@ -21188,6 +21387,16 @@ SQLITE_API int sqlite3_os_end(void){  #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  ** large file support, these should be no-ops. @@ -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,12 +25057,16 @@ 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++); +  /* 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; +    }    } -  h = BITVEC_HASH(i); -  while( p->u.aHash[h] ){ +  /* 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,99 +27418,23 @@ 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 */ +  sqlite3_pcache *pCache;             /* Pluggable cache module */ +  PgHdr *pPage1;  };  /* -** Free slots in the page block allocator -*/ -typedef struct PgFreeslot PgFreeslot; -struct PgFreeslot { -  PgFreeslot *pNext;  /* Next free slot */ -}; - -/* -** 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  ** tests.  Enable the expensive asserts using the @@ -26773,48 +27450,6 @@ static SQLITE_WSD struct PCacheGlobal {  #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  ** is not, either fail an assert or return zero. Otherwise, return  ** non-zero. This is only used in debugging builds, as follows: @@ -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) ); -} +static void pcacheRemoveFromDirtyList(PgHdr *pPage){ +  PCache *p = 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) ); -} +  assert( pPage->pDirtyNext || pPage==p->pDirtyTail ); +  assert( pPage->pDirtyPrev || pPage==p->pDirty ); -/* -** 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; -} - -/* -** 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 ); - -  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; -    } -  } -} - -/* -** 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; +  /* 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;    } -} -/* -** 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; -  }else{ -    assert( pcache_g.pLruTail==pPage ); -    pcache_g.pLruTail = pPage->pPrevLru; -  } -  if( pPage->pPrevLru ){ -    assert( pcache_g.pLruHead!=pPage ); -    pPage->pPrevLru->pNextLru = pPage->pNextLru; +  if( pPage->pDirtyNext ){ +    pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;    }else{ -    assert( pcache_g.pLruHead==pPage ); -    pcache_g.pLruHead = pPage->pNextLru; +    assert( pPage==p->pDirtyTail ); +    p->pDirtyTail = pPage->pDirtyPrev;    } -} - -/* -** 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; +  if( pPage->pDirtyPrev ){ +    pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;    }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; -    } +    assert( pPage==p->pDirty ); +    p->pDirty = pPage->pDirtyNext;    } -} +  pPage->pDirtyNext = 0; +  pPage->pDirtyPrev = 0; -/*********************************************** 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); -  } -} -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++; +  p->pDirty = pPage; +  if( !p->pDirtyTail ){ +    p->pDirtyTail = pPage;    } -  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;    } -  if( !pPage && createFlag ){ -    if( pCache->nHash<=pCache->nPage ){ -      rc = pcacheResizeHash(pCache, pCache->nHash<256 ? 256 : pCache->nHash*2); +  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; + +    /* 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(); +  if( pCache->pCache ){ +    sqlite3GlobalConfig.pcache.xDestroy(pCache->pCache);    } -  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 ); -  } -} -#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];    } -  for(p=pCache->pClean; p; p=p->pNext){ -    p->flags &= mask; +  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; +} -  if( 0==(mask&PGHDR_NEED_SYNC) ){ -    pCache->pSynced = pCache->pDirtyTail; -    assert( !pCache->pSynced || (pCache->pSynced->flags&PGHDR_NEED_SYNC)==0 ); +/* +** 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);    } +} -  pcacheExitMutex(); +/* +** 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;  }  /* -** Set the suggested cache-size value. +** Free a page object allocated by pcache1AllocPage().  */ -SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *pCache){ -  return pCache->nMax; +static void pcache1FreePage(PgHdr1 *p){ +  if( p ){ +    if( p->pCache->bPurgeable ){ +      pcache1.nCurrentPage--; +    } +    pcache1Free(p); +  }  }  /* -** Set the suggested cache-size value. +** 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 sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ -  if( mxPage<10 ){ -    mxPage = 10; +SQLITE_PRIVATE void *sqlite3PageMalloc(int sz){ +  void *p; +  pcache1EnterMutex(); +  p = pcache1Alloc(sz); +  pcache1LeaveMutex(); +  return p; +} + +/* +** Free an allocated buffer obtained from sqlite3PageMalloc(). +*/ +SQLITE_PRIVATE void sqlite3PageFree(void *p){ +  pcache1EnterMutex(); +  pcache1Free(p); +  pcache1LeaveMutex(); +} + +/******************************************************************************/ +/******** General Implementation Functions ************************************/ + +/* +** 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. +*/ +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 ){ @@ -75898,11 +76809,6 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){  */  /* -** The number of bits in a Bitmask.  "BMS" means "BitMask Size". -*/ -#define BMS  (sizeof(Bitmask)*8) - -/*  ** Trace output macros  */  #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) @@ -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 - | 
