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 storage
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.
20 ** Additional information is available on the "dbstat.html" page of the
21 ** official SQLite documentation.
24 #include "sqliteInt.h" /* Requires access to internal data structures */
25 #if (defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)) \
26 && !defined(SQLITE_OMIT_VIRTUALTABLE)
29 ** The pager and btree modules arrange objects in memory so that there are
30 ** always approximately 200 bytes of addressable memory following each page
31 ** buffer. This way small buffer overreads caused by corrupt database pages
32 ** do not cause undefined behaviour. This module pads each page buffer
33 ** by the following number of bytes for the same purpose.
35 #define DBSTAT_PAGE_PADDING_BYTES 256
40 ** The value of the 'path' column describes the path taken from the
41 ** root-node of the b-tree structure to each page. The value of the
42 ** root-node path is '/'.
44 ** The value of the path for the left-most child page of the root of
45 ** a b-tree is '/000/'. (Btrees store content ordered from left to right
46 ** so the pages to the left have smaller keys than the pages to the right.)
47 ** The next to left-most child of the root page is
48 ** '/001', and so on, each sibling page identified by a 3-digit hex
49 ** value. The children of the 451st left-most sibling have paths such
50 ** as '/1c2/000/, '/1c2/001/' etc.
52 ** Overflow pages are specified by appending a '+' character and a
53 ** six-digit hexadecimal value to the path to the cell they are linked
54 ** from. For example, the three overflow pages in a chain linked from
55 ** the left-most cell of the 450th child of the root page are identified
58 ** '/1c2/000+000000' // First page in overflow chain
59 ** '/1c2/000+000001' // Second page in overflow chain
60 ** '/1c2/000+000002' // Third page in overflow chain
62 ** If the paths are sorted using the BINARY collation sequence, then
63 ** the overflow pages associated with a cell will appear earlier in the
64 ** sort-order than its child page:
66 ** '/1c2/000/' // Left-most child of 451st child of root
68 static const char zDbstatSchema
[] =
70 " name TEXT," /* 0 Name of table or index */
71 " path TEXT," /* 1 Path to page from root (NULL for agg) */
72 " pageno INTEGER," /* 2 Page number (page count for aggregates) */
73 " pagetype TEXT," /* 3 'internal', 'leaf', 'overflow', or NULL */
74 " ncell INTEGER," /* 4 Cells on page (0 for overflow) */
75 " payload INTEGER," /* 5 Bytes of payload on this page */
76 " unused INTEGER," /* 6 Bytes of unused space on this page */
77 " mx_payload INTEGER," /* 7 Largest payload size of all cells */
78 " pgoffset INTEGER," /* 8 Offset of page in file (NULL for agg) */
79 " pgsize INTEGER," /* 9 Size of the page (sum for aggregate) */
80 " schema TEXT HIDDEN," /* 10 Database schema being analyzed */
81 " aggregate BOOLEAN HIDDEN" /* 11 aggregate info for each table */
85 /* Forward reference to data structured used in this module */
86 typedef struct StatTable StatTable
;
87 typedef struct StatCursor StatCursor
;
88 typedef struct StatPage StatPage
;
89 typedef struct StatCell StatCell
;
91 /* Size information for a single cell within a btree page */
93 int nLocal
; /* Bytes of local payload */
94 u32 iChildPg
; /* Child node (or 0 if this is a leaf) */
95 int nOvfl
; /* Entries in aOvfl[] */
96 u32
*aOvfl
; /* Array of overflow page numbers */
97 int nLastOvfl
; /* Bytes of payload on final overflow page */
98 int iOvfl
; /* Iterates through aOvfl[] */
101 /* Size information for a single btree page */
103 u32 iPgno
; /* Page number */
104 u8
*aPg
; /* Page buffer from sqlite3_malloc() */
105 int iCell
; /* Current cell */
106 char *zPath
; /* Path to this page */
108 /* Variables populated by statDecodePage(): */
109 u8 flags
; /* Copy of flags byte */
110 int nCell
; /* Number of cells on page */
111 int nUnused
; /* Number of unused bytes on page */
112 StatCell
*aCell
; /* Array of parsed cells */
113 u32 iRightChildPg
; /* Right-child page number (or 0) */
114 int nMxPayload
; /* Largest payload of any cell on the page */
117 /* The cursor for scanning the dbstat virtual table */
119 sqlite3_vtab_cursor base
; /* base class. MUST BE FIRST! */
120 sqlite3_stmt
*pStmt
; /* Iterates through set of root pages */
121 u8 isEof
; /* After pStmt has returned SQLITE_DONE */
122 u8 isAgg
; /* Aggregate results for each table */
123 int iDb
; /* Schema used for this query */
125 StatPage aPage
[32]; /* Pages in path to current page */
126 int iPage
; /* Current entry in aPage[] */
128 /* Values to return. */
129 u32 iPageno
; /* Value of 'pageno' column */
130 char *zName
; /* Value of 'name' column */
131 char *zPath
; /* Value of 'path' column */
132 char *zPagetype
; /* Value of 'pagetype' column */
133 int nPage
; /* Number of pages in current btree */
134 int nCell
; /* Value of 'ncell' column */
135 int nMxPayload
; /* Value of 'mx_payload' column */
136 i64 nUnused
; /* Value of 'unused' column */
137 i64 nPayload
; /* Value of 'payload' column */
138 i64 iOffset
; /* Value of 'pgOffset' column */
139 i64 szPage
; /* Value of 'pgSize' column */
142 /* An instance of the DBSTAT virtual table */
144 sqlite3_vtab base
; /* base class. MUST BE FIRST! */
145 sqlite3
*db
; /* Database connection that owns this vtab */
146 int iDb
; /* Index of database to analyze */
150 # define get2byte(x) ((x)[0]<<8 | (x)[1])
154 ** Connect to or create a new DBSTAT virtual table.
156 static int statConnect(
159 int argc
, const char *const*argv
,
160 sqlite3_vtab
**ppVtab
,
170 sqlite3TokenInit(&nm
, (char*)argv
[3]);
171 iDb
= sqlite3FindDb(db
, &nm
);
173 *pzErr
= sqlite3_mprintf("no such database: %s", argv
[3]);
179 sqlite3_vtab_config(db
, SQLITE_VTAB_DIRECTONLY
);
180 rc
= sqlite3_declare_vtab(db
, zDbstatSchema
);
182 pTab
= (StatTable
*)sqlite3_malloc64(sizeof(StatTable
));
183 if( pTab
==0 ) rc
= SQLITE_NOMEM_BKPT
;
186 assert( rc
==SQLITE_OK
|| pTab
==0 );
188 memset(pTab
, 0, sizeof(StatTable
));
193 *ppVtab
= (sqlite3_vtab
*)pTab
;
198 ** Disconnect from or destroy the DBSTAT virtual table.
200 static int statDisconnect(sqlite3_vtab
*pVtab
){
206 ** Compute the best query strategy and return the result in idxNum.
208 ** idxNum-Bit Meaning
209 ** ---------- ----------------------------------------------
210 ** 0x01 There is a schema=? term in the WHERE clause
211 ** 0x02 There is a name=? term in the WHERE clause
212 ** 0x04 There is an aggregate=? term in the WHERE clause
213 ** 0x08 Output should be ordered by name and path
215 static int statBestIndex(sqlite3_vtab
*tab
, sqlite3_index_info
*pIdxInfo
){
222 /* Look for a valid schema=? constraint. If found, change the idxNum to
223 ** 1 and request the value of that constraint be sent to xFilter. And
224 ** lower the cost estimate to encourage the constrained version to be
227 for(i
=0; i
<pIdxInfo
->nConstraint
; i
++){
228 if( pIdxInfo
->aConstraint
[i
].op
!=SQLITE_INDEX_CONSTRAINT_EQ
) continue;
229 if( pIdxInfo
->aConstraint
[i
].usable
==0 ){
230 /* Force DBSTAT table should always be the right-most table in a join */
231 return SQLITE_CONSTRAINT
;
233 switch( pIdxInfo
->aConstraint
[i
].iColumn
){
238 case 10: { /* schema */
242 case 11: { /* aggregate */
250 pIdxInfo
->aConstraintUsage
[iSchema
].argvIndex
= ++i
;
251 pIdxInfo
->aConstraintUsage
[iSchema
].omit
= 1;
252 pIdxInfo
->idxNum
|= 0x01;
255 pIdxInfo
->aConstraintUsage
[iName
].argvIndex
= ++i
;
256 pIdxInfo
->idxNum
|= 0x02;
259 pIdxInfo
->aConstraintUsage
[iAgg
].argvIndex
= ++i
;
260 pIdxInfo
->idxNum
|= 0x04;
262 pIdxInfo
->estimatedCost
= 1.0;
264 /* Records are always returned in ascending order of (name, path).
265 ** If this will satisfy the client, set the orderByConsumed flag so that
266 ** SQLite does not do an external sort.
268 if( ( pIdxInfo
->nOrderBy
==1
269 && pIdxInfo
->aOrderBy
[0].iColumn
==0
270 && pIdxInfo
->aOrderBy
[0].desc
==0
272 ( pIdxInfo
->nOrderBy
==2
273 && pIdxInfo
->aOrderBy
[0].iColumn
==0
274 && pIdxInfo
->aOrderBy
[0].desc
==0
275 && pIdxInfo
->aOrderBy
[1].iColumn
==1
276 && pIdxInfo
->aOrderBy
[1].desc
==0
279 pIdxInfo
->orderByConsumed
= 1;
280 pIdxInfo
->idxNum
|= 0x08;
287 ** Open a new DBSTAT cursor.
289 static int statOpen(sqlite3_vtab
*pVTab
, sqlite3_vtab_cursor
**ppCursor
){
290 StatTable
*pTab
= (StatTable
*)pVTab
;
293 pCsr
= (StatCursor
*)sqlite3_malloc64(sizeof(StatCursor
));
295 return SQLITE_NOMEM_BKPT
;
297 memset(pCsr
, 0, sizeof(StatCursor
));
298 pCsr
->base
.pVtab
= pVTab
;
299 pCsr
->iDb
= pTab
->iDb
;
302 *ppCursor
= (sqlite3_vtab_cursor
*)pCsr
;
306 static void statClearCells(StatPage
*p
){
309 for(i
=0; i
<p
->nCell
; i
++){
310 sqlite3_free(p
->aCell
[i
].aOvfl
);
312 sqlite3_free(p
->aCell
);
318 static void statClearPage(StatPage
*p
){
321 sqlite3_free(p
->zPath
);
322 memset(p
, 0, sizeof(StatPage
));
326 static void statResetCsr(StatCursor
*pCsr
){
328 /* In some circumstances, specifically if an OOM has occurred, the call
329 ** to sqlite3_reset() may cause the pager to be reset (emptied). It is
330 ** important that statClearPage() is called to free any page refs before
331 ** this happens. dbsqlfuzz 9ed3e4e3816219d3509d711636c38542bf3f40b1. */
332 for(i
=0; i
<ArraySize(pCsr
->aPage
); i
++){
333 statClearPage(&pCsr
->aPage
[i
]);
334 sqlite3_free(pCsr
->aPage
[i
].aPg
);
335 pCsr
->aPage
[i
].aPg
= 0;
337 sqlite3_reset(pCsr
->pStmt
);
339 sqlite3_free(pCsr
->zPath
);
344 /* Resize the space-used counters inside of the cursor */
345 static void statResetCounts(StatCursor
*pCsr
){
347 pCsr
->nMxPayload
= 0;
355 ** Close a DBSTAT cursor.
357 static int statClose(sqlite3_vtab_cursor
*pCursor
){
358 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
360 sqlite3_finalize(pCsr
->pStmt
);
366 ** For a single cell on a btree page, compute the number of bytes of
367 ** content (payload) stored on that page. That is to say, compute the
368 ** number of bytes of content not found on overflow pages.
370 static int getLocalPayload(
371 int nUsable
, /* Usable bytes per page */
372 u8 flags
, /* Page flags */
373 int nTotal
/* Total record (payload) size */
379 if( flags
==0x0D ){ /* Table leaf node */
380 nMinLocal
= (nUsable
- 12) * 32 / 255 - 23;
381 nMaxLocal
= nUsable
- 35;
382 }else{ /* Index interior and leaf nodes */
383 nMinLocal
= (nUsable
- 12) * 32 / 255 - 23;
384 nMaxLocal
= (nUsable
- 12) * 64 / 255 - 23;
387 nLocal
= nMinLocal
+ (nTotal
- nMinLocal
) % (nUsable
- 4);
388 if( nLocal
>nMaxLocal
) nLocal
= nMinLocal
;
392 /* Populate the StatPage object with information about the all
393 ** cells found on the page currently under analysis.
395 static int statDecodePage(Btree
*pBt
, StatPage
*p
){
403 u8
*aHdr
= &aData
[p
->iPgno
==1 ? 100 : 0];
406 if( p
->flags
==0x0A || p
->flags
==0x0D ){
409 }else if( p
->flags
==0x05 || p
->flags
==0x02 ){
413 goto statPageIsCorrupt
;
415 if( p
->iPgno
==1 ) nHdr
+= 100;
416 p
->nCell
= get2byte(&aHdr
[3]);
418 szPage
= sqlite3BtreeGetPageSize(pBt
);
420 nUnused
= get2byte(&aHdr
[5]) - nHdr
- 2*p
->nCell
;
421 nUnused
+= (int)aHdr
[7];
422 iOff
= get2byte(&aHdr
[1]);
425 if( iOff
>=szPage
) goto statPageIsCorrupt
;
426 nUnused
+= get2byte(&aData
[iOff
+2]);
427 iNext
= get2byte(&aData
[iOff
]);
428 if( iNext
<iOff
+4 && iNext
>0 ) goto statPageIsCorrupt
;
431 p
->nUnused
= nUnused
;
432 p
->iRightChildPg
= isLeaf
? 0 : sqlite3Get4byte(&aHdr
[8]);
435 int i
; /* Used to iterate through cells */
436 int nUsable
; /* Usable bytes per page */
438 sqlite3BtreeEnter(pBt
);
439 nUsable
= szPage
- sqlite3BtreeGetReserveNoMutex(pBt
);
440 sqlite3BtreeLeave(pBt
);
441 p
->aCell
= sqlite3_malloc64((p
->nCell
+1) * sizeof(StatCell
));
442 if( p
->aCell
==0 ) return SQLITE_NOMEM_BKPT
;
443 memset(p
->aCell
, 0, (p
->nCell
+1) * sizeof(StatCell
));
445 for(i
=0; i
<p
->nCell
; i
++){
446 StatCell
*pCell
= &p
->aCell
[i
];
448 iOff
= get2byte(&aData
[nHdr
+i
*2]);
449 if( iOff
<nHdr
|| iOff
>=szPage
) goto statPageIsCorrupt
;
451 pCell
->iChildPg
= sqlite3Get4byte(&aData
[iOff
]);
454 if( p
->flags
==0x05 ){
455 /* A table interior node. nPayload==0. */
457 u32 nPayload
; /* Bytes of payload total (local+overflow) */
458 int nLocal
; /* Bytes of payload stored locally */
459 iOff
+= getVarint32(&aData
[iOff
], nPayload
);
460 if( p
->flags
==0x0D ){
462 iOff
+= sqlite3GetVarint(&aData
[iOff
], &dummy
);
464 if( nPayload
>(u32
)p
->nMxPayload
) p
->nMxPayload
= nPayload
;
465 nLocal
= getLocalPayload(nUsable
, p
->flags
, nPayload
);
466 if( nLocal
<0 ) goto statPageIsCorrupt
;
467 pCell
->nLocal
= nLocal
;
468 assert( nPayload
>=(u32
)nLocal
);
469 assert( nLocal
<=(nUsable
-35) );
470 if( nPayload
>(u32
)nLocal
){
472 int nOvfl
= ((nPayload
- nLocal
) + nUsable
-4 - 1) / (nUsable
- 4);
473 if( iOff
+nLocal
+4>nUsable
|| nPayload
>0x7fffffff ){
474 goto statPageIsCorrupt
;
476 pCell
->nLastOvfl
= (nPayload
-nLocal
) - (nOvfl
-1) * (nUsable
-4);
477 pCell
->nOvfl
= nOvfl
;
478 pCell
->aOvfl
= sqlite3_malloc64(sizeof(u32
)*nOvfl
);
479 if( pCell
->aOvfl
==0 ) return SQLITE_NOMEM_BKPT
;
480 pCell
->aOvfl
[0] = sqlite3Get4byte(&aData
[iOff
+nLocal
]);
481 for(j
=1; j
<nOvfl
; j
++){
483 u32 iPrev
= pCell
->aOvfl
[j
-1];
485 rc
= sqlite3PagerGet(sqlite3BtreePager(pBt
), iPrev
, &pPg
, 0);
490 pCell
->aOvfl
[j
] = sqlite3Get4byte(sqlite3PagerGetData(pPg
));
491 sqlite3PagerUnref(pPg
);
507 ** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on
508 ** the current value of pCsr->iPageno.
510 static void statSizeAndOffset(StatCursor
*pCsr
){
511 StatTable
*pTab
= (StatTable
*)((sqlite3_vtab_cursor
*)pCsr
)->pVtab
;
512 Btree
*pBt
= pTab
->db
->aDb
[pTab
->iDb
].pBt
;
513 Pager
*pPager
= sqlite3BtreePager(pBt
);
517 /* If connected to a ZIPVFS backend, find the page size and
518 ** offset from ZIPVFS.
520 fd
= sqlite3PagerFile(pPager
);
521 x
[0] = pCsr
->iPageno
;
522 if( sqlite3OsFileControl(fd
, 230440, &x
)==SQLITE_OK
){
523 pCsr
->iOffset
= x
[0];
524 pCsr
->szPage
+= x
[1];
526 /* Not ZIPVFS: The default page size and offset */
527 pCsr
->szPage
+= sqlite3BtreeGetPageSize(pBt
);
528 pCsr
->iOffset
= (i64
)pCsr
->szPage
* (pCsr
->iPageno
- 1);
533 ** Load a copy of the page data for page iPg into the buffer belonging
534 ** to page object pPg. Allocate the buffer if necessary. Return SQLITE_OK
535 ** if successful, or an SQLite error code otherwise.
537 static int statGetPage(
538 Btree
*pBt
, /* Load page from this b-tree */
539 u32 iPg
, /* Page number to load */
540 StatPage
*pPg
/* Load page into this object */
542 int pgsz
= sqlite3BtreeGetPageSize(pBt
);
547 pPg
->aPg
= (u8
*)sqlite3_malloc(pgsz
+ DBSTAT_PAGE_PADDING_BYTES
);
549 return SQLITE_NOMEM_BKPT
;
551 memset(&pPg
->aPg
[pgsz
], 0, DBSTAT_PAGE_PADDING_BYTES
);
554 rc
= sqlite3PagerGet(sqlite3BtreePager(pBt
), iPg
, &pDbPage
, 0);
556 const u8
*a
= sqlite3PagerGetData(pDbPage
);
557 memcpy(pPg
->aPg
, a
, pgsz
);
558 sqlite3PagerUnref(pDbPage
);
565 ** Move a DBSTAT cursor to the next entry. Normally, the next
566 ** entry will be the next page, but in aggregated mode (pCsr->isAgg!=0),
567 ** the next entry is the next btree.
569 static int statNext(sqlite3_vtab_cursor
*pCursor
){
573 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
574 StatTable
*pTab
= (StatTable
*)pCursor
->pVtab
;
575 Btree
*pBt
= pTab
->db
->aDb
[pCsr
->iDb
].pBt
;
576 Pager
*pPager
= sqlite3BtreePager(pBt
);
578 sqlite3_free(pCsr
->zPath
);
583 /* Start measuring space on the next btree */
584 statResetCounts(pCsr
);
585 rc
= sqlite3_step(pCsr
->pStmt
);
586 if( rc
==SQLITE_ROW
){
588 u32 iRoot
= (u32
)sqlite3_column_int64(pCsr
->pStmt
, 1);
589 sqlite3PagerPagecount(pPager
, &nPage
);
592 return sqlite3_reset(pCsr
->pStmt
);
594 rc
= statGetPage(pBt
, iRoot
, &pCsr
->aPage
[0]);
595 pCsr
->aPage
[0].iPgno
= iRoot
;
596 pCsr
->aPage
[0].iCell
= 0;
598 pCsr
->aPage
[0].zPath
= z
= sqlite3_mprintf("/");
599 if( z
==0 ) rc
= SQLITE_NOMEM_BKPT
;
605 return sqlite3_reset(pCsr
->pStmt
);
608 /* Continue analyzing the btree previously started */
609 StatPage
*p
= &pCsr
->aPage
[pCsr
->iPage
];
610 if( !pCsr
->isAgg
) statResetCounts(pCsr
);
611 while( p
->iCell
<p
->nCell
){
612 StatCell
*pCell
= &p
->aCell
[p
->iCell
];
613 while( pCell
->iOvfl
<pCell
->nOvfl
){
615 sqlite3BtreeEnter(pBt
);
616 nUsable
= sqlite3BtreeGetPageSize(pBt
) -
617 sqlite3BtreeGetReserveNoMutex(pBt
);
618 sqlite3BtreeLeave(pBt
);
620 statSizeAndOffset(pCsr
);
621 if( pCell
->iOvfl
<pCell
->nOvfl
-1 ){
622 pCsr
->nPayload
+= nUsable
- 4;
624 pCsr
->nPayload
+= pCell
->nLastOvfl
;
625 pCsr
->nUnused
+= nUsable
- 4 - pCell
->nLastOvfl
;
627 iOvfl
= pCell
->iOvfl
;
630 pCsr
->zName
= (char *)sqlite3_column_text(pCsr
->pStmt
, 0);
631 pCsr
->iPageno
= pCell
->aOvfl
[iOvfl
];
632 pCsr
->zPagetype
= "overflow";
633 pCsr
->zPath
= z
= sqlite3_mprintf(
634 "%s%.3x+%.6x", p
->zPath
, p
->iCell
, iOvfl
636 return z
==0 ? SQLITE_NOMEM_BKPT
: SQLITE_OK
;
639 if( p
->iRightChildPg
) break;
643 if( !p
->iRightChildPg
|| p
->iCell
>p
->nCell
){
646 if( pCsr
->isAgg
&& pCsr
->iPage
<0 ){
647 /* label-statNext-done: When computing aggregate space usage over
648 ** an entire btree, this is the exit point from this function */
651 goto statNextRestart
; /* Tail recursion */
654 if( pCsr
->iPage
>=ArraySize(pCsr
->aPage
) ){
656 return SQLITE_CORRUPT_BKPT
;
658 assert( p
==&pCsr
->aPage
[pCsr
->iPage
-1] );
660 if( p
->iCell
==p
->nCell
){
661 p
[1].iPgno
= p
->iRightChildPg
;
663 p
[1].iPgno
= p
->aCell
[p
->iCell
].iChildPg
;
665 rc
= statGetPage(pBt
, p
[1].iPgno
, &p
[1]);
669 p
[1].zPath
= z
= sqlite3_mprintf("%s%.3x/", p
->zPath
, p
->iCell
);
670 if( z
==0 ) rc
= SQLITE_NOMEM_BKPT
;
676 /* Populate the StatCursor fields with the values to be returned
677 ** by the xColumn() and xRowid() methods.
681 StatPage
*p
= &pCsr
->aPage
[pCsr
->iPage
];
682 pCsr
->zName
= (char *)sqlite3_column_text(pCsr
->pStmt
, 0);
683 pCsr
->iPageno
= p
->iPgno
;
685 rc
= statDecodePage(pBt
, p
);
687 statSizeAndOffset(pCsr
);
690 case 0x05: /* table internal */
691 case 0x02: /* index internal */
692 pCsr
->zPagetype
= "internal";
694 case 0x0D: /* table leaf */
695 case 0x0A: /* index leaf */
696 pCsr
->zPagetype
= "leaf";
699 pCsr
->zPagetype
= "corrupted";
702 pCsr
->nCell
+= p
->nCell
;
703 pCsr
->nUnused
+= p
->nUnused
;
704 if( p
->nMxPayload
>pCsr
->nMxPayload
) pCsr
->nMxPayload
= p
->nMxPayload
;
706 pCsr
->zPath
= z
= sqlite3_mprintf("%s", p
->zPath
);
707 if( z
==0 ) rc
= SQLITE_NOMEM_BKPT
;
710 for(i
=0; i
<p
->nCell
; i
++){
711 nPayload
+= p
->aCell
[i
].nLocal
;
713 pCsr
->nPayload
+= nPayload
;
715 /* If computing aggregate space usage by btree, continue with the
716 ** next page. The loop will exit via the return at label-statNext-done
718 if( pCsr
->isAgg
) goto statNextRestart
;
725 static int statEof(sqlite3_vtab_cursor
*pCursor
){
726 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
730 /* Initialize a cursor according to the query plan idxNum using the
731 ** arguments in argv[0]. See statBestIndex() for a description of the
732 ** meaning of the bits in idxNum.
734 static int statFilter(
735 sqlite3_vtab_cursor
*pCursor
,
736 int idxNum
, const char *idxStr
,
737 int argc
, sqlite3_value
**argv
739 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
740 StatTable
*pTab
= (StatTable
*)(pCursor
->pVtab
);
741 sqlite3_str
*pSql
; /* Query of btrees to analyze */
742 char *zSql
; /* String value of pSql */
743 int iArg
= 0; /* Count of argv[] parameters used so far */
744 int rc
= SQLITE_OK
; /* Result of this operation */
745 const char *zName
= 0; /* Only provide analysis of this table */
750 sqlite3_finalize(pCsr
->pStmt
);
753 /* schema=? constraint is present. Get its value */
754 const char *zDbase
= (const char*)sqlite3_value_text(argv
[iArg
++]);
755 pCsr
->iDb
= sqlite3FindDbName(pTab
->db
, zDbase
);
762 pCsr
->iDb
= pTab
->iDb
;
765 /* name=? constraint is present */
766 zName
= (const char*)sqlite3_value_text(argv
[iArg
++]);
769 /* aggregate=? constraint is present */
770 pCsr
->isAgg
= sqlite3_value_double(argv
[iArg
++])!=0.0;
774 pSql
= sqlite3_str_new(pTab
->db
);
775 sqlite3_str_appendf(pSql
,
777 "SELECT 'sqlite_schema' AS name,1 AS rootpage,'table' AS type"
779 "SELECT name,rootpage,type"
780 " FROM \"%w\".sqlite_schema WHERE rootpage!=0)",
781 pTab
->db
->aDb
[pCsr
->iDb
].zDbSName
);
783 sqlite3_str_appendf(pSql
, "WHERE name=%Q", zName
);
786 sqlite3_str_appendf(pSql
, " ORDER BY name");
788 zSql
= sqlite3_str_finish(pSql
);
790 return SQLITE_NOMEM_BKPT
;
792 rc
= sqlite3_prepare_v2(pTab
->db
, zSql
, -1, &pCsr
->pStmt
, 0);
798 rc
= statNext(pCursor
);
803 static int statColumn(
804 sqlite3_vtab_cursor
*pCursor
,
805 sqlite3_context
*ctx
,
808 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
811 sqlite3_result_text(ctx
, pCsr
->zName
, -1, SQLITE_TRANSIENT
);
815 sqlite3_result_text(ctx
, pCsr
->zPath
, -1, SQLITE_TRANSIENT
);
820 sqlite3_result_int64(ctx
, pCsr
->nPage
);
822 sqlite3_result_int64(ctx
, pCsr
->iPageno
);
825 case 3: /* pagetype */
827 sqlite3_result_text(ctx
, pCsr
->zPagetype
, -1, SQLITE_STATIC
);
831 sqlite3_result_int64(ctx
, pCsr
->nCell
);
833 case 5: /* payload */
834 sqlite3_result_int64(ctx
, pCsr
->nPayload
);
837 sqlite3_result_int64(ctx
, pCsr
->nUnused
);
839 case 7: /* mx_payload */
840 sqlite3_result_int64(ctx
, pCsr
->nMxPayload
);
842 case 8: /* pgoffset */
844 sqlite3_result_int64(ctx
, pCsr
->iOffset
);
848 sqlite3_result_int64(ctx
, pCsr
->szPage
);
850 case 10: { /* schema */
851 sqlite3
*db
= sqlite3_context_db_handle(ctx
);
853 sqlite3_result_text(ctx
, db
->aDb
[iDb
].zDbSName
, -1, SQLITE_STATIC
);
856 default: { /* aggregate */
857 sqlite3_result_int(ctx
, pCsr
->isAgg
);
864 static int statRowid(sqlite3_vtab_cursor
*pCursor
, sqlite_int64
*pRowid
){
865 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
866 *pRowid
= pCsr
->iPageno
;
871 ** Invoke this routine to register the "dbstat" virtual table module
873 int sqlite3DbstatRegister(sqlite3
*db
){
874 static sqlite3_module dbstat_module
= {
876 statConnect
, /* xCreate */
877 statConnect
, /* xConnect */
878 statBestIndex
, /* xBestIndex */
879 statDisconnect
, /* xDisconnect */
880 statDisconnect
, /* xDestroy */
881 statOpen
, /* xOpen - open a cursor */
882 statClose
, /* xClose - close a cursor */
883 statFilter
, /* xFilter - configure scan constraints */
884 statNext
, /* xNext - advance a cursor */
885 statEof
, /* xEof - check for end of scan */
886 statColumn
, /* xColumn - read data */
887 statRowid
, /* xRowid - read data */
901 return sqlite3_create_module(db
, "dbstat", &dbstat_module
, 0);
903 #elif defined(SQLITE_ENABLE_DBSTAT_VTAB)
904 int sqlite3DbstatRegister(sqlite3
*db
){ return SQLITE_OK
; }
905 #endif /* SQLITE_ENABLE_DBSTAT_VTAB */