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