diff options
author | Scott MacVicar <scottmac@php.net> | 2008-11-22 11:04:26 +0000 |
---|---|---|
committer | Scott MacVicar <scottmac@php.net> | 2008-11-22 11:04:26 +0000 |
commit | 55e5bb5a99dda1286cb78d5d9ef4e1d6a3ca7605 (patch) | |
tree | c2d35fbe918e20e6ca3776794706660376367c25 /ext/sqlite3/libsqlite/sqlite3.c | |
parent | a064b61971afbcf143789efd79833a29921f19d9 (diff) | |
download | php-git-55e5bb5a99dda1286cb78d5d9ef4e1d6a3ca7605.tar.gz |
Update libsqlite to 3.6.6
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 - |