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