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.68 2007/01/03 23:37:28 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], 0, &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 free(aRoot); 589 if( zResult ){ 590 Tcl_AppendResult(interp, zResult, 0); 591 sqliteFree(zResult); 592 } 593 return TCL_OK; 594 } 595 596 /* 597 ** Usage: btree_cursor_list ID 598 ** 599 ** Print information about all cursors to standard output for debugging. 600 */ 601 static int btree_cursor_list( 602 void *NotUsed, 603 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 604 int argc, /* Number of arguments */ 605 const char **argv /* Text of each argument */ 606 ){ 607 Btree *pBt; 608 609 if( argc!=2 ){ 610 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 611 " ID\"", 0); 612 return TCL_ERROR; 613 } 614 pBt = sqlite3TextToPtr(argv[1]); 615 sqlite3BtreeCursorList(pBt); 616 return SQLITE_OK; 617 } 618 619 /* 620 ** Usage: btree_cursor ID TABLENUM WRITEABLE 621 ** 622 ** Create a new cursor. Return the ID for the cursor. 623 */ 624 static int btree_cursor( 625 void *NotUsed, 626 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 627 int argc, /* Number of arguments */ 628 const char **argv /* Text of each argument */ 629 ){ 630 Btree *pBt; 631 int iTable; 632 BtCursor *pCur; 633 int rc; 634 int wrFlag; 635 char zBuf[30]; 636 637 if( argc!=4 ){ 638 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 639 " ID TABLENUM WRITEABLE\"", 0); 640 return TCL_ERROR; 641 } 642 pBt = sqlite3TextToPtr(argv[1]); 643 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; 644 if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR; 645 rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, 0, &pCur); 646 if( rc ){ 647 Tcl_AppendResult(interp, errorName(rc), 0); 648 return TCL_ERROR; 649 } 650 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur); 651 Tcl_AppendResult(interp, zBuf, 0); 652 return SQLITE_OK; 653 } 654 655 /* 656 ** Usage: btree_close_cursor ID 657 ** 658 ** Close a cursor opened using btree_cursor. 659 */ 660 static int btree_close_cursor( 661 void *NotUsed, 662 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 663 int argc, /* Number of arguments */ 664 const char **argv /* Text of each argument */ 665 ){ 666 BtCursor *pCur; 667 int rc; 668 669 if( argc!=2 ){ 670 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 671 " ID\"", 0); 672 return TCL_ERROR; 673 } 674 pCur = sqlite3TextToPtr(argv[1]); 675 rc = sqlite3BtreeCloseCursor(pCur); 676 if( rc ){ 677 Tcl_AppendResult(interp, errorName(rc), 0); 678 return TCL_ERROR; 679 } 680 return SQLITE_OK; 681 } 682 683 /* 684 ** Usage: btree_move_to ID KEY 685 ** 686 ** Move the cursor to the entry with the given key. 687 */ 688 static int btree_move_to( 689 void *NotUsed, 690 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 691 int argc, /* Number of arguments */ 692 const char **argv /* Text of each argument */ 693 ){ 694 BtCursor *pCur; 695 int rc; 696 int res; 697 char zBuf[20]; 698 699 if( argc!=3 ){ 700 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 701 " ID KEY\"", 0); 702 return TCL_ERROR; 703 } 704 pCur = sqlite3TextToPtr(argv[1]); 705 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ 706 int iKey; 707 if( Tcl_GetInt(interp, argv[2], &iKey) ) return TCL_ERROR; 708 rc = sqlite3BtreeMoveto(pCur, 0, iKey, &res); 709 }else{ 710 rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), &res); 711 } 712 if( rc ){ 713 Tcl_AppendResult(interp, errorName(rc), 0); 714 return TCL_ERROR; 715 } 716 if( res<0 ) res = -1; 717 if( res>0 ) res = 1; 718 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",res); 719 Tcl_AppendResult(interp, zBuf, 0); 720 return SQLITE_OK; 721 } 722 723 /* 724 ** Usage: btree_delete ID 725 ** 726 ** Delete the entry that the cursor is pointing to 727 */ 728 static int btree_delete( 729 void *NotUsed, 730 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 731 int argc, /* Number of arguments */ 732 const char **argv /* Text of each argument */ 733 ){ 734 BtCursor *pCur; 735 int rc; 736 737 if( argc!=2 ){ 738 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 739 " ID\"", 0); 740 return TCL_ERROR; 741 } 742 pCur = sqlite3TextToPtr(argv[1]); 743 rc = sqlite3BtreeDelete(pCur); 744 if( rc ){ 745 Tcl_AppendResult(interp, errorName(rc), 0); 746 return TCL_ERROR; 747 } 748 return SQLITE_OK; 749 } 750 751 /* 752 ** Usage: btree_insert ID KEY DATA 753 ** 754 ** Create a new entry with the given key and data. If an entry already 755 ** exists with the same key the old entry is overwritten. 756 */ 757 static int btree_insert( 758 void * clientData, 759 Tcl_Interp *interp, 760 int objc, 761 Tcl_Obj *CONST objv[] 762 ){ 763 BtCursor *pCur; 764 int rc; 765 766 if( objc!=4 ){ 767 Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA"); 768 return TCL_ERROR; 769 } 770 pCur = sqlite3TextToPtr(Tcl_GetString(objv[1])); 771 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ 772 i64 iKey; 773 int len; 774 unsigned char *pBuf; 775 if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ) return TCL_ERROR; 776 pBuf = Tcl_GetByteArrayFromObj(objv[3], &len); 777 rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len); 778 }else{ 779 int keylen; 780 int dlen; 781 unsigned char *pKBuf; 782 unsigned char *pDBuf; 783 pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen); 784 pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen); 785 rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen); 786 } 787 if( rc ){ 788 Tcl_AppendResult(interp, errorName(rc), 0); 789 return TCL_ERROR; 790 } 791 return SQLITE_OK; 792 } 793 794 /* 795 ** Usage: btree_next ID 796 ** 797 ** Move the cursor to the next entry in the table. Return 0 on success 798 ** or 1 if the cursor was already on the last entry in the table or if 799 ** the table is empty. 800 */ 801 static int btree_next( 802 void *NotUsed, 803 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 804 int argc, /* Number of arguments */ 805 const char **argv /* Text of each argument */ 806 ){ 807 BtCursor *pCur; 808 int rc; 809 int res = 0; 810 char zBuf[100]; 811 812 if( argc!=2 ){ 813 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 814 " ID\"", 0); 815 return TCL_ERROR; 816 } 817 pCur = sqlite3TextToPtr(argv[1]); 818 rc = sqlite3BtreeNext(pCur, &res); 819 if( rc ){ 820 Tcl_AppendResult(interp, errorName(rc), 0); 821 return TCL_ERROR; 822 } 823 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 824 Tcl_AppendResult(interp, zBuf, 0); 825 return SQLITE_OK; 826 } 827 828 /* 829 ** Usage: btree_prev ID 830 ** 831 ** Move the cursor to the previous entry in the table. Return 0 on 832 ** success and 1 if the cursor was already on the first entry in 833 ** the table or if the table was empty. 834 */ 835 static int btree_prev( 836 void *NotUsed, 837 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 838 int argc, /* Number of arguments */ 839 const char **argv /* Text of each argument */ 840 ){ 841 BtCursor *pCur; 842 int rc; 843 int res = 0; 844 char zBuf[100]; 845 846 if( argc!=2 ){ 847 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 848 " ID\"", 0); 849 return TCL_ERROR; 850 } 851 pCur = sqlite3TextToPtr(argv[1]); 852 rc = sqlite3BtreePrevious(pCur, &res); 853 if( rc ){ 854 Tcl_AppendResult(interp, errorName(rc), 0); 855 return TCL_ERROR; 856 } 857 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 858 Tcl_AppendResult(interp, zBuf, 0); 859 return SQLITE_OK; 860 } 861 862 /* 863 ** Usage: btree_first ID 864 ** 865 ** Move the cursor to the first entry in the table. Return 0 if the 866 ** cursor was left point to something and 1 if the table is empty. 867 */ 868 static int btree_first( 869 void *NotUsed, 870 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 871 int argc, /* Number of arguments */ 872 const char **argv /* Text of each argument */ 873 ){ 874 BtCursor *pCur; 875 int rc; 876 int res = 0; 877 char zBuf[100]; 878 879 if( argc!=2 ){ 880 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 881 " ID\"", 0); 882 return TCL_ERROR; 883 } 884 pCur = sqlite3TextToPtr(argv[1]); 885 rc = sqlite3BtreeFirst(pCur, &res); 886 if( rc ){ 887 Tcl_AppendResult(interp, errorName(rc), 0); 888 return TCL_ERROR; 889 } 890 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 891 Tcl_AppendResult(interp, zBuf, 0); 892 return SQLITE_OK; 893 } 894 895 /* 896 ** Usage: btree_last ID 897 ** 898 ** Move the cursor to the last entry in the table. Return 0 if the 899 ** cursor was left point to something and 1 if the table is empty. 900 */ 901 static int btree_last( 902 void *NotUsed, 903 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 904 int argc, /* Number of arguments */ 905 const char **argv /* Text of each argument */ 906 ){ 907 BtCursor *pCur; 908 int rc; 909 int res = 0; 910 char zBuf[100]; 911 912 if( argc!=2 ){ 913 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 914 " ID\"", 0); 915 return TCL_ERROR; 916 } 917 pCur = sqlite3TextToPtr(argv[1]); 918 rc = sqlite3BtreeLast(pCur, &res); 919 if( rc ){ 920 Tcl_AppendResult(interp, errorName(rc), 0); 921 return TCL_ERROR; 922 } 923 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 924 Tcl_AppendResult(interp, zBuf, 0); 925 return SQLITE_OK; 926 } 927 928 /* 929 ** Usage: btree_eof ID 930 ** 931 ** Return TRUE if the given cursor is not pointing at a valid entry. 932 ** Return FALSE if the cursor does point to a valid entry. 933 */ 934 static int btree_eof( 935 void *NotUsed, 936 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 937 int argc, /* Number of arguments */ 938 const char **argv /* Text of each argument */ 939 ){ 940 BtCursor *pCur; 941 char zBuf[50]; 942 943 if( argc!=2 ){ 944 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 945 " ID\"", 0); 946 return TCL_ERROR; 947 } 948 pCur = sqlite3TextToPtr(argv[1]); 949 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", sqlite3BtreeEof(pCur)); 950 Tcl_AppendResult(interp, zBuf, 0); 951 return SQLITE_OK; 952 } 953 954 /* 955 ** Usage: btree_keysize ID 956 ** 957 ** Return the number of bytes of key. For an INTKEY table, this 958 ** returns the key itself. 959 */ 960 static int btree_keysize( 961 void *NotUsed, 962 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 963 int argc, /* Number of arguments */ 964 const char **argv /* Text of each argument */ 965 ){ 966 BtCursor *pCur; 967 u64 n; 968 char zBuf[50]; 969 970 if( argc!=2 ){ 971 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 972 " ID\"", 0); 973 return TCL_ERROR; 974 } 975 pCur = sqlite3TextToPtr(argv[1]); 976 sqlite3BtreeKeySize(pCur, (i64*)&n); 977 sqlite3_snprintf(sizeof(zBuf),zBuf, "%llu", n); 978 Tcl_AppendResult(interp, zBuf, 0); 979 return SQLITE_OK; 980 } 981 982 /* 983 ** Usage: btree_key ID 984 ** 985 ** Return the key for the entry at which the cursor is pointing. 986 */ 987 static int btree_key( 988 void *NotUsed, 989 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 990 int argc, /* Number of arguments */ 991 const char **argv /* Text of each argument */ 992 ){ 993 BtCursor *pCur; 994 int rc; 995 u64 n; 996 char *zBuf; 997 998 if( argc!=2 ){ 999 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1000 " ID\"", 0); 1001 return TCL_ERROR; 1002 } 1003 pCur = sqlite3TextToPtr(argv[1]); 1004 sqlite3BtreeKeySize(pCur, (i64*)&n); 1005 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ 1006 char zBuf2[60]; 1007 sqlite3_snprintf(sizeof(zBuf2),zBuf2, "%llu", n); 1008 Tcl_AppendResult(interp, zBuf2, 0); 1009 }else{ 1010 zBuf = malloc( n+1 ); 1011 rc = sqlite3BtreeKey(pCur, 0, n, zBuf); 1012 if( rc ){ 1013 Tcl_AppendResult(interp, errorName(rc), 0); 1014 return TCL_ERROR; 1015 } 1016 zBuf[n] = 0; 1017 Tcl_AppendResult(interp, zBuf, 0); 1018 free(zBuf); 1019 } 1020 return SQLITE_OK; 1021 } 1022 1023 /* 1024 ** Usage: btree_data ID ?N? 1025 ** 1026 ** Return the data for the entry at which the cursor is pointing. 1027 */ 1028 static int btree_data( 1029 void *NotUsed, 1030 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1031 int argc, /* Number of arguments */ 1032 const char **argv /* Text of each argument */ 1033 ){ 1034 BtCursor *pCur; 1035 int rc; 1036 u32 n; 1037 char *zBuf; 1038 1039 if( argc!=2 && argc!=3 ){ 1040 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1041 " ID\"", 0); 1042 return TCL_ERROR; 1043 } 1044 pCur = sqlite3TextToPtr(argv[1]); 1045 if( argc==2 ){ 1046 sqlite3BtreeDataSize(pCur, &n); 1047 }else{ 1048 n = atoi(argv[2]); 1049 } 1050 zBuf = malloc( n+1 ); 1051 rc = sqlite3BtreeData(pCur, 0, n, zBuf); 1052 if( rc ){ 1053 Tcl_AppendResult(interp, errorName(rc), 0); 1054 free(zBuf); 1055 return TCL_ERROR; 1056 } 1057 zBuf[n] = 0; 1058 Tcl_AppendResult(interp, zBuf, 0); 1059 free(zBuf); 1060 return SQLITE_OK; 1061 } 1062 1063 /* 1064 ** Usage: btree_fetch_key ID AMT 1065 ** 1066 ** Use the sqlite3BtreeKeyFetch() routine to get AMT bytes of the key. 1067 ** If sqlite3BtreeKeyFetch() fails, return an empty string. 1068 */ 1069 static int btree_fetch_key( 1070 void *NotUsed, 1071 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1072 int argc, /* Number of arguments */ 1073 const char **argv /* Text of each argument */ 1074 ){ 1075 BtCursor *pCur; 1076 int n; 1077 int amt; 1078 u64 nKey; 1079 const char *zBuf; 1080 char zStatic[1000]; 1081 1082 if( argc!=3 ){ 1083 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1084 " ID AMT\"", 0); 1085 return TCL_ERROR; 1086 } 1087 pCur = sqlite3TextToPtr(argv[1]); 1088 if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; 1089 sqlite3BtreeKeySize(pCur, (i64*)&nKey); 1090 zBuf = sqlite3BtreeKeyFetch(pCur, &amt); 1091 if( zBuf && amt>=n ){ 1092 assert( nKey<sizeof(zStatic) ); 1093 if( n>0 ) nKey = n; 1094 memcpy(zStatic, zBuf, (int)nKey); 1095 zStatic[nKey] = 0; 1096 Tcl_AppendResult(interp, zStatic, 0); 1097 } 1098 return TCL_OK; 1099 } 1100 1101 /* 1102 ** Usage: btree_fetch_data ID AMT 1103 ** 1104 ** Use the sqlite3BtreeDataFetch() routine to get AMT bytes of the key. 1105 ** If sqlite3BtreeDataFetch() fails, return an empty string. 1106 */ 1107 static int btree_fetch_data( 1108 void *NotUsed, 1109 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1110 int argc, /* Number of arguments */ 1111 const char **argv /* Text of each argument */ 1112 ){ 1113 BtCursor *pCur; 1114 int n; 1115 int amt; 1116 u32 nData; 1117 const char *zBuf; 1118 char zStatic[1000]; 1119 1120 if( argc!=3 ){ 1121 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1122 " ID AMT\"", 0); 1123 return TCL_ERROR; 1124 } 1125 pCur = sqlite3TextToPtr(argv[1]); 1126 if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; 1127 sqlite3BtreeDataSize(pCur, &nData); 1128 zBuf = sqlite3BtreeDataFetch(pCur, &amt); 1129 if( zBuf && amt>=n ){ 1130 assert( nData<sizeof(zStatic) ); 1131 if( n>0 ) nData = n; 1132 memcpy(zStatic, zBuf, (int)nData); 1133 zStatic[nData] = 0; 1134 Tcl_AppendResult(interp, zStatic, 0); 1135 } 1136 return TCL_OK; 1137 } 1138 1139 /* 1140 ** Usage: btree_payload_size ID 1141 ** 1142 ** Return the number of bytes of payload 1143 */ 1144 static int btree_payload_size( 1145 void *NotUsed, 1146 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1147 int argc, /* Number of arguments */ 1148 const char **argv /* Text of each argument */ 1149 ){ 1150 BtCursor *pCur; 1151 int n2; 1152 u64 n1; 1153 char zBuf[50]; 1154 1155 if( argc!=2 ){ 1156 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1157 " ID\"", 0); 1158 return TCL_ERROR; 1159 } 1160 pCur = sqlite3TextToPtr(argv[1]); 1161 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ 1162 n1 = 0; 1163 }else{ 1164 sqlite3BtreeKeySize(pCur, (i64*)&n1); 1165 } 1166 sqlite3BtreeDataSize(pCur, (u32*)&n2); 1167 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2)); 1168 Tcl_AppendResult(interp, zBuf, 0); 1169 return SQLITE_OK; 1170 } 1171 1172 /* 1173 ** Usage: btree_cursor_info ID ?UP-CNT? 1174 ** 1175 ** Return integers containing information about the entry the 1176 ** cursor is pointing to: 1177 ** 1178 ** aResult[0] = The page number 1179 ** aResult[1] = The entry number 1180 ** aResult[2] = Total number of entries on this page 1181 ** aResult[3] = Cell size (local payload + header) 1182 ** aResult[4] = Number of free bytes on this page 1183 ** aResult[5] = Number of free blocks on the page 1184 ** aResult[6] = Total payload size (local + overflow) 1185 ** aResult[7] = Header size in bytes 1186 ** aResult[8] = Local payload size 1187 ** aResult[9] = Parent page number 1188 */ 1189 static int btree_cursor_info( 1190 void *NotUsed, 1191 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1192 int argc, /* Number of arguments */ 1193 const char **argv /* Text of each argument */ 1194 ){ 1195 BtCursor *pCur; 1196 int rc; 1197 int i, j; 1198 int up; 1199 int aResult[10]; 1200 char zBuf[400]; 1201 1202 if( argc!=2 && argc!=3 ){ 1203 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1204 " ID ?UP-CNT?\"", 0); 1205 return TCL_ERROR; 1206 } 1207 pCur = sqlite3TextToPtr(argv[1]); 1208 if( argc==3 ){ 1209 if( Tcl_GetInt(interp, argv[2], &up) ) return TCL_ERROR; 1210 }else{ 1211 up = 0; 1212 } 1213 rc = sqlite3BtreeCursorInfo(pCur, aResult, up); 1214 if( rc ){ 1215 Tcl_AppendResult(interp, errorName(rc), 0); 1216 return TCL_ERROR; 1217 } 1218 j = 0; 1219 for(i=0; i<sizeof(aResult)/sizeof(aResult[0]); i++){ 1220 sqlite3_snprintf(40,&zBuf[j]," %d", aResult[i]); 1221 j += strlen(&zBuf[j]); 1222 } 1223 Tcl_AppendResult(interp, &zBuf[1], 0); 1224 return SQLITE_OK; 1225 } 1226 1227 /* 1228 ** The command is provided for the purpose of setting breakpoints. 1229 ** in regression test scripts. 1230 ** 1231 ** By setting a GDB breakpoint on this procedure and executing the 1232 ** btree_breakpoint command in a test script, we can stop GDB at 1233 ** the point in the script where the btree_breakpoint command is 1234 ** inserted. This is useful for debugging. 1235 */ 1236 static int btree_breakpoint( 1237 void *NotUsed, 1238 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1239 int argc, /* Number of arguments */ 1240 const char **argv /* Text of each argument */ 1241 ){ 1242 return TCL_OK; 1243 } 1244 1245 /* 1246 ** usage: varint_test START MULTIPLIER COUNT INCREMENT 1247 ** 1248 ** This command tests the sqlite3PutVarint() and sqlite3GetVarint() 1249 ** routines, both for accuracy and for speed. 1250 ** 1251 ** An integer is written using PutVarint() and read back with 1252 ** GetVarint() and varified to be unchanged. This repeats COUNT 1253 ** times. The first integer is START*MULTIPLIER. Each iteration 1254 ** increases the integer by INCREMENT. 1255 ** 1256 ** This command returns nothing if it works. It returns an error message 1257 ** if something goes wrong. 1258 */ 1259 static int btree_varint_test( 1260 void *NotUsed, 1261 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1262 int argc, /* Number of arguments */ 1263 const char **argv /* Text of each argument */ 1264 ){ 1265 u32 start, mult, count, incr; 1266 u64 in, out; 1267 int n1, n2, i, j; 1268 unsigned char zBuf[100]; 1269 if( argc!=5 ){ 1270 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1271 " START MULTIPLIER COUNT INCREMENT\"", 0); 1272 return TCL_ERROR; 1273 } 1274 if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR; 1275 if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR; 1276 if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR; 1277 if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR; 1278 in = start; 1279 in *= mult; 1280 for(i=0; i<count; i++){ 1281 char zErr[200]; 1282 n1 = sqlite3PutVarint(zBuf, in); 1283 if( n1>9 || n1<1 ){ 1284 sprintf(zErr, "PutVarint returned %d - should be between 1 and 9", n1); 1285 Tcl_AppendResult(interp, zErr, 0); 1286 return TCL_ERROR; 1287 } 1288 n2 = sqlite3GetVarint(zBuf, &out); 1289 if( n1!=n2 ){ 1290 sprintf(zErr, "PutVarint returned %d and GetVarint returned %d", n1, n2); 1291 Tcl_AppendResult(interp, zErr, 0); 1292 return TCL_ERROR; 1293 } 1294 if( in!=out ){ 1295 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out); 1296 Tcl_AppendResult(interp, zErr, 0); 1297 return TCL_ERROR; 1298 } 1299 if( (in & 0xffffffff)==in ){ 1300 u32 out32; 1301 n2 = sqlite3GetVarint32(zBuf, &out32); 1302 out = out32; 1303 if( n1!=n2 ){ 1304 sprintf(zErr, "PutVarint returned %d and GetVarint32 returned %d", 1305 n1, n2); 1306 Tcl_AppendResult(interp, zErr, 0); 1307 return TCL_ERROR; 1308 } 1309 if( in!=out ){ 1310 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32", 1311 in, out); 1312 Tcl_AppendResult(interp, zErr, 0); 1313 return TCL_ERROR; 1314 } 1315 } 1316 1317 /* In order to get realistic timings, run getVarint 19 more times. 1318 ** This is because getVarint is called about 20 times more often 1319 ** than putVarint. 1320 */ 1321 for(j=0; j<19; j++){ 1322 sqlite3GetVarint(zBuf, &out); 1323 } 1324 in += incr; 1325 } 1326 return TCL_OK; 1327 } 1328 1329 /* 1330 ** usage: btree_from_db DB-HANDLE 1331 ** 1332 ** This command returns the btree handle for the main database associated 1333 ** with the database-handle passed as the argument. Example usage: 1334 ** 1335 ** sqlite3 db test.db 1336 ** set bt [btree_from_db db] 1337 */ 1338 static int btree_from_db( 1339 void *NotUsed, 1340 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1341 int argc, /* Number of arguments */ 1342 const char **argv /* Text of each argument */ 1343 ){ 1344 char zBuf[100]; 1345 Tcl_CmdInfo info; 1346 sqlite3 *db; 1347 Btree *pBt; 1348 1349 if( argc!=2 ){ 1350 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1351 " DB-HANDLE\"", 0); 1352 return TCL_ERROR; 1353 } 1354 1355 if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){ 1356 Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0); 1357 return TCL_ERROR; 1358 } 1359 db = *((sqlite3 **)info.objClientData); 1360 assert( db ); 1361 1362 pBt = db->aDb[0].pBt; 1363 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt); 1364 Tcl_SetResult(interp, zBuf, TCL_VOLATILE); 1365 return TCL_OK; 1366 } 1367 1368 1369 /* 1370 ** usage: btree_set_cache_size ID NCACHE 1371 ** 1372 ** Set the size of the cache used by btree $ID. 1373 */ 1374 static int btree_set_cache_size( 1375 void *NotUsed, 1376 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1377 int argc, /* Number of arguments */ 1378 const char **argv /* Text of each argument */ 1379 ){ 1380 int nCache; 1381 Btree *pBt; 1382 1383 if( argc!=3 ){ 1384 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1385 " BT NCACHE\"", 0); 1386 return TCL_ERROR; 1387 } 1388 pBt = sqlite3TextToPtr(argv[1]); 1389 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; 1390 sqlite3BtreeSetCacheSize(pBt, nCache); 1391 return TCL_OK; 1392 } 1393 1394 1395 /* 1396 ** Register commands with the TCL interpreter. 1397 */ 1398 int Sqlitetest3_Init(Tcl_Interp *interp){ 1399 extern int sqlite3_btree_trace; 1400 static struct { 1401 char *zName; 1402 Tcl_CmdProc *xProc; 1403 } aCmd[] = { 1404 { "btree_open", (Tcl_CmdProc*)btree_open }, 1405 { "btree_close", (Tcl_CmdProc*)btree_close }, 1406 { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction }, 1407 { "btree_commit", (Tcl_CmdProc*)btree_commit }, 1408 { "btree_rollback", (Tcl_CmdProc*)btree_rollback }, 1409 { "btree_create_table", (Tcl_CmdProc*)btree_create_table }, 1410 { "btree_drop_table", (Tcl_CmdProc*)btree_drop_table }, 1411 { "btree_clear_table", (Tcl_CmdProc*)btree_clear_table }, 1412 { "btree_get_meta", (Tcl_CmdProc*)btree_get_meta }, 1413 { "btree_update_meta", (Tcl_CmdProc*)btree_update_meta }, 1414 { "btree_page_dump", (Tcl_CmdProc*)btree_page_dump }, 1415 { "btree_tree_dump", (Tcl_CmdProc*)btree_tree_dump }, 1416 { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats }, 1417 { "btree_pager_ref_dump", (Tcl_CmdProc*)btree_pager_ref_dump }, 1418 { "btree_cursor", (Tcl_CmdProc*)btree_cursor }, 1419 { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor }, 1420 { "btree_move_to", (Tcl_CmdProc*)btree_move_to }, 1421 { "btree_delete", (Tcl_CmdProc*)btree_delete }, 1422 { "btree_next", (Tcl_CmdProc*)btree_next }, 1423 { "btree_prev", (Tcl_CmdProc*)btree_prev }, 1424 { "btree_eof", (Tcl_CmdProc*)btree_eof }, 1425 { "btree_keysize", (Tcl_CmdProc*)btree_keysize }, 1426 { "btree_key", (Tcl_CmdProc*)btree_key }, 1427 { "btree_data", (Tcl_CmdProc*)btree_data }, 1428 { "btree_fetch_key", (Tcl_CmdProc*)btree_fetch_key }, 1429 { "btree_fetch_data", (Tcl_CmdProc*)btree_fetch_data }, 1430 { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size }, 1431 { "btree_first", (Tcl_CmdProc*)btree_first }, 1432 { "btree_last", (Tcl_CmdProc*)btree_last }, 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 { "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info }, 1442 { "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list }, 1443 }; 1444 int i; 1445 1446 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 1447 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 1448 } 1449 Tcl_LinkVar(interp, "pager_refinfo_enable", (char*)&pager3_refinfo_enable, 1450 TCL_LINK_INT); 1451 Tcl_LinkVar(interp, "btree_trace", (char*)&sqlite3_btree_trace, 1452 TCL_LINK_INT); 1453 1454 /* The btree_insert command is implemented using the tcl 'object' 1455 ** interface, not the string interface like the other commands in this 1456 ** file. This is so binary data can be inserted into btree tables. 1457 */ 1458 Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0); 1459 return TCL_OK; 1460 } 1461