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