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