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