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.61 2005/01/21 08:13:15 danielk1977 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_INTERNAL: zName = "SQLITE_INTERNAL"; break; 34 case SQLITE_PERM: zName = "SQLITE_PERM"; break; 35 case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; 36 case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; 37 case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; 38 case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; 39 case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; 40 case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; 41 case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; 42 case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break; 43 case SQLITE_FULL: zName = "SQLITE_FULL"; break; 44 case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; 45 case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; 46 case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; 47 case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; 48 default: zName = "SQLITE_Unknown"; break; 49 } 50 return zName; 51 } 52 53 /* 54 ** Usage: btree_open FILENAME NCACHE FLAGS 55 ** 56 ** Open a new database 57 */ 58 static int btree_open( 59 void *NotUsed, 60 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 61 int argc, /* Number of arguments */ 62 const char **argv /* Text of each argument */ 63 ){ 64 Btree *pBt; 65 int rc, nCache, flags; 66 char zBuf[100]; 67 if( argc!=4 ){ 68 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 69 " FILENAME NCACHE FLAGS\"", 0); 70 return TCL_ERROR; 71 } 72 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; 73 if( Tcl_GetInt(interp, argv[3], &flags) ) return TCL_ERROR; 74 rc = sqlite3BtreeOpen(argv[1], &pBt, flags); 75 if( rc!=SQLITE_OK ){ 76 Tcl_AppendResult(interp, errorName(rc), 0); 77 return TCL_ERROR; 78 } 79 sqlite3BtreeSetCacheSize(pBt, nCache); 80 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt); 81 Tcl_AppendResult(interp, zBuf, 0); 82 return TCL_OK; 83 } 84 85 /* 86 ** Usage: btree_close ID 87 ** 88 ** Close the given database. 89 */ 90 static int btree_close( 91 void *NotUsed, 92 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 93 int argc, /* Number of arguments */ 94 const char **argv /* Text of each argument */ 95 ){ 96 Btree *pBt; 97 int rc; 98 if( argc!=2 ){ 99 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 100 " ID\"", 0); 101 return TCL_ERROR; 102 } 103 pBt = sqlite3TextToPtr(argv[1]); 104 rc = sqlite3BtreeClose(pBt); 105 if( rc!=SQLITE_OK ){ 106 Tcl_AppendResult(interp, errorName(rc), 0); 107 return TCL_ERROR; 108 } 109 return TCL_OK; 110 } 111 112 /* 113 ** Usage: btree_begin_transaction ID 114 ** 115 ** Start a new transaction 116 */ 117 static int btree_begin_transaction( 118 void *NotUsed, 119 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 120 int argc, /* Number of arguments */ 121 const char **argv /* Text of each argument */ 122 ){ 123 Btree *pBt; 124 int rc; 125 if( argc!=2 ){ 126 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 127 " ID\"", 0); 128 return TCL_ERROR; 129 } 130 pBt = sqlite3TextToPtr(argv[1]); 131 rc = sqlite3BtreeBeginTrans(pBt, 1); 132 if( rc!=SQLITE_OK ){ 133 Tcl_AppendResult(interp, errorName(rc), 0); 134 return TCL_ERROR; 135 } 136 return TCL_OK; 137 } 138 139 /* 140 ** Usage: btree_rollback ID 141 ** 142 ** Rollback changes 143 */ 144 static int btree_rollback( 145 void *NotUsed, 146 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 147 int argc, /* Number of arguments */ 148 const char **argv /* Text of each argument */ 149 ){ 150 Btree *pBt; 151 int rc; 152 if( argc!=2 ){ 153 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 154 " ID\"", 0); 155 return TCL_ERROR; 156 } 157 pBt = sqlite3TextToPtr(argv[1]); 158 rc = sqlite3BtreeRollback(pBt); 159 if( rc!=SQLITE_OK ){ 160 Tcl_AppendResult(interp, errorName(rc), 0); 161 return TCL_ERROR; 162 } 163 return TCL_OK; 164 } 165 166 /* 167 ** Usage: btree_commit ID 168 ** 169 ** Commit all changes 170 */ 171 static int btree_commit( 172 void *NotUsed, 173 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 174 int argc, /* Number of arguments */ 175 const char **argv /* Text of each argument */ 176 ){ 177 Btree *pBt; 178 int rc; 179 if( argc!=2 ){ 180 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 181 " ID\"", 0); 182 return TCL_ERROR; 183 } 184 pBt = sqlite3TextToPtr(argv[1]); 185 rc = sqlite3BtreeCommit(pBt); 186 if( rc!=SQLITE_OK ){ 187 Tcl_AppendResult(interp, errorName(rc), 0); 188 return TCL_ERROR; 189 } 190 return TCL_OK; 191 } 192 193 /* 194 ** Usage: btree_begin_statement ID 195 ** 196 ** Start a new statement transaction 197 */ 198 static int btree_begin_statement( 199 void *NotUsed, 200 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 201 int argc, /* Number of arguments */ 202 const char **argv /* Text of each argument */ 203 ){ 204 Btree *pBt; 205 int rc; 206 if( argc!=2 ){ 207 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 208 " ID\"", 0); 209 return TCL_ERROR; 210 } 211 pBt = sqlite3TextToPtr(argv[1]); 212 rc = sqlite3BtreeBeginStmt(pBt); 213 if( rc!=SQLITE_OK ){ 214 Tcl_AppendResult(interp, errorName(rc), 0); 215 return TCL_ERROR; 216 } 217 return TCL_OK; 218 } 219 220 /* 221 ** Usage: btree_rollback_statement ID 222 ** 223 ** Rollback changes 224 */ 225 static int btree_rollback_statement( 226 void *NotUsed, 227 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 228 int argc, /* Number of arguments */ 229 const char **argv /* Text of each argument */ 230 ){ 231 Btree *pBt; 232 int rc; 233 if( argc!=2 ){ 234 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 235 " ID\"", 0); 236 return TCL_ERROR; 237 } 238 pBt = sqlite3TextToPtr(argv[1]); 239 rc = sqlite3BtreeRollbackStmt(pBt); 240 if( rc!=SQLITE_OK ){ 241 Tcl_AppendResult(interp, errorName(rc), 0); 242 return TCL_ERROR; 243 } 244 return TCL_OK; 245 } 246 247 /* 248 ** Usage: btree_commit_statement ID 249 ** 250 ** Commit all changes 251 */ 252 static int btree_commit_statement( 253 void *NotUsed, 254 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 255 int argc, /* Number of arguments */ 256 const char **argv /* Text of each argument */ 257 ){ 258 Btree *pBt; 259 int rc; 260 if( argc!=2 ){ 261 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 262 " ID\"", 0); 263 return TCL_ERROR; 264 } 265 pBt = sqlite3TextToPtr(argv[1]); 266 rc = sqlite3BtreeCommitStmt(pBt); 267 if( rc!=SQLITE_OK ){ 268 Tcl_AppendResult(interp, errorName(rc), 0); 269 return TCL_ERROR; 270 } 271 return TCL_OK; 272 } 273 274 /* 275 ** Usage: btree_create_table ID FLAGS 276 ** 277 ** Create a new table in the database 278 */ 279 static int btree_create_table( 280 void *NotUsed, 281 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 282 int argc, /* Number of arguments */ 283 const char **argv /* Text of each argument */ 284 ){ 285 Btree *pBt; 286 int rc, iTable, flags; 287 char zBuf[30]; 288 if( argc!=3 ){ 289 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 290 " ID FLAGS\"", 0); 291 return TCL_ERROR; 292 } 293 pBt = sqlite3TextToPtr(argv[1]); 294 if( Tcl_GetInt(interp, argv[2], &flags) ) return TCL_ERROR; 295 rc = sqlite3BtreeCreateTable(pBt, &iTable, flags); 296 if( rc!=SQLITE_OK ){ 297 Tcl_AppendResult(interp, errorName(rc), 0); 298 return TCL_ERROR; 299 } 300 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", iTable); 301 Tcl_AppendResult(interp, zBuf, 0); 302 return TCL_OK; 303 } 304 305 /* 306 ** Usage: btree_drop_table ID TABLENUM 307 ** 308 ** Delete an entire table from the database 309 */ 310 static int btree_drop_table( 311 void *NotUsed, 312 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 313 int argc, /* Number of arguments */ 314 const char **argv /* Text of each argument */ 315 ){ 316 Btree *pBt; 317 int iTable; 318 int rc; 319 int notUsed1; 320 if( argc!=3 ){ 321 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 322 " ID TABLENUM\"", 0); 323 return TCL_ERROR; 324 } 325 pBt = sqlite3TextToPtr(argv[1]); 326 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; 327 rc = sqlite3BtreeDropTable(pBt, iTable, ¬Used1); 328 if( rc!=SQLITE_OK ){ 329 Tcl_AppendResult(interp, errorName(rc), 0); 330 return TCL_ERROR; 331 } 332 return TCL_OK; 333 } 334 335 /* 336 ** Usage: btree_clear_table ID TABLENUM 337 ** 338 ** Remove all entries from the given table but keep the table around. 339 */ 340 static int btree_clear_table( 341 void *NotUsed, 342 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 343 int argc, /* Number of arguments */ 344 const char **argv /* Text of each argument */ 345 ){ 346 Btree *pBt; 347 int iTable; 348 int rc; 349 if( argc!=3 ){ 350 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 351 " ID TABLENUM\"", 0); 352 return TCL_ERROR; 353 } 354 pBt = sqlite3TextToPtr(argv[1]); 355 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; 356 rc = sqlite3BtreeClearTable(pBt, iTable); 357 if( rc!=SQLITE_OK ){ 358 Tcl_AppendResult(interp, errorName(rc), 0); 359 return TCL_ERROR; 360 } 361 return TCL_OK; 362 } 363 364 /* 365 ** Usage: btree_get_meta ID 366 ** 367 ** Return meta data 368 */ 369 static int btree_get_meta( 370 void *NotUsed, 371 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 372 int argc, /* Number of arguments */ 373 const char **argv /* Text of each argument */ 374 ){ 375 Btree *pBt; 376 int rc; 377 int i; 378 if( argc!=2 ){ 379 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 380 " ID\"", 0); 381 return TCL_ERROR; 382 } 383 pBt = sqlite3TextToPtr(argv[1]); 384 for(i=0; i<SQLITE_N_BTREE_META; i++){ 385 char zBuf[30]; 386 unsigned int v; 387 rc = sqlite3BtreeGetMeta(pBt, i, &v); 388 if( rc!=SQLITE_OK ){ 389 Tcl_AppendResult(interp, errorName(rc), 0); 390 return TCL_ERROR; 391 } 392 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",v); 393 Tcl_AppendElement(interp, zBuf); 394 } 395 return TCL_OK; 396 } 397 398 /* 399 ** Usage: btree_update_meta ID METADATA... 400 ** 401 ** Return meta data 402 */ 403 static int btree_update_meta( 404 void *NotUsed, 405 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 406 int argc, /* Number of arguments */ 407 const char **argv /* Text of each argument */ 408 ){ 409 Btree *pBt; 410 int rc; 411 int i; 412 int aMeta[SQLITE_N_BTREE_META]; 413 414 if( argc!=2+SQLITE_N_BTREE_META ){ 415 char zBuf[30]; 416 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",SQLITE_N_BTREE_META); 417 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 418 " ID METADATA...\" (METADATA is ", zBuf, " integers)", 0); 419 return TCL_ERROR; 420 } 421 pBt = sqlite3TextToPtr(argv[1]); 422 for(i=1; i<SQLITE_N_BTREE_META; i++){ 423 if( Tcl_GetInt(interp, argv[i+2], &aMeta[i]) ) return TCL_ERROR; 424 } 425 for(i=1; i<SQLITE_N_BTREE_META; i++){ 426 rc = sqlite3BtreeUpdateMeta(pBt, i, aMeta[i]); 427 if( rc!=SQLITE_OK ){ 428 Tcl_AppendResult(interp, errorName(rc), 0); 429 return TCL_ERROR; 430 } 431 } 432 return TCL_OK; 433 } 434 435 /* 436 ** Usage: btree_page_dump ID PAGENUM 437 ** 438 ** Print a disassembly of a page on standard output 439 */ 440 static int btree_page_dump( 441 void *NotUsed, 442 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 443 int argc, /* Number of arguments */ 444 const char **argv /* Text of each argument */ 445 ){ 446 Btree *pBt; 447 int iPage; 448 int rc; 449 450 if( argc!=3 ){ 451 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 452 " ID\"", 0); 453 return TCL_ERROR; 454 } 455 pBt = sqlite3TextToPtr(argv[1]); 456 if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR; 457 rc = sqlite3BtreePageDump(pBt, iPage, 0); 458 if( rc!=SQLITE_OK ){ 459 Tcl_AppendResult(interp, errorName(rc), 0); 460 return TCL_ERROR; 461 } 462 return TCL_OK; 463 } 464 465 /* 466 ** Usage: btree_tree_dump ID PAGENUM 467 ** 468 ** Print a disassembly of a page and all its child pages on standard output 469 */ 470 static int btree_tree_dump( 471 void *NotUsed, 472 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 473 int argc, /* Number of arguments */ 474 const char **argv /* Text of each argument */ 475 ){ 476 Btree *pBt; 477 int iPage; 478 int rc; 479 480 if( argc!=3 ){ 481 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 482 " ID\"", 0); 483 return TCL_ERROR; 484 } 485 pBt = sqlite3TextToPtr(argv[1]); 486 if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR; 487 rc = sqlite3BtreePageDump(pBt, iPage, 1); 488 if( rc!=SQLITE_OK ){ 489 Tcl_AppendResult(interp, errorName(rc), 0); 490 return TCL_ERROR; 491 } 492 return TCL_OK; 493 } 494 495 /* 496 ** Usage: btree_pager_stats ID 497 ** 498 ** Returns pager statistics 499 */ 500 static int btree_pager_stats( 501 void *NotUsed, 502 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 503 int argc, /* Number of arguments */ 504 const char **argv /* Text of each argument */ 505 ){ 506 Btree *pBt; 507 int i; 508 int *a; 509 510 if( argc!=2 ){ 511 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 512 " ID\"", 0); 513 return TCL_ERROR; 514 } 515 pBt = sqlite3TextToPtr(argv[1]); 516 a = sqlite3pager_stats(sqlite3BtreePager(pBt)); 517 for(i=0; i<11; i++){ 518 static char *zName[] = { 519 "ref", "page", "max", "size", "state", "err", 520 "hit", "miss", "ovfl", "read", "write" 521 }; 522 char zBuf[100]; 523 Tcl_AppendElement(interp, zName[i]); 524 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]); 525 Tcl_AppendElement(interp, zBuf); 526 } 527 return TCL_OK; 528 } 529 530 /* 531 ** Usage: btree_pager_ref_dump ID 532 ** 533 ** Print out all outstanding pages. 534 */ 535 static int btree_pager_ref_dump( 536 void *NotUsed, 537 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 538 int argc, /* Number of arguments */ 539 const char **argv /* Text of each argument */ 540 ){ 541 Btree *pBt; 542 543 if( argc!=2 ){ 544 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 545 " ID\"", 0); 546 return TCL_ERROR; 547 } 548 pBt = sqlite3TextToPtr(argv[1]); 549 #ifdef SQLITE_DEBUG 550 sqlite3pager_refdump(sqlite3BtreePager(pBt)); 551 #endif 552 return TCL_OK; 553 } 554 555 /* 556 ** Usage: btree_integrity_check ID ROOT ... 557 ** 558 ** Look through every page of the given BTree file to verify correct 559 ** formatting and linkage. Return a line of text for each problem found. 560 ** Return an empty string if everything worked. 561 */ 562 static int btree_integrity_check( 563 void *NotUsed, 564 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 565 int argc, /* Number of arguments */ 566 const char **argv /* Text of each argument */ 567 ){ 568 Btree *pBt; 569 int nRoot; 570 int *aRoot; 571 int i; 572 char *zResult; 573 574 if( argc<3 ){ 575 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 576 " ID ROOT ...\"", 0); 577 return TCL_ERROR; 578 } 579 pBt = sqlite3TextToPtr(argv[1]); 580 nRoot = argc-2; 581 aRoot = malloc( sizeof(int)*(argc-2) ); 582 for(i=0; i<argc-2; i++){ 583 if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR; 584 } 585 #ifndef SQLITE_OMIT_INTEGRITY_CHECK 586 zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot); 587 #else 588 zResult = 0; 589 #endif 590 if( zResult ){ 591 Tcl_AppendResult(interp, zResult, 0); 592 sqliteFree(zResult); 593 } 594 return TCL_OK; 595 } 596 597 /* 598 ** Usage: btree_cursor_list ID 599 ** 600 ** Print information about all cursors to standard output for debugging. 601 */ 602 static int btree_cursor_list( 603 void *NotUsed, 604 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 605 int argc, /* Number of arguments */ 606 const char **argv /* Text of each argument */ 607 ){ 608 Btree *pBt; 609 610 if( argc!=2 ){ 611 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 612 " ID\"", 0); 613 return TCL_ERROR; 614 } 615 pBt = sqlite3TextToPtr(argv[1]); 616 sqlite3BtreeCursorList(pBt); 617 return SQLITE_OK; 618 } 619 620 /* 621 ** Usage: btree_cursor ID TABLENUM WRITEABLE 622 ** 623 ** Create a new cursor. Return the ID for the cursor. 624 */ 625 static int btree_cursor( 626 void *NotUsed, 627 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 628 int argc, /* Number of arguments */ 629 const char **argv /* Text of each argument */ 630 ){ 631 Btree *pBt; 632 int iTable; 633 BtCursor *pCur; 634 int rc; 635 int wrFlag; 636 char zBuf[30]; 637 638 if( argc!=4 ){ 639 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 640 " ID TABLENUM WRITEABLE\"", 0); 641 return TCL_ERROR; 642 } 643 pBt = sqlite3TextToPtr(argv[1]); 644 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; 645 if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR; 646 rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, 0, &pCur); 647 if( rc ){ 648 Tcl_AppendResult(interp, errorName(rc), 0); 649 return TCL_ERROR; 650 } 651 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur); 652 Tcl_AppendResult(interp, zBuf, 0); 653 return SQLITE_OK; 654 } 655 656 /* 657 ** Usage: btree_close_cursor ID 658 ** 659 ** Close a cursor opened using btree_cursor. 660 */ 661 static int btree_close_cursor( 662 void *NotUsed, 663 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 664 int argc, /* Number of arguments */ 665 const char **argv /* Text of each argument */ 666 ){ 667 BtCursor *pCur; 668 int rc; 669 670 if( argc!=2 ){ 671 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 672 " ID\"", 0); 673 return TCL_ERROR; 674 } 675 pCur = sqlite3TextToPtr(argv[1]); 676 rc = sqlite3BtreeCloseCursor(pCur); 677 if( rc ){ 678 Tcl_AppendResult(interp, errorName(rc), 0); 679 return TCL_ERROR; 680 } 681 return SQLITE_OK; 682 } 683 684 /* 685 ** Usage: btree_move_to ID KEY 686 ** 687 ** Move the cursor to the entry with the given key. 688 */ 689 static int btree_move_to( 690 void *NotUsed, 691 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 692 int argc, /* Number of arguments */ 693 const char **argv /* Text of each argument */ 694 ){ 695 BtCursor *pCur; 696 int rc; 697 int res; 698 char zBuf[20]; 699 700 if( argc!=3 ){ 701 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 702 " ID KEY\"", 0); 703 return TCL_ERROR; 704 } 705 pCur = sqlite3TextToPtr(argv[1]); 706 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ 707 int iKey; 708 if( Tcl_GetInt(interp, argv[2], &iKey) ) return TCL_ERROR; 709 rc = sqlite3BtreeMoveto(pCur, 0, iKey, &res); 710 }else{ 711 rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), &res); 712 } 713 if( rc ){ 714 Tcl_AppendResult(interp, errorName(rc), 0); 715 return TCL_ERROR; 716 } 717 if( res<0 ) res = -1; 718 if( res>0 ) res = 1; 719 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",res); 720 Tcl_AppendResult(interp, zBuf, 0); 721 return SQLITE_OK; 722 } 723 724 /* 725 ** Usage: btree_delete ID 726 ** 727 ** Delete the entry that the cursor is pointing to 728 */ 729 static int btree_delete( 730 void *NotUsed, 731 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 732 int argc, /* Number of arguments */ 733 const char **argv /* Text of each argument */ 734 ){ 735 BtCursor *pCur; 736 int rc; 737 738 if( argc!=2 ){ 739 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 740 " ID\"", 0); 741 return TCL_ERROR; 742 } 743 pCur = sqlite3TextToPtr(argv[1]); 744 rc = sqlite3BtreeDelete(pCur); 745 if( rc ){ 746 Tcl_AppendResult(interp, errorName(rc), 0); 747 return TCL_ERROR; 748 } 749 return SQLITE_OK; 750 } 751 752 /* 753 ** Usage: btree_insert ID KEY DATA 754 ** 755 ** Create a new entry with the given key and data. If an entry already 756 ** exists with the same key the old entry is overwritten. 757 */ 758 static int btree_insert( 759 void * clientData, 760 Tcl_Interp *interp, 761 int objc, 762 Tcl_Obj *CONST objv[] 763 ){ 764 BtCursor *pCur; 765 int rc; 766 767 if( objc!=4 ){ 768 Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA"); 769 return TCL_ERROR; 770 } 771 pCur = sqlite3TextToPtr(Tcl_GetString(objv[1])); 772 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ 773 i64 iKey; 774 int len; 775 unsigned char *pBuf; 776 if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ) return TCL_ERROR; 777 pBuf = Tcl_GetByteArrayFromObj(objv[3], &len); 778 rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len); 779 }else{ 780 int keylen; 781 int dlen; 782 unsigned char *pKBuf; 783 unsigned char *pDBuf; 784 pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen); 785 pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen); 786 rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen); 787 } 788 if( rc ){ 789 Tcl_AppendResult(interp, errorName(rc), 0); 790 return TCL_ERROR; 791 } 792 return SQLITE_OK; 793 } 794 795 /* 796 ** Usage: btree_next ID 797 ** 798 ** Move the cursor to the next entry in the table. Return 0 on success 799 ** or 1 if the cursor was already on the last entry in the table or if 800 ** the table is empty. 801 */ 802 static int btree_next( 803 void *NotUsed, 804 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 805 int argc, /* Number of arguments */ 806 const char **argv /* Text of each argument */ 807 ){ 808 BtCursor *pCur; 809 int rc; 810 int res = 0; 811 char zBuf[100]; 812 813 if( argc!=2 ){ 814 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 815 " ID\"", 0); 816 return TCL_ERROR; 817 } 818 pCur = sqlite3TextToPtr(argv[1]); 819 rc = sqlite3BtreeNext(pCur, &res); 820 if( rc ){ 821 Tcl_AppendResult(interp, errorName(rc), 0); 822 return TCL_ERROR; 823 } 824 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 825 Tcl_AppendResult(interp, zBuf, 0); 826 return SQLITE_OK; 827 } 828 829 /* 830 ** Usage: btree_prev ID 831 ** 832 ** Move the cursor to the previous entry in the table. Return 0 on 833 ** success and 1 if the cursor was already on the first entry in 834 ** the table or if the table was empty. 835 */ 836 static int btree_prev( 837 void *NotUsed, 838 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 839 int argc, /* Number of arguments */ 840 const char **argv /* Text of each argument */ 841 ){ 842 BtCursor *pCur; 843 int rc; 844 int res = 0; 845 char zBuf[100]; 846 847 if( argc!=2 ){ 848 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 849 " ID\"", 0); 850 return TCL_ERROR; 851 } 852 pCur = sqlite3TextToPtr(argv[1]); 853 rc = sqlite3BtreePrevious(pCur, &res); 854 if( rc ){ 855 Tcl_AppendResult(interp, errorName(rc), 0); 856 return TCL_ERROR; 857 } 858 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 859 Tcl_AppendResult(interp, zBuf, 0); 860 return SQLITE_OK; 861 } 862 863 /* 864 ** Usage: btree_first ID 865 ** 866 ** Move the cursor to the first entry in the table. Return 0 if the 867 ** cursor was left point to something and 1 if the table is empty. 868 */ 869 static int btree_first( 870 void *NotUsed, 871 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 872 int argc, /* Number of arguments */ 873 const char **argv /* Text of each argument */ 874 ){ 875 BtCursor *pCur; 876 int rc; 877 int res = 0; 878 char zBuf[100]; 879 880 if( argc!=2 ){ 881 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 882 " ID\"", 0); 883 return TCL_ERROR; 884 } 885 pCur = sqlite3TextToPtr(argv[1]); 886 rc = sqlite3BtreeFirst(pCur, &res); 887 if( rc ){ 888 Tcl_AppendResult(interp, errorName(rc), 0); 889 return TCL_ERROR; 890 } 891 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 892 Tcl_AppendResult(interp, zBuf, 0); 893 return SQLITE_OK; 894 } 895 896 /* 897 ** Usage: btree_last ID 898 ** 899 ** Move the cursor to the last entry in the table. Return 0 if the 900 ** cursor was left point to something and 1 if the table is empty. 901 */ 902 static int btree_last( 903 void *NotUsed, 904 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 905 int argc, /* Number of arguments */ 906 const char **argv /* Text of each argument */ 907 ){ 908 BtCursor *pCur; 909 int rc; 910 int res = 0; 911 char zBuf[100]; 912 913 if( argc!=2 ){ 914 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 915 " ID\"", 0); 916 return TCL_ERROR; 917 } 918 pCur = sqlite3TextToPtr(argv[1]); 919 rc = sqlite3BtreeLast(pCur, &res); 920 if( rc ){ 921 Tcl_AppendResult(interp, errorName(rc), 0); 922 return TCL_ERROR; 923 } 924 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 925 Tcl_AppendResult(interp, zBuf, 0); 926 return SQLITE_OK; 927 } 928 929 /* 930 ** Usage: btree_eof ID 931 ** 932 ** Return TRUE if the given cursor is not pointing at a valid entry. 933 ** Return FALSE if the cursor does point to a valid entry. 934 */ 935 static int btree_eof( 936 void *NotUsed, 937 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 938 int argc, /* Number of arguments */ 939 const char **argv /* Text of each argument */ 940 ){ 941 BtCursor *pCur; 942 char zBuf[50]; 943 944 if( argc!=2 ){ 945 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 946 " ID\"", 0); 947 return TCL_ERROR; 948 } 949 pCur = sqlite3TextToPtr(argv[1]); 950 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", sqlite3BtreeEof(pCur)); 951 Tcl_AppendResult(interp, zBuf, 0); 952 return SQLITE_OK; 953 } 954 955 /* 956 ** Usage: btree_keysize ID 957 ** 958 ** Return the number of bytes of key. For an INTKEY table, this 959 ** returns the key itself. 960 */ 961 static int btree_keysize( 962 void *NotUsed, 963 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 964 int argc, /* Number of arguments */ 965 const char **argv /* Text of each argument */ 966 ){ 967 BtCursor *pCur; 968 u64 n; 969 char zBuf[50]; 970 971 if( argc!=2 ){ 972 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 973 " ID\"", 0); 974 return TCL_ERROR; 975 } 976 pCur = sqlite3TextToPtr(argv[1]); 977 sqlite3BtreeKeySize(pCur, &n); 978 sqlite3_snprintf(sizeof(zBuf),zBuf, "%llu", n); 979 Tcl_AppendResult(interp, zBuf, 0); 980 return SQLITE_OK; 981 } 982 983 /* 984 ** Usage: btree_key ID 985 ** 986 ** Return the key for the entry at which the cursor is pointing. 987 */ 988 static int btree_key( 989 void *NotUsed, 990 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 991 int argc, /* Number of arguments */ 992 const char **argv /* Text of each argument */ 993 ){ 994 BtCursor *pCur; 995 int rc; 996 u64 n; 997 char *zBuf; 998 999 if( argc!=2 ){ 1000 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1001 " ID\"", 0); 1002 return TCL_ERROR; 1003 } 1004 pCur = sqlite3TextToPtr(argv[1]); 1005 sqlite3BtreeKeySize(pCur, &n); 1006 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ 1007 char zBuf2[60]; 1008 sqlite3_snprintf(sizeof(zBuf2),zBuf2, "%llu", n); 1009 Tcl_AppendResult(interp, zBuf2, 0); 1010 }else{ 1011 zBuf = malloc( n+1 ); 1012 rc = sqlite3BtreeKey(pCur, 0, n, zBuf); 1013 if( rc ){ 1014 Tcl_AppendResult(interp, errorName(rc), 0); 1015 return TCL_ERROR; 1016 } 1017 zBuf[n] = 0; 1018 Tcl_AppendResult(interp, zBuf, 0); 1019 free(zBuf); 1020 } 1021 return SQLITE_OK; 1022 } 1023 1024 /* 1025 ** Usage: btree_data ID ?N? 1026 ** 1027 ** Return the data for the entry at which the cursor is pointing. 1028 */ 1029 static int btree_data( 1030 void *NotUsed, 1031 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1032 int argc, /* Number of arguments */ 1033 const char **argv /* Text of each argument */ 1034 ){ 1035 BtCursor *pCur; 1036 int rc; 1037 u32 n; 1038 char *zBuf; 1039 1040 if( argc!=2 && argc!=3 ){ 1041 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1042 " ID\"", 0); 1043 return TCL_ERROR; 1044 } 1045 pCur = sqlite3TextToPtr(argv[1]); 1046 if( argc==2 ){ 1047 sqlite3BtreeDataSize(pCur, &n); 1048 }else{ 1049 n = atoi(argv[2]); 1050 } 1051 zBuf = malloc( n+1 ); 1052 rc = sqlite3BtreeData(pCur, 0, n, zBuf); 1053 if( rc ){ 1054 Tcl_AppendResult(interp, errorName(rc), 0); 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, &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, &n1); 1165 } 1166 sqlite3BtreeDataSize(pCur, &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_cursor_info", (Tcl_CmdProc*)btree_cursor_info }, 1434 { "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list }, 1435 { "btree_integrity_check", (Tcl_CmdProc*)btree_integrity_check }, 1436 { "btree_breakpoint", (Tcl_CmdProc*)btree_breakpoint }, 1437 { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test }, 1438 { "btree_begin_statement", (Tcl_CmdProc*)btree_begin_statement }, 1439 { "btree_commit_statement", (Tcl_CmdProc*)btree_commit_statement }, 1440 { "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement }, 1441 { "btree_from_db", (Tcl_CmdProc*)btree_from_db }, 1442 { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size }, 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