| OLD | NEW |
| (Empty) |
| 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 } | |
| OLD | NEW |