Add the SQLITE_DBCONFIG_RESET_DATABASE control for resetting a corrupt
[sqlite.git] / src / test_malloc.c
blob33bc3807bad320564fd3f1e97b533e7e03384fe3
1 /*
2 ** 2007 August 15
3 **
4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
6 **
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
13 ** This file contains code used to implement test interfaces to the
14 ** memory allocation subsystem.
16 #include "sqliteInt.h"
17 #if defined(INCLUDE_SQLITE_TCL_H)
18 # include "sqlite_tcl.h"
19 #else
20 # include "tcl.h"
21 #endif
22 #include <stdlib.h>
23 #include <string.h>
24 #include <assert.h>
27 ** This structure is used to encapsulate the global state variables used
28 ** by malloc() fault simulation.
30 static struct MemFault {
31 int iCountdown; /* Number of pending successes before a failure */
32 int nRepeat; /* Number of times to repeat the failure */
33 int nBenign; /* Number of benign failures seen since last config */
34 int nFail; /* Number of failures seen since last config */
35 u8 enable; /* True if enabled */
36 int isInstalled; /* True if the fault simulation layer is installed */
37 int isBenignMode; /* True if malloc failures are considered benign */
38 sqlite3_mem_methods m; /* 'Real' malloc implementation */
39 } memfault;
42 ** This routine exists as a place to set a breakpoint that will
43 ** fire on any simulated malloc() failure.
45 static void sqlite3Fault(void){
46 static int cnt = 0;
47 cnt++;
51 ** Check to see if a fault should be simulated. Return true to simulate
52 ** the fault. Return false if the fault should not be simulated.
54 static int faultsimStep(void){
55 if( likely(!memfault.enable) ){
56 return 0;
58 if( memfault.iCountdown>0 ){
59 memfault.iCountdown--;
60 return 0;
62 sqlite3Fault();
63 memfault.nFail++;
64 if( memfault.isBenignMode>0 ){
65 memfault.nBenign++;
67 memfault.nRepeat--;
68 if( memfault.nRepeat<=0 ){
69 memfault.enable = 0;
71 return 1;
75 ** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation
76 ** logic.
78 static void *faultsimMalloc(int n){
79 void *p = 0;
80 if( !faultsimStep() ){
81 p = memfault.m.xMalloc(n);
83 return p;
88 ** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation
89 ** logic.
91 static void *faultsimRealloc(void *pOld, int n){
92 void *p = 0;
93 if( !faultsimStep() ){
94 p = memfault.m.xRealloc(pOld, n);
96 return p;
99 /*
100 ** The following method calls are passed directly through to the underlying
101 ** malloc system:
103 ** xFree
104 ** xSize
105 ** xRoundup
106 ** xInit
107 ** xShutdown
109 static void faultsimFree(void *p){
110 memfault.m.xFree(p);
112 static int faultsimSize(void *p){
113 return memfault.m.xSize(p);
115 static int faultsimRoundup(int n){
116 return memfault.m.xRoundup(n);
118 static int faultsimInit(void *p){
119 return memfault.m.xInit(memfault.m.pAppData);
121 static void faultsimShutdown(void *p){
122 memfault.m.xShutdown(memfault.m.pAppData);
126 ** This routine configures the malloc failure simulation. After
127 ** calling this routine, the next nDelay mallocs will succeed, followed
128 ** by a block of nRepeat failures, after which malloc() calls will begin
129 ** to succeed again.
131 static void faultsimConfig(int nDelay, int nRepeat){
132 memfault.iCountdown = nDelay;
133 memfault.nRepeat = nRepeat;
134 memfault.nBenign = 0;
135 memfault.nFail = 0;
136 memfault.enable = nDelay>=0;
138 /* Sometimes, when running multi-threaded tests, the isBenignMode
139 ** variable is not properly incremented/decremented so that it is
140 ** 0 when not inside a benign malloc block. This doesn't affect
141 ** the multi-threaded tests, as they do not use this system. But
142 ** it does affect OOM tests run later in the same process. So
143 ** zero the variable here, just to be sure.
145 memfault.isBenignMode = 0;
149 ** Return the number of faults (both hard and benign faults) that have
150 ** occurred since the injector was last configured.
152 static int faultsimFailures(void){
153 return memfault.nFail;
157 ** Return the number of benign faults that have occurred since the
158 ** injector was last configured.
160 static int faultsimBenignFailures(void){
161 return memfault.nBenign;
165 ** Return the number of successes that will occur before the next failure.
166 ** If no failures are scheduled, return -1.
168 static int faultsimPending(void){
169 if( memfault.enable ){
170 return memfault.iCountdown;
171 }else{
172 return -1;
177 static void faultsimBeginBenign(void){
178 memfault.isBenignMode++;
180 static void faultsimEndBenign(void){
181 memfault.isBenignMode--;
185 ** Add or remove the fault-simulation layer using sqlite3_config(). If
186 ** the argument is non-zero, the
188 static int faultsimInstall(int install){
189 static struct sqlite3_mem_methods m = {
190 faultsimMalloc, /* xMalloc */
191 faultsimFree, /* xFree */
192 faultsimRealloc, /* xRealloc */
193 faultsimSize, /* xSize */
194 faultsimRoundup, /* xRoundup */
195 faultsimInit, /* xInit */
196 faultsimShutdown, /* xShutdown */
197 0 /* pAppData */
199 int rc;
201 install = (install ? 1 : 0);
202 assert(memfault.isInstalled==1 || memfault.isInstalled==0);
204 if( install==memfault.isInstalled ){
205 return SQLITE_ERROR;
208 if( install ){
209 rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);
210 assert(memfault.m.xMalloc);
211 if( rc==SQLITE_OK ){
212 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
214 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
215 faultsimBeginBenign, faultsimEndBenign
217 }else{
218 sqlite3_mem_methods m2;
219 assert(memfault.m.xMalloc);
221 /* One should be able to reset the default memory allocator by storing
222 ** a zeroed allocator then calling GETMALLOC. */
223 memset(&m2, 0, sizeof(m2));
224 sqlite3_config(SQLITE_CONFIG_MALLOC, &m2);
225 sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m2);
226 assert( memcmp(&m2, &memfault.m, sizeof(m2))==0 );
228 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m);
229 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
230 (void*)0, (void*)0);
233 if( rc==SQLITE_OK ){
234 memfault.isInstalled = 1;
236 return rc;
239 #ifdef SQLITE_TEST
242 ** This function is implemented in main.c. Returns a pointer to a static
243 ** buffer containing the symbolic SQLite error code that corresponds to
244 ** the least-significant 8-bits of the integer passed as an argument.
245 ** For example:
247 ** sqlite3ErrName(1) -> "SQLITE_ERROR"
249 extern const char *sqlite3ErrName(int);
252 ** Transform pointers to text and back again
254 static void pointerToText(void *p, char *z){
255 static const char zHex[] = "0123456789abcdef";
256 int i, k;
257 unsigned int u;
258 sqlite3_uint64 n;
259 if( p==0 ){
260 strcpy(z, "0");
261 return;
263 if( sizeof(n)==sizeof(p) ){
264 memcpy(&n, &p, sizeof(p));
265 }else if( sizeof(u)==sizeof(p) ){
266 memcpy(&u, &p, sizeof(u));
267 n = u;
268 }else{
269 assert( 0 );
271 for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
272 z[k] = zHex[n&0xf];
273 n >>= 4;
275 z[sizeof(p)*2] = 0;
277 static int hexToInt(int h){
278 if( h>='0' && h<='9' ){
279 return h - '0';
280 }else if( h>='a' && h<='f' ){
281 return h - 'a' + 10;
282 }else{
283 return -1;
286 static int textToPointer(const char *z, void **pp){
287 sqlite3_uint64 n = 0;
288 int i;
289 unsigned int u;
290 for(i=0; i<sizeof(void*)*2 && z[0]; i++){
291 int v;
292 v = hexToInt(*z++);
293 if( v<0 ) return TCL_ERROR;
294 n = n*16 + v;
296 if( *z!=0 ) return TCL_ERROR;
297 if( sizeof(n)==sizeof(*pp) ){
298 memcpy(pp, &n, sizeof(n));
299 }else if( sizeof(u)==sizeof(*pp) ){
300 u = (unsigned int)n;
301 memcpy(pp, &u, sizeof(u));
302 }else{
303 assert( 0 );
305 return TCL_OK;
309 ** Usage: sqlite3_malloc NBYTES
311 ** Raw test interface for sqlite3_malloc().
313 static int SQLITE_TCLAPI test_malloc(
314 void * clientData,
315 Tcl_Interp *interp,
316 int objc,
317 Tcl_Obj *CONST objv[]
319 int nByte;
320 void *p;
321 char zOut[100];
322 if( objc!=2 ){
323 Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
324 return TCL_ERROR;
326 if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
327 p = sqlite3_malloc((unsigned)nByte);
328 pointerToText(p, zOut);
329 Tcl_AppendResult(interp, zOut, NULL);
330 return TCL_OK;
334 ** Usage: sqlite3_realloc PRIOR NBYTES
336 ** Raw test interface for sqlite3_realloc().
338 static int SQLITE_TCLAPI test_realloc(
339 void * clientData,
340 Tcl_Interp *interp,
341 int objc,
342 Tcl_Obj *CONST objv[]
344 int nByte;
345 void *pPrior, *p;
346 char zOut[100];
347 if( objc!=3 ){
348 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
349 return TCL_ERROR;
351 if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
352 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
353 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
354 return TCL_ERROR;
356 p = sqlite3_realloc(pPrior, (unsigned)nByte);
357 pointerToText(p, zOut);
358 Tcl_AppendResult(interp, zOut, NULL);
359 return TCL_OK;
363 ** Usage: sqlite3_free PRIOR
365 ** Raw test interface for sqlite3_free().
367 static int SQLITE_TCLAPI test_free(
368 void * clientData,
369 Tcl_Interp *interp,
370 int objc,
371 Tcl_Obj *CONST objv[]
373 void *pPrior;
374 if( objc!=2 ){
375 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
376 return TCL_ERROR;
378 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
379 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
380 return TCL_ERROR;
382 sqlite3_free(pPrior);
383 return TCL_OK;
387 ** These routines are in test_hexio.c
389 int sqlite3TestHexToBin(const char *, int, char *);
390 int sqlite3TestBinToHex(char*,int);
393 ** Usage: memset ADDRESS SIZE HEX
395 ** Set a chunk of memory (obtained from malloc, probably) to a
396 ** specified hex pattern.
398 static int SQLITE_TCLAPI test_memset(
399 void * clientData,
400 Tcl_Interp *interp,
401 int objc,
402 Tcl_Obj *CONST objv[]
404 void *p;
405 int size, n, i;
406 char *zHex;
407 char *zOut;
408 char zBin[100];
410 if( objc!=4 ){
411 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
412 return TCL_ERROR;
414 if( textToPointer(Tcl_GetString(objv[1]), &p) ){
415 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
416 return TCL_ERROR;
418 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
419 return TCL_ERROR;
421 if( size<=0 ){
422 Tcl_AppendResult(interp, "size must be positive", (char*)0);
423 return TCL_ERROR;
425 zHex = Tcl_GetStringFromObj(objv[3], &n);
426 if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
427 n = sqlite3TestHexToBin(zHex, n, zBin);
428 if( n==0 ){
429 Tcl_AppendResult(interp, "no data", (char*)0);
430 return TCL_ERROR;
432 zOut = p;
433 for(i=0; i<size; i++){
434 zOut[i] = zBin[i%n];
436 return TCL_OK;
440 ** Usage: memget ADDRESS SIZE
442 ** Return memory as hexadecimal text.
444 static int SQLITE_TCLAPI test_memget(
445 void * clientData,
446 Tcl_Interp *interp,
447 int objc,
448 Tcl_Obj *CONST objv[]
450 void *p;
451 int size, n;
452 char *zBin;
453 char zHex[100];
455 if( objc!=3 ){
456 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");
457 return TCL_ERROR;
459 if( textToPointer(Tcl_GetString(objv[1]), &p) ){
460 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
461 return TCL_ERROR;
463 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
464 return TCL_ERROR;
466 if( size<=0 ){
467 Tcl_AppendResult(interp, "size must be positive", (char*)0);
468 return TCL_ERROR;
470 zBin = p;
471 while( size>0 ){
472 if( size>(sizeof(zHex)-1)/2 ){
473 n = (sizeof(zHex)-1)/2;
474 }else{
475 n = size;
477 memcpy(zHex, zBin, n);
478 zBin += n;
479 size -= n;
480 sqlite3TestBinToHex(zHex, n);
481 Tcl_AppendResult(interp, zHex, (char*)0);
483 return TCL_OK;
487 ** Usage: sqlite3_memory_used
489 ** Raw test interface for sqlite3_memory_used().
491 static int SQLITE_TCLAPI test_memory_used(
492 void * clientData,
493 Tcl_Interp *interp,
494 int objc,
495 Tcl_Obj *CONST objv[]
497 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
498 return TCL_OK;
502 ** Usage: sqlite3_memory_highwater ?RESETFLAG?
504 ** Raw test interface for sqlite3_memory_highwater().
506 static int SQLITE_TCLAPI test_memory_highwater(
507 void * clientData,
508 Tcl_Interp *interp,
509 int objc,
510 Tcl_Obj *CONST objv[]
512 int resetFlag = 0;
513 if( objc!=1 && objc!=2 ){
514 Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
515 return TCL_ERROR;
517 if( objc==2 ){
518 if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
520 Tcl_SetObjResult(interp,
521 Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
522 return TCL_OK;
526 ** Usage: sqlite3_memdebug_backtrace DEPTH
528 ** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined
529 ** then this routine is a no-op.
531 static int SQLITE_TCLAPI test_memdebug_backtrace(
532 void * clientData,
533 Tcl_Interp *interp,
534 int objc,
535 Tcl_Obj *CONST objv[]
537 int depth;
538 if( objc!=2 ){
539 Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
540 return TCL_ERROR;
542 if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
543 #ifdef SQLITE_MEMDEBUG
545 extern void sqlite3MemdebugBacktrace(int);
546 sqlite3MemdebugBacktrace(depth);
548 #endif
549 return TCL_OK;
553 ** Usage: sqlite3_memdebug_dump FILENAME
555 ** Write a summary of unfreed memory to FILENAME.
557 static int SQLITE_TCLAPI test_memdebug_dump(
558 void * clientData,
559 Tcl_Interp *interp,
560 int objc,
561 Tcl_Obj *CONST objv[]
563 if( objc!=2 ){
564 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
565 return TCL_ERROR;
567 #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
568 || defined(SQLITE_POW2_MEMORY_SIZE)
570 extern void sqlite3MemdebugDump(const char*);
571 sqlite3MemdebugDump(Tcl_GetString(objv[1]));
573 #endif
574 return TCL_OK;
578 ** Usage: sqlite3_memdebug_malloc_count
580 ** Return the total number of times malloc() has been called.
582 static int SQLITE_TCLAPI test_memdebug_malloc_count(
583 void * clientData,
584 Tcl_Interp *interp,
585 int objc,
586 Tcl_Obj *CONST objv[]
588 int nMalloc = -1;
589 if( objc!=1 ){
590 Tcl_WrongNumArgs(interp, 1, objv, "");
591 return TCL_ERROR;
593 #if defined(SQLITE_MEMDEBUG)
595 extern int sqlite3MemdebugMallocCount();
596 nMalloc = sqlite3MemdebugMallocCount();
598 #endif
599 Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));
600 return TCL_OK;
605 ** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS?
607 ** where options are:
609 ** -repeat <count>
610 ** -benigncnt <varname>
612 ** Arrange for a simulated malloc() failure after COUNTER successes.
613 ** If a repeat count is specified, the fault is repeated that many
614 ** times.
616 ** Each call to this routine overrides the prior counter value.
617 ** This routine returns the number of simulated failures that have
618 ** happened since the previous call to this routine.
620 ** To disable simulated failures, use a COUNTER of -1.
622 static int SQLITE_TCLAPI test_memdebug_fail(
623 void * clientData,
624 Tcl_Interp *interp,
625 int objc,
626 Tcl_Obj *CONST objv[]
628 int ii;
629 int iFail;
630 int nRepeat = 1;
631 Tcl_Obj *pBenignCnt = 0;
632 int nBenign;
633 int nFail = 0;
635 if( objc<2 ){
636 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
637 return TCL_ERROR;
639 if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
641 for(ii=2; ii<objc; ii+=2){
642 int nOption;
643 char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
644 char *zErr = 0;
646 if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
647 if( ii==(objc-1) ){
648 zErr = "option requires an argument: ";
649 }else{
650 if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){
651 return TCL_ERROR;
654 }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){
655 if( ii==(objc-1) ){
656 zErr = "option requires an argument: ";
657 }else{
658 pBenignCnt = objv[ii+1];
660 }else{
661 zErr = "unknown option: ";
664 if( zErr ){
665 Tcl_AppendResult(interp, zErr, zOption, 0);
666 return TCL_ERROR;
670 nBenign = faultsimBenignFailures();
671 nFail = faultsimFailures();
672 faultsimConfig(iFail, nRepeat);
674 if( pBenignCnt ){
675 Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);
677 Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
678 return TCL_OK;
682 ** Usage: sqlite3_memdebug_pending
684 ** Return the number of malloc() calls that will succeed before a
685 ** simulated failure occurs. A negative return value indicates that
686 ** no malloc() failure is scheduled.
688 static int SQLITE_TCLAPI test_memdebug_pending(
689 void * clientData,
690 Tcl_Interp *interp,
691 int objc,
692 Tcl_Obj *CONST objv[]
694 int nPending;
695 if( objc!=1 ){
696 Tcl_WrongNumArgs(interp, 1, objv, "");
697 return TCL_ERROR;
699 nPending = faultsimPending();
700 Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));
701 return TCL_OK;
705 ** The following global variable keeps track of the number of tests
706 ** that have run. This variable is only useful when running in the
707 ** debugger.
709 static int sqlite3_memdebug_title_count = 0;
712 ** Usage: sqlite3_memdebug_settitle TITLE
714 ** Set a title string stored with each allocation. The TITLE is
715 ** typically the name of the test that was running when the
716 ** allocation occurred. The TITLE is stored with the allocation
717 ** and can be used to figure out which tests are leaking memory.
719 ** Each title overwrite the previous.
721 static int SQLITE_TCLAPI test_memdebug_settitle(
722 void * clientData,
723 Tcl_Interp *interp,
724 int objc,
725 Tcl_Obj *CONST objv[]
727 sqlite3_memdebug_title_count++;
728 if( objc!=2 ){
729 Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
730 return TCL_ERROR;
732 #ifdef SQLITE_MEMDEBUG
734 const char *zTitle;
735 extern int sqlite3MemdebugSettitle(const char*);
736 zTitle = Tcl_GetString(objv[1]);
737 sqlite3MemdebugSettitle(zTitle);
739 #endif
740 return TCL_OK;
743 #define MALLOC_LOG_FRAMES 10
744 #define MALLOC_LOG_KEYINTS ( \
745 10 * ((sizeof(int)>=sizeof(void*)) ? 1 : sizeof(void*)/sizeof(int)) \
747 static Tcl_HashTable aMallocLog;
748 static int mallocLogEnabled = 0;
750 typedef struct MallocLog MallocLog;
751 struct MallocLog {
752 int nCall;
753 int nByte;
756 #ifdef SQLITE_MEMDEBUG
757 static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
758 if( mallocLogEnabled ){
759 MallocLog *pLog;
760 Tcl_HashEntry *pEntry;
761 int isNew;
763 int aKey[MALLOC_LOG_KEYINTS];
764 unsigned int nKey = sizeof(int)*MALLOC_LOG_KEYINTS;
766 memset(aKey, 0, nKey);
767 if( (sizeof(void*)*nFrame)<nKey ){
768 nKey = nFrame*sizeof(void*);
770 memcpy(aKey, aFrame, nKey);
772 pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew);
773 if( isNew ){
774 pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog));
775 memset(pLog, 0, sizeof(MallocLog));
776 Tcl_SetHashValue(pEntry, (ClientData)pLog);
777 }else{
778 pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
781 pLog->nCall++;
782 pLog->nByte += nByte;
785 #endif /* SQLITE_MEMDEBUG */
787 static void test_memdebug_log_clear(void){
788 Tcl_HashSearch search;
789 Tcl_HashEntry *pEntry;
790 for(
791 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
792 pEntry;
793 pEntry=Tcl_NextHashEntry(&search)
795 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
796 Tcl_Free((char *)pLog);
798 Tcl_DeleteHashTable(&aMallocLog);
799 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);
802 static int SQLITE_TCLAPI test_memdebug_log(
803 void * clientData,
804 Tcl_Interp *interp,
805 int objc,
806 Tcl_Obj *CONST objv[]
808 static int isInit = 0;
809 int iSub;
811 static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" };
812 enum MB_enum {
813 MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC
816 if( !isInit ){
817 #ifdef SQLITE_MEMDEBUG
818 extern void sqlite3MemdebugBacktraceCallback(
819 void (*xBacktrace)(int, int, void **));
820 sqlite3MemdebugBacktraceCallback(test_memdebug_callback);
821 #endif
822 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);
823 isInit = 1;
826 if( objc<2 ){
827 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
829 if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){
830 return TCL_ERROR;
833 switch( (enum MB_enum)iSub ){
834 case MB_LOG_START:
835 mallocLogEnabled = 1;
836 break;
837 case MB_LOG_STOP:
838 mallocLogEnabled = 0;
839 break;
840 case MB_LOG_DUMP: {
841 Tcl_HashSearch search;
842 Tcl_HashEntry *pEntry;
843 Tcl_Obj *pRet = Tcl_NewObj();
845 assert(sizeof(Tcl_WideInt)>=sizeof(void*));
847 for(
848 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
849 pEntry;
850 pEntry=Tcl_NextHashEntry(&search)
852 Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];
853 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
854 Tcl_WideInt *aKey = (Tcl_WideInt *)Tcl_GetHashKey(&aMallocLog, pEntry);
855 int ii;
857 apElem[0] = Tcl_NewIntObj(pLog->nCall);
858 apElem[1] = Tcl_NewIntObj(pLog->nByte);
859 for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){
860 apElem[ii+2] = Tcl_NewWideIntObj(aKey[ii]);
863 Tcl_ListObjAppendElement(interp, pRet,
864 Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem)
868 Tcl_SetObjResult(interp, pRet);
869 break;
871 case MB_LOG_CLEAR: {
872 test_memdebug_log_clear();
873 break;
876 case MB_LOG_SYNC: {
877 #ifdef SQLITE_MEMDEBUG
878 extern void sqlite3MemdebugSync();
879 test_memdebug_log_clear();
880 mallocLogEnabled = 1;
881 sqlite3MemdebugSync();
882 #endif
883 break;
887 return TCL_OK;
891 ** Usage: sqlite3_config_pagecache SIZE N
893 ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
894 ** The buffer is static and is of limited size. N might be
895 ** adjusted downward as needed to accommodate the requested size.
896 ** The revised value of N is returned.
898 ** A negative SIZE causes the buffer pointer to be NULL.
900 static int SQLITE_TCLAPI test_config_pagecache(
901 void * clientData,
902 Tcl_Interp *interp,
903 int objc,
904 Tcl_Obj *CONST objv[]
906 int sz, N;
907 Tcl_Obj *pRes;
908 static char *buf = 0;
909 if( objc!=3 ){
910 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
911 return TCL_ERROR;
913 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
914 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
915 free(buf);
916 buf = 0;
918 /* Set the return value */
919 pRes = Tcl_NewObj();
920 Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(sqlite3GlobalConfig.szPage));
921 Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(sqlite3GlobalConfig.nPage));
922 Tcl_SetObjResult(interp, pRes);
924 if( sz<0 ){
925 sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, 0);
926 }else{
927 buf = malloc( sz*N );
928 sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);
930 return TCL_OK;
934 ** Usage: sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED
936 ** Set up the alternative test page cache. Install if INSTALL_FLAG is
937 ** true and uninstall (reverting to the default page cache) if INSTALL_FLAG
938 ** is false. DISCARD_CHANGE is an integer between 0 and 100 inclusive
939 ** which determines the chance of discarding a page when unpinned. 100
940 ** is certainty. 0 is never. PRNG_SEED is the pseudo-random number generator
941 ** seed.
943 static int SQLITE_TCLAPI test_alt_pcache(
944 void * clientData,
945 Tcl_Interp *interp,
946 int objc,
947 Tcl_Obj *CONST objv[]
949 int installFlag;
950 int discardChance = 0;
951 int prngSeed = 0;
952 int highStress = 0;
953 extern void installTestPCache(int,unsigned,unsigned,unsigned);
954 if( objc<2 || objc>5 ){
955 Tcl_WrongNumArgs(interp, 1, objv,
956 "INSTALLFLAG DISCARDCHANCE PRNGSEEED HIGHSTRESS");
957 return TCL_ERROR;
959 if( Tcl_GetIntFromObj(interp, objv[1], &installFlag) ) return TCL_ERROR;
960 if( objc>=3 && Tcl_GetIntFromObj(interp, objv[2], &discardChance) ){
961 return TCL_ERROR;
963 if( objc>=4 && Tcl_GetIntFromObj(interp, objv[3], &prngSeed) ){
964 return TCL_ERROR;
966 if( objc>=5 && Tcl_GetIntFromObj(interp, objv[4], &highStress) ){
967 return TCL_ERROR;
969 if( discardChance<0 || discardChance>100 ){
970 Tcl_AppendResult(interp, "discard-chance should be between 0 and 100",
971 (char*)0);
972 return TCL_ERROR;
974 installTestPCache(installFlag, (unsigned)discardChance, (unsigned)prngSeed,
975 (unsigned)highStress);
976 return TCL_OK;
980 ** Usage: sqlite3_config_memstatus BOOLEAN
982 ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.
984 static int SQLITE_TCLAPI test_config_memstatus(
985 void * clientData,
986 Tcl_Interp *interp,
987 int objc,
988 Tcl_Obj *CONST objv[]
990 int enable, rc;
991 if( objc!=2 ){
992 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
993 return TCL_ERROR;
995 if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR;
996 rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable);
997 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
998 return TCL_OK;
1002 ** Usage: sqlite3_config_lookaside SIZE COUNT
1005 static int SQLITE_TCLAPI test_config_lookaside(
1006 void * clientData,
1007 Tcl_Interp *interp,
1008 int objc,
1009 Tcl_Obj *CONST objv[]
1011 int sz, cnt;
1012 Tcl_Obj *pRet;
1013 if( objc!=3 ){
1014 Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT");
1015 return TCL_ERROR;
1017 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
1018 if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR;
1019 pRet = Tcl_NewObj();
1020 Tcl_ListObjAppendElement(
1021 interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.szLookaside)
1023 Tcl_ListObjAppendElement(
1024 interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.nLookaside)
1026 sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt);
1027 Tcl_SetObjResult(interp, pRet);
1028 return TCL_OK;
1033 ** Usage: sqlite3_db_config_lookaside CONNECTION BUFID SIZE COUNT
1035 ** There are two static buffers with BUFID 1 and 2. Each static buffer
1036 ** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL
1037 ** which will cause sqlite3_db_config() to allocate space on its own.
1039 static int SQLITE_TCLAPI test_db_config_lookaside(
1040 void * clientData,
1041 Tcl_Interp *interp,
1042 int objc,
1043 Tcl_Obj *CONST objv[]
1045 int rc;
1046 int sz, cnt;
1047 sqlite3 *db;
1048 int bufid;
1049 static char azBuf[2][10000];
1050 extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1051 if( objc!=5 ){
1052 Tcl_WrongNumArgs(interp, 1, objv, "BUFID SIZE COUNT");
1053 return TCL_ERROR;
1055 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1056 if( Tcl_GetIntFromObj(interp, objv[2], &bufid) ) return TCL_ERROR;
1057 if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR;
1058 if( Tcl_GetIntFromObj(interp, objv[4], &cnt) ) return TCL_ERROR;
1059 if( bufid==0 ){
1060 rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, (void*)0, sz, cnt);
1061 }else if( bufid>=1 && bufid<=2 && sz*cnt<=sizeof(azBuf[0]) ){
1062 rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz,cnt);
1063 }else{
1064 Tcl_AppendResult(interp, "illegal arguments - see documentation", (char*)0);
1065 return TCL_ERROR;
1067 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1068 return TCL_OK;
1072 ** Usage: sqlite3_config_heap NBYTE NMINALLOC
1074 static int SQLITE_TCLAPI test_config_heap(
1075 void * clientData,
1076 Tcl_Interp *interp,
1077 int objc,
1078 Tcl_Obj *CONST objv[]
1080 static char *zBuf; /* Use this memory */
1081 int nByte; /* Size of buffer to pass to sqlite3_config() */
1082 int nMinAlloc; /* Size of minimum allocation */
1083 int rc; /* Return code of sqlite3_config() */
1085 Tcl_Obj * CONST *aArg = &objv[1];
1086 int nArg = objc-1;
1088 if( nArg!=2 ){
1089 Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC");
1090 return TCL_ERROR;
1092 if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
1093 if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR;
1095 if( nByte==0 ){
1096 free( zBuf );
1097 zBuf = 0;
1098 rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0);
1099 }else{
1100 zBuf = realloc(zBuf, nByte);
1101 rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc);
1104 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1105 return TCL_OK;
1109 ** Usage: sqlite3_config_heap_size NBYTE
1111 static int SQLITE_TCLAPI test_config_heap_size(
1112 void * clientData,
1113 Tcl_Interp *interp,
1114 int objc,
1115 Tcl_Obj *CONST objv[]
1117 int nByte; /* Size to pass to sqlite3_config() */
1118 int rc; /* Return code of sqlite3_config() */
1120 Tcl_Obj * CONST *aArg = &objv[1];
1121 int nArg = objc-1;
1123 if( nArg!=1 ){
1124 Tcl_WrongNumArgs(interp, 1, objv, "NBYTE");
1125 return TCL_ERROR;
1127 if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
1129 rc = sqlite3_config(SQLITE_CONFIG_WIN32_HEAPSIZE, nByte);
1131 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1132 return TCL_OK;
1136 ** Usage: sqlite3_config_error [DB]
1138 ** Invoke sqlite3_config() or sqlite3_db_config() with invalid
1139 ** opcodes and verify that they return errors.
1141 static int SQLITE_TCLAPI test_config_error(
1142 void * clientData,
1143 Tcl_Interp *interp,
1144 int objc,
1145 Tcl_Obj *CONST objv[]
1147 sqlite3 *db;
1148 extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1150 if( objc!=2 && objc!=1 ){
1151 Tcl_WrongNumArgs(interp, 1, objv, "[DB]");
1152 return TCL_ERROR;
1154 if( objc==2 ){
1155 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1156 if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){
1157 Tcl_AppendResult(interp,
1158 "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR",
1159 (char*)0);
1160 return TCL_ERROR;
1162 }else{
1163 if( sqlite3_config(99999)!=SQLITE_ERROR ){
1164 Tcl_AppendResult(interp,
1165 "sqlite3_config(99999) does not return SQLITE_ERROR",
1166 (char*)0);
1167 return TCL_ERROR;
1170 return TCL_OK;
1174 ** Usage: sqlite3_config_uri BOOLEAN
1176 ** Enables or disables interpretation of URI parameters by default using
1177 ** SQLITE_CONFIG_URI.
1179 static int SQLITE_TCLAPI test_config_uri(
1180 void * clientData,
1181 Tcl_Interp *interp,
1182 int objc,
1183 Tcl_Obj *CONST objv[]
1185 int rc;
1186 int bOpenUri;
1188 if( objc!=2 ){
1189 Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
1190 return TCL_ERROR;
1192 if( Tcl_GetBooleanFromObj(interp, objv[1], &bOpenUri) ){
1193 return TCL_ERROR;
1196 rc = sqlite3_config(SQLITE_CONFIG_URI, bOpenUri);
1197 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1199 return TCL_OK;
1203 ** Usage: sqlite3_config_cis BOOLEAN
1205 ** Enables or disables the use of the covering-index scan optimization.
1206 ** SQLITE_CONFIG_COVERING_INDEX_SCAN.
1208 static int SQLITE_TCLAPI test_config_cis(
1209 void * clientData,
1210 Tcl_Interp *interp,
1211 int objc,
1212 Tcl_Obj *CONST objv[]
1214 int rc;
1215 int bUseCis;
1217 if( objc!=2 ){
1218 Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
1219 return TCL_ERROR;
1221 if( Tcl_GetBooleanFromObj(interp, objv[1], &bUseCis) ){
1222 return TCL_ERROR;
1225 rc = sqlite3_config(SQLITE_CONFIG_COVERING_INDEX_SCAN, bUseCis);
1226 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1228 return TCL_OK;
1232 ** Usage: sqlite3_config_pmasz INTEGER
1234 ** Set the minimum PMA size.
1236 static int SQLITE_TCLAPI test_config_pmasz(
1237 void * clientData,
1238 Tcl_Interp *interp,
1239 int objc,
1240 Tcl_Obj *CONST objv[]
1242 int rc;
1243 int iPmaSz;
1245 if( objc!=2 ){
1246 Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
1247 return TCL_ERROR;
1249 if( Tcl_GetIntFromObj(interp, objv[1], &iPmaSz) ){
1250 return TCL_ERROR;
1253 rc = sqlite3_config(SQLITE_CONFIG_PMASZ, iPmaSz);
1254 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1256 return TCL_OK;
1261 ** Usage: sqlite3_dump_memsys3 FILENAME
1262 ** sqlite3_dump_memsys5 FILENAME
1264 ** Write a summary of unfreed memsys3 allocations to FILENAME.
1266 static int SQLITE_TCLAPI test_dump_memsys3(
1267 void * clientData,
1268 Tcl_Interp *interp,
1269 int objc,
1270 Tcl_Obj *CONST objv[]
1272 if( objc!=2 ){
1273 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
1274 return TCL_ERROR;
1277 switch( SQLITE_PTR_TO_INT(clientData) ){
1278 case 3: {
1279 #ifdef SQLITE_ENABLE_MEMSYS3
1280 extern void sqlite3Memsys3Dump(const char*);
1281 sqlite3Memsys3Dump(Tcl_GetString(objv[1]));
1282 break;
1283 #endif
1285 case 5: {
1286 #ifdef SQLITE_ENABLE_MEMSYS5
1287 extern void sqlite3Memsys5Dump(const char*);
1288 sqlite3Memsys5Dump(Tcl_GetString(objv[1]));
1289 break;
1290 #endif
1293 return TCL_OK;
1297 ** Usage: sqlite3_status OPCODE RESETFLAG
1299 ** Return a list of three elements which are the sqlite3_status() return
1300 ** code, the current value, and the high-water mark value.
1302 static int SQLITE_TCLAPI test_status(
1303 void * clientData,
1304 Tcl_Interp *interp,
1305 int objc,
1306 Tcl_Obj *CONST objv[]
1308 int rc, iValue, mxValue;
1309 int i, op = 0, resetFlag;
1310 const char *zOpName;
1311 static const struct {
1312 const char *zName;
1313 int op;
1314 } aOp[] = {
1315 { "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED },
1316 { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE },
1317 { "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED },
1318 { "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW },
1319 { "SQLITE_STATUS_PAGECACHE_SIZE", SQLITE_STATUS_PAGECACHE_SIZE },
1320 { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED },
1321 { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW },
1322 { "SQLITE_STATUS_SCRATCH_SIZE", SQLITE_STATUS_SCRATCH_SIZE },
1323 { "SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK },
1324 { "SQLITE_STATUS_MALLOC_COUNT", SQLITE_STATUS_MALLOC_COUNT },
1326 Tcl_Obj *pResult;
1327 if( objc!=3 ){
1328 Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
1329 return TCL_ERROR;
1331 zOpName = Tcl_GetString(objv[1]);
1332 for(i=0; i<ArraySize(aOp); i++){
1333 if( strcmp(aOp[i].zName, zOpName)==0 ){
1334 op = aOp[i].op;
1335 break;
1338 if( i>=ArraySize(aOp) ){
1339 if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;
1341 if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;
1342 iValue = 0;
1343 mxValue = 0;
1344 rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);
1345 pResult = Tcl_NewObj();
1346 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1347 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1348 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1349 Tcl_SetObjResult(interp, pResult);
1350 return TCL_OK;
1354 ** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG
1356 ** Return a list of three elements which are the sqlite3_db_status() return
1357 ** code, the current value, and the high-water mark value.
1359 static int SQLITE_TCLAPI test_db_status(
1360 void * clientData,
1361 Tcl_Interp *interp,
1362 int objc,
1363 Tcl_Obj *CONST objv[]
1365 int rc, iValue, mxValue;
1366 int i, op = 0, resetFlag;
1367 const char *zOpName;
1368 sqlite3 *db;
1369 extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1370 static const struct {
1371 const char *zName;
1372 int op;
1373 } aOp[] = {
1374 { "LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED },
1375 { "CACHE_USED", SQLITE_DBSTATUS_CACHE_USED },
1376 { "SCHEMA_USED", SQLITE_DBSTATUS_SCHEMA_USED },
1377 { "STMT_USED", SQLITE_DBSTATUS_STMT_USED },
1378 { "LOOKASIDE_HIT", SQLITE_DBSTATUS_LOOKASIDE_HIT },
1379 { "LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE },
1380 { "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL },
1381 { "CACHE_HIT", SQLITE_DBSTATUS_CACHE_HIT },
1382 { "CACHE_MISS", SQLITE_DBSTATUS_CACHE_MISS },
1383 { "CACHE_WRITE", SQLITE_DBSTATUS_CACHE_WRITE },
1384 { "DEFERRED_FKS", SQLITE_DBSTATUS_DEFERRED_FKS },
1385 { "CACHE_USED_SHARED", SQLITE_DBSTATUS_CACHE_USED_SHARED },
1386 { "CACHE_SPILL", SQLITE_DBSTATUS_CACHE_SPILL },
1388 Tcl_Obj *pResult;
1389 if( objc!=4 ){
1390 Tcl_WrongNumArgs(interp, 1, objv, "DB PARAMETER RESETFLAG");
1391 return TCL_ERROR;
1393 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1394 zOpName = Tcl_GetString(objv[2]);
1395 if( memcmp(zOpName, "SQLITE_", 7)==0 ) zOpName += 7;
1396 if( memcmp(zOpName, "DBSTATUS_", 9)==0 ) zOpName += 9;
1397 for(i=0; i<ArraySize(aOp); i++){
1398 if( strcmp(aOp[i].zName, zOpName)==0 ){
1399 op = aOp[i].op;
1400 break;
1403 if( i>=ArraySize(aOp) ){
1404 if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR;
1406 if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR;
1407 iValue = 0;
1408 mxValue = 0;
1409 rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag);
1410 pResult = Tcl_NewObj();
1411 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1412 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1413 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1414 Tcl_SetObjResult(interp, pResult);
1415 return TCL_OK;
1419 ** install_malloc_faultsim BOOLEAN
1421 static int SQLITE_TCLAPI test_install_malloc_faultsim(
1422 void * clientData,
1423 Tcl_Interp *interp,
1424 int objc,
1425 Tcl_Obj *CONST objv[]
1427 int rc;
1428 int isInstall;
1430 if( objc!=2 ){
1431 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
1432 return TCL_ERROR;
1434 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
1435 return TCL_ERROR;
1437 rc = faultsimInstall(isInstall);
1438 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1439 return TCL_OK;
1443 ** sqlite3_install_memsys3
1445 static int SQLITE_TCLAPI test_install_memsys3(
1446 void * clientData,
1447 Tcl_Interp *interp,
1448 int objc,
1449 Tcl_Obj *CONST objv[]
1451 int rc = SQLITE_MISUSE;
1452 #ifdef SQLITE_ENABLE_MEMSYS3
1453 const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
1454 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetMemsys3());
1455 #endif
1456 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1457 return TCL_OK;
1460 static int SQLITE_TCLAPI test_vfs_oom_test(
1461 void * clientData,
1462 Tcl_Interp *interp,
1463 int objc,
1464 Tcl_Obj *CONST objv[]
1466 extern int sqlite3_memdebug_vfs_oom_test;
1467 if( objc>2 ){
1468 Tcl_WrongNumArgs(interp, 1, objv, "?INTEGER?");
1469 return TCL_ERROR;
1470 }else if( objc==2 ){
1471 int iNew;
1472 if( Tcl_GetIntFromObj(interp, objv[1], &iNew) ) return TCL_ERROR;
1473 sqlite3_memdebug_vfs_oom_test = iNew;
1475 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_memdebug_vfs_oom_test));
1476 return TCL_OK;
1480 ** Register commands with the TCL interpreter.
1482 int Sqlitetest_malloc_Init(Tcl_Interp *interp){
1483 static struct {
1484 char *zName;
1485 Tcl_ObjCmdProc *xProc;
1486 int clientData;
1487 } aObjCmd[] = {
1488 { "sqlite3_malloc", test_malloc ,0 },
1489 { "sqlite3_realloc", test_realloc ,0 },
1490 { "sqlite3_free", test_free ,0 },
1491 { "memset", test_memset ,0 },
1492 { "memget", test_memget ,0 },
1493 { "sqlite3_memory_used", test_memory_used ,0 },
1494 { "sqlite3_memory_highwater", test_memory_highwater ,0 },
1495 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace ,0 },
1496 { "sqlite3_memdebug_dump", test_memdebug_dump ,0 },
1497 { "sqlite3_memdebug_fail", test_memdebug_fail ,0 },
1498 { "sqlite3_memdebug_pending", test_memdebug_pending ,0 },
1499 { "sqlite3_memdebug_settitle", test_memdebug_settitle ,0 },
1500 { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 },
1501 { "sqlite3_memdebug_log", test_memdebug_log ,0 },
1502 { "sqlite3_config_pagecache", test_config_pagecache ,0 },
1503 { "sqlite3_config_alt_pcache", test_alt_pcache ,0 },
1504 { "sqlite3_status", test_status ,0 },
1505 { "sqlite3_db_status", test_db_status ,0 },
1506 { "install_malloc_faultsim", test_install_malloc_faultsim ,0 },
1507 { "sqlite3_config_heap", test_config_heap ,0 },
1508 { "sqlite3_config_heap_size", test_config_heap_size ,0 },
1509 { "sqlite3_config_memstatus", test_config_memstatus ,0 },
1510 { "sqlite3_config_lookaside", test_config_lookaside ,0 },
1511 { "sqlite3_config_error", test_config_error ,0 },
1512 { "sqlite3_config_uri", test_config_uri ,0 },
1513 { "sqlite3_config_cis", test_config_cis ,0 },
1514 { "sqlite3_config_pmasz", test_config_pmasz ,0 },
1515 { "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 },
1516 { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
1517 { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },
1518 { "sqlite3_install_memsys3", test_install_memsys3 ,0 },
1519 { "sqlite3_memdebug_vfs_oom_test", test_vfs_oom_test ,0 },
1521 int i;
1522 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
1523 ClientData c = (ClientData)SQLITE_INT_TO_PTR(aObjCmd[i].clientData);
1524 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
1526 return TCL_OK;
1528 #endif