1 /* 2 ** 2001 September 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 ** Code for testing the btree.c module in SQLite. This code 13 ** is not included in the SQLite library. It is used for automated 14 ** testing of the SQLite library. 15 ** 16 ** $Id: test3.c,v 1.62 2005/08/11 02:10:19 drh Exp $ 17 */ 18 #include "sqliteInt.h" 19 #include "pager.h" 20 #include "btree.h" 21 #include "tcl.h" 22 #include <stdlib.h> 23 #include <string.h> 24 25 /* 26 ** Interpret an SQLite error number 27 */ 28 static char *errorName(int rc){ 29 char *zName; 30 switch( rc ){ 31 case SQLITE_OK: zName = "SQLITE_OK"; break; 32 case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; 33 case SQLITE_PERM: zName = "SQLITE_PERM"; break; 34 case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; 35 case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; 36 case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; 37 case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; 38 case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; 39 case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; 40 case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; 41 case SQLITE_FULL: zName = "SQLITE_FULL"; break; 42 case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; 43 case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; 44 case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; 45 case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; 46 default: zName = "SQLITE_Unknown"; break; 47 } 48 return zName; 49 } 50 51 /* 52 ** Usage: btree_open FILENAME NCACHE FLAGS 53 ** 54 ** Open a new database 55 */ 56 static int btree_open( 57 void *NotUsed, 58 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 59 int argc, /* Number of arguments */ 60 const char **argv /* Text of each argument */ 61 ){ 62 Btree *pBt; 63 int rc, nCache, flags; 64 char zBuf[100]; 65 if( argc!=4 ){ 66 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 67 " FILENAME NCACHE FLAGS\"", 0); 68 return TCL_ERROR; 69 } 70 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; 71 if( Tcl_GetInt(interp, argv[3], &flags) ) return TCL_ERROR; 72 rc = sqlite3BtreeOpen(argv[1], &pBt, flags); 73 if( rc!=SQLITE_OK ){ 74 Tcl_AppendResult(interp, errorName(rc), 0); 75 return TCL_ERROR; 76 } 77 sqlite3BtreeSetCacheSize(pBt, nCache); 78 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt); 79 Tcl_AppendResult(interp, zBuf, 0); 80 return TCL_OK; 81 } 82 83 /* 84 ** Usage: btree_close ID 85 ** 86 ** Close the given database. 87 */ 88 static int btree_close( 89 void *NotUsed, 90 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 91 int argc, /* Number of arguments */ 92 const char **argv /* Text of each argument */ 93 ){ 94 Btree *pBt; 95 int rc; 96 if( argc!=2 ){ 97 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 98 " ID\"", 0); 99 return TCL_ERROR; 100 } 101 pBt = sqlite3TextToPtr(argv[1]); 102 rc = sqlite3BtreeClose(pBt); 103 if( rc!=SQLITE_OK ){ 104 Tcl_AppendResult(interp, errorName(rc), 0); 105 return TCL_ERROR; 106 } 107 return TCL_OK; 108 } 109 110 /* 111 ** Usage: btree_begin_transaction ID 112 ** 113 ** Start a new transaction 114 */ 115 static int btree_begin_transaction( 116 void *NotUsed, 117 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 118 int argc, /* Number of arguments */ 119 const char **argv /* Text of each argument */ 120 ){ 121 Btree *pBt; 122 int rc; 123 if( argc!=2 ){ 124 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 125 " ID\"", 0); 126 return TCL_ERROR; 127 } 128 pBt = sqlite3TextToPtr(argv[1]); 129 rc = sqlite3BtreeBeginTrans(pBt, 1); 130 if( rc!=SQLITE_OK ){ 131 Tcl_AppendResult(interp, errorName(rc), 0); 132 return TCL_ERROR; 133 } 134 return TCL_OK; 135 } 136 137 /* 138 ** Usage: btree_rollback ID 139 ** 140 ** Rollback changes 141 */ 142 static int btree_rollback( 143 void *NotUsed, 144 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 145 int argc, /* Number of arguments */ 146 const char **argv /* Text of each argument */ 147 ){ 148 Btree *pBt; 149 int rc; 150 if( argc!=2 ){ 151 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 152 " ID\"", 0); 153 return TCL_ERROR; 154 } 155 pBt = sqlite3TextToPtr(argv[1]); 156 rc = sqlite3BtreeRollback(pBt); 157 if( rc!=SQLITE_OK ){ 158 Tcl_AppendResult(interp, errorName(rc), 0); 159 return TCL_ERROR; 160 } 161 return TCL_OK; 162 } 163 164 /* 165 ** Usage: btree_commit ID 166 ** 167 ** Commit all changes 168 */ 169 static int btree_commit( 170 void *NotUsed, 171 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 172 int argc, /* Number of arguments */ 173 const char **argv /* Text of each argument */ 174 ){ 175 Btree *pBt; 176 int rc; 177 if( argc!=2 ){ 178 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 179 " ID\"", 0); 180 return TCL_ERROR; 181 } 182 pBt = sqlite3TextToPtr(argv[1]); 183 rc = sqlite3BtreeCommit(pBt); 184 if( rc!=SQLITE_OK ){ 185 Tcl_AppendResult(interp, errorName(rc), 0); 186 return TCL_ERROR; 187 } 188 return TCL_OK; 189 } 190 191 /* 192 ** Usage: btree_begin_statement ID 193 ** 194 ** Start a new statement transaction 195 */ 196 static int btree_begin_statement( 197 void *NotUsed, 198 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 199 int argc, /* Number of arguments */ 200 const char **argv /* Text of each argument */ 201 ){ 202 Btree *pBt; 203 int rc; 204 if( argc!=2 ){ 205 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 206 " ID\"", 0); 207 return TCL_ERROR; 208 } 209 pBt = sqlite3TextToPtr(argv[1]); 210 rc = sqlite3BtreeBeginStmt(pBt); 211 if( rc!=SQLITE_OK ){ 212 Tcl_AppendResult(interp, errorName(rc), 0); 213 return TCL_ERROR; 214 } 215 return TCL_OK; 216 } 217 218 /* 219 ** Usage: btree_rollback_statement ID 220 ** 221 ** Rollback changes 222 */ 223 static int btree_rollback_statement( 224 void *NotUsed, 225 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 226 int argc, /* Number of arguments */ 227 const char **argv /* Text of each argument */ 228 ){ 229 Btree *pBt; 230 int rc; 231 if( argc!=2 ){ 232 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 233 " ID\"", 0); 234 return TCL_ERROR; 235 } 236 pBt = sqlite3TextToPtr(argv[1]); 237 rc = sqlite3BtreeRollbackStmt(pBt); 238 if( rc!=SQLITE_OK ){ 239 Tcl_AppendResult(interp, errorName(rc), 0); 240 return TCL_ERROR; 241 } 242 return TCL_OK; 243 } 244 245 /* 246 ** Usage: btree_commit_statement ID 247 ** 248 ** Commit all changes 249 */ 250 static int btree_commit_statement( 251 void *NotUsed, 252 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 253 int argc, /* Number of arguments */ 254 const char **argv /* Text of each argument */ 255 ){ 256 Btree *pBt; 257 int rc; 258 if( argc!=2 ){ 259 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 260 " ID\"", 0); 261 return TCL_ERROR; 262 } 263 pBt = sqlite3TextToPtr(argv[1]); 264 rc = sqlite3BtreeCommitStmt(pBt); 265 if( rc!=SQLITE_OK ){ 266 Tcl_AppendResult(interp, errorName(rc), 0); 267 return TCL_ERROR; 268 } 269 return TCL_OK; 270 } 271 272 /* 273 ** Usage: btree_create_table ID FLAGS 274 ** 275 ** Create a new table in the database 276 */ 277 static int btree_create_table( 278 void *NotUsed, 279 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 280 int argc, /* Number of arguments */ 281 const char **argv /* Text of each argument */ 282 ){ 283 Btree *pBt; 284 int rc, iTable, flags; 285 char zBuf[30]; 286 if( argc!=3 ){ 287 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 288 " ID FLAGS\"", 0); 289 return TCL_ERROR; 290 } 291 pBt = sqlite3TextToPtr(argv[1]); 292 if( Tcl_GetInt(interp, argv[2], &flags) ) return TCL_ERROR; 293 rc = sqlite3BtreeCreateTable(pBt, &iTable, flags); 294 if( rc!=SQLITE_OK ){ 295 Tcl_AppendResult(interp, errorName(rc), 0); 296 return TCL_ERROR; 297 } 298 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", iTable); 299 Tcl_AppendResult(interp, zBuf, 0); 300 return TCL_OK; 301 } 302 303 /* 304 ** Usage: btree_drop_table ID TABLENUM 305 ** 306 ** Delete an entire table from the database 307 */ 308 static int btree_drop_table( 309 void *NotUsed, 310 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 311 int argc, /* Number of arguments */ 312 const char **argv /* Text of each argument */ 313 ){ 314 Btree *pBt; 315 int iTable; 316 int rc; 317 int notUsed1; 318 if( argc!=3 ){ 319 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 320 " ID TABLENUM\"", 0); 321 return TCL_ERROR; 322 } 323 pBt = sqlite3TextToPtr(argv[1]); 324 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; 325 rc = sqlite3BtreeDropTable(pBt, iTable, ¬Used1); 326 if( rc!=SQLITE_OK ){ 327 Tcl_AppendResult(interp, errorName(rc), 0); 328 return TCL_ERROR; 329 } 330 return TCL_OK; 331 } 332 333 /* 334 ** Usage: btree_clear_table ID TABLENUM 335 ** 336 ** Remove all entries from the given table but keep the table around. 337 */ 338 static int btree_clear_table( 339 void *NotUsed, 340 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 341 int argc, /* Number of arguments */ 342 const char **argv /* Text of each argument */ 343 ){ 344 Btree *pBt; 345 int iTable; 346 int rc; 347 if( argc!=3 ){ 348 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 349 " ID TABLENUM\"", 0); 350 return TCL_ERROR; 351 } 352 pBt = sqlite3TextToPtr(argv[1]); 353 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; 354 rc = sqlite3BtreeClearTable(pBt, iTable); 355 if( rc!=SQLITE_OK ){ 356 Tcl_AppendResult(interp, errorName(rc), 0); 357 return TCL_ERROR; 358 } 359 return TCL_OK; 360 } 361 362 /* 363 ** Usage: btree_get_meta ID 364 ** 365 ** Return meta data 366 */ 367 static int btree_get_meta( 368 void *NotUsed, 369 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 370 int argc, /* Number of arguments */ 371 const char **argv /* Text of each argument */ 372 ){ 373 Btree *pBt; 374 int rc; 375 int i; 376 if( argc!=2 ){ 377 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 378 " ID\"", 0); 379 return TCL_ERROR; 380 } 381 pBt = sqlite3TextToPtr(argv[1]); 382 for(i=0; i<SQLITE_N_BTREE_META; i++){ 383 char zBuf[30]; 384 unsigned int v; 385 rc = sqlite3BtreeGetMeta(pBt, i, &v); 386 if( rc!=SQLITE_OK ){ 387 Tcl_AppendResult(interp, errorName(rc), 0); 388 return TCL_ERROR; 389 } 390 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",v); 391 Tcl_AppendElement(interp, zBuf); 392 } 393 return TCL_OK; 394 } 395 396 /* 397 ** Usage: btree_update_meta ID METADATA... 398 ** 399 ** Return meta data 400 */ 401 static int btree_update_meta( 402 void *NotUsed, 403 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 404 int argc, /* Number of arguments */ 405 const char **argv /* Text of each argument */ 406 ){ 407 Btree *pBt; 408 int rc; 409 int i; 410 int aMeta[SQLITE_N_BTREE_META]; 411 412 if( argc!=2+SQLITE_N_BTREE_META ){ 413 char zBuf[30]; 414 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",SQLITE_N_BTREE_META); 415 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 416 " ID METADATA...\" (METADATA is ", zBuf, " integers)", 0); 417 return TCL_ERROR; 418 } 419 pBt = sqlite3TextToPtr(argv[1]); 420 for(i=1; i<SQLITE_N_BTREE_META; i++){ 421 if( Tcl_GetInt(interp, argv[i+2], &aMeta[i]) ) return TCL_ERROR; 422 } 423 for(i=1; i<SQLITE_N_BTREE_META; i++){ 424 rc = sqlite3BtreeUpdateMeta(pBt, i, aMeta[i]); 425 if( rc!=SQLITE_OK ){ 426 Tcl_AppendResult(interp, errorName(rc), 0); 427 return TCL_ERROR; 428 } 429 } 430 return TCL_OK; 431 } 432 433 /* 434 ** Usage: btree_page_dump ID PAGENUM 435 ** 436 ** Print a disassembly of a page on standard output 437 */ 438 static int btree_page_dump( 439 void *NotUsed, 440 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 441 int argc, /* Number of arguments */ 442 const char **argv /* Text of each argument */ 443 ){ 444 Btree *pBt; 445 int iPage; 446 int rc; 447 448 if( argc!=3 ){ 449 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 450 " ID\"", 0); 451 return TCL_ERROR; 452 } 453 pBt = sqlite3TextToPtr(argv[1]); 454 if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR; 455 rc = sqlite3BtreePageDump(pBt, iPage, 0); 456 if( rc!=SQLITE_OK ){ 457 Tcl_AppendResult(interp, errorName(rc), 0); 458 return TCL_ERROR; 459 } 460 return TCL_OK; 461 } 462 463 /* 464 ** Usage: btree_tree_dump ID PAGENUM 465 ** 466 ** Print a disassembly of a page and all its child pages on standard output 467 */ 468 static int btree_tree_dump( 469 void *NotUsed, 470 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 471 int argc, /* Number of arguments */ 472 const char **argv /* Text of each argument */ 473 ){ 474 Btree *pBt; 475 int iPage; 476 int rc; 477 478 if( argc!=3 ){ 479 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 480 " ID\"", 0); 481 return TCL_ERROR; 482 } 483 pBt = sqlite3TextToPtr(argv[1]); 484 if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR; 485 rc = sqlite3BtreePageDump(pBt, iPage, 1); 486 if( rc!=SQLITE_OK ){ 487 Tcl_AppendResult(interp, errorName(rc), 0); 488 return TCL_ERROR; 489 } 490 return TCL_OK; 491 } 492 493 /* 494 ** Usage: btree_pager_stats ID 495 ** 496 ** Returns pager statistics 497 */ 498 static int btree_pager_stats( 499 void *NotUsed, 500 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 501 int argc, /* Number of arguments */ 502 const char **argv /* Text of each argument */ 503 ){ 504 Btree *pBt; 505 int i; 506 int *a; 507 508 if( argc!=2 ){ 509 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 510 " ID\"", 0); 511 return TCL_ERROR; 512 } 513 pBt = sqlite3TextToPtr(argv[1]); 514 a = sqlite3pager_stats(sqlite3BtreePager(pBt)); 515 for(i=0; i<11; i++){ 516 static char *zName[] = { 517 "ref", "page", "max", "size", "state", "err", 518 "hit", "miss", "ovfl", "read", "write" 519 }; 520 char zBuf[100]; 521 Tcl_AppendElement(interp, zName[i]); 522 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]); 523 Tcl_AppendElement(interp, zBuf); 524 } 525 return TCL_OK; 526 } 527 528 /* 529 ** Usage: btree_pager_ref_dump ID 530 ** 531 ** Print out all outstanding pages. 532 */ 533 static int btree_pager_ref_dump( 534 void *NotUsed, 535 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 536 int argc, /* Number of arguments */ 537 const char **argv /* Text of each argument */ 538 ){ 539 Btree *pBt; 540 541 if( argc!=2 ){ 542 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 543 " ID\"", 0); 544 return TCL_ERROR; 545 } 546 pBt = sqlite3TextToPtr(argv[1]); 547 #ifdef SQLITE_DEBUG 548 sqlite3pager_refdump(sqlite3BtreePager(pBt)); 549 #endif 550 return TCL_OK; 551 } 552 553 /* 554 ** Usage: btree_integrity_check ID ROOT ... 555 ** 556 ** Look through every page of the given BTree file to verify correct 557 ** formatting and linkage. Return a line of text for each problem found. 558 ** Return an empty string if everything worked. 559 */ 560 static int btree_integrity_check( 561 void *NotUsed, 562 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 563 int argc, /* Number of arguments */ 564 const char **argv /* Text of each argument */ 565 ){ 566 Btree *pBt; 567 int nRoot; 568 int *aRoot; 569 int i; 570 char *zResult; 571 572 if( argc<3 ){ 573 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 574 " ID ROOT ...\"", 0); 575 return TCL_ERROR; 576 } 577 pBt = sqlite3TextToPtr(argv[1]); 578 nRoot = argc-2; 579 aRoot = malloc( sizeof(int)*(argc-2) ); 580 for(i=0; i<argc-2; i++){ 581 if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR; 582 } 583 #ifndef SQLITE_OMIT_INTEGRITY_CHECK 584 zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot); 585 #else 586 zResult = 0; 587 #endif 588 if( zResult ){ 589 Tcl_AppendResult(interp, zResult, 0); 590 sqliteFree(zResult); 591 } 592 return TCL_OK; 593 } 594 595 /* 596 ** Usage: btree_cursor_list ID 597 ** 598 ** Print information about all cursors to standard output for debugging. 599 */ 600 static int btree_cursor_list( 601 void *NotUsed, 602 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 603 int argc, /* Number of arguments */ 604 const char **argv /* Text of each argument */ 605 ){ 606 Btree *pBt; 607 608 if( argc!=2 ){ 609 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 610 " ID\"", 0); 611 return TCL_ERROR; 612 } 613 pBt = sqlite3TextToPtr(argv[1]); 614 sqlite3BtreeCursorList(pBt); 615 return SQLITE_OK; 616 } 617 618 /* 619 ** Usage: btree_cursor ID TABLENUM WRITEABLE 620 ** 621 ** Create a new cursor. Return the ID for the cursor. 622 */ 623 static int btree_cursor( 624 void *NotUsed, 625 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 626 int argc, /* Number of arguments */ 627 const char **argv /* Text of each argument */ 628 ){ 629 Btree *pBt; 630 int iTable; 631 BtCursor *pCur; 632 int rc; 633 int wrFlag; 634 char zBuf[30]; 635 636 if( argc!=4 ){ 637 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 638 " ID TABLENUM WRITEABLE\"", 0); 639 return TCL_ERROR; 640 } 641 pBt = sqlite3TextToPtr(argv[1]); 642 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; 643 if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR; 644 rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, 0, &pCur); 645 if( rc ){ 646 Tcl_AppendResult(interp, errorName(rc), 0); 647 return TCL_ERROR; 648 } 649 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur); 650 Tcl_AppendResult(interp, zBuf, 0); 651 return SQLITE_OK; 652 } 653 654 /* 655 ** Usage: btree_close_cursor ID 656 ** 657 ** Close a cursor opened using btree_cursor. 658 */ 659 static int btree_close_cursor( 660 void *NotUsed, 661 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 662 int argc, /* Number of arguments */ 663 const char **argv /* Text of each argument */ 664 ){ 665 BtCursor *pCur; 666 int rc; 667 668 if( argc!=2 ){ 669 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 670 " ID\"", 0); 671 return TCL_ERROR; 672 } 673 pCur = sqlite3TextToPtr(argv[1]); 674 rc = sqlite3BtreeCloseCursor(pCur); 675 if( rc ){ 676 Tcl_AppendResult(interp, errorName(rc), 0); 677 return TCL_ERROR; 678 } 679 return SQLITE_OK; 680 } 681 682 /* 683 ** Usage: btree_move_to ID KEY 684 ** 685 ** Move the cursor to the entry with the given key. 686 */ 687 static int btree_move_to( 688 void *NotUsed, 689 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 690 int argc, /* Number of arguments */ 691 const char **argv /* Text of each argument */ 692 ){ 693 BtCursor *pCur; 694 int rc; 695 int res; 696 char zBuf[20]; 697 698 if( argc!=3 ){ 699 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 700 " ID KEY\"", 0); 701 return TCL_ERROR; 702 } 703 pCur = sqlite3TextToPtr(argv[1]); 704 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ 705 int iKey; 706 if( Tcl_GetInt(interp, argv[2], &iKey) ) return TCL_ERROR; 707 rc = sqlite3BtreeMoveto(pCur, 0, iKey, &res); 708 }else{ 709 rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), &res); 710 } 711 if( rc ){ 712 Tcl_AppendResult(interp, errorName(rc), 0); 713 return TCL_ERROR; 714 } 715 if( res<0 ) res = -1; 716 if( res>0 ) res = 1; 717 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",res); 718 Tcl_AppendResult(interp, zBuf, 0); 719 return SQLITE_OK; 720 } 721 722 /* 723 ** Usage: btree_delete ID 724 ** 725 ** Delete the entry that the cursor is pointing to 726 */ 727 static int btree_delete( 728 void *NotUsed, 729 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 730 int argc, /* Number of arguments */ 731 const char **argv /* Text of each argument */ 732 ){ 733 BtCursor *pCur; 734 int rc; 735 736 if( argc!=2 ){ 737 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 738 " ID\"", 0); 739 return TCL_ERROR; 740 } 741 pCur = sqlite3TextToPtr(argv[1]); 742 rc = sqlite3BtreeDelete(pCur); 743 if( rc ){ 744 Tcl_AppendResult(interp, errorName(rc), 0); 745 return TCL_ERROR; 746 } 747 return SQLITE_OK; 748 } 749 750 /* 751 ** Usage: btree_insert ID KEY DATA 752 ** 753 ** Create a new entry with the given key and data. If an entry already 754 ** exists with the same key the old entry is overwritten. 755 */ 756 static int btree_insert( 757 void * clientData, 758 Tcl_Interp *interp, 759 int objc, 760 Tcl_Obj *CONST objv[] 761 ){ 762 BtCursor *pCur; 763 int rc; 764 765 if( objc!=4 ){ 766 Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA"); 767 return TCL_ERROR; 768 } 769 pCur = sqlite3TextToPtr(Tcl_GetString(objv[1])); 770 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ 771 i64 iKey; 772 int len; 773 unsigned char *pBuf; 774 if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ) return TCL_ERROR; 775 pBuf = Tcl_GetByteArrayFromObj(objv[3], &len); 776 rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len); 777 }else{ 778 int keylen; 779 int dlen; 780 unsigned char *pKBuf; 781 unsigned char *pDBuf; 782 pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen); 783 pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen); 784 rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen); 785 } 786 if( rc ){ 787 Tcl_AppendResult(interp, errorName(rc), 0); 788 return TCL_ERROR; 789 } 790 return SQLITE_OK; 791 } 792 793 /* 794 ** Usage: btree_next ID 795 ** 796 ** Move the cursor to the next entry in the table. Return 0 on success 797 ** or 1 if the cursor was already on the last entry in the table or if 798 ** the table is empty. 799 */ 800 static int btree_next( 801 void *NotUsed, 802 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 803 int argc, /* Number of arguments */ 804 const char **argv /* Text of each argument */ 805 ){ 806 BtCursor *pCur; 807 int rc; 808 int res = 0; 809 char zBuf[100]; 810 811 if( argc!=2 ){ 812 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 813 " ID\"", 0); 814 return TCL_ERROR; 815 } 816 pCur = sqlite3TextToPtr(argv[1]); 817 rc = sqlite3BtreeNext(pCur, &res); 818 if( rc ){ 819 Tcl_AppendResult(interp, errorName(rc), 0); 820 return TCL_ERROR; 821 } 822 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 823 Tcl_AppendResult(interp, zBuf, 0); 824 return SQLITE_OK; 825 } 826 827 /* 828 ** Usage: btree_prev ID 829 ** 830 ** Move the cursor to the previous entry in the table. Return 0 on 831 ** success and 1 if the cursor was already on the first entry in 832 ** the table or if the table was empty. 833 */ 834 static int btree_prev( 835 void *NotUsed, 836 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 837 int argc, /* Number of arguments */ 838 const char **argv /* Text of each argument */ 839 ){ 840 BtCursor *pCur; 841 int rc; 842 int res = 0; 843 char zBuf[100]; 844 845 if( argc!=2 ){ 846 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 847 " ID\"", 0); 848 return TCL_ERROR; 849 } 850 pCur = sqlite3TextToPtr(argv[1]); 851 rc = sqlite3BtreePrevious(pCur, &res); 852 if( rc ){ 853 Tcl_AppendResult(interp, errorName(rc), 0); 854 return TCL_ERROR; 855 } 856 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 857 Tcl_AppendResult(interp, zBuf, 0); 858 return SQLITE_OK; 859 } 860 861 /* 862 ** Usage: btree_first ID 863 ** 864 ** Move the cursor to the first entry in the table. Return 0 if the 865 ** cursor was left point to something and 1 if the table is empty. 866 */ 867 static int btree_first( 868 void *NotUsed, 869 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 870 int argc, /* Number of arguments */ 871 const char **argv /* Text of each argument */ 872 ){ 873 BtCursor *pCur; 874 int rc; 875 int res = 0; 876 char zBuf[100]; 877 878 if( argc!=2 ){ 879 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 880 " ID\"", 0); 881 return TCL_ERROR; 882 } 883 pCur = sqlite3TextToPtr(argv[1]); 884 rc = sqlite3BtreeFirst(pCur, &res); 885 if( rc ){ 886 Tcl_AppendResult(interp, errorName(rc), 0); 887 return TCL_ERROR; 888 } 889 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 890 Tcl_AppendResult(interp, zBuf, 0); 891 return SQLITE_OK; 892 } 893 894 /* 895 ** Usage: btree_last ID 896 ** 897 ** Move the cursor to the last entry in the table. Return 0 if the 898 ** cursor was left point to something and 1 if the table is empty. 899 */ 900 static int btree_last( 901 void *NotUsed, 902 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 903 int argc, /* Number of arguments */ 904 const char **argv /* Text of each argument */ 905 ){ 906 BtCursor *pCur; 907 int rc; 908 int res = 0; 909 char zBuf[100]; 910 911 if( argc!=2 ){ 912 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 913 " ID\"", 0); 914 return TCL_ERROR; 915 } 916 pCur = sqlite3TextToPtr(argv[1]); 917 rc = sqlite3BtreeLast(pCur, &res); 918 if( rc ){ 919 Tcl_AppendResult(interp, errorName(rc), 0); 920 return TCL_ERROR; 921 } 922 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 923 Tcl_AppendResult(interp, zBuf, 0); 924 return SQLITE_OK; 925 } 926 927 /* 928 ** Usage: btree_eof ID 929 ** 930 ** Return TRUE if the given cursor is not pointing at a valid entry. 931 ** Return FALSE if the cursor does point to a valid entry. 932 */ 933 static int btree_eof( 934 void *NotUsed, 935 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 936 int argc, /* Number of arguments */ 937 const char **argv /* Text of each argument */ 938 ){ 939 BtCursor *pCur; 940 char zBuf[50]; 941 942 if( argc!=2 ){ 943 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 944 " ID\"", 0); 945 return TCL_ERROR; 946 } 947 pCur = sqlite3TextToPtr(argv[1]); 948 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", sqlite3BtreeEof(pCur)); 949 Tcl_AppendResult(interp, zBuf, 0); 950 return SQLITE_OK; 951 } 952 953 /* 954 ** Usage: btree_keysize ID 955 ** 956 ** Return the number of bytes of key. For an INTKEY table, this 957 ** returns the key itself. 958 */ 959 static int btree_keysize( 960 void *NotUsed, 961 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 962 int argc, /* Number of arguments */ 963 const char **argv /* Text of each argument */ 964 ){ 965 BtCursor *pCur; 966 u64 n; 967 char zBuf[50]; 968 969 if( argc!=2 ){ 970 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 971 " ID\"", 0); 972 return TCL_ERROR; 973 } 974 pCur = sqlite3TextToPtr(argv[1]); 975 sqlite3BtreeKeySize(pCur, &n); 976 sqlite3_snprintf(sizeof(zBuf),zBuf, "%llu", n); 977 Tcl_AppendResult(interp, zBuf, 0); 978 return SQLITE_OK; 979 } 980 981 /* 982 ** Usage: btree_key ID 983 ** 984 ** Return the key for the entry at which the cursor is pointing. 985 */ 986 static int btree_key( 987 void *NotUsed, 988 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 989 int argc, /* Number of arguments */ 990 const char **argv /* Text of each argument */ 991 ){ 992 BtCursor *pCur; 993 int rc; 994 u64 n; 995 char *zBuf; 996 997 if( argc!=2 ){ 998 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 999 " ID\"", 0); 1000 return TCL_ERROR; 1001 } 1002 pCur = sqlite3TextToPtr(argv[1]); 1003 sqlite3BtreeKeySize(pCur, &n); 1004 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ 1005 char zBuf2[60]; 1006 sqlite3_snprintf(sizeof(zBuf2),zBuf2, "%llu", n); 1007 Tcl_AppendResult(interp, zBuf2, 0); 1008 }else{ 1009 zBuf = malloc( n+1 ); 1010 rc = sqlite3BtreeKey(pCur, 0, n, zBuf); 1011 if( rc ){ 1012 Tcl_AppendResult(interp, errorName(rc), 0); 1013 return TCL_ERROR; 1014 } 1015 zBuf[n] = 0; 1016 Tcl_AppendResult(interp, zBuf, 0); 1017 free(zBuf); 1018 } 1019 return SQLITE_OK; 1020 } 1021 1022 /* 1023 ** Usage: btree_data ID ?N? 1024 ** 1025 ** Return the data for the entry at which the cursor is pointing. 1026 */ 1027 static int btree_data( 1028 void *NotUsed, 1029 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1030 int argc, /* Number of arguments */ 1031 const char **argv /* Text of each argument */ 1032 ){ 1033 BtCursor *pCur; 1034 int rc; 1035 u32 n; 1036 char *zBuf; 1037 1038 if( argc!=2 && argc!=3 ){ 1039 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1040 " ID\"", 0); 1041 return TCL_ERROR; 1042 } 1043 pCur = sqlite3TextToPtr(argv[1]); 1044 if( argc==2 ){ 1045 sqlite3BtreeDataSize(pCur, &n); 1046 }else{ 1047 n = atoi(argv[2]); 1048 } 1049 zBuf = malloc( n+1 ); 1050 rc = sqlite3BtreeData(pCur, 0, n, zBuf); 1051 if( rc ){ 1052 Tcl_AppendResult(interp, errorName(rc), 0); 1053 return TCL_ERROR; 1054 } 1055 zBuf[n] = 0; 1056 Tcl_AppendResult(interp, zBuf, 0); 1057 free(zBuf); 1058 return SQLITE_OK; 1059 } 1060 1061 /* 1062 ** Usage: btree_fetch_key ID AMT 1063 ** 1064 ** Use the sqlite3BtreeKeyFetch() routine to get AMT bytes of the key. 1065 ** If sqlite3BtreeKeyFetch() fails, return an empty string. 1066 */ 1067 static int btree_fetch_key( 1068 void *NotUsed, 1069 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1070 int argc, /* Number of arguments */ 1071 const char **argv /* Text of each argument */ 1072 ){ 1073 BtCursor *pCur; 1074 int n; 1075 int amt; 1076 u64 nKey; 1077 const char *zBuf; 1078 char zStatic[1000]; 1079 1080 if( argc!=3 ){ 1081 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1082 " ID AMT\"", 0); 1083 return TCL_ERROR; 1084 } 1085 pCur = sqlite3TextToPtr(argv[1]); 1086 if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; 1087 sqlite3BtreeKeySize(pCur, &nKey); 1088 zBuf = sqlite3BtreeKeyFetch(pCur, &amt); 1089 if( zBuf && amt>=n ){ 1090 assert( nKey<sizeof(zStatic) ); 1091 if( n>0 ) nKey = n; 1092 memcpy(zStatic, zBuf, (int)nKey); 1093 zStatic[nKey] = 0; 1094 Tcl_AppendResult(interp, zStatic, 0); 1095 } 1096 return TCL_OK; 1097 } 1098 1099 /* 1100 ** Usage: btree_fetch_data ID AMT 1101 ** 1102 ** Use the sqlite3BtreeDataFetch() routine to get AMT bytes of the key. 1103 ** If sqlite3BtreeDataFetch() fails, return an empty string. 1104 */ 1105 static int btree_fetch_data( 1106 void *NotUsed, 1107 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1108 int argc, /* Number of arguments */ 1109 const char **argv /* Text of each argument */ 1110 ){ 1111 BtCursor *pCur; 1112 int n; 1113 int amt; 1114 u32 nData; 1115 const char *zBuf; 1116 char zStatic[1000]; 1117 1118 if( argc!=3 ){ 1119 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1120 " ID AMT\"", 0); 1121 return TCL_ERROR; 1122 } 1123 pCur = sqlite3TextToPtr(argv[1]); 1124 if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; 1125 sqlite3BtreeDataSize(pCur, &nData); 1126 zBuf = sqlite3BtreeDataFetch(pCur, &amt); 1127 if( zBuf && amt>=n ){ 1128 assert( nData<sizeof(zStatic) ); 1129 if( n>0 ) nData = n; 1130 memcpy(zStatic, zBuf, (int)nData); 1131 zStatic[nData] = 0; 1132 Tcl_AppendResult(interp, zStatic, 0); 1133 } 1134 return TCL_OK; 1135 } 1136 1137 /* 1138 ** Usage: btree_payload_size ID 1139 ** 1140 ** Return the number of bytes of payload 1141 */ 1142 static int btree_payload_size( 1143 void *NotUsed, 1144 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1145 int argc, /* Number of arguments */ 1146 const char **argv /* Text of each argument */ 1147 ){ 1148 BtCursor *pCur; 1149 int n2; 1150 u64 n1; 1151 char zBuf[50]; 1152 1153 if( argc!=2 ){ 1154 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1155 " ID\"", 0); 1156 return TCL_ERROR; 1157 } 1158 pCur = sqlite3TextToPtr(argv[1]); 1159 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ 1160 n1 = 0; 1161 }else{ 1162 sqlite3BtreeKeySize(pCur, &n1); 1163 } 1164 sqlite3BtreeDataSize(pCur, &n2); 1165 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2)); 1166 Tcl_AppendResult(interp, zBuf, 0); 1167 return SQLITE_OK; 1168 } 1169 1170 /* 1171 ** Usage: btree_cursor_info ID ?UP-CNT? 1172 ** 1173 ** Return integers containing information about the entry the 1174 ** cursor is pointing to: 1175 ** 1176 ** aResult[0] = The page number 1177 ** aResult[1] = The entry number 1178 ** aResult[2] = Total number of entries on this page 1179 ** aResult[3] = Cell size (local payload + header) 1180 ** aResult[4] = Number of free bytes on this page 1181 ** aResult[5] = Number of free blocks on the page 1182 ** aResult[6] = Total payload size (local + overflow) 1183 ** aResult[7] = Header size in bytes 1184 ** aResult[8] = Local payload size 1185 ** aResult[9] = Parent page number 1186 */ 1187 static int btree_cursor_info( 1188 void *NotUsed, 1189 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1190 int argc, /* Number of arguments */ 1191 const char **argv /* Text of each argument */ 1192 ){ 1193 BtCursor *pCur; 1194 int rc; 1195 int i, j; 1196 int up; 1197 int aResult[10]; 1198 char zBuf[400]; 1199 1200 if( argc!=2 && argc!=3 ){ 1201 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1202 " ID ?UP-CNT?\"", 0); 1203 return TCL_ERROR; 1204 } 1205 pCur = sqlite3TextToPtr(argv[1]); 1206 if( argc==3 ){ 1207 if( Tcl_GetInt(interp, argv[2], &up) ) return TCL_ERROR; 1208 }else{ 1209 up = 0; 1210 } 1211 rc = sqlite3BtreeCursorInfo(pCur, aResult, up); 1212 if( rc ){ 1213 Tcl_AppendResult(interp, errorName(rc), 0); 1214 return TCL_ERROR; 1215 } 1216 j = 0; 1217 for(i=0; i<sizeof(aResult)/sizeof(aResult[0]); i++){ 1218 sqlite3_snprintf(40,&zBuf[j]," %d", aResult[i]); 1219 j += strlen(&zBuf[j]); 1220 } 1221 Tcl_AppendResult(interp, &zBuf[1], 0); 1222 return SQLITE_OK; 1223 } 1224 1225 /* 1226 ** The command is provided for the purpose of setting breakpoints. 1227 ** in regression test scripts. 1228 ** 1229 ** By setting a GDB breakpoint on this procedure and executing the 1230 ** btree_breakpoint command in a test script, we can stop GDB at 1231 ** the point in the script where the btree_breakpoint command is 1232 ** inserted. This is useful for debugging. 1233 */ 1234 static int btree_breakpoint( 1235 void *NotUsed, 1236 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1237 int argc, /* Number of arguments */ 1238 const char **argv /* Text of each argument */ 1239 ){ 1240 return TCL_OK; 1241 } 1242 1243 /* 1244 ** usage: varint_test START MULTIPLIER COUNT INCREMENT 1245 ** 1246 ** This command tests the sqlite3PutVarint() and sqlite3GetVarint() 1247 ** routines, both for accuracy and for speed. 1248 ** 1249 ** An integer is written using PutVarint() and read back with 1250 ** GetVarint() and varified to be unchanged. This repeats COUNT 1251 ** times. The first integer is START*MULTIPLIER. Each iteration 1252 ** increases the integer by INCREMENT. 1253 ** 1254 ** This command returns nothing if it works. It returns an error message 1255 ** if something goes wrong. 1256 */ 1257 static int btree_varint_test( 1258 void *NotUsed, 1259 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1260 int argc, /* Number of arguments */ 1261 const char **argv /* Text of each argument */ 1262 ){ 1263 u32 start, mult, count, incr; 1264 u64 in, out; 1265 int n1, n2, i, j; 1266 unsigned char zBuf[100]; 1267 if( argc!=5 ){ 1268 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1269 " START MULTIPLIER COUNT INCREMENT\"", 0); 1270 return TCL_ERROR; 1271 } 1272 if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR; 1273 if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR; 1274 if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR; 1275 if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR; 1276 in = start; 1277 in *= mult; 1278 for(i=0; i<count; i++){ 1279 char zErr[200]; 1280 n1 = sqlite3PutVarint(zBuf, in); 1281 if( n1>9 || n1<1 ){ 1282 sprintf(zErr, "PutVarint returned %d - should be between 1 and 9", n1); 1283 Tcl_AppendResult(interp, zErr, 0); 1284 return TCL_ERROR; 1285 } 1286 n2 = sqlite3GetVarint(zBuf, &out); 1287 if( n1!=n2 ){ 1288 sprintf(zErr, "PutVarint returned %d and GetVarint returned %d", n1, n2); 1289 Tcl_AppendResult(interp, zErr, 0); 1290 return TCL_ERROR; 1291 } 1292 if( in!=out ){ 1293 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out); 1294 Tcl_AppendResult(interp, zErr, 0); 1295 return TCL_ERROR; 1296 } 1297 if( (in & 0xffffffff)==in ){ 1298 u32 out32; 1299 n2 = sqlite3GetVarint32(zBuf, &out32); 1300 out = out32; 1301 if( n1!=n2 ){ 1302 sprintf(zErr, "PutVarint returned %d and GetVarint32 returned %d", 1303 n1, n2); 1304 Tcl_AppendResult(interp, zErr, 0); 1305 return TCL_ERROR; 1306 } 1307 if( in!=out ){ 1308 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32", 1309 in, out); 1310 Tcl_AppendResult(interp, zErr, 0); 1311 return TCL_ERROR; 1312 } 1313 } 1314 1315 /* In order to get realistic timings, run getVarint 19 more times. 1316 ** This is because getVarint is called about 20 times more often 1317 ** than putVarint. 1318 */ 1319 for(j=0; j<19; j++){ 1320 sqlite3GetVarint(zBuf, &out); 1321 } 1322 in += incr; 1323 } 1324 return TCL_OK; 1325 } 1326 1327 /* 1328 ** usage: btree_from_db DB-HANDLE 1329 ** 1330 ** This command returns the btree handle for the main database associated 1331 ** with the database-handle passed as the argument. Example usage: 1332 ** 1333 ** sqlite3 db test.db 1334 ** set bt [btree_from_db db] 1335 */ 1336 static int btree_from_db( 1337 void *NotUsed, 1338 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1339 int argc, /* Number of arguments */ 1340 const char **argv /* Text of each argument */ 1341 ){ 1342 char zBuf[100]; 1343 Tcl_CmdInfo info; 1344 sqlite3 *db; 1345 Btree *pBt; 1346 1347 if( argc!=2 ){ 1348 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1349 " DB-HANDLE\"", 0); 1350 return TCL_ERROR; 1351 } 1352 1353 if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){ 1354 Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0); 1355 return TCL_ERROR; 1356 } 1357 db = *((sqlite3 **)info.objClientData); 1358 assert( db ); 1359 1360 pBt = db->aDb[0].pBt; 1361 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt); 1362 Tcl_SetResult(interp, zBuf, TCL_VOLATILE); 1363 return TCL_OK; 1364 } 1365 1366 1367 /* 1368 ** usage: btree_set_cache_size ID NCACHE 1369 ** 1370 ** Set the size of the cache used by btree $ID. 1371 */ 1372 static int btree_set_cache_size( 1373 void *NotUsed, 1374 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1375 int argc, /* Number of arguments */ 1376 const char **argv /* Text of each argument */ 1377 ){ 1378 int nCache; 1379 Btree *pBt; 1380 1381 if( argc!=3 ){ 1382 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1383 " BT NCACHE\"", 0); 1384 return TCL_ERROR; 1385 } 1386 pBt = sqlite3TextToPtr(argv[1]); 1387 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; 1388 sqlite3BtreeSetCacheSize(pBt, nCache); 1389 return TCL_OK; 1390 } 1391 1392 1393 /* 1394 ** Register commands with the TCL interpreter. 1395 */ 1396 int Sqlitetest3_Init(Tcl_Interp *interp){ 1397 extern int sqlite3_btree_trace; 1398 static struct { 1399 char *zName; 1400 Tcl_CmdProc *xProc; 1401 } aCmd[] = { 1402 { "btree_open", (Tcl_CmdProc*)btree_open }, 1403 { "btree_close", (Tcl_CmdProc*)btree_close }, 1404 { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction }, 1405 { "btree_commit", (Tcl_CmdProc*)btree_commit }, 1406 { "btree_rollback", (Tcl_CmdProc*)btree_rollback }, 1407 { "btree_create_table", (Tcl_CmdProc*)btree_create_table }, 1408 { "btree_drop_table", (Tcl_CmdProc*)btree_drop_table }, 1409 { "btree_clear_table", (Tcl_CmdProc*)btree_clear_table }, 1410 { "btree_get_meta", (Tcl_CmdProc*)btree_get_meta }, 1411 { "btree_update_meta", (Tcl_CmdProc*)btree_update_meta }, 1412 { "btree_page_dump", (Tcl_CmdProc*)btree_page_dump }, 1413 { "btree_tree_dump", (Tcl_CmdProc*)btree_tree_dump }, 1414 { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats }, 1415 { "btree_pager_ref_dump", (Tcl_CmdProc*)btree_pager_ref_dump }, 1416 { "btree_cursor", (Tcl_CmdProc*)btree_cursor }, 1417 { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor }, 1418 { "btree_move_to", (Tcl_CmdProc*)btree_move_to }, 1419 { "btree_delete", (Tcl_CmdProc*)btree_delete }, 1420 { "btree_next", (Tcl_CmdProc*)btree_next }, 1421 { "btree_prev", (Tcl_CmdProc*)btree_prev }, 1422 { "btree_eof", (Tcl_CmdProc*)btree_eof }, 1423 { "btree_keysize", (Tcl_CmdProc*)btree_keysize }, 1424 { "btree_key", (Tcl_CmdProc*)btree_key }, 1425 { "btree_data", (Tcl_CmdProc*)btree_data }, 1426 { "btree_fetch_key", (Tcl_CmdProc*)btree_fetch_key }, 1427 { "btree_fetch_data", (Tcl_CmdProc*)btree_fetch_data }, 1428 { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size }, 1429 { "btree_first", (Tcl_CmdProc*)btree_first }, 1430 { "btree_last", (Tcl_CmdProc*)btree_last }, 1431 { "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info }, 1432 { "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list }, 1433 { "btree_integrity_check", (Tcl_CmdProc*)btree_integrity_check }, 1434 { "btree_breakpoint", (Tcl_CmdProc*)btree_breakpoint }, 1435 { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test }, 1436 { "btree_begin_statement", (Tcl_CmdProc*)btree_begin_statement }, 1437 { "btree_commit_statement", (Tcl_CmdProc*)btree_commit_statement }, 1438 { "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement }, 1439 { "btree_from_db", (Tcl_CmdProc*)btree_from_db }, 1440 { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size }, 1441 }; 1442 int i; 1443 1444 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 1445 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 1446 } 1447 Tcl_LinkVar(interp, "pager_refinfo_enable", (char*)&pager3_refinfo_enable, 1448 TCL_LINK_INT); 1449 Tcl_LinkVar(interp, "btree_trace", (char*)&sqlite3_btree_trace, 1450 TCL_LINK_INT); 1451 1452 /* The btree_insert command is implemented using the tcl 'object' 1453 ** interface, not the string interface like the other commands in this 1454 ** file. This is so binary data can be inserted into btree tables. 1455 */ 1456 Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0); 1457 return TCL_OK; 1458 } 1459