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