Fix minor malloc() related problems and add sqlite3_soft_heap_limit() stubs. (CVS 2814)

FossilOrigin-Name: 1637f3796015d1582ed8c6bc8bdf8c067b4bade9
This commit is contained in:
danielk1977 2005-12-12 06:53:03 +00:00
parent 97f2ebc192
commit 7ddad969a4
12 changed files with 198 additions and 116 deletions

View File

@ -1,5 +1,5 @@
C Add\sthe\s"exists"\smethod\sto\sthe\sTCL\sinterface.\s(CVS\s2813) C Fix\sminor\smalloc()\srelated\sproblems\sand\sadd\ssqlite3_soft_heap_limit()\sstubs.\s(CVS\s2814)
D 2005-12-10T21:19:05 D 2005-12-12T06:53:04
F Makefile.in e3c6b3a38d734d41574c04f2fc90d18de2b87102 F Makefile.in e3c6b3a38d734d41574c04f2fc90d18de2b87102
F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092 F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@ -38,7 +38,7 @@ F src/btree.c de0fc1a0f6a4631001ffb6070d1b7588cdebcbc5
F src/btree.h 1ed561263ca0e335bc3e81d761c9d5ff8c22f61e F src/btree.h 1ed561263ca0e335bc3e81d761c9d5ff8c22f61e
F src/build.c 306dde3134acd8f1c9f3821d81c3cb598af91280 F src/build.c 306dde3134acd8f1c9f3821d81c3cb598af91280
F src/callback.c 4bc404e9912eecb28be1235581833f6269920c27 F src/callback.c 4bc404e9912eecb28be1235581833f6269920c27
F src/complete.c 4de937dfdd4c79a501772ab2035b26082f337a79 F src/complete.c df1681cef40dec33a286006981845f87b194e7a4
F src/date.c bb079317bff6a2b78aba5c0d2ddae5f6f03acfb7 F src/date.c bb079317bff6a2b78aba5c0d2ddae5f6f03acfb7
F src/delete.c 6010a081edda9871895260def092e852f0bb60a0 F src/delete.c 6010a081edda9871895260def092e852f0bb60a0
F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d
@ -47,8 +47,8 @@ F src/func.c 25f1e5710b71cb345b492a18088f546188599f6b
F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863 F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
F src/insert.c 5393479164f317ea0aeec954c6500cafa097ef33 F src/insert.c 5393479164f317ea0aeec954c6500cafa097ef33
F src/legacy.c 7b88d20efc8e6c208f262d97aee9c8e2cf02bc91 F src/legacy.c 59757d857ab95fcbb0ac27692d3201e35f093dd7
F src/main.c d8656320f9299c70ee6a41deab5350d615ffa3b7 F src/main.c 95ba159727e4342d871e8c0aae42321ae10d8195
F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
F src/os.c bdd3a2fd089777e7ad18b57c896f1141d5a0c1fd F src/os.c bdd3a2fd089777e7ad18b57c896f1141d5a0c1fd
F src/os.h d5ae3f4c1c7731437b6cddec279b7c06f761c44e F src/os.h d5ae3f4c1c7731437b6cddec279b7c06f761c44e
@ -63,16 +63,16 @@ F src/pager.c 49f63a54b57164a70df0b1539141003fd27856c6
F src/pager.h e7b41ce8e7b5f629d456708b7ad9a8c8ede37140 F src/pager.h e7b41ce8e7b5f629d456708b7ad9a8c8ede37140
F src/parse.y d0b1f9a4d508bf043cdbc7079aa26dff7d358651 F src/parse.y d0b1f9a4d508bf043cdbc7079aa26dff7d358651
F src/pragma.c 8883b4d34796efa315bdd0ec1b03f580ef1575b9 F src/pragma.c 8883b4d34796efa315bdd0ec1b03f580ef1575b9
F src/prepare.c 8d75f7dbe7b1055789be17d6a70f1fedcaf4c31d F src/prepare.c 9717bd4236020aeabc488819b994d4164a97ffdf
F src/printf.c f47a2f4b5387cd2ebb12e9117a1a5d6bd9a2b812 F src/printf.c f47a2f4b5387cd2ebb12e9117a1a5d6bd9a2b812
F src/random.c ff5e9a8cad790e2a51cd4d2e7737dc8540e09d1d F src/random.c ff5e9a8cad790e2a51cd4d2e7737dc8540e09d1d
F src/select.c 2292b065bc6be61e01aad39a2e1b93e332fb7e57 F src/select.c 2292b065bc6be61e01aad39a2e1b93e332fb7e57
F src/shell.c 4872acee1d2a826c73c914961e469e563204b7f9 F src/shell.c 4872acee1d2a826c73c914961e469e563204b7f9
F src/sqlite.h.in 8e648e1f386e4509f2f96c09ded7c07b0df0c9a2 F src/sqlite.h.in a52db91dfa4f90e8e42361f6c7824c09b4e101ad
F src/sqliteInt.h feb11bfe9bf79b4493319173c47739fe2bb7ffa4 F src/sqliteInt.h 22b18da438fb1298bfd6ad1e2e3b5a2826100da8
F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316 F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316
F src/tclsqlite.c 6b34de66e8098c306bc3b96300143c23d4797769 F src/tclsqlite.c c155bf5f9ce9ae8950037931f7f7efcc0d92d9c5
F src/test1.c feae6cb2d70a1bc83d7084c590212989922b0f47 F src/test1.c e995c713219d93a022fd6228150b5340aebcf456
F src/test2.c 36390cdfc70c08e5ee0b466d0654a117f398bbff F src/test2.c 36390cdfc70c08e5ee0b466d0654a117f398bbff
F src/test3.c 7c97833e33496c2b69f4fe6b9882ac60a481da97 F src/test3.c 7c97833e33496c2b69f4fe6b9882ac60a481da97
F src/test4.c a8fd681e139e1c61f22a77d07fc3a99cb28fff3f F src/test4.c a8fd681e139e1c61f22a77d07fc3a99cb28fff3f
@ -82,7 +82,7 @@ F src/tokenize.c 7a3a3d3cc734f684a77c4dfd09eb46fcee25394c
F src/trigger.c 2925ba96d964d9b717e74006bf7e64b8a6b70d97 F src/trigger.c 2925ba96d964d9b717e74006bf7e64b8a6b70d97
F src/update.c ec8e540617b116725b5a55c8d6b4db8bc67fdd7d F src/update.c ec8e540617b116725b5a55c8d6b4db8bc67fdd7d
F src/utf.c a1fd34e5db0dc4da1c37405381a656230c7b922d F src/utf.c a1fd34e5db0dc4da1c37405381a656230c7b922d
F src/util.c 94c0b99e66243b3452c81cd321eb6e61e4c5fba0 F src/util.c e525154652f7aecb8773cae55ada9f43024bb2c4
F src/vacuum.c fbfdd3967fd34e2f260fafed88dcbf3c10856b94 F src/vacuum.c fbfdd3967fd34e2f260fafed88dcbf3c10856b94
F src/vdbe.c d09c185f4badac6c79f2a919cbf661e7b5618293 F src/vdbe.c d09c185f4badac6c79f2a919cbf661e7b5618293
F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13 F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13
@ -221,7 +221,7 @@ F test/subselect.test 2d13fb7f450db3595adcdd24079a0dd1d2d6abc2
F test/sync.test 6e8b885cec5ccba2090e92c90f747a7142f53c88 F test/sync.test 6e8b885cec5ccba2090e92c90f747a7142f53c88
F test/table.test ec0e6c2186bb8f6824f470caa118524dfd8fe057 F test/table.test ec0e6c2186bb8f6824f470caa118524dfd8fe057
F test/tableapi.test 6a66d58b37d46dc0f2b3c7d4bd2617d209399bd1 F test/tableapi.test 6a66d58b37d46dc0f2b3c7d4bd2617d209399bd1
F test/tclsqlite.test 07729a3b683407362bbd63c2a17b4c9ea8b0ec27 F test/tclsqlite.test 9890d58c6c2a72b6a57daf88e2e7aa9c4a141213
F test/temptable.test 7927261befdbc7b0a7ffebb85ecc70a74fa7b15b F test/temptable.test 7927261befdbc7b0a7ffebb85ecc70a74fa7b15b
F test/tester.tcl a06c798a653daefb5bce2c85fc3a7d06450a1875 F test/tester.tcl a06c798a653daefb5bce2c85fc3a7d06450a1875
F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35 F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35
@ -327,7 +327,7 @@ F www/tclsqlite.tcl ddcf912ea48695603c8ed7efb29f0812ef8d1b49
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
P 398037906956f0274ca35cbff6961f6df5149295 P 8a355d7aade5c7a95ab08aeedf1ee1857c121c33
R 8e7c1e3ead7dacbb9408f99afbdcbea3 R 75658ca824ff0ff17378f907ba53f1f6
U drh U danielk1977
Z b05b2682bc485f2f8d89f673d48ca998 Z 573b0e314e198362cddb16601e85e971

View File

@ -1 +1 @@
8a355d7aade5c7a95ab08aeedf1ee1857c121c33 1637f3796015d1582ed8c6bc8bdf8c067b4bade9

View File

@ -16,7 +16,7 @@
** separating it out, the code will be automatically omitted from ** separating it out, the code will be automatically omitted from
** static links that do not use it. ** 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" #include "sqliteInt.h"
#ifndef SQLITE_OMIT_COMPLETE #ifndef SQLITE_OMIT_COMPLETE
@ -255,6 +255,9 @@ int sqlite3_complete16(const void *zSql){
zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8); zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8);
if( zSql8 ){ if( zSql8 ){
rc = sqlite3_complete(zSql8); rc = sqlite3_complete(zSql8);
}else if( zSql ){
rc = SQLITE_NOMEM;
sqlite3MallocClearFailed();
} }
sqlite3ValueFree(pVal); sqlite3ValueFree(pVal);
return rc; return rc;

View File

@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be ** other files are for internal use by SQLite and should not be
** accessed by users of the library. ** 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" #include "sqliteInt.h"
@ -70,7 +70,6 @@ int sqlite3_exec(
nCol = sqlite3_column_count(pStmt); nCol = sqlite3_column_count(pStmt);
azCols = sqliteMalloc(2*nCol*sizeof(const char *)); azCols = sqliteMalloc(2*nCol*sizeof(const char *));
if( nCol && !azCols ){ if( nCol && !azCols ){
rc = SQLITE_NOMEM;
goto exec_out; goto exec_out;
} }
@ -124,7 +123,9 @@ exec_out:
if( sqlite3Tsd()->mallocFailed ){ if( sqlite3Tsd()->mallocFailed ){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
sqlite3MallocClearFailed();
} }
if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){ if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){
*pzErrMsg = malloc(1+strlen(sqlite3_errmsg(db))); *pzErrMsg = malloc(1+strlen(sqlite3_errmsg(db)));
if( *pzErrMsg ){ if( *pzErrMsg ){

View File

@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be ** other files are for internal use by SQLite and should not be
** accessed by users of the library. ** 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 "sqliteInt.h"
#include "os.h" #include "os.h"
@ -153,6 +153,9 @@ int sqlite3_close(sqlite3 *db){
return SQLITE_ERROR; return SQLITE_ERROR;
} }
/* sqlite3_close() may not invoke sqliteMalloc(). */
sqlite3MallocDisallow();
for(j=0; j<db->nDb; j++){ for(j=0; j<db->nDb; j++){
struct Db *pDb = &db->aDb[j]; struct Db *pDb = &db->aDb[j];
if( pDb->pBt ){ if( pDb->pBt ){
@ -186,6 +189,7 @@ int sqlite3_close(sqlite3 *db){
sqlite3ValueFree(db->pErr); sqlite3ValueFree(db->pErr);
} }
#if 0
#ifndef SQLITE_OMIT_GLOBALRECOVER #ifndef SQLITE_OMIT_GLOBALRECOVER
{ {
sqlite3 *pPrev; sqlite3 *pPrev;
@ -202,10 +206,12 @@ int sqlite3_close(sqlite3 *db){
} }
sqlite3Os.xLeaveMutex(); sqlite3Os.xLeaveMutex();
} }
#endif
#endif #endif
db->magic = SQLITE_MAGIC_ERROR; db->magic = SQLITE_MAGIC_ERROR;
sqliteFree(db); sqliteFree(db);
sqlite3MallocAllow();
return SQLITE_OK; return SQLITE_OK;
} }
@ -691,10 +697,11 @@ const void *sqlite3_errmsg16(sqlite3 *db){
#endif /* SQLITE_OMIT_UTF16 */ #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){ int sqlite3_errcode(sqlite3 *db){
if( sqlite3Tsd()->mallocFailed ){ if( !db || sqlite3Tsd()->mallocFailed ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
if( sqlite3SafetyCheck(db) ){ if( sqlite3SafetyCheck(db) ){
@ -716,6 +723,8 @@ static int openDatabase(
int rc, i; int rc, i;
CollSeq *pColl; CollSeq *pColl;
assert( !sqlite3Tsd()->mallocFailed );
/* Allocate the sqlite data structure */ /* Allocate the sqlite data structure */
db = sqliteMalloc( sizeof(sqlite3) ); db = sqliteMalloc( sizeof(sqlite3) );
if( db==0 ) goto opendb_out; if( db==0 ) goto opendb_out;
@ -741,8 +750,12 @@ static int openDatabase(
*/ */
if( sqlite3_create_collation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc) || if( sqlite3_create_collation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc) ||
sqlite3_create_collation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) || sqlite3_create_collation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) ||
(db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0))==0 ){ (db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0))==0
assert(rc!=SQLITE_OK || sqlite3Tsd()->mallocFailed); ){
/* 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; db->magic = SQLITE_MAGIC_CLOSED;
goto opendb_out; goto opendb_out;
} }
@ -785,19 +798,13 @@ static int openDatabase(
db->magic = SQLITE_MAGIC_OPEN; db->magic = SQLITE_MAGIC_OPEN;
opendb_out: opendb_out:
if( sqlite3_errcode(db)==SQLITE_OK && sqlite3Tsd()->mallocFailed ){ if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){
sqlite3Error(db, SQLITE_NOMEM, 0); sqlite3_close(db);
db = 0;
} }
*ppDb = db; *ppDb = db;
#ifndef SQLITE_OMIT_GLOBALRECOVER sqlite3MallocClearFailed();
if( db ){ return rc;
sqlite3Os.xEnterMutex();
db->pNext = pDbList;
pDbList = db;
sqlite3Os.xLeaveMutex();
}
#endif
return sqlite3_errcode(db);
} }
/* /*
@ -822,6 +829,7 @@ int sqlite3_open16(
int rc = SQLITE_NOMEM; int rc = SQLITE_NOMEM;
sqlite3_value *pVal; sqlite3_value *pVal;
assert( zFilename );
assert( ppDb ); assert( ppDb );
*ppDb = 0; *ppDb = 0;
pVal = sqlite3ValueNew(); pVal = sqlite3ValueNew();
@ -832,10 +840,11 @@ int sqlite3_open16(
if( rc==SQLITE_OK && *ppDb ){ if( rc==SQLITE_OK && *ppDb ){
rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0); rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
} }
}else{
assert( sqlite3Tsd()->mallocFailed );
sqlite3MallocClearFailed();
} }
if( pVal ){
sqlite3ValueFree(pVal); sqlite3ValueFree(pVal);
}
return rc; return rc;
} }
@ -1001,39 +1010,10 @@ int sqlite3_collation_needed16(
#ifndef SQLITE_OMIT_GLOBALRECOVER #ifndef SQLITE_OMIT_GLOBALRECOVER
/* /*
** This function is called to recover from a malloc failure that occured ** This function is now an anachronism. It used to be used to recover from a
** within SQLite. ** malloc() failure, but SQLite now does this automatically.
**
** 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.
*/ */
int sqlite3_global_recover(){ 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; return SQLITE_OK;
} }
#endif #endif

View File

@ -13,7 +13,7 @@
** interface, and routines that contribute to loading the database schema ** interface, and routines that contribute to loading the database schema
** from disk. ** 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 "sqliteInt.h"
#include "os.h" #include "os.h"
@ -443,12 +443,6 @@ int sqlite3_prepare(
if( sqlite3Tsd()->mallocFailed ){ if( sqlite3Tsd()->mallocFailed ){
sParse.rc = SQLITE_NOMEM; 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_DONE ) sParse.rc = SQLITE_OK;
if( sParse.rc!=SQLITE_OK && sParse.checkSchema && !schemaIsValid(db) ){ if( sParse.rc!=SQLITE_OK && sParse.checkSchema && !schemaIsValid(db) ){

View File

@ -12,7 +12,7 @@
** This header file defines the interface that the SQLite library ** This header file defines the interface that the SQLite library
** presents to client programs. ** 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_ #ifndef _SQLITE3_H_
#define _SQLITE3_H_ #define _SQLITE3_H_
@ -1276,6 +1276,21 @@ int sqlite3_get_autocommit(sqlite3*);
*/ */
sqlite3 *sqlite3_db_handle(sqlite3_stmt*); 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 ** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support. ** builds on processors without floating point support.

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** 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_ #ifndef _SQLITEINT_H_
#define _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; typedef struct SqliteTsd SqliteTsd;
struct SqliteTsd { struct SqliteTsd {
int mallocFailed; /* True after a malloc() has failed */ 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 #ifndef NDEBUG
int mallocAllowed; /* assert() in sqlite3Malloc() if not set */ int mallocAllowed; /* assert() in sqlite3Malloc() if not set */
#endif #endif

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** A TCL Interface to SQLite ** 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 */ #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", "copy", "errorcode", "eval",
"exists", "function", "last_insert_rowid", "exists", "function", "last_insert_rowid",
"nullvalue", "onecolumn", "profile", "nullvalue", "onecolumn", "profile",
"progress", "rekey", "timeout", "progress", "rekey", "soft_heap_limit",
"total_changes", "trace", "transaction", "timeout", "total_changes", "trace",
"version", 0 "transaction", "version", 0
}; };
enum DB_enum { enum DB_enum {
DB_AUTHORIZER, DB_BUSY, DB_CACHE, 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_COPY, DB_ERRORCODE, DB_EVAL,
DB_EXISTS, DB_FUNCTION, DB_LAST_INSERT_ROWID, DB_EXISTS, DB_FUNCTION, DB_LAST_INSERT_ROWID,
DB_NULLVALUE, DB_ONECOLUMN, DB_PROFILE, DB_NULLVALUE, DB_ONECOLUMN, DB_PROFILE,
DB_PROGRESS, DB_REKEY, DB_TIMEOUT, DB_PROGRESS, DB_REKEY, DB_SOFT_HEAP_LIMIT,
DB_TOTAL_CHANGES, DB_TRACE, DB_TRANSACTION, DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE,
DB_VERSION DB_TRANSACTION, DB_VERSION
}; };
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */ /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
@ -1706,6 +1706,26 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break; 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 ** $db total_changes
** **

View File

@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated ** is not included in the SQLite library. It is used for automated
** testing of the SQLite library. ** 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 "sqliteInt.h"
#include "tcl.h" #include "tcl.h"
@ -810,7 +810,6 @@ static int sqlite_malloc_fail(
} }
sqlite3_iMallocFail = n; sqlite3_iMallocFail = n;
sqlite3_iMallocReset = rep; sqlite3_iMallocReset = rep;
sqlite3Tsd()->mallocFailed = 0;
return TCL_OK; return TCL_OK;
} }
#endif #endif

View File

@ -14,7 +14,7 @@
** This file contains functions for allocating memory, comparing ** This file contains functions for allocating memory, comparing
** strings, and stuff like that. ** 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 "sqliteInt.h"
#include <stdarg.h> #include <stdarg.h>
@ -119,7 +119,7 @@ int sqlite3OsAllocationSize(void *p){
#define TESTALLOC_STACKSIZE 128 #define TESTALLOC_STACKSIZE 128
#define TESTALLOC_STACKFRAMES ((TESTALLOC_STACKSIZE-8)/sizeof(void*)) #define TESTALLOC_STACKFRAMES ((TESTALLOC_STACKSIZE-8)/sizeof(void*))
#else #else
#define backtrace(x, y) 0 #define backtrace(x, y)
#define TESTALLOC_STACKSIZE 0 #define TESTALLOC_STACKSIZE 0
#define TESTALLOC_STACKFRAMES 0 #define TESTALLOC_STACKFRAMES 0
#endif #endif
@ -137,7 +137,9 @@ int sqlite3OsAllocationSize(void *p){
#define TESTALLOC_FILESIZE 64 #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 #define TESTALLOC_USERSIZE 64
const char *sqlite3_malloc_id = 0; const char *sqlite3_malloc_id = 0;
@ -365,7 +367,14 @@ static void relinkAlloc(void *p)
/* /*
** This function sets the result of the Tcl interpreter passed as an argument ** 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 ** to a list containing an entry for each currently outstanding call made to
** sqliteMalloc and friends by the current thread. ** 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, ** Todo: We could have a version of this function that outputs to stdout,
** to debug memory leaks when Tcl is not available. ** to debug memory leaks when Tcl is not available.
@ -464,16 +473,46 @@ void OSMALLOC_FAILED(){
sqlite3Tsd()->isFail = 0; sqlite3Tsd()->isFail = 0;
} }
int OSSIZEOF(void *p){
if( p ){
return sqlite3OsAllocationSize(p) - TESTALLOC_OVERHEAD;
}
return 0;
}
#else #else
#define OSMALLOC(x) sqlite3OsMalloc(x) #define OSMALLOC(x) sqlite3OsMalloc(x)
#define OSREALLOC(x,y) sqlite3OsRealloc(x,y) #define OSREALLOC(x,y) sqlite3OsRealloc(x,y)
#define OSFREE(x) sqlite3OsFree(x) #define OSFREE(x) sqlite3OsFree(x)
#define OSSIZEOF(x) sqlite3OsAllocationSize(x)
#define OSMALLOC_FAILED() #define OSMALLOC_FAILED()
#endif #endif
/* /*
** End code for memory allocation system test layer. ** 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 ** Allocate and return N bytes of uninitialised memory by calling
** sqlite3OsMalloc(). If the Malloc() call fails, attempt to free memory ** sqlite3OsMalloc(). If the Malloc() call fails, attempt to free memory
@ -482,8 +521,8 @@ void OSMALLOC_FAILED(){
void *sqlite3MallocRaw(int n){ void *sqlite3MallocRaw(int n){
SqliteTsd *pTsd = sqlite3Tsd(); SqliteTsd *pTsd = sqlite3Tsd();
void *p = 0; void *p = 0;
if( n>0 && !pTsd->mallocFailed ){ if( n>0 && !pTsd->mallocFailed ){
handleSoftLimit(n);
while( !(p = OSMALLOC(n)) && sqlite3_release_memory(n) ); while( !(p = OSMALLOC(n)) && sqlite3_release_memory(n) );
if( !p ){ if( !p ){
sqlite3Tsd()->mallocFailed = 1; sqlite3Tsd()->mallocFailed = 1;
@ -508,6 +547,7 @@ void *sqlite3Realloc(void *p, int n){
return sqlite3Malloc(n); return sqlite3Malloc(n);
}else{ }else{
void *np = 0; void *np = 0;
handleSoftLimit(n - OSSIZEOF(p));
while( !(np = OSREALLOC(p, n)) && sqlite3_release_memory(n) ); while( !(np = OSREALLOC(p, n)) && sqlite3_release_memory(n) );
if( !np ){ if( !np ){
pTsd->mallocFailed = 1; pTsd->mallocFailed = 1;
@ -529,7 +569,7 @@ void sqlite3FreeX(void *p){
/* /*
** A version of sqliteMalloc() that is always a function, not a macro. ** 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){ void *sqlite3MallocX(int n){
return sqliteMalloc(n); return sqliteMalloc(n);
@ -1208,9 +1248,15 @@ void *sqlite3TextToPtr(const char *z){
/* /*
** Return a pointer to the SqliteTsd associated with the calling thread. ** Return a pointer to the SqliteTsd associated with the calling thread.
** TODO: Actually return thread-specific-data instead of this global pointer.
*/ */
SqliteTsd *sqlite3Tsd(){
static SqliteTsd tsd = { static SqliteTsd tsd = {
0 /* mallocFailed flag */ 0 /* mallocFailed flag */
#ifndef SQLITE_OMIT_SOFTHEAPLIMIT
, 0xFFFFFFFF /* nSoftHeapLimit */
, 0 /* nAlloc */
#endif
#ifndef NDEBUG #ifndef NDEBUG
, 1 /* mallocAllowed flag */ , 1 /* mallocAllowed flag */
#endif #endif
@ -1221,14 +1267,33 @@ static SqliteTsd tsd = {
, 0 , 0
#endif #endif
}; };
SqliteTsd *sqlite3Tsd(){
return &tsd; return &tsd;
} }
/*
** Clear the "mallocFailed" flag. This should be invoked before exiting any
** entry points that may have called sqliteMalloc().
*/
void sqlite3MallocClearFailed(){ void sqlite3MallocClearFailed(){
sqlite3Tsd()->mallocFailed = 0; 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 #ifndef NDEBUG
/* /*
** This function sets a flag in the thread-specific-data structure that will ** This function sets a flag in the thread-specific-data structure that will

View File

@ -15,7 +15,7 @@
# interface is pretty well tested. This file contains some addition # interface is pretty well tested. This file contains some addition
# tests for fringe issues that the main test suite does not cover. # 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] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -34,7 +34,7 @@ do_test tcl-1.1 {
do_test tcl-1.2 { do_test tcl-1.2 {
set v [catch {db bogus} msg] set v [catch {db bogus} msg]
lappend v $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 { do_test tcl-1.3 {
execsql {CREATE TABLE t1(a int, b int)} execsql {CREATE TABLE t1(a int, b int)}
execsql {INSERT INTO t1 VALUES(10,20)} execsql {INSERT INTO t1 VALUES(10,20)}
@ -110,27 +110,27 @@ do_test tcl-1.15 {
set v [catch {db function} msg] set v [catch {db function} msg]
lappend v $msg lappend v $msg
} {1 {wrong # args: should be "db function NAME SCRIPT"}} } {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] set v [catch {db last_insert_rowid xyz} msg]
lappend v $msg lappend v $msg
} {1 {wrong # args: should be "db last_insert_rowid "}} } {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] set v [catch {db rekey} msg]
lappend v $msg lappend v $msg
} {1 {wrong # args: should be "db rekey KEY"}} } {1 {wrong # args: should be "db rekey KEY"}}
do_test tcl-1.16 { do_test tcl-1.18 {
set v [catch {db timeout} msg] set v [catch {db timeout} msg]
lappend v $msg lappend v $msg
} {1 {wrong # args: should be "db timeout MILLISECONDS"}} } {1 {wrong # args: should be "db timeout MILLISECONDS"}}
do_test tcl-1.17 { do_test tcl-1.19 {
set v [catch {db collate} msg] set v [catch {db collate} msg]
lappend v $msg lappend v $msg
} {1 {wrong # args: should be "db collate NAME SCRIPT"}} } {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] set v [catch {db collation_needed} msg]
lappend v $msg lappend v $msg
} {1 {wrong # args: should be "db collation_needed SCRIPT"}} } {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] set v [catch {db total_changes xyz} msg]
lappend v $msg lappend v $msg
} {1 {wrong # args: should be "db total_changes "}} } {1 {wrong # args: should be "db total_changes "}}