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