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 #include "sqliteInt.h" 17 #include "btreeInt.h" 18 #if defined(INCLUDE_SQLITE_TCL_H) 19 # include "sqlite_tcl.h" 20 #else 21 # include "tcl.h" 22 #endif 23 #include <stdlib.h> 24 #include <string.h> 25 26 extern const char *sqlite3ErrName(int); 27 28 /* 29 ** A bogus sqlite3 connection structure for use in the btree 30 ** tests. 31 */ 32 static sqlite3 sDb; 33 static int nRefSqlite3 = 0; 34 35 /* 36 ** Usage: btree_open FILENAME NCACHE 37 ** 38 ** Open a new database 39 */ 40 static int SQLITE_TCLAPI btree_open( 41 void *NotUsed, 42 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 43 int argc, /* Number of arguments */ 44 const char **argv /* Text of each argument */ 45 ){ 46 Btree *pBt; 47 int rc, nCache; 48 char zBuf[100]; 49 int n; 50 char *zFilename; 51 if( argc!=3 ){ 52 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 53 " FILENAME NCACHE FLAGS\"", 0); 54 return TCL_ERROR; 55 } 56 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; 57 nRefSqlite3++; 58 if( nRefSqlite3==1 ){ 59 sDb.pVfs = sqlite3_vfs_find(0); 60 sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE); 61 sqlite3_mutex_enter(sDb.mutex); 62 } 63 n = (int)strlen(argv[1]); 64 zFilename = sqlite3_malloc( n+2 ); 65 if( zFilename==0 ) return TCL_ERROR; 66 memcpy(zFilename, argv[1], n+1); 67 zFilename[n+1] = 0; 68 rc = sqlite3BtreeOpen(sDb.pVfs, zFilename, &sDb, &pBt, 0, 69 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB); 70 sqlite3_free(zFilename); 71 if( rc!=SQLITE_OK ){ 72 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); 73 return TCL_ERROR; 74 } 75 sqlite3BtreeSetCacheSize(pBt, nCache); 76 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt); 77 Tcl_AppendResult(interp, zBuf, 0); 78 return TCL_OK; 79 } 80 81 /* 82 ** Usage: btree_close ID 83 ** 84 ** Close the given database. 85 */ 86 static int SQLITE_TCLAPI btree_close( 87 void *NotUsed, 88 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 89 int argc, /* Number of arguments */ 90 const char **argv /* Text of each argument */ 91 ){ 92 Btree *pBt; 93 int rc; 94 if( argc!=2 ){ 95 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 96 " ID\"", 0); 97 return TCL_ERROR; 98 } 99 pBt = sqlite3TestTextToPtr(argv[1]); 100 rc = sqlite3BtreeClose(pBt); 101 if( rc!=SQLITE_OK ){ 102 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); 103 return TCL_ERROR; 104 } 105 nRefSqlite3--; 106 if( nRefSqlite3==0 ){ 107 sqlite3_mutex_leave(sDb.mutex); 108 sqlite3_mutex_free(sDb.mutex); 109 sDb.mutex = 0; 110 sDb.pVfs = 0; 111 } 112 return TCL_OK; 113 } 114 115 116 /* 117 ** Usage: btree_begin_transaction ID 118 ** 119 ** Start a new transaction 120 */ 121 static int SQLITE_TCLAPI btree_begin_transaction( 122 void *NotUsed, 123 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 124 int argc, /* Number of arguments */ 125 const char **argv /* Text of each argument */ 126 ){ 127 Btree *pBt; 128 int rc; 129 if( argc!=2 ){ 130 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 131 " ID\"", 0); 132 return TCL_ERROR; 133 } 134 pBt = sqlite3TestTextToPtr(argv[1]); 135 sqlite3BtreeEnter(pBt); 136 rc = sqlite3BtreeBeginTrans(pBt, 1); 137 sqlite3BtreeLeave(pBt); 138 if( rc!=SQLITE_OK ){ 139 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); 140 return TCL_ERROR; 141 } 142 return TCL_OK; 143 } 144 145 /* 146 ** Usage: btree_pager_stats ID 147 ** 148 ** Returns pager statistics 149 */ 150 static int SQLITE_TCLAPI btree_pager_stats( 151 void *NotUsed, 152 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 153 int argc, /* Number of arguments */ 154 const char **argv /* Text of each argument */ 155 ){ 156 Btree *pBt; 157 int i; 158 int *a; 159 160 if( argc!=2 ){ 161 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 162 " ID\"", 0); 163 return TCL_ERROR; 164 } 165 pBt = sqlite3TestTextToPtr(argv[1]); 166 167 /* Normally in this file, with a b-tree handle opened using the 168 ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly. 169 ** But this function is sometimes called with a btree handle obtained 170 ** from an open SQLite connection (using [btree_from_db]). In this case 171 ** we need to obtain the mutex for the controlling SQLite handle before 172 ** it is safe to call sqlite3BtreeEnter(). 173 */ 174 sqlite3_mutex_enter(pBt->db->mutex); 175 176 sqlite3BtreeEnter(pBt); 177 a = sqlite3PagerStats(sqlite3BtreePager(pBt)); 178 for(i=0; i<11; i++){ 179 static char *zName[] = { 180 "ref", "page", "max", "size", "state", "err", 181 "hit", "miss", "ovfl", "read", "write" 182 }; 183 char zBuf[100]; 184 Tcl_AppendElement(interp, zName[i]); 185 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]); 186 Tcl_AppendElement(interp, zBuf); 187 } 188 sqlite3BtreeLeave(pBt); 189 190 /* Release the mutex on the SQLite handle that controls this b-tree */ 191 sqlite3_mutex_leave(pBt->db->mutex); 192 return TCL_OK; 193 } 194 195 /* 196 ** Usage: btree_cursor ID TABLENUM WRITEABLE 197 ** 198 ** Create a new cursor. Return the ID for the cursor. 199 */ 200 static int SQLITE_TCLAPI btree_cursor( 201 void *NotUsed, 202 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 203 int argc, /* Number of arguments */ 204 const char **argv /* Text of each argument */ 205 ){ 206 Btree *pBt; 207 int iTable; 208 BtCursor *pCur; 209 int rc = SQLITE_OK; 210 int wrFlag; 211 char zBuf[30]; 212 213 if( argc!=4 ){ 214 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 215 " ID TABLENUM WRITEABLE\"", 0); 216 return TCL_ERROR; 217 } 218 pBt = sqlite3TestTextToPtr(argv[1]); 219 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; 220 if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR; 221 if( wrFlag ) wrFlag = BTREE_WRCSR; 222 pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize()); 223 memset(pCur, 0, sqlite3BtreeCursorSize()); 224 sqlite3_mutex_enter(pBt->db->mutex); 225 sqlite3BtreeEnter(pBt); 226 #ifndef SQLITE_OMIT_SHARED_CACHE 227 rc = sqlite3BtreeLockTable(pBt, iTable, !!wrFlag); 228 #endif 229 if( rc==SQLITE_OK ){ 230 rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur); 231 } 232 sqlite3BtreeLeave(pBt); 233 sqlite3_mutex_leave(pBt->db->mutex); 234 if( rc ){ 235 ckfree((char *)pCur); 236 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); 237 return TCL_ERROR; 238 } 239 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur); 240 Tcl_AppendResult(interp, zBuf, 0); 241 return SQLITE_OK; 242 } 243 244 /* 245 ** Usage: btree_close_cursor ID 246 ** 247 ** Close a cursor opened using btree_cursor. 248 */ 249 static int SQLITE_TCLAPI btree_close_cursor( 250 void *NotUsed, 251 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 252 int argc, /* Number of arguments */ 253 const char **argv /* Text of each argument */ 254 ){ 255 BtCursor *pCur; 256 int rc; 257 258 if( argc!=2 ){ 259 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 260 " ID\"", 0); 261 return TCL_ERROR; 262 } 263 pCur = sqlite3TestTextToPtr(argv[1]); 264 #if SQLITE_THREADSAFE>0 265 { 266 Btree *pBt = pCur->pBtree; 267 sqlite3_mutex_enter(pBt->db->mutex); 268 sqlite3BtreeEnter(pBt); 269 rc = sqlite3BtreeCloseCursor(pCur); 270 sqlite3BtreeLeave(pBt); 271 sqlite3_mutex_leave(pBt->db->mutex); 272 } 273 #else 274 rc = sqlite3BtreeCloseCursor(pCur); 275 #endif 276 ckfree((char *)pCur); 277 if( rc ){ 278 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); 279 return TCL_ERROR; 280 } 281 return SQLITE_OK; 282 } 283 284 /* 285 ** Usage: btree_next ID 286 ** 287 ** Move the cursor to the next entry in the table. Return 0 on success 288 ** or 1 if the cursor was already on the last entry in the table or if 289 ** the table is empty. 290 */ 291 static int SQLITE_TCLAPI btree_next( 292 void *NotUsed, 293 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 294 int argc, /* Number of arguments */ 295 const char **argv /* Text of each argument */ 296 ){ 297 BtCursor *pCur; 298 int rc; 299 int res = 0; 300 char zBuf[100]; 301 302 if( argc!=2 ){ 303 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 304 " ID\"", 0); 305 return TCL_ERROR; 306 } 307 pCur = sqlite3TestTextToPtr(argv[1]); 308 sqlite3BtreeEnter(pCur->pBtree); 309 rc = sqlite3BtreeNext(pCur, 0); 310 if( rc==SQLITE_DONE ){ 311 res = 1; 312 rc = SQLITE_OK; 313 } 314 sqlite3BtreeLeave(pCur->pBtree); 315 if( rc ){ 316 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); 317 return TCL_ERROR; 318 } 319 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 320 Tcl_AppendResult(interp, zBuf, 0); 321 return SQLITE_OK; 322 } 323 324 /* 325 ** Usage: btree_first ID 326 ** 327 ** Move the cursor to the first entry in the table. Return 0 if the 328 ** cursor was left point to something and 1 if the table is empty. 329 */ 330 static int SQLITE_TCLAPI btree_first( 331 void *NotUsed, 332 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 333 int argc, /* Number of arguments */ 334 const char **argv /* Text of each argument */ 335 ){ 336 BtCursor *pCur; 337 int rc; 338 int res = 0; 339 char zBuf[100]; 340 341 if( argc!=2 ){ 342 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 343 " ID\"", 0); 344 return TCL_ERROR; 345 } 346 pCur = sqlite3TestTextToPtr(argv[1]); 347 sqlite3BtreeEnter(pCur->pBtree); 348 rc = sqlite3BtreeFirst(pCur, &res); 349 sqlite3BtreeLeave(pCur->pBtree); 350 if( rc ){ 351 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); 352 return TCL_ERROR; 353 } 354 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 355 Tcl_AppendResult(interp, zBuf, 0); 356 return SQLITE_OK; 357 } 358 359 /* 360 ** Usage: btree_eof ID 361 ** 362 ** Return TRUE if the given cursor is not pointing at a valid entry. 363 ** Return FALSE if the cursor does point to a valid entry. 364 */ 365 static int SQLITE_TCLAPI btree_eof( 366 void *NotUsed, 367 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 368 int argc, /* Number of arguments */ 369 const char **argv /* Text of each argument */ 370 ){ 371 BtCursor *pCur; 372 int rc; 373 char zBuf[50]; 374 375 if( argc!=2 ){ 376 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 377 " ID\"", 0); 378 return TCL_ERROR; 379 } 380 pCur = sqlite3TestTextToPtr(argv[1]); 381 sqlite3BtreeEnter(pCur->pBtree); 382 rc = sqlite3BtreeEof(pCur); 383 sqlite3BtreeLeave(pCur->pBtree); 384 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc); 385 Tcl_AppendResult(interp, zBuf, 0); 386 return SQLITE_OK; 387 } 388 389 /* 390 ** Usage: btree_payload_size ID 391 ** 392 ** Return the number of bytes of payload 393 */ 394 static int SQLITE_TCLAPI btree_payload_size( 395 void *NotUsed, 396 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 397 int argc, /* Number of arguments */ 398 const char **argv /* Text of each argument */ 399 ){ 400 BtCursor *pCur; 401 u32 n; 402 char zBuf[50]; 403 404 if( argc!=2 ){ 405 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 406 " ID\"", 0); 407 return TCL_ERROR; 408 } 409 pCur = sqlite3TestTextToPtr(argv[1]); 410 sqlite3BtreeEnter(pCur->pBtree); 411 n = sqlite3BtreePayloadSize(pCur); 412 sqlite3BtreeLeave(pCur->pBtree); 413 sqlite3_snprintf(sizeof(zBuf),zBuf, "%u", n); 414 Tcl_AppendResult(interp, zBuf, 0); 415 return SQLITE_OK; 416 } 417 418 /* 419 ** usage: varint_test START MULTIPLIER COUNT INCREMENT 420 ** 421 ** This command tests the putVarint() and getVarint() 422 ** routines, both for accuracy and for speed. 423 ** 424 ** An integer is written using putVarint() and read back with 425 ** getVarint() and varified to be unchanged. This repeats COUNT 426 ** times. The first integer is START*MULTIPLIER. Each iteration 427 ** increases the integer by INCREMENT. 428 ** 429 ** This command returns nothing if it works. It returns an error message 430 ** if something goes wrong. 431 */ 432 static int SQLITE_TCLAPI btree_varint_test( 433 void *NotUsed, 434 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 435 int argc, /* Number of arguments */ 436 const char **argv /* Text of each argument */ 437 ){ 438 u32 start, mult, count, incr; 439 u64 in, out; 440 int n1, n2, i, j; 441 unsigned char zBuf[100]; 442 if( argc!=5 ){ 443 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 444 " START MULTIPLIER COUNT INCREMENT\"", 0); 445 return TCL_ERROR; 446 } 447 if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR; 448 if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR; 449 if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR; 450 if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR; 451 in = start; 452 in *= mult; 453 for(i=0; i<(int)count; i++){ 454 char zErr[200]; 455 n1 = putVarint(zBuf, in); 456 if( n1>9 || n1<1 ){ 457 sqlite3_snprintf(sizeof(zErr), zErr, 458 "putVarint returned %d - should be between 1 and 9", n1); 459 Tcl_AppendResult(interp, zErr, 0); 460 return TCL_ERROR; 461 } 462 n2 = getVarint(zBuf, &out); 463 if( n1!=n2 ){ 464 sqlite3_snprintf(sizeof(zErr), zErr, 465 "putVarint returned %d and getVarint returned %d", n1, n2); 466 Tcl_AppendResult(interp, zErr, 0); 467 return TCL_ERROR; 468 } 469 if( in!=out ){ 470 sqlite3_snprintf(sizeof(zErr), zErr, 471 "Wrote 0x%016llx and got back 0x%016llx", in, out); 472 Tcl_AppendResult(interp, zErr, 0); 473 return TCL_ERROR; 474 } 475 if( (in & 0xffffffff)==in ){ 476 u32 out32; 477 n2 = getVarint32(zBuf, out32); 478 out = out32; 479 if( n1!=n2 ){ 480 sqlite3_snprintf(sizeof(zErr), zErr, 481 "putVarint returned %d and GetVarint32 returned %d", 482 n1, n2); 483 Tcl_AppendResult(interp, zErr, 0); 484 return TCL_ERROR; 485 } 486 if( in!=out ){ 487 sqlite3_snprintf(sizeof(zErr), zErr, 488 "Wrote 0x%016llx and got back 0x%016llx from GetVarint32", 489 in, out); 490 Tcl_AppendResult(interp, zErr, 0); 491 return TCL_ERROR; 492 } 493 } 494 495 /* In order to get realistic timings, run getVarint 19 more times. 496 ** This is because getVarint is called about 20 times more often 497 ** than putVarint. 498 */ 499 for(j=0; j<19; j++){ 500 getVarint(zBuf, &out); 501 } 502 in += incr; 503 } 504 return TCL_OK; 505 } 506 507 /* 508 ** usage: btree_from_db DB-HANDLE 509 ** 510 ** This command returns the btree handle for the main database associated 511 ** with the database-handle passed as the argument. Example usage: 512 ** 513 ** sqlite3 db test.db 514 ** set bt [btree_from_db db] 515 */ 516 static int SQLITE_TCLAPI btree_from_db( 517 void *NotUsed, 518 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 519 int argc, /* Number of arguments */ 520 const char **argv /* Text of each argument */ 521 ){ 522 char zBuf[100]; 523 Tcl_CmdInfo info; 524 sqlite3 *db; 525 Btree *pBt; 526 int iDb = 0; 527 528 if( argc!=2 && argc!=3 ){ 529 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 530 " DB-HANDLE ?N?\"", 0); 531 return TCL_ERROR; 532 } 533 534 if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){ 535 Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0); 536 return TCL_ERROR; 537 } 538 if( argc==3 ){ 539 iDb = atoi(argv[2]); 540 } 541 542 db = *((sqlite3 **)info.objClientData); 543 assert( db ); 544 545 pBt = db->aDb[iDb].pBt; 546 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt); 547 Tcl_SetResult(interp, zBuf, TCL_VOLATILE); 548 return TCL_OK; 549 } 550 551 /* 552 ** Usage: btree_ismemdb ID 553 ** 554 ** Return true if the B-Tree is currently stored entirely in memory. 555 */ 556 static int SQLITE_TCLAPI btree_ismemdb( 557 void *NotUsed, 558 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 559 int argc, /* Number of arguments */ 560 const char **argv /* Text of each argument */ 561 ){ 562 Btree *pBt; 563 int res; 564 sqlite3_file *pFile; 565 566 if( argc!=2 ){ 567 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 568 " ID\"", 0); 569 return TCL_ERROR; 570 } 571 pBt = sqlite3TestTextToPtr(argv[1]); 572 sqlite3_mutex_enter(pBt->db->mutex); 573 sqlite3BtreeEnter(pBt); 574 pFile = sqlite3PagerFile(sqlite3BtreePager(pBt)); 575 res = (pFile->pMethods==0); 576 sqlite3BtreeLeave(pBt); 577 sqlite3_mutex_leave(pBt->db->mutex); 578 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res)); 579 return SQLITE_OK; 580 } 581 582 /* 583 ** usage: btree_set_cache_size ID NCACHE 584 ** 585 ** Set the size of the cache used by btree $ID. 586 */ 587 static int SQLITE_TCLAPI btree_set_cache_size( 588 void *NotUsed, 589 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 590 int argc, /* Number of arguments */ 591 const char **argv /* Text of each argument */ 592 ){ 593 int nCache; 594 Btree *pBt; 595 596 if( argc!=3 ){ 597 Tcl_AppendResult( 598 interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", 0); 599 return TCL_ERROR; 600 } 601 pBt = sqlite3TestTextToPtr(argv[1]); 602 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; 603 604 sqlite3_mutex_enter(pBt->db->mutex); 605 sqlite3BtreeEnter(pBt); 606 sqlite3BtreeSetCacheSize(pBt, nCache); 607 sqlite3BtreeLeave(pBt); 608 sqlite3_mutex_leave(pBt->db->mutex); 609 return TCL_OK; 610 } 611 612 /* 613 ** usage: btree_insert CSR ?KEY? VALUE 614 ** 615 ** Set the size of the cache used by btree $ID. 616 */ 617 static int SQLITE_TCLAPI btree_insert( 618 ClientData clientData, 619 Tcl_Interp *interp, 620 int objc, 621 Tcl_Obj *const objv[] 622 ){ 623 BtCursor *pCur; 624 int rc; 625 BtreePayload x; 626 627 if( objc!=4 && objc!=3 ){ 628 Tcl_WrongNumArgs(interp, 1, objv, "?-intkey? CSR KEY VALUE"); 629 return TCL_ERROR; 630 } 631 632 memset(&x, 0, sizeof(x)); 633 if( objc==4 ){ 634 if( Tcl_GetIntFromObj(interp, objv[2], &rc) ) return TCL_ERROR; 635 x.nKey = rc; 636 x.pData = (void*)Tcl_GetByteArrayFromObj(objv[3], &x.nData); 637 }else{ 638 x.pKey = (void*)Tcl_GetByteArrayFromObj(objv[2], &rc); 639 x.nKey = rc; 640 } 641 pCur = (BtCursor*)sqlite3TestTextToPtr(Tcl_GetString(objv[1])); 642 643 sqlite3_mutex_enter(pCur->pBtree->db->mutex); 644 sqlite3BtreeEnter(pCur->pBtree); 645 rc = sqlite3BtreeInsert(pCur, &x, 0, 0); 646 sqlite3BtreeLeave(pCur->pBtree); 647 sqlite3_mutex_leave(pCur->pBtree->db->mutex); 648 649 Tcl_ResetResult(interp); 650 if( rc ){ 651 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); 652 return TCL_ERROR; 653 } 654 return TCL_OK; 655 } 656 657 658 /* 659 ** Register commands with the TCL interpreter. 660 */ 661 int Sqlitetest3_Init(Tcl_Interp *interp){ 662 static struct { 663 char *zName; 664 Tcl_CmdProc *xProc; 665 } aCmd[] = { 666 { "btree_open", (Tcl_CmdProc*)btree_open }, 667 { "btree_close", (Tcl_CmdProc*)btree_close }, 668 { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction }, 669 { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats }, 670 { "btree_cursor", (Tcl_CmdProc*)btree_cursor }, 671 { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor }, 672 { "btree_next", (Tcl_CmdProc*)btree_next }, 673 { "btree_eof", (Tcl_CmdProc*)btree_eof }, 674 { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size }, 675 { "btree_first", (Tcl_CmdProc*)btree_first }, 676 { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test }, 677 { "btree_from_db", (Tcl_CmdProc*)btree_from_db }, 678 { "btree_ismemdb", (Tcl_CmdProc*)btree_ismemdb }, 679 { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size } 680 }; 681 int i; 682 683 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 684 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 685 } 686 687 Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0); 688 689 return TCL_OK; 690 } 691