Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -2593,10 +2593,11 @@ SQLITE_MAX_ATTACHED, SQLITE_MAX_LIKE_PATTERN_LENGTH, SQLITE_MAX_VARIABLE_NUMBER, /* IMP: R-38091-32352 */ SQLITE_MAX_TRIGGER_DEPTH, SQLITE_MAX_WORKER_THREADS, + SQLITE_MAX_HEAP_K, }; /* ** Make sure the hard limits are set to reasonable values */ @@ -2671,11 +2672,12 @@ assert( aHardLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]== SQLITE_MAX_LIKE_PATTERN_LENGTH ); assert( aHardLimit[SQLITE_LIMIT_VARIABLE_NUMBER]==SQLITE_MAX_VARIABLE_NUMBER); assert( aHardLimit[SQLITE_LIMIT_TRIGGER_DEPTH]==SQLITE_MAX_TRIGGER_DEPTH ); assert( aHardLimit[SQLITE_LIMIT_WORKER_THREADS]==SQLITE_MAX_WORKER_THREADS ); - assert( SQLITE_LIMIT_WORKER_THREADS==(SQLITE_N_LIMIT-1) ); + assert( aHardLimit[SQLITE_LIMIT_HEAP_K]==SQLITE_MAX_HEAP_K ); + assert( SQLITE_LIMIT_WORKER_THREADS==(SQLITE_N_LIMIT-2) ); if( limitId<0 || limitId>=SQLITE_N_LIMIT ){ return -1; } @@ -3066,10 +3068,11 @@ db->nDb = 2; db->magic = SQLITE_MAGIC_BUSY; db->aDb = db->aDbStatic; db->lookaside.bDisable = 1; db->lookaside.sz = 0; + db->nMemUsed = 0; assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); db->aLimit[SQLITE_LIMIT_WORKER_THREADS] = SQLITE_DEFAULT_WORKER_THREADS; db->autoCommit = 1; Index: src/malloc.c ================================================================== --- src/malloc.c +++ src/malloc.c @@ -330,10 +330,19 @@ ** *db->pnBytesFreed. */ static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){ *db->pnBytesFreed += sqlite3DbMallocSize(db,p); } + +static SQLITE_NOINLINE void sqlite3DbFreeTail(sqlite3 *db, void *p){ + db->nMemUsed -= sqlite3MallocSize(p); + assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); + sqlite3MemdebugSetType(p, MEMTYPE_HEAP); + sqlite3_free(p); +} /* ** Free memory that might be associated with a particular database ** connection. Calling sqlite3DbFree(D,X) for X==0 is a harmless no-op. ** The sqlite3DbFreeNN(D,X) version requires that X be non-NULL. @@ -354,10 +363,12 @@ #endif pBuf->pNext = db->lookaside.pFree; db->lookaside.pFree = pBuf; return; } + sqlite3DbFreeTail(db, p); + return; } assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); @@ -467,13 +478,22 @@ */ static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){ void *p; assert( db!=0 ); p = sqlite3Malloc(n); - if( !p ) sqlite3OomFault(db); - sqlite3MemdebugSetType(p, + if( p==0 ){ + sqlite3OomFault(db); + }else{ + sqlite3MemdebugSetType(p, (db->lookaside.bDisable==0) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP); + db->nMemUsed += sqlite3MallocSize(p); + if( db->nMemUsed > 1024*(i64)db->aLimit[SQLITE_LIMIT_HEAP_K] ){ + sqlite3DbFreeNN(db, p); + p = 0; + sqlite3OomFault(db); + } + } return p; } /* ** Allocate memory, either lookaside (if possible) or heap. Index: src/shell.c.in ================================================================== --- src/shell.c.in +++ src/shell.c.in @@ -7893,10 +7893,11 @@ { "attached", SQLITE_LIMIT_ATTACHED }, { "like_pattern_length", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, { "variable_number", SQLITE_LIMIT_VARIABLE_NUMBER }, { "trigger_depth", SQLITE_LIMIT_TRIGGER_DEPTH }, { "worker_threads", SQLITE_LIMIT_WORKER_THREADS }, + { "heap_k", SQLITE_LIMIT_HEAP_K }, }; int i, n2; open_db(p, 0); if( nArg==1 ){ for(i=0; iThe maximum depth of recursion for triggers.)^ ** ** [[SQLITE_LIMIT_WORKER_THREADS]] ^(
SQLITE_LIMIT_WORKER_THREADS
**
The maximum number of auxiliary worker threads that a single ** [prepared statement] may start.
)^ +** +** [[SQLITE_LIMIT_HEAP_K]] ^(
SQLITE_LIMIT_HEAP_K
+**
The maximum number of kibibytes (one kibibyte is 1024 bytes) that +** an individual [database connection] is allowed to allocate.)^ ** */ #define SQLITE_LIMIT_LENGTH 0 #define SQLITE_LIMIT_SQL_LENGTH 1 #define SQLITE_LIMIT_COLUMN 2 @@ -3717,10 +3721,11 @@ #define SQLITE_LIMIT_ATTACHED 7 #define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8 #define SQLITE_LIMIT_VARIABLE_NUMBER 9 #define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_WORKER_THREADS 11 +#define SQLITE_LIMIT_HEAP_K 12 /* ** CAPI3REF: Prepare Flags ** ** These constants define various flags that can be passed into Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -1248,11 +1248,11 @@ /* ** The number of different kinds of things that can be limited ** using the sqlite3_limit() interface. */ -#define SQLITE_N_LIMIT (SQLITE_LIMIT_WORKER_THREADS+1) +#define SQLITE_N_LIMIT (SQLITE_LIMIT_HEAP_K+1) /* ** Lookaside malloc is a set of fixed-size buffers that can be used ** to satisfy small transient memory allocation requests for objects ** associated with a particular database connection. The use of @@ -1415,10 +1415,11 @@ int nVdbeRead; /* Number of active VDBEs that read or write */ int nVdbeWrite; /* Number of active VDBEs that read and write */ int nVdbeExec; /* Number of nested calls to VdbeExec() */ int nVDestroy; /* Number of active OP_VDestroy operations */ int nExtension; /* Number of loaded extensions */ + i64 nMemUsed; /* Memory used by this database connection */ void **aExtension; /* Array of shared library handles */ int (*xTrace)(u32,void*,void*,void*); /* Trace function */ void *pTraceArg; /* Argument to the trace function */ #ifndef SQLITE_OMIT_DEPRECATED void (*xProfile)(void*,const char*,u64); /* Profiling function */ Index: src/sqliteLimit.h ================================================================== --- src/sqliteLimit.h +++ src/sqliteLimit.h @@ -207,5 +207,16 @@ ** may be executed. */ #ifndef SQLITE_MAX_TRIGGER_DEPTH # define SQLITE_MAX_TRIGGER_DEPTH 1000 #endif + +/* +** Maximum number of kibibytes (1 kibibyte == 1024 bytes) that a single +** database connection is allowed to allocate. Memory allocations that +** are percipitated by a database conection but are not directly attached +** to a database connection (such as memory used for the page cache) are +** not counted toward this limit. +*/ +#ifndef SQLITE_MAX_HEAP_K +# define SQLITE_MAX_HEAP_K 1048576 +#endif Index: src/test1.c ================================================================== --- src/test1.c +++ src/test1.c @@ -6325,10 +6325,11 @@ { "SQLITE_LIMIT_ATTACHED", SQLITE_LIMIT_ATTACHED }, { "SQLITE_LIMIT_LIKE_PATTERN_LENGTH", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, { "SQLITE_LIMIT_VARIABLE_NUMBER", SQLITE_LIMIT_VARIABLE_NUMBER }, { "SQLITE_LIMIT_TRIGGER_DEPTH", SQLITE_LIMIT_TRIGGER_DEPTH }, { "SQLITE_LIMIT_WORKER_THREADS", SQLITE_LIMIT_WORKER_THREADS }, + { "SQLITE_LIMIT_HEAP_K", SQLITE_LIMIT_HEAP_K }, /* Out of range test cases */ { "SQLITE_LIMIT_TOOSMALL", -1, }, { "SQLITE_LIMIT_TOOBIG", SQLITE_LIMIT_WORKER_THREADS+1 }, };