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