4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
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.
11 ******************************************************************************
13 ** This file contains an implementation of the "dbstat" virtual table.
15 ** The dbstat virtual table is used to extract low-level formatting
16 ** information from an SQLite database in order to implement the
17 ** "sqlite3_analyzer" utility. See the ../tool/spaceanal.tcl script
18 ** for an example implementation.
21 #ifndef SQLITE_AMALGAMATION
22 # include "sqliteInt.h"
25 #ifndef SQLITE_OMIT_VIRTUALTABLE
30 ** The value of the 'path' column describes the path taken from the
31 ** root-node of the b-tree structure to each page. The value of the
32 ** root-node path is '/'.
34 ** The value of the path for the left-most child page of the root of
35 ** a b-tree is '/000/'. (Btrees store content ordered from left to right
36 ** so the pages to the left have smaller keys than the pages to the right.)
37 ** The next to left-most child of the root page is
38 ** '/001', and so on, each sibling page identified by a 3-digit hex
39 ** value. The children of the 451st left-most sibling have paths such
40 ** as '/1c2/000/, '/1c2/001/' etc.
42 ** Overflow pages are specified by appending a '+' character and a
43 ** six-digit hexadecimal value to the path to the cell they are linked
44 ** from. For example, the three overflow pages in a chain linked from
45 ** the left-most cell of the 450th child of the root page are identified
48 ** '/1c2/000+000000' // First page in overflow chain
49 ** '/1c2/000+000001' // Second page in overflow chain
50 ** '/1c2/000+000002' // Third page in overflow chain
52 ** If the paths are sorted using the BINARY collation sequence, then
53 ** the overflow pages associated with a cell will appear earlier in the
54 ** sort-order than its child page:
56 ** '/1c2/000/' // Left-most child of 451st child of root
60 " name STRING, /* Name of table or index */" \
61 " path INTEGER, /* Path to page from root */" \
62 " pageno INTEGER, /* Page number */" \
63 " pagetype STRING, /* 'internal', 'leaf' or 'overflow' */" \
64 " ncell INTEGER, /* Cells on page (0 for overflow) */" \
65 " payload INTEGER, /* Bytes of payload on this page */" \
66 " unused INTEGER, /* Bytes of unused space on this page */" \
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 */" \
73 typedef struct StatTable StatTable
;
74 typedef struct StatCursor StatCursor
;
75 typedef struct StatPage StatPage
;
76 typedef struct StatCell StatCell
;
79 int nLocal
; /* Bytes of local payload */
80 u32 iChildPg
; /* Child node (or 0 if this is a leaf) */
81 int nOvfl
; /* Entries in aOvfl[] */
82 u32
*aOvfl
; /* Array of overflow page numbers */
83 int nLastOvfl
; /* Bytes of payload on final overflow page */
84 int iOvfl
; /* Iterates through aOvfl[] */
92 char *zPath
; /* Path to this page */
94 /* Variables populated by statDecodePage(): */
95 u8 flags
; /* Copy of flags byte */
96 int nCell
; /* Number of cells on page */
97 int nUnused
; /* Number of unused bytes on page */
98 StatCell
*aCell
; /* Array of parsed cells */
99 u32 iRightChildPg
; /* Right-child page number (or 0) */
100 int nMxPayload
; /* Largest payload of any cell on this page */
104 sqlite3_vtab_cursor base
;
105 sqlite3_stmt
*pStmt
; /* Iterates through set of root pages */
106 int isEof
; /* After pStmt has returned SQLITE_DONE */
109 int iPage
; /* Current entry in aPage[] */
111 /* Values to return. */
112 char *zName
; /* Value of 'name' column */
113 char *zPath
; /* Value of 'path' column */
114 u32 iPageno
; /* Value of 'pageno' column */
115 char *zPagetype
; /* Value of 'pagetype' column */
116 int nCell
; /* Value of 'ncell' column */
117 int nPayload
; /* Value of 'payload' column */
118 int nUnused
; /* Value of 'unused' column */
119 int nMxPayload
; /* Value of 'mx_payload' column */
120 i64 iOffset
; /* Value of 'pgOffset' column */
121 int szPage
; /* Value of 'pgSize' column */
130 # define get2byte(x) ((x)[0]<<8 | (x)[1])
134 ** Connect to or create a statvfs virtual table.
136 static int statConnect(
139 int argc
, const char *const*argv
,
140 sqlite3_vtab
**ppVtab
,
145 pTab
= (StatTable
*)sqlite3_malloc(sizeof(StatTable
));
146 memset(pTab
, 0, sizeof(StatTable
));
149 sqlite3_declare_vtab(db
, VTAB_SCHEMA
);
150 *ppVtab
= &pTab
->base
;
155 ** Disconnect from or destroy a statvfs virtual table.
157 static int statDisconnect(sqlite3_vtab
*pVtab
){
163 ** There is no "best-index". This virtual table always does a linear
164 ** scan of the binary VFS log file.
166 static int statBestIndex(sqlite3_vtab
*tab
, sqlite3_index_info
*pIdxInfo
){
168 /* Records are always returned in ascending order of (name, path).
169 ** If this will satisfy the client, set the orderByConsumed flag so that
170 ** SQLite does not do an external sort.
172 if( ( pIdxInfo
->nOrderBy
==1
173 && pIdxInfo
->aOrderBy
[0].iColumn
==0
174 && pIdxInfo
->aOrderBy
[0].desc
==0
176 ( pIdxInfo
->nOrderBy
==2
177 && pIdxInfo
->aOrderBy
[0].iColumn
==0
178 && pIdxInfo
->aOrderBy
[0].desc
==0
179 && pIdxInfo
->aOrderBy
[1].iColumn
==1
180 && pIdxInfo
->aOrderBy
[1].desc
==0
183 pIdxInfo
->orderByConsumed
= 1;
186 pIdxInfo
->estimatedCost
= 10.0;
191 ** Open a new statvfs cursor.
193 static int statOpen(sqlite3_vtab
*pVTab
, sqlite3_vtab_cursor
**ppCursor
){
194 StatTable
*pTab
= (StatTable
*)pVTab
;
198 pCsr
= (StatCursor
*)sqlite3_malloc(sizeof(StatCursor
));
199 memset(pCsr
, 0, sizeof(StatCursor
));
200 pCsr
->base
.pVtab
= pVTab
;
202 rc
= sqlite3_prepare_v2(pTab
->db
,
203 "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
205 "SELECT name, rootpage, type FROM sqlite_master WHERE rootpage!=0"
206 " ORDER BY name", -1,
214 *ppCursor
= (sqlite3_vtab_cursor
*)pCsr
;
218 static void statClearPage(StatPage
*p
){
220 for(i
=0; i
<p
->nCell
; i
++){
221 sqlite3_free(p
->aCell
[i
].aOvfl
);
223 sqlite3PagerUnref(p
->pPg
);
224 sqlite3_free(p
->aCell
);
225 sqlite3_free(p
->zPath
);
226 memset(p
, 0, sizeof(StatPage
));
229 static void statResetCsr(StatCursor
*pCsr
){
231 sqlite3_reset(pCsr
->pStmt
);
232 for(i
=0; i
<ArraySize(pCsr
->aPage
); i
++){
233 statClearPage(&pCsr
->aPage
[i
]);
236 sqlite3_free(pCsr
->zPath
);
241 ** Close a statvfs cursor.
243 static int statClose(sqlite3_vtab_cursor
*pCursor
){
244 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
246 sqlite3_finalize(pCsr
->pStmt
);
251 static void getLocalPayload(
252 int nUsable
, /* Usable bytes per page */
253 u8 flags
, /* Page flags */
254 int nTotal
, /* Total record (payload) size */
255 int *pnLocal
/* OUT: Bytes stored locally */
261 if( flags
==0x0D ){ /* Table leaf node */
262 nMinLocal
= (nUsable
- 12) * 32 / 255 - 23;
263 nMaxLocal
= nUsable
- 35;
264 }else{ /* Index interior and leaf nodes */
265 nMinLocal
= (nUsable
- 12) * 32 / 255 - 23;
266 nMaxLocal
= (nUsable
- 12) * 64 / 255 - 23;
269 nLocal
= nMinLocal
+ (nTotal
- nMinLocal
) % (nUsable
- 4);
270 if( nLocal
>nMaxLocal
) nLocal
= nMinLocal
;
274 static int statDecodePage(Btree
*pBt
, StatPage
*p
){
281 u8
*aData
= sqlite3PagerGetData(p
->pPg
);
282 u8
*aHdr
= &aData
[p
->iPgno
==1 ? 100 : 0];
285 p
->nCell
= get2byte(&aHdr
[3]);
288 isLeaf
= (p
->flags
==0x0A || p
->flags
==0x0D);
289 nHdr
= 12 - isLeaf
*4 + (p
->iPgno
==1)*100;
291 nUnused
= get2byte(&aHdr
[5]) - nHdr
- 2*p
->nCell
;
292 nUnused
+= (int)aHdr
[7];
293 iOff
= get2byte(&aHdr
[1]);
295 nUnused
+= get2byte(&aData
[iOff
+2]);
296 iOff
= get2byte(&aData
[iOff
]);
298 p
->nUnused
= nUnused
;
299 p
->iRightChildPg
= isLeaf
? 0 : sqlite3Get4byte(&aHdr
[8]);
300 szPage
= sqlite3BtreeGetPageSize(pBt
);
303 int i
; /* Used to iterate through cells */
304 int nUsable
= szPage
- sqlite3BtreeGetReserve(pBt
);
306 p
->aCell
= sqlite3_malloc((p
->nCell
+1) * sizeof(StatCell
));
307 memset(p
->aCell
, 0, (p
->nCell
+1) * sizeof(StatCell
));
309 for(i
=0; i
<p
->nCell
; i
++){
310 StatCell
*pCell
= &p
->aCell
[i
];
312 iOff
= get2byte(&aData
[nHdr
+i
*2]);
314 pCell
->iChildPg
= sqlite3Get4byte(&aData
[iOff
]);
317 if( p
->flags
==0x05 ){
318 /* A table interior node. nPayload==0. */
320 u32 nPayload
; /* Bytes of payload total (local+overflow) */
321 int nLocal
; /* Bytes of payload stored locally */
322 iOff
+= getVarint32(&aData
[iOff
], nPayload
);
323 if( p
->flags
==0x0D ){
325 iOff
+= sqlite3GetVarint(&aData
[iOff
], &dummy
);
327 if( nPayload
>(u32
)p
->nMxPayload
) p
->nMxPayload
= nPayload
;
328 getLocalPayload(nUsable
, p
->flags
, nPayload
, &nLocal
);
329 pCell
->nLocal
= nLocal
;
331 assert( nPayload
>=(u32
)nLocal
);
332 assert( nLocal
<=(nUsable
-35) );
333 if( nPayload
>(u32
)nLocal
){
335 int nOvfl
= ((nPayload
- nLocal
) + nUsable
-4 - 1) / (nUsable
- 4);
336 pCell
->nLastOvfl
= (nPayload
-nLocal
) - (nOvfl
-1) * (nUsable
-4);
337 pCell
->nOvfl
= nOvfl
;
338 pCell
->aOvfl
= sqlite3_malloc(sizeof(u32
)*nOvfl
);
339 pCell
->aOvfl
[0] = sqlite3Get4byte(&aData
[iOff
+nLocal
]);
340 for(j
=1; j
<nOvfl
; j
++){
342 u32 iPrev
= pCell
->aOvfl
[j
-1];
344 rc
= sqlite3PagerGet(sqlite3BtreePager(pBt
), iPrev
, &pPg
);
349 pCell
->aOvfl
[j
] = sqlite3Get4byte(sqlite3PagerGetData(pPg
));
350 sqlite3PagerUnref(pPg
);
361 ** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on
362 ** the current value of pCsr->iPageno.
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
);
371 /* The default page size and offset */
372 pCsr
->szPage
= sqlite3BtreeGetPageSize(pBt
);
373 pCsr
->iOffset
= (i64
)pCsr
->szPage
* (pCsr
->iPageno
- 1);
375 /* If connected to a ZIPVFS backend, override the page size and
376 ** offset with actual values obtained from ZIPVFS.
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];
387 ** Move a statvfs cursor to the next entry in the file.
389 static int statNext(sqlite3_vtab_cursor
*pCursor
){
392 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
393 StatTable
*pTab
= (StatTable
*)pCursor
->pVtab
;
394 Btree
*pBt
= pTab
->db
->aDb
[0].pBt
;
395 Pager
*pPager
= sqlite3BtreePager(pBt
);
397 sqlite3_free(pCsr
->zPath
);
401 if( pCsr
->aPage
[0].pPg
==0 ){
402 rc
= sqlite3_step(pCsr
->pStmt
);
403 if( rc
==SQLITE_ROW
){
405 u32 iRoot
= (u32
)sqlite3_column_int64(pCsr
->pStmt
, 1);
406 sqlite3PagerPagecount(pPager
, &nPage
);
409 return sqlite3_reset(pCsr
->pStmt
);
411 rc
= sqlite3PagerGet(pPager
, iRoot
, &pCsr
->aPage
[0].pPg
);
412 pCsr
->aPage
[0].iPgno
= iRoot
;
413 pCsr
->aPage
[0].iCell
= 0;
414 pCsr
->aPage
[0].zPath
= sqlite3_mprintf("/");
418 return sqlite3_reset(pCsr
->pStmt
);
422 /* Page p itself has already been visited. */
423 StatPage
*p
= &pCsr
->aPage
[pCsr
->iPage
];
425 while( p
->iCell
<p
->nCell
){
426 StatCell
*pCell
= &p
->aCell
[p
->iCell
];
427 if( pCell
->iOvfl
<pCell
->nOvfl
){
428 int nUsable
= sqlite3BtreeGetPageSize(pBt
)-sqlite3BtreeGetReserve(pBt
);
429 pCsr
->zName
= (char *)sqlite3_column_text(pCsr
->pStmt
, 0);
430 pCsr
->iPageno
= pCell
->aOvfl
[pCell
->iOvfl
];
431 pCsr
->zPagetype
= "overflow";
433 pCsr
->nMxPayload
= 0;
434 pCsr
->zPath
= sqlite3_mprintf(
435 "%s%.3x+%.6x", p
->zPath
, p
->iCell
, pCell
->iOvfl
437 if( pCell
->iOvfl
<pCell
->nOvfl
-1 ){
439 pCsr
->nPayload
= nUsable
- 4;
441 pCsr
->nPayload
= pCell
->nLastOvfl
;
442 pCsr
->nUnused
= nUsable
- 4 - pCsr
->nPayload
;
445 statSizeAndOffset(pCsr
);
448 if( p
->iRightChildPg
) break;
452 if( !p
->iRightChildPg
|| p
->iCell
>p
->nCell
){
454 if( pCsr
->iPage
==0 ) return statNext(pCursor
);
456 goto statNextRestart
; /* Tail recursion */
459 assert( p
==&pCsr
->aPage
[pCsr
->iPage
-1] );
461 if( p
->iCell
==p
->nCell
){
462 p
[1].iPgno
= p
->iRightChildPg
;
464 p
[1].iPgno
= p
->aCell
[p
->iCell
].iChildPg
;
466 rc
= sqlite3PagerGet(pPager
, p
[1].iPgno
, &p
[1].pPg
);
468 p
[1].zPath
= sqlite3_mprintf("%s%.3x/", p
->zPath
, p
->iCell
);
473 /* Populate the StatCursor fields with the values to be returned
474 ** by the xColumn() and xRowid() methods.
478 StatPage
*p
= &pCsr
->aPage
[pCsr
->iPage
];
479 pCsr
->zName
= (char *)sqlite3_column_text(pCsr
->pStmt
, 0);
480 pCsr
->iPageno
= p
->iPgno
;
482 statDecodePage(pBt
, p
);
483 statSizeAndOffset(pCsr
);
486 case 0x05: /* table internal */
487 case 0x02: /* index internal */
488 pCsr
->zPagetype
= "internal";
490 case 0x0D: /* table leaf */
491 case 0x0A: /* index leaf */
492 pCsr
->zPagetype
= "leaf";
495 pCsr
->zPagetype
= "corrupted";
498 pCsr
->nCell
= p
->nCell
;
499 pCsr
->nUnused
= p
->nUnused
;
500 pCsr
->nMxPayload
= p
->nMxPayload
;
501 pCsr
->zPath
= sqlite3_mprintf("%s", p
->zPath
);
503 for(i
=0; i
<p
->nCell
; i
++){
504 nPayload
+= p
->aCell
[i
].nLocal
;
506 pCsr
->nPayload
= nPayload
;
512 static int statEof(sqlite3_vtab_cursor
*pCursor
){
513 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
517 static int statFilter(
518 sqlite3_vtab_cursor
*pCursor
,
519 int idxNum
, const char *idxStr
,
520 int argc
, sqlite3_value
**argv
522 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
525 return statNext(pCursor
);
528 static int statColumn(
529 sqlite3_vtab_cursor
*pCursor
,
530 sqlite3_context
*ctx
,
533 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
536 sqlite3_result_text(ctx
, pCsr
->zName
, -1, SQLITE_STATIC
);
539 sqlite3_result_text(ctx
, pCsr
->zPath
, -1, SQLITE_TRANSIENT
);
542 sqlite3_result_int64(ctx
, pCsr
->iPageno
);
544 case 3: /* pagetype */
545 sqlite3_result_text(ctx
, pCsr
->zPagetype
, -1, SQLITE_STATIC
);
548 sqlite3_result_int(ctx
, pCsr
->nCell
);
550 case 5: /* payload */
551 sqlite3_result_int(ctx
, pCsr
->nPayload
);
554 sqlite3_result_int(ctx
, pCsr
->nUnused
);
556 case 7: /* mx_payload */
557 sqlite3_result_int(ctx
, pCsr
->nMxPayload
);
559 case 8: /* pgoffset */
560 sqlite3_result_int64(ctx
, pCsr
->iOffset
);
563 sqlite3_result_int(ctx
, pCsr
->szPage
);
569 static int statRowid(sqlite3_vtab_cursor
*pCursor
, sqlite_int64
*pRowid
){
570 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
571 *pRowid
= pCsr
->iPageno
;
575 int sqlite3_dbstat_register(sqlite3
*db
){
576 static sqlite3_module dbstat_module
= {
578 statConnect
, /* xCreate */
579 statConnect
, /* xConnect */
580 statBestIndex
, /* xBestIndex */
581 statDisconnect
, /* xDisconnect */
582 statDisconnect
, /* xDestroy */
583 statOpen
, /* xOpen - open a cursor */
584 statClose
, /* xClose - close a cursor */
585 statFilter
, /* xFilter - configure scan constraints */
586 statNext
, /* xNext - advance a cursor */
587 statEof
, /* xEof - check for end of scan */
588 statColumn
, /* xColumn - read data */
589 statRowid
, /* xRowid - read data */
598 sqlite3_create_module(db
, "dbstat", &dbstat_module
, 0);
604 #if defined(SQLITE_TEST) || TCLSH==2
607 static int test_dbstat(
611 Tcl_Obj
*CONST objv
[]
613 #ifdef SQLITE_OMIT_VIRTUALTABLE
614 Tcl_AppendResult(interp
, "dbstat not available because of "
615 "SQLITE_OMIT_VIRTUALTABLE", (void*)0);
618 struct SqliteDb
{ sqlite3
*db
; };
623 Tcl_WrongNumArgs(interp
, 1, objv
, "DB");
627 zDb
= Tcl_GetString(objv
[1]);
628 if( Tcl_GetCommandInfo(interp
, zDb
, &cmdInfo
) ){
629 sqlite3
* db
= ((struct SqliteDb
*)cmdInfo
.objClientData
)->db
;
630 sqlite3_dbstat_register(db
);
636 int SqlitetestStat_Init(Tcl_Interp
*interp
){
637 Tcl_CreateObjCommand(interp
, "register_dbstat_vtab", test_dbstat
, 0, 0);
640 #endif /* if defined(SQLITE_TEST) || TCLSH==2 */