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.75 2007/05/17 14:45:13 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_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 = sqlite3PagerStats(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 sqlite3PagerRefdump(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 int nErr; 571 char *zResult; 572 573 if( argc<3 ){ 574 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 575 " ID ROOT ...\"", 0); 576 return TCL_ERROR; 577 } 578 pBt = sqlite3TextToPtr(argv[1]); 579 nRoot = argc-2; 580 aRoot = (int*)malloc( sizeof(int)*(argc-2) ); 581 for(i=0; i<argc-2; i++){ 582 if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR; 583 } 584 #ifndef SQLITE_OMIT_INTEGRITY_CHECK 585 zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot, 10000, &nErr); 586 #else 587 zResult = 0; 588 #endif 589 free((void*)aRoot); 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, 0, &res); 710 }else{ 711 rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), 0, &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 ?NZERO? 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 int nZero; 767 768 if( objc!=4 && objc!=5 ){ 769 Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA ?NZERO?"); 770 return TCL_ERROR; 771 } 772 pCur = sqlite3TextToPtr(Tcl_GetString(objv[1])); 773 if( objc==5 ){ 774 if( Tcl_GetIntFromObj(interp, objv[4], &nZero) ) return TCL_ERROR; 775 }else{ 776 nZero = 0; 777 } 778 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ 779 i64 iKey; 780 int len; 781 unsigned char *pBuf; 782 if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ) return TCL_ERROR; 783 pBuf = Tcl_GetByteArrayFromObj(objv[3], &len); 784 rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len, nZero, 0); 785 }else{ 786 int keylen; 787 int dlen; 788 unsigned char *pKBuf; 789 unsigned char *pDBuf; 790 pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen); 791 pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen); 792 rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen, nZero, 0); 793 } 794 if( rc ){ 795 Tcl_AppendResult(interp, errorName(rc), 0); 796 return TCL_ERROR; 797 } 798 return SQLITE_OK; 799 } 800 801 /* 802 ** Usage: btree_next ID 803 ** 804 ** Move the cursor to the next entry in the table. Return 0 on success 805 ** or 1 if the cursor was already on the last entry in the table or if 806 ** the table is empty. 807 */ 808 static int btree_next( 809 void *NotUsed, 810 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 811 int argc, /* Number of arguments */ 812 const char **argv /* Text of each argument */ 813 ){ 814 BtCursor *pCur; 815 int rc; 816 int res = 0; 817 char zBuf[100]; 818 819 if( argc!=2 ){ 820 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 821 " ID\"", 0); 822 return TCL_ERROR; 823 } 824 pCur = sqlite3TextToPtr(argv[1]); 825 rc = sqlite3BtreeNext(pCur, &res); 826 if( rc ){ 827 Tcl_AppendResult(interp, errorName(rc), 0); 828 return TCL_ERROR; 829 } 830 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 831 Tcl_AppendResult(interp, zBuf, 0); 832 return SQLITE_OK; 833 } 834 835 /* 836 ** Usage: btree_prev ID 837 ** 838 ** Move the cursor to the previous entry in the table. Return 0 on 839 ** success and 1 if the cursor was already on the first entry in 840 ** the table or if the table was empty. 841 */ 842 static int btree_prev( 843 void *NotUsed, 844 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 845 int argc, /* Number of arguments */ 846 const char **argv /* Text of each argument */ 847 ){ 848 BtCursor *pCur; 849 int rc; 850 int res = 0; 851 char zBuf[100]; 852 853 if( argc!=2 ){ 854 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 855 " ID\"", 0); 856 return TCL_ERROR; 857 } 858 pCur = sqlite3TextToPtr(argv[1]); 859 rc = sqlite3BtreePrevious(pCur, &res); 860 if( rc ){ 861 Tcl_AppendResult(interp, errorName(rc), 0); 862 return TCL_ERROR; 863 } 864 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 865 Tcl_AppendResult(interp, zBuf, 0); 866 return SQLITE_OK; 867 } 868 869 /* 870 ** Usage: btree_first ID 871 ** 872 ** Move the cursor to the first entry in the table. Return 0 if the 873 ** cursor was left point to something and 1 if the table is empty. 874 */ 875 static int btree_first( 876 void *NotUsed, 877 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 878 int argc, /* Number of arguments */ 879 const char **argv /* Text of each argument */ 880 ){ 881 BtCursor *pCur; 882 int rc; 883 int res = 0; 884 char zBuf[100]; 885 886 if( argc!=2 ){ 887 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 888 " ID\"", 0); 889 return TCL_ERROR; 890 } 891 pCur = sqlite3TextToPtr(argv[1]); 892 rc = sqlite3BtreeFirst(pCur, &res); 893 if( rc ){ 894 Tcl_AppendResult(interp, errorName(rc), 0); 895 return TCL_ERROR; 896 } 897 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 898 Tcl_AppendResult(interp, zBuf, 0); 899 return SQLITE_OK; 900 } 901 902 /* 903 ** Usage: btree_last ID 904 ** 905 ** Move the cursor to the last entry in the table. Return 0 if the 906 ** cursor was left point to something and 1 if the table is empty. 907 */ 908 static int btree_last( 909 void *NotUsed, 910 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 911 int argc, /* Number of arguments */ 912 const char **argv /* Text of each argument */ 913 ){ 914 BtCursor *pCur; 915 int rc; 916 int res = 0; 917 char zBuf[100]; 918 919 if( argc!=2 ){ 920 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 921 " ID\"", 0); 922 return TCL_ERROR; 923 } 924 pCur = sqlite3TextToPtr(argv[1]); 925 rc = sqlite3BtreeLast(pCur, &res); 926 if( rc ){ 927 Tcl_AppendResult(interp, errorName(rc), 0); 928 return TCL_ERROR; 929 } 930 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 931 Tcl_AppendResult(interp, zBuf, 0); 932 return SQLITE_OK; 933 } 934 935 /* 936 ** Usage: btree_eof ID 937 ** 938 ** Return TRUE if the given cursor is not pointing at a valid entry. 939 ** Return FALSE if the cursor does point to a valid entry. 940 */ 941 static int btree_eof( 942 void *NotUsed, 943 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 944 int argc, /* Number of arguments */ 945 const char **argv /* Text of each argument */ 946 ){ 947 BtCursor *pCur; 948 char zBuf[50]; 949 950 if( argc!=2 ){ 951 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 952 " ID\"", 0); 953 return TCL_ERROR; 954 } 955 pCur = sqlite3TextToPtr(argv[1]); 956 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", sqlite3BtreeEof(pCur)); 957 Tcl_AppendResult(interp, zBuf, 0); 958 return SQLITE_OK; 959 } 960 961 /* 962 ** Usage: btree_keysize ID 963 ** 964 ** Return the number of bytes of key. For an INTKEY table, this 965 ** returns the key itself. 966 */ 967 static int btree_keysize( 968 void *NotUsed, 969 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 970 int argc, /* Number of arguments */ 971 const char **argv /* Text of each argument */ 972 ){ 973 BtCursor *pCur; 974 u64 n; 975 char zBuf[50]; 976 977 if( argc!=2 ){ 978 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 979 " ID\"", 0); 980 return TCL_ERROR; 981 } 982 pCur = sqlite3TextToPtr(argv[1]); 983 sqlite3BtreeKeySize(pCur, (i64*)&n); 984 sqlite3_snprintf(sizeof(zBuf),zBuf, "%llu", n); 985 Tcl_AppendResult(interp, zBuf, 0); 986 return SQLITE_OK; 987 } 988 989 /* 990 ** Usage: btree_key ID 991 ** 992 ** Return the key for the entry at which the cursor is pointing. 993 */ 994 static int btree_key( 995 void *NotUsed, 996 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 997 int argc, /* Number of arguments */ 998 const char **argv /* Text of each argument */ 999 ){ 1000 BtCursor *pCur; 1001 int rc; 1002 u64 n; 1003 char *zBuf; 1004 1005 if( argc!=2 ){ 1006 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1007 " ID\"", 0); 1008 return TCL_ERROR; 1009 } 1010 pCur = sqlite3TextToPtr(argv[1]); 1011 sqlite3BtreeKeySize(pCur, (i64*)&n); 1012 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ 1013 char zBuf2[60]; 1014 sqlite3_snprintf(sizeof(zBuf2),zBuf2, "%llu", n); 1015 Tcl_AppendResult(interp, zBuf2, 0); 1016 }else{ 1017 zBuf = malloc( n+1 ); 1018 rc = sqlite3BtreeKey(pCur, 0, n, zBuf); 1019 if( rc ){ 1020 Tcl_AppendResult(interp, errorName(rc), 0); 1021 return TCL_ERROR; 1022 } 1023 zBuf[n] = 0; 1024 Tcl_AppendResult(interp, zBuf, 0); 1025 free(zBuf); 1026 } 1027 return SQLITE_OK; 1028 } 1029 1030 /* 1031 ** Usage: btree_data ID ?N? 1032 ** 1033 ** Return the data for the entry at which the cursor is pointing. 1034 */ 1035 static int btree_data( 1036 void *NotUsed, 1037 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1038 int argc, /* Number of arguments */ 1039 const char **argv /* Text of each argument */ 1040 ){ 1041 BtCursor *pCur; 1042 int rc; 1043 u32 n; 1044 char *zBuf; 1045 1046 if( argc!=2 && argc!=3 ){ 1047 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1048 " ID\"", 0); 1049 return TCL_ERROR; 1050 } 1051 pCur = sqlite3TextToPtr(argv[1]); 1052 if( argc==2 ){ 1053 sqlite3BtreeDataSize(pCur, &n); 1054 }else{ 1055 n = atoi(argv[2]); 1056 } 1057 zBuf = malloc( n+1 ); 1058 rc = sqlite3BtreeData(pCur, 0, n, zBuf); 1059 if( rc ){ 1060 Tcl_AppendResult(interp, errorName(rc), 0); 1061 free(zBuf); 1062 return TCL_ERROR; 1063 } 1064 zBuf[n] = 0; 1065 Tcl_AppendResult(interp, zBuf, 0); 1066 free(zBuf); 1067 return SQLITE_OK; 1068 } 1069 1070 /* 1071 ** Usage: btree_fetch_key ID AMT 1072 ** 1073 ** Use the sqlite3BtreeKeyFetch() routine to get AMT bytes of the key. 1074 ** If sqlite3BtreeKeyFetch() fails, return an empty string. 1075 */ 1076 static int btree_fetch_key( 1077 void *NotUsed, 1078 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1079 int argc, /* Number of arguments */ 1080 const char **argv /* Text of each argument */ 1081 ){ 1082 BtCursor *pCur; 1083 int n; 1084 int amt; 1085 u64 nKey; 1086 const char *zBuf; 1087 char zStatic[1000]; 1088 1089 if( argc!=3 ){ 1090 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1091 " ID AMT\"", 0); 1092 return TCL_ERROR; 1093 } 1094 pCur = sqlite3TextToPtr(argv[1]); 1095 if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; 1096 sqlite3BtreeKeySize(pCur, (i64*)&nKey); 1097 zBuf = sqlite3BtreeKeyFetch(pCur, &amt); 1098 if( zBuf && amt>=n ){ 1099 assert( nKey<sizeof(zStatic) ); 1100 if( n>0 ) nKey = n; 1101 memcpy(zStatic, zBuf, (int)nKey); 1102 zStatic[nKey] = 0; 1103 Tcl_AppendResult(interp, zStatic, 0); 1104 } 1105 return TCL_OK; 1106 } 1107 1108 /* 1109 ** Usage: btree_fetch_data ID AMT 1110 ** 1111 ** Use the sqlite3BtreeDataFetch() routine to get AMT bytes of the key. 1112 ** If sqlite3BtreeDataFetch() fails, return an empty string. 1113 */ 1114 static int btree_fetch_data( 1115 void *NotUsed, 1116 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1117 int argc, /* Number of arguments */ 1118 const char **argv /* Text of each argument */ 1119 ){ 1120 BtCursor *pCur; 1121 int n; 1122 int amt; 1123 u32 nData; 1124 const char *zBuf; 1125 char zStatic[1000]; 1126 1127 if( argc!=3 ){ 1128 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1129 " ID AMT\"", 0); 1130 return TCL_ERROR; 1131 } 1132 pCur = sqlite3TextToPtr(argv[1]); 1133 if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; 1134 sqlite3BtreeDataSize(pCur, &nData); 1135 zBuf = sqlite3BtreeDataFetch(pCur, &amt); 1136 if( zBuf && amt>=n ){ 1137 assert( nData<sizeof(zStatic) ); 1138 if( n>0 ) nData = n; 1139 memcpy(zStatic, zBuf, (int)nData); 1140 zStatic[nData] = 0; 1141 Tcl_AppendResult(interp, zStatic, 0); 1142 } 1143 return TCL_OK; 1144 } 1145 1146 /* 1147 ** Usage: btree_payload_size ID 1148 ** 1149 ** Return the number of bytes of payload 1150 */ 1151 static int btree_payload_size( 1152 void *NotUsed, 1153 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1154 int argc, /* Number of arguments */ 1155 const char **argv /* Text of each argument */ 1156 ){ 1157 BtCursor *pCur; 1158 int n2; 1159 u64 n1; 1160 char zBuf[50]; 1161 1162 if( argc!=2 ){ 1163 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1164 " ID\"", 0); 1165 return TCL_ERROR; 1166 } 1167 pCur = sqlite3TextToPtr(argv[1]); 1168 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ 1169 n1 = 0; 1170 }else{ 1171 sqlite3BtreeKeySize(pCur, (i64*)&n1); 1172 } 1173 sqlite3BtreeDataSize(pCur, (u32*)&n2); 1174 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2)); 1175 Tcl_AppendResult(interp, zBuf, 0); 1176 return SQLITE_OK; 1177 } 1178 1179 /* 1180 ** Usage: btree_cursor_info ID ?UP-CNT? 1181 ** 1182 ** Return integers containing information about the entry the 1183 ** cursor is pointing to: 1184 ** 1185 ** aResult[0] = The page number 1186 ** aResult[1] = The entry number 1187 ** aResult[2] = Total number of entries on this page 1188 ** aResult[3] = Cell size (local payload + header) 1189 ** aResult[4] = Number of free bytes on this page 1190 ** aResult[5] = Number of free blocks on the page 1191 ** aResult[6] = Total payload size (local + overflow) 1192 ** aResult[7] = Header size in bytes 1193 ** aResult[8] = Local payload size 1194 ** aResult[9] = Parent page number 1195 ** aResult[10]= Page number of the first overflow page 1196 */ 1197 static int btree_cursor_info( 1198 void *NotUsed, 1199 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1200 int argc, /* Number of arguments */ 1201 const char **argv /* Text of each argument */ 1202 ){ 1203 BtCursor *pCur; 1204 int rc; 1205 int i, j; 1206 int up; 1207 int aResult[11]; 1208 char zBuf[400]; 1209 1210 if( argc!=2 && argc!=3 ){ 1211 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1212 " ID ?UP-CNT?\"", 0); 1213 return TCL_ERROR; 1214 } 1215 pCur = sqlite3TextToPtr(argv[1]); 1216 if( argc==3 ){ 1217 if( Tcl_GetInt(interp, argv[2], &up) ) return TCL_ERROR; 1218 }else{ 1219 up = 0; 1220 } 1221 rc = sqlite3BtreeCursorInfo(pCur, aResult, up); 1222 if( rc ){ 1223 Tcl_AppendResult(interp, errorName(rc), 0); 1224 return TCL_ERROR; 1225 } 1226 j = 0; 1227 for(i=0; i<sizeof(aResult)/sizeof(aResult[0]); i++){ 1228 sqlite3_snprintf(40,&zBuf[j]," %d", aResult[i]); 1229 j += strlen(&zBuf[j]); 1230 } 1231 Tcl_AppendResult(interp, &zBuf[1], 0); 1232 return SQLITE_OK; 1233 } 1234 1235 /* 1236 ** Copied from btree.c: 1237 */ 1238 static u32 t4Get4byte(unsigned char *p){ 1239 return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; 1240 } 1241 1242 /* 1243 ** btree_ovfl_info BTREE CURSOR 1244 ** 1245 ** Given a cursor, return the sequence of pages number that form the 1246 ** overflow pages for the data of the entry that the cursor is point 1247 ** to. 1248 */ 1249 static int btree_ovfl_info( 1250 void *NotUsed, 1251 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1252 int argc, /* Number of arguments */ 1253 const char **argv /* Text of each argument */ 1254 ){ 1255 Btree *pBt; 1256 BtCursor *pCur; 1257 Pager *pPager; 1258 int rc; 1259 int n; 1260 int dataSize; 1261 u32 pgno; 1262 void *pPage; 1263 int aResult[11]; 1264 char zElem[100]; 1265 Tcl_DString str; 1266 1267 if( argc!=3 ){ 1268 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1269 " BTREE CURSOR", 0); 1270 return TCL_ERROR; 1271 } 1272 pBt = sqlite3TextToPtr(argv[1]); 1273 pCur = sqlite3TextToPtr(argv[2]); 1274 if( (*(void**)pCur) != (void*)pBt ){ 1275 Tcl_AppendResult(interp, "Cursor ", argv[2], " does not belong to btree ", 1276 argv[1], 0); 1277 return TCL_ERROR; 1278 } 1279 pPager = sqlite3BtreePager(pBt); 1280 rc = sqlite3BtreeCursorInfo(pCur, aResult, 0); 1281 if( rc ){ 1282 Tcl_AppendResult(interp, errorName(rc), 0); 1283 return TCL_ERROR; 1284 } 1285 dataSize = sqlite3BtreeGetPageSize(pBt) - sqlite3BtreeGetReserve(pBt); 1286 Tcl_DStringInit(&str); 1287 n = aResult[6] - aResult[8]; 1288 n = (n + dataSize - 1)/dataSize; 1289 pgno = (u32)aResult[10]; 1290 while( pgno && n-- ){ 1291 DbPage *pDbPage; 1292 sprintf(zElem, "%d", pgno); 1293 Tcl_DStringAppendElement(&str, zElem); 1294 if( sqlite3PagerGet(pPager, pgno, &pDbPage)!=SQLITE_OK ){ 1295 Tcl_DStringFree(&str); 1296 Tcl_AppendResult(interp, "unable to get page ", zElem, 0); 1297 return TCL_ERROR; 1298 } 1299 pPage = sqlite3PagerGetData(pDbPage); 1300 pgno = t4Get4byte((unsigned char*)pPage); 1301 sqlite3PagerUnref(pDbPage); 1302 } 1303 Tcl_DStringResult(interp, &str); 1304 return SQLITE_OK; 1305 } 1306 1307 /* 1308 ** The command is provided for the purpose of setting breakpoints. 1309 ** in regression test scripts. 1310 ** 1311 ** By setting a GDB breakpoint on this procedure and executing the 1312 ** btree_breakpoint command in a test script, we can stop GDB at 1313 ** the point in the script where the btree_breakpoint command is 1314 ** inserted. This is useful for debugging. 1315 */ 1316 static int btree_breakpoint( 1317 void *NotUsed, 1318 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1319 int argc, /* Number of arguments */ 1320 const char **argv /* Text of each argument */ 1321 ){ 1322 return TCL_OK; 1323 } 1324 1325 /* 1326 ** usage: varint_test START MULTIPLIER COUNT INCREMENT 1327 ** 1328 ** This command tests the sqlite3PutVarint() and sqlite3GetVarint() 1329 ** routines, both for accuracy and for speed. 1330 ** 1331 ** An integer is written using PutVarint() and read back with 1332 ** GetVarint() and varified to be unchanged. This repeats COUNT 1333 ** times. The first integer is START*MULTIPLIER. Each iteration 1334 ** increases the integer by INCREMENT. 1335 ** 1336 ** This command returns nothing if it works. It returns an error message 1337 ** if something goes wrong. 1338 */ 1339 static int btree_varint_test( 1340 void *NotUsed, 1341 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1342 int argc, /* Number of arguments */ 1343 const char **argv /* Text of each argument */ 1344 ){ 1345 u32 start, mult, count, incr; 1346 u64 in, out; 1347 int n1, n2, i, j; 1348 unsigned char zBuf[100]; 1349 if( argc!=5 ){ 1350 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1351 " START MULTIPLIER COUNT INCREMENT\"", 0); 1352 return TCL_ERROR; 1353 } 1354 if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR; 1355 if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR; 1356 if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR; 1357 if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR; 1358 in = start; 1359 in *= mult; 1360 for(i=0; i<count; i++){ 1361 char zErr[200]; 1362 n1 = sqlite3PutVarint(zBuf, in); 1363 if( n1>9 || n1<1 ){ 1364 sprintf(zErr, "PutVarint returned %d - should be between 1 and 9", n1); 1365 Tcl_AppendResult(interp, zErr, 0); 1366 return TCL_ERROR; 1367 } 1368 n2 = sqlite3GetVarint(zBuf, &out); 1369 if( n1!=n2 ){ 1370 sprintf(zErr, "PutVarint returned %d and GetVarint returned %d", n1, n2); 1371 Tcl_AppendResult(interp, zErr, 0); 1372 return TCL_ERROR; 1373 } 1374 if( in!=out ){ 1375 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out); 1376 Tcl_AppendResult(interp, zErr, 0); 1377 return TCL_ERROR; 1378 } 1379 if( (in & 0xffffffff)==in ){ 1380 u32 out32; 1381 n2 = sqlite3GetVarint32(zBuf, &out32); 1382 out = out32; 1383 if( n1!=n2 ){ 1384 sprintf(zErr, "PutVarint returned %d and GetVarint32 returned %d", 1385 n1, n2); 1386 Tcl_AppendResult(interp, zErr, 0); 1387 return TCL_ERROR; 1388 } 1389 if( in!=out ){ 1390 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32", 1391 in, out); 1392 Tcl_AppendResult(interp, zErr, 0); 1393 return TCL_ERROR; 1394 } 1395 } 1396 1397 /* In order to get realistic timings, run getVarint 19 more times. 1398 ** This is because getVarint is called about 20 times more often 1399 ** than putVarint. 1400 */ 1401 for(j=0; j<19; j++){ 1402 sqlite3GetVarint(zBuf, &out); 1403 } 1404 in += incr; 1405 } 1406 return TCL_OK; 1407 } 1408 1409 /* 1410 ** usage: btree_from_db DB-HANDLE 1411 ** 1412 ** This command returns the btree handle for the main database associated 1413 ** with the database-handle passed as the argument. Example usage: 1414 ** 1415 ** sqlite3 db test.db 1416 ** set bt [btree_from_db db] 1417 */ 1418 static int btree_from_db( 1419 void *NotUsed, 1420 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1421 int argc, /* Number of arguments */ 1422 const char **argv /* Text of each argument */ 1423 ){ 1424 char zBuf[100]; 1425 Tcl_CmdInfo info; 1426 sqlite3 *db; 1427 Btree *pBt; 1428 int iDb = 0; 1429 1430 if( argc!=2 && argc!=3 ){ 1431 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1432 " DB-HANDLE ?N?\"", 0); 1433 return TCL_ERROR; 1434 } 1435 1436 if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){ 1437 Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0); 1438 return TCL_ERROR; 1439 } 1440 if( argc==3 ){ 1441 iDb = atoi(argv[2]); 1442 } 1443 1444 db = *((sqlite3 **)info.objClientData); 1445 assert( db ); 1446 1447 pBt = db->aDb[iDb].pBt; 1448 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt); 1449 Tcl_SetResult(interp, zBuf, TCL_VOLATILE); 1450 return TCL_OK; 1451 } 1452 1453 1454 /* 1455 ** usage: btree_set_cache_size ID NCACHE 1456 ** 1457 ** Set the size of the cache used by btree $ID. 1458 */ 1459 static int btree_set_cache_size( 1460 void *NotUsed, 1461 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 1462 int argc, /* Number of arguments */ 1463 const char **argv /* Text of each argument */ 1464 ){ 1465 int nCache; 1466 Btree *pBt; 1467 1468 if( argc!=3 ){ 1469 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 1470 " BT NCACHE\"", 0); 1471 return TCL_ERROR; 1472 } 1473 pBt = sqlite3TextToPtr(argv[1]); 1474 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; 1475 sqlite3BtreeSetCacheSize(pBt, nCache); 1476 return TCL_OK; 1477 } 1478 1479 1480 /* 1481 ** Register commands with the TCL interpreter. 1482 */ 1483 int Sqlitetest3_Init(Tcl_Interp *interp){ 1484 extern int sqlite3_btree_trace; 1485 static struct { 1486 char *zName; 1487 Tcl_CmdProc *xProc; 1488 } aCmd[] = { 1489 { "btree_open", (Tcl_CmdProc*)btree_open }, 1490 { "btree_close", (Tcl_CmdProc*)btree_close }, 1491 { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction }, 1492 { "btree_commit", (Tcl_CmdProc*)btree_commit }, 1493 { "btree_rollback", (Tcl_CmdProc*)btree_rollback }, 1494 { "btree_create_table", (Tcl_CmdProc*)btree_create_table }, 1495 { "btree_drop_table", (Tcl_CmdProc*)btree_drop_table }, 1496 { "btree_clear_table", (Tcl_CmdProc*)btree_clear_table }, 1497 { "btree_get_meta", (Tcl_CmdProc*)btree_get_meta }, 1498 { "btree_update_meta", (Tcl_CmdProc*)btree_update_meta }, 1499 { "btree_page_dump", (Tcl_CmdProc*)btree_page_dump }, 1500 { "btree_tree_dump", (Tcl_CmdProc*)btree_tree_dump }, 1501 { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats }, 1502 { "btree_pager_ref_dump", (Tcl_CmdProc*)btree_pager_ref_dump }, 1503 { "btree_cursor", (Tcl_CmdProc*)btree_cursor }, 1504 { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor }, 1505 { "btree_move_to", (Tcl_CmdProc*)btree_move_to }, 1506 { "btree_delete", (Tcl_CmdProc*)btree_delete }, 1507 { "btree_next", (Tcl_CmdProc*)btree_next }, 1508 { "btree_prev", (Tcl_CmdProc*)btree_prev }, 1509 { "btree_eof", (Tcl_CmdProc*)btree_eof }, 1510 { "btree_keysize", (Tcl_CmdProc*)btree_keysize }, 1511 { "btree_key", (Tcl_CmdProc*)btree_key }, 1512 { "btree_data", (Tcl_CmdProc*)btree_data }, 1513 { "btree_fetch_key", (Tcl_CmdProc*)btree_fetch_key }, 1514 { "btree_fetch_data", (Tcl_CmdProc*)btree_fetch_data }, 1515 { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size }, 1516 { "btree_first", (Tcl_CmdProc*)btree_first }, 1517 { "btree_last", (Tcl_CmdProc*)btree_last }, 1518 { "btree_integrity_check", (Tcl_CmdProc*)btree_integrity_check }, 1519 { "btree_breakpoint", (Tcl_CmdProc*)btree_breakpoint }, 1520 { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test }, 1521 { "btree_begin_statement", (Tcl_CmdProc*)btree_begin_statement }, 1522 { "btree_commit_statement", (Tcl_CmdProc*)btree_commit_statement }, 1523 { "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement }, 1524 { "btree_from_db", (Tcl_CmdProc*)btree_from_db }, 1525 { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size }, 1526 { "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info }, 1527 { "btree_ovfl_info", (Tcl_CmdProc*)btree_ovfl_info }, 1528 { "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list }, 1529 }; 1530 int i; 1531 1532 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 1533 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 1534 } 1535 Tcl_LinkVar(interp, "pager_refinfo_enable", (char*)&pager3_refinfo_enable, 1536 TCL_LINK_INT); 1537 Tcl_LinkVar(interp, "btree_trace", (char*)&sqlite3_btree_trace, 1538 TCL_LINK_INT); 1539 1540 /* The btree_insert command is implemented using the tcl 'object' 1541 ** interface, not the string interface like the other commands in this 1542 ** file. This is so binary data can be inserted into btree tables. 1543 */ 1544 Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0); 1545 return TCL_OK; 1546 } 1547