]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix minor malloc() related problems and add sqlite3_soft_heap_limit() stubs. (CVS...
authordanielk1977 <danielk1977@noemail.net>
Mon, 12 Dec 2005 06:53:03 +0000 (06:53 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Mon, 12 Dec 2005 06:53:03 +0000 (06:53 +0000)
FossilOrigin-Name: 1637f3796015d1582ed8c6bc8bdf8c067b4bade9

12 files changed:
manifest
manifest.uuid
src/complete.c
src/legacy.c
src/main.c
src/prepare.c
src/sqlite.h.in
src/sqliteInt.h
src/tclsqlite.c
src/test1.c
src/util.c
test/tclsqlite.test

index 51911fcb26d05e11b7d2e354b57b57b7df740193..0e95aa858a6c006c83902f0924e866d3b1531a71 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\s"exists"\smethod\sto\sthe\sTCL\sinterface.\s(CVS\s2813)
-D 2005-12-10T21:19:05
+C Fix\sminor\smalloc()\srelated\sproblems\sand\sadd\ssqlite3_soft_heap_limit()\sstubs.\s(CVS\s2814)
+D 2005-12-12T06:53:04
 F Makefile.in e3c6b3a38d734d41574c04f2fc90d18de2b87102
 F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -38,7 +38,7 @@ F src/btree.c de0fc1a0f6a4631001ffb6070d1b7588cdebcbc5
 F src/btree.h 1ed561263ca0e335bc3e81d761c9d5ff8c22f61e
 F src/build.c 306dde3134acd8f1c9f3821d81c3cb598af91280
 F src/callback.c 4bc404e9912eecb28be1235581833f6269920c27
-F src/complete.c 4de937dfdd4c79a501772ab2035b26082f337a79
+F src/complete.c df1681cef40dec33a286006981845f87b194e7a4
 F src/date.c bb079317bff6a2b78aba5c0d2ddae5f6f03acfb7
 F src/delete.c 6010a081edda9871895260def092e852f0bb60a0
 F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d
@@ -47,8 +47,8 @@ F src/func.c 25f1e5710b71cb345b492a18088f546188599f6b
 F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863
 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
 F src/insert.c 5393479164f317ea0aeec954c6500cafa097ef33
-F src/legacy.c 7b88d20efc8e6c208f262d97aee9c8e2cf02bc91
-F src/main.c d8656320f9299c70ee6a41deab5350d615ffa3b7
+F src/legacy.c 59757d857ab95fcbb0ac27692d3201e35f093dd7
+F src/main.c 95ba159727e4342d871e8c0aae42321ae10d8195
 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
 F src/os.c bdd3a2fd089777e7ad18b57c896f1141d5a0c1fd
 F src/os.h d5ae3f4c1c7731437b6cddec279b7c06f761c44e
@@ -63,16 +63,16 @@ F src/pager.c 49f63a54b57164a70df0b1539141003fd27856c6
 F src/pager.h e7b41ce8e7b5f629d456708b7ad9a8c8ede37140
 F src/parse.y d0b1f9a4d508bf043cdbc7079aa26dff7d358651
 F src/pragma.c 8883b4d34796efa315bdd0ec1b03f580ef1575b9
-F src/prepare.c 8d75f7dbe7b1055789be17d6a70f1fedcaf4c31d
+F src/prepare.c 9717bd4236020aeabc488819b994d4164a97ffdf
 F src/printf.c f47a2f4b5387cd2ebb12e9117a1a5d6bd9a2b812
 F src/random.c ff5e9a8cad790e2a51cd4d2e7737dc8540e09d1d
 F src/select.c 2292b065bc6be61e01aad39a2e1b93e332fb7e57
 F src/shell.c 4872acee1d2a826c73c914961e469e563204b7f9
-F src/sqlite.h.in 8e648e1f386e4509f2f96c09ded7c07b0df0c9a2
-F src/sqliteInt.h feb11bfe9bf79b4493319173c47739fe2bb7ffa4
+F src/sqlite.h.in a52db91dfa4f90e8e42361f6c7824c09b4e101ad
+F src/sqliteInt.h 22b18da438fb1298bfd6ad1e2e3b5a2826100da8
 F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316
-F src/tclsqlite.c 6b34de66e8098c306bc3b96300143c23d4797769
-F src/test1.c feae6cb2d70a1bc83d7084c590212989922b0f47
+F src/tclsqlite.c c155bf5f9ce9ae8950037931f7f7efcc0d92d9c5
+F src/test1.c e995c713219d93a022fd6228150b5340aebcf456
 F src/test2.c 36390cdfc70c08e5ee0b466d0654a117f398bbff
 F src/test3.c 7c97833e33496c2b69f4fe6b9882ac60a481da97
 F src/test4.c a8fd681e139e1c61f22a77d07fc3a99cb28fff3f
@@ -82,7 +82,7 @@ F src/tokenize.c 7a3a3d3cc734f684a77c4dfd09eb46fcee25394c
 F src/trigger.c 2925ba96d964d9b717e74006bf7e64b8a6b70d97
 F src/update.c ec8e540617b116725b5a55c8d6b4db8bc67fdd7d
 F src/utf.c a1fd34e5db0dc4da1c37405381a656230c7b922d
-F src/util.c 94c0b99e66243b3452c81cd321eb6e61e4c5fba0
+F src/util.c e525154652f7aecb8773cae55ada9f43024bb2c4
 F src/vacuum.c fbfdd3967fd34e2f260fafed88dcbf3c10856b94
 F src/vdbe.c d09c185f4badac6c79f2a919cbf661e7b5618293
 F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13
@@ -221,7 +221,7 @@ F test/subselect.test 2d13fb7f450db3595adcdd24079a0dd1d2d6abc2
 F test/sync.test 6e8b885cec5ccba2090e92c90f747a7142f53c88
 F test/table.test ec0e6c2186bb8f6824f470caa118524dfd8fe057
 F test/tableapi.test 6a66d58b37d46dc0f2b3c7d4bd2617d209399bd1
-F test/tclsqlite.test 07729a3b683407362bbd63c2a17b4c9ea8b0ec27
+F test/tclsqlite.test 9890d58c6c2a72b6a57daf88e2e7aa9c4a141213
 F test/temptable.test 7927261befdbc7b0a7ffebb85ecc70a74fa7b15b
 F test/tester.tcl a06c798a653daefb5bce2c85fc3a7d06450a1875
 F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35
@@ -327,7 +327,7 @@ F www/tclsqlite.tcl ddcf912ea48695603c8ed7efb29f0812ef8d1b49
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
 F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P 398037906956f0274ca35cbff6961f6df5149295
-R 8e7c1e3ead7dacbb9408f99afbdcbea3
-U drh
-Z b05b2682bc485f2f8d89f673d48ca998
+P 8a355d7aade5c7a95ab08aeedf1ee1857c121c33
+R 75658ca824ff0ff17378f907ba53f1f6
+U danielk1977
+Z 573b0e314e198362cddb16601e85e971
index 5b3017794974d654810817e02555932f4784d3d8..185fd1d43e08da1379bc85c8856e4bd6ebcf6aff 100644 (file)
@@ -1 +1 @@
-8a355d7aade5c7a95ab08aeedf1ee1857c121c33
\ No newline at end of file
+1637f3796015d1582ed8c6bc8bdf8c067b4bade9
\ No newline at end of file
index 4cc76b5019d75f290874d16f6f723a576ba5e4a0..61a87e57c352b2d1ca7bbbfe08adf79edd4147a9 100644 (file)
@@ -16,7 +16,7 @@
 ** separating it out, the code will be automatically omitted from
 ** static links that do not use it.
 **
-** $Id: complete.c,v 1.1 2005/08/14 17:53:21 drh Exp $
+** $Id: complete.c,v 1.2 2005/12/12 06:53:04 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #ifndef SQLITE_OMIT_COMPLETE
@@ -255,6 +255,9 @@ int sqlite3_complete16(const void *zSql){
   zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8);
   if( zSql8 ){
     rc = sqlite3_complete(zSql8);
+  }else if( zSql ){
+    rc = SQLITE_NOMEM;
+    sqlite3MallocClearFailed();
   }
   sqlite3ValueFree(pVal);
   return rc;
index 4a3c2d248d2a9f192c21073e5700d2c8bc6c40dd..40fa8f5b0781522b9ffe13b37a1463f0fa8f1791 100644 (file)
@@ -14,7 +14,7 @@
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: legacy.c,v 1.8 2005/12/06 12:52:59 danielk1977 Exp $
+** $Id: legacy.c,v 1.9 2005/12/12 06:53:04 danielk1977 Exp $
 */
 
 #include "sqliteInt.h"
@@ -70,7 +70,6 @@ int sqlite3_exec(
     nCol = sqlite3_column_count(pStmt);
     azCols = sqliteMalloc(2*nCol*sizeof(const char *));
     if( nCol && !azCols ){
-      rc = SQLITE_NOMEM;
       goto exec_out;
     }
 
@@ -124,7 +123,9 @@ exec_out:
 
   if( sqlite3Tsd()->mallocFailed ){
     rc = SQLITE_NOMEM;
+    sqlite3MallocClearFailed();
   }
+
   if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){
     *pzErrMsg = malloc(1+strlen(sqlite3_errmsg(db)));
     if( *pzErrMsg ){
index 3410770878fef44013aeb5196ebca325df163b0e..ff5bc08752e7bcb092fc1989852746da15147bc3 100644 (file)
@@ -14,7 +14,7 @@
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: main.c,v 1.307 2005/12/09 20:02:05 drh Exp $
+** $Id: main.c,v 1.308 2005/12/12 06:53:04 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -153,6 +153,9 @@ int sqlite3_close(sqlite3 *db){
     return SQLITE_ERROR;
   }
 
+  /* sqlite3_close() may not invoke sqliteMalloc(). */
+  sqlite3MallocDisallow();
+
   for(j=0; j<db->nDb; j++){
     struct Db *pDb = &db->aDb[j];
     if( pDb->pBt ){
@@ -186,6 +189,7 @@ int sqlite3_close(sqlite3 *db){
     sqlite3ValueFree(db->pErr);
   }
 
+#if 0 
 #ifndef SQLITE_OMIT_GLOBALRECOVER
   {
     sqlite3 *pPrev;
@@ -202,10 +206,12 @@ int sqlite3_close(sqlite3 *db){
     }
     sqlite3Os.xLeaveMutex();
   }
+#endif
 #endif
 
   db->magic = SQLITE_MAGIC_ERROR;
   sqliteFree(db);
+  sqlite3MallocAllow();
   return SQLITE_OK;
 }
 
@@ -691,10 +697,11 @@ const void *sqlite3_errmsg16(sqlite3 *db){
 #endif /* SQLITE_OMIT_UTF16 */
 
 /*
-** Return the most recent error code generated by an SQLite routine.
+** Return the most recent error code generated by an SQLite routine. If NULL is
+** passed to this function, we assume a malloc() failed during sqlite3_open().
 */
 int sqlite3_errcode(sqlite3 *db){
-  if( sqlite3Tsd()->mallocFailed ){
+  if( !db || sqlite3Tsd()->mallocFailed ){
     return SQLITE_NOMEM;
   }
   if( sqlite3SafetyCheck(db) ){
@@ -716,6 +723,8 @@ static int openDatabase(
   int rc, i;
   CollSeq *pColl;
 
+  assert( !sqlite3Tsd()->mallocFailed );
+
   /* Allocate the sqlite data structure */
   db = sqliteMalloc( sizeof(sqlite3) );
   if( db==0 ) goto opendb_out;
@@ -741,8 +750,12 @@ static int openDatabase(
   */
   if( sqlite3_create_collation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc) ||
       sqlite3_create_collation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) ||
-      (db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0))==0 ){
-    assert(rc!=SQLITE_OK || sqlite3Tsd()->mallocFailed);
+      (db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0))==0 
+  ){
+    /* sqlite3_create_collation() is an external API. So the mallocFailed flag
+    ** will have been cleared before returning. So set it explicitly here.
+    */
+    sqlite3Tsd()->mallocFailed = 1;
     db->magic = SQLITE_MAGIC_CLOSED;
     goto opendb_out;
   }
@@ -785,19 +798,13 @@ static int openDatabase(
   db->magic = SQLITE_MAGIC_OPEN;
 
 opendb_out:
-  if( sqlite3_errcode(db)==SQLITE_OK && sqlite3Tsd()->mallocFailed ){
-    sqlite3Error(db, SQLITE_NOMEM, 0);
+  if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){
+    sqlite3_close(db);
+    db = 0;
   }
   *ppDb = db;
-#ifndef SQLITE_OMIT_GLOBALRECOVER
-  if( db ){
-    sqlite3Os.xEnterMutex();
-    db->pNext = pDbList;
-    pDbList = db;
-    sqlite3Os.xLeaveMutex();
-  }
-#endif
-  return sqlite3_errcode(db);
+  sqlite3MallocClearFailed();
+  return rc;
 }
 
 /*
@@ -822,6 +829,7 @@ int sqlite3_open16(
   int rc = SQLITE_NOMEM;
   sqlite3_value *pVal;
 
+  assert( zFilename );
   assert( ppDb );
   *ppDb = 0;
   pVal = sqlite3ValueNew();
@@ -832,10 +840,11 @@ int sqlite3_open16(
     if( rc==SQLITE_OK && *ppDb ){
       rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
     }
+  }else{
+    assert( sqlite3Tsd()->mallocFailed );
+    sqlite3MallocClearFailed();
   }
-  if( pVal ){
-    sqlite3ValueFree(pVal);
-  }
+  sqlite3ValueFree(pVal);
 
   return rc;
 }
@@ -1001,39 +1010,10 @@ int sqlite3_collation_needed16(
 
 #ifndef SQLITE_OMIT_GLOBALRECOVER
 /*
-** This function is called to recover from a malloc failure that occured
-** within SQLite. 
-**
-** This function is *not* threadsafe. Calling this from within a threaded
-** application when threads other than the caller have used SQLite is 
-** dangerous and will almost certainly result in malfunctions.
+** This function is now an anachronism. It used to be used to recover from a
+** malloc() failure, but SQLite now does this automatically.
 */
 int sqlite3_global_recover(){
-#if 0
-  int rc = SQLITE_OK;
-
-  if( sqlite3Tsd()->mallocFailed ){
-    sqlite3 *db;
-    int i;
-    sqlite3Tsd()->mallocFailed = 0;
-    for(db=pDbList; db; db=db->pNext ){
-      sqlite3ExpirePreparedStatements(db);
-      for(i=0; i<db->nDb; i++){
-        Btree *pBt = db->aDb[i].pBt;
-        if( pBt && (rc=sqlite3BtreeReset(pBt))!=0 ){
-          goto recover_out;
-        }
-      } 
-      db->autoCommit = 1;
-    }
-  }
-
-recover_out:
-  if( rc!=SQLITE_OK ){
-    sqlite3Tsd()->mallocFailed = 1;
-  }
-  return rc;
-#endif
   return SQLITE_OK;
 }
 #endif
index ecd7fa6c115d75c8860c97bcd2761a6c5cec1fda..c702fb9f197741eda4058e797fe23d9148d79826 100644 (file)
@@ -13,7 +13,7 @@
 ** interface, and routines that contribute to loading the database schema
 ** from disk.
 **
-** $Id: prepare.c,v 1.7 2005/12/09 20:02:05 drh Exp $
+** $Id: prepare.c,v 1.8 2005/12/12 06:53:04 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -443,12 +443,6 @@ int sqlite3_prepare(
 
   if( sqlite3Tsd()->mallocFailed ){
     sParse.rc = SQLITE_NOMEM;
-#if 0
-    sqlite3RollbackInternalChanges(db);
-    sqlite3RollbackAll(db);
-    db->flags &= ~SQLITE_InTrans;
-    db->autoCommit = 1;
-#endif
   }
   if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
   if( sParse.rc!=SQLITE_OK && sParse.checkSchema && !schemaIsValid(db) ){
index c07876ce7e52b9aa1357d476bc79dbd04826d09d..8c9e95a504893babc0556ca33b5ac73ceb4863ae 100644 (file)
@@ -12,7 +12,7 @@
 ** This header file defines the interface that the SQLite library
 ** presents to client programs.
 **
-** @(#) $Id: sqlite.h.in,v 1.143 2005/10/20 07:28:19 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.144 2005/12/12 06:53:05 danielk1977 Exp $
 */
 #ifndef _SQLITE3_H_
 #define _SQLITE3_H_
@@ -1276,6 +1276,21 @@ int sqlite3_get_autocommit(sqlite3*);
 */
 sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
 
+/*
+** Place a "soft" limit on the amount of heap memory that may be allocated by
+** SQLite within the current thread. If an internal allocation is requested 
+** that would exceed the specified limit, sqlite3_release_memory() is invoked
+** one or more times to free up some space before the allocation is made.
+**
+** The limit is called "soft", because if sqlite3_release_memory() cannot free
+** sufficient memory to prevent the limit from being exceeded, the memory is
+** allocated anyway and the current operation proceeds.
+**
+** This function is only available if the library was compiled without the 
+** SQLITE_OMIT_SOFTHEAPLIMIT option set.
+*/
+void sqlite3_soft_heap_limit(int);
+
 /*
 ** Undo the hack that converts floating point types to integer for
 ** builds on processors without floating point support.
index 1eac934bdbb6d5aa576fff69f812cbbee2d855bb..2ce46e0ad5a2536bb1a32f90c5afd23bf7190fa5 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.433 2005/12/09 20:02:06 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.434 2005/12/12 06:53:05 danielk1977 Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -269,6 +269,11 @@ extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */
 typedef struct SqliteTsd SqliteTsd;
 struct SqliteTsd {
   int mallocFailed;               /* True after a malloc() has failed */
+#ifndef SQLITE_OMIT_SOFTHEAPLIMIT
+  unsigned int nSoftHeapLimit;    /* (uint)-1 for unlimited */
+  unsigned int nAlloc;            /* Number of bytes currently allocated */
+#endif
+
 #ifndef NDEBUG
   int mallocAllowed;              /* assert() in sqlite3Malloc() if not set */
 #endif
index 6ee0b9027886c35da56099b87323b85afb936058..3b58df75c3cddcdf8ea7a2a31acf6609de0ff6e1 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** A TCL Interface to SQLite
 **
-** $Id: tclsqlite.c,v 1.136 2005/12/10 21:19:05 drh Exp $
+** $Id: tclsqlite.c,v 1.137 2005/12/12 06:53:05 danielk1977 Exp $
 */
 #ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */
 
@@ -623,9 +623,9 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
     "copy",               "errorcode",         "eval",
     "exists",             "function",          "last_insert_rowid",
     "nullvalue",          "onecolumn",         "profile",
-    "progress",           "rekey",             "timeout",
-    "total_changes",      "trace",             "transaction",
-    "version",            0                    
+    "progress",           "rekey",             "soft_heap_limit",
+    "timeout",            "total_changes",     "trace",
+    "transaction",        "version",            0                    
   };
   enum DB_enum {
     DB_AUTHORIZER,        DB_BUSY,             DB_CACHE,
@@ -634,9 +634,9 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
     DB_COPY,              DB_ERRORCODE,        DB_EVAL,
     DB_EXISTS,            DB_FUNCTION,         DB_LAST_INSERT_ROWID,
     DB_NULLVALUE,         DB_ONECOLUMN,        DB_PROFILE,
-    DB_PROGRESS,          DB_REKEY,            DB_TIMEOUT,
-    DB_TOTAL_CHANGES,     DB_TRACE,            DB_TRANSACTION,
-    DB_VERSION
+    DB_PROGRESS,          DB_REKEY,            DB_SOFT_HEAP_LIMIT,
+    DB_TIMEOUT,           DB_TOTAL_CHANGES,    DB_TRACE,
+    DB_TRANSACTION,       DB_VERSION
   };
   /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
 
@@ -1705,6 +1705,26 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
     sqlite3_busy_timeout(pDb->db, ms);
     break;
   }
+
+  /*
+  **     $db soft_heap_limit N
+  **
+  ** Set the soft-heap-limit for this thread. Note that the limit is 
+  ** per-thread, not per-database.
+  */
+  case DB_SOFT_HEAP_LIMIT: {
+    int n;
+    if( objc!=3 ){
+      Tcl_WrongNumArgs(interp, 2, objv, "BYTES");
+      return TCL_ERROR;
+    }
+    if( Tcl_GetIntFromObj(interp, objv[2], &n) ){
+      return TCL_ERROR;
+    }
+    sqlite3_soft_heap_limit(n);
+    Tcl_ResetResult(interp);
+    break;
+  }
   
   /*
   **     $db total_changes
@@ -1961,7 +1981,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
 #ifdef SQLITE_MEMDEBUG
     sqlite3_iMallocFail = mallocfail;
 #endif
-   }
+  }
 #endif  
   p->interp = interp;
   return TCL_OK;
index 40de2e7379a13ee7aa0fef3cd8e722689d2e11e3..b7d47d6537fc01741d28a89e64594f6ada01c8da 100644 (file)
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test1.c,v 1.174 2005/12/09 20:21:59 drh Exp $
+** $Id: test1.c,v 1.175 2005/12/12 06:53:05 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "tcl.h"
@@ -810,7 +810,6 @@ static int sqlite_malloc_fail(
   }
   sqlite3_iMallocFail = n;
   sqlite3_iMallocReset = rep;
-  sqlite3Tsd()->mallocFailed = 0;
   return TCL_OK;
 }
 #endif
index 3edc20f4a3dd9732d718b1f0235ae0bbadd15648..49b2c76dfe77608577f1fe3936c8459e092ecd05 100644 (file)
@@ -14,7 +14,7 @@
 ** This file contains functions for allocating memory, comparing
 ** strings, and stuff like that.
 **
-** $Id: util.c,v 1.151 2005/12/09 14:39:04 danielk1977 Exp $
+** $Id: util.c,v 1.152 2005/12/12 06:53:05 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <stdarg.h>
@@ -119,7 +119,7 @@ int sqlite3OsAllocationSize(void *p){
   #define TESTALLOC_STACKSIZE 128
   #define TESTALLOC_STACKFRAMES ((TESTALLOC_STACKSIZE-8)/sizeof(void*))
 #else
-  #define backtrace(x, y) 0
+  #define backtrace(x, y)
   #define TESTALLOC_STACKSIZE 0
   #define TESTALLOC_STACKFRAMES 0
 #endif
@@ -137,7 +137,9 @@ int sqlite3OsAllocationSize(void *p){
 #define TESTALLOC_FILESIZE 64
 
 /*
-** Size reserved for storing the user string.
+** Size reserved for storing the user string. Each time a Malloc() or Realloc()
+** call succeeds, up to TESTALLOC_USERSIZE bytes of the string pointed to by
+** sqlite3_malloc_id are stored along with the other test system metadata.
 */
 #define TESTALLOC_USERSIZE 64
 const char *sqlite3_malloc_id = 0;
@@ -364,8 +366,15 @@ static void relinkAlloc(void *p)
 
 /*
 ** This function sets the result of the Tcl interpreter passed as an argument
-** to a list containing an entry for each currently outstanding call made to
-** sqliteMalloc and friends by the current thread.
+** to a list containing an entry for each currently outstanding call made to 
+** sqliteMalloc and friends by the current thread. Each list entry is itself a
+** list, consisting of the following (in order):
+**
+**     * The number of bytes allocated
+**     * The __FILE__ macro at the time of the sqliteMalloc() call.
+**     * The __LINE__ macro ...
+**     * The value of the sqlite3_malloc_id variable ...
+**     * The output of backtrace() (if available) ...
 **
 ** Todo: We could have a version of this function that outputs to stdout, 
 ** to debug memory leaks when Tcl is not available.
@@ -464,16 +473,46 @@ void OSMALLOC_FAILED(){
   sqlite3Tsd()->isFail = 0;
 }
 
+int OSSIZEOF(void *p){
+  if( p ){
+    return sqlite3OsAllocationSize(p) - TESTALLOC_OVERHEAD;
+  }
+  return 0;
+}
+
 #else
 #define OSMALLOC(x) sqlite3OsMalloc(x)
 #define OSREALLOC(x,y) sqlite3OsRealloc(x,y)
 #define OSFREE(x) sqlite3OsFree(x)
+#define OSSIZEOF(x) sqlite3OsAllocationSize(x)
 #define OSMALLOC_FAILED()
 #endif
 /*
 ** End code for memory allocation system test layer.
 **--------------------------------------------------------------------------*/
 
+/*
+** The handleSoftLimit() function is called before each call to 
+** sqlite3OsMalloc() or sqlite3OsRealloc(). The parameter 'n' is the number of
+** extra bytes about to be allocated (for Realloc() this means the size of the
+** new allocation less the size of the old allocation). If the extra allocation
+** means that the total memory allocated to SQLite in this thread would exceed
+** the limit set by sqlite3_soft_heap_limit(), then sqlite3_release_memory() is
+** called to try to avoid this. No indication of whether or not this is
+** successful is returned to the caller.
+**
+** If SQLITE_OMIT_SOFTHEAPLIMIT is defined, this function is a no-op.
+*/
+#ifndef SQLITE_OMIT_SOFTHEAPLIMIT
+static void handleSoftLimit(int n){
+  SqliteTsd *pTsd = sqlite3Tsd();
+  pTsd->nAlloc += n;
+  while( pTsd->nAlloc>pTsd->nSoftHeapLimit && sqlite3_release_memory(n) );
+}
+#else
+#define handleSoftLimit()
+#endif
+
 /*
 ** Allocate and return N bytes of uninitialised memory by calling
 ** sqlite3OsMalloc(). If the Malloc() call fails, attempt to free memory 
@@ -482,8 +521,8 @@ void OSMALLOC_FAILED(){
 void *sqlite3MallocRaw(int n){
   SqliteTsd *pTsd = sqlite3Tsd();
   void *p = 0;
-
   if( n>0 && !pTsd->mallocFailed ){
+    handleSoftLimit(n);
     while( !(p = OSMALLOC(n)) && sqlite3_release_memory(n) );
     if( !p ){
       sqlite3Tsd()->mallocFailed = 1;
@@ -508,6 +547,7 @@ void *sqlite3Realloc(void *p, int n){
     return sqlite3Malloc(n);
   }else{
     void *np = 0;
+    handleSoftLimit(n - OSSIZEOF(p));
     while( !(np = OSREALLOC(p, n)) && sqlite3_release_memory(n) );
     if( !np ){
       pTsd->mallocFailed = 1;
@@ -529,7 +569,7 @@ void sqlite3FreeX(void *p){
 
 /*
 ** A version of sqliteMalloc() that is always a function, not a macro.
-** Currently, this is used only to alloc only used drawback.
+** Currently, this is used only to alloc to allocate the parser engine.
 */
 void *sqlite3MallocX(int n){
   return sqliteMalloc(n);
@@ -1208,27 +1248,52 @@ void *sqlite3TextToPtr(const char *z){
 
 /*
 ** Return a pointer to the SqliteTsd associated with the calling thread.
+** TODO: Actually return thread-specific-data instead of this global pointer.
 */
-static SqliteTsd tsd = {
-  0                    /* mallocFailed flag */
-#ifndef NDEBUG
-  , 1                  /* mallocAllowed flag */
-#endif
-#ifdef SQLITE_MEMDEBUG
-  , 0
-  , 0
-  , 0
-  , 0
-#endif
-};
 SqliteTsd *sqlite3Tsd(){
+  static SqliteTsd tsd = {
+    0                    /* mallocFailed flag */
+  #ifndef SQLITE_OMIT_SOFTHEAPLIMIT
+    , 0xFFFFFFFF         /* nSoftHeapLimit */
+    , 0                  /* nAlloc */
+  #endif
+  #ifndef NDEBUG
+    , 1                  /* mallocAllowed flag */
+  #endif
+  #ifdef SQLITE_MEMDEBUG
+    , 0
+    , 0
+    , 0
+    , 0
+  #endif
+  };
   return &tsd;
 }
 
+/*
+** Clear the "mallocFailed" flag. This should be invoked before exiting any
+** entry points that may have called sqliteMalloc().
+*/
 void sqlite3MallocClearFailed(){
   sqlite3Tsd()->mallocFailed = 0;
 }
 
+#ifndef SQLITE_OMIT_SOFTHEAPLIMIT
+/*
+** Set the soft heap-size limit for the current thread.
+*/
+void sqlite3_soft_heap_limit(int n){
+  unsigned int N;
+  if( n<0 ){
+    /* No limit */
+    N = 0xFFFFFFFF;
+  }else{
+    N = n;
+  }
+  sqlite3Tsd()->nSoftHeapLimit = N;
+}
+#endif
+
 #ifndef NDEBUG
 /*
 ** This function sets a flag in the thread-specific-data structure that will
index ba833d026e84ab9889d96cada2570742ba43d8b1..083d42377f4acd1cf21c44467ffce9cfb2385ba9 100644 (file)
@@ -15,7 +15,7 @@
 # interface is pretty well tested.  This file contains some addition
 # tests for fringe issues that the main test suite does not cover.
 #
-# $Id: tclsqlite.test,v 1.45 2005/12/10 21:19:06 drh Exp $
+# $Id: tclsqlite.test,v 1.46 2005/12/12 06:53:05 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -34,7 +34,7 @@ do_test tcl-1.1 {
 do_test tcl-1.2 {
   set v [catch {db bogus} msg]
   lappend v $msg
-} {1 {bad option "bogus": must be authorizer, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, errorcode, eval, exists, function, last_insert_rowid, nullvalue, onecolumn, profile, progress, rekey, timeout, total_changes, trace, transaction, or version}}
+} {1 {bad option "bogus": must be authorizer, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, errorcode, eval, exists, function, last_insert_rowid, nullvalue, onecolumn, profile, progress, rekey, soft_heap_limit, timeout, total_changes, trace, transaction, or version}}
 do_test tcl-1.3 {
   execsql {CREATE TABLE t1(a int, b int)}
   execsql {INSERT INTO t1 VALUES(10,20)}
@@ -110,27 +110,27 @@ do_test tcl-1.15 {
   set v [catch {db function} msg]
   lappend v $msg
 } {1 {wrong # args: should be "db function NAME SCRIPT"}}
-do_test tcl-1.14 {
+do_test tcl-1.16 {
   set v [catch {db last_insert_rowid xyz} msg]
   lappend v $msg
 } {1 {wrong # args: should be "db last_insert_rowid "}}
-do_test tcl-1.15 {
+do_test tcl-1.17 {
   set v [catch {db rekey} msg]
   lappend v $msg
 } {1 {wrong # args: should be "db rekey KEY"}}
-do_test tcl-1.16 {
+do_test tcl-1.18 {
   set v [catch {db timeout} msg]
   lappend v $msg
 } {1 {wrong # args: should be "db timeout MILLISECONDS"}}
-do_test tcl-1.17 {
+do_test tcl-1.19 {
   set v [catch {db collate} msg]
   lappend v $msg
 } {1 {wrong # args: should be "db collate NAME SCRIPT"}}
-do_test tcl-1.18 {
+do_test tcl-1.20 {
   set v [catch {db collation_needed} msg]
   lappend v $msg
 } {1 {wrong # args: should be "db collation_needed SCRIPT"}}
-do_test tcl-1.19 {
+do_test tcl-1.21 {
   set v [catch {db total_changes xyz} msg]
   lappend v $msg
 } {1 {wrong # args: should be "db total_changes "}}