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.23 2003/04/13 18:26:52 paul Exp $ 17 */ 18 #include "sqliteInt.h" 19 #include "pager.h" 20 #include "btree.h" 21 #include "tcl.h" 22 #include <stdlib.h> 23 #include <string.h> 24 25 /* 26 ** Interpret an SQLite error number 27 */ 28 static char *errorName(int rc){ 29 char *zName; 30 switch( rc ){ 31 case SQLITE_OK: zName = "SQLITE_OK"; break; 32 case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; 33 case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; 34 case SQLITE_PERM: zName = "SQLITE_PERM"; break; 35 case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; 36 case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; 37 case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; 38 case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; 39 case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; 40 case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; 41 case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; 42 case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break; 43 case SQLITE_FULL: zName = "SQLITE_FULL"; break; 44 case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; 45 case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; 46 default: zName = "SQLITE_Unknown"; break; 47 } 48 return zName; 49 } 50 51 /* 52 ** Usage: btree_open FILENAME 53 ** 54 ** Open a new database 55 */ 56 static int btree_open( 57 void *NotUsed, 58 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 59 int argc, /* Number of arguments */ 60 const char **argv /* Text of each argument */ 61 ){ 62 Btree *pBt; 63 int rc; 64 char zBuf[100]; 65 if( argc!=2 ){ 66 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 67 " FILENAME\"", 0); 68 return TCL_ERROR; 69 } 70 rc = sqliteBtreeFactory(0, argv[1], 0, 1000, &pBt); 71 if( rc!=SQLITE_OK ){ 72 Tcl_AppendResult(interp, errorName(rc), 0); 73 return TCL_ERROR; 74 } 75 sprintf(zBuf,"%p", pBt); 76 if( strncmp(zBuf,"0x",2) ){ 77 sprintf(zBuf, "0x%p", pBt); 78 } 79 Tcl_AppendResult(interp, zBuf, 0); 80 return TCL_OK; 81 } 82 83 /* 84 ** Usage: btree_close ID 85 ** 86 ** Close the given database. 87 */ 88 static int btree_close( 89 void *NotUsed, 90 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 91 int argc, /* Number of arguments */ 92 const char **argv /* Text of each argument */ 93 ){ 94 Btree *pBt; 95 int rc; 96 if( argc!=2 ){ 97 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 98 " ID\"", 0); 99 return TCL_ERROR; 100 } 101 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; 102 rc = sqliteBtreeClose(pBt); 103 if( rc!=SQLITE_OK ){ 104 Tcl_AppendResult(interp, errorName(rc), 0); 105 return TCL_ERROR; 106 } 107 return TCL_OK; 108 } 109 110 /* 111 ** Usage: btree_begin_transaction ID 112 ** 113 ** Start a new transaction 114 */ 115 static int btree_begin_transaction( 116 void *NotUsed, 117 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 118 int argc, /* Number of arguments */ 119 const char **argv /* Text of each argument */ 120 ){ 121 Btree *pBt; 122 int rc; 123 if( argc!=2 ){ 124 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 125 " ID\"", 0); 126 return TCL_ERROR; 127 } 128 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; 129 rc = sqliteBtreeBeginTrans(pBt); 130 if( rc!=SQLITE_OK ){ 131 Tcl_AppendResult(interp, errorName(rc), 0); 132 return TCL_ERROR; 133 } 134 return TCL_OK; 135 } 136 137 /* 138 ** Usage: btree_rollback ID 139 ** 140 ** Rollback changes 141 */ 142 static int btree_rollback( 143 void *NotUsed, 144 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 145 int argc, /* Number of arguments */ 146 const char **argv /* Text of each argument */ 147 ){ 148 Btree *pBt; 149 int rc; 150 if( argc!=2 ){ 151 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 152 " ID\"", 0); 153 return TCL_ERROR; 154 } 155 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; 156 rc = sqliteBtreeRollback(pBt); 157 if( rc!=SQLITE_OK ){ 158 Tcl_AppendResult(interp, errorName(rc), 0); 159 return TCL_ERROR; 160 } 161 return TCL_OK; 162 } 163 164 /* 165 ** Usage: btree_commit ID 166 ** 167 ** Commit all changes 168 */ 169 static int btree_commit( 170 void *NotUsed, 171 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 172 int argc, /* Number of arguments */ 173 const char **argv /* Text of each argument */ 174 ){ 175 Btree *pBt; 176 int rc; 177 if( argc!=2 ){ 178 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 179 " ID\"", 0); 180 return TCL_ERROR; 181 } 182 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; 183 rc = sqliteBtreeCommit(pBt); 184 if( rc!=SQLITE_OK ){ 185 Tcl_AppendResult(interp, errorName(rc), 0); 186 return TCL_ERROR; 187 } 188 return TCL_OK; 189 } 190 191 /* 192 ** Usage: btree_create_table ID 193 ** 194 ** Create a new table in the database 195 */ 196 static int btree_create_table( 197 void *NotUsed, 198 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 199 int argc, /* Number of arguments */ 200 const char **argv /* Text of each argument */ 201 ){ 202 Btree *pBt; 203 int rc, iTable; 204 char zBuf[30]; 205 if( argc!=2 ){ 206 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 207 " ID\"", 0); 208 return TCL_ERROR; 209 } 210 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; 211 rc = sqliteBtreeCreateTable(pBt, &iTable); 212 if( rc!=SQLITE_OK ){ 213 Tcl_AppendResult(interp, errorName(rc), 0); 214 return TCL_ERROR; 215 } 216 sprintf(zBuf, "%d", iTable); 217 Tcl_AppendResult(interp, zBuf, 0); 218 return TCL_OK; 219 } 220 221 /* 222 ** Usage: btree_drop_table ID TABLENUM 223 ** 224 ** Delete an entire table from the database 225 */ 226 static int btree_drop_table( 227 void *NotUsed, 228 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 229 int argc, /* Number of arguments */ 230 const char **argv /* Text of each argument */ 231 ){ 232 Btree *pBt; 233 int iTable; 234 int rc; 235 if( argc!=3 ){ 236 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 237 " ID TABLENUM\"", 0); 238 return TCL_ERROR; 239 } 240 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; 241 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; 242 rc = sqliteBtreeDropTable(pBt, iTable); 243 if( rc!=SQLITE_OK ){ 244 Tcl_AppendResult(interp, errorName(rc), 0); 245 return TCL_ERROR; 246 } 247 return TCL_OK; 248 } 249 250 /* 251 ** Usage: btree_clear_table ID TABLENUM 252 ** 253 ** Remove all entries from the given table but keep the table around. 254 */ 255 static int btree_clear_table( 256 void *NotUsed, 257 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 258 int argc, /* Number of arguments */ 259 const char **argv /* Text of each argument */ 260 ){ 261 Btree *pBt; 262 int iTable; 263 int rc; 264 if( argc!=3 ){ 265 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 266 " ID TABLENUM\"", 0); 267 return TCL_ERROR; 268 } 269 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; 270 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; 271 rc = sqliteBtreeClearTable(pBt, iTable); 272 if( rc!=SQLITE_OK ){ 273 Tcl_AppendResult(interp, errorName(rc), 0); 274 return TCL_ERROR; 275 } 276 return TCL_OK; 277 } 278 279 /* 280 ** Usage: btree_get_meta ID 281 ** 282 ** Return meta data 283 */ 284 static int btree_get_meta( 285 void *NotUsed, 286 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 287 int argc, /* Number of arguments */ 288 const char **argv /* Text of each argument */ 289 ){ 290 Btree *pBt; 291 int rc; 292 int i; 293 int aMeta[SQLITE_N_BTREE_META]; 294 if( argc!=2 ){ 295 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 296 " ID\"", 0); 297 return TCL_ERROR; 298 } 299 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; 300 rc = sqliteBtreeGetMeta(pBt, aMeta); 301 if( rc!=SQLITE_OK ){ 302 Tcl_AppendResult(interp, errorName(rc), 0); 303 return TCL_ERROR; 304 } 305 for(i=0; i<SQLITE_N_BTREE_META; i++){ 306 char zBuf[30]; 307 sprintf(zBuf,"%d",aMeta[i]); 308 Tcl_AppendElement(interp, zBuf); 309 } 310 return TCL_OK; 311 } 312 313 /* 314 ** Usage: btree_update_meta ID METADATA... 315 ** 316 ** Return meta data 317 */ 318 static int btree_update_meta( 319 void *NotUsed, 320 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 321 int argc, /* Number of arguments */ 322 const char **argv /* Text of each argument */ 323 ){ 324 Btree *pBt; 325 int rc; 326 int i; 327 int aMeta[SQLITE_N_BTREE_META]; 328 329 if( argc!=2+SQLITE_N_BTREE_META ){ 330 char zBuf[30]; 331 sprintf(zBuf,"%d",SQLITE_N_BTREE_META); 332 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 333 " ID METADATA...\" (METADATA is ", zBuf, " integers)", 0); 334 return TCL_ERROR; 335 } 336 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; 337 for(i=0; i<SQLITE_N_BTREE_META; i++){ 338 if( Tcl_GetInt(interp, argv[i+2], &aMeta[i]) ) return TCL_ERROR; 339 } 340 rc = sqliteBtreeUpdateMeta(pBt, aMeta); 341 if( rc!=SQLITE_OK ){ 342 Tcl_AppendResult(interp, errorName(rc), 0); 343 return TCL_ERROR; 344 } 345 return TCL_OK; 346 } 347 348 /* 349 ** Usage: btree_page_dump ID PAGENUM 350 ** 351 ** Print a disassembly of a page on standard output 352 */ 353 static int btree_page_dump( 354 void *NotUsed, 355 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 356 int argc, /* Number of arguments */ 357 const char **argv /* Text of each argument */ 358 ){ 359 Btree *pBt; 360 int iPage; 361 int rc; 362 363 if( argc!=3 ){ 364 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 365 " ID\"", 0); 366 return TCL_ERROR; 367 } 368 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; 369 if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR; 370 rc = sqliteBtreePageDump(pBt, iPage, 0); 371 if( rc!=SQLITE_OK ){ 372 Tcl_AppendResult(interp, errorName(rc), 0); 373 return TCL_ERROR; 374 } 375 return TCL_OK; 376 } 377 378 /* 379 ** Usage: btree_tree_dump ID PAGENUM 380 ** 381 ** Print a disassembly of a page and all its child pages on standard output 382 */ 383 static int btree_tree_dump( 384 void *NotUsed, 385 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 386 int argc, /* Number of arguments */ 387 const char **argv /* Text of each argument */ 388 ){ 389 Btree *pBt; 390 int iPage; 391 int rc; 392 393 if( argc!=3 ){ 394 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 395 " ID\"", 0); 396 return TCL_ERROR; 397 } 398 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; 399 if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR; 400 rc = sqliteBtreePageDump(pBt, iPage, 1); 401 if( rc!=SQLITE_OK ){ 402 Tcl_AppendResult(interp, errorName(rc), 0); 403 return TCL_ERROR; 404 } 405 return TCL_OK; 406 } 407 408 /* 409 ** Usage: btree_pager_stats ID 410 ** 411 ** Returns pager statistics 412 */ 413 static int btree_pager_stats( 414 void *NotUsed, 415 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 416 int argc, /* Number of arguments */ 417 const char **argv /* Text of each argument */ 418 ){ 419 Btree *pBt; 420 int i; 421 int *a; 422 423 if( argc!=2 ){ 424 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 425 " ID\"", 0); 426 return TCL_ERROR; 427 } 428 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; 429 a = sqlitepager_stats(sqliteBtreePager(pBt)); 430 for(i=0; i<9; i++){ 431 static char *zName[] = { 432 "ref", "page", "max", "size", "state", "err", 433 "hit", "miss", "ovfl", 434 }; 435 char zBuf[100]; 436 Tcl_AppendElement(interp, zName[i]); 437 sprintf(zBuf,"%d",a[i]); 438 Tcl_AppendElement(interp, zBuf); 439 } 440 return TCL_OK; 441 } 442 443 /* 444 ** Usage: btree_pager_ref_dump ID 445 ** 446 ** Print out all outstanding pages. 447 */ 448 static int btree_pager_ref_dump( 449 void *NotUsed, 450 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 451 int argc, /* Number of arguments */ 452 const char **argv /* Text of each argument */ 453 ){ 454 Btree *pBt; 455 456 if( argc!=2 ){ 457 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 458 " ID\"", 0); 459 return TCL_ERROR; 460 } 461 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; 462 sqlitepager_refdump(sqliteBtreePager(pBt)); 463 return TCL_OK; 464 } 465 466 /* 467 ** Usage: btree_integrity_check ID ROOT ... 468 ** 469 ** Look through every page of the given BTree file to verify correct 470 ** formatting and linkage. Return a line of text for each problem found. 471 ** Return an empty string if everything worked. 472 */ 473 static int btree_integrity_check( 474 void *NotUsed, 475 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 476 int argc, /* Number of arguments */ 477 const char **argv /* Text of each argument */ 478 ){ 479 Btree *pBt; 480 char *zResult; 481 int nRoot; 482 int *aRoot; 483 int i; 484 485 if( argc<3 ){ 486 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 487 " ID ROOT ...\"", 0); 488 return TCL_ERROR; 489 } 490 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; 491 nRoot = argc-2; 492 aRoot = malloc( sizeof(int)*(argc-2) ); 493 for(i=0; i<argc-2; i++){ 494 if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR; 495 } 496 zResult = sqliteBtreeIntegrityCheck(pBt, aRoot, nRoot); 497 if( zResult ){ 498 Tcl_AppendResult(interp, zResult, 0); 499 sqliteFree(zResult); 500 } 501 return TCL_OK; 502 } 503 504 /* 505 ** Usage: btree_cursor ID TABLENUM WRITEABLE 506 ** 507 ** Create a new cursor. Return the ID for the cursor. 508 */ 509 static int btree_cursor( 510 void *NotUsed, 511 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 512 int argc, /* Number of arguments */ 513 const char **argv /* Text of each argument */ 514 ){ 515 Btree *pBt; 516 int iTable; 517 BtCursor *pCur; 518 int rc; 519 int wrFlag; 520 char zBuf[30]; 521 522 if( argc!=4 ){ 523 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 524 " ID TABLENUM WRITEABLE\"", 0); 525 return TCL_ERROR; 526 } 527 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; 528 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; 529 if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR; 530 rc = sqliteBtreeCursor(pBt, iTable, wrFlag, &pCur); 531 if( rc ){ 532 Tcl_AppendResult(interp, errorName(rc), 0); 533 return TCL_ERROR; 534 } 535 sprintf(zBuf,"0x%x", (int)pCur); 536 Tcl_AppendResult(interp, zBuf, 0); 537 return SQLITE_OK; 538 } 539 540 /* 541 ** Usage: btree_close_cursor ID 542 ** 543 ** Close a cursor opened using btree_cursor. 544 */ 545 static int btree_close_cursor( 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 BtCursor *pCur; 552 int rc; 553 554 if( argc!=2 ){ 555 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 556 " ID\"", 0); 557 return TCL_ERROR; 558 } 559 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; 560 rc = sqliteBtreeCloseCursor(pCur); 561 if( rc ){ 562 Tcl_AppendResult(interp, errorName(rc), 0); 563 return TCL_ERROR; 564 } 565 return SQLITE_OK; 566 } 567 568 /* 569 ** Usage: btree_move_to ID KEY 570 ** 571 ** Move the cursor to the entry with the given key. 572 */ 573 static int btree_move_to( 574 void *NotUsed, 575 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 576 int argc, /* Number of arguments */ 577 const char **argv /* Text of each argument */ 578 ){ 579 BtCursor *pCur; 580 int rc; 581 int res; 582 char zBuf[20]; 583 584 if( argc!=3 ){ 585 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 586 " ID KEY\"", 0); 587 return TCL_ERROR; 588 } 589 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; 590 rc = sqliteBtreeMoveto(pCur, argv[2], strlen(argv[2]), &res); 591 if( rc ){ 592 Tcl_AppendResult(interp, errorName(rc), 0); 593 return TCL_ERROR; 594 } 595 if( res<0 ) res = -1; 596 if( res>0 ) res = 1; 597 sprintf(zBuf,"%d",res); 598 Tcl_AppendResult(interp, zBuf, 0); 599 return SQLITE_OK; 600 } 601 602 /* 603 ** Usage: btree_delete ID 604 ** 605 ** Delete the entry that the cursor is pointing to 606 */ 607 static int btree_delete( 608 void *NotUsed, 609 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 610 int argc, /* Number of arguments */ 611 const char **argv /* Text of each argument */ 612 ){ 613 BtCursor *pCur; 614 int rc; 615 616 if( argc!=2 ){ 617 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 618 " ID\"", 0); 619 return TCL_ERROR; 620 } 621 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; 622 rc = sqliteBtreeDelete(pCur); 623 if( rc ){ 624 Tcl_AppendResult(interp, errorName(rc), 0); 625 return TCL_ERROR; 626 } 627 return SQLITE_OK; 628 } 629 630 /* 631 ** Usage: btree_insert ID KEY DATA 632 ** 633 ** Create a new entry with the given key and data. If an entry already 634 ** exists with the same key the old entry is overwritten. 635 */ 636 static int btree_insert( 637 void *NotUsed, 638 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 639 int argc, /* Number of arguments */ 640 const char **argv /* Text of each argument */ 641 ){ 642 BtCursor *pCur; 643 int rc; 644 645 if( argc!=4 ){ 646 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 647 " ID KEY DATA\"", 0); 648 return TCL_ERROR; 649 } 650 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; 651 rc = sqliteBtreeInsert(pCur, argv[2], strlen(argv[2]), 652 argv[3], strlen(argv[3])); 653 if( rc ){ 654 Tcl_AppendResult(interp, errorName(rc), 0); 655 return TCL_ERROR; 656 } 657 return SQLITE_OK; 658 } 659 660 /* 661 ** Usage: btree_next ID 662 ** 663 ** Move the cursor to the next entry in the table. Return 0 on success 664 ** or 1 if the cursor was already on the last entry in the table or if 665 ** the table is empty. 666 */ 667 static int btree_next( 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 BtCursor *pCur; 674 int rc; 675 int res = 0; 676 char zBuf[100]; 677 678 if( argc!=2 ){ 679 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 680 " ID\"", 0); 681 return TCL_ERROR; 682 } 683 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; 684 rc = sqliteBtreeNext(pCur, &res); 685 if( rc ){ 686 Tcl_AppendResult(interp, errorName(rc), 0); 687 return TCL_ERROR; 688 } 689 sprintf(zBuf,"%d",res); 690 Tcl_AppendResult(interp, zBuf, 0); 691 return SQLITE_OK; 692 } 693 694 /* 695 ** Usage: btree_prev ID 696 ** 697 ** Move the cursor to the previous entry in the table. Return 0 on 698 ** success and 1 if the cursor was already on the first entry in 699 ** the table or if the table was empty. 700 */ 701 static int btree_prev( 702 void *NotUsed, 703 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 704 int argc, /* Number of arguments */ 705 const char **argv /* Text of each argument */ 706 ){ 707 BtCursor *pCur; 708 int rc; 709 int res = 0; 710 char zBuf[100]; 711 712 if( argc!=2 ){ 713 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 714 " ID\"", 0); 715 return TCL_ERROR; 716 } 717 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; 718 rc = sqliteBtreePrevious(pCur, &res); 719 if( rc ){ 720 Tcl_AppendResult(interp, errorName(rc), 0); 721 return TCL_ERROR; 722 } 723 sprintf(zBuf,"%d",res); 724 Tcl_AppendResult(interp, zBuf, 0); 725 return SQLITE_OK; 726 } 727 728 /* 729 ** Usage: btree_first ID 730 ** 731 ** Move the cursor to the first entry in the table. Return 0 if the 732 ** cursor was left point to something and 1 if the table is empty. 733 */ 734 static int btree_first( 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 int rc; 742 int res = 0; 743 char zBuf[100]; 744 745 if( argc!=2 ){ 746 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 747 " ID\"", 0); 748 return TCL_ERROR; 749 } 750 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; 751 rc = sqliteBtreeFirst(pCur, &res); 752 if( rc ){ 753 Tcl_AppendResult(interp, errorName(rc), 0); 754 return TCL_ERROR; 755 } 756 sprintf(zBuf,"%d",res); 757 Tcl_AppendResult(interp, zBuf, 0); 758 return SQLITE_OK; 759 } 760 761 /* 762 ** Usage: btree_last ID 763 ** 764 ** Move the cursor to the last entry in the table. Return 0 if the 765 ** cursor was left point to something and 1 if the table is empty. 766 */ 767 static int btree_last( 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 = 0; 776 char zBuf[100]; 777 778 if( argc!=2 ){ 779 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 780 " ID\"", 0); 781 return TCL_ERROR; 782 } 783 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; 784 rc = sqliteBtreeLast(pCur, &res); 785 if( rc ){ 786 Tcl_AppendResult(interp, errorName(rc), 0); 787 return TCL_ERROR; 788 } 789 sprintf(zBuf,"%d",res); 790 Tcl_AppendResult(interp, zBuf, 0); 791 return SQLITE_OK; 792 } 793 794 /* 795 ** Usage: btree_key ID 796 ** 797 ** Return the key for the entry at which the cursor is pointing. 798 */ 799 static int btree_key( 800 void *NotUsed, 801 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 802 int argc, /* Number of arguments */ 803 const char **argv /* Text of each argument */ 804 ){ 805 BtCursor *pCur; 806 int rc; 807 int n; 808 char *zBuf; 809 810 if( argc!=2 ){ 811 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 812 " ID\"", 0); 813 return TCL_ERROR; 814 } 815 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; 816 sqliteBtreeKeySize(pCur, &n); 817 zBuf = malloc( n+1 ); 818 rc = sqliteBtreeKey(pCur, 0, n, zBuf); 819 if( rc!=n ){ 820 char zMsg[100]; 821 free(zBuf); 822 sprintf(zMsg, "truncated key: got %d of %d bytes", rc, n); 823 Tcl_AppendResult(interp, zMsg, 0); 824 return TCL_ERROR; 825 } 826 zBuf[n] = 0; 827 Tcl_AppendResult(interp, zBuf, 0); 828 free(zBuf); 829 return SQLITE_OK; 830 } 831 832 /* 833 ** Usage: btree_data ID 834 ** 835 ** Return the data for the entry at which the cursor is pointing. 836 */ 837 static int btree_data( 838 void *NotUsed, 839 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 840 int argc, /* Number of arguments */ 841 const char **argv /* Text of each argument */ 842 ){ 843 BtCursor *pCur; 844 int rc; 845 int n; 846 char *zBuf; 847 848 if( argc!=2 ){ 849 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 850 " ID\"", 0); 851 return TCL_ERROR; 852 } 853 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; 854 sqliteBtreeDataSize(pCur, &n); 855 zBuf = malloc( n+1 ); 856 rc = sqliteBtreeData(pCur, 0, n, zBuf); 857 if( rc!=n ){ 858 char zMsg[100]; 859 free(zBuf); 860 sprintf(zMsg, "truncated data: got %d of %d bytes", rc, n); 861 Tcl_AppendResult(interp, zMsg, 0); 862 return TCL_ERROR; 863 } 864 zBuf[n] = 0; 865 Tcl_AppendResult(interp, zBuf, 0); 866 free(zBuf); 867 return SQLITE_OK; 868 } 869 870 /* 871 ** Usage: btree_payload_size ID 872 ** 873 ** Return the number of bytes of payload 874 */ 875 static int btree_payload_size( 876 void *NotUsed, 877 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 878 int argc, /* Number of arguments */ 879 const char **argv /* Text of each argument */ 880 ){ 881 BtCursor *pCur; 882 int n1, n2; 883 char zBuf[50]; 884 885 if( argc!=2 ){ 886 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 887 " ID\"", 0); 888 return TCL_ERROR; 889 } 890 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; 891 sqliteBtreeKeySize(pCur, &n1); 892 sqliteBtreeDataSize(pCur, &n2); 893 sprintf(zBuf, "%d", n1+n2); 894 Tcl_AppendResult(interp, zBuf, 0); 895 return SQLITE_OK; 896 } 897 898 /* 899 ** Usage: btree_cursor_dump ID 900 ** 901 ** Return eight integers containing information about the entry the 902 ** cursor is pointing to: 903 ** 904 ** aResult[0] = The page number 905 ** aResult[1] = The entry number 906 ** aResult[2] = Total number of entries on this page 907 ** aResult[3] = Size of this entry 908 ** aResult[4] = Number of free bytes on this page 909 ** aResult[5] = Number of free blocks on the page 910 ** aResult[6] = Page number of the left child of this entry 911 ** aResult[7] = Page number of the right child for the whole page 912 */ 913 static int btree_cursor_dump( 914 void *NotUsed, 915 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 916 int argc, /* Number of arguments */ 917 const char **argv /* Text of each argument */ 918 ){ 919 BtCursor *pCur; 920 int rc; 921 int i, j; 922 int aResult[8]; 923 char zBuf[400]; 924 925 if( argc!=2 ){ 926 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 927 " ID\"", 0); 928 return TCL_ERROR; 929 } 930 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; 931 rc = sqliteBtreeCursorDump(pCur, aResult); 932 if( rc ){ 933 Tcl_AppendResult(interp, errorName(rc), 0); 934 return TCL_ERROR; 935 } 936 j = 0; 937 for(i=0; i<sizeof(aResult)/sizeof(aResult[0]); i++){ 938 sprintf(&zBuf[j]," %d", aResult[i]); 939 j += strlen(&zBuf[j]); 940 } 941 Tcl_AppendResult(interp, &zBuf[1], 0); 942 return SQLITE_OK; 943 } 944 945 /* 946 ** Register commands with the TCL interpreter. 947 */ 948 int Sqlitetest3_Init(Tcl_Interp *interp){ 949 static struct { 950 char *zName; 951 Tcl_CmdProc *xProc; 952 } aCmd[] = { 953 { "btree_open", (Tcl_CmdProc*)btree_open }, 954 { "btree_close", (Tcl_CmdProc*)btree_close }, 955 { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction }, 956 { "btree_commit", (Tcl_CmdProc*)btree_commit }, 957 { "btree_rollback", (Tcl_CmdProc*)btree_rollback }, 958 { "btree_create_table", (Tcl_CmdProc*)btree_create_table }, 959 { "btree_drop_table", (Tcl_CmdProc*)btree_drop_table }, 960 { "btree_clear_table", (Tcl_CmdProc*)btree_clear_table }, 961 { "btree_get_meta", (Tcl_CmdProc*)btree_get_meta }, 962 { "btree_update_meta", (Tcl_CmdProc*)btree_update_meta }, 963 { "btree_page_dump", (Tcl_CmdProc*)btree_page_dump }, 964 { "btree_tree_dump", (Tcl_CmdProc*)btree_tree_dump }, 965 { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats }, 966 { "btree_pager_ref_dump", (Tcl_CmdProc*)btree_pager_ref_dump }, 967 { "btree_cursor", (Tcl_CmdProc*)btree_cursor }, 968 { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor }, 969 { "btree_move_to", (Tcl_CmdProc*)btree_move_to }, 970 { "btree_delete", (Tcl_CmdProc*)btree_delete }, 971 { "btree_insert", (Tcl_CmdProc*)btree_insert }, 972 { "btree_next", (Tcl_CmdProc*)btree_next }, 973 { "btree_prev", (Tcl_CmdProc*)btree_prev }, 974 { "btree_key", (Tcl_CmdProc*)btree_key }, 975 { "btree_data", (Tcl_CmdProc*)btree_data }, 976 { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size }, 977 { "btree_first", (Tcl_CmdProc*)btree_first }, 978 { "btree_last", (Tcl_CmdProc*)btree_last }, 979 { "btree_cursor_dump", (Tcl_CmdProc*)btree_cursor_dump }, 980 { "btree_integrity_check", (Tcl_CmdProc*)btree_integrity_check }, 981 }; 982 int i; 983 984 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 985 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 986 } 987 Tcl_LinkVar(interp, "pager_refinfo_enable", (char*)&pager_refinfo_enable, 988 TCL_LINK_INT); 989 Tcl_LinkVar(interp, "btree_native_byte_order",(char*)&btree_native_byte_order, 990 TCL_LINK_INT); 991 return TCL_OK; 992 } 993