xref: /sqlite-3.40.0/src/test_malloc.c (revision 7bb22ac7)
12f999a67Sdrh /*
22f999a67Sdrh ** 2007 August 15
32f999a67Sdrh **
42f999a67Sdrh ** The author disclaims copyright to this source code.  In place of
52f999a67Sdrh ** a legal notice, here is a blessing:
62f999a67Sdrh **
72f999a67Sdrh **    May you do good and not evil.
82f999a67Sdrh **    May you find forgiveness for yourself and forgive others.
92f999a67Sdrh **    May you share freely, never taking more than you give.
102f999a67Sdrh **
112f999a67Sdrh *************************************************************************
122f999a67Sdrh **
132f999a67Sdrh ** This file contains code used to implement test interfaces to the
142f999a67Sdrh ** memory allocation subsystem.
152f999a67Sdrh */
162f999a67Sdrh #include "sqliteInt.h"
172f999a67Sdrh #include "tcl.h"
182f999a67Sdrh #include <stdlib.h>
192f999a67Sdrh #include <string.h>
202f999a67Sdrh #include <assert.h>
212f999a67Sdrh 
22ef05f2dfSdanielk1977 /*
23ef05f2dfSdanielk1977 ** This structure is used to encapsulate the global state variables used
24ef05f2dfSdanielk1977 ** by malloc() fault simulation.
25ef05f2dfSdanielk1977 */
26ef05f2dfSdanielk1977 static struct MemFault {
27ef05f2dfSdanielk1977   int iCountdown;         /* Number of pending successes before a failure */
28ef05f2dfSdanielk1977   int nRepeat;            /* Number of times to repeat the failure */
29ef05f2dfSdanielk1977   int nBenign;            /* Number of benign failures seen since last config */
30ef05f2dfSdanielk1977   int nFail;              /* Number of failures seen since last config */
31ef05f2dfSdanielk1977   u8 enable;              /* True if enabled */
32ef05f2dfSdanielk1977   int isInstalled;        /* True if the fault simulation layer is installed */
332d1d86fbSdanielk1977   int isBenignMode;       /* True if malloc failures are considered benign */
34ef05f2dfSdanielk1977   sqlite3_mem_methods m;  /* 'Real' malloc implementation */
35ef05f2dfSdanielk1977 } memfault;
36ef05f2dfSdanielk1977 
37ef05f2dfSdanielk1977 /*
38ef05f2dfSdanielk1977 ** This routine exists as a place to set a breakpoint that will
39ef05f2dfSdanielk1977 ** fire on any simulated malloc() failure.
40ef05f2dfSdanielk1977 */
41ef05f2dfSdanielk1977 static void sqlite3Fault(void){
42ef05f2dfSdanielk1977   static int cnt = 0;
43ef05f2dfSdanielk1977   cnt++;
44ef05f2dfSdanielk1977 }
45ef05f2dfSdanielk1977 
46ef05f2dfSdanielk1977 /*
47ef05f2dfSdanielk1977 ** Check to see if a fault should be simulated.  Return true to simulate
48ef05f2dfSdanielk1977 ** the fault.  Return false if the fault should not be simulated.
49ef05f2dfSdanielk1977 */
5064aca191Sdanielk1977 static int faultsimStep(void){
51ef05f2dfSdanielk1977   if( likely(!memfault.enable) ){
52ef05f2dfSdanielk1977     return 0;
53ef05f2dfSdanielk1977   }
54ef05f2dfSdanielk1977   if( memfault.iCountdown>0 ){
55ef05f2dfSdanielk1977     memfault.iCountdown--;
56ef05f2dfSdanielk1977     return 0;
57ef05f2dfSdanielk1977   }
58ef05f2dfSdanielk1977   sqlite3Fault();
59ef05f2dfSdanielk1977   memfault.nFail++;
602d1d86fbSdanielk1977   if( memfault.isBenignMode>0 ){
61ef05f2dfSdanielk1977     memfault.nBenign++;
62ef05f2dfSdanielk1977   }
63ef05f2dfSdanielk1977   memfault.nRepeat--;
64ef05f2dfSdanielk1977   if( memfault.nRepeat<=0 ){
65ef05f2dfSdanielk1977     memfault.enable = 0;
66ef05f2dfSdanielk1977   }
67ef05f2dfSdanielk1977   return 1;
68ef05f2dfSdanielk1977 }
69ef05f2dfSdanielk1977 
70ef05f2dfSdanielk1977 /*
71ef05f2dfSdanielk1977 ** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation
72ef05f2dfSdanielk1977 ** logic.
73ef05f2dfSdanielk1977 */
74ef05f2dfSdanielk1977 static void *faultsimMalloc(int n){
75ef05f2dfSdanielk1977   void *p = 0;
76ef05f2dfSdanielk1977   if( !faultsimStep() ){
77ef05f2dfSdanielk1977     p = memfault.m.xMalloc(n);
78ef05f2dfSdanielk1977   }
79ef05f2dfSdanielk1977   return p;
80ef05f2dfSdanielk1977 }
81ef05f2dfSdanielk1977 
82ef05f2dfSdanielk1977 
83ef05f2dfSdanielk1977 /*
84ef05f2dfSdanielk1977 ** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation
85ef05f2dfSdanielk1977 ** logic.
86ef05f2dfSdanielk1977 */
87ef05f2dfSdanielk1977 static void *faultsimRealloc(void *pOld, int n){
88ef05f2dfSdanielk1977   void *p = 0;
89ef05f2dfSdanielk1977   if( !faultsimStep() ){
90ef05f2dfSdanielk1977     p = memfault.m.xRealloc(pOld, n);
91ef05f2dfSdanielk1977   }
92ef05f2dfSdanielk1977   return p;
93ef05f2dfSdanielk1977 }
94ef05f2dfSdanielk1977 
95ef05f2dfSdanielk1977 /*
96ef05f2dfSdanielk1977 ** The following method calls are passed directly through to the underlying
97ef05f2dfSdanielk1977 ** malloc system:
98ef05f2dfSdanielk1977 **
99ef05f2dfSdanielk1977 **     xFree
100ef05f2dfSdanielk1977 **     xSize
101ef05f2dfSdanielk1977 **     xRoundup
102ef05f2dfSdanielk1977 **     xInit
103ef05f2dfSdanielk1977 **     xShutdown
104ef05f2dfSdanielk1977 */
105ef05f2dfSdanielk1977 static void faultsimFree(void *p){
106ef05f2dfSdanielk1977   memfault.m.xFree(p);
107ef05f2dfSdanielk1977 }
108ef05f2dfSdanielk1977 static int faultsimSize(void *p){
109ef05f2dfSdanielk1977   return memfault.m.xSize(p);
110ef05f2dfSdanielk1977 }
111ef05f2dfSdanielk1977 static int faultsimRoundup(int n){
112ef05f2dfSdanielk1977   return memfault.m.xRoundup(n);
113ef05f2dfSdanielk1977 }
114ef05f2dfSdanielk1977 static int faultsimInit(void *p){
115ef05f2dfSdanielk1977   return memfault.m.xInit(memfault.m.pAppData);
116ef05f2dfSdanielk1977 }
117ef05f2dfSdanielk1977 static void faultsimShutdown(void *p){
118ef05f2dfSdanielk1977   memfault.m.xShutdown(memfault.m.pAppData);
119ef05f2dfSdanielk1977 }
120ef05f2dfSdanielk1977 
121ef05f2dfSdanielk1977 /*
122ef05f2dfSdanielk1977 ** This routine configures the malloc failure simulation.  After
123ef05f2dfSdanielk1977 ** calling this routine, the next nDelay mallocs will succeed, followed
124ef05f2dfSdanielk1977 ** by a block of nRepeat failures, after which malloc() calls will begin
125ef05f2dfSdanielk1977 ** to succeed again.
126ef05f2dfSdanielk1977 */
127ef05f2dfSdanielk1977 static void faultsimConfig(int nDelay, int nRepeat){
128ef05f2dfSdanielk1977   memfault.iCountdown = nDelay;
129ef05f2dfSdanielk1977   memfault.nRepeat = nRepeat;
130ef05f2dfSdanielk1977   memfault.nBenign = 0;
131ef05f2dfSdanielk1977   memfault.nFail = 0;
132ef05f2dfSdanielk1977   memfault.enable = nDelay>=0;
133b48c1f19Sdanielk1977 
134b48c1f19Sdanielk1977   /* Sometimes, when running multi-threaded tests, the isBenignMode
135b48c1f19Sdanielk1977   ** variable is not properly incremented/decremented so that it is
136b48c1f19Sdanielk1977   ** 0 when not inside a benign malloc block. This doesn't affect
137b48c1f19Sdanielk1977   ** the multi-threaded tests, as they do not use this system. But
138b48c1f19Sdanielk1977   ** it does affect OOM tests run later in the same process. So
139b48c1f19Sdanielk1977   ** zero the variable here, just to be sure.
140b48c1f19Sdanielk1977   */
141b48c1f19Sdanielk1977   memfault.isBenignMode = 0;
142ef05f2dfSdanielk1977 }
143ef05f2dfSdanielk1977 
144ef05f2dfSdanielk1977 /*
145ef05f2dfSdanielk1977 ** Return the number of faults (both hard and benign faults) that have
146ef05f2dfSdanielk1977 ** occurred since the injector was last configured.
147ef05f2dfSdanielk1977 */
148ef05f2dfSdanielk1977 static int faultsimFailures(void){
149ef05f2dfSdanielk1977   return memfault.nFail;
150ef05f2dfSdanielk1977 }
151ef05f2dfSdanielk1977 
152ef05f2dfSdanielk1977 /*
153ef05f2dfSdanielk1977 ** Return the number of benign faults that have occurred since the
154ef05f2dfSdanielk1977 ** injector was last configured.
155ef05f2dfSdanielk1977 */
156ef05f2dfSdanielk1977 static int faultsimBenignFailures(void){
157ef05f2dfSdanielk1977   return memfault.nBenign;
158ef05f2dfSdanielk1977 }
159ef05f2dfSdanielk1977 
160ef05f2dfSdanielk1977 /*
161ef05f2dfSdanielk1977 ** Return the number of successes that will occur before the next failure.
162ef05f2dfSdanielk1977 ** If no failures are scheduled, return -1.
163ef05f2dfSdanielk1977 */
164ef05f2dfSdanielk1977 static int faultsimPending(void){
165ef05f2dfSdanielk1977   if( memfault.enable ){
166ef05f2dfSdanielk1977     return memfault.iCountdown;
167ef05f2dfSdanielk1977   }else{
168ef05f2dfSdanielk1977     return -1;
169ef05f2dfSdanielk1977   }
170ef05f2dfSdanielk1977 }
171ef05f2dfSdanielk1977 
1722d1d86fbSdanielk1977 
1732d1d86fbSdanielk1977 static void faultsimBeginBenign(void){
1742d1d86fbSdanielk1977   memfault.isBenignMode++;
1752d1d86fbSdanielk1977 }
1762d1d86fbSdanielk1977 static void faultsimEndBenign(void){
1772d1d86fbSdanielk1977   memfault.isBenignMode--;
1782d1d86fbSdanielk1977 }
1792d1d86fbSdanielk1977 
180ef05f2dfSdanielk1977 /*
181ef05f2dfSdanielk1977 ** Add or remove the fault-simulation layer using sqlite3_config(). If
182ef05f2dfSdanielk1977 ** the argument is non-zero, the
183ef05f2dfSdanielk1977 */
184ef05f2dfSdanielk1977 static int faultsimInstall(int install){
185ef05f2dfSdanielk1977   static struct sqlite3_mem_methods m = {
186ef05f2dfSdanielk1977     faultsimMalloc,                   /* xMalloc */
187ef05f2dfSdanielk1977     faultsimFree,                     /* xFree */
188ef05f2dfSdanielk1977     faultsimRealloc,                  /* xRealloc */
189ef05f2dfSdanielk1977     faultsimSize,                     /* xSize */
190ef05f2dfSdanielk1977     faultsimRoundup,                  /* xRoundup */
191ef05f2dfSdanielk1977     faultsimInit,                     /* xInit */
192ef05f2dfSdanielk1977     faultsimShutdown,                 /* xShutdown */
193ef05f2dfSdanielk1977     0                                 /* pAppData */
194ef05f2dfSdanielk1977   };
195ef05f2dfSdanielk1977   int rc;
196ef05f2dfSdanielk1977 
197ef05f2dfSdanielk1977   install = (install ? 1 : 0);
198ef05f2dfSdanielk1977   assert(memfault.isInstalled==1 || memfault.isInstalled==0);
199ef05f2dfSdanielk1977 
200ef05f2dfSdanielk1977   if( install==memfault.isInstalled ){
201ef05f2dfSdanielk1977     return SQLITE_ERROR;
202ef05f2dfSdanielk1977   }
203ef05f2dfSdanielk1977 
2042d1d86fbSdanielk1977   if( install ){
205ef05f2dfSdanielk1977     rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);
206ef05f2dfSdanielk1977     assert(memfault.m.xMalloc);
207ef05f2dfSdanielk1977     if( rc==SQLITE_OK ){
208ef05f2dfSdanielk1977       rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
209ef05f2dfSdanielk1977     }
2102d1d86fbSdanielk1977     sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
2112d1d86fbSdanielk1977         faultsimBeginBenign, faultsimEndBenign
2122d1d86fbSdanielk1977     );
2132d1d86fbSdanielk1977   }else{
2141b67f3caSdrh     sqlite3_mem_methods m;
2152d1d86fbSdanielk1977     assert(memfault.m.xMalloc);
2161b67f3caSdrh 
2171b67f3caSdrh     /* One should be able to reset the default memory allocator by storing
2181b67f3caSdrh     ** a zeroed allocator then calling GETMALLOC. */
2191b67f3caSdrh     memset(&m, 0, sizeof(m));
2201b67f3caSdrh     sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
2211b67f3caSdrh     sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m);
2221b67f3caSdrh     assert( memcmp(&m, &memfault.m, sizeof(m))==0 );
2231b67f3caSdrh 
2242d1d86fbSdanielk1977     rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m);
2252d1d86fbSdanielk1977     sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 0, 0);
2262d1d86fbSdanielk1977   }
227ef05f2dfSdanielk1977 
228ef05f2dfSdanielk1977   if( rc==SQLITE_OK ){
229ef05f2dfSdanielk1977     memfault.isInstalled = 1;
230ef05f2dfSdanielk1977   }
231ef05f2dfSdanielk1977   return rc;
232ef05f2dfSdanielk1977 }
233ef05f2dfSdanielk1977 
234ef05f2dfSdanielk1977 #ifdef SQLITE_TEST
235ef05f2dfSdanielk1977 
236ef05f2dfSdanielk1977 /*
237e84d8d32Smistachkin ** This function is implemented in main.c. Returns a pointer to a static
238ef05f2dfSdanielk1977 ** buffer containing the symbolic SQLite error code that corresponds to
239ef05f2dfSdanielk1977 ** the least-significant 8-bits of the integer passed as an argument.
240ef05f2dfSdanielk1977 ** For example:
241ef05f2dfSdanielk1977 **
242e84d8d32Smistachkin **   sqlite3ErrName(1) -> "SQLITE_ERROR"
243ef05f2dfSdanielk1977 */
244e84d8d32Smistachkin extern const char *sqlite3ErrName(int);
245d09414cdSdanielk1977 
2462f999a67Sdrh /*
2472f999a67Sdrh ** Transform pointers to text and back again
2482f999a67Sdrh */
2492f999a67Sdrh static void pointerToText(void *p, char *z){
2502f999a67Sdrh   static const char zHex[] = "0123456789abcdef";
2512f999a67Sdrh   int i, k;
2524a50aac5Sdrh   unsigned int u;
2534a50aac5Sdrh   sqlite3_uint64 n;
2548a42cbd3Sdrh   if( p==0 ){
2558a42cbd3Sdrh     strcpy(z, "0");
2568a42cbd3Sdrh     return;
2578a42cbd3Sdrh   }
2584a50aac5Sdrh   if( sizeof(n)==sizeof(p) ){
2594a50aac5Sdrh     memcpy(&n, &p, sizeof(p));
2604a50aac5Sdrh   }else if( sizeof(u)==sizeof(p) ){
2614a50aac5Sdrh     memcpy(&u, &p, sizeof(u));
2624a50aac5Sdrh     n = u;
2634a50aac5Sdrh   }else{
2644a50aac5Sdrh     assert( 0 );
2654a50aac5Sdrh   }
2662f999a67Sdrh   for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
2672f999a67Sdrh     z[k] = zHex[n&0xf];
2682f999a67Sdrh     n >>= 4;
2692f999a67Sdrh   }
2702f999a67Sdrh   z[sizeof(p)*2] = 0;
2712f999a67Sdrh }
2722f999a67Sdrh static int hexToInt(int h){
2732f999a67Sdrh   if( h>='0' && h<='9' ){
2742f999a67Sdrh     return h - '0';
2752f999a67Sdrh   }else if( h>='a' && h<='f' ){
2762f999a67Sdrh     return h - 'a' + 10;
2772f999a67Sdrh   }else{
2782f999a67Sdrh     return -1;
2792f999a67Sdrh   }
2802f999a67Sdrh }
2812f999a67Sdrh static int textToPointer(const char *z, void **pp){
2822f999a67Sdrh   sqlite3_uint64 n = 0;
2832f999a67Sdrh   int i;
2844a50aac5Sdrh   unsigned int u;
2852f999a67Sdrh   for(i=0; i<sizeof(void*)*2 && z[0]; i++){
2862f999a67Sdrh     int v;
2872f999a67Sdrh     v = hexToInt(*z++);
2882f999a67Sdrh     if( v<0 ) return TCL_ERROR;
2892f999a67Sdrh     n = n*16 + v;
2902f999a67Sdrh   }
2912f999a67Sdrh   if( *z!=0 ) return TCL_ERROR;
2924a50aac5Sdrh   if( sizeof(n)==sizeof(*pp) ){
2934a50aac5Sdrh     memcpy(pp, &n, sizeof(n));
2944a50aac5Sdrh   }else if( sizeof(u)==sizeof(*pp) ){
2954a50aac5Sdrh     u = (unsigned int)n;
2964a50aac5Sdrh     memcpy(pp, &u, sizeof(u));
2974a50aac5Sdrh   }else{
2984a50aac5Sdrh     assert( 0 );
2994a50aac5Sdrh   }
3002f999a67Sdrh   return TCL_OK;
3012f999a67Sdrh }
3022f999a67Sdrh 
3032f999a67Sdrh /*
3042f999a67Sdrh ** Usage:    sqlite3_malloc  NBYTES
3052f999a67Sdrh **
3062f999a67Sdrh ** Raw test interface for sqlite3_malloc().
3072f999a67Sdrh */
3082f999a67Sdrh static int test_malloc(
3092f999a67Sdrh   void * clientData,
3102f999a67Sdrh   Tcl_Interp *interp,
3112f999a67Sdrh   int objc,
3122f999a67Sdrh   Tcl_Obj *CONST objv[]
3132f999a67Sdrh ){
3142f999a67Sdrh   int nByte;
3152f999a67Sdrh   void *p;
3162f999a67Sdrh   char zOut[100];
3172f999a67Sdrh   if( objc!=2 ){
3182f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
3192f999a67Sdrh     return TCL_ERROR;
3202f999a67Sdrh   }
3212f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
3222f999a67Sdrh   p = sqlite3_malloc((unsigned)nByte);
3232f999a67Sdrh   pointerToText(p, zOut);
3242f999a67Sdrh   Tcl_AppendResult(interp, zOut, NULL);
3252f999a67Sdrh   return TCL_OK;
3262f999a67Sdrh }
3272f999a67Sdrh 
3282f999a67Sdrh /*
3292f999a67Sdrh ** Usage:    sqlite3_realloc  PRIOR  NBYTES
3302f999a67Sdrh **
3312f999a67Sdrh ** Raw test interface for sqlite3_realloc().
3322f999a67Sdrh */
3332f999a67Sdrh static int test_realloc(
3342f999a67Sdrh   void * clientData,
3352f999a67Sdrh   Tcl_Interp *interp,
3362f999a67Sdrh   int objc,
3372f999a67Sdrh   Tcl_Obj *CONST objv[]
3382f999a67Sdrh ){
3392f999a67Sdrh   int nByte;
3402f999a67Sdrh   void *pPrior, *p;
3412f999a67Sdrh   char zOut[100];
3422f999a67Sdrh   if( objc!=3 ){
3432f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
3442f999a67Sdrh     return TCL_ERROR;
3452f999a67Sdrh   }
3462f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
3472f999a67Sdrh   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
3482f999a67Sdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
3492f999a67Sdrh     return TCL_ERROR;
3502f999a67Sdrh   }
3512f999a67Sdrh   p = sqlite3_realloc(pPrior, (unsigned)nByte);
3522f999a67Sdrh   pointerToText(p, zOut);
3532f999a67Sdrh   Tcl_AppendResult(interp, zOut, NULL);
3542f999a67Sdrh   return TCL_OK;
3552f999a67Sdrh }
3562f999a67Sdrh 
3572f999a67Sdrh /*
3582f999a67Sdrh ** Usage:    sqlite3_free  PRIOR
3592f999a67Sdrh **
3602f999a67Sdrh ** Raw test interface for sqlite3_free().
3612f999a67Sdrh */
3622f999a67Sdrh static int test_free(
3632f999a67Sdrh   void * clientData,
3642f999a67Sdrh   Tcl_Interp *interp,
3652f999a67Sdrh   int objc,
3662f999a67Sdrh   Tcl_Obj *CONST objv[]
3672f999a67Sdrh ){
3682f999a67Sdrh   void *pPrior;
3692f999a67Sdrh   if( objc!=2 ){
3702f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
3712f999a67Sdrh     return TCL_ERROR;
3722f999a67Sdrh   }
3732f999a67Sdrh   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
3742f999a67Sdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
3752f999a67Sdrh     return TCL_ERROR;
3762f999a67Sdrh   }
3772f999a67Sdrh   sqlite3_free(pPrior);
3782f999a67Sdrh   return TCL_OK;
3792f999a67Sdrh }
3802f999a67Sdrh 
3812f999a67Sdrh /*
3829c7a60dfSdrh ** These routines are in test_hexio.c
3839c7a60dfSdrh */
3849c7a60dfSdrh int sqlite3TestHexToBin(const char *, int, char *);
3859c7a60dfSdrh int sqlite3TestBinToHex(char*,int);
3869c7a60dfSdrh 
3879c7a60dfSdrh /*
3889c7a60dfSdrh ** Usage:    memset  ADDRESS  SIZE  HEX
3899c7a60dfSdrh **
3909c7a60dfSdrh ** Set a chunk of memory (obtained from malloc, probably) to a
3919c7a60dfSdrh ** specified hex pattern.
3929c7a60dfSdrh */
3939c7a60dfSdrh static int test_memset(
3949c7a60dfSdrh   void * clientData,
3959c7a60dfSdrh   Tcl_Interp *interp,
3969c7a60dfSdrh   int objc,
3979c7a60dfSdrh   Tcl_Obj *CONST objv[]
3989c7a60dfSdrh ){
3999c7a60dfSdrh   void *p;
4009c7a60dfSdrh   int size, n, i;
4019c7a60dfSdrh   char *zHex;
4029c7a60dfSdrh   char *zOut;
4039c7a60dfSdrh   char zBin[100];
4049c7a60dfSdrh 
4059c7a60dfSdrh   if( objc!=4 ){
4069c7a60dfSdrh     Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
4079c7a60dfSdrh     return TCL_ERROR;
4089c7a60dfSdrh   }
4099c7a60dfSdrh   if( textToPointer(Tcl_GetString(objv[1]), &p) ){
4109c7a60dfSdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
4119c7a60dfSdrh     return TCL_ERROR;
4129c7a60dfSdrh   }
4139c7a60dfSdrh   if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
4149c7a60dfSdrh     return TCL_ERROR;
4159c7a60dfSdrh   }
4169c7a60dfSdrh   if( size<=0 ){
4179c7a60dfSdrh     Tcl_AppendResult(interp, "size must be positive", (char*)0);
4189c7a60dfSdrh     return TCL_ERROR;
4199c7a60dfSdrh   }
4209c7a60dfSdrh   zHex = Tcl_GetStringFromObj(objv[3], &n);
4219c7a60dfSdrh   if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
4229c7a60dfSdrh   n = sqlite3TestHexToBin(zHex, n, zBin);
4239c7a60dfSdrh   if( n==0 ){
4249c7a60dfSdrh     Tcl_AppendResult(interp, "no data", (char*)0);
4259c7a60dfSdrh     return TCL_ERROR;
4269c7a60dfSdrh   }
4279c7a60dfSdrh   zOut = p;
4289c7a60dfSdrh   for(i=0; i<size; i++){
4299c7a60dfSdrh     zOut[i] = zBin[i%n];
4309c7a60dfSdrh   }
4319c7a60dfSdrh   return TCL_OK;
4329c7a60dfSdrh }
4339c7a60dfSdrh 
4349c7a60dfSdrh /*
4359c7a60dfSdrh ** Usage:    memget  ADDRESS  SIZE
4369c7a60dfSdrh **
4379c7a60dfSdrh ** Return memory as hexadecimal text.
4389c7a60dfSdrh */
4399c7a60dfSdrh static int test_memget(
4409c7a60dfSdrh   void * clientData,
4419c7a60dfSdrh   Tcl_Interp *interp,
4429c7a60dfSdrh   int objc,
4439c7a60dfSdrh   Tcl_Obj *CONST objv[]
4449c7a60dfSdrh ){
4459c7a60dfSdrh   void *p;
4469c7a60dfSdrh   int size, n;
4479c7a60dfSdrh   char *zBin;
4489c7a60dfSdrh   char zHex[100];
4499c7a60dfSdrh 
4509c7a60dfSdrh   if( objc!=3 ){
4519c7a60dfSdrh     Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");
4529c7a60dfSdrh     return TCL_ERROR;
4539c7a60dfSdrh   }
4549c7a60dfSdrh   if( textToPointer(Tcl_GetString(objv[1]), &p) ){
4559c7a60dfSdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
4569c7a60dfSdrh     return TCL_ERROR;
4579c7a60dfSdrh   }
4589c7a60dfSdrh   if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
4599c7a60dfSdrh     return TCL_ERROR;
4609c7a60dfSdrh   }
4619c7a60dfSdrh   if( size<=0 ){
4629c7a60dfSdrh     Tcl_AppendResult(interp, "size must be positive", (char*)0);
4639c7a60dfSdrh     return TCL_ERROR;
4649c7a60dfSdrh   }
4659c7a60dfSdrh   zBin = p;
4669c7a60dfSdrh   while( size>0 ){
4679c7a60dfSdrh     if( size>(sizeof(zHex)-1)/2 ){
4689c7a60dfSdrh       n = (sizeof(zHex)-1)/2;
4699c7a60dfSdrh     }else{
4709c7a60dfSdrh       n = size;
4719c7a60dfSdrh     }
4729c7a60dfSdrh     memcpy(zHex, zBin, n);
4739c7a60dfSdrh     zBin += n;
4749c7a60dfSdrh     size -= n;
4759c7a60dfSdrh     sqlite3TestBinToHex(zHex, n);
4769c7a60dfSdrh     Tcl_AppendResult(interp, zHex, (char*)0);
4779c7a60dfSdrh   }
4789c7a60dfSdrh   return TCL_OK;
4799c7a60dfSdrh }
4809c7a60dfSdrh 
4819c7a60dfSdrh /*
4822f999a67Sdrh ** Usage:    sqlite3_memory_used
4832f999a67Sdrh **
4842f999a67Sdrh ** Raw test interface for sqlite3_memory_used().
4852f999a67Sdrh */
4862f999a67Sdrh static int test_memory_used(
4872f999a67Sdrh   void * clientData,
4882f999a67Sdrh   Tcl_Interp *interp,
4892f999a67Sdrh   int objc,
4902f999a67Sdrh   Tcl_Obj *CONST objv[]
4912f999a67Sdrh ){
4922f999a67Sdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
4932f999a67Sdrh   return TCL_OK;
4942f999a67Sdrh }
4952f999a67Sdrh 
4962f999a67Sdrh /*
4972f999a67Sdrh ** Usage:    sqlite3_memory_highwater ?RESETFLAG?
4982f999a67Sdrh **
4992f999a67Sdrh ** Raw test interface for sqlite3_memory_highwater().
5002f999a67Sdrh */
5012f999a67Sdrh static int test_memory_highwater(
5022f999a67Sdrh   void * clientData,
5032f999a67Sdrh   Tcl_Interp *interp,
5042f999a67Sdrh   int objc,
5052f999a67Sdrh   Tcl_Obj *CONST objv[]
5062f999a67Sdrh ){
5072f999a67Sdrh   int resetFlag = 0;
5082f999a67Sdrh   if( objc!=1 && objc!=2 ){
5092f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
5102f999a67Sdrh     return TCL_ERROR;
5112f999a67Sdrh   }
5122f999a67Sdrh   if( objc==2 ){
5132f999a67Sdrh     if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
5142f999a67Sdrh   }
5152f999a67Sdrh   Tcl_SetObjResult(interp,
5162f999a67Sdrh      Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
5172f999a67Sdrh   return TCL_OK;
5182f999a67Sdrh }
5192f999a67Sdrh 
5202f999a67Sdrh /*
5212f999a67Sdrh ** Usage:    sqlite3_memdebug_backtrace DEPTH
5222f999a67Sdrh **
5232f999a67Sdrh ** Set the depth of backtracing.  If SQLITE_MEMDEBUG is not defined
5242f999a67Sdrh ** then this routine is a no-op.
5252f999a67Sdrh */
5262f999a67Sdrh static int test_memdebug_backtrace(
5272f999a67Sdrh   void * clientData,
5282f999a67Sdrh   Tcl_Interp *interp,
5292f999a67Sdrh   int objc,
5302f999a67Sdrh   Tcl_Obj *CONST objv[]
5312f999a67Sdrh ){
5322f999a67Sdrh   int depth;
5332f999a67Sdrh   if( objc!=2 ){
5342f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
5352f999a67Sdrh     return TCL_ERROR;
5362f999a67Sdrh   }
5372f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
5382f999a67Sdrh #ifdef SQLITE_MEMDEBUG
5392f999a67Sdrh   {
54049e4fd71Sdrh     extern void sqlite3MemdebugBacktrace(int);
54149e4fd71Sdrh     sqlite3MemdebugBacktrace(depth);
5422f999a67Sdrh   }
5432f999a67Sdrh #endif
5442f999a67Sdrh   return TCL_OK;
5452f999a67Sdrh }
5462f999a67Sdrh 
5472f999a67Sdrh /*
5482f999a67Sdrh ** Usage:    sqlite3_memdebug_dump  FILENAME
5492f999a67Sdrh **
5502f999a67Sdrh ** Write a summary of unfreed memory to FILENAME.
5512f999a67Sdrh */
5522f999a67Sdrh static int test_memdebug_dump(
5532f999a67Sdrh   void * clientData,
5542f999a67Sdrh   Tcl_Interp *interp,
5552f999a67Sdrh   int objc,
5562f999a67Sdrh   Tcl_Obj *CONST objv[]
5572f999a67Sdrh ){
5582f999a67Sdrh   if( objc!=2 ){
5592f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
5602f999a67Sdrh     return TCL_ERROR;
5612f999a67Sdrh   }
5622d7636e2Sdrh #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
5632d7636e2Sdrh      || defined(SQLITE_POW2_MEMORY_SIZE)
5642f999a67Sdrh   {
56549e4fd71Sdrh     extern void sqlite3MemdebugDump(const char*);
56649e4fd71Sdrh     sqlite3MemdebugDump(Tcl_GetString(objv[1]));
5672f999a67Sdrh   }
5682f999a67Sdrh #endif
5692f999a67Sdrh   return TCL_OK;
5702f999a67Sdrh }
5712f999a67Sdrh 
572a7a8e14bSdanielk1977 /*
573a7a8e14bSdanielk1977 ** Usage:    sqlite3_memdebug_malloc_count
574a7a8e14bSdanielk1977 **
575a7a8e14bSdanielk1977 ** Return the total number of times malloc() has been called.
576a7a8e14bSdanielk1977 */
577a7a8e14bSdanielk1977 static int test_memdebug_malloc_count(
578a7a8e14bSdanielk1977   void * clientData,
579a7a8e14bSdanielk1977   Tcl_Interp *interp,
580a7a8e14bSdanielk1977   int objc,
581a7a8e14bSdanielk1977   Tcl_Obj *CONST objv[]
582a7a8e14bSdanielk1977 ){
583a7a8e14bSdanielk1977   int nMalloc = -1;
584a7a8e14bSdanielk1977   if( objc!=1 ){
585a7a8e14bSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "");
586a7a8e14bSdanielk1977     return TCL_ERROR;
587a7a8e14bSdanielk1977   }
588a7a8e14bSdanielk1977 #if defined(SQLITE_MEMDEBUG)
589a7a8e14bSdanielk1977   {
59049e4fd71Sdrh     extern int sqlite3MemdebugMallocCount();
59149e4fd71Sdrh     nMalloc = sqlite3MemdebugMallocCount();
592a7a8e14bSdanielk1977   }
593a7a8e14bSdanielk1977 #endif
594a7a8e14bSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));
595a7a8e14bSdanielk1977   return TCL_OK;
596a7a8e14bSdanielk1977 }
597a7a8e14bSdanielk1977 
5982f999a67Sdrh 
5992f999a67Sdrh /*
600a1644fd8Sdanielk1977 ** Usage:    sqlite3_memdebug_fail  COUNTER  ?OPTIONS?
601a1644fd8Sdanielk1977 **
602a1644fd8Sdanielk1977 ** where options are:
603a1644fd8Sdanielk1977 **
604643167ffSdrh **     -repeat    <count>
605a1644fd8Sdanielk1977 **     -benigncnt <varname>
6060e6f1546Sdrh **
6070e6f1546Sdrh ** Arrange for a simulated malloc() failure after COUNTER successes.
608643167ffSdrh ** If a repeat count is specified, the fault is repeated that many
609643167ffSdrh ** times.
6100e6f1546Sdrh **
6110e6f1546Sdrh ** Each call to this routine overrides the prior counter value.
6120e6f1546Sdrh ** This routine returns the number of simulated failures that have
6130e6f1546Sdrh ** happened since the previous call to this routine.
6140e6f1546Sdrh **
6150e6f1546Sdrh ** To disable simulated failures, use a COUNTER of -1.
6160e6f1546Sdrh */
6170e6f1546Sdrh static int test_memdebug_fail(
6180e6f1546Sdrh   void * clientData,
6190e6f1546Sdrh   Tcl_Interp *interp,
6200e6f1546Sdrh   int objc,
6210e6f1546Sdrh   Tcl_Obj *CONST objv[]
6220e6f1546Sdrh ){
623a1644fd8Sdanielk1977   int ii;
6240e6f1546Sdrh   int iFail;
625643167ffSdrh   int nRepeat = 1;
626a1644fd8Sdanielk1977   Tcl_Obj *pBenignCnt = 0;
627643167ffSdrh   int nBenign;
6280e6f1546Sdrh   int nFail = 0;
629a1644fd8Sdanielk1977 
630a1644fd8Sdanielk1977   if( objc<2 ){
631a1644fd8Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
6320e6f1546Sdrh     return TCL_ERROR;
6330e6f1546Sdrh   }
6340e6f1546Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
635a1644fd8Sdanielk1977 
636a1644fd8Sdanielk1977   for(ii=2; ii<objc; ii+=2){
637a1644fd8Sdanielk1977     int nOption;
638a1644fd8Sdanielk1977     char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
639a1644fd8Sdanielk1977     char *zErr = 0;
640a1644fd8Sdanielk1977 
641a1644fd8Sdanielk1977     if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
642a1644fd8Sdanielk1977       if( ii==(objc-1) ){
643a1644fd8Sdanielk1977         zErr = "option requires an argument: ";
644ed138fb3Sdrh       }else{
645643167ffSdrh         if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){
646a1644fd8Sdanielk1977           return TCL_ERROR;
647ed138fb3Sdrh         }
648a1644fd8Sdanielk1977       }
649a1644fd8Sdanielk1977     }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){
650a1644fd8Sdanielk1977       if( ii==(objc-1) ){
651a1644fd8Sdanielk1977         zErr = "option requires an argument: ";
652a1644fd8Sdanielk1977       }else{
653a1644fd8Sdanielk1977         pBenignCnt = objv[ii+1];
654a1644fd8Sdanielk1977       }
655a1644fd8Sdanielk1977     }else{
656a1644fd8Sdanielk1977       zErr = "unknown option: ";
657a1644fd8Sdanielk1977     }
658a1644fd8Sdanielk1977 
659a1644fd8Sdanielk1977     if( zErr ){
660a1644fd8Sdanielk1977       Tcl_AppendResult(interp, zErr, zOption, 0);
661a1644fd8Sdanielk1977       return TCL_ERROR;
662a1644fd8Sdanielk1977     }
663a1644fd8Sdanielk1977   }
664a1644fd8Sdanielk1977 
665ef05f2dfSdanielk1977   nBenign = faultsimBenignFailures();
666ef05f2dfSdanielk1977   nFail = faultsimFailures();
667ef05f2dfSdanielk1977   faultsimConfig(iFail, nRepeat);
668ef05f2dfSdanielk1977 
669a1644fd8Sdanielk1977   if( pBenignCnt ){
670643167ffSdrh     Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);
671a1644fd8Sdanielk1977   }
6720e6f1546Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
6730e6f1546Sdrh   return TCL_OK;
6740e6f1546Sdrh }
6750e6f1546Sdrh 
676cd03724cSdanielk1977 /*
677cd03724cSdanielk1977 ** Usage:    sqlite3_memdebug_pending
678cd03724cSdanielk1977 **
679cd03724cSdanielk1977 ** Return the number of malloc() calls that will succeed before a
680cd03724cSdanielk1977 ** simulated failure occurs. A negative return value indicates that
681cd03724cSdanielk1977 ** no malloc() failure is scheduled.
682cd03724cSdanielk1977 */
683cd03724cSdanielk1977 static int test_memdebug_pending(
684cd03724cSdanielk1977   void * clientData,
685cd03724cSdanielk1977   Tcl_Interp *interp,
686cd03724cSdanielk1977   int objc,
687cd03724cSdanielk1977   Tcl_Obj *CONST objv[]
688cd03724cSdanielk1977 ){
6895efaf070Sdrh   int nPending;
690cd03724cSdanielk1977   if( objc!=1 ){
691cd03724cSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "");
692cd03724cSdanielk1977     return TCL_ERROR;
693cd03724cSdanielk1977   }
694ef05f2dfSdanielk1977   nPending = faultsimPending();
695ed13d98cSdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));
696cd03724cSdanielk1977   return TCL_OK;
697cd03724cSdanielk1977 }
698cd03724cSdanielk1977 
69944ee1dc8Sdrh /*
70044ee1dc8Sdrh ** The following global variable keeps track of the number of tests
70144ee1dc8Sdrh ** that have run.  This variable is only useful when running in the
70244ee1dc8Sdrh ** debugger.
70344ee1dc8Sdrh */
70444ee1dc8Sdrh static int sqlite3_memdebug_title_count = 0;
7050e6f1546Sdrh 
7060e6f1546Sdrh /*
7074a50aac5Sdrh ** Usage:    sqlite3_memdebug_settitle TITLE
7084a50aac5Sdrh **
7094a50aac5Sdrh ** Set a title string stored with each allocation.  The TITLE is
7104a50aac5Sdrh ** typically the name of the test that was running when the
7114a50aac5Sdrh ** allocation occurred.  The TITLE is stored with the allocation
7124a50aac5Sdrh ** and can be used to figure out which tests are leaking memory.
7134a50aac5Sdrh **
7144a50aac5Sdrh ** Each title overwrite the previous.
7154a50aac5Sdrh */
7164a50aac5Sdrh static int test_memdebug_settitle(
7174a50aac5Sdrh   void * clientData,
7184a50aac5Sdrh   Tcl_Interp *interp,
7194a50aac5Sdrh   int objc,
7204a50aac5Sdrh   Tcl_Obj *CONST objv[]
7214a50aac5Sdrh ){
72244ee1dc8Sdrh   sqlite3_memdebug_title_count++;
7234a50aac5Sdrh   if( objc!=2 ){
7244a50aac5Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
7254a50aac5Sdrh     return TCL_ERROR;
7264a50aac5Sdrh   }
7274a50aac5Sdrh #ifdef SQLITE_MEMDEBUG
7284a50aac5Sdrh   {
729caffb1a5Sdrh     const char *zTitle;
73049e4fd71Sdrh     extern int sqlite3MemdebugSettitle(const char*);
731a359b5eeSmistachkin     zTitle = Tcl_GetString(objv[1]);
73249e4fd71Sdrh     sqlite3MemdebugSettitle(zTitle);
7334a50aac5Sdrh   }
7344a50aac5Sdrh #endif
7354a50aac5Sdrh   return TCL_OK;
7364a50aac5Sdrh }
7374a50aac5Sdrh 
738cd3e8f7cSdanielk1977 #define MALLOC_LOG_FRAMES  10
739ec561a35Sdan #define MALLOC_LOG_KEYINTS (                                              \
740ec561a35Sdan     10 * ((sizeof(int)>=sizeof(void*)) ? 1 : sizeof(void*)/sizeof(int))   \
741ec561a35Sdan )
7426f332c18Sdanielk1977 static Tcl_HashTable aMallocLog;
7436f332c18Sdanielk1977 static int mallocLogEnabled = 0;
7446f332c18Sdanielk1977 
7456f332c18Sdanielk1977 typedef struct MallocLog MallocLog;
7466f332c18Sdanielk1977 struct MallocLog {
7476f332c18Sdanielk1977   int nCall;
7486f332c18Sdanielk1977   int nByte;
7496f332c18Sdanielk1977 };
7506f332c18Sdanielk1977 
751afdd23a4Sshane #ifdef SQLITE_MEMDEBUG
7526f332c18Sdanielk1977 static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
7536f332c18Sdanielk1977   if( mallocLogEnabled ){
7546f332c18Sdanielk1977     MallocLog *pLog;
7556f332c18Sdanielk1977     Tcl_HashEntry *pEntry;
7566f332c18Sdanielk1977     int isNew;
7576f332c18Sdanielk1977 
758ec561a35Sdan     int aKey[MALLOC_LOG_KEYINTS];
759f6418891Smistachkin     unsigned int nKey = sizeof(int)*MALLOC_LOG_KEYINTS;
7606f332c18Sdanielk1977 
7616f332c18Sdanielk1977     memset(aKey, 0, nKey);
7626f332c18Sdanielk1977     if( (sizeof(void*)*nFrame)<nKey ){
7636f332c18Sdanielk1977       nKey = nFrame*sizeof(void*);
7646f332c18Sdanielk1977     }
7656f332c18Sdanielk1977     memcpy(aKey, aFrame, nKey);
7666f332c18Sdanielk1977 
7676f332c18Sdanielk1977     pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew);
7686f332c18Sdanielk1977     if( isNew ){
7696f332c18Sdanielk1977       pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog));
7706f332c18Sdanielk1977       memset(pLog, 0, sizeof(MallocLog));
7716f332c18Sdanielk1977       Tcl_SetHashValue(pEntry, (ClientData)pLog);
7726f332c18Sdanielk1977     }else{
7736f332c18Sdanielk1977       pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
7746f332c18Sdanielk1977     }
7756f332c18Sdanielk1977 
7766f332c18Sdanielk1977     pLog->nCall++;
7776f332c18Sdanielk1977     pLog->nByte += nByte;
7786f332c18Sdanielk1977   }
7796f332c18Sdanielk1977 }
780afdd23a4Sshane #endif /* SQLITE_MEMDEBUG */
7816f332c18Sdanielk1977 
78264aca191Sdanielk1977 static void test_memdebug_log_clear(void){
783dbdc4d49Sdanielk1977   Tcl_HashSearch search;
784dbdc4d49Sdanielk1977   Tcl_HashEntry *pEntry;
785dbdc4d49Sdanielk1977   for(
786dbdc4d49Sdanielk1977     pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
787dbdc4d49Sdanielk1977     pEntry;
788dbdc4d49Sdanielk1977     pEntry=Tcl_NextHashEntry(&search)
789dbdc4d49Sdanielk1977   ){
790dbdc4d49Sdanielk1977     MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
791dbdc4d49Sdanielk1977     Tcl_Free((char *)pLog);
792dbdc4d49Sdanielk1977   }
793dbdc4d49Sdanielk1977   Tcl_DeleteHashTable(&aMallocLog);
794ec561a35Sdan   Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);
795dbdc4d49Sdanielk1977 }
796dbdc4d49Sdanielk1977 
7976f332c18Sdanielk1977 static int test_memdebug_log(
7986f332c18Sdanielk1977   void * clientData,
7996f332c18Sdanielk1977   Tcl_Interp *interp,
8006f332c18Sdanielk1977   int objc,
8016f332c18Sdanielk1977   Tcl_Obj *CONST objv[]
8026f332c18Sdanielk1977 ){
8036f332c18Sdanielk1977   static int isInit = 0;
8046f332c18Sdanielk1977   int iSub;
8056f332c18Sdanielk1977 
806dbdc4d49Sdanielk1977   static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" };
807dbdc4d49Sdanielk1977   enum MB_enum {
808dbdc4d49Sdanielk1977       MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC
809dbdc4d49Sdanielk1977   };
8106f332c18Sdanielk1977 
8116f332c18Sdanielk1977   if( !isInit ){
8126f332c18Sdanielk1977 #ifdef SQLITE_MEMDEBUG
8136f332c18Sdanielk1977     extern void sqlite3MemdebugBacktraceCallback(
8146f332c18Sdanielk1977         void (*xBacktrace)(int, int, void **));
8156f332c18Sdanielk1977     sqlite3MemdebugBacktraceCallback(test_memdebug_callback);
8166f332c18Sdanielk1977 #endif
817ec561a35Sdan     Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);
8186f332c18Sdanielk1977     isInit = 1;
8196f332c18Sdanielk1977   }
8206f332c18Sdanielk1977 
8216f332c18Sdanielk1977   if( objc<2 ){
8226f332c18Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
8236f332c18Sdanielk1977   }
8246f332c18Sdanielk1977   if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){
8256f332c18Sdanielk1977     return TCL_ERROR;
8266f332c18Sdanielk1977   }
8276f332c18Sdanielk1977 
8286f332c18Sdanielk1977   switch( (enum MB_enum)iSub ){
8296f332c18Sdanielk1977     case MB_LOG_START:
8306f332c18Sdanielk1977       mallocLogEnabled = 1;
8316f332c18Sdanielk1977       break;
8326f332c18Sdanielk1977     case MB_LOG_STOP:
8336f332c18Sdanielk1977       mallocLogEnabled = 0;
8346f332c18Sdanielk1977       break;
8356f332c18Sdanielk1977     case MB_LOG_DUMP: {
8366f332c18Sdanielk1977       Tcl_HashSearch search;
8376f332c18Sdanielk1977       Tcl_HashEntry *pEntry;
8386f332c18Sdanielk1977       Tcl_Obj *pRet = Tcl_NewObj();
8396f332c18Sdanielk1977 
840ec561a35Sdan       assert(sizeof(Tcl_WideInt)>=sizeof(void*));
8416f332c18Sdanielk1977 
8426f332c18Sdanielk1977       for(
8436f332c18Sdanielk1977         pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
8446f332c18Sdanielk1977         pEntry;
8456f332c18Sdanielk1977         pEntry=Tcl_NextHashEntry(&search)
8466f332c18Sdanielk1977       ){
8476f332c18Sdanielk1977         Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];
8486f332c18Sdanielk1977         MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
849ec561a35Sdan         Tcl_WideInt *aKey = (Tcl_WideInt *)Tcl_GetHashKey(&aMallocLog, pEntry);
8506f332c18Sdanielk1977         int ii;
8516f332c18Sdanielk1977 
8526f332c18Sdanielk1977         apElem[0] = Tcl_NewIntObj(pLog->nCall);
8536f332c18Sdanielk1977         apElem[1] = Tcl_NewIntObj(pLog->nByte);
8546f332c18Sdanielk1977         for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){
855ec561a35Sdan           apElem[ii+2] = Tcl_NewWideIntObj(aKey[ii]);
8566f332c18Sdanielk1977         }
8576f332c18Sdanielk1977 
8586f332c18Sdanielk1977         Tcl_ListObjAppendElement(interp, pRet,
8596f332c18Sdanielk1977             Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem)
8606f332c18Sdanielk1977         );
8616f332c18Sdanielk1977       }
8626f332c18Sdanielk1977 
8636f332c18Sdanielk1977       Tcl_SetObjResult(interp, pRet);
8646f332c18Sdanielk1977       break;
8656f332c18Sdanielk1977     }
8666f332c18Sdanielk1977     case MB_LOG_CLEAR: {
867dbdc4d49Sdanielk1977       test_memdebug_log_clear();
868dbdc4d49Sdanielk1977       break;
8696f332c18Sdanielk1977     }
870dbdc4d49Sdanielk1977 
871dbdc4d49Sdanielk1977     case MB_LOG_SYNC: {
872b940492eSdrh #ifdef SQLITE_MEMDEBUG
873dbdc4d49Sdanielk1977       extern void sqlite3MemdebugSync();
874dbdc4d49Sdanielk1977       test_memdebug_log_clear();
875dbdc4d49Sdanielk1977       mallocLogEnabled = 1;
876dbdc4d49Sdanielk1977       sqlite3MemdebugSync();
877b940492eSdrh #endif
878dbdc4d49Sdanielk1977       break;
8796f332c18Sdanielk1977     }
8806f332c18Sdanielk1977   }
8816f332c18Sdanielk1977 
8826f332c18Sdanielk1977   return TCL_OK;
8836f332c18Sdanielk1977 }
8844a50aac5Sdrh 
8854a50aac5Sdrh /*
8869ac3fe97Sdrh ** Usage:    sqlite3_config_scratch SIZE N
8879ac3fe97Sdrh **
8889ac3fe97Sdrh ** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH.
8899ac3fe97Sdrh ** The buffer is static and is of limited size.  N might be
89060ec914cSpeter.d.reid ** adjusted downward as needed to accommodate the requested size.
8919ac3fe97Sdrh ** The revised value of N is returned.
8929ac3fe97Sdrh **
8939ac3fe97Sdrh ** A negative SIZE causes the buffer pointer to be NULL.
8949ac3fe97Sdrh */
8959ac3fe97Sdrh static int test_config_scratch(
8969ac3fe97Sdrh   void * clientData,
8979ac3fe97Sdrh   Tcl_Interp *interp,
8989ac3fe97Sdrh   int objc,
8999ac3fe97Sdrh   Tcl_Obj *CONST objv[]
9009ac3fe97Sdrh ){
9019ac3fe97Sdrh   int sz, N, rc;
9029ac3fe97Sdrh   Tcl_Obj *pResult;
9035f4bcf15Sdrh   static char *buf = 0;
9049ac3fe97Sdrh   if( objc!=3 ){
9059ac3fe97Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
9069ac3fe97Sdrh     return TCL_ERROR;
9079ac3fe97Sdrh   }
908f7141990Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
909f7141990Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
9105f4bcf15Sdrh   free(buf);
9119ac3fe97Sdrh   if( sz<0 ){
9125f4bcf15Sdrh     buf = 0;
9139ac3fe97Sdrh     rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0);
914f7141990Sdrh   }else{
9156480aad4Sdrh     buf = malloc( sz*N + 1 );
9169ac3fe97Sdrh     rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N);
9179ac3fe97Sdrh   }
9189ac3fe97Sdrh   pResult = Tcl_NewObj();
9199ac3fe97Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
9209ac3fe97Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
9219ac3fe97Sdrh   Tcl_SetObjResult(interp, pResult);
9229ac3fe97Sdrh   return TCL_OK;
9239ac3fe97Sdrh }
9249ac3fe97Sdrh 
9259ac3fe97Sdrh /*
9269ac3fe97Sdrh ** Usage:    sqlite3_config_pagecache SIZE N
9279ac3fe97Sdrh **
9289ac3fe97Sdrh ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
9299ac3fe97Sdrh ** The buffer is static and is of limited size.  N might be
93060ec914cSpeter.d.reid ** adjusted downward as needed to accommodate the requested size.
9319ac3fe97Sdrh ** The revised value of N is returned.
9329ac3fe97Sdrh **
9339ac3fe97Sdrh ** A negative SIZE causes the buffer pointer to be NULL.
9349ac3fe97Sdrh */
9359ac3fe97Sdrh static int test_config_pagecache(
9369ac3fe97Sdrh   void * clientData,
9379ac3fe97Sdrh   Tcl_Interp *interp,
9389ac3fe97Sdrh   int objc,
9399ac3fe97Sdrh   Tcl_Obj *CONST objv[]
9409ac3fe97Sdrh ){
9419ac3fe97Sdrh   int sz, N, rc;
9429ac3fe97Sdrh   Tcl_Obj *pResult;
9435f4bcf15Sdrh   static char *buf = 0;
9449ac3fe97Sdrh   if( objc!=3 ){
9459ac3fe97Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
9469ac3fe97Sdrh     return TCL_ERROR;
9479ac3fe97Sdrh   }
948f7141990Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
949f7141990Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
9505f4bcf15Sdrh   free(buf);
9519ac3fe97Sdrh   if( sz<0 ){
9525f4bcf15Sdrh     buf = 0;
953f7141990Sdrh     rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0);
954f7141990Sdrh   }else{
9550a60a384Sdrh     buf = malloc( sz*N );
9569ac3fe97Sdrh     rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);
9579ac3fe97Sdrh   }
9589ac3fe97Sdrh   pResult = Tcl_NewObj();
9599ac3fe97Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
9609ac3fe97Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
9619ac3fe97Sdrh   Tcl_SetObjResult(interp, pResult);
9629ac3fe97Sdrh   return TCL_OK;
9639ac3fe97Sdrh }
9649ac3fe97Sdrh 
965f7141990Sdrh /*
966b232c232Sdrh ** Usage:    sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED
967b232c232Sdrh **
968b232c232Sdrh ** Set up the alternative test page cache.  Install if INSTALL_FLAG is
969b232c232Sdrh ** true and uninstall (reverting to the default page cache) if INSTALL_FLAG
970b232c232Sdrh ** is false.  DISCARD_CHANGE is an integer between 0 and 100 inclusive
971b232c232Sdrh ** which determines the chance of discarding a page when unpinned.  100
972b232c232Sdrh ** is certainty.  0 is never.  PRNG_SEED is the pseudo-random number generator
973b232c232Sdrh ** seed.
974b232c232Sdrh */
975b232c232Sdrh static int test_alt_pcache(
976b232c232Sdrh   void * clientData,
977b232c232Sdrh   Tcl_Interp *interp,
978b232c232Sdrh   int objc,
979b232c232Sdrh   Tcl_Obj *CONST objv[]
980b232c232Sdrh ){
981b232c232Sdrh   int installFlag;
982f2a84e3cSdrh   int discardChance = 0;
983f2a84e3cSdrh   int prngSeed = 0;
984f2a84e3cSdrh   int highStress = 0;
985f2a84e3cSdrh   extern void installTestPCache(int,unsigned,unsigned,unsigned);
986f2a84e3cSdrh   if( objc<2 || objc>5 ){
987f2a84e3cSdrh     Tcl_WrongNumArgs(interp, 1, objv,
988f2a84e3cSdrh         "INSTALLFLAG DISCARDCHANCE PRNGSEEED HIGHSTRESS");
989b232c232Sdrh     return TCL_ERROR;
990b232c232Sdrh   }
991b232c232Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &installFlag) ) return TCL_ERROR;
992f2a84e3cSdrh   if( objc>=3 && Tcl_GetIntFromObj(interp, objv[2], &discardChance) ){
993f2a84e3cSdrh      return TCL_ERROR;
994f2a84e3cSdrh   }
995f2a84e3cSdrh   if( objc>=4 && Tcl_GetIntFromObj(interp, objv[3], &prngSeed) ){
996f2a84e3cSdrh      return TCL_ERROR;
997f2a84e3cSdrh   }
998f2a84e3cSdrh   if( objc>=5 && Tcl_GetIntFromObj(interp, objv[4], &highStress) ){
999f2a84e3cSdrh     return TCL_ERROR;
1000f2a84e3cSdrh   }
1001b232c232Sdrh   if( discardChance<0 || discardChance>100 ){
1002b232c232Sdrh     Tcl_AppendResult(interp, "discard-chance should be between 0 and 100",
1003b232c232Sdrh                      (char*)0);
1004b232c232Sdrh     return TCL_ERROR;
1005b232c232Sdrh   }
1006f2a84e3cSdrh   installTestPCache(installFlag, (unsigned)discardChance, (unsigned)prngSeed,
1007f2a84e3cSdrh                     (unsigned)highStress);
1008b232c232Sdrh   return TCL_OK;
1009b232c232Sdrh }
1010b232c232Sdrh 
1011b232c232Sdrh /*
10128a42cbd3Sdrh ** Usage:    sqlite3_config_memstatus BOOLEAN
10138a42cbd3Sdrh **
10148a42cbd3Sdrh ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.
10158a42cbd3Sdrh */
10168a42cbd3Sdrh static int test_config_memstatus(
10178a42cbd3Sdrh   void * clientData,
10188a42cbd3Sdrh   Tcl_Interp *interp,
10198a42cbd3Sdrh   int objc,
10208a42cbd3Sdrh   Tcl_Obj *CONST objv[]
10218a42cbd3Sdrh ){
10228a42cbd3Sdrh   int enable, rc;
10238a42cbd3Sdrh   if( objc!=2 ){
10248a42cbd3Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
10258a42cbd3Sdrh     return TCL_ERROR;
10268a42cbd3Sdrh   }
10278a42cbd3Sdrh   if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR;
10288a42cbd3Sdrh   rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable);
10298a42cbd3Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
10308a42cbd3Sdrh   return TCL_OK;
10318a42cbd3Sdrh }
10328a42cbd3Sdrh 
10338a42cbd3Sdrh /*
1034633e6d57Sdrh ** Usage:    sqlite3_config_lookaside  SIZE  COUNT
1035633e6d57Sdrh **
1036633e6d57Sdrh */
1037633e6d57Sdrh static int test_config_lookaside(
1038633e6d57Sdrh   void * clientData,
1039633e6d57Sdrh   Tcl_Interp *interp,
1040633e6d57Sdrh   int objc,
1041633e6d57Sdrh   Tcl_Obj *CONST objv[]
1042633e6d57Sdrh ){
1043633e6d57Sdrh   int sz, cnt;
1044ab7bee89Sdanielk1977   Tcl_Obj *pRet;
1045633e6d57Sdrh   if( objc!=3 ){
1046633e6d57Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT");
1047633e6d57Sdrh     return TCL_ERROR;
1048633e6d57Sdrh   }
1049633e6d57Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
1050633e6d57Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR;
1051ab7bee89Sdanielk1977   pRet = Tcl_NewObj();
1052ab7bee89Sdanielk1977   Tcl_ListObjAppendElement(
1053ab7bee89Sdanielk1977       interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.szLookaside)
1054ab7bee89Sdanielk1977   );
1055ab7bee89Sdanielk1977   Tcl_ListObjAppendElement(
1056ab7bee89Sdanielk1977       interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.nLookaside)
1057ab7bee89Sdanielk1977   );
1058caffb1a5Sdrh   sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt);
1059ab7bee89Sdanielk1977   Tcl_SetObjResult(interp, pRet);
1060633e6d57Sdrh   return TCL_OK;
1061633e6d57Sdrh }
1062633e6d57Sdrh 
1063633e6d57Sdrh 
1064633e6d57Sdrh /*
1065e9d1c720Sdrh ** Usage:    sqlite3_db_config_lookaside  CONNECTION  BUFID  SIZE  COUNT
1066633e6d57Sdrh **
1067e9d1c720Sdrh ** There are two static buffers with BUFID 1 and 2.   Each static buffer
1068e9d1c720Sdrh ** is 10KB in size.  A BUFID of 0 indicates that the buffer should be NULL
1069e9d1c720Sdrh ** which will cause sqlite3_db_config() to allocate space on its own.
1070633e6d57Sdrh */
1071633e6d57Sdrh static int test_db_config_lookaside(
1072633e6d57Sdrh   void * clientData,
1073633e6d57Sdrh   Tcl_Interp *interp,
1074633e6d57Sdrh   int objc,
1075633e6d57Sdrh   Tcl_Obj *CONST objv[]
1076633e6d57Sdrh ){
1077633e6d57Sdrh   int rc;
1078633e6d57Sdrh   int sz, cnt;
1079633e6d57Sdrh   sqlite3 *db;
1080e9d1c720Sdrh   int bufid;
1081e9d1c720Sdrh   static char azBuf[2][10000];
1082e84d8d32Smistachkin   extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1083e9d1c720Sdrh   if( objc!=5 ){
1084e9d1c720Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "BUFID SIZE COUNT");
1085633e6d57Sdrh     return TCL_ERROR;
1086633e6d57Sdrh   }
1087633e6d57Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1088e9d1c720Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &bufid) ) return TCL_ERROR;
1089e9d1c720Sdrh   if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR;
1090e9d1c720Sdrh   if( Tcl_GetIntFromObj(interp, objv[4], &cnt) ) return TCL_ERROR;
1091e9d1c720Sdrh   if( bufid==0 ){
1092e9d1c720Sdrh     rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, 0, sz, cnt);
1093e9d1c720Sdrh   }else if( bufid>=1 && bufid<=2 && sz*cnt<=sizeof(azBuf[0]) ){
1094e9d1c720Sdrh     rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz,cnt);
1095e9d1c720Sdrh   }else{
1096e9d1c720Sdrh     Tcl_AppendResult(interp, "illegal arguments - see documentation", (char*)0);
1097e9d1c720Sdrh     return TCL_ERROR;
1098e9d1c720Sdrh   }
1099633e6d57Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1100633e6d57Sdrh   return TCL_OK;
1101633e6d57Sdrh }
1102633e6d57Sdrh 
1103633e6d57Sdrh /*
11048765b466Smistachkin ** Usage:    sqlite3_config_heap NBYTE NMINALLOC
11055099be5eSdanielk1977 */
11065099be5eSdanielk1977 static int test_config_heap(
11075099be5eSdanielk1977   void * clientData,
11085099be5eSdanielk1977   Tcl_Interp *interp,
11095099be5eSdanielk1977   int objc,
11105099be5eSdanielk1977   Tcl_Obj *CONST objv[]
11115099be5eSdanielk1977 ){
11127830cd41Sdrh   static char *zBuf; /* Use this memory */
11135099be5eSdanielk1977   int nByte;         /* Size of buffer to pass to sqlite3_config() */
11145099be5eSdanielk1977   int nMinAlloc;     /* Size of minimum allocation */
11155099be5eSdanielk1977   int rc;            /* Return code of sqlite3_config() */
11165099be5eSdanielk1977 
11175099be5eSdanielk1977   Tcl_Obj * CONST *aArg = &objv[1];
11185099be5eSdanielk1977   int nArg = objc-1;
11195099be5eSdanielk1977 
11205099be5eSdanielk1977   if( nArg!=2 ){
11218a42cbd3Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC");
11225099be5eSdanielk1977     return TCL_ERROR;
11235099be5eSdanielk1977   }
11245099be5eSdanielk1977   if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
11255099be5eSdanielk1977   if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR;
11265099be5eSdanielk1977 
11270d84e5b2Sdanielk1977   if( nByte==0 ){
11287830cd41Sdrh     free( zBuf );
11297830cd41Sdrh     zBuf = 0;
11308a42cbd3Sdrh     rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0);
11310d84e5b2Sdanielk1977   }else{
11327830cd41Sdrh     zBuf = realloc(zBuf, nByte);
11335099be5eSdanielk1977     rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc);
11340d84e5b2Sdanielk1977   }
11355099be5eSdanielk1977 
1136e84d8d32Smistachkin   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
11375099be5eSdanielk1977   return TCL_OK;
11385099be5eSdanielk1977 }
11395099be5eSdanielk1977 
11405099be5eSdanielk1977 /*
1141ac1f1045Smistachkin ** Usage:    sqlite3_config_heap_size NBYTE
1142ac1f1045Smistachkin */
1143ac1f1045Smistachkin static int test_config_heap_size(
1144ac1f1045Smistachkin   void * clientData,
1145ac1f1045Smistachkin   Tcl_Interp *interp,
1146ac1f1045Smistachkin   int objc,
1147ac1f1045Smistachkin   Tcl_Obj *CONST objv[]
1148ac1f1045Smistachkin ){
1149ac1f1045Smistachkin   int nByte;         /* Size to pass to sqlite3_config() */
1150ac1f1045Smistachkin   int rc;            /* Return code of sqlite3_config() */
1151ac1f1045Smistachkin 
1152ac1f1045Smistachkin   Tcl_Obj * CONST *aArg = &objv[1];
1153ac1f1045Smistachkin   int nArg = objc-1;
1154ac1f1045Smistachkin 
1155ac1f1045Smistachkin   if( nArg!=1 ){
1156ac1f1045Smistachkin     Tcl_WrongNumArgs(interp, 1, objv, "NBYTE");
1157ac1f1045Smistachkin     return TCL_ERROR;
1158ac1f1045Smistachkin   }
1159ac1f1045Smistachkin   if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
1160ac1f1045Smistachkin 
1161af8641bdSmistachkin   rc = sqlite3_config(SQLITE_CONFIG_WIN32_HEAPSIZE, nByte);
1162ac1f1045Smistachkin 
1163ac1f1045Smistachkin   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1164ac1f1045Smistachkin   return TCL_OK;
1165ac1f1045Smistachkin }
1166ac1f1045Smistachkin 
1167ac1f1045Smistachkin /*
11688765b466Smistachkin ** Usage:    sqlite3_config_error  [DB]
11696480aad4Sdrh **
11706480aad4Sdrh ** Invoke sqlite3_config() or sqlite3_db_config() with invalid
11716480aad4Sdrh ** opcodes and verify that they return errors.
11726480aad4Sdrh */
11736480aad4Sdrh static int test_config_error(
11746480aad4Sdrh   void * clientData,
11756480aad4Sdrh   Tcl_Interp *interp,
11766480aad4Sdrh   int objc,
11776480aad4Sdrh   Tcl_Obj *CONST objv[]
11786480aad4Sdrh ){
11796480aad4Sdrh   sqlite3 *db;
1180e84d8d32Smistachkin   extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
11816480aad4Sdrh 
11826480aad4Sdrh   if( objc!=2 && objc!=1 ){
11836480aad4Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "[DB]");
11846480aad4Sdrh     return TCL_ERROR;
11856480aad4Sdrh   }
11866480aad4Sdrh   if( objc==2 ){
11876480aad4Sdrh     if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
11886480aad4Sdrh     if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){
11896480aad4Sdrh       Tcl_AppendResult(interp,
11906480aad4Sdrh             "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR",
11916480aad4Sdrh             (char*)0);
11926480aad4Sdrh       return TCL_ERROR;
11936480aad4Sdrh     }
11946480aad4Sdrh   }else{
11956480aad4Sdrh     if( sqlite3_config(99999)!=SQLITE_ERROR ){
11966480aad4Sdrh       Tcl_AppendResult(interp,
11976480aad4Sdrh           "sqlite3_config(99999) does not return SQLITE_ERROR",
11986480aad4Sdrh           (char*)0);
11996480aad4Sdrh       return TCL_ERROR;
12006480aad4Sdrh     }
12016480aad4Sdrh   }
12026480aad4Sdrh   return TCL_OK;
12036480aad4Sdrh }
12046480aad4Sdrh 
12056480aad4Sdrh /*
12068765b466Smistachkin ** Usage:    sqlite3_config_uri  BOOLEAN
1207cd74b611Sdan **
12088765b466Smistachkin ** Enables or disables interpretation of URI parameters by default using
12098765b466Smistachkin ** SQLITE_CONFIG_URI.
1210cd74b611Sdan */
1211cd74b611Sdan static int test_config_uri(
1212cd74b611Sdan   void * clientData,
1213cd74b611Sdan   Tcl_Interp *interp,
1214cd74b611Sdan   int objc,
1215cd74b611Sdan   Tcl_Obj *CONST objv[]
1216cd74b611Sdan ){
1217cd74b611Sdan   int rc;
1218cd74b611Sdan   int bOpenUri;
1219cd74b611Sdan 
1220cd74b611Sdan   if( objc!=2 ){
1221cd74b611Sdan     Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
1222cd74b611Sdan     return TCL_ERROR;
1223cd74b611Sdan   }
1224cd74b611Sdan   if( Tcl_GetBooleanFromObj(interp, objv[1], &bOpenUri) ){
1225cd74b611Sdan     return TCL_ERROR;
1226cd74b611Sdan   }
1227cd74b611Sdan 
1228cd74b611Sdan   rc = sqlite3_config(SQLITE_CONFIG_URI, bOpenUri);
1229e84d8d32Smistachkin   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1230cd74b611Sdan 
1231cd74b611Sdan   return TCL_OK;
1232cd74b611Sdan }
1233cd74b611Sdan 
1234cd74b611Sdan /*
1235de9a7b8aSdrh ** Usage:    sqlite3_config_cis  BOOLEAN
1236de9a7b8aSdrh **
1237de9a7b8aSdrh ** Enables or disables the use of the covering-index scan optimization.
1238de9a7b8aSdrh ** SQLITE_CONFIG_COVERING_INDEX_SCAN.
1239de9a7b8aSdrh */
1240de9a7b8aSdrh static int test_config_cis(
1241de9a7b8aSdrh   void * clientData,
1242de9a7b8aSdrh   Tcl_Interp *interp,
1243de9a7b8aSdrh   int objc,
1244de9a7b8aSdrh   Tcl_Obj *CONST objv[]
1245de9a7b8aSdrh ){
1246de9a7b8aSdrh   int rc;
1247de9a7b8aSdrh   int bUseCis;
1248de9a7b8aSdrh 
1249de9a7b8aSdrh   if( objc!=2 ){
1250de9a7b8aSdrh     Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
1251de9a7b8aSdrh     return TCL_ERROR;
1252de9a7b8aSdrh   }
1253de9a7b8aSdrh   if( Tcl_GetBooleanFromObj(interp, objv[1], &bUseCis) ){
1254de9a7b8aSdrh     return TCL_ERROR;
1255de9a7b8aSdrh   }
1256de9a7b8aSdrh 
1257de9a7b8aSdrh   rc = sqlite3_config(SQLITE_CONFIG_COVERING_INDEX_SCAN, bUseCis);
1258e84d8d32Smistachkin   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1259de9a7b8aSdrh 
1260de9a7b8aSdrh   return TCL_OK;
1261de9a7b8aSdrh }
1262de9a7b8aSdrh 
12633bd1791dSdrh /*
12643bd1791dSdrh ** Usage:    sqlite3_config_pmasz  INTEGER
12653bd1791dSdrh **
12663bd1791dSdrh ** Set the minimum PMA size.
12673bd1791dSdrh */
12683bd1791dSdrh static int test_config_pmasz(
12693bd1791dSdrh   void * clientData,
12703bd1791dSdrh   Tcl_Interp *interp,
12713bd1791dSdrh   int objc,
12723bd1791dSdrh   Tcl_Obj *CONST objv[]
12733bd1791dSdrh ){
12743bd1791dSdrh   int rc;
12753bd1791dSdrh   int iPmaSz;
12763bd1791dSdrh 
12773bd1791dSdrh   if( objc!=2 ){
12783bd1791dSdrh     Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
12793bd1791dSdrh     return TCL_ERROR;
12803bd1791dSdrh   }
12813bd1791dSdrh   if( Tcl_GetIntFromObj(interp, objv[1], &iPmaSz) ){
12823bd1791dSdrh     return TCL_ERROR;
12833bd1791dSdrh   }
12843bd1791dSdrh 
12853bd1791dSdrh   rc = sqlite3_config(SQLITE_CONFIG_PMASZ, iPmaSz);
12863bd1791dSdrh   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
12873bd1791dSdrh 
12883bd1791dSdrh   return TCL_OK;
12893bd1791dSdrh }
12903bd1791dSdrh 
1291578e1ca8Sdan 
1292578e1ca8Sdan /*
12938765b466Smistachkin ** Usage:    sqlite3_dump_memsys3  FILENAME
1294c66c0e14Sdanielk1977 **           sqlite3_dump_memsys5  FILENAME
129532155ef0Sdanielk1977 **
129632155ef0Sdanielk1977 ** Write a summary of unfreed memsys3 allocations to FILENAME.
129732155ef0Sdanielk1977 */
129832155ef0Sdanielk1977 static int test_dump_memsys3(
129932155ef0Sdanielk1977   void * clientData,
130032155ef0Sdanielk1977   Tcl_Interp *interp,
130132155ef0Sdanielk1977   int objc,
130232155ef0Sdanielk1977   Tcl_Obj *CONST objv[]
130332155ef0Sdanielk1977 ){
130432155ef0Sdanielk1977   if( objc!=2 ){
130532155ef0Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
130632155ef0Sdanielk1977     return TCL_ERROR;
130732155ef0Sdanielk1977   }
1308c66c0e14Sdanielk1977 
1309860e332cSdrh   switch( SQLITE_PTR_TO_INT(clientData) ){
13100d84e5b2Sdanielk1977     case 3: {
1311c66c0e14Sdanielk1977 #ifdef SQLITE_ENABLE_MEMSYS3
131232155ef0Sdanielk1977       extern void sqlite3Memsys3Dump(const char*);
131332155ef0Sdanielk1977       sqlite3Memsys3Dump(Tcl_GetString(objv[1]));
1314c66c0e14Sdanielk1977       break;
131532155ef0Sdanielk1977 #endif
1316c66c0e14Sdanielk1977     }
13170d84e5b2Sdanielk1977     case 5: {
1318c66c0e14Sdanielk1977 #ifdef SQLITE_ENABLE_MEMSYS5
1319c66c0e14Sdanielk1977       extern void sqlite3Memsys5Dump(const char*);
1320c66c0e14Sdanielk1977       sqlite3Memsys5Dump(Tcl_GetString(objv[1]));
1321c66c0e14Sdanielk1977       break;
1322c66c0e14Sdanielk1977 #endif
1323c66c0e14Sdanielk1977     }
1324c66c0e14Sdanielk1977   }
132532155ef0Sdanielk1977   return TCL_OK;
132632155ef0Sdanielk1977 }
132732155ef0Sdanielk1977 
132832155ef0Sdanielk1977 /*
1329f7141990Sdrh ** Usage:    sqlite3_status  OPCODE  RESETFLAG
1330f7141990Sdrh **
1331f7141990Sdrh ** Return a list of three elements which are the sqlite3_status() return
1332f7141990Sdrh ** code, the current value, and the high-water mark value.
1333f7141990Sdrh */
1334f7141990Sdrh static int test_status(
1335f7141990Sdrh   void * clientData,
1336f7141990Sdrh   Tcl_Interp *interp,
1337f7141990Sdrh   int objc,
1338f7141990Sdrh   Tcl_Obj *CONST objv[]
1339f7141990Sdrh ){
1340f7141990Sdrh   int rc, iValue, mxValue;
1341*7bb22ac7Smistachkin   int i, op = 0, resetFlag;
1342f7141990Sdrh   const char *zOpName;
1343f7141990Sdrh   static const struct {
1344f7141990Sdrh     const char *zName;
1345f7141990Sdrh     int op;
1346f7141990Sdrh   } aOp[] = {
1347f7141990Sdrh     { "SQLITE_STATUS_MEMORY_USED",         SQLITE_STATUS_MEMORY_USED         },
1348e50135e2Sdrh     { "SQLITE_STATUS_MALLOC_SIZE",         SQLITE_STATUS_MALLOC_SIZE         },
1349f7141990Sdrh     { "SQLITE_STATUS_PAGECACHE_USED",      SQLITE_STATUS_PAGECACHE_USED      },
1350f7141990Sdrh     { "SQLITE_STATUS_PAGECACHE_OVERFLOW",  SQLITE_STATUS_PAGECACHE_OVERFLOW  },
1351e50135e2Sdrh     { "SQLITE_STATUS_PAGECACHE_SIZE",      SQLITE_STATUS_PAGECACHE_SIZE      },
1352f7141990Sdrh     { "SQLITE_STATUS_SCRATCH_USED",        SQLITE_STATUS_SCRATCH_USED        },
1353f7141990Sdrh     { "SQLITE_STATUS_SCRATCH_OVERFLOW",    SQLITE_STATUS_SCRATCH_OVERFLOW    },
1354e50135e2Sdrh     { "SQLITE_STATUS_SCRATCH_SIZE",        SQLITE_STATUS_SCRATCH_SIZE        },
1355ec424a5bSdrh     { "SQLITE_STATUS_PARSER_STACK",        SQLITE_STATUS_PARSER_STACK        },
1356eafc43b1Sdrh     { "SQLITE_STATUS_MALLOC_COUNT",        SQLITE_STATUS_MALLOC_COUNT        },
1357f7141990Sdrh   };
1358f7141990Sdrh   Tcl_Obj *pResult;
1359f7141990Sdrh   if( objc!=3 ){
1360f7141990Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
1361f7141990Sdrh     return TCL_ERROR;
1362f7141990Sdrh   }
1363f7141990Sdrh   zOpName = Tcl_GetString(objv[1]);
1364f7141990Sdrh   for(i=0; i<ArraySize(aOp); i++){
1365f7141990Sdrh     if( strcmp(aOp[i].zName, zOpName)==0 ){
1366f7141990Sdrh       op = aOp[i].op;
1367f7141990Sdrh       break;
1368f7141990Sdrh     }
1369f7141990Sdrh   }
1370f7141990Sdrh   if( i>=ArraySize(aOp) ){
1371f7141990Sdrh     if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;
1372f7141990Sdrh   }
1373f7141990Sdrh   if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;
1374af005fbcSdrh   iValue = 0;
1375af005fbcSdrh   mxValue = 0;
1376f7141990Sdrh   rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);
1377f7141990Sdrh   pResult = Tcl_NewObj();
1378f7141990Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1379f7141990Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1380f7141990Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1381f7141990Sdrh   Tcl_SetObjResult(interp, pResult);
1382f7141990Sdrh   return TCL_OK;
1383f7141990Sdrh }
13849ac3fe97Sdrh 
13859ac3fe97Sdrh /*
1386633e6d57Sdrh ** Usage:    sqlite3_db_status  DATABASE  OPCODE  RESETFLAG
1387633e6d57Sdrh **
1388633e6d57Sdrh ** Return a list of three elements which are the sqlite3_db_status() return
1389633e6d57Sdrh ** code, the current value, and the high-water mark value.
1390633e6d57Sdrh */
1391633e6d57Sdrh static int test_db_status(
1392633e6d57Sdrh   void * clientData,
1393633e6d57Sdrh   Tcl_Interp *interp,
1394633e6d57Sdrh   int objc,
1395633e6d57Sdrh   Tcl_Obj *CONST objv[]
1396633e6d57Sdrh ){
1397633e6d57Sdrh   int rc, iValue, mxValue;
1398*7bb22ac7Smistachkin   int i, op = 0, resetFlag;
1399633e6d57Sdrh   const char *zOpName;
1400633e6d57Sdrh   sqlite3 *db;
1401e84d8d32Smistachkin   extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1402633e6d57Sdrh   static const struct {
1403633e6d57Sdrh     const char *zName;
1404633e6d57Sdrh     int op;
1405633e6d57Sdrh   } aOp[] = {
14062a58e9ccSdrh     { "LOOKASIDE_USED",      SQLITE_DBSTATUS_LOOKASIDE_USED      },
14072a58e9ccSdrh     { "CACHE_USED",          SQLITE_DBSTATUS_CACHE_USED          },
14082a58e9ccSdrh     { "SCHEMA_USED",         SQLITE_DBSTATUS_SCHEMA_USED         },
14092a58e9ccSdrh     { "STMT_USED",           SQLITE_DBSTATUS_STMT_USED           },
14102a58e9ccSdrh     { "LOOKASIDE_HIT",       SQLITE_DBSTATUS_LOOKASIDE_HIT       },
14112a58e9ccSdrh     { "LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE },
141258ca31c9Sdan     { "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL },
141358ca31c9Sdan     { "CACHE_HIT",           SQLITE_DBSTATUS_CACHE_HIT           },
14149ad3ee40Sdrh     { "CACHE_MISS",          SQLITE_DBSTATUS_CACHE_MISS          },
1415648e2643Sdrh     { "CACHE_WRITE",         SQLITE_DBSTATUS_CACHE_WRITE         },
1416648e2643Sdrh     { "DEFERRED_FKS",        SQLITE_DBSTATUS_DEFERRED_FKS        }
1417633e6d57Sdrh   };
1418633e6d57Sdrh   Tcl_Obj *pResult;
1419633e6d57Sdrh   if( objc!=4 ){
142058ca31c9Sdan     Tcl_WrongNumArgs(interp, 1, objv, "DB PARAMETER RESETFLAG");
1421633e6d57Sdrh     return TCL_ERROR;
1422633e6d57Sdrh   }
1423633e6d57Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1424633e6d57Sdrh   zOpName = Tcl_GetString(objv[2]);
14252a58e9ccSdrh   if( memcmp(zOpName, "SQLITE_", 7)==0 ) zOpName += 7;
14262a58e9ccSdrh   if( memcmp(zOpName, "DBSTATUS_", 9)==0 ) zOpName += 9;
1427633e6d57Sdrh   for(i=0; i<ArraySize(aOp); i++){
1428633e6d57Sdrh     if( strcmp(aOp[i].zName, zOpName)==0 ){
1429633e6d57Sdrh       op = aOp[i].op;
1430633e6d57Sdrh       break;
1431633e6d57Sdrh     }
1432633e6d57Sdrh   }
1433633e6d57Sdrh   if( i>=ArraySize(aOp) ){
1434633e6d57Sdrh     if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR;
1435633e6d57Sdrh   }
1436633e6d57Sdrh   if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR;
1437633e6d57Sdrh   iValue = 0;
1438633e6d57Sdrh   mxValue = 0;
1439633e6d57Sdrh   rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag);
1440633e6d57Sdrh   pResult = Tcl_NewObj();
1441633e6d57Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1442633e6d57Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1443633e6d57Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1444633e6d57Sdrh   Tcl_SetObjResult(interp, pResult);
1445633e6d57Sdrh   return TCL_OK;
1446633e6d57Sdrh }
1447633e6d57Sdrh 
1448633e6d57Sdrh /*
1449d09414cdSdanielk1977 ** install_malloc_faultsim BOOLEAN
1450d09414cdSdanielk1977 */
1451d09414cdSdanielk1977 static int test_install_malloc_faultsim(
1452d09414cdSdanielk1977   void * clientData,
1453d09414cdSdanielk1977   Tcl_Interp *interp,
1454d09414cdSdanielk1977   int objc,
1455d09414cdSdanielk1977   Tcl_Obj *CONST objv[]
1456d09414cdSdanielk1977 ){
1457d09414cdSdanielk1977   int rc;
1458d09414cdSdanielk1977   int isInstall;
1459d09414cdSdanielk1977 
1460d09414cdSdanielk1977   if( objc!=2 ){
1461d09414cdSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
1462d09414cdSdanielk1977     return TCL_ERROR;
1463d09414cdSdanielk1977   }
1464d09414cdSdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
1465d09414cdSdanielk1977     return TCL_ERROR;
1466d09414cdSdanielk1977   }
1467ef05f2dfSdanielk1977   rc = faultsimInstall(isInstall);
1468e84d8d32Smistachkin   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1469d09414cdSdanielk1977   return TCL_OK;
1470d09414cdSdanielk1977 }
1471d09414cdSdanielk1977 
1472d09414cdSdanielk1977 /*
14738b322827Sdanielk1977 ** sqlite3_install_memsys3
14748b322827Sdanielk1977 */
14758b322827Sdanielk1977 static int test_install_memsys3(
14768b322827Sdanielk1977   void * clientData,
14778b322827Sdanielk1977   Tcl_Interp *interp,
14788b322827Sdanielk1977   int objc,
14798b322827Sdanielk1977   Tcl_Obj *CONST objv[]
14808b322827Sdanielk1977 ){
14818b322827Sdanielk1977   int rc = SQLITE_MISUSE;
14828b322827Sdanielk1977 #ifdef SQLITE_ENABLE_MEMSYS3
14838b322827Sdanielk1977   const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
14848b322827Sdanielk1977   rc = sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetMemsys3());
14858b322827Sdanielk1977 #endif
1486e84d8d32Smistachkin   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
14878b322827Sdanielk1977   return TCL_OK;
14888b322827Sdanielk1977 }
14898b322827Sdanielk1977 
1490c396d4afSdan static int test_vfs_oom_test(
1491c396d4afSdan   void * clientData,
1492c396d4afSdan   Tcl_Interp *interp,
1493c396d4afSdan   int objc,
1494c396d4afSdan   Tcl_Obj *CONST objv[]
1495c396d4afSdan ){
1496c396d4afSdan   extern int sqlite3_memdebug_vfs_oom_test;
1497c396d4afSdan   if( objc>2 ){
1498c396d4afSdan     Tcl_WrongNumArgs(interp, 1, objv, "?INTEGER?");
1499c396d4afSdan     return TCL_ERROR;
1500c396d4afSdan   }else if( objc==2 ){
1501c396d4afSdan     int iNew;
1502c396d4afSdan     if( Tcl_GetIntFromObj(interp, objv[1], &iNew) ) return TCL_ERROR;
1503c396d4afSdan     sqlite3_memdebug_vfs_oom_test = iNew;
1504c396d4afSdan   }
1505c396d4afSdan   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_memdebug_vfs_oom_test));
1506c396d4afSdan   return TCL_OK;
1507c396d4afSdan }
1508c396d4afSdan 
15098b322827Sdanielk1977 /*
15102f999a67Sdrh ** Register commands with the TCL interpreter.
15112f999a67Sdrh */
15122f999a67Sdrh int Sqlitetest_malloc_Init(Tcl_Interp *interp){
15132f999a67Sdrh   static struct {
15142f999a67Sdrh      char *zName;
15152f999a67Sdrh      Tcl_ObjCmdProc *xProc;
1516c66c0e14Sdanielk1977      int clientData;
15172f999a67Sdrh   } aObjCmd[] = {
15188a42cbd3Sdrh      { "sqlite3_malloc",             test_malloc                   ,0 },
15198a42cbd3Sdrh      { "sqlite3_realloc",            test_realloc                  ,0 },
15208a42cbd3Sdrh      { "sqlite3_free",               test_free                     ,0 },
15218a42cbd3Sdrh      { "memset",                     test_memset                   ,0 },
15228a42cbd3Sdrh      { "memget",                     test_memget                   ,0 },
15238a42cbd3Sdrh      { "sqlite3_memory_used",        test_memory_used              ,0 },
15248a42cbd3Sdrh      { "sqlite3_memory_highwater",   test_memory_highwater         ,0 },
15258a42cbd3Sdrh      { "sqlite3_memdebug_backtrace", test_memdebug_backtrace       ,0 },
15268a42cbd3Sdrh      { "sqlite3_memdebug_dump",      test_memdebug_dump            ,0 },
15278a42cbd3Sdrh      { "sqlite3_memdebug_fail",      test_memdebug_fail            ,0 },
15288a42cbd3Sdrh      { "sqlite3_memdebug_pending",   test_memdebug_pending         ,0 },
15298a42cbd3Sdrh      { "sqlite3_memdebug_settitle",  test_memdebug_settitle        ,0 },
15308a42cbd3Sdrh      { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 },
15318a42cbd3Sdrh      { "sqlite3_memdebug_log",       test_memdebug_log             ,0 },
15328a42cbd3Sdrh      { "sqlite3_config_scratch",     test_config_scratch           ,0 },
15338a42cbd3Sdrh      { "sqlite3_config_pagecache",   test_config_pagecache         ,0 },
1534b232c232Sdrh      { "sqlite3_config_alt_pcache",  test_alt_pcache               ,0 },
15358a42cbd3Sdrh      { "sqlite3_status",             test_status                   ,0 },
1536633e6d57Sdrh      { "sqlite3_db_status",          test_db_status                ,0 },
15378a42cbd3Sdrh      { "install_malloc_faultsim",    test_install_malloc_faultsim  ,0 },
15385099be5eSdanielk1977      { "sqlite3_config_heap",        test_config_heap              ,0 },
1539ac1f1045Smistachkin      { "sqlite3_config_heap_size",   test_config_heap_size         ,0 },
15408a42cbd3Sdrh      { "sqlite3_config_memstatus",   test_config_memstatus         ,0 },
1541633e6d57Sdrh      { "sqlite3_config_lookaside",   test_config_lookaside         ,0 },
15426480aad4Sdrh      { "sqlite3_config_error",       test_config_error             ,0 },
1543cd74b611Sdan      { "sqlite3_config_uri",         test_config_uri               ,0 },
1544de9a7b8aSdrh      { "sqlite3_config_cis",         test_config_cis               ,0 },
15453bd1791dSdrh      { "sqlite3_config_pmasz",       test_config_pmasz             ,0 },
1546633e6d57Sdrh      { "sqlite3_db_config_lookaside",test_db_config_lookaside      ,0 },
15470d84e5b2Sdanielk1977      { "sqlite3_dump_memsys3",       test_dump_memsys3             ,3 },
1548b232c232Sdrh      { "sqlite3_dump_memsys5",       test_dump_memsys3             ,5 },
15498b322827Sdanielk1977      { "sqlite3_install_memsys3",    test_install_memsys3          ,0 },
1550c396d4afSdan      { "sqlite3_memdebug_vfs_oom_test", test_vfs_oom_test          ,0 },
15512f999a67Sdrh   };
15522f999a67Sdrh   int i;
15532f999a67Sdrh   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
1554860e332cSdrh     ClientData c = (ClientData)SQLITE_INT_TO_PTR(aObjCmd[i].clientData);
1555c66c0e14Sdanielk1977     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
15562f999a67Sdrh   }
15572f999a67Sdrh   return TCL_OK;
15582f999a67Sdrh }
1559ef05f2dfSdanielk1977 #endif
1560