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