| 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 ** $Id: test3.c,v 1.111 2009/07/09 05:07:38 danielk1977 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_pager_stats ID | |
| 162 ** | |
| 163 ** Returns pager statistics | |
| 164 */ | |
| 165 static int btree_pager_stats( | |
| 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 i; | |
| 173 int *a; | |
| 174 | |
| 175 if( argc!=2 ){ | |
| 176 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| 177 " ID\"", 0); | |
| 178 return TCL_ERROR; | |
| 179 } | |
| 180 pBt = sqlite3TestTextToPtr(argv[1]); | |
| 181 | |
| 182 /* Normally in this file, with a b-tree handle opened using the | |
| 183 ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly. | |
| 184 ** But this function is sometimes called with a btree handle obtained | |
| 185 ** from an open SQLite connection (using [btree_from_db]). In this case | |
| 186 ** we need to obtain the mutex for the controlling SQLite handle before | |
| 187 ** it is safe to call sqlite3BtreeEnter(). | |
| 188 */ | |
| 189 sqlite3_mutex_enter(pBt->db->mutex); | |
| 190 | |
| 191 sqlite3BtreeEnter(pBt); | |
| 192 a = sqlite3PagerStats(sqlite3BtreePager(pBt)); | |
| 193 for(i=0; i<11; i++){ | |
| 194 static char *zName[] = { | |
| 195 "ref", "page", "max", "size", "state", "err", | |
| 196 "hit", "miss", "ovfl", "read", "write" | |
| 197 }; | |
| 198 char zBuf[100]; | |
| 199 Tcl_AppendElement(interp, zName[i]); | |
| 200 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]); | |
| 201 Tcl_AppendElement(interp, zBuf); | |
| 202 } | |
| 203 sqlite3BtreeLeave(pBt); | |
| 204 | |
| 205 /* Release the mutex on the SQLite handle that controls this b-tree */ | |
| 206 sqlite3_mutex_leave(pBt->db->mutex); | |
| 207 return TCL_OK; | |
| 208 } | |
| 209 | |
| 210 /* | |
| 211 ** Usage: btree_cursor ID TABLENUM WRITEABLE | |
| 212 ** | |
| 213 ** Create a new cursor. Return the ID for the cursor. | |
| 214 */ | |
| 215 static int btree_cursor( | |
| 216 void *NotUsed, | |
| 217 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| 218 int argc, /* Number of arguments */ | |
| 219 const char **argv /* Text of each argument */ | |
| 220 ){ | |
| 221 Btree *pBt; | |
| 222 int iTable; | |
| 223 BtCursor *pCur; | |
| 224 int rc; | |
| 225 int wrFlag; | |
| 226 char zBuf[30]; | |
| 227 | |
| 228 if( argc!=4 ){ | |
| 229 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| 230 " ID TABLENUM WRITEABLE\"", 0); | |
| 231 return TCL_ERROR; | |
| 232 } | |
| 233 pBt = sqlite3TestTextToPtr(argv[1]); | |
| 234 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; | |
| 235 if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR; | |
| 236 pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize()); | |
| 237 memset(pCur, 0, sqlite3BtreeCursorSize()); | |
| 238 sqlite3BtreeEnter(pBt); | |
| 239 rc = sqlite3BtreeLockTable(pBt, iTable, wrFlag); | |
| 240 if( rc==SQLITE_OK ){ | |
| 241 rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur); | |
| 242 } | |
| 243 sqlite3BtreeLeave(pBt); | |
| 244 if( rc ){ | |
| 245 ckfree((char *)pCur); | |
| 246 Tcl_AppendResult(interp, errorName(rc), 0); | |
| 247 return TCL_ERROR; | |
| 248 } | |
| 249 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur); | |
| 250 Tcl_AppendResult(interp, zBuf, 0); | |
| 251 return SQLITE_OK; | |
| 252 } | |
| 253 | |
| 254 /* | |
| 255 ** Usage: btree_close_cursor ID | |
| 256 ** | |
| 257 ** Close a cursor opened using btree_cursor. | |
| 258 */ | |
| 259 static int btree_close_cursor( | |
| 260 void *NotUsed, | |
| 261 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| 262 int argc, /* Number of arguments */ | |
| 263 const char **argv /* Text of each argument */ | |
| 264 ){ | |
| 265 BtCursor *pCur; | |
| 266 Btree *pBt; | |
| 267 int rc; | |
| 268 | |
| 269 if( argc!=2 ){ | |
| 270 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| 271 " ID\"", 0); | |
| 272 return TCL_ERROR; | |
| 273 } | |
| 274 pCur = sqlite3TestTextToPtr(argv[1]); | |
| 275 pBt = pCur->pBtree; | |
| 276 sqlite3BtreeEnter(pBt); | |
| 277 rc = sqlite3BtreeCloseCursor(pCur); | |
| 278 sqlite3BtreeLeave(pBt); | |
| 279 ckfree((char *)pCur); | |
| 280 if( rc ){ | |
| 281 Tcl_AppendResult(interp, errorName(rc), 0); | |
| 282 return TCL_ERROR; | |
| 283 } | |
| 284 return SQLITE_OK; | |
| 285 } | |
| 286 | |
| 287 /* | |
| 288 ** Usage: btree_next ID | |
| 289 ** | |
| 290 ** Move the cursor to the next entry in the table. Return 0 on success | |
| 291 ** or 1 if the cursor was already on the last entry in the table or if | |
| 292 ** the table is empty. | |
| 293 */ | |
| 294 static int btree_next( | |
| 295 void *NotUsed, | |
| 296 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| 297 int argc, /* Number of arguments */ | |
| 298 const char **argv /* Text of each argument */ | |
| 299 ){ | |
| 300 BtCursor *pCur; | |
| 301 int rc; | |
| 302 int res = 0; | |
| 303 char zBuf[100]; | |
| 304 | |
| 305 if( argc!=2 ){ | |
| 306 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| 307 " ID\"", 0); | |
| 308 return TCL_ERROR; | |
| 309 } | |
| 310 pCur = sqlite3TestTextToPtr(argv[1]); | |
| 311 sqlite3BtreeEnter(pCur->pBtree); | |
| 312 rc = sqlite3BtreeNext(pCur, &res); | |
| 313 sqlite3BtreeLeave(pCur->pBtree); | |
| 314 if( rc ){ | |
| 315 Tcl_AppendResult(interp, errorName(rc), 0); | |
| 316 return TCL_ERROR; | |
| 317 } | |
| 318 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); | |
| 319 Tcl_AppendResult(interp, zBuf, 0); | |
| 320 return SQLITE_OK; | |
| 321 } | |
| 322 | |
| 323 /* | |
| 324 ** Usage: btree_first ID | |
| 325 ** | |
| 326 ** Move the cursor to the first entry in the table. Return 0 if the | |
| 327 ** cursor was left point to something and 1 if the table is empty. | |
| 328 */ | |
| 329 static int btree_first( | |
| 330 void *NotUsed, | |
| 331 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| 332 int argc, /* Number of arguments */ | |
| 333 const char **argv /* Text of each argument */ | |
| 334 ){ | |
| 335 BtCursor *pCur; | |
| 336 int rc; | |
| 337 int res = 0; | |
| 338 char zBuf[100]; | |
| 339 | |
| 340 if( argc!=2 ){ | |
| 341 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| 342 " ID\"", 0); | |
| 343 return TCL_ERROR; | |
| 344 } | |
| 345 pCur = sqlite3TestTextToPtr(argv[1]); | |
| 346 sqlite3BtreeEnter(pCur->pBtree); | |
| 347 rc = sqlite3BtreeFirst(pCur, &res); | |
| 348 sqlite3BtreeLeave(pCur->pBtree); | |
| 349 if( rc ){ | |
| 350 Tcl_AppendResult(interp, errorName(rc), 0); | |
| 351 return TCL_ERROR; | |
| 352 } | |
| 353 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); | |
| 354 Tcl_AppendResult(interp, zBuf, 0); | |
| 355 return SQLITE_OK; | |
| 356 } | |
| 357 | |
| 358 /* | |
| 359 ** Usage: btree_eof ID | |
| 360 ** | |
| 361 ** Return TRUE if the given cursor is not pointing at a valid entry. | |
| 362 ** Return FALSE if the cursor does point to a valid entry. | |
| 363 */ | |
| 364 static int btree_eof( | |
| 365 void *NotUsed, | |
| 366 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| 367 int argc, /* Number of arguments */ | |
| 368 const char **argv /* Text of each argument */ | |
| 369 ){ | |
| 370 BtCursor *pCur; | |
| 371 int rc; | |
| 372 char zBuf[50]; | |
| 373 | |
| 374 if( argc!=2 ){ | |
| 375 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| 376 " ID\"", 0); | |
| 377 return TCL_ERROR; | |
| 378 } | |
| 379 pCur = sqlite3TestTextToPtr(argv[1]); | |
| 380 sqlite3BtreeEnter(pCur->pBtree); | |
| 381 rc = sqlite3BtreeEof(pCur); | |
| 382 sqlite3BtreeLeave(pCur->pBtree); | |
| 383 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc); | |
| 384 Tcl_AppendResult(interp, zBuf, 0); | |
| 385 return SQLITE_OK; | |
| 386 } | |
| 387 | |
| 388 /* | |
| 389 ** Usage: btree_payload_size ID | |
| 390 ** | |
| 391 ** Return the number of bytes of payload | |
| 392 */ | |
| 393 static int btree_payload_size( | |
| 394 void *NotUsed, | |
| 395 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| 396 int argc, /* Number of arguments */ | |
| 397 const char **argv /* Text of each argument */ | |
| 398 ){ | |
| 399 BtCursor *pCur; | |
| 400 int n2; | |
| 401 u64 n1; | |
| 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 | |
| 412 /* The cursor may be in "require-seek" state. If this is the case, the | |
| 413 ** call to BtreeDataSize() will fix it. */ | |
| 414 sqlite3BtreeDataSize(pCur, (u32*)&n2); | |
| 415 if( pCur->apPage[pCur->iPage]->intKey ){ | |
| 416 n1 = 0; | |
| 417 }else{ | |
| 418 sqlite3BtreeKeySize(pCur, (i64*)&n1); | |
| 419 } | |
| 420 sqlite3BtreeLeave(pCur->pBtree); | |
| 421 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2)); | |
| 422 Tcl_AppendResult(interp, zBuf, 0); | |
| 423 return SQLITE_OK; | |
| 424 } | |
| 425 | |
| 426 /* | |
| 427 ** usage: varint_test START MULTIPLIER COUNT INCREMENT | |
| 428 ** | |
| 429 ** This command tests the putVarint() and getVarint() | |
| 430 ** routines, both for accuracy and for speed. | |
| 431 ** | |
| 432 ** An integer is written using putVarint() and read back with | |
| 433 ** getVarint() and varified to be unchanged. This repeats COUNT | |
| 434 ** times. The first integer is START*MULTIPLIER. Each iteration | |
| 435 ** increases the integer by INCREMENT. | |
| 436 ** | |
| 437 ** This command returns nothing if it works. It returns an error message | |
| 438 ** if something goes wrong. | |
| 439 */ | |
| 440 static int btree_varint_test( | |
| 441 void *NotUsed, | |
| 442 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| 443 int argc, /* Number of arguments */ | |
| 444 const char **argv /* Text of each argument */ | |
| 445 ){ | |
| 446 u32 start, mult, count, incr; | |
| 447 u64 in, out; | |
| 448 int n1, n2, i, j; | |
| 449 unsigned char zBuf[100]; | |
| 450 if( argc!=5 ){ | |
| 451 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| 452 " START MULTIPLIER COUNT INCREMENT\"", 0); | |
| 453 return TCL_ERROR; | |
| 454 } | |
| 455 if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR; | |
| 456 if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR; | |
| 457 if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR; | |
| 458 if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR; | |
| 459 in = start; | |
| 460 in *= mult; | |
| 461 for(i=0; i<count; i++){ | |
| 462 char zErr[200]; | |
| 463 n1 = putVarint(zBuf, in); | |
| 464 if( n1>9 || n1<1 ){ | |
| 465 sprintf(zErr, "putVarint returned %d - should be between 1 and 9", n1); | |
| 466 Tcl_AppendResult(interp, zErr, 0); | |
| 467 return TCL_ERROR; | |
| 468 } | |
| 469 n2 = getVarint(zBuf, &out); | |
| 470 if( n1!=n2 ){ | |
| 471 sprintf(zErr, "putVarint returned %d and getVarint returned %d", n1, n2); | |
| 472 Tcl_AppendResult(interp, zErr, 0); | |
| 473 return TCL_ERROR; | |
| 474 } | |
| 475 if( in!=out ){ | |
| 476 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out); | |
| 477 Tcl_AppendResult(interp, zErr, 0); | |
| 478 return TCL_ERROR; | |
| 479 } | |
| 480 if( (in & 0xffffffff)==in ){ | |
| 481 u32 out32; | |
| 482 n2 = getVarint32(zBuf, out32); | |
| 483 out = out32; | |
| 484 if( n1!=n2 ){ | |
| 485 sprintf(zErr, "putVarint returned %d and GetVarint32 returned %d", | |
| 486 n1, n2); | |
| 487 Tcl_AppendResult(interp, zErr, 0); | |
| 488 return TCL_ERROR; | |
| 489 } | |
| 490 if( in!=out ){ | |
| 491 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32", | |
| 492 in, out); | |
| 493 Tcl_AppendResult(interp, zErr, 0); | |
| 494 return TCL_ERROR; | |
| 495 } | |
| 496 } | |
| 497 | |
| 498 /* In order to get realistic timings, run getVarint 19 more times. | |
| 499 ** This is because getVarint is called about 20 times more often | |
| 500 ** than putVarint. | |
| 501 */ | |
| 502 for(j=0; j<19; j++){ | |
| 503 getVarint(zBuf, &out); | |
| 504 } | |
| 505 in += incr; | |
| 506 } | |
| 507 return TCL_OK; | |
| 508 } | |
| 509 | |
| 510 /* | |
| 511 ** usage: btree_from_db DB-HANDLE | |
| 512 ** | |
| 513 ** This command returns the btree handle for the main database associated | |
| 514 ** with the database-handle passed as the argument. Example usage: | |
| 515 ** | |
| 516 ** sqlite3 db test.db | |
| 517 ** set bt [btree_from_db db] | |
| 518 */ | |
| 519 static int btree_from_db( | |
| 520 void *NotUsed, | |
| 521 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| 522 int argc, /* Number of arguments */ | |
| 523 const char **argv /* Text of each argument */ | |
| 524 ){ | |
| 525 char zBuf[100]; | |
| 526 Tcl_CmdInfo info; | |
| 527 sqlite3 *db; | |
| 528 Btree *pBt; | |
| 529 int iDb = 0; | |
| 530 | |
| 531 if( argc!=2 && argc!=3 ){ | |
| 532 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| 533 " DB-HANDLE ?N?\"", 0); | |
| 534 return TCL_ERROR; | |
| 535 } | |
| 536 | |
| 537 if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){ | |
| 538 Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0); | |
| 539 return TCL_ERROR; | |
| 540 } | |
| 541 if( argc==3 ){ | |
| 542 iDb = atoi(argv[2]); | |
| 543 } | |
| 544 | |
| 545 db = *((sqlite3 **)info.objClientData); | |
| 546 assert( db ); | |
| 547 | |
| 548 pBt = db->aDb[iDb].pBt; | |
| 549 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt); | |
| 550 Tcl_SetResult(interp, zBuf, TCL_VOLATILE); | |
| 551 return TCL_OK; | |
| 552 } | |
| 553 | |
| 554 /* | |
| 555 ** Usage: btree_ismemdb ID | |
| 556 ** | |
| 557 ** Return true if the B-Tree is in-memory. | |
| 558 */ | |
| 559 static int btree_ismemdb( | |
| 560 void *NotUsed, | |
| 561 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| 562 int argc, /* Number of arguments */ | |
| 563 const char **argv /* Text of each argument */ | |
| 564 ){ | |
| 565 Btree *pBt; | |
| 566 int res; | |
| 567 | |
| 568 if( argc!=2 ){ | |
| 569 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| 570 " ID\"", 0); | |
| 571 return TCL_ERROR; | |
| 572 } | |
| 573 pBt = sqlite3TestTextToPtr(argv[1]); | |
| 574 sqlite3_mutex_enter(pBt->db->mutex); | |
| 575 sqlite3BtreeEnter(pBt); | |
| 576 res = sqlite3PagerIsMemdb(sqlite3BtreePager(pBt)); | |
| 577 sqlite3BtreeLeave(pBt); | |
| 578 sqlite3_mutex_leave(pBt->db->mutex); | |
| 579 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res)); | |
| 580 return SQLITE_OK; | |
| 581 } | |
| 582 | |
| 583 /* | |
| 584 ** usage: btree_set_cache_size ID NCACHE | |
| 585 ** | |
| 586 ** Set the size of the cache used by btree $ID. | |
| 587 */ | |
| 588 static int btree_set_cache_size( | |
| 589 void *NotUsed, | |
| 590 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| 591 int argc, /* Number of arguments */ | |
| 592 const char **argv /* Text of each argument */ | |
| 593 ){ | |
| 594 int nCache; | |
| 595 Btree *pBt; | |
| 596 | |
| 597 if( argc!=3 ){ | |
| 598 Tcl_AppendResult( | |
| 599 interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", 0); | |
| 600 return TCL_ERROR; | |
| 601 } | |
| 602 pBt = sqlite3TestTextToPtr(argv[1]); | |
| 603 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; | |
| 604 | |
| 605 sqlite3_mutex_enter(pBt->db->mutex); | |
| 606 sqlite3BtreeEnter(pBt); | |
| 607 sqlite3BtreeSetCacheSize(pBt, nCache); | |
| 608 sqlite3BtreeLeave(pBt); | |
| 609 sqlite3_mutex_leave(pBt->db->mutex); | |
| 610 return TCL_OK; | |
| 611 } | |
| 612 | |
| 613 | |
| 614 | |
| 615 /* | |
| 616 ** Register commands with the TCL interpreter. | |
| 617 */ | |
| 618 int Sqlitetest3_Init(Tcl_Interp *interp){ | |
| 619 static struct { | |
| 620 char *zName; | |
| 621 Tcl_CmdProc *xProc; | |
| 622 } aCmd[] = { | |
| 623 { "btree_open", (Tcl_CmdProc*)btree_open }, | |
| 624 { "btree_close", (Tcl_CmdProc*)btree_close }, | |
| 625 { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction }, | |
| 626 { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats }, | |
| 627 { "btree_cursor", (Tcl_CmdProc*)btree_cursor }, | |
| 628 { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor }, | |
| 629 { "btree_next", (Tcl_CmdProc*)btree_next }, | |
| 630 { "btree_eof", (Tcl_CmdProc*)btree_eof }, | |
| 631 { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size }, | |
| 632 { "btree_first", (Tcl_CmdProc*)btree_first }, | |
| 633 { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test }, | |
| 634 { "btree_from_db", (Tcl_CmdProc*)btree_from_db }, | |
| 635 { "btree_ismemdb", (Tcl_CmdProc*)btree_ismemdb }, | |
| 636 { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size } | |
| 637 }; | |
| 638 int i; | |
| 639 | |
| 640 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ | |
| 641 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); | |
| 642 } | |
| 643 | |
| 644 return TCL_OK; | |
| 645 } | |
| OLD | NEW |