]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Changes to delay freeing buffers associated with vdbe memory cells until either sqlit...
authordanielk1977 <danielk1977@noemail.net>
Wed, 26 Mar 2008 18:34:43 +0000 (18:34 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Wed, 26 Mar 2008 18:34:43 +0000 (18:34 +0000)
FossilOrigin-Name: 8c2f69521f13bc24cf005520efbe0589eeadd763

12 files changed:
manifest
manifest.uuid
src/malloc.c
src/mutex.c
src/mutex_os2.c
src/mutex_unix.c
src/mutex_w32.c
src/sqlite.h.in
src/vdbe.h
src/vdbeInt.h
src/vdbeapi.c
src/vdbeaux.c

index 644953086a4c7b2daadc3164c3dcc39ad8d510c6..dfb6a841e9fcb97da2317f36ed7f14389524ef67 100644 (file)
--- 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
index 1037dfbc2d7c42c4edd1433ff2f1343ef84c0400..464d2eff6887d19a26b6bf9121fd74f54ff13d7a 100644 (file)
@@ -1 +1 @@
-afe1963ec5588d2195f027fa438cf63d49c89cd9
\ No newline at end of file
+8c2f69521f13bc24cf005520efbe0589eeadd763
\ No newline at end of file
index a04734868bb1a27a8c80f6a46de9e2946a3342aa..55d5c76dee0b9a8f441ea41aac61ccdabf6de534 100644 (file)
@@ -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 <stdarg.h>
@@ -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
index 5815ff216984f8e137ee5d90166e5ddd90137bb8..f4372c961c54aad391ae01f125764f9dc4cd311e 100644 (file)
@@ -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:
index cbffeeebc209c6b43d86f514df869d29d6f7c3e7..ed5477a54247a1836aa5d9bc4ee9e9cfd5571ae4 100644 (file)
@@ -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;
index 93e7e9a190d0c2291356f3c797568cc9bd902e17..a21798af6803404760766b9e35e1f2f6a501f2b9 100644 (file)
@@ -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 ){
index 1944ccc79cafd4bde639a885a857c49109243562..7fc73da12809be681f3401f85dbb707b07b8ff82 100644 (file)
@@ -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;
index 335772c45b4b850975d4db911669af12a733c1ce..d6c68ccb2c7e22d270af43fddba1b9328e61b20b 100644 (file)
@@ -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*);
 ** <li>  SQLITE_MUTEX_STATIC_MEM2
 ** <li>  SQLITE_MUTEX_STATIC_PRNG
 ** <li>  SQLITE_MUTEX_STATIC_LRU
+** <li>  SQLITE_MUTEX_STATIC_LRU2
 ** </ul> {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}
index ad6d870042a4034124437ca23a19e142b1a5eb94..5d6bc905add52febd96377532786e63c37c9d66f 100644 (file)
@@ -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*);
index 08821f2661c2e85fb970d2a62cff90cf6e60dd8c..d492a26b426032101e8c7bc2d3c277adeb260839 100644 (file)
@@ -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*);
index dfefae1165e68c7f9c83558f677aca220e819d18..c0bde8692ecfabb13abd14f0e9eb4fdf642f4181 100644 (file)
 #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 && nFree<n; p=pNext){
+    pNext = p->pLruNext;
+
+    /* 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;
     }
index 9399315cf54f23b4e0564d7f6e9e569133a368cb..6b737d2c8717a38cb43078cf29388861569ab850 100644 (file)
@@ -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; n<p->nMem; 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; i<p->contextStackTop; 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;