]> git.ipfire.org Git - thirdparty/sqlite.git/blob - src/test_malloc.c
JS error message and doc typos reported in the forum. No code changes.
[thirdparty/sqlite.git] / src / test_malloc.c
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.
10 **
11 *************************************************************************
12 **
13 ** This file contains code used to implement test interfaces to the
14 ** memory allocation subsystem.
15 */
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>
25
26 /*
27 ** This structure is used to encapsulate the global state variables used
28 ** by malloc() fault simulation.
29 */
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 int nOkBefore; /* Successful allocations prior to the first fault */
36 int nOkAfter; /* Successful allocations after a fault */
37 u8 enable; /* True if enabled */
38 int isInstalled; /* True if the fault simulation layer is installed */
39 int isBenignMode; /* True if malloc failures are considered benign */
40 sqlite3_mem_methods m; /* 'Real' malloc implementation */
41 } memfault;
42
43 /*
44 ** This routine exists as a place to set a breakpoint that will
45 ** fire on any simulated malloc() failure.
46 */
47 static void sqlite3Fault(void){
48 static int cnt = 0;
49 cnt++;
50 }
51
52 /*
53 ** This routine exists as a place to set a breakpoint that will
54 ** fire the first time any malloc() fails on a single test case.
55 ** The sqlite3Fault() routine above runs on every malloc() failure.
56 ** This routine only runs on the first such failure.
57 */
58 static void sqlite3FirstFault(void){
59 static int cnt2 = 0;
60 cnt2++;
61 }
62
63 /*
64 ** Check to see if a fault should be simulated. Return true to simulate
65 ** the fault. Return false if the fault should not be simulated.
66 */
67 static int faultsimStep(void){
68 if( likely(!memfault.enable) ){
69 memfault.nOkAfter++;
70 return 0;
71 }
72 if( memfault.iCountdown>0 ){
73 memfault.iCountdown--;
74 memfault.nOkBefore++;
75 return 0;
76 }
77 if( memfault.nFail==0 ) sqlite3FirstFault();
78 sqlite3Fault();
79 memfault.nFail++;
80 if( memfault.isBenignMode>0 ){
81 memfault.nBenign++;
82 }
83 memfault.nRepeat--;
84 if( memfault.nRepeat<=0 ){
85 memfault.enable = 0;
86 }
87 return 1;
88 }
89
90 /*
91 ** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation
92 ** logic.
93 */
94 static void *faultsimMalloc(int n){
95 void *p = 0;
96 if( !faultsimStep() ){
97 p = memfault.m.xMalloc(n);
98 }
99 return p;
100 }
101
102
103 /*
104 ** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation
105 ** logic.
106 */
107 static void *faultsimRealloc(void *pOld, int n){
108 void *p = 0;
109 if( !faultsimStep() ){
110 p = memfault.m.xRealloc(pOld, n);
111 }
112 return p;
113 }
114
115 /*
116 ** This routine configures the malloc failure simulation. After
117 ** calling this routine, the next nDelay mallocs will succeed, followed
118 ** by a block of nRepeat failures, after which malloc() calls will begin
119 ** to succeed again.
120 */
121 static void faultsimConfig(int nDelay, int nRepeat){
122 memfault.iCountdown = nDelay;
123 memfault.nRepeat = nRepeat;
124 memfault.nBenign = 0;
125 memfault.nFail = 0;
126 memfault.nOkBefore = 0;
127 memfault.nOkAfter = 0;
128 memfault.enable = nDelay>=0;
129
130 /* Sometimes, when running multi-threaded tests, the isBenignMode
131 ** variable is not properly incremented/decremented so that it is
132 ** 0 when not inside a benign malloc block. This doesn't affect
133 ** the multi-threaded tests, as they do not use this system. But
134 ** it does affect OOM tests run later in the same process. So
135 ** zero the variable here, just to be sure.
136 */
137 memfault.isBenignMode = 0;
138 }
139
140 /*
141 ** Return the number of faults (both hard and benign faults) that have
142 ** occurred since the injector was last configured.
143 */
144 static int faultsimFailures(void){
145 return memfault.nFail;
146 }
147
148 /*
149 ** Return the number of benign faults that have occurred since the
150 ** injector was last configured.
151 */
152 static int faultsimBenignFailures(void){
153 return memfault.nBenign;
154 }
155
156 /*
157 ** Return the number of successes that will occur before the next failure.
158 ** If no failures are scheduled, return -1.
159 */
160 static int faultsimPending(void){
161 if( memfault.enable ){
162 return memfault.iCountdown;
163 }else{
164 return -1;
165 }
166 }
167
168
169 static void faultsimBeginBenign(void){
170 memfault.isBenignMode++;
171 }
172 static void faultsimEndBenign(void){
173 memfault.isBenignMode--;
174 }
175
176 /*
177 ** Add or remove the fault-simulation layer using sqlite3_config(). If
178 ** the argument is non-zero, the
179 */
180 static int faultsimInstall(int install){
181 int rc;
182
183 install = (install ? 1 : 0);
184 assert(memfault.isInstalled==1 || memfault.isInstalled==0);
185
186 if( install==memfault.isInstalled ){
187 return SQLITE_ERROR;
188 }
189
190 if( install ){
191 rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);
192 assert(memfault.m.xMalloc);
193 if( rc==SQLITE_OK ){
194 sqlite3_mem_methods m = memfault.m;
195 m.xMalloc = faultsimMalloc;
196 m.xRealloc = faultsimRealloc;
197 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
198 }
199 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
200 faultsimBeginBenign, faultsimEndBenign
201 );
202 }else{
203 sqlite3_mem_methods m2;
204 assert(memfault.m.xMalloc);
205
206 /* One should be able to reset the default memory allocator by storing
207 ** a zeroed allocator then calling GETMALLOC. */
208 memset(&m2, 0, sizeof(m2));
209 sqlite3_config(SQLITE_CONFIG_MALLOC, &m2);
210 sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m2);
211 assert( memcmp(&m2, &memfault.m, sizeof(m2))==0 );
212
213 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m);
214 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
215 (void*)0, (void*)0);
216 }
217
218 if( rc==SQLITE_OK ){
219 memfault.isInstalled = 1;
220 }
221 return rc;
222 }
223
224 #ifdef SQLITE_TEST
225
226 /*
227 ** This function is implemented in main.c. Returns a pointer to a static
228 ** buffer containing the symbolic SQLite error code that corresponds to
229 ** the least-significant 8-bits of the integer passed as an argument.
230 ** For example:
231 **
232 ** sqlite3ErrName(1) -> "SQLITE_ERROR"
233 */
234 extern const char *sqlite3ErrName(int);
235
236 /*
237 ** Transform pointers to text and back again
238 */
239 static void pointerToText(void *p, char *z){
240 static const char zHex[] = "0123456789abcdef";
241 int i, k;
242 unsigned int u;
243 sqlite3_uint64 n;
244 if( p==0 ){
245 strcpy(z, "0");
246 return;
247 }
248 if( sizeof(n)==sizeof(p) ){
249 memcpy(&n, &p, sizeof(p));
250 }else if( sizeof(u)==sizeof(p) ){
251 memcpy(&u, &p, sizeof(u));
252 n = u;
253 }else{
254 assert( 0 );
255 }
256 for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
257 z[k] = zHex[n&0xf];
258 n >>= 4;
259 }
260 z[sizeof(p)*2] = 0;
261 }
262 static int hexToInt(int h){
263 if( h>='0' && h<='9' ){
264 return h - '0';
265 }else if( h>='a' && h<='f' ){
266 return h - 'a' + 10;
267 }else{
268 return -1;
269 }
270 }
271 static int textToPointer(const char *z, void **pp){
272 sqlite3_uint64 n = 0;
273 int i;
274 unsigned int u;
275 for(i=0; i<sizeof(void*)*2 && z[0]; i++){
276 int v;
277 v = hexToInt(*z++);
278 if( v<0 ) return TCL_ERROR;
279 n = n*16 + v;
280 }
281 if( *z!=0 ) return TCL_ERROR;
282 if( sizeof(n)==sizeof(*pp) ){
283 memcpy(pp, &n, sizeof(n));
284 }else if( sizeof(u)==sizeof(*pp) ){
285 u = (unsigned int)n;
286 memcpy(pp, &u, sizeof(u));
287 }else{
288 assert( 0 );
289 }
290 return TCL_OK;
291 }
292
293 /*
294 ** Usage: sqlite3_malloc NBYTES
295 **
296 ** Raw test interface for sqlite3_malloc().
297 */
298 static int SQLITE_TCLAPI test_malloc(
299 void * clientData,
300 Tcl_Interp *interp,
301 int objc,
302 Tcl_Obj *CONST objv[]
303 ){
304 int nByte;
305 void *p;
306 char zOut[100];
307 if( objc!=2 ){
308 Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
309 return TCL_ERROR;
310 }
311 if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
312 p = sqlite3_malloc((unsigned)nByte);
313 pointerToText(p, zOut);
314 Tcl_AppendResult(interp, zOut, NULL);
315 return TCL_OK;
316 }
317
318 /*
319 ** Usage: sqlite3_realloc PRIOR NBYTES
320 **
321 ** Raw test interface for sqlite3_realloc().
322 */
323 static int SQLITE_TCLAPI test_realloc(
324 void * clientData,
325 Tcl_Interp *interp,
326 int objc,
327 Tcl_Obj *CONST objv[]
328 ){
329 int nByte;
330 void *pPrior, *p;
331 char zOut[100];
332 if( objc!=3 ){
333 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
334 return TCL_ERROR;
335 }
336 if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
337 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
338 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
339 return TCL_ERROR;
340 }
341 p = sqlite3_realloc(pPrior, (unsigned)nByte);
342 pointerToText(p, zOut);
343 Tcl_AppendResult(interp, zOut, NULL);
344 return TCL_OK;
345 }
346
347 /*
348 ** Usage: sqlite3_free PRIOR
349 **
350 ** Raw test interface for sqlite3_free().
351 */
352 static int SQLITE_TCLAPI test_free(
353 void * clientData,
354 Tcl_Interp *interp,
355 int objc,
356 Tcl_Obj *CONST objv[]
357 ){
358 void *pPrior;
359 if( objc!=2 ){
360 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
361 return TCL_ERROR;
362 }
363 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
364 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
365 return TCL_ERROR;
366 }
367 sqlite3_free(pPrior);
368 return TCL_OK;
369 }
370
371 /*
372 ** These routines are in test_hexio.c
373 */
374 int sqlite3TestHexToBin(const char *, int, char *);
375 int sqlite3TestBinToHex(char*,int);
376
377 /*
378 ** Usage: memset ADDRESS SIZE HEX
379 **
380 ** Set a chunk of memory (obtained from malloc, probably) to a
381 ** specified hex pattern.
382 */
383 static int SQLITE_TCLAPI test_memset(
384 void * clientData,
385 Tcl_Interp *interp,
386 int objc,
387 Tcl_Obj *CONST objv[]
388 ){
389 void *p;
390 int size, n, i;
391 char *zHex;
392 char *zOut;
393 char zBin[100];
394
395 if( objc!=4 ){
396 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
397 return TCL_ERROR;
398 }
399 if( textToPointer(Tcl_GetString(objv[1]), &p) ){
400 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
401 return TCL_ERROR;
402 }
403 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
404 return TCL_ERROR;
405 }
406 if( size<=0 ){
407 Tcl_AppendResult(interp, "size must be positive", (char*)0);
408 return TCL_ERROR;
409 }
410 zHex = Tcl_GetStringFromObj(objv[3], &n);
411 if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
412 n = sqlite3TestHexToBin(zHex, n, zBin);
413 if( n==0 ){
414 Tcl_AppendResult(interp, "no data", (char*)0);
415 return TCL_ERROR;
416 }
417 zOut = p;
418 for(i=0; i<size; i++){
419 zOut[i] = zBin[i%n];
420 }
421 return TCL_OK;
422 }
423
424 /*
425 ** Usage: memget ADDRESS SIZE
426 **
427 ** Return memory as hexadecimal text.
428 */
429 static int SQLITE_TCLAPI test_memget(
430 void * clientData,
431 Tcl_Interp *interp,
432 int objc,
433 Tcl_Obj *CONST objv[]
434 ){
435 void *p;
436 int size, n;
437 char *zBin;
438 char zHex[100];
439
440 if( objc!=3 ){
441 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");
442 return TCL_ERROR;
443 }
444 if( textToPointer(Tcl_GetString(objv[1]), &p) ){
445 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
446 return TCL_ERROR;
447 }
448 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
449 return TCL_ERROR;
450 }
451 if( size<=0 ){
452 Tcl_AppendResult(interp, "size must be positive", (char*)0);
453 return TCL_ERROR;
454 }
455 zBin = p;
456 while( size>0 ){
457 if( size>(sizeof(zHex)-1)/2 ){
458 n = (sizeof(zHex)-1)/2;
459 }else{
460 n = size;
461 }
462 memcpy(zHex, zBin, n);
463 zBin += n;
464 size -= n;
465 sqlite3TestBinToHex(zHex, n);
466 Tcl_AppendResult(interp, zHex, (char*)0);
467 }
468 return TCL_OK;
469 }
470
471 /*
472 ** Usage: sqlite3_memory_used
473 **
474 ** Raw test interface for sqlite3_memory_used().
475 */
476 static int SQLITE_TCLAPI test_memory_used(
477 void * clientData,
478 Tcl_Interp *interp,
479 int objc,
480 Tcl_Obj *CONST objv[]
481 ){
482 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
483 return TCL_OK;
484 }
485
486 /*
487 ** Usage: sqlite3_memory_highwater ?RESETFLAG?
488 **
489 ** Raw test interface for sqlite3_memory_highwater().
490 */
491 static int SQLITE_TCLAPI test_memory_highwater(
492 void * clientData,
493 Tcl_Interp *interp,
494 int objc,
495 Tcl_Obj *CONST objv[]
496 ){
497 int resetFlag = 0;
498 if( objc!=1 && objc!=2 ){
499 Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
500 return TCL_ERROR;
501 }
502 if( objc==2 ){
503 if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
504 }
505 Tcl_SetObjResult(interp,
506 Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
507 return TCL_OK;
508 }
509
510 /*
511 ** Usage: sqlite3_memdebug_backtrace DEPTH
512 **
513 ** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined
514 ** then this routine is a no-op.
515 */
516 static int SQLITE_TCLAPI test_memdebug_backtrace(
517 void * clientData,
518 Tcl_Interp *interp,
519 int objc,
520 Tcl_Obj *CONST objv[]
521 ){
522 int depth;
523 if( objc!=2 ){
524 Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
525 return TCL_ERROR;
526 }
527 if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
528 #ifdef SQLITE_MEMDEBUG
529 {
530 extern void sqlite3MemdebugBacktrace(int);
531 sqlite3MemdebugBacktrace(depth);
532 }
533 #endif
534 return TCL_OK;
535 }
536
537 /*
538 ** Usage: sqlite3_memdebug_dump FILENAME
539 **
540 ** Write a summary of unfreed memory to FILENAME.
541 */
542 static int SQLITE_TCLAPI test_memdebug_dump(
543 void * clientData,
544 Tcl_Interp *interp,
545 int objc,
546 Tcl_Obj *CONST objv[]
547 ){
548 if( objc!=2 ){
549 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
550 return TCL_ERROR;
551 }
552 #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
553 || defined(SQLITE_POW2_MEMORY_SIZE)
554 {
555 extern void sqlite3MemdebugDump(const char*);
556 sqlite3MemdebugDump(Tcl_GetString(objv[1]));
557 }
558 #endif
559 return TCL_OK;
560 }
561
562 /*
563 ** Usage: sqlite3_memdebug_malloc_count
564 **
565 ** Return the total number of times malloc() has been called.
566 */
567 static int SQLITE_TCLAPI test_memdebug_malloc_count(
568 void * clientData,
569 Tcl_Interp *interp,
570 int objc,
571 Tcl_Obj *CONST objv[]
572 ){
573 int nMalloc = -1;
574 if( objc!=1 ){
575 Tcl_WrongNumArgs(interp, 1, objv, "");
576 return TCL_ERROR;
577 }
578 #if defined(SQLITE_MEMDEBUG)
579 {
580 extern int sqlite3MemdebugMallocCount();
581 nMalloc = sqlite3MemdebugMallocCount();
582 }
583 #endif
584 Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));
585 return TCL_OK;
586 }
587
588
589 /*
590 ** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS?
591 **
592 ** where options are:
593 **
594 ** -repeat <count>
595 ** -benigncnt <varname>
596 **
597 ** Arrange for a simulated malloc() failure after COUNTER successes.
598 ** If a repeat count is specified, the fault is repeated that many
599 ** times.
600 **
601 ** Each call to this routine overrides the prior counter value.
602 ** This routine returns the number of simulated failures that have
603 ** happened since the previous call to this routine.
604 **
605 ** To disable simulated failures, use a COUNTER of -1.
606 */
607 static int SQLITE_TCLAPI test_memdebug_fail(
608 void * clientData,
609 Tcl_Interp *interp,
610 int objc,
611 Tcl_Obj *CONST objv[]
612 ){
613 int ii;
614 int iFail;
615 int nRepeat = 1;
616 Tcl_Obj *pBenignCnt = 0;
617 int nBenign;
618 int nFail = 0;
619
620 if( objc<2 ){
621 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
622 return TCL_ERROR;
623 }
624 if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
625
626 for(ii=2; ii<objc; ii+=2){
627 int nOption;
628 char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
629 char *zErr = 0;
630
631 if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
632 if( ii==(objc-1) ){
633 zErr = "option requires an argument: ";
634 }else{
635 if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){
636 return TCL_ERROR;
637 }
638 }
639 }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){
640 if( ii==(objc-1) ){
641 zErr = "option requires an argument: ";
642 }else{
643 pBenignCnt = objv[ii+1];
644 }
645 }else{
646 zErr = "unknown option: ";
647 }
648
649 if( zErr ){
650 Tcl_AppendResult(interp, zErr, zOption, 0);
651 return TCL_ERROR;
652 }
653 }
654
655 nBenign = faultsimBenignFailures();
656 nFail = faultsimFailures();
657 faultsimConfig(iFail, nRepeat);
658
659 if( pBenignCnt ){
660 Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);
661 }
662 Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
663 return TCL_OK;
664 }
665
666 /*
667 ** Usage: sqlite3_memdebug_pending
668 **
669 ** Return the number of malloc() calls that will succeed before a
670 ** simulated failure occurs. A negative return value indicates that
671 ** no malloc() failure is scheduled.
672 */
673 static int SQLITE_TCLAPI test_memdebug_pending(
674 void * clientData,
675 Tcl_Interp *interp,
676 int objc,
677 Tcl_Obj *CONST objv[]
678 ){
679 int nPending;
680 if( objc!=1 ){
681 Tcl_WrongNumArgs(interp, 1, objv, "");
682 return TCL_ERROR;
683 }
684 nPending = faultsimPending();
685 Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));
686 return TCL_OK;
687 }
688
689 /*
690 ** The following global variable keeps track of the number of tests
691 ** that have run. This variable is only useful when running in the
692 ** debugger.
693 */
694 static int sqlite3_memdebug_title_count = 0;
695
696 /*
697 ** Usage: sqlite3_memdebug_settitle TITLE
698 **
699 ** Set a title string stored with each allocation. The TITLE is
700 ** typically the name of the test that was running when the
701 ** allocation occurred. The TITLE is stored with the allocation
702 ** and can be used to figure out which tests are leaking memory.
703 **
704 ** Each title overwrite the previous.
705 */
706 static int SQLITE_TCLAPI test_memdebug_settitle(
707 void * clientData,
708 Tcl_Interp *interp,
709 int objc,
710 Tcl_Obj *CONST objv[]
711 ){
712 sqlite3_memdebug_title_count++;
713 if( objc!=2 ){
714 Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
715 return TCL_ERROR;
716 }
717 #ifdef SQLITE_MEMDEBUG
718 {
719 const char *zTitle;
720 extern int sqlite3MemdebugSettitle(const char*);
721 zTitle = Tcl_GetString(objv[1]);
722 sqlite3MemdebugSettitle(zTitle);
723 }
724 #endif
725 return TCL_OK;
726 }
727
728 #define MALLOC_LOG_FRAMES 10
729 #define MALLOC_LOG_KEYINTS ( \
730 10 * ((sizeof(int)>=sizeof(void*)) ? 1 : sizeof(void*)/sizeof(int)) \
731 )
732 static Tcl_HashTable aMallocLog;
733 static int mallocLogEnabled = 0;
734
735 typedef struct MallocLog MallocLog;
736 struct MallocLog {
737 int nCall;
738 int nByte;
739 };
740
741 #ifdef SQLITE_MEMDEBUG
742 static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
743 if( mallocLogEnabled ){
744 MallocLog *pLog;
745 Tcl_HashEntry *pEntry;
746 int isNew;
747
748 int aKey[MALLOC_LOG_KEYINTS];
749 unsigned int nKey = sizeof(int)*MALLOC_LOG_KEYINTS;
750
751 memset(aKey, 0, nKey);
752 if( (sizeof(void*)*nFrame)<nKey ){
753 nKey = nFrame*sizeof(void*);
754 }
755 memcpy(aKey, aFrame, nKey);
756
757 pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew);
758 if( isNew ){
759 pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog));
760 memset(pLog, 0, sizeof(MallocLog));
761 Tcl_SetHashValue(pEntry, (ClientData)pLog);
762 }else{
763 pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
764 }
765
766 pLog->nCall++;
767 pLog->nByte += nByte;
768 }
769 }
770 #endif /* SQLITE_MEMDEBUG */
771
772 static void test_memdebug_log_clear(void){
773 Tcl_HashSearch search;
774 Tcl_HashEntry *pEntry;
775 for(
776 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
777 pEntry;
778 pEntry=Tcl_NextHashEntry(&search)
779 ){
780 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
781 Tcl_Free((char *)pLog);
782 }
783 Tcl_DeleteHashTable(&aMallocLog);
784 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);
785 }
786
787 static int SQLITE_TCLAPI test_memdebug_log(
788 void * clientData,
789 Tcl_Interp *interp,
790 int objc,
791 Tcl_Obj *CONST objv[]
792 ){
793 static int isInit = 0;
794 int iSub;
795
796 static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" };
797 enum MB_enum {
798 MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC
799 };
800
801 if( !isInit ){
802 #ifdef SQLITE_MEMDEBUG
803 extern void sqlite3MemdebugBacktraceCallback(
804 void (*xBacktrace)(int, int, void **));
805 sqlite3MemdebugBacktraceCallback(test_memdebug_callback);
806 #endif
807 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);
808 isInit = 1;
809 }
810
811 if( objc<2 ){
812 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
813 }
814 if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){
815 return TCL_ERROR;
816 }
817
818 switch( (enum MB_enum)iSub ){
819 case MB_LOG_START:
820 mallocLogEnabled = 1;
821 break;
822 case MB_LOG_STOP:
823 mallocLogEnabled = 0;
824 break;
825 case MB_LOG_DUMP: {
826 Tcl_HashSearch search;
827 Tcl_HashEntry *pEntry;
828 Tcl_Obj *pRet = Tcl_NewObj();
829
830 assert(sizeof(Tcl_WideInt)>=sizeof(void*));
831
832 for(
833 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
834 pEntry;
835 pEntry=Tcl_NextHashEntry(&search)
836 ){
837 Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];
838 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
839 Tcl_WideInt *aKey = (Tcl_WideInt *)Tcl_GetHashKey(&aMallocLog, pEntry);
840 int ii;
841
842 apElem[0] = Tcl_NewIntObj(pLog->nCall);
843 apElem[1] = Tcl_NewIntObj(pLog->nByte);
844 for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){
845 apElem[ii+2] = Tcl_NewWideIntObj(aKey[ii]);
846 }
847
848 Tcl_ListObjAppendElement(interp, pRet,
849 Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem)
850 );
851 }
852
853 Tcl_SetObjResult(interp, pRet);
854 break;
855 }
856 case MB_LOG_CLEAR: {
857 test_memdebug_log_clear();
858 break;
859 }
860
861 case MB_LOG_SYNC: {
862 #ifdef SQLITE_MEMDEBUG
863 extern void sqlite3MemdebugSync();
864 test_memdebug_log_clear();
865 mallocLogEnabled = 1;
866 sqlite3MemdebugSync();
867 #endif
868 break;
869 }
870 }
871
872 return TCL_OK;
873 }
874
875 /*
876 ** Usage: sqlite3_config_pagecache SIZE N
877 **
878 ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
879 ** The buffer is static and is of limited size. N might be
880 ** adjusted downward as needed to accommodate the requested size.
881 ** The revised value of N is returned.
882 **
883 ** A negative SIZE causes the buffer pointer to be NULL.
884 */
885 static int SQLITE_TCLAPI test_config_pagecache(
886 void * clientData,
887 Tcl_Interp *interp,
888 int objc,
889 Tcl_Obj *CONST objv[]
890 ){
891 int sz, N;
892 Tcl_Obj *pRes;
893 static char *buf = 0;
894 if( objc!=3 ){
895 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
896 return TCL_ERROR;
897 }
898 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
899 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
900 free(buf);
901 buf = 0;
902
903 /* Set the return value */
904 pRes = Tcl_NewObj();
905 Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(sqlite3GlobalConfig.szPage));
906 Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(sqlite3GlobalConfig.nPage));
907 Tcl_SetObjResult(interp, pRes);
908
909 if( sz<0 ){
910 sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, 0);
911 }else{
912 buf = malloc( sz*N );
913 sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);
914 }
915 return TCL_OK;
916 }
917
918 /*
919 ** Usage: sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED
920 **
921 ** Set up the alternative test page cache. Install if INSTALL_FLAG is
922 ** true and uninstall (reverting to the default page cache) if INSTALL_FLAG
923 ** is false. DISCARD_CHANGE is an integer between 0 and 100 inclusive
924 ** which determines the chance of discarding a page when unpinned. 100
925 ** is certainty. 0 is never. PRNG_SEED is the pseudo-random number generator
926 ** seed.
927 */
928 static int SQLITE_TCLAPI test_alt_pcache(
929 void * clientData,
930 Tcl_Interp *interp,
931 int objc,
932 Tcl_Obj *CONST objv[]
933 ){
934 int installFlag;
935 int discardChance = 0;
936 int prngSeed = 0;
937 int highStress = 0;
938 extern void installTestPCache(int,unsigned,unsigned,unsigned);
939 if( objc<2 || objc>5 ){
940 Tcl_WrongNumArgs(interp, 1, objv,
941 "INSTALLFLAG DISCARDCHANCE PRNGSEEED HIGHSTRESS");
942 return TCL_ERROR;
943 }
944 if( Tcl_GetIntFromObj(interp, objv[1], &installFlag) ) return TCL_ERROR;
945 if( objc>=3 && Tcl_GetIntFromObj(interp, objv[2], &discardChance) ){
946 return TCL_ERROR;
947 }
948 if( objc>=4 && Tcl_GetIntFromObj(interp, objv[3], &prngSeed) ){
949 return TCL_ERROR;
950 }
951 if( objc>=5 && Tcl_GetIntFromObj(interp, objv[4], &highStress) ){
952 return TCL_ERROR;
953 }
954 if( discardChance<0 || discardChance>100 ){
955 Tcl_AppendResult(interp, "discard-chance should be between 0 and 100",
956 (char*)0);
957 return TCL_ERROR;
958 }
959 installTestPCache(installFlag, (unsigned)discardChance, (unsigned)prngSeed,
960 (unsigned)highStress);
961 return TCL_OK;
962 }
963
964 /*
965 ** Usage: sqlite3_config_memstatus BOOLEAN
966 **
967 ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.
968 */
969 static int SQLITE_TCLAPI test_config_memstatus(
970 void * clientData,
971 Tcl_Interp *interp,
972 int objc,
973 Tcl_Obj *CONST objv[]
974 ){
975 int enable, rc;
976 if( objc!=2 ){
977 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
978 return TCL_ERROR;
979 }
980 if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR;
981 rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable);
982 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
983 return TCL_OK;
984 }
985
986 /*
987 ** Usage: sqlite3_config_lookaside SIZE COUNT
988 **
989 */
990 static int SQLITE_TCLAPI test_config_lookaside(
991 void * clientData,
992 Tcl_Interp *interp,
993 int objc,
994 Tcl_Obj *CONST objv[]
995 ){
996 int sz, cnt;
997 Tcl_Obj *pRet;
998 if( objc!=3 ){
999 Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT");
1000 return TCL_ERROR;
1001 }
1002 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
1003 if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR;
1004 pRet = Tcl_NewObj();
1005 Tcl_ListObjAppendElement(
1006 interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.szLookaside)
1007 );
1008 Tcl_ListObjAppendElement(
1009 interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.nLookaside)
1010 );
1011 sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt);
1012 Tcl_SetObjResult(interp, pRet);
1013 return TCL_OK;
1014 }
1015
1016
1017 /*
1018 ** Usage: sqlite3_db_config_lookaside CONNECTION BUFID SIZE COUNT
1019 **
1020 ** There are two static buffers with BUFID 1 and 2. Each static buffer
1021 ** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL
1022 ** which will cause sqlite3_db_config() to allocate space on its own.
1023 */
1024 static int SQLITE_TCLAPI test_db_config_lookaside(
1025 void * clientData,
1026 Tcl_Interp *interp,
1027 int objc,
1028 Tcl_Obj *CONST objv[]
1029 ){
1030 int rc;
1031 int sz, cnt;
1032 sqlite3 *db;
1033 int bufid;
1034 static char azBuf[2][10000];
1035 extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1036 if( objc!=5 ){
1037 Tcl_WrongNumArgs(interp, 1, objv, "BUFID SIZE COUNT");
1038 return TCL_ERROR;
1039 }
1040 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1041 if( Tcl_GetIntFromObj(interp, objv[2], &bufid) ) return TCL_ERROR;
1042 if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR;
1043 if( Tcl_GetIntFromObj(interp, objv[4], &cnt) ) return TCL_ERROR;
1044 if( bufid==0 ){
1045 rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, (void*)0, sz, cnt);
1046 }else if( bufid>=1 && bufid<=2 && sz*cnt<=sizeof(azBuf[0]) ){
1047 rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz,cnt);
1048 }else{
1049 Tcl_AppendResult(interp, "illegal arguments - see documentation", (char*)0);
1050 return TCL_ERROR;
1051 }
1052 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1053 return TCL_OK;
1054 }
1055
1056 /*
1057 ** Usage: sqlite3_config_heap NBYTE NMINALLOC
1058 */
1059 static int SQLITE_TCLAPI test_config_heap(
1060 void * clientData,
1061 Tcl_Interp *interp,
1062 int objc,
1063 Tcl_Obj *CONST objv[]
1064 ){
1065 static char *zBuf; /* Use this memory */
1066 int nByte; /* Size of buffer to pass to sqlite3_config() */
1067 int nMinAlloc; /* Size of minimum allocation */
1068 int rc; /* Return code of sqlite3_config() */
1069
1070 Tcl_Obj * CONST *aArg = &objv[1];
1071 int nArg = objc-1;
1072
1073 if( nArg!=2 ){
1074 Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC");
1075 return TCL_ERROR;
1076 }
1077 if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
1078 if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR;
1079
1080 if( nByte==0 ){
1081 free( zBuf );
1082 zBuf = 0;
1083 rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0);
1084 }else{
1085 zBuf = realloc(zBuf, nByte);
1086 rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc);
1087 }
1088
1089 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1090 return TCL_OK;
1091 }
1092
1093 /*
1094 ** Usage: sqlite3_config_heap_size NBYTE
1095 */
1096 static int SQLITE_TCLAPI test_config_heap_size(
1097 void * clientData,
1098 Tcl_Interp *interp,
1099 int objc,
1100 Tcl_Obj *CONST objv[]
1101 ){
1102 int nByte; /* Size to pass to sqlite3_config() */
1103 int rc; /* Return code of sqlite3_config() */
1104
1105 Tcl_Obj * CONST *aArg = &objv[1];
1106 int nArg = objc-1;
1107
1108 if( nArg!=1 ){
1109 Tcl_WrongNumArgs(interp, 1, objv, "NBYTE");
1110 return TCL_ERROR;
1111 }
1112 if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
1113
1114 rc = sqlite3_config(SQLITE_CONFIG_WIN32_HEAPSIZE, nByte);
1115
1116 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1117 return TCL_OK;
1118 }
1119
1120 /*
1121 ** Usage: sqlite3_config_error [DB]
1122 **
1123 ** Invoke sqlite3_config() or sqlite3_db_config() with invalid
1124 ** opcodes and verify that they return errors.
1125 */
1126 static int SQLITE_TCLAPI test_config_error(
1127 void * clientData,
1128 Tcl_Interp *interp,
1129 int objc,
1130 Tcl_Obj *CONST objv[]
1131 ){
1132 sqlite3 *db;
1133 extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1134
1135 if( objc!=2 && objc!=1 ){
1136 Tcl_WrongNumArgs(interp, 1, objv, "[DB]");
1137 return TCL_ERROR;
1138 }
1139 if( objc==2 ){
1140 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1141 if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){
1142 Tcl_AppendResult(interp,
1143 "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR",
1144 (char*)0);
1145 return TCL_ERROR;
1146 }
1147 }else{
1148 if( sqlite3_config(99999)!=SQLITE_ERROR ){
1149 Tcl_AppendResult(interp,
1150 "sqlite3_config(99999) does not return SQLITE_ERROR",
1151 (char*)0);
1152 return TCL_ERROR;
1153 }
1154 }
1155 return TCL_OK;
1156 }
1157
1158 /*
1159 ** Usage: sqlite3_config_uri BOOLEAN
1160 **
1161 ** Enables or disables interpretation of URI parameters by default using
1162 ** SQLITE_CONFIG_URI.
1163 */
1164 static int SQLITE_TCLAPI test_config_uri(
1165 void * clientData,
1166 Tcl_Interp *interp,
1167 int objc,
1168 Tcl_Obj *CONST objv[]
1169 ){
1170 int rc;
1171 int bOpenUri;
1172
1173 if( objc!=2 ){
1174 Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
1175 return TCL_ERROR;
1176 }
1177 if( Tcl_GetBooleanFromObj(interp, objv[1], &bOpenUri) ){
1178 return TCL_ERROR;
1179 }
1180
1181 rc = sqlite3_config(SQLITE_CONFIG_URI, bOpenUri);
1182 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1183
1184 return TCL_OK;
1185 }
1186
1187 /*
1188 ** Usage: sqlite3_config_cis BOOLEAN
1189 **
1190 ** Enables or disables the use of the covering-index scan optimization.
1191 ** SQLITE_CONFIG_COVERING_INDEX_SCAN.
1192 */
1193 static int SQLITE_TCLAPI test_config_cis(
1194 void * clientData,
1195 Tcl_Interp *interp,
1196 int objc,
1197 Tcl_Obj *CONST objv[]
1198 ){
1199 int rc;
1200 int bUseCis;
1201
1202 if( objc!=2 ){
1203 Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
1204 return TCL_ERROR;
1205 }
1206 if( Tcl_GetBooleanFromObj(interp, objv[1], &bUseCis) ){
1207 return TCL_ERROR;
1208 }
1209
1210 rc = sqlite3_config(SQLITE_CONFIG_COVERING_INDEX_SCAN, bUseCis);
1211 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1212
1213 return TCL_OK;
1214 }
1215
1216 /*
1217 ** Usage: sqlite3_config_pmasz INTEGER
1218 **
1219 ** Set the minimum PMA size.
1220 */
1221 static int SQLITE_TCLAPI test_config_pmasz(
1222 void * clientData,
1223 Tcl_Interp *interp,
1224 int objc,
1225 Tcl_Obj *CONST objv[]
1226 ){
1227 int rc;
1228 int iPmaSz;
1229
1230 if( objc!=2 ){
1231 Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
1232 return TCL_ERROR;
1233 }
1234 if( Tcl_GetIntFromObj(interp, objv[1], &iPmaSz) ){
1235 return TCL_ERROR;
1236 }
1237
1238 rc = sqlite3_config(SQLITE_CONFIG_PMASZ, iPmaSz);
1239 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1240
1241 return TCL_OK;
1242 }
1243
1244
1245 /*
1246 ** Usage: sqlite3_dump_memsys3 FILENAME
1247 ** sqlite3_dump_memsys5 FILENAME
1248 **
1249 ** Write a summary of unfreed memsys3 allocations to FILENAME.
1250 */
1251 static int SQLITE_TCLAPI test_dump_memsys3(
1252 void * clientData,
1253 Tcl_Interp *interp,
1254 int objc,
1255 Tcl_Obj *CONST objv[]
1256 ){
1257 if( objc!=2 ){
1258 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
1259 return TCL_ERROR;
1260 }
1261
1262 switch( SQLITE_PTR_TO_INT(clientData) ){
1263 case 3: {
1264 #ifdef SQLITE_ENABLE_MEMSYS3
1265 extern void sqlite3Memsys3Dump(const char*);
1266 sqlite3Memsys3Dump(Tcl_GetString(objv[1]));
1267 break;
1268 #endif
1269 }
1270 case 5: {
1271 #ifdef SQLITE_ENABLE_MEMSYS5
1272 extern void sqlite3Memsys5Dump(const char*);
1273 sqlite3Memsys5Dump(Tcl_GetString(objv[1]));
1274 break;
1275 #endif
1276 }
1277 }
1278 return TCL_OK;
1279 }
1280
1281 /*
1282 ** Usage: sqlite3_status OPCODE RESETFLAG
1283 **
1284 ** Return a list of three elements which are the sqlite3_status() return
1285 ** code, the current value, and the high-water mark value.
1286 */
1287 static int SQLITE_TCLAPI test_status(
1288 void * clientData,
1289 Tcl_Interp *interp,
1290 int objc,
1291 Tcl_Obj *CONST objv[]
1292 ){
1293 int rc, iValue, mxValue;
1294 int i, op = 0, resetFlag;
1295 const char *zOpName;
1296 static const struct {
1297 const char *zName;
1298 int op;
1299 } aOp[] = {
1300 { "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED },
1301 { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE },
1302 { "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED },
1303 { "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW },
1304 { "SQLITE_STATUS_PAGECACHE_SIZE", SQLITE_STATUS_PAGECACHE_SIZE },
1305 { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED },
1306 { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW },
1307 { "SQLITE_STATUS_SCRATCH_SIZE", SQLITE_STATUS_SCRATCH_SIZE },
1308 { "SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK },
1309 { "SQLITE_STATUS_MALLOC_COUNT", SQLITE_STATUS_MALLOC_COUNT },
1310 };
1311 Tcl_Obj *pResult;
1312 if( objc!=3 ){
1313 Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
1314 return TCL_ERROR;
1315 }
1316 zOpName = Tcl_GetString(objv[1]);
1317 for(i=0; i<ArraySize(aOp); i++){
1318 if( strcmp(aOp[i].zName, zOpName)==0 ){
1319 op = aOp[i].op;
1320 break;
1321 }
1322 }
1323 if( i>=ArraySize(aOp) ){
1324 if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;
1325 }
1326 if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;
1327 iValue = 0;
1328 mxValue = 0;
1329 rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);
1330 pResult = Tcl_NewObj();
1331 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1332 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1333 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1334 Tcl_SetObjResult(interp, pResult);
1335 return TCL_OK;
1336 }
1337
1338 /*
1339 ** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG
1340 **
1341 ** Return a list of three elements which are the sqlite3_db_status() return
1342 ** code, the current value, and the high-water mark value.
1343 */
1344 static int SQLITE_TCLAPI test_db_status(
1345 void * clientData,
1346 Tcl_Interp *interp,
1347 int objc,
1348 Tcl_Obj *CONST objv[]
1349 ){
1350 int rc, iValue, mxValue;
1351 int i, op = 0, resetFlag;
1352 const char *zOpName;
1353 sqlite3 *db;
1354 extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1355 static const struct {
1356 const char *zName;
1357 int op;
1358 } aOp[] = {
1359 { "LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED },
1360 { "CACHE_USED", SQLITE_DBSTATUS_CACHE_USED },
1361 { "SCHEMA_USED", SQLITE_DBSTATUS_SCHEMA_USED },
1362 { "STMT_USED", SQLITE_DBSTATUS_STMT_USED },
1363 { "LOOKASIDE_HIT", SQLITE_DBSTATUS_LOOKASIDE_HIT },
1364 { "LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE },
1365 { "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL },
1366 { "CACHE_HIT", SQLITE_DBSTATUS_CACHE_HIT },
1367 { "CACHE_MISS", SQLITE_DBSTATUS_CACHE_MISS },
1368 { "CACHE_WRITE", SQLITE_DBSTATUS_CACHE_WRITE },
1369 { "DEFERRED_FKS", SQLITE_DBSTATUS_DEFERRED_FKS },
1370 { "CACHE_USED_SHARED", SQLITE_DBSTATUS_CACHE_USED_SHARED },
1371 { "CACHE_SPILL", SQLITE_DBSTATUS_CACHE_SPILL },
1372 };
1373 Tcl_Obj *pResult;
1374 if( objc!=4 ){
1375 Tcl_WrongNumArgs(interp, 1, objv, "DB PARAMETER RESETFLAG");
1376 return TCL_ERROR;
1377 }
1378 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1379 zOpName = Tcl_GetString(objv[2]);
1380 if( memcmp(zOpName, "SQLITE_", 7)==0 ) zOpName += 7;
1381 if( memcmp(zOpName, "DBSTATUS_", 9)==0 ) zOpName += 9;
1382 for(i=0; i<ArraySize(aOp); i++){
1383 if( strcmp(aOp[i].zName, zOpName)==0 ){
1384 op = aOp[i].op;
1385 break;
1386 }
1387 }
1388 if( i>=ArraySize(aOp) ){
1389 if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR;
1390 }
1391 if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR;
1392 iValue = 0;
1393 mxValue = 0;
1394 rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag);
1395 pResult = Tcl_NewObj();
1396 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1397 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1398 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1399 Tcl_SetObjResult(interp, pResult);
1400 return TCL_OK;
1401 }
1402
1403 /*
1404 ** install_malloc_faultsim BOOLEAN
1405 */
1406 static int SQLITE_TCLAPI test_install_malloc_faultsim(
1407 void * clientData,
1408 Tcl_Interp *interp,
1409 int objc,
1410 Tcl_Obj *CONST objv[]
1411 ){
1412 int rc;
1413 int isInstall;
1414
1415 if( objc!=2 ){
1416 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
1417 return TCL_ERROR;
1418 }
1419 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
1420 return TCL_ERROR;
1421 }
1422 rc = faultsimInstall(isInstall);
1423 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1424 return TCL_OK;
1425 }
1426
1427 /*
1428 ** sqlite3_install_memsys3
1429 */
1430 static int SQLITE_TCLAPI test_install_memsys3(
1431 void * clientData,
1432 Tcl_Interp *interp,
1433 int objc,
1434 Tcl_Obj *CONST objv[]
1435 ){
1436 int rc = SQLITE_MISUSE;
1437 #ifdef SQLITE_ENABLE_MEMSYS3
1438 const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
1439 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetMemsys3());
1440 #endif
1441 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1442 return TCL_OK;
1443 }
1444
1445 static int SQLITE_TCLAPI test_vfs_oom_test(
1446 void * clientData,
1447 Tcl_Interp *interp,
1448 int objc,
1449 Tcl_Obj *CONST objv[]
1450 ){
1451 extern int sqlite3_memdebug_vfs_oom_test;
1452 if( objc>2 ){
1453 Tcl_WrongNumArgs(interp, 1, objv, "?INTEGER?");
1454 return TCL_ERROR;
1455 }else if( objc==2 ){
1456 int iNew;
1457 if( Tcl_GetIntFromObj(interp, objv[1], &iNew) ) return TCL_ERROR;
1458 sqlite3_memdebug_vfs_oom_test = iNew;
1459 }
1460 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_memdebug_vfs_oom_test));
1461 return TCL_OK;
1462 }
1463
1464 /*
1465 ** Register commands with the TCL interpreter.
1466 */
1467 int Sqlitetest_malloc_Init(Tcl_Interp *interp){
1468 static struct {
1469 char *zName;
1470 Tcl_ObjCmdProc *xProc;
1471 int clientData;
1472 } aObjCmd[] = {
1473 { "sqlite3_malloc", test_malloc ,0 },
1474 { "sqlite3_realloc", test_realloc ,0 },
1475 { "sqlite3_free", test_free ,0 },
1476 { "memset", test_memset ,0 },
1477 { "memget", test_memget ,0 },
1478 { "sqlite3_memory_used", test_memory_used ,0 },
1479 { "sqlite3_memory_highwater", test_memory_highwater ,0 },
1480 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace ,0 },
1481 { "sqlite3_memdebug_dump", test_memdebug_dump ,0 },
1482 { "sqlite3_memdebug_fail", test_memdebug_fail ,0 },
1483 { "sqlite3_memdebug_pending", test_memdebug_pending ,0 },
1484 { "sqlite3_memdebug_settitle", test_memdebug_settitle ,0 },
1485 { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 },
1486 { "sqlite3_memdebug_log", test_memdebug_log ,0 },
1487 { "sqlite3_config_pagecache", test_config_pagecache ,0 },
1488 { "sqlite3_config_alt_pcache", test_alt_pcache ,0 },
1489 { "sqlite3_status", test_status ,0 },
1490 { "sqlite3_db_status", test_db_status ,0 },
1491 { "install_malloc_faultsim", test_install_malloc_faultsim ,0 },
1492 { "sqlite3_config_heap", test_config_heap ,0 },
1493 { "sqlite3_config_heap_size", test_config_heap_size ,0 },
1494 { "sqlite3_config_memstatus", test_config_memstatus ,0 },
1495 { "sqlite3_config_lookaside", test_config_lookaside ,0 },
1496 { "sqlite3_config_error", test_config_error ,0 },
1497 { "sqlite3_config_uri", test_config_uri ,0 },
1498 { "sqlite3_config_cis", test_config_cis ,0 },
1499 { "sqlite3_config_pmasz", test_config_pmasz ,0 },
1500 { "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 },
1501 { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
1502 { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },
1503 { "sqlite3_install_memsys3", test_install_memsys3 ,0 },
1504 { "sqlite3_memdebug_vfs_oom_test", test_vfs_oom_test ,0 },
1505 };
1506 int i;
1507 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
1508 ClientData c = (ClientData)SQLITE_INT_TO_PTR(aObjCmd[i].clientData);
1509 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
1510 }
1511 return TCL_OK;
1512 }
1513 #endif