blob: d5f0a6df5afc16d9b65732e1f78e9496b47a7e2f [file] [log] [blame]
drh2f999a62007-08-15 19:16:43 +00001/*
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.
drh2f999a62007-08-15 19:16:43 +000015*/
16#include "sqliteInt.h"
17#include "tcl.h"
18#include <stdlib.h>
19#include <string.h>
20#include <assert.h>
21
danielk1977ef05f2d2008-06-20 11:05:37 +000022/*
23** This structure is used to encapsulate the global state variables used
24** by malloc() fault simulation.
25*/
26static struct MemFault {
27 int iCountdown; /* Number of pending successes before a failure */
28 int nRepeat; /* Number of times to repeat the failure */
29 int nBenign; /* Number of benign failures seen since last config */
30 int nFail; /* Number of failures seen since last config */
31 u8 enable; /* True if enabled */
32 int isInstalled; /* True if the fault simulation layer is installed */
danielk19772d1d86f2008-06-20 14:59:51 +000033 int isBenignMode; /* True if malloc failures are considered benign */
danielk1977ef05f2d2008-06-20 11:05:37 +000034 sqlite3_mem_methods m; /* 'Real' malloc implementation */
35} memfault;
36
37/*
38** This routine exists as a place to set a breakpoint that will
39** fire on any simulated malloc() failure.
40*/
41static void sqlite3Fault(void){
42 static int cnt = 0;
43 cnt++;
44}
45
46/*
47** Check to see if a fault should be simulated. Return true to simulate
48** the fault. Return false if the fault should not be simulated.
49*/
danielk197764aca192009-04-07 11:21:28 +000050static int faultsimStep(void){
danielk1977ef05f2d2008-06-20 11:05:37 +000051 if( likely(!memfault.enable) ){
52 return 0;
53 }
54 if( memfault.iCountdown>0 ){
55 memfault.iCountdown--;
56 return 0;
57 }
58 sqlite3Fault();
59 memfault.nFail++;
danielk19772d1d86f2008-06-20 14:59:51 +000060 if( memfault.isBenignMode>0 ){
danielk1977ef05f2d2008-06-20 11:05:37 +000061 memfault.nBenign++;
62 }
63 memfault.nRepeat--;
64 if( memfault.nRepeat<=0 ){
65 memfault.enable = 0;
66 }
67 return 1;
68}
69
70/*
71** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation
72** logic.
73*/
74static void *faultsimMalloc(int n){
75 void *p = 0;
76 if( !faultsimStep() ){
77 p = memfault.m.xMalloc(n);
78 }
79 return p;
80}
81
82
83/*
84** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation
85** logic.
86*/
87static void *faultsimRealloc(void *pOld, int n){
88 void *p = 0;
89 if( !faultsimStep() ){
90 p = memfault.m.xRealloc(pOld, n);
91 }
92 return p;
93}
94
95/*
96** The following method calls are passed directly through to the underlying
97** malloc system:
98**
99** xFree
100** xSize
101** xRoundup
102** xInit
103** xShutdown
104*/
105static void faultsimFree(void *p){
106 memfault.m.xFree(p);
107}
108static int faultsimSize(void *p){
109 return memfault.m.xSize(p);
110}
111static int faultsimRoundup(int n){
112 return memfault.m.xRoundup(n);
113}
114static int faultsimInit(void *p){
115 return memfault.m.xInit(memfault.m.pAppData);
116}
117static void faultsimShutdown(void *p){
118 memfault.m.xShutdown(memfault.m.pAppData);
119}
120
121/*
122** This routine configures the malloc failure simulation. After
123** calling this routine, the next nDelay mallocs will succeed, followed
124** by a block of nRepeat failures, after which malloc() calls will begin
125** to succeed again.
126*/
127static void faultsimConfig(int nDelay, int nRepeat){
128 memfault.iCountdown = nDelay;
129 memfault.nRepeat = nRepeat;
130 memfault.nBenign = 0;
131 memfault.nFail = 0;
132 memfault.enable = nDelay>=0;
danielk1977b48c1f12009-02-04 15:27:40 +0000133
134 /* Sometimes, when running multi-threaded tests, the isBenignMode
135 ** variable is not properly incremented/decremented so that it is
136 ** 0 when not inside a benign malloc block. This doesn't affect
137 ** the multi-threaded tests, as they do not use this system. But
138 ** it does affect OOM tests run later in the same process. So
139 ** zero the variable here, just to be sure.
140 */
141 memfault.isBenignMode = 0;
danielk1977ef05f2d2008-06-20 11:05:37 +0000142}
143
144/*
145** Return the number of faults (both hard and benign faults) that have
146** occurred since the injector was last configured.
147*/
148static int faultsimFailures(void){
149 return memfault.nFail;
150}
151
152/*
153** Return the number of benign faults that have occurred since the
154** injector was last configured.
155*/
156static int faultsimBenignFailures(void){
157 return memfault.nBenign;
158}
159
160/*
161** Return the number of successes that will occur before the next failure.
162** If no failures are scheduled, return -1.
163*/
164static int faultsimPending(void){
165 if( memfault.enable ){
166 return memfault.iCountdown;
167 }else{
168 return -1;
169 }
170}
171
danielk19772d1d86f2008-06-20 14:59:51 +0000172
173static void faultsimBeginBenign(void){
174 memfault.isBenignMode++;
175}
176static void faultsimEndBenign(void){
177 memfault.isBenignMode--;
178}
179
danielk1977ef05f2d2008-06-20 11:05:37 +0000180/*
181** Add or remove the fault-simulation layer using sqlite3_config(). If
182** the argument is non-zero, the
183*/
184static int faultsimInstall(int install){
185 static struct sqlite3_mem_methods m = {
186 faultsimMalloc, /* xMalloc */
187 faultsimFree, /* xFree */
188 faultsimRealloc, /* xRealloc */
189 faultsimSize, /* xSize */
190 faultsimRoundup, /* xRoundup */
191 faultsimInit, /* xInit */
192 faultsimShutdown, /* xShutdown */
193 0 /* pAppData */
194 };
195 int rc;
196
197 install = (install ? 1 : 0);
198 assert(memfault.isInstalled==1 || memfault.isInstalled==0);
199
200 if( install==memfault.isInstalled ){
201 return SQLITE_ERROR;
202 }
203
danielk19772d1d86f2008-06-20 14:59:51 +0000204 if( install ){
205 rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);
206 assert(memfault.m.xMalloc);
207 if( rc==SQLITE_OK ){
208 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
209 }
210 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
211 faultsimBeginBenign, faultsimEndBenign
212 );
213 }else{
drh1b67f3c2008-10-10 17:41:28 +0000214 sqlite3_mem_methods m;
danielk19772d1d86f2008-06-20 14:59:51 +0000215 assert(memfault.m.xMalloc);
drh1b67f3c2008-10-10 17:41:28 +0000216
217 /* One should be able to reset the default memory allocator by storing
218 ** a zeroed allocator then calling GETMALLOC. */
219 memset(&m, 0, sizeof(m));
220 sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
221 sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m);
222 assert( memcmp(&m, &memfault.m, sizeof(m))==0 );
223
danielk19772d1d86f2008-06-20 14:59:51 +0000224 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m);
225 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 0, 0);
danielk1977ef05f2d2008-06-20 11:05:37 +0000226 }
227
228 if( rc==SQLITE_OK ){
229 memfault.isInstalled = 1;
230 }
231 return rc;
232}
233
234#ifdef SQLITE_TEST
235
236/*
237** This function is implemented in test1.c. Returns a pointer to a static
238** buffer containing the symbolic SQLite error code that corresponds to
239** the least-significant 8-bits of the integer passed as an argument.
240** For example:
241**
242** sqlite3TestErrorName(1) -> "SQLITE_ERROR"
243*/
danielk1977d09414c2008-06-19 18:17:49 +0000244const char *sqlite3TestErrorName(int);
245
drh2f999a62007-08-15 19:16:43 +0000246/*
247** Transform pointers to text and back again
248*/
249static void pointerToText(void *p, char *z){
250 static const char zHex[] = "0123456789abcdef";
251 int i, k;
drh4a50aac2007-08-23 02:47:53 +0000252 unsigned int u;
253 sqlite3_uint64 n;
drh8a42cbd2008-07-10 18:13:42 +0000254 if( p==0 ){
255 strcpy(z, "0");
256 return;
257 }
drh4a50aac2007-08-23 02:47:53 +0000258 if( sizeof(n)==sizeof(p) ){
259 memcpy(&n, &p, sizeof(p));
260 }else if( sizeof(u)==sizeof(p) ){
261 memcpy(&u, &p, sizeof(u));
262 n = u;
263 }else{
264 assert( 0 );
265 }
drh2f999a62007-08-15 19:16:43 +0000266 for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
267 z[k] = zHex[n&0xf];
268 n >>= 4;
269 }
270 z[sizeof(p)*2] = 0;
271}
272static int hexToInt(int h){
273 if( h>='0' && h<='9' ){
274 return h - '0';
275 }else if( h>='a' && h<='f' ){
276 return h - 'a' + 10;
277 }else{
278 return -1;
279 }
280}
281static int textToPointer(const char *z, void **pp){
282 sqlite3_uint64 n = 0;
283 int i;
drh4a50aac2007-08-23 02:47:53 +0000284 unsigned int u;
drh2f999a62007-08-15 19:16:43 +0000285 for(i=0; i<sizeof(void*)*2 && z[0]; i++){
286 int v;
287 v = hexToInt(*z++);
288 if( v<0 ) return TCL_ERROR;
289 n = n*16 + v;
290 }
291 if( *z!=0 ) return TCL_ERROR;
drh4a50aac2007-08-23 02:47:53 +0000292 if( sizeof(n)==sizeof(*pp) ){
293 memcpy(pp, &n, sizeof(n));
294 }else if( sizeof(u)==sizeof(*pp) ){
295 u = (unsigned int)n;
296 memcpy(pp, &u, sizeof(u));
297 }else{
298 assert( 0 );
299 }
drh2f999a62007-08-15 19:16:43 +0000300 return TCL_OK;
301}
302
303/*
304** Usage: sqlite3_malloc NBYTES
305**
306** Raw test interface for sqlite3_malloc().
307*/
308static int test_malloc(
309 void * clientData,
310 Tcl_Interp *interp,
311 int objc,
312 Tcl_Obj *CONST objv[]
313){
314 int nByte;
315 void *p;
316 char zOut[100];
317 if( objc!=2 ){
318 Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
319 return TCL_ERROR;
320 }
321 if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
322 p = sqlite3_malloc((unsigned)nByte);
323 pointerToText(p, zOut);
324 Tcl_AppendResult(interp, zOut, NULL);
325 return TCL_OK;
326}
327
328/*
329** Usage: sqlite3_realloc PRIOR NBYTES
330**
331** Raw test interface for sqlite3_realloc().
332*/
333static int test_realloc(
334 void * clientData,
335 Tcl_Interp *interp,
336 int objc,
337 Tcl_Obj *CONST objv[]
338){
339 int nByte;
340 void *pPrior, *p;
341 char zOut[100];
342 if( objc!=3 ){
343 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
344 return TCL_ERROR;
345 }
346 if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
347 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
348 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
349 return TCL_ERROR;
350 }
351 p = sqlite3_realloc(pPrior, (unsigned)nByte);
352 pointerToText(p, zOut);
353 Tcl_AppendResult(interp, zOut, NULL);
354 return TCL_OK;
355}
356
drh2f999a62007-08-15 19:16:43 +0000357/*
358** Usage: sqlite3_free PRIOR
359**
360** Raw test interface for sqlite3_free().
361*/
362static int test_free(
363 void * clientData,
364 Tcl_Interp *interp,
365 int objc,
366 Tcl_Obj *CONST objv[]
367){
368 void *pPrior;
369 if( objc!=2 ){
370 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
371 return TCL_ERROR;
372 }
373 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
374 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
375 return TCL_ERROR;
376 }
377 sqlite3_free(pPrior);
378 return TCL_OK;
379}
380
381/*
drh9c7a60d2007-10-19 17:47:24 +0000382** These routines are in test_hexio.c
383*/
384int sqlite3TestHexToBin(const char *, int, char *);
385int sqlite3TestBinToHex(char*,int);
386
387/*
388** Usage: memset ADDRESS SIZE HEX
389**
390** Set a chunk of memory (obtained from malloc, probably) to a
391** specified hex pattern.
392*/
393static int test_memset(
394 void * clientData,
395 Tcl_Interp *interp,
396 int objc,
397 Tcl_Obj *CONST objv[]
398){
399 void *p;
400 int size, n, i;
401 char *zHex;
402 char *zOut;
403 char zBin[100];
404
405 if( objc!=4 ){
406 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
407 return TCL_ERROR;
408 }
409 if( textToPointer(Tcl_GetString(objv[1]), &p) ){
410 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
411 return TCL_ERROR;
412 }
413 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
414 return TCL_ERROR;
415 }
416 if( size<=0 ){
417 Tcl_AppendResult(interp, "size must be positive", (char*)0);
418 return TCL_ERROR;
419 }
420 zHex = Tcl_GetStringFromObj(objv[3], &n);
421 if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
422 n = sqlite3TestHexToBin(zHex, n, zBin);
423 if( n==0 ){
424 Tcl_AppendResult(interp, "no data", (char*)0);
425 return TCL_ERROR;
426 }
427 zOut = p;
428 for(i=0; i<size; i++){
429 zOut[i] = zBin[i%n];
430 }
431 return TCL_OK;
432}
433
434/*
435** Usage: memget ADDRESS SIZE
436**
437** Return memory as hexadecimal text.
438*/
439static int test_memget(
440 void * clientData,
441 Tcl_Interp *interp,
442 int objc,
443 Tcl_Obj *CONST objv[]
444){
445 void *p;
446 int size, n;
447 char *zBin;
448 char zHex[100];
449
450 if( objc!=3 ){
451 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");
452 return TCL_ERROR;
453 }
454 if( textToPointer(Tcl_GetString(objv[1]), &p) ){
455 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
456 return TCL_ERROR;
457 }
458 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
459 return TCL_ERROR;
460 }
461 if( size<=0 ){
462 Tcl_AppendResult(interp, "size must be positive", (char*)0);
463 return TCL_ERROR;
464 }
465 zBin = p;
466 while( size>0 ){
467 if( size>(sizeof(zHex)-1)/2 ){
468 n = (sizeof(zHex)-1)/2;
469 }else{
470 n = size;
471 }
472 memcpy(zHex, zBin, n);
473 zBin += n;
474 size -= n;
475 sqlite3TestBinToHex(zHex, n);
476 Tcl_AppendResult(interp, zHex, (char*)0);
477 }
478 return TCL_OK;
479}
480
481/*
drh2f999a62007-08-15 19:16:43 +0000482** Usage: sqlite3_memory_used
483**
484** Raw test interface for sqlite3_memory_used().
485*/
486static int test_memory_used(
487 void * clientData,
488 Tcl_Interp *interp,
489 int objc,
490 Tcl_Obj *CONST objv[]
491){
492 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
493 return TCL_OK;
494}
495
496/*
497** Usage: sqlite3_memory_highwater ?RESETFLAG?
498**
499** Raw test interface for sqlite3_memory_highwater().
500*/
501static int test_memory_highwater(
502 void * clientData,
503 Tcl_Interp *interp,
504 int objc,
505 Tcl_Obj *CONST objv[]
506){
507 int resetFlag = 0;
508 if( objc!=1 && objc!=2 ){
509 Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
510 return TCL_ERROR;
511 }
512 if( objc==2 ){
513 if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
514 }
515 Tcl_SetObjResult(interp,
516 Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
517 return TCL_OK;
518}
519
520/*
521** Usage: sqlite3_memdebug_backtrace DEPTH
522**
523** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined
524** then this routine is a no-op.
525*/
526static int test_memdebug_backtrace(
527 void * clientData,
528 Tcl_Interp *interp,
529 int objc,
530 Tcl_Obj *CONST objv[]
531){
532 int depth;
533 if( objc!=2 ){
534 Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
535 return TCL_ERROR;
536 }
537 if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
538#ifdef SQLITE_MEMDEBUG
539 {
drh49e4fd72008-02-19 15:15:15 +0000540 extern void sqlite3MemdebugBacktrace(int);
541 sqlite3MemdebugBacktrace(depth);
drh2f999a62007-08-15 19:16:43 +0000542 }
543#endif
544 return TCL_OK;
545}
546
547/*
548** Usage: sqlite3_memdebug_dump FILENAME
549**
550** Write a summary of unfreed memory to FILENAME.
551*/
552static int test_memdebug_dump(
553 void * clientData,
554 Tcl_Interp *interp,
555 int objc,
556 Tcl_Obj *CONST objv[]
557){
558 if( objc!=2 ){
559 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
560 return TCL_ERROR;
561 }
drh2d7636e2008-02-16 16:21:45 +0000562#if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
563 || defined(SQLITE_POW2_MEMORY_SIZE)
drh2f999a62007-08-15 19:16:43 +0000564 {
drh49e4fd72008-02-19 15:15:15 +0000565 extern void sqlite3MemdebugDump(const char*);
566 sqlite3MemdebugDump(Tcl_GetString(objv[1]));
drh2f999a62007-08-15 19:16:43 +0000567 }
568#endif
569 return TCL_OK;
570}
571
danielk1977a7a8e142008-02-13 18:25:27 +0000572/*
573** Usage: sqlite3_memdebug_malloc_count
574**
575** Return the total number of times malloc() has been called.
576*/
577static int test_memdebug_malloc_count(
578 void * clientData,
579 Tcl_Interp *interp,
580 int objc,
581 Tcl_Obj *CONST objv[]
582){
583 int nMalloc = -1;
584 if( objc!=1 ){
585 Tcl_WrongNumArgs(interp, 1, objv, "");
586 return TCL_ERROR;
587 }
588#if defined(SQLITE_MEMDEBUG)
589 {
drh49e4fd72008-02-19 15:15:15 +0000590 extern int sqlite3MemdebugMallocCount();
591 nMalloc = sqlite3MemdebugMallocCount();
danielk1977a7a8e142008-02-13 18:25:27 +0000592 }
593#endif
594 Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));
595 return TCL_OK;
596}
597
drh2f999a62007-08-15 19:16:43 +0000598
599/*
danielk1977a1644fd2007-08-29 12:31:25 +0000600** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS?
601**
602** where options are:
603**
drh643167f2008-01-22 21:30:53 +0000604** -repeat <count>
danielk1977a1644fd2007-08-29 12:31:25 +0000605** -benigncnt <varname>
drh0e6f1542007-08-15 20:41:28 +0000606**
607** Arrange for a simulated malloc() failure after COUNTER successes.
drh643167f2008-01-22 21:30:53 +0000608** If a repeat count is specified, the fault is repeated that many
609** times.
drh0e6f1542007-08-15 20:41:28 +0000610**
611** Each call to this routine overrides the prior counter value.
612** This routine returns the number of simulated failures that have
613** happened since the previous call to this routine.
614**
615** To disable simulated failures, use a COUNTER of -1.
616*/
617static int test_memdebug_fail(
618 void * clientData,
619 Tcl_Interp *interp,
620 int objc,
621 Tcl_Obj *CONST objv[]
622){
danielk1977a1644fd2007-08-29 12:31:25 +0000623 int ii;
drh0e6f1542007-08-15 20:41:28 +0000624 int iFail;
drh643167f2008-01-22 21:30:53 +0000625 int nRepeat = 1;
danielk1977a1644fd2007-08-29 12:31:25 +0000626 Tcl_Obj *pBenignCnt = 0;
drh643167f2008-01-22 21:30:53 +0000627 int nBenign;
drh0e6f1542007-08-15 20:41:28 +0000628 int nFail = 0;
danielk1977a1644fd2007-08-29 12:31:25 +0000629
630 if( objc<2 ){
631 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
drh0e6f1542007-08-15 20:41:28 +0000632 return TCL_ERROR;
633 }
634 if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
danielk1977a1644fd2007-08-29 12:31:25 +0000635
636 for(ii=2; ii<objc; ii+=2){
637 int nOption;
638 char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
639 char *zErr = 0;
640
641 if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
642 if( ii==(objc-1) ){
643 zErr = "option requires an argument: ";
644 }else{
drh643167f2008-01-22 21:30:53 +0000645 if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){
danielk1977a1644fd2007-08-29 12:31:25 +0000646 return TCL_ERROR;
647 }
648 }
649 }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){
650 if( ii==(objc-1) ){
651 zErr = "option requires an argument: ";
652 }else{
653 pBenignCnt = objv[ii+1];
654 }
655 }else{
656 zErr = "unknown option: ";
657 }
658
659 if( zErr ){
660 Tcl_AppendResult(interp, zErr, zOption, 0);
661 return TCL_ERROR;
662 }
drhed138fb2007-08-22 22:04:37 +0000663 }
danielk1977a1644fd2007-08-29 12:31:25 +0000664
danielk1977ef05f2d2008-06-20 11:05:37 +0000665 nBenign = faultsimBenignFailures();
666 nFail = faultsimFailures();
667 faultsimConfig(iFail, nRepeat);
668
drh643167f2008-01-22 21:30:53 +0000669 if( pBenignCnt ){
670 Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);
drh0e6f1542007-08-15 20:41:28 +0000671 }
drh0e6f1542007-08-15 20:41:28 +0000672 Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
673 return TCL_OK;
674}
675
danielk1977cd037242007-08-30 15:46:06 +0000676/*
677** Usage: sqlite3_memdebug_pending
678**
679** Return the number of malloc() calls that will succeed before a
680** simulated failure occurs. A negative return value indicates that
681** no malloc() failure is scheduled.
682*/
683static int test_memdebug_pending(
684 void * clientData,
685 Tcl_Interp *interp,
686 int objc,
687 Tcl_Obj *CONST objv[]
688){
drh5efaf072008-03-18 00:07:10 +0000689 int nPending;
danielk1977cd037242007-08-30 15:46:06 +0000690 if( objc!=1 ){
691 Tcl_WrongNumArgs(interp, 1, objv, "");
692 return TCL_ERROR;
693 }
danielk1977ef05f2d2008-06-20 11:05:37 +0000694 nPending = faultsimPending();
drh5efaf072008-03-18 00:07:10 +0000695 Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));
danielk1977cd037242007-08-30 15:46:06 +0000696 return TCL_OK;
697}
698
drh0e6f1542007-08-15 20:41:28 +0000699
700/*
drh4a50aac2007-08-23 02:47:53 +0000701** Usage: sqlite3_memdebug_settitle TITLE
702**
703** Set a title string stored with each allocation. The TITLE is
704** typically the name of the test that was running when the
705** allocation occurred. The TITLE is stored with the allocation
706** and can be used to figure out which tests are leaking memory.
707**
708** Each title overwrite the previous.
709*/
710static int test_memdebug_settitle(
711 void * clientData,
712 Tcl_Interp *interp,
713 int objc,
714 Tcl_Obj *CONST objv[]
715){
716 const char *zTitle;
717 if( objc!=2 ){
718 Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
719 return TCL_ERROR;
720 }
721 zTitle = Tcl_GetString(objv[1]);
722#ifdef SQLITE_MEMDEBUG
723 {
drh49e4fd72008-02-19 15:15:15 +0000724 extern int sqlite3MemdebugSettitle(const char*);
725 sqlite3MemdebugSettitle(zTitle);
drh4a50aac2007-08-23 02:47:53 +0000726 }
727#endif
728 return TCL_OK;
729}
730
danielk1977cd3e8f72008-03-25 09:47:35 +0000731#define MALLOC_LOG_FRAMES 10
danielk19776f332c12008-03-21 14:22:44 +0000732static Tcl_HashTable aMallocLog;
733static int mallocLogEnabled = 0;
734
735typedef struct MallocLog MallocLog;
736struct MallocLog {
737 int nCall;
738 int nByte;
739};
740
shaneafdd23a2008-05-29 02:57:47 +0000741#ifdef SQLITE_MEMDEBUG
danielk19776f332c12008-03-21 14:22:44 +0000742static 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_FRAMES];
749 int nKey = sizeof(int)*MALLOC_LOG_FRAMES;
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}
shaneafdd23a2008-05-29 02:57:47 +0000770#endif /* SQLITE_MEMDEBUG */
danielk19776f332c12008-03-21 14:22:44 +0000771
danielk197764aca192009-04-07 11:21:28 +0000772static void test_memdebug_log_clear(void){
danielk1977dbdc4d42008-03-28 07:42:53 +0000773 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_FRAMES);
785}
786
danielk19776f332c12008-03-21 14:22:44 +0000787static int 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
danielk1977dbdc4d42008-03-28 07:42:53 +0000796 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 };
danielk19776f332c12008-03-21 14:22:44 +0000800
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_FRAMES);
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(int)==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 int *aKey = (int *)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_NewIntObj(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: {
danielk1977dbdc4d42008-03-28 07:42:53 +0000857 test_memdebug_log_clear();
858 break;
859 }
860
861 case MB_LOG_SYNC: {
drhb9404922008-03-28 12:53:38 +0000862#ifdef SQLITE_MEMDEBUG
danielk1977dbdc4d42008-03-28 07:42:53 +0000863 extern void sqlite3MemdebugSync();
864 test_memdebug_log_clear();
865 mallocLogEnabled = 1;
866 sqlite3MemdebugSync();
drhb9404922008-03-28 12:53:38 +0000867#endif
danielk1977dbdc4d42008-03-28 07:42:53 +0000868 break;
danielk19776f332c12008-03-21 14:22:44 +0000869 }
870 }
871
872 return TCL_OK;
873}
drh4a50aac2007-08-23 02:47:53 +0000874
875/*
drh9ac3fe92008-06-18 18:12:04 +0000876** Usage: sqlite3_config_scratch SIZE N
877**
878** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH.
879** The buffer is static and is of limited size. N might be
880** adjusted downward as needed to accomodate the requested size.
881** The revised value of N is returned.
882**
883** A negative SIZE causes the buffer pointer to be NULL.
884*/
885static int test_config_scratch(
886 void * clientData,
887 Tcl_Interp *interp,
888 int objc,
889 Tcl_Obj *CONST objv[]
890){
891 int sz, N, rc;
892 Tcl_Obj *pResult;
drh5f4bcf12008-07-29 14:29:06 +0000893 static char *buf = 0;
drh9ac3fe92008-06-18 18:12:04 +0000894 if( objc!=3 ){
895 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
896 return TCL_ERROR;
897 }
drhf7141992008-06-19 00:16:08 +0000898 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
899 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
drh5f4bcf12008-07-29 14:29:06 +0000900 free(buf);
drh9ac3fe92008-06-18 18:12:04 +0000901 if( sz<0 ){
drh5f4bcf12008-07-29 14:29:06 +0000902 buf = 0;
drh9ac3fe92008-06-18 18:12:04 +0000903 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0);
drhf7141992008-06-19 00:16:08 +0000904 }else{
drh6480aad2008-08-01 16:31:14 +0000905 buf = malloc( sz*N + 1 );
drh9ac3fe92008-06-18 18:12:04 +0000906 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N);
907 }
908 pResult = Tcl_NewObj();
909 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
910 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
911 Tcl_SetObjResult(interp, pResult);
912 return TCL_OK;
913}
914
915/*
916** Usage: sqlite3_config_pagecache SIZE N
917**
918** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
919** The buffer is static and is of limited size. N might be
920** adjusted downward as needed to accomodate the requested size.
921** The revised value of N is returned.
922**
923** A negative SIZE causes the buffer pointer to be NULL.
924*/
925static int test_config_pagecache(
926 void * clientData,
927 Tcl_Interp *interp,
928 int objc,
929 Tcl_Obj *CONST objv[]
930){
931 int sz, N, rc;
932 Tcl_Obj *pResult;
drh5f4bcf12008-07-29 14:29:06 +0000933 static char *buf = 0;
drh9ac3fe92008-06-18 18:12:04 +0000934 if( objc!=3 ){
935 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
936 return TCL_ERROR;
937 }
drhf7141992008-06-19 00:16:08 +0000938 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
939 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
drh5f4bcf12008-07-29 14:29:06 +0000940 free(buf);
drh9ac3fe92008-06-18 18:12:04 +0000941 if( sz<0 ){
drh5f4bcf12008-07-29 14:29:06 +0000942 buf = 0;
drhf7141992008-06-19 00:16:08 +0000943 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0);
944 }else{
drh0a60a382008-07-31 17:16:05 +0000945 buf = malloc( sz*N );
drh9ac3fe92008-06-18 18:12:04 +0000946 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);
947 }
948 pResult = Tcl_NewObj();
949 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
950 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
951 Tcl_SetObjResult(interp, pResult);
952 return TCL_OK;
953}
954
drhf7141992008-06-19 00:16:08 +0000955/*
drhb232c232008-11-19 01:20:26 +0000956** Usage: sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED
957**
958** Set up the alternative test page cache. Install if INSTALL_FLAG is
959** true and uninstall (reverting to the default page cache) if INSTALL_FLAG
960** is false. DISCARD_CHANGE is an integer between 0 and 100 inclusive
961** which determines the chance of discarding a page when unpinned. 100
962** is certainty. 0 is never. PRNG_SEED is the pseudo-random number generator
963** seed.
964*/
965static int test_alt_pcache(
966 void * clientData,
967 Tcl_Interp *interp,
968 int objc,
969 Tcl_Obj *CONST objv[]
970){
971 int installFlag;
drhf2a84e32009-01-07 03:59:47 +0000972 int discardChance = 0;
973 int prngSeed = 0;
974 int highStress = 0;
975 extern void installTestPCache(int,unsigned,unsigned,unsigned);
976 if( objc<2 || objc>5 ){
977 Tcl_WrongNumArgs(interp, 1, objv,
978 "INSTALLFLAG DISCARDCHANCE PRNGSEEED HIGHSTRESS");
drhb232c232008-11-19 01:20:26 +0000979 return TCL_ERROR;
980 }
981 if( Tcl_GetIntFromObj(interp, objv[1], &installFlag) ) return TCL_ERROR;
drhf2a84e32009-01-07 03:59:47 +0000982 if( objc>=3 && Tcl_GetIntFromObj(interp, objv[2], &discardChance) ){
983 return TCL_ERROR;
984 }
985 if( objc>=4 && Tcl_GetIntFromObj(interp, objv[3], &prngSeed) ){
986 return TCL_ERROR;
987 }
988 if( objc>=5 && Tcl_GetIntFromObj(interp, objv[4], &highStress) ){
989 return TCL_ERROR;
990 }
drhb232c232008-11-19 01:20:26 +0000991 if( discardChance<0 || discardChance>100 ){
992 Tcl_AppendResult(interp, "discard-chance should be between 0 and 100",
993 (char*)0);
994 return TCL_ERROR;
995 }
drhf2a84e32009-01-07 03:59:47 +0000996 installTestPCache(installFlag, (unsigned)discardChance, (unsigned)prngSeed,
997 (unsigned)highStress);
drhb232c232008-11-19 01:20:26 +0000998 return TCL_OK;
999}
1000
1001/*
drh8a42cbd2008-07-10 18:13:42 +00001002** Usage: sqlite3_config_memstatus BOOLEAN
1003**
1004** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.
1005*/
1006static int test_config_memstatus(
1007 void * clientData,
1008 Tcl_Interp *interp,
1009 int objc,
1010 Tcl_Obj *CONST objv[]
1011){
1012 int enable, rc;
1013 if( objc!=2 ){
1014 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
1015 return TCL_ERROR;
1016 }
1017 if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR;
1018 rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable);
1019 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1020 return TCL_OK;
1021}
1022
1023/*
drh633e6d52008-07-28 19:34:53 +00001024** Usage: sqlite3_config_lookaside SIZE COUNT
1025**
1026*/
1027static int test_config_lookaside(
1028 void * clientData,
1029 Tcl_Interp *interp,
1030 int objc,
1031 Tcl_Obj *CONST objv[]
1032){
1033 int rc;
1034 int sz, cnt;
danielk1977ab7bee82008-10-15 11:43:55 +00001035 Tcl_Obj *pRet;
drh633e6d52008-07-28 19:34:53 +00001036 if( objc!=3 ){
1037 Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT");
1038 return TCL_ERROR;
1039 }
1040 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
1041 if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR;
danielk1977ab7bee82008-10-15 11:43:55 +00001042 pRet = Tcl_NewObj();
1043 Tcl_ListObjAppendElement(
1044 interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.szLookaside)
1045 );
1046 Tcl_ListObjAppendElement(
1047 interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.nLookaside)
1048 );
drh633e6d52008-07-28 19:34:53 +00001049 rc = sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt);
danielk1977ab7bee82008-10-15 11:43:55 +00001050 Tcl_SetObjResult(interp, pRet);
drh633e6d52008-07-28 19:34:53 +00001051 return TCL_OK;
1052}
1053
1054
1055/*
drhe9d1c722008-08-04 20:13:26 +00001056** Usage: sqlite3_db_config_lookaside CONNECTION BUFID SIZE COUNT
drh633e6d52008-07-28 19:34:53 +00001057**
drhe9d1c722008-08-04 20:13:26 +00001058** There are two static buffers with BUFID 1 and 2. Each static buffer
1059** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL
1060** which will cause sqlite3_db_config() to allocate space on its own.
drh633e6d52008-07-28 19:34:53 +00001061*/
1062static int test_db_config_lookaside(
1063 void * clientData,
1064 Tcl_Interp *interp,
1065 int objc,
1066 Tcl_Obj *CONST objv[]
1067){
1068 int rc;
1069 int sz, cnt;
1070 sqlite3 *db;
drhe9d1c722008-08-04 20:13:26 +00001071 int bufid;
1072 static char azBuf[2][10000];
drh633e6d52008-07-28 19:34:53 +00001073 int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
drhe9d1c722008-08-04 20:13:26 +00001074 if( objc!=5 ){
1075 Tcl_WrongNumArgs(interp, 1, objv, "BUFID SIZE COUNT");
drh633e6d52008-07-28 19:34:53 +00001076 return TCL_ERROR;
1077 }
1078 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
drhe9d1c722008-08-04 20:13:26 +00001079 if( Tcl_GetIntFromObj(interp, objv[2], &bufid) ) return TCL_ERROR;
1080 if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR;
1081 if( Tcl_GetIntFromObj(interp, objv[4], &cnt) ) return TCL_ERROR;
1082 if( bufid==0 ){
1083 rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, 0, sz, cnt);
1084 }else if( bufid>=1 && bufid<=2 && sz*cnt<=sizeof(azBuf[0]) ){
1085 rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz,cnt);
1086 }else{
1087 Tcl_AppendResult(interp, "illegal arguments - see documentation", (char*)0);
1088 return TCL_ERROR;
1089 }
drh633e6d52008-07-28 19:34:53 +00001090 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1091 return TCL_OK;
1092}
1093
1094/*
danielk19775099be52008-06-27 13:27:03 +00001095** Usage:
1096**
drh8a42cbd2008-07-10 18:13:42 +00001097** sqlite3_config_heap NBYTE NMINALLOC
danielk19775099be52008-06-27 13:27:03 +00001098*/
1099static int test_config_heap(
1100 void * clientData,
1101 Tcl_Interp *interp,
1102 int objc,
1103 Tcl_Obj *CONST objv[]
1104){
drh7830cd42008-07-16 12:25:32 +00001105 static char *zBuf; /* Use this memory */
1106 static int szBuf; /* Bytes allocated for zBuf */
danielk19775099be52008-06-27 13:27:03 +00001107 int nByte; /* Size of buffer to pass to sqlite3_config() */
1108 int nMinAlloc; /* Size of minimum allocation */
1109 int rc; /* Return code of sqlite3_config() */
danielk19775099be52008-06-27 13:27:03 +00001110
1111 Tcl_Obj * CONST *aArg = &objv[1];
1112 int nArg = objc-1;
1113
danielk19775099be52008-06-27 13:27:03 +00001114 if( nArg!=2 ){
drh8a42cbd2008-07-10 18:13:42 +00001115 Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC");
danielk19775099be52008-06-27 13:27:03 +00001116 return TCL_ERROR;
1117 }
1118 if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
1119 if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR;
1120
danielk19770d84e5b2008-06-27 14:05:24 +00001121 if( nByte==0 ){
drh7830cd42008-07-16 12:25:32 +00001122 free( zBuf );
1123 zBuf = 0;
1124 szBuf = 0;
drh8a42cbd2008-07-10 18:13:42 +00001125 rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0);
danielk19770d84e5b2008-06-27 14:05:24 +00001126 }else{
drh7830cd42008-07-16 12:25:32 +00001127 zBuf = realloc(zBuf, nByte);
1128 szBuf = nByte;
danielk19770d84e5b2008-06-27 14:05:24 +00001129 rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc);
danielk19775099be52008-06-27 13:27:03 +00001130 }
danielk19775099be52008-06-27 13:27:03 +00001131
1132 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
1133 return TCL_OK;
1134}
1135
1136/*
drh6480aad2008-08-01 16:31:14 +00001137** tclcmd: sqlite3_config_error [DB]
1138**
1139** Invoke sqlite3_config() or sqlite3_db_config() with invalid
1140** opcodes and verify that they return errors.
1141*/
1142static int test_config_error(
1143 void * clientData,
1144 Tcl_Interp *interp,
1145 int objc,
1146 Tcl_Obj *CONST objv[]
1147){
1148 sqlite3 *db;
1149 int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1150
1151 if( objc!=2 && objc!=1 ){
1152 Tcl_WrongNumArgs(interp, 1, objv, "[DB]");
1153 return TCL_ERROR;
1154 }
1155 if( objc==2 ){
1156 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1157 if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){
1158 Tcl_AppendResult(interp,
1159 "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR",
1160 (char*)0);
1161 return TCL_ERROR;
1162 }
1163 }else{
1164 if( sqlite3_config(99999)!=SQLITE_ERROR ){
1165 Tcl_AppendResult(interp,
1166 "sqlite3_config(99999) does not return SQLITE_ERROR",
1167 (char*)0);
1168 return TCL_ERROR;
1169 }
1170 }
1171 return TCL_OK;
1172}
1173
1174/*
danielk1977c66c0e12008-06-25 14:26:07 +00001175** Usage:
1176**
1177** sqlite3_dump_memsys3 FILENAME
1178** sqlite3_dump_memsys5 FILENAME
danielk197732155ef2008-06-25 10:34:34 +00001179**
1180** Write a summary of unfreed memsys3 allocations to FILENAME.
1181*/
1182static int test_dump_memsys3(
1183 void * clientData,
1184 Tcl_Interp *interp,
1185 int objc,
1186 Tcl_Obj *CONST objv[]
1187){
1188 if( objc!=2 ){
1189 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
1190 return TCL_ERROR;
1191 }
danielk1977c66c0e12008-06-25 14:26:07 +00001192
1193 switch( (int)clientData ){
danielk19770d84e5b2008-06-27 14:05:24 +00001194 case 3: {
danielk1977c66c0e12008-06-25 14:26:07 +00001195#ifdef SQLITE_ENABLE_MEMSYS3
1196 extern void sqlite3Memsys3Dump(const char*);
1197 sqlite3Memsys3Dump(Tcl_GetString(objv[1]));
1198 break;
danielk197732155ef2008-06-25 10:34:34 +00001199#endif
danielk1977c66c0e12008-06-25 14:26:07 +00001200 }
danielk19770d84e5b2008-06-27 14:05:24 +00001201 case 5: {
danielk1977c66c0e12008-06-25 14:26:07 +00001202#ifdef SQLITE_ENABLE_MEMSYS5
1203 extern void sqlite3Memsys5Dump(const char*);
1204 sqlite3Memsys5Dump(Tcl_GetString(objv[1]));
1205 break;
1206#endif
1207 }
1208 }
danielk197732155ef2008-06-25 10:34:34 +00001209 return TCL_OK;
1210}
1211
1212/*
drhf7141992008-06-19 00:16:08 +00001213** Usage: sqlite3_status OPCODE RESETFLAG
1214**
1215** Return a list of three elements which are the sqlite3_status() return
1216** code, the current value, and the high-water mark value.
1217*/
1218static int test_status(
1219 void * clientData,
1220 Tcl_Interp *interp,
1221 int objc,
1222 Tcl_Obj *CONST objv[]
1223){
1224 int rc, iValue, mxValue;
1225 int i, op, resetFlag;
1226 const char *zOpName;
1227 static const struct {
1228 const char *zName;
1229 int op;
1230 } aOp[] = {
1231 { "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED },
drhe50135e2008-08-05 17:53:22 +00001232 { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE },
drhf7141992008-06-19 00:16:08 +00001233 { "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED },
1234 { "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW },
drhe50135e2008-08-05 17:53:22 +00001235 { "SQLITE_STATUS_PAGECACHE_SIZE", SQLITE_STATUS_PAGECACHE_SIZE },
drhf7141992008-06-19 00:16:08 +00001236 { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED },
1237 { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW },
drhe50135e2008-08-05 17:53:22 +00001238 { "SQLITE_STATUS_SCRATCH_SIZE", SQLITE_STATUS_SCRATCH_SIZE },
drhec424a52008-07-25 15:39:03 +00001239 { "SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK },
drhf7141992008-06-19 00:16:08 +00001240 };
1241 Tcl_Obj *pResult;
1242 if( objc!=3 ){
1243 Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
1244 return TCL_ERROR;
1245 }
1246 zOpName = Tcl_GetString(objv[1]);
1247 for(i=0; i<ArraySize(aOp); i++){
1248 if( strcmp(aOp[i].zName, zOpName)==0 ){
1249 op = aOp[i].op;
1250 break;
1251 }
1252 }
1253 if( i>=ArraySize(aOp) ){
1254 if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;
1255 }
1256 if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;
drhaf005fb2008-07-09 16:51:51 +00001257 iValue = 0;
1258 mxValue = 0;
drhf7141992008-06-19 00:16:08 +00001259 rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);
1260 pResult = Tcl_NewObj();
1261 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1262 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1263 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1264 Tcl_SetObjResult(interp, pResult);
1265 return TCL_OK;
1266}
drh9ac3fe92008-06-18 18:12:04 +00001267
1268/*
drh633e6d52008-07-28 19:34:53 +00001269** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG
1270**
1271** Return a list of three elements which are the sqlite3_db_status() return
1272** code, the current value, and the high-water mark value.
1273*/
1274static int test_db_status(
1275 void * clientData,
1276 Tcl_Interp *interp,
1277 int objc,
1278 Tcl_Obj *CONST objv[]
1279){
1280 int rc, iValue, mxValue;
1281 int i, op, resetFlag;
1282 const char *zOpName;
1283 sqlite3 *db;
1284 int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1285 static const struct {
1286 const char *zName;
1287 int op;
1288 } aOp[] = {
1289 { "SQLITE_DBSTATUS_LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED },
drh63da0892010-03-10 21:42:07 +00001290 { "SQLITE_DBSTATUS_CACHE_USED", SQLITE_DBSTATUS_CACHE_USED },
drh633e6d52008-07-28 19:34:53 +00001291 };
1292 Tcl_Obj *pResult;
1293 if( objc!=4 ){
1294 Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
1295 return TCL_ERROR;
1296 }
1297 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1298 zOpName = Tcl_GetString(objv[2]);
1299 for(i=0; i<ArraySize(aOp); i++){
1300 if( strcmp(aOp[i].zName, zOpName)==0 ){
1301 op = aOp[i].op;
1302 break;
1303 }
1304 }
1305 if( i>=ArraySize(aOp) ){
1306 if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR;
1307 }
1308 if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR;
1309 iValue = 0;
1310 mxValue = 0;
1311 rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag);
1312 pResult = Tcl_NewObj();
1313 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1314 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1315 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1316 Tcl_SetObjResult(interp, pResult);
1317 return TCL_OK;
1318}
1319
1320/*
danielk1977d09414c2008-06-19 18:17:49 +00001321** install_malloc_faultsim BOOLEAN
1322*/
1323static int test_install_malloc_faultsim(
1324 void * clientData,
1325 Tcl_Interp *interp,
1326 int objc,
1327 Tcl_Obj *CONST objv[]
1328){
1329 int rc;
1330 int isInstall;
1331
1332 if( objc!=2 ){
1333 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
1334 return TCL_ERROR;
1335 }
1336 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
1337 return TCL_ERROR;
1338 }
danielk1977ef05f2d2008-06-20 11:05:37 +00001339 rc = faultsimInstall(isInstall);
danielk1977d09414c2008-06-19 18:17:49 +00001340 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
1341 return TCL_OK;
1342}
1343
1344/*
danielk19778b322822009-07-01 18:09:01 +00001345** sqlite3_install_memsys3
1346*/
1347static int test_install_memsys3(
1348 void * clientData,
1349 Tcl_Interp *interp,
1350 int objc,
1351 Tcl_Obj *CONST objv[]
1352){
1353 int rc = SQLITE_MISUSE;
1354#ifdef SQLITE_ENABLE_MEMSYS3
1355 const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
1356 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetMemsys3());
1357#endif
1358 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
1359 return TCL_OK;
1360}
1361
1362/*
drh2f999a62007-08-15 19:16:43 +00001363** Register commands with the TCL interpreter.
1364*/
1365int Sqlitetest_malloc_Init(Tcl_Interp *interp){
1366 static struct {
1367 char *zName;
1368 Tcl_ObjCmdProc *xProc;
danielk1977c66c0e12008-06-25 14:26:07 +00001369 int clientData;
drh2f999a62007-08-15 19:16:43 +00001370 } aObjCmd[] = {
drh8a42cbd2008-07-10 18:13:42 +00001371 { "sqlite3_malloc", test_malloc ,0 },
1372 { "sqlite3_realloc", test_realloc ,0 },
1373 { "sqlite3_free", test_free ,0 },
1374 { "memset", test_memset ,0 },
1375 { "memget", test_memget ,0 },
1376 { "sqlite3_memory_used", test_memory_used ,0 },
1377 { "sqlite3_memory_highwater", test_memory_highwater ,0 },
1378 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace ,0 },
1379 { "sqlite3_memdebug_dump", test_memdebug_dump ,0 },
1380 { "sqlite3_memdebug_fail", test_memdebug_fail ,0 },
1381 { "sqlite3_memdebug_pending", test_memdebug_pending ,0 },
1382 { "sqlite3_memdebug_settitle", test_memdebug_settitle ,0 },
1383 { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 },
1384 { "sqlite3_memdebug_log", test_memdebug_log ,0 },
1385 { "sqlite3_config_scratch", test_config_scratch ,0 },
1386 { "sqlite3_config_pagecache", test_config_pagecache ,0 },
drhb232c232008-11-19 01:20:26 +00001387 { "sqlite3_config_alt_pcache", test_alt_pcache ,0 },
drh8a42cbd2008-07-10 18:13:42 +00001388 { "sqlite3_status", test_status ,0 },
drh633e6d52008-07-28 19:34:53 +00001389 { "sqlite3_db_status", test_db_status ,0 },
drh8a42cbd2008-07-10 18:13:42 +00001390 { "install_malloc_faultsim", test_install_malloc_faultsim ,0 },
danielk19770d84e5b2008-06-27 14:05:24 +00001391 { "sqlite3_config_heap", test_config_heap ,0 },
drh8a42cbd2008-07-10 18:13:42 +00001392 { "sqlite3_config_memstatus", test_config_memstatus ,0 },
drh633e6d52008-07-28 19:34:53 +00001393 { "sqlite3_config_lookaside", test_config_lookaside ,0 },
drh6480aad2008-08-01 16:31:14 +00001394 { "sqlite3_config_error", test_config_error ,0 },
drh633e6d52008-07-28 19:34:53 +00001395 { "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 },
danielk19770d84e5b2008-06-27 14:05:24 +00001396 { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
drhb232c232008-11-19 01:20:26 +00001397 { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },
danielk19778b322822009-07-01 18:09:01 +00001398 { "sqlite3_install_memsys3", test_install_memsys3 ,0 },
drh2f999a62007-08-15 19:16:43 +00001399 };
1400 int i;
1401 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
danielk1977c66c0e12008-06-25 14:26:07 +00001402 ClientData c = (ClientData)aObjCmd[i].clientData;
1403 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
drh2f999a62007-08-15 19:16:43 +00001404 }
1405 return TCL_OK;
1406}
danielk1977ef05f2d2008-06-20 11:05:37 +00001407#endif