Index: src/main.c
==================================================================
--- src/main.c
+++ src/main.c
@@ -512,10 +512,17 @@
if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE;
if( szMmap>mxMmap) szMmap = mxMmap;
sqlite3GlobalConfig.szMmap = szMmap;
break;
}
+
+#if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC)
+ case SQLITE_CONFIG_WIN32_HEAPSIZE: {
+ sqlite3GlobalConfig.nHeap = va_arg(ap, int);
+ break;
+ }
+#endif
default: {
rc = SQLITE_ERROR;
break;
}
Index: src/os_win.c
==================================================================
--- src/os_win.c
+++ src/os_win.c
@@ -1399,18 +1399,24 @@
assert( pWinMemData->magic1==WINMEM_MAGIC1 );
assert( pWinMemData->magic2==WINMEM_MAGIC2 );
#if !SQLITE_OS_WINRT && SQLITE_WIN32_HEAP_CREATE
if( !pWinMemData->hHeap ){
+ DWORD dwInitialSize = SQLITE_WIN32_HEAP_INIT_SIZE;
+ DWORD dwMaximumSize = (DWORD)sqlite3GlobalConfig.nHeap;
+ if( dwMaximumSize==0 ){
+ dwMaximumSize = SQLITE_WIN32_HEAP_MAX_SIZE;
+ }else if( dwInitialSize>dwMaximumSize ){
+ dwInitialSize = dwMaximumSize;
+ }
pWinMemData->hHeap = osHeapCreate(SQLITE_WIN32_HEAP_FLAGS,
- SQLITE_WIN32_HEAP_INIT_SIZE,
- SQLITE_WIN32_HEAP_MAX_SIZE);
+ dwInitialSize, dwMaximumSize);
if( !pWinMemData->hHeap ){
sqlite3_log(SQLITE_NOMEM,
- "failed to HeapCreate (%lu), flags=%u, initSize=%u, maxSize=%u",
- osGetLastError(), SQLITE_WIN32_HEAP_FLAGS,
- SQLITE_WIN32_HEAP_INIT_SIZE, SQLITE_WIN32_HEAP_MAX_SIZE);
+ "failed to HeapCreate (%lu), flags=%u, initSize=%lu, maxSize=%lu",
+ osGetLastError(), SQLITE_WIN32_HEAP_FLAGS, dwInitialSize,
+ dwMaximumSize);
return SQLITE_NOMEM;
}
pWinMemData->bOwned = TRUE;
assert( pWinMemData->bOwned );
}
Index: src/sqlite.h.in
==================================================================
--- src/sqlite.h.in
+++ src/sqlite.h.in
@@ -1680,10 +1680,17 @@
** cannot be changed at run-time. Nor may the maximum allowed mmap size
** exceed the compile-time maximum mmap size set by the
** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^
** ^If either argument to this option is negative, then that argument is
** changed to its compile-time default.
+**
+** [[SQLITE_CONFIG_WIN32_HEAPSIZE]]
+**
SQLITE_CONFIG_WIN32_HEAPSIZE
+** ^This option is only available if SQLite is compiled for Windows
+** with the [SQLITE_WIN32_MALLOC] pre-processor macro defined.
+** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
+** that specifies the maximum size of the heap.
**
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
@@ -1704,10 +1711,11 @@
#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
+#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
/*
** CAPI3REF: Database Connection Configuration Options
**
** These constants are the available integer configuration options that
Index: src/test_config.c
==================================================================
--- src/test_config.c
+++ src/test_config.c
@@ -60,10 +60,16 @@
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
Tcl_SetVar2(interp, "sqlite_options", "curdir", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "curdir", "0", TCL_GLOBAL_ONLY);
#endif
+
+#ifdef SQLITE_WIN32_MALLOC
+ Tcl_SetVar2(interp, "sqlite_options", "win32malloc", "1", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "win32malloc", "0", TCL_GLOBAL_ONLY);
+#endif
#ifdef SQLITE_DEBUG
Tcl_SetVar2(interp, "sqlite_options", "debug", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "debug", "0", TCL_GLOBAL_ONLY);
Index: src/test_malloc.c
==================================================================
--- src/test_malloc.c
+++ src/test_malloc.c
@@ -1127,10 +1127,37 @@
}
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
return TCL_OK;
}
+
+/*
+** Usage: sqlite3_config_heap_size NBYTE
+*/
+static int test_config_heap_size(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ int nByte; /* Size to pass to sqlite3_config() */
+ int rc; /* Return code of sqlite3_config() */
+
+ Tcl_Obj * CONST *aArg = &objv[1];
+ int nArg = objc-1;
+
+ if( nArg!=1 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "NBYTE");
+ return TCL_ERROR;
+ }
+ if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
+
+ rc = sqlite3_config(SQLITE_CONFIG_WIN32_HEAPSIZE, nByte);
+
+ Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
+ return TCL_OK;
+}
/*
** Usage: sqlite3_config_error [DB]
**
** Invoke sqlite3_config() or sqlite3_db_config() with invalid
@@ -1471,10 +1498,11 @@
{ "sqlite3_config_alt_pcache", test_alt_pcache ,0 },
{ "sqlite3_status", test_status ,0 },
{ "sqlite3_db_status", test_db_status ,0 },
{ "install_malloc_faultsim", test_install_malloc_faultsim ,0 },
{ "sqlite3_config_heap", test_config_heap ,0 },
+ { "sqlite3_config_heap_size", test_config_heap_size ,0 },
{ "sqlite3_config_memstatus", test_config_memstatus ,0 },
{ "sqlite3_config_lookaside", test_config_lookaside ,0 },
{ "sqlite3_config_error", test_config_error ,0 },
{ "sqlite3_config_uri", test_config_uri ,0 },
{ "sqlite3_config_cis", test_config_cis ,0 },
ADDED test/win32heap.test
Index: test/win32heap.test
==================================================================
--- /dev/null
+++ test/win32heap.test
@@ -0,0 +1,74 @@
+# 2013 November 22
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library. The
+# focus of this script is recovery from transient manditory locks
+# that sometimes appear on database files due to anti-virus software.
+#
+
+if {$tcl_platform(platform)!="windows"} return
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+ifcapable !win32malloc {
+ finish_test
+ return
+}
+
+set testprefix win32heap
+
+do_test 1.1 {
+ catch {db close}
+ sqlite3_shutdown
+ sqlite3_config_heap_size 1048576
+ sqlite3_initialize
+} {SQLITE_OK}
+
+do_test 1.2 {
+ sqlite3 db test.db
+ catchsql {
+ CREATE TABLE t1(x);
+ }
+} {0 {}}
+
+do_test 1.3 {
+ catchsql {
+ INSERT INTO t1 (x) VALUES(RANDOMBLOB(1048576));
+ }
+} {1 {out of memory}}
+
+do_test 1.4 {
+ catchsql {
+ SELECT COUNT(*) FROM t1;
+ }
+} {0 0}
+
+do_test 1.5 {
+ catch {db close}
+ sqlite3_shutdown
+ sqlite3_config_heap_size 0
+ sqlite3_initialize
+} {SQLITE_OK}
+
+do_test 1.6 {
+ sqlite3 db test.db
+ catchsql {
+ INSERT INTO t1 (x) VALUES(RANDOMBLOB(1048576));
+ }
+} {0 {}}
+
+do_test 1.7 {
+ catchsql {
+ SELECT COUNT(*) FROM t1;
+ }
+} {0 1}
+
+finish_test