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 sqlite3_mutex_enter(pBt->db->mutex); 221 sqlite3BtreeEnter(pBt); 222 #ifndef SQLITE_OMIT_SHARED_CACHE 223 rc = sqlite3BtreeLockTable(pBt, iTable, !!wrFlag); 224 #endif 225 if( rc==SQLITE_OK ){ 226 rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur); 227 } 228 sqlite3BtreeLeave(pBt); 229 sqlite3_mutex_leave(pBt->db->mutex); 230 if( rc ){ 231 ckfree((char *)pCur); 232 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); 233 return TCL_ERROR; 234 } 235 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur); 236 Tcl_AppendResult(interp, zBuf, 0); 237 return SQLITE_OK; 238 } 239 240 /* 241 ** Usage: btree_close_cursor ID 242 ** 243 ** Close a cursor opened using btree_cursor. 244 */ 245 static int btree_close_cursor( 246 void *NotUsed, 247 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 248 int argc, /* Number of arguments */ 249 const char **argv /* Text of each argument */ 250 ){ 251 BtCursor *pCur; 252 Btree *pBt; 253 int rc; 254 255 if( argc!=2 ){ 256 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 257 " ID\"", 0); 258 return TCL_ERROR; 259 } 260 pCur = sqlite3TestTextToPtr(argv[1]); 261 pBt = pCur->pBtree; 262 sqlite3_mutex_enter(pBt->db->mutex); 263 sqlite3BtreeEnter(pBt); 264 rc = sqlite3BtreeCloseCursor(pCur); 265 sqlite3BtreeLeave(pBt); 266 sqlite3_mutex_leave(pBt->db->mutex); 267 ckfree((char *)pCur); 268 if( rc ){ 269 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); 270 return TCL_ERROR; 271 } 272 return SQLITE_OK; 273 } 274 275 /* 276 ** Usage: btree_next ID 277 ** 278 ** Move the cursor to the next entry in the table. Return 0 on success 279 ** or 1 if the cursor was already on the last entry in the table or if 280 ** the table is empty. 281 */ 282 static int btree_next( 283 void *NotUsed, 284 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 285 int argc, /* Number of arguments */ 286 const char **argv /* Text of each argument */ 287 ){ 288 BtCursor *pCur; 289 int rc; 290 int res = 0; 291 char zBuf[100]; 292 293 if( argc!=2 ){ 294 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 295 " ID\"", 0); 296 return TCL_ERROR; 297 } 298 pCur = sqlite3TestTextToPtr(argv[1]); 299 sqlite3BtreeEnter(pCur->pBtree); 300 rc = sqlite3BtreeNext(pCur, &res); 301 sqlite3BtreeLeave(pCur->pBtree); 302 if( rc ){ 303 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); 304 return TCL_ERROR; 305 } 306 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 307 Tcl_AppendResult(interp, zBuf, 0); 308 return SQLITE_OK; 309 } 310 311 /* 312 ** Usage: btree_first ID 313 ** 314 ** Move the cursor to the first entry in the table. Return 0 if the 315 ** cursor was left point to something and 1 if the table is empty. 316 */ 317 static int btree_first( 318 void *NotUsed, 319 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 320 int argc, /* Number of arguments */ 321 const char **argv /* Text of each argument */ 322 ){ 323 BtCursor *pCur; 324 int rc; 325 int res = 0; 326 char zBuf[100]; 327 328 if( argc!=2 ){ 329 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 330 " ID\"", 0); 331 return TCL_ERROR; 332 } 333 pCur = sqlite3TestTextToPtr(argv[1]); 334 sqlite3BtreeEnter(pCur->pBtree); 335 rc = sqlite3BtreeFirst(pCur, &res); 336 sqlite3BtreeLeave(pCur->pBtree); 337 if( rc ){ 338 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); 339 return TCL_ERROR; 340 } 341 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); 342 Tcl_AppendResult(interp, zBuf, 0); 343 return SQLITE_OK; 344 } 345 346 /* 347 ** Usage: btree_eof ID 348 ** 349 ** Return TRUE if the given cursor is not pointing at a valid entry. 350 ** Return FALSE if the cursor does point to a valid entry. 351 */ 352 static int btree_eof( 353 void *NotUsed, 354 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 355 int argc, /* Number of arguments */ 356 const char **argv /* Text of each argument */ 357 ){ 358 BtCursor *pCur; 359 int rc; 360 char zBuf[50]; 361 362 if( argc!=2 ){ 363 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 364 " ID\"", 0); 365 return TCL_ERROR; 366 } 367 pCur = sqlite3TestTextToPtr(argv[1]); 368 sqlite3BtreeEnter(pCur->pBtree); 369 rc = sqlite3BtreeEof(pCur); 370 sqlite3BtreeLeave(pCur->pBtree); 371 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc); 372 Tcl_AppendResult(interp, zBuf, 0); 373 return SQLITE_OK; 374 } 375 376 /* 377 ** Usage: btree_payload_size ID 378 ** 379 ** Return the number of bytes of payload 380 */ 381 static int btree_payload_size( 382 void *NotUsed, 383 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 384 int argc, /* Number of arguments */ 385 const char **argv /* Text of each argument */ 386 ){ 387 BtCursor *pCur; 388 int n2; 389 u64 n1; 390 char zBuf[50]; 391 392 if( argc!=2 ){ 393 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 394 " ID\"", 0); 395 return TCL_ERROR; 396 } 397 pCur = sqlite3TestTextToPtr(argv[1]); 398 sqlite3BtreeEnter(pCur->pBtree); 399 400 /* The cursor may be in "require-seek" state. If this is the case, the 401 ** call to BtreeDataSize() will fix it. */ 402 sqlite3BtreeDataSize(pCur, (u32*)&n2); 403 if( pCur->apPage[pCur->iPage]->intKey ){ 404 n1 = 0; 405 }else{ 406 sqlite3BtreeKeySize(pCur, (i64*)&n1); 407 } 408 sqlite3BtreeLeave(pCur->pBtree); 409 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2)); 410 Tcl_AppendResult(interp, zBuf, 0); 411 return SQLITE_OK; 412 } 413 414 /* 415 ** usage: varint_test START MULTIPLIER COUNT INCREMENT 416 ** 417 ** This command tests the putVarint() and getVarint() 418 ** routines, both for accuracy and for speed. 419 ** 420 ** An integer is written using putVarint() and read back with 421 ** getVarint() and varified to be unchanged. This repeats COUNT 422 ** times. The first integer is START*MULTIPLIER. Each iteration 423 ** increases the integer by INCREMENT. 424 ** 425 ** This command returns nothing if it works. It returns an error message 426 ** if something goes wrong. 427 */ 428 static int btree_varint_test( 429 void *NotUsed, 430 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 431 int argc, /* Number of arguments */ 432 const char **argv /* Text of each argument */ 433 ){ 434 u32 start, mult, count, incr; 435 u64 in, out; 436 int n1, n2, i, j; 437 unsigned char zBuf[100]; 438 if( argc!=5 ){ 439 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 440 " START MULTIPLIER COUNT INCREMENT\"", 0); 441 return TCL_ERROR; 442 } 443 if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR; 444 if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR; 445 if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR; 446 if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR; 447 in = start; 448 in *= mult; 449 for(i=0; i<(int)count; i++){ 450 char zErr[200]; 451 n1 = putVarint(zBuf, in); 452 if( n1>9 || n1<1 ){ 453 sqlite3_snprintf(sizeof(zErr), zErr, 454 "putVarint returned %d - should be between 1 and 9", n1); 455 Tcl_AppendResult(interp, zErr, 0); 456 return TCL_ERROR; 457 } 458 n2 = getVarint(zBuf, &out); 459 if( n1!=n2 ){ 460 sqlite3_snprintf(sizeof(zErr), zErr, 461 "putVarint returned %d and getVarint returned %d", n1, n2); 462 Tcl_AppendResult(interp, zErr, 0); 463 return TCL_ERROR; 464 } 465 if( in!=out ){ 466 sqlite3_snprintf(sizeof(zErr), zErr, 467 "Wrote 0x%016llx and got back 0x%016llx", in, out); 468 Tcl_AppendResult(interp, zErr, 0); 469 return TCL_ERROR; 470 } 471 if( (in & 0xffffffff)==in ){ 472 u32 out32; 473 n2 = getVarint32(zBuf, out32); 474 out = out32; 475 if( n1!=n2 ){ 476 sqlite3_snprintf(sizeof(zErr), zErr, 477 "putVarint returned %d and GetVarint32 returned %d", 478 n1, n2); 479 Tcl_AppendResult(interp, zErr, 0); 480 return TCL_ERROR; 481 } 482 if( in!=out ){ 483 sqlite3_snprintf(sizeof(zErr), zErr, 484 "Wrote 0x%016llx and got back 0x%016llx from GetVarint32", 485 in, out); 486 Tcl_AppendResult(interp, zErr, 0); 487 return TCL_ERROR; 488 } 489 } 490 491 /* In order to get realistic timings, run getVarint 19 more times. 492 ** This is because getVarint is called about 20 times more often 493 ** than putVarint. 494 */ 495 for(j=0; j<19; j++){ 496 getVarint(zBuf, &out); 497 } 498 in += incr; 499 } 500 return TCL_OK; 501 } 502 503 /* 504 ** usage: btree_from_db DB-HANDLE 505 ** 506 ** This command returns the btree handle for the main database associated 507 ** with the database-handle passed as the argument. Example usage: 508 ** 509 ** sqlite3 db test.db 510 ** set bt [btree_from_db db] 511 */ 512 static int btree_from_db( 513 void *NotUsed, 514 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 515 int argc, /* Number of arguments */ 516 const char **argv /* Text of each argument */ 517 ){ 518 char zBuf[100]; 519 Tcl_CmdInfo info; 520 sqlite3 *db; 521 Btree *pBt; 522 int iDb = 0; 523 524 if( argc!=2 && argc!=3 ){ 525 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 526 " DB-HANDLE ?N?\"", 0); 527 return TCL_ERROR; 528 } 529 530 if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){ 531 Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0); 532 return TCL_ERROR; 533 } 534 if( argc==3 ){ 535 iDb = atoi(argv[2]); 536 } 537 538 db = *((sqlite3 **)info.objClientData); 539 assert( db ); 540 541 pBt = db->aDb[iDb].pBt; 542 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt); 543 Tcl_SetResult(interp, zBuf, TCL_VOLATILE); 544 return TCL_OK; 545 } 546 547 /* 548 ** Usage: btree_ismemdb ID 549 ** 550 ** Return true if the B-Tree is in-memory. 551 */ 552 static int btree_ismemdb( 553 void *NotUsed, 554 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 555 int argc, /* Number of arguments */ 556 const char **argv /* Text of each argument */ 557 ){ 558 Btree *pBt; 559 int res; 560 561 if( argc!=2 ){ 562 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 563 " ID\"", 0); 564 return TCL_ERROR; 565 } 566 pBt = sqlite3TestTextToPtr(argv[1]); 567 sqlite3_mutex_enter(pBt->db->mutex); 568 sqlite3BtreeEnter(pBt); 569 res = sqlite3PagerIsMemdb(sqlite3BtreePager(pBt)); 570 sqlite3BtreeLeave(pBt); 571 sqlite3_mutex_leave(pBt->db->mutex); 572 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res)); 573 return SQLITE_OK; 574 } 575 576 /* 577 ** usage: btree_set_cache_size ID NCACHE 578 ** 579 ** Set the size of the cache used by btree $ID. 580 */ 581 static int btree_set_cache_size( 582 void *NotUsed, 583 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 584 int argc, /* Number of arguments */ 585 const char **argv /* Text of each argument */ 586 ){ 587 int nCache; 588 Btree *pBt; 589 590 if( argc!=3 ){ 591 Tcl_AppendResult( 592 interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", 0); 593 return TCL_ERROR; 594 } 595 pBt = sqlite3TestTextToPtr(argv[1]); 596 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; 597 598 sqlite3_mutex_enter(pBt->db->mutex); 599 sqlite3BtreeEnter(pBt); 600 sqlite3BtreeSetCacheSize(pBt, nCache); 601 sqlite3BtreeLeave(pBt); 602 sqlite3_mutex_leave(pBt->db->mutex); 603 return TCL_OK; 604 } 605 606 /* 607 ** usage: btree_insert CSR ?KEY? VALUE 608 ** 609 ** Set the size of the cache used by btree $ID. 610 */ 611 static int btree_insert( 612 ClientData clientData, 613 Tcl_Interp *interp, 614 int objc, 615 Tcl_Obj *const objv[] 616 ){ 617 BtCursor *pCur; 618 int rc; 619 void *pKey = 0; 620 int nKey = 0; 621 void *pData = 0; 622 int nData = 0; 623 624 if( objc!=4 && objc!=3 ){ 625 Tcl_WrongNumArgs(interp, 1, objv, "?-intkey? CSR KEY VALUE"); 626 return TCL_ERROR; 627 } 628 629 if( objc==4 ){ 630 if( Tcl_GetIntFromObj(interp, objv[2], &nKey) ) return TCL_ERROR; 631 pData = (void*)Tcl_GetByteArrayFromObj(objv[3], &nData); 632 }else{ 633 pKey = (void*)Tcl_GetByteArrayFromObj(objv[2], &nKey); 634 } 635 pCur = (BtCursor*)sqlite3TestTextToPtr(Tcl_GetString(objv[1])); 636 637 sqlite3_mutex_enter(pCur->pBtree->db->mutex); 638 sqlite3BtreeEnter(pCur->pBtree); 639 rc = sqlite3BtreeInsert(pCur, pKey, nKey, pData, nData, 0, 0, 0); 640 sqlite3BtreeLeave(pCur->pBtree); 641 sqlite3_mutex_leave(pCur->pBtree->db->mutex); 642 643 Tcl_ResetResult(interp); 644 if( rc ){ 645 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); 646 return TCL_ERROR; 647 } 648 return TCL_OK; 649 } 650 651 652 /* 653 ** Register commands with the TCL interpreter. 654 */ 655 int Sqlitetest3_Init(Tcl_Interp *interp){ 656 static struct { 657 char *zName; 658 Tcl_CmdProc *xProc; 659 } aCmd[] = { 660 { "btree_open", (Tcl_CmdProc*)btree_open }, 661 { "btree_close", (Tcl_CmdProc*)btree_close }, 662 { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction }, 663 { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats }, 664 { "btree_cursor", (Tcl_CmdProc*)btree_cursor }, 665 { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor }, 666 { "btree_next", (Tcl_CmdProc*)btree_next }, 667 { "btree_eof", (Tcl_CmdProc*)btree_eof }, 668 { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size }, 669 { "btree_first", (Tcl_CmdProc*)btree_first }, 670 { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test }, 671 { "btree_from_db", (Tcl_CmdProc*)btree_from_db }, 672 { "btree_ismemdb", (Tcl_CmdProc*)btree_ismemdb }, 673 { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size } 674 }; 675 int i; 676 677 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 678 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 679 } 680 681 Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0); 682 683 return TCL_OK; 684 } 685