OLD | NEW |
1 /* | 1 /* |
2 ** 2010 July 12 | 2 ** 2010 July 12 |
3 ** | 3 ** |
4 ** The author disclaims copyright to this source code. In place of | 4 ** The author disclaims copyright to this source code. In place of |
5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: |
6 ** | 6 ** |
7 ** May you do good and not evil. | 7 ** May you do good and not evil. |
8 ** May you find forgiveness for yourself and forgive others. | 8 ** May you find forgiveness for yourself and forgive others. |
9 ** May you share freely, never taking more than you give. | 9 ** May you share freely, never taking more than you give. |
10 ** | 10 ** |
11 ****************************************************************************** | 11 ****************************************************************************** |
12 ** | 12 ** |
13 ** This file contains an implementation of the "dbstat" virtual table. | 13 ** This file contains an implementation of the "dbstat" virtual table. |
14 ** | 14 ** |
15 ** The dbstat virtual table is used to extract low-level formatting | 15 ** The dbstat virtual table is used to extract low-level formatting |
16 ** information from an SQLite database in order to implement the | 16 ** information from an SQLite database in order to implement the |
17 ** "sqlite3_analyzer" utility. See the ../tool/spaceanal.tcl script | 17 ** "sqlite3_analyzer" utility. See the ../tool/spaceanal.tcl script |
18 ** for an example implementation. | 18 ** for an example implementation. |
19 */ | 19 */ |
20 | 20 |
21 #include "sqliteInt.h" | 21 #ifndef SQLITE_AMALGAMATION |
| 22 # include "sqliteInt.h" |
| 23 #endif |
22 | 24 |
23 #ifndef SQLITE_OMIT_VIRTUALTABLE | 25 #ifndef SQLITE_OMIT_VIRTUALTABLE |
24 | 26 |
25 /* | 27 /* |
26 ** Page paths: | 28 ** Page paths: |
27 ** | 29 ** |
28 ** The value of the 'path' column describes the path taken from the | 30 ** The value of the 'path' column describes the path taken from the |
29 ** root-node of the b-tree structure to each page. The value of the | 31 ** root-node of the b-tree structure to each page. The value of the |
30 ** root-node path is '/'. | 32 ** root-node path is '/'. |
31 ** | 33 ** |
(...skipping 23 matching lines...) Expand all Loading... |
55 */ | 57 */ |
56 #define VTAB_SCHEMA \ | 58 #define VTAB_SCHEMA \ |
57 "CREATE TABLE xx( " \ | 59 "CREATE TABLE xx( " \ |
58 " name STRING, /* Name of table or index */" \ | 60 " name STRING, /* Name of table or index */" \ |
59 " path INTEGER, /* Path to page from root */" \ | 61 " path INTEGER, /* Path to page from root */" \ |
60 " pageno INTEGER, /* Page number */" \ | 62 " pageno INTEGER, /* Page number */" \ |
61 " pagetype STRING, /* 'internal', 'leaf' or 'overflow' */" \ | 63 " pagetype STRING, /* 'internal', 'leaf' or 'overflow' */" \ |
62 " ncell INTEGER, /* Cells on page (0 for overflow) */" \ | 64 " ncell INTEGER, /* Cells on page (0 for overflow) */" \ |
63 " payload INTEGER, /* Bytes of payload on this page */" \ | 65 " payload INTEGER, /* Bytes of payload on this page */" \ |
64 " unused INTEGER, /* Bytes of unused space on this page */" \ | 66 " unused INTEGER, /* Bytes of unused space on this page */" \ |
65 " mx_payload INTEGER /* Largest payload size of all cells */" \ | 67 " mx_payload INTEGER, /* Largest payload size of all cells */" \ |
| 68 " pgoffset INTEGER, /* Offset of page in file */" \ |
| 69 " pgsize INTEGER /* Size of the page */" \ |
66 ");" | 70 ");" |
67 | 71 |
68 #if 0 | |
69 #define VTAB_SCHEMA2 \ | |
70 "CREATE TABLE yy( " \ | |
71 " pageno INTEGER, /* B-tree page number */" \ | |
72 " cellno INTEGER, /* Cell number within page */" \ | |
73 " local INTEGER, /* Bytes of content stored locally */" \ | |
74 " payload INTEGER, /* Total cell payload size */" \ | |
75 " novfl INTEGER /* Number of overflow pages */" \ | |
76 ");" | |
77 #endif | |
78 | |
79 | 72 |
80 typedef struct StatTable StatTable; | 73 typedef struct StatTable StatTable; |
81 typedef struct StatCursor StatCursor; | 74 typedef struct StatCursor StatCursor; |
82 typedef struct StatPage StatPage; | 75 typedef struct StatPage StatPage; |
83 typedef struct StatCell StatCell; | 76 typedef struct StatCell StatCell; |
84 | 77 |
85 struct StatCell { | 78 struct StatCell { |
86 int nLocal; /* Bytes of local payload */ | 79 int nLocal; /* Bytes of local payload */ |
87 u32 iChildPg; /* Child node (or 0 if this is a leaf) */ | 80 u32 iChildPg; /* Child node (or 0 if this is a leaf) */ |
88 int nOvfl; /* Entries in aOvfl[] */ | 81 int nOvfl; /* Entries in aOvfl[] */ |
(...skipping 28 matching lines...) Expand all Loading... |
117 | 110 |
118 /* Values to return. */ | 111 /* Values to return. */ |
119 char *zName; /* Value of 'name' column */ | 112 char *zName; /* Value of 'name' column */ |
120 char *zPath; /* Value of 'path' column */ | 113 char *zPath; /* Value of 'path' column */ |
121 u32 iPageno; /* Value of 'pageno' column */ | 114 u32 iPageno; /* Value of 'pageno' column */ |
122 char *zPagetype; /* Value of 'pagetype' column */ | 115 char *zPagetype; /* Value of 'pagetype' column */ |
123 int nCell; /* Value of 'ncell' column */ | 116 int nCell; /* Value of 'ncell' column */ |
124 int nPayload; /* Value of 'payload' column */ | 117 int nPayload; /* Value of 'payload' column */ |
125 int nUnused; /* Value of 'unused' column */ | 118 int nUnused; /* Value of 'unused' column */ |
126 int nMxPayload; /* Value of 'mx_payload' column */ | 119 int nMxPayload; /* Value of 'mx_payload' column */ |
| 120 i64 iOffset; /* Value of 'pgOffset' column */ |
| 121 int szPage; /* Value of 'pgSize' column */ |
127 }; | 122 }; |
128 | 123 |
129 struct StatTable { | 124 struct StatTable { |
130 sqlite3_vtab base; | 125 sqlite3_vtab base; |
131 sqlite3 *db; | 126 sqlite3 *db; |
132 }; | 127 }; |
133 | 128 |
134 #ifndef get2byte | 129 #ifndef get2byte |
135 # define get2byte(x) ((x)[0]<<8 | (x)[1]) | 130 # define get2byte(x) ((x)[0]<<8 | (x)[1]) |
136 #endif | 131 #endif |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 nLocal = nMinLocal + (nTotal - nMinLocal) % (nUsable - 4); | 269 nLocal = nMinLocal + (nTotal - nMinLocal) % (nUsable - 4); |
275 if( nLocal>nMaxLocal ) nLocal = nMinLocal; | 270 if( nLocal>nMaxLocal ) nLocal = nMinLocal; |
276 *pnLocal = nLocal; | 271 *pnLocal = nLocal; |
277 } | 272 } |
278 | 273 |
279 static int statDecodePage(Btree *pBt, StatPage *p){ | 274 static int statDecodePage(Btree *pBt, StatPage *p){ |
280 int nUnused; | 275 int nUnused; |
281 int iOff; | 276 int iOff; |
282 int nHdr; | 277 int nHdr; |
283 int isLeaf; | 278 int isLeaf; |
| 279 int szPage; |
284 | 280 |
285 u8 *aData = sqlite3PagerGetData(p->pPg); | 281 u8 *aData = sqlite3PagerGetData(p->pPg); |
286 u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0]; | 282 u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0]; |
287 | 283 |
288 p->flags = aHdr[0]; | 284 p->flags = aHdr[0]; |
289 p->nCell = get2byte(&aHdr[3]); | 285 p->nCell = get2byte(&aHdr[3]); |
290 p->nMxPayload = 0; | 286 p->nMxPayload = 0; |
291 | 287 |
292 isLeaf = (p->flags==0x0A || p->flags==0x0D); | 288 isLeaf = (p->flags==0x0A || p->flags==0x0D); |
293 nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100; | 289 nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100; |
294 | 290 |
295 nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell; | 291 nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell; |
296 nUnused += (int)aHdr[7]; | 292 nUnused += (int)aHdr[7]; |
297 iOff = get2byte(&aHdr[1]); | 293 iOff = get2byte(&aHdr[1]); |
298 while( iOff ){ | 294 while( iOff ){ |
299 nUnused += get2byte(&aData[iOff+2]); | 295 nUnused += get2byte(&aData[iOff+2]); |
300 iOff = get2byte(&aData[iOff]); | 296 iOff = get2byte(&aData[iOff]); |
301 } | 297 } |
302 p->nUnused = nUnused; | 298 p->nUnused = nUnused; |
303 p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]); | 299 p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]); |
| 300 szPage = sqlite3BtreeGetPageSize(pBt); |
304 | 301 |
305 if( p->nCell ){ | 302 if( p->nCell ){ |
306 int i; /* Used to iterate through cells */ | 303 int i; /* Used to iterate through cells */ |
307 int nUsable = sqlite3BtreeGetPageSize(pBt) - sqlite3BtreeGetReserve(pBt); | 304 int nUsable = szPage - sqlite3BtreeGetReserve(pBt); |
308 | 305 |
309 p->aCell = sqlite3_malloc((p->nCell+1) * sizeof(StatCell)); | 306 p->aCell = sqlite3_malloc((p->nCell+1) * sizeof(StatCell)); |
310 memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell)); | 307 memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell)); |
311 | 308 |
312 for(i=0; i<p->nCell; i++){ | 309 for(i=0; i<p->nCell; i++){ |
313 StatCell *pCell = &p->aCell[i]; | 310 StatCell *pCell = &p->aCell[i]; |
314 | 311 |
315 iOff = get2byte(&aData[nHdr+i*2]); | 312 iOff = get2byte(&aData[nHdr+i*2]); |
316 if( !isLeaf ){ | 313 if( !isLeaf ){ |
317 pCell->iChildPg = sqlite3Get4byte(&aData[iOff]); | 314 pCell->iChildPg = sqlite3Get4byte(&aData[iOff]); |
318 iOff += 4; | 315 iOff += 4; |
319 } | 316 } |
320 if( p->flags==0x05 ){ | 317 if( p->flags==0x05 ){ |
321 /* A table interior node. nPayload==0. */ | 318 /* A table interior node. nPayload==0. */ |
322 }else{ | 319 }else{ |
323 u32 nPayload; /* Bytes of payload total (local+overflow) */ | 320 u32 nPayload; /* Bytes of payload total (local+overflow) */ |
324 int nLocal; /* Bytes of payload stored locally */ | 321 int nLocal; /* Bytes of payload stored locally */ |
325 iOff += getVarint32(&aData[iOff], nPayload); | 322 iOff += getVarint32(&aData[iOff], nPayload); |
326 if( p->flags==0x0D ){ | 323 if( p->flags==0x0D ){ |
327 u64 dummy; | 324 u64 dummy; |
328 iOff += sqlite3GetVarint(&aData[iOff], &dummy); | 325 iOff += sqlite3GetVarint(&aData[iOff], &dummy); |
329 } | 326 } |
330 if( nPayload>p->nMxPayload ) p->nMxPayload = nPayload; | 327 if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload; |
331 getLocalPayload(nUsable, p->flags, nPayload, &nLocal); | 328 getLocalPayload(nUsable, p->flags, nPayload, &nLocal); |
332 pCell->nLocal = nLocal; | 329 pCell->nLocal = nLocal; |
333 assert( nPayload>=nLocal ); | 330 assert( nLocal>=0 ); |
| 331 assert( nPayload>=(u32)nLocal ); |
334 assert( nLocal<=(nUsable-35) ); | 332 assert( nLocal<=(nUsable-35) ); |
335 if( nPayload>nLocal ){ | 333 if( nPayload>(u32)nLocal ){ |
336 int j; | 334 int j; |
337 int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4); | 335 int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4); |
338 pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4); | 336 pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4); |
339 pCell->nOvfl = nOvfl; | 337 pCell->nOvfl = nOvfl; |
340 pCell->aOvfl = sqlite3_malloc(sizeof(u32)*nOvfl); | 338 pCell->aOvfl = sqlite3_malloc(sizeof(u32)*nOvfl); |
341 pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]); | 339 pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]); |
342 for(j=1; j<nOvfl; j++){ | 340 for(j=1; j<nOvfl; j++){ |
343 int rc; | 341 int rc; |
344 u32 iPrev = pCell->aOvfl[j-1]; | 342 u32 iPrev = pCell->aOvfl[j-1]; |
345 DbPage *pPg = 0; | 343 DbPage *pPg = 0; |
346 rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg); | 344 rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg); |
347 if( rc!=SQLITE_OK ){ | 345 if( rc!=SQLITE_OK ){ |
348 assert( pPg==0 ); | 346 assert( pPg==0 ); |
349 return rc; | 347 return rc; |
350 } | 348 } |
351 pCell->aOvfl[j] = sqlite3Get4byte(sqlite3PagerGetData(pPg)); | 349 pCell->aOvfl[j] = sqlite3Get4byte(sqlite3PagerGetData(pPg)); |
352 sqlite3PagerUnref(pPg); | 350 sqlite3PagerUnref(pPg); |
353 } | 351 } |
354 } | 352 } |
355 } | 353 } |
356 } | 354 } |
357 } | 355 } |
358 | 356 |
359 return SQLITE_OK; | 357 return SQLITE_OK; |
360 } | 358 } |
361 | 359 |
362 /* | 360 /* |
| 361 ** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on |
| 362 ** the current value of pCsr->iPageno. |
| 363 */ |
| 364 static void statSizeAndOffset(StatCursor *pCsr){ |
| 365 StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab; |
| 366 Btree *pBt = pTab->db->aDb[0].pBt; |
| 367 Pager *pPager = sqlite3BtreePager(pBt); |
| 368 sqlite3_file *fd; |
| 369 sqlite3_int64 x[2]; |
| 370 |
| 371 /* The default page size and offset */ |
| 372 pCsr->szPage = sqlite3BtreeGetPageSize(pBt); |
| 373 pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1); |
| 374 |
| 375 /* If connected to a ZIPVFS backend, override the page size and |
| 376 ** offset with actual values obtained from ZIPVFS. |
| 377 */ |
| 378 fd = sqlite3PagerFile(pPager); |
| 379 x[0] = pCsr->iPageno; |
| 380 if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){ |
| 381 pCsr->iOffset = x[0]; |
| 382 pCsr->szPage = (int)x[1]; |
| 383 } |
| 384 } |
| 385 |
| 386 /* |
363 ** Move a statvfs cursor to the next entry in the file. | 387 ** Move a statvfs cursor to the next entry in the file. |
364 */ | 388 */ |
365 static int statNext(sqlite3_vtab_cursor *pCursor){ | 389 static int statNext(sqlite3_vtab_cursor *pCursor){ |
366 int rc; | 390 int rc; |
367 int nPayload; | 391 int nPayload; |
368 StatCursor *pCsr = (StatCursor *)pCursor; | 392 StatCursor *pCsr = (StatCursor *)pCursor; |
369 StatTable *pTab = (StatTable *)pCursor->pVtab; | 393 StatTable *pTab = (StatTable *)pCursor->pVtab; |
370 Btree *pBt = pTab->db->aDb[0].pBt; | 394 Btree *pBt = pTab->db->aDb[0].pBt; |
371 Pager *pPager = sqlite3BtreePager(pBt); | 395 Pager *pPager = sqlite3BtreePager(pBt); |
372 | 396 |
373 sqlite3_free(pCsr->zPath); | 397 sqlite3_free(pCsr->zPath); |
374 pCsr->zPath = 0; | 398 pCsr->zPath = 0; |
375 | 399 |
| 400 statNextRestart: |
376 if( pCsr->aPage[0].pPg==0 ){ | 401 if( pCsr->aPage[0].pPg==0 ){ |
377 rc = sqlite3_step(pCsr->pStmt); | 402 rc = sqlite3_step(pCsr->pStmt); |
378 if( rc==SQLITE_ROW ){ | 403 if( rc==SQLITE_ROW ){ |
379 int nPage; | 404 int nPage; |
380 u32 iRoot = sqlite3_column_int64(pCsr->pStmt, 1); | 405 u32 iRoot = (u32)sqlite3_column_int64(pCsr->pStmt, 1); |
381 sqlite3PagerPagecount(pPager, &nPage); | 406 sqlite3PagerPagecount(pPager, &nPage); |
382 if( nPage==0 ){ | 407 if( nPage==0 ){ |
383 pCsr->isEof = 1; | 408 pCsr->isEof = 1; |
384 return sqlite3_reset(pCsr->pStmt); | 409 return sqlite3_reset(pCsr->pStmt); |
385 } | 410 } |
386 rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg); | 411 rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg); |
387 pCsr->aPage[0].iPgno = iRoot; | 412 pCsr->aPage[0].iPgno = iRoot; |
388 pCsr->aPage[0].iCell = 0; | 413 pCsr->aPage[0].iCell = 0; |
389 pCsr->aPage[0].zPath = sqlite3_mprintf("/"); | 414 pCsr->aPage[0].zPath = sqlite3_mprintf("/"); |
390 pCsr->iPage = 0; | 415 pCsr->iPage = 0; |
(...skipping 19 matching lines...) Expand all Loading... |
410 "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl | 435 "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl |
411 ); | 436 ); |
412 if( pCell->iOvfl<pCell->nOvfl-1 ){ | 437 if( pCell->iOvfl<pCell->nOvfl-1 ){ |
413 pCsr->nUnused = 0; | 438 pCsr->nUnused = 0; |
414 pCsr->nPayload = nUsable - 4; | 439 pCsr->nPayload = nUsable - 4; |
415 }else{ | 440 }else{ |
416 pCsr->nPayload = pCell->nLastOvfl; | 441 pCsr->nPayload = pCell->nLastOvfl; |
417 pCsr->nUnused = nUsable - 4 - pCsr->nPayload; | 442 pCsr->nUnused = nUsable - 4 - pCsr->nPayload; |
418 } | 443 } |
419 pCell->iOvfl++; | 444 pCell->iOvfl++; |
| 445 statSizeAndOffset(pCsr); |
420 return SQLITE_OK; | 446 return SQLITE_OK; |
421 } | 447 } |
422 if( p->iRightChildPg ) break; | 448 if( p->iRightChildPg ) break; |
423 p->iCell++; | 449 p->iCell++; |
424 } | 450 } |
425 | 451 |
426 while( !p->iRightChildPg || p->iCell>p->nCell ){ | 452 if( !p->iRightChildPg || p->iCell>p->nCell ){ |
427 statClearPage(p); | 453 statClearPage(p); |
428 if( pCsr->iPage==0 ) return statNext(pCursor); | 454 if( pCsr->iPage==0 ) return statNext(pCursor); |
429 pCsr->iPage--; | 455 pCsr->iPage--; |
430 p = &pCsr->aPage[pCsr->iPage]; | 456 goto statNextRestart; /* Tail recursion */ |
431 } | 457 } |
432 pCsr->iPage++; | 458 pCsr->iPage++; |
433 assert( p==&pCsr->aPage[pCsr->iPage-1] ); | 459 assert( p==&pCsr->aPage[pCsr->iPage-1] ); |
434 | 460 |
435 if( p->iCell==p->nCell ){ | 461 if( p->iCell==p->nCell ){ |
436 p[1].iPgno = p->iRightChildPg; | 462 p[1].iPgno = p->iRightChildPg; |
437 }else{ | 463 }else{ |
438 p[1].iPgno = p->aCell[p->iCell].iChildPg; | 464 p[1].iPgno = p->aCell[p->iCell].iChildPg; |
439 } | 465 } |
440 rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg); | 466 rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg); |
441 p[1].iCell = 0; | 467 p[1].iCell = 0; |
442 p[1].zPath = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell); | 468 p[1].zPath = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell); |
443 p->iCell++; | 469 p->iCell++; |
444 } | 470 } |
445 | 471 |
446 | 472 |
447 /* Populate the StatCursor fields with the values to be returned | 473 /* Populate the StatCursor fields with the values to be returned |
448 ** by the xColumn() and xRowid() methods. | 474 ** by the xColumn() and xRowid() methods. |
449 */ | 475 */ |
450 if( rc==SQLITE_OK ){ | 476 if( rc==SQLITE_OK ){ |
451 int i; | 477 int i; |
452 StatPage *p = &pCsr->aPage[pCsr->iPage]; | 478 StatPage *p = &pCsr->aPage[pCsr->iPage]; |
453 pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0); | 479 pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0); |
454 pCsr->iPageno = p->iPgno; | 480 pCsr->iPageno = p->iPgno; |
455 | 481 |
456 statDecodePage(pBt, p); | 482 statDecodePage(pBt, p); |
| 483 statSizeAndOffset(pCsr); |
457 | 484 |
458 switch( p->flags ){ | 485 switch( p->flags ){ |
459 case 0x05: /* table internal */ | 486 case 0x05: /* table internal */ |
460 case 0x02: /* index internal */ | 487 case 0x02: /* index internal */ |
461 pCsr->zPagetype = "internal"; | 488 pCsr->zPagetype = "internal"; |
462 break; | 489 break; |
463 case 0x0D: /* table leaf */ | 490 case 0x0D: /* table leaf */ |
464 case 0x0A: /* index leaf */ | 491 case 0x0A: /* index leaf */ |
465 pCsr->zPagetype = "leaf"; | 492 pCsr->zPagetype = "leaf"; |
466 break; | 493 break; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 break; | 549 break; |
523 case 5: /* payload */ | 550 case 5: /* payload */ |
524 sqlite3_result_int(ctx, pCsr->nPayload); | 551 sqlite3_result_int(ctx, pCsr->nPayload); |
525 break; | 552 break; |
526 case 6: /* unused */ | 553 case 6: /* unused */ |
527 sqlite3_result_int(ctx, pCsr->nUnused); | 554 sqlite3_result_int(ctx, pCsr->nUnused); |
528 break; | 555 break; |
529 case 7: /* mx_payload */ | 556 case 7: /* mx_payload */ |
530 sqlite3_result_int(ctx, pCsr->nMxPayload); | 557 sqlite3_result_int(ctx, pCsr->nMxPayload); |
531 break; | 558 break; |
| 559 case 8: /* pgoffset */ |
| 560 sqlite3_result_int64(ctx, pCsr->iOffset); |
| 561 break; |
| 562 case 9: /* pgsize */ |
| 563 sqlite3_result_int(ctx, pCsr->szPage); |
| 564 break; |
532 } | 565 } |
533 return SQLITE_OK; | 566 return SQLITE_OK; |
534 } | 567 } |
535 | 568 |
536 static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ | 569 static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ |
537 StatCursor *pCsr = (StatCursor *)pCursor; | 570 StatCursor *pCsr = (StatCursor *)pCursor; |
538 *pRowid = pCsr->iPageno; | 571 *pRowid = pCsr->iPageno; |
539 return SQLITE_OK; | 572 return SQLITE_OK; |
540 } | 573 } |
541 | 574 |
(...skipping 19 matching lines...) Expand all Loading... |
561 0, /* xRollback */ | 594 0, /* xRollback */ |
562 0, /* xFindMethod */ | 595 0, /* xFindMethod */ |
563 0, /* xRename */ | 596 0, /* xRename */ |
564 }; | 597 }; |
565 sqlite3_create_module(db, "dbstat", &dbstat_module, 0); | 598 sqlite3_create_module(db, "dbstat", &dbstat_module, 0); |
566 return SQLITE_OK; | 599 return SQLITE_OK; |
567 } | 600 } |
568 | 601 |
569 #endif | 602 #endif |
570 | 603 |
571 #ifdef SQLITE_TEST | 604 #if defined(SQLITE_TEST) || TCLSH==2 |
572 #include <tcl.h> | 605 #include <tcl.h> |
573 | 606 |
574 static int test_dbstat( | 607 static int test_dbstat( |
575 void *clientData, | 608 void *clientData, |
576 Tcl_Interp *interp, | 609 Tcl_Interp *interp, |
577 int objc, | 610 int objc, |
578 Tcl_Obj *CONST objv[] | 611 Tcl_Obj *CONST objv[] |
579 ){ | 612 ){ |
580 #ifdef SQLITE_OMIT_VIRTUALTABLE | 613 #ifdef SQLITE_OMIT_VIRTUALTABLE |
581 Tcl_AppendResult(interp, "dbstat not available because of " | 614 Tcl_AppendResult(interp, "dbstat not available because of " |
(...skipping 15 matching lines...) Expand all Loading... |
597 sqlite3_dbstat_register(db); | 630 sqlite3_dbstat_register(db); |
598 } | 631 } |
599 return TCL_OK; | 632 return TCL_OK; |
600 #endif | 633 #endif |
601 } | 634 } |
602 | 635 |
603 int SqlitetestStat_Init(Tcl_Interp *interp){ | 636 int SqlitetestStat_Init(Tcl_Interp *interp){ |
604 Tcl_CreateObjCommand(interp, "register_dbstat_vtab", test_dbstat, 0, 0); | 637 Tcl_CreateObjCommand(interp, "register_dbstat_vtab", test_dbstat, 0, 0); |
605 return TCL_OK; | 638 return TCL_OK; |
606 } | 639 } |
607 #endif | 640 #endif /* if defined(SQLITE_TEST) || TCLSH==2 */ |
OLD | NEW |