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