From: danielk1977 Date: Wed, 26 Mar 2008 18:34:43 +0000 (+0000) Subject: Changes to delay freeing buffers associated with vdbe memory cells until either sqlit... X-Git-Tag: version-3.6.10~1255 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dfb316d43242a61212feec6c1293b4519f348a79;p=thirdparty%2Fsqlite.git Changes to delay freeing buffers associated with vdbe memory cells until either sqlite3_finalize() or sqlite3_release_memory() is called. (CVS 4922) FossilOrigin-Name: 8c2f69521f13bc24cf005520efbe0589eeadd763 --- diff --git a/manifest b/manifest index 644953086a..dfb6a841e9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Work\saround\sproblems\swith\scompilers\sthat\sdo\snot\sallow\sC\spreprocessor\nmacros\swith\sempty\sarguments.\s(CVS\s4921) -D 2008-03-26T17:18:48 +C Changes\sto\sdelay\sfreeing\sbuffers\sassociated\swith\svdbe\smemory\scells\suntil\seither\ssqlite3_finalize()\sor\ssqlite3_release_memory()\sis\scalled.\s(CVS\s4922) +D 2008-03-26T18:34:43 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in cf434ce8ca902e69126ae0f94fc9f7dc7428a5fa F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -105,18 +105,18 @@ F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2 F src/legacy.c 8267890e6a0a71f13b680794520999c642299081 F src/loadext.c f26b22f7c84153c9d5dbd7c240848823c6e6b6dc F src/main.c 7d22155e35094bc5d368202c3db8a3fc429548af -F src/malloc.c 60e392a4c12c839517f9b0db7b995f825444fb35 +F src/malloc.c 12c1ae98ef1eff34b13c9eb526e0b7b479e1e820 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 F src/mem1.c fc716ff521b6dd3e43eaa211967383308800e70a F src/mem2.c a4694eff7397de20a7e4b3d70c3faeaf63bf4647 F src/mem3.c 52547678a2ae50c203d54be1a5bf51eb02438a3f F src/mem4.c 45c328ec6dcb7e8d319cb383615b5fe547ca5409 F src/mem5.c 11d98b76f77873aab86b543cbd1a8ddc4e680d58 -F src/mutex.c 3259f62c2429967aee6dc112117a6d2f499ef061 +F src/mutex.c d455f0876d5aad9935a23d01e6ae1bf4bd462d6a F src/mutex.h 079fa6fe9da18ceb89e79012c010594c6672addb -F src/mutex_os2.c 19ab15764736f13b94b4f70e53f77547cbddd47a -F src/mutex_unix.c a6e111947a3cdaa2cda394ed060d7f496fcb4af8 -F src/mutex_w32.c 6e197765f283815496193e78e9548b5d0e53b68e +F src/mutex_os2.c 2911ea96955ab6cba734cc4ad903fe76f834b39e +F src/mutex_unix.c c54275523ba4d9b00d6c7783602929b5556dbaf9 +F src/mutex_w32.c 133698096a2c4e81cd11ea6f4de7891c66f7b9f7 F src/os.c 9b943f71aaa1519f26cd45693a91b429b63aa042 F src/os.h 497bf5f0f2648461ef65940cfb59ba427430f3fc F src/os_common.h e8b748b2f2ecc8a498e50bfe5d8721f189c19d2a @@ -138,7 +138,7 @@ F src/random.c 2b2db2de4ab491f5a14d3480466f8f4b5a5db74a F src/select.c 5b5197016a0b751fdb78758370ba127175d3f786 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c 22297fffa6f00a6c6d44020fa13b1184a1bb372d -F src/sqlite.h.in 61d8d1cefcbf0803c03c2179be138a78bfd1d335 +F src/sqlite.h.in b1ac824d9fc163a5d2226ebf5990b09a02a11117 F src/sqlite3ext.h faacd0e6a81aabee0861c6d7883c9172e74ef5b3 F src/sqliteInt.h db668a07004d53a47c5d570963842489c6c4c3f3 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8 @@ -175,10 +175,10 @@ F src/utf.c 32b00d6e19010025e58f2ecb2f921d5e126771b4 F src/util.c dba9e04121eb17ec4643d6ca231ff859452cf0e2 F src/vacuum.c 3524411bfb58aac0d87eadd3e5b7cd532772af30 F src/vdbe.c 0068703495a197e7b77dbdff604b42896722a1cc -F src/vdbe.h ecca2e1c1ac1066f4e68ad38068a20ea32ea7063 -F src/vdbeInt.h 4d767f189a1d13ff8d4881de60aacc470e54f5b8 -F src/vdbeapi.c b9e9d7a58690c1e1ae66de7232edccf4793ad817 -F src/vdbeaux.c e45929a3b5e59e8f2d69b7d6164c9a636149e1df +F src/vdbe.h f72201a0657d5f3d6cc008d1f8d9cc65768518c9 +F src/vdbeInt.h 2584494757e7d8e7015754d4017b36f758c2adef +F src/vdbeapi.c f74189e4cae0d93b2744386b9ac57f5ab60c5133 +F src/vdbeaux.c c77a88c97cf5836eb1f68ca6fea967569472712b F src/vdbeblob.c cc713c142c3d4952b380c98ee035f850830ddbdb F src/vdbefifo.c a30c237b2a3577e1415fb6e288cbb6b8ed1e5736 F src/vdbemem.c d48a71d66a7afd564b6537ab7e7442f7729fa5af @@ -618,7 +618,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P d016d0784097e6657de26ccc6bece34913093fb0 -R 6a30be694ce8b9a07ddf6aceb1a9f0a1 -U drh -Z e985441f36301e76052987bf9e15f80e +P afe1963ec5588d2195f027fa438cf63d49c89cd9 +R 214d193014a5eff088fafe70f8060fb1 +U danielk1977 +Z ddfa33c54c6e0388e4067b98a41cbe5a diff --git a/manifest.uuid b/manifest.uuid index 1037dfbc2d..464d2eff68 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -afe1963ec5588d2195f027fa438cf63d49c89cd9 \ No newline at end of file +8c2f69521f13bc24cf005520efbe0589eeadd763 \ No newline at end of file diff --git a/src/malloc.c b/src/malloc.c index a04734868b..55d5c76dee 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -12,7 +12,7 @@ ** Memory allocation functions used throughout sqlite. ** ** -** $Id: malloc.c,v 1.14 2007/10/20 16:36:31 drh Exp $ +** $Id: malloc.c,v 1.15 2008/03/26 18:34:43 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -59,7 +59,9 @@ void sqlite3_soft_heap_limit(int n){ */ int sqlite3_release_memory(int n){ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT - return sqlite3PagerReleaseMemory(n); + int nRet = sqlite3VdbeReleaseMemory(n); + nRet += sqlite3PagerReleaseMemory(n-nRet); + return nRet; #else return SQLITE_OK; #endif diff --git a/src/mutex.c b/src/mutex.c index 5815ff2169..f4372c961c 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -19,7 +19,7 @@ ** implementation is suitable for testing. ** debugging purposes ** -** $Id: mutex.c,v 1.16 2007/09/10 16:13:00 danielk1977 Exp $ +** $Id: mutex.c,v 1.17 2008/03/26 18:34:43 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -44,7 +44,7 @@ struct sqlite3_mutex { ** that means that a mutex could not be allocated. */ sqlite3_mutex *sqlite3_mutex_alloc(int id){ - static sqlite3_mutex aStatic[5]; + static sqlite3_mutex aStatic[6]; sqlite3_mutex *pNew = 0; switch( id ){ case SQLITE_MUTEX_FAST: diff --git a/src/mutex_os2.c b/src/mutex_os2.c index cbffeeebc2..ed5477a542 100644 --- a/src/mutex_os2.c +++ b/src/mutex_os2.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains the C functions that implement mutexes for OS/2 ** -** $Id: mutex_os2.c,v 1.5 2008/02/01 19:42:38 pweilbacher Exp $ +** $Id: mutex_os2.c,v 1.6 2008/03/26 18:34:43 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -101,6 +101,7 @@ sqlite3_mutex *sqlite3_mutex_alloc(int iType){ { OS2_MUTEX_INITIALIZER, }, { OS2_MUTEX_INITIALIZER, }, { OS2_MUTEX_INITIALIZER, }, + { OS2_MUTEX_INITIALIZER, }, }; if ( !isInit ){ APIRET rc; diff --git a/src/mutex_unix.c b/src/mutex_unix.c index 93e7e9a190..a21798af68 100644 --- a/src/mutex_unix.c +++ b/src/mutex_unix.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains the C functions that implement mutexes for pthreads ** -** $Id: mutex_unix.c,v 1.5 2007/11/28 14:04:57 drh Exp $ +** $Id: mutex_unix.c,v 1.6 2008/03/26 18:34:43 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -88,6 +88,7 @@ sqlite3_mutex *sqlite3_mutex_alloc(int iType){ { PTHREAD_MUTEX_INITIALIZER, }, { PTHREAD_MUTEX_INITIALIZER, }, { PTHREAD_MUTEX_INITIALIZER, }, + { PTHREAD_MUTEX_INITIALIZER, }, }; sqlite3_mutex *p; switch( iType ){ diff --git a/src/mutex_w32.c b/src/mutex_w32.c index 1944ccc79c..7fc73da128 100644 --- a/src/mutex_w32.c +++ b/src/mutex_w32.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains the C functions that implement mutexes for win32 ** -** $Id: mutex_w32.c,v 1.5 2007/10/05 15:08:01 drh Exp $ +** $Id: mutex_w32.c,v 1.6 2008/03/26 18:34:43 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -111,7 +111,7 @@ sqlite3_mutex *sqlite3_mutex_alloc(int iType){ break; } default: { - static sqlite3_mutex staticMutexes[5]; + static sqlite3_mutex staticMutexes[6]; static int isInit = 0; while( !isInit ){ static long lock = 0; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 335772c45b..d6c68ccb2c 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -30,7 +30,7 @@ ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** -** @(#) $Id: sqlite.h.in,v 1.300 2008/03/24 12:51:46 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.301 2008/03/26 18:34:43 danielk1977 Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ @@ -5440,6 +5440,7 @@ int sqlite3_vfs_unregister(sqlite3_vfs*); **
  • SQLITE_MUTEX_STATIC_MEM2 **
  • SQLITE_MUTEX_STATIC_PRNG **
  • SQLITE_MUTEX_STATIC_LRU +**
  • SQLITE_MUTEX_STATIC_LRU2 ** {END} ** ** {F17015} The first two constants cause sqlite3_mutex_alloc() to create @@ -5552,6 +5553,7 @@ int sqlite3_mutex_notheld(sqlite3_mutex*); #define SQLITE_MUTEX_STATIC_MEM2 4 /* sqlite3_release_memory() */ #define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */ #define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ +#define SQLITE_MUTEX_STATIC_LRU2 7 /* lru page list */ /* ** CAPI3REF: Low-Level Control Of Database Files {F11300} diff --git a/src/vdbe.h b/src/vdbe.h index ad6d870042..5d6bc905ad 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -15,7 +15,7 @@ ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** -** $Id: vdbe.h,v 1.128 2008/03/25 17:23:34 drh Exp $ +** $Id: vdbe.h,v 1.129 2008/03/26 18:34:43 danielk1977 Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -174,7 +174,7 @@ int sqlite3VdbeCurrentAddr(Vdbe*); void sqlite3VdbeTrace(Vdbe*,FILE*); #endif void sqlite3VdbeResetStepResult(Vdbe*); -int sqlite3VdbeReset(Vdbe*); +int sqlite3VdbeReset(Vdbe*, int); void sqlite3VdbeSetNumCols(Vdbe*,int); int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int); void sqlite3VdbeCountChanges(Vdbe*); @@ -182,6 +182,7 @@ sqlite3 *sqlite3VdbeDb(Vdbe*); void sqlite3VdbeSetSql(Vdbe*, const char *z, int n); void sqlite3VdbeSwap(Vdbe*,Vdbe*); +int sqlite3VdbeReleaseMemory(int); UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,void*,int); void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*); int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 08821f2661..d492a26b42 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -333,6 +333,10 @@ struct Vdbe { int fetchId; /* Statement number used by sqlite3_fetch_statement */ int lru; /* Counter used for LRU cache replacement */ #endif +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT + Vdbe *pLruPrev; + Vdbe *pLruNext; +#endif }; /* @@ -414,6 +418,7 @@ int sqlite3VdbeMemFinalize(Mem*, FuncDef*); const char *sqlite3OpcodeName(int); int sqlite3VdbeOpcodeHasProperty(int, int); int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); +int sqlite3VdbeReleaseBuffers(Vdbe *p); #ifndef NDEBUG void sqlite3VdbeMemSanity(Mem*); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index dfefae1165..c0bde8692e 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -16,6 +16,160 @@ #include "sqliteInt.h" #include "vdbeInt.h" +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT +/* +** The following structure contains pointers to the end points of a +** doubly-linked list of all compiled SQL statements that may be holding +** buffers eligible for release when the sqlite3_release_memory() interface is +** invoked. Access to this list is protected by the SQLITE_MUTEX_STATIC_LRU2 +** mutex. +** +** Statements are added to the end of this list when sqlite3_reset() is +** called. They are removed either when sqlite3_step() or sqlite3_finalize() +** is called. When statements are added to this list, the associated +** register array (p->aMem[1..p->nMem]) may contain dynamic buffers that +** can be freed using sqlite3VdbeReleaseMemory(). +** +** When statements are added or removed from this list, the mutex +** associated with the Vdbe being added or removed (Vdbe.db->mutex) is +** already held. The LRU2 mutex is then obtained, blocking if necessary, +** the linked-list pointers manipulated and the LRU2 mutex relinquished. +*/ +struct StatementLruList { + Vdbe *pFirst; + Vdbe *pLast; +}; +static struct StatementLruList sqlite3LruStatements; + +/* +** Check that the list looks to be internally consistent. This is used +** as part of an assert() statement as follows: +** +** assert( stmtLruCheck() ); +*/ +static int stmtLruCheck(){ + Vdbe *p; + for(p=sqlite3LruStatements.pFirst; p; p=p->pLruNext){ + assert(p->pLruNext || p==sqlite3LruStatements.pLast); + assert(!p->pLruNext || p->pLruNext->pLruPrev==p); + assert(p->pLruPrev || p==sqlite3LruStatements.pFirst); + assert(!p->pLruPrev || p->pLruPrev->pLruNext==p); + } + return 1; +} + +/* +** Add vdbe p to the end of the statement lru list. It is assumed that +** p is not already part of the list when this is called. The lru list +** is protected by the SQLITE_MUTEX_STATIC_LRU mutex. +*/ +static void stmtLruAdd(Vdbe *p){ + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU2)); + + if( p->pLruPrev || p->pLruNext || sqlite3LruStatements.pFirst==p ){ + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU2)); + return; + } + + assert( stmtLruCheck() ); + + if( !sqlite3LruStatements.pFirst ){ + assert( !sqlite3LruStatements.pLast ); + sqlite3LruStatements.pFirst = p; + sqlite3LruStatements.pLast = p; + }else{ + assert( !sqlite3LruStatements.pLast->pLruNext ); + p->pLruPrev = sqlite3LruStatements.pLast; + sqlite3LruStatements.pLast->pLruNext = p; + sqlite3LruStatements.pLast = p; + } + + assert( stmtLruCheck() ); + + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU2)); +} + +/* +** Assuming the SQLITE_MUTEX_STATIC_LRU2 mutext is already held, remove +** statement p from the least-recently-used statement list. If the +** statement is not currently part of the list, this call is a no-op. +*/ +static void stmtLruRemoveNomutex(Vdbe *p){ + if( p->pLruPrev || p->pLruNext || p==sqlite3LruStatements.pFirst ){ + assert( stmtLruCheck() ); + if( p->pLruNext ){ + p->pLruNext->pLruPrev = p->pLruPrev; + }else{ + sqlite3LruStatements.pLast = p->pLruPrev; + } + if( p->pLruPrev ){ + p->pLruPrev->pLruNext = p->pLruNext; + }else{ + sqlite3LruStatements.pFirst = p->pLruNext; + } + p->pLruNext = 0; + p->pLruPrev = 0; + assert( stmtLruCheck() ); + } +} + +/* +** Assuming the SQLITE_MUTEX_STATIC_LRU2 mutext is not held, remove +** statement p from the least-recently-used statement list. If the +** statement is not currently part of the list, this call is a no-op. +*/ +static void stmtLruRemove(Vdbe *p){ + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU2)); + stmtLruRemoveNomutex(p); + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU2)); +} + +/* +** Try to release n bytes of memory by freeing buffers associated +** with the memory registers of currently unused vdbes. +*/ +int sqlite3VdbeReleaseMemory(int n){ + Vdbe *p; + Vdbe *pNext; + int nFree = 0; + + sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU2)); + for(p=sqlite3LruStatements.pFirst; p && nFreepLruNext; + + /* For each statement handle in the lru list, attempt to obtain the + ** associated database mutex. If it cannot be obtained, continue + ** to the next statement handle. It is not possible to block on + ** the database mutex - that could cause deadlock. + */ + if( SQLITE_OK==sqlite3_mutex_try(p->db->mutex) ){ + nFree += sqlite3VdbeReleaseBuffers(p); + stmtLruRemoveNomutex(p); + sqlite3_mutex_leave(p->db->mutex); + } + } + sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU2)); + + return nFree; +} + +/* +** Call sqlite3Reprepare() on the statement. Remove it from the +** lru list before doing so, as Reprepare() will free all the +** memory register buffers anyway. +*/ +int vdbeReprepare(Vdbe *p){ + stmtLruRemove(p); + return sqlite3Reprepare(p); +} + +#else /* !SQLITE_ENABLE_MEMORY_MANAGEMENT */ + #define stmtLruRemove(x) + #define stmtLruAdd(x) + #define vdbeReprepare(x) sqlite3Reprepare(x) +#endif + + /* ** Return TRUE (non-zero) of the statement supplied as an argument needs ** to be recompiled. A statement needs to be recompiled whenever the @@ -48,6 +202,7 @@ int sqlite3_finalize(sqlite3_stmt *pStmt){ sqlite3_mutex *mutex = v->db->mutex; #endif sqlite3_mutex_enter(mutex); + stmtLruRemove(v); rc = sqlite3VdbeFinalize(v); sqlite3_mutex_leave(mutex); } @@ -69,7 +224,8 @@ int sqlite3_reset(sqlite3_stmt *pStmt){ }else{ Vdbe *v = (Vdbe*)pStmt; sqlite3_mutex_enter(v->db->mutex); - rc = sqlite3VdbeReset(v); + rc = sqlite3VdbeReset(v, 0); + stmtLruAdd(v); sqlite3VdbeMakeReady(v, -1, 0, 0, 0); assert( (rc & (v->db->errMask))==rc ); sqlite3_mutex_leave(v->db->mutex); @@ -306,6 +462,7 @@ static int sqlite3Step(Vdbe *p){ db->activeVdbeCnt++; p->pc = 0; + stmtLruRemove(p); } #ifndef SQLITE_OMIT_EXPLAIN if( p->explain ){ @@ -377,7 +534,7 @@ int sqlite3_step(sqlite3_stmt *pStmt){ sqlite3_mutex_enter(db->mutex); while( (rc = sqlite3Step(v))==SQLITE_SCHEMA && cnt++ < 5 - && sqlite3Reprepare(v) ){ + && vdbeReprepare(v) ){ sqlite3_reset(pStmt); v->expired = 0; } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 9399315cf5..6b737d2c87 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -737,19 +737,39 @@ void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){ /* ** Release an array of N Mem elements */ -static void releaseMemArray(Mem *p, int N){ +static void releaseMemArray(Mem *p, int N, int freebuffers){ if( p && N ){ sqlite3 *db = p->db; int malloc_failed = db->mallocFailed; while( N-->0 ){ assert( N<2 || p[0].db==p[1].db ); - sqlite3VdbeMemRelease(p); - p++->flags = MEM_Null; + if( freebuffers || p->xDel ){ + sqlite3VdbeMemRelease(p); + p->flags = MEM_Null; + } + p++; } db->mallocFailed = malloc_failed; } } +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT +int sqlite3VdbeReleaseBuffers(Vdbe *p){ + int ii; + int nFree = 0; + assert( sqlite3_mutex_held(p->db->mutex) ); + for(ii=1; ii<=p->nMem; ii++){ + Mem *pMem = &p->aMem[ii]; + if( pMem->z && pMem->flags&MEM_Dyn ){ + assert( !pMem->xDel ); + nFree += sqlite3MallocSize(pMem->z); + sqlite3VdbeMemRelease(pMem); + } + } + return nFree; +} +#endif + #ifndef SQLITE_OMIT_EXPLAIN /* ** Give a listing of the program in the virtual machine. @@ -780,7 +800,7 @@ int sqlite3VdbeList( ** the result, result columns may become dynamic if the user calls ** sqlite3_column_text16(), causing a translation to UTF-16 encoding. */ - releaseMemArray(pMem, p->nMem); + releaseMemArray(pMem, p->nMem, 1); do{ i = p->pc++; @@ -1010,7 +1030,7 @@ void sqlite3VdbeMakeReady( #ifdef SQLITE_DEBUG for(n=1; nnMem; n++){ assert( p->aMem[n].db==db ); - assert( p->aMem[n].flags==MEM_Null ); + //assert( p->aMem[n].flags==MEM_Null ); } #endif @@ -1090,14 +1110,13 @@ static void closeAllCursorsExceptActiveVtabs(Vdbe *p){ ** sorters that were left open. It also deletes the values of ** variables in the aVar[] array. */ -static void Cleanup(Vdbe *p){ +static void Cleanup(Vdbe *p, int freebuffers){ int i; closeAllCursorsExceptActiveVtabs(p); for(i=1; i<=p->nMem; i++){ MemSetTypeFlag(&p->aMem[i], MEM_Null); } - - releaseMemArray(&p->aMem[1], p->nMem); + releaseMemArray(&p->aMem[1], p->nMem, freebuffers); sqlite3VdbeFifoClear(&p->sFifo); if( p->contextStack ){ for(i=0; icontextStackTop; i++){ @@ -1123,7 +1142,7 @@ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ Mem *pColName; int n; - releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); + releaseMemArray(p->aColName, p->nResColumn*COLNAME_N, 1); sqlite3_free(p->aColName); n = nResColumn*COLNAME_N; p->nResColumn = nResColumn; @@ -1648,7 +1667,7 @@ void sqlite3VdbeResetStepResult(Vdbe *p){ ** virtual machine from VDBE_MAGIC_RUN or VDBE_MAGIC_HALT back to ** VDBE_MAGIC_INIT. */ -int sqlite3VdbeReset(Vdbe *p){ +int sqlite3VdbeReset(Vdbe *p, int freebuffers){ sqlite3 *db; db = p->db; @@ -1687,7 +1706,7 @@ int sqlite3VdbeReset(Vdbe *p){ /* Reclaim all memory used by the VDBE */ - Cleanup(p); + Cleanup(p, freebuffers); /* Save profiling information from this VDBE run. */ @@ -1725,11 +1744,12 @@ int sqlite3VdbeReset(Vdbe *p){ int sqlite3VdbeFinalize(Vdbe *p){ int rc = SQLITE_OK; if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){ - rc = sqlite3VdbeReset(p); + rc = sqlite3VdbeReset(p, 1); assert( (rc & p->db->errMask)==rc ); }else if( p->magic!=VDBE_MAGIC_INIT ){ return SQLITE_MISUSE; } + releaseMemArray(&p->aMem[1], p->nMem, 1); sqlite3VdbeDelete(p); return rc; } @@ -1759,7 +1779,7 @@ void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){ void sqlite3VdbeDelete(Vdbe *p){ int i; if( p==0 ) return; - Cleanup(p); + Cleanup(p, 1); if( p->pPrev ){ p->pPrev->pNext = p->pNext; }else{ @@ -1779,12 +1799,12 @@ void sqlite3VdbeDelete(Vdbe *p){ } sqlite3_free(p->aOp); } - releaseMemArray(p->aVar, p->nVar); + releaseMemArray(p->aVar, p->nVar, 1); sqlite3_free(p->aLabel); if( p->aMem ){ sqlite3_free(&p->aMem[1]); } - releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); + releaseMemArray(p->aColName, p->nResColumn*COLNAME_N, 1); sqlite3_free(p->aColName); sqlite3_free(p->zSql); p->magic = VDBE_MAGIC_DEAD;