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)
31 ** The value of the 'path' column describes the path taken from the
32 ** root-node of the b-tree structure to each page. The value of the
33 ** root-node path is '/'.
35 ** The value of the path for the left-most child page of the root of
36 ** a b-tree is '/000/'. (Btrees store content ordered from left to right
37 ** so the pages to the left have smaller keys than the pages to the right.)
38 ** The next to left-most child of the root page is
39 ** '/001', and so on, each sibling page identified by a 3-digit hex
40 ** value. The children of the 451st left-most sibling have paths such
41 ** as '/1c2/000/, '/1c2/001/' etc.
43 ** Overflow pages are specified by appending a '+' character and a
44 ** six-digit hexadecimal value to the path to the cell they are linked
45 ** from. For example, the three overflow pages in a chain linked from
46 ** the left-most cell of the 450th child of the root page are identified
49 ** '/1c2/000+000000' // First page in overflow chain
50 ** '/1c2/000+000001' // Second page in overflow chain
51 ** '/1c2/000+000002' // Third page in overflow chain
53 ** If the paths are sorted using the BINARY collation sequence, then
54 ** the overflow pages associated with a cell will appear earlier in the
55 ** sort-order than its child page:
57 ** '/1c2/000/' // Left-most child of 451st child of root
59 static const char zDbstatSchema
[] =
61 " name TEXT," /* 0 Name of table or index */
62 " path TEXT," /* 1 Path to page from root (NULL for agg) */
63 " pageno INTEGER," /* 2 Page number (page count for aggregates) */
64 " pagetype TEXT," /* 3 'internal', 'leaf', 'overflow', or NULL */
65 " ncell INTEGER," /* 4 Cells on page (0 for overflow) */
66 " payload INTEGER," /* 5 Bytes of payload on this page */
67 " unused INTEGER," /* 6 Bytes of unused space on this page */
68 " mx_payload INTEGER," /* 7 Largest payload size of all cells */
69 " pgoffset INTEGER," /* 8 Offset of page in file (NULL for agg) */
70 " pgsize INTEGER," /* 9 Size of the page (sum for aggregate) */
71 " schema TEXT HIDDEN," /* 10 Database schema being analyzed */
72 " aggregate BOOLEAN HIDDEN" /* 11 aggregate info for each table */
76 /* Forward reference to data structured used in this module */
77 typedef struct StatTable StatTable
;
78 typedef struct StatCursor StatCursor
;
79 typedef struct StatPage StatPage
;
80 typedef struct StatCell StatCell
;
82 /* Size information for a single cell within a btree page */
84 int nLocal
; /* Bytes of local payload */
85 u32 iChildPg
; /* Child node (or 0 if this is a leaf) */
86 int nOvfl
; /* Entries in aOvfl[] */
87 u32
*aOvfl
; /* Array of overflow page numbers */
88 int nLastOvfl
; /* Bytes of payload on final overflow page */
89 int iOvfl
; /* Iterates through aOvfl[] */
92 /* Size information for a single btree page */
94 u32 iPgno
; /* Page number */
95 DbPage
*pPg
; /* Page content */
96 int iCell
; /* Current cell */
98 char *zPath
; /* Path to this page */
100 /* Variables populated by statDecodePage(): */
101 u8 flags
; /* Copy of flags byte */
102 int nCell
; /* Number of cells on page */
103 int nUnused
; /* Number of unused bytes on page */
104 StatCell
*aCell
; /* Array of parsed cells */
105 u32 iRightChildPg
; /* Right-child page number (or 0) */
106 int nMxPayload
; /* Largest payload of any cell on the page */
109 /* The cursor for scanning the dbstat virtual table */
111 sqlite3_vtab_cursor base
; /* base class. MUST BE FIRST! */
112 sqlite3_stmt
*pStmt
; /* Iterates through set of root pages */
113 u8 isEof
; /* After pStmt has returned SQLITE_DONE */
114 u8 isAgg
; /* Aggregate results for each table */
115 int iDb
; /* Schema used for this query */
117 StatPage aPage
[32]; /* Pages in path to current page */
118 int iPage
; /* Current entry in aPage[] */
120 /* Values to return. */
121 u32 iPageno
; /* Value of 'pageno' column */
122 char *zName
; /* Value of 'name' column */
123 char *zPath
; /* Value of 'path' column */
124 char *zPagetype
; /* Value of 'pagetype' column */
125 int nPage
; /* Number of pages in current btree */
126 int nCell
; /* Value of 'ncell' column */
127 int nMxPayload
; /* Value of 'mx_payload' column */
128 i64 nUnused
; /* Value of 'unused' column */
129 i64 nPayload
; /* Value of 'payload' column */
130 i64 iOffset
; /* Value of 'pgOffset' column */
131 i64 szPage
; /* Value of 'pgSize' column */
134 /* An instance of the DBSTAT virtual table */
136 sqlite3_vtab base
; /* base class. MUST BE FIRST! */
137 sqlite3
*db
; /* Database connection that owns this vtab */
138 int iDb
; /* Index of database to analyze */
142 # define get2byte(x) ((x)[0]<<8 | (x)[1])
146 ** Connect to or create a new DBSTAT virtual table.
148 static int statConnect(
151 int argc
, const char *const*argv
,
152 sqlite3_vtab
**ppVtab
,
161 sqlite3TokenInit(&nm
, (char*)argv
[3]);
162 iDb
= sqlite3FindDb(db
, &nm
);
164 *pzErr
= sqlite3_mprintf("no such database: %s", argv
[3]);
170 sqlite3_vtab_config(db
, SQLITE_VTAB_DIRECTONLY
);
171 rc
= sqlite3_declare_vtab(db
, zDbstatSchema
);
173 pTab
= (StatTable
*)sqlite3_malloc64(sizeof(StatTable
));
174 if( pTab
==0 ) rc
= SQLITE_NOMEM_BKPT
;
177 assert( rc
==SQLITE_OK
|| pTab
==0 );
179 memset(pTab
, 0, sizeof(StatTable
));
184 *ppVtab
= (sqlite3_vtab
*)pTab
;
189 ** Disconnect from or destroy the DBSTAT virtual table.
191 static int statDisconnect(sqlite3_vtab
*pVtab
){
197 ** Compute the best query strategy and return the result in idxNum.
199 ** idxNum-Bit Meaning
200 ** ---------- ----------------------------------------------
201 ** 0x01 There is a schema=? term in the WHERE clause
202 ** 0x02 There is a name=? term in the WHERE clause
203 ** 0x04 There is an aggregate=? term in the WHERE clause
204 ** 0x08 Output should be ordered by name and path
206 static int statBestIndex(sqlite3_vtab
*tab
, sqlite3_index_info
*pIdxInfo
){
212 /* Look for a valid schema=? constraint. If found, change the idxNum to
213 ** 1 and request the value of that constraint be sent to xFilter. And
214 ** lower the cost estimate to encourage the constrained version to be
217 for(i
=0; i
<pIdxInfo
->nConstraint
; i
++){
218 if( pIdxInfo
->aConstraint
[i
].op
!=SQLITE_INDEX_CONSTRAINT_EQ
) continue;
219 if( pIdxInfo
->aConstraint
[i
].usable
==0 ){
220 /* Force DBSTAT table should always be the right-most table in a join */
221 return SQLITE_CONSTRAINT
;
223 switch( pIdxInfo
->aConstraint
[i
].iColumn
){
228 case 10: { /* schema */
232 case 11: { /* aggregate */
240 pIdxInfo
->aConstraintUsage
[iSchema
].argvIndex
= ++i
;
241 pIdxInfo
->aConstraintUsage
[iSchema
].omit
= 1;
242 pIdxInfo
->idxNum
|= 0x01;
245 pIdxInfo
->aConstraintUsage
[iName
].argvIndex
= ++i
;
246 pIdxInfo
->idxNum
|= 0x02;
249 pIdxInfo
->aConstraintUsage
[iAgg
].argvIndex
= ++i
;
250 pIdxInfo
->idxNum
|= 0x04;
252 pIdxInfo
->estimatedCost
= 1.0;
254 /* Records are always returned in ascending order of (name, path).
255 ** If this will satisfy the client, set the orderByConsumed flag so that
256 ** SQLite does not do an external sort.
258 if( ( pIdxInfo
->nOrderBy
==1
259 && pIdxInfo
->aOrderBy
[0].iColumn
==0
260 && pIdxInfo
->aOrderBy
[0].desc
==0
262 ( pIdxInfo
->nOrderBy
==2
263 && pIdxInfo
->aOrderBy
[0].iColumn
==0
264 && pIdxInfo
->aOrderBy
[0].desc
==0
265 && pIdxInfo
->aOrderBy
[1].iColumn
==1
266 && pIdxInfo
->aOrderBy
[1].desc
==0
269 pIdxInfo
->orderByConsumed
= 1;
270 pIdxInfo
->idxNum
|= 0x08;
277 ** Open a new DBSTAT cursor.
279 static int statOpen(sqlite3_vtab
*pVTab
, sqlite3_vtab_cursor
**ppCursor
){
280 StatTable
*pTab
= (StatTable
*)pVTab
;
283 pCsr
= (StatCursor
*)sqlite3_malloc64(sizeof(StatCursor
));
285 return SQLITE_NOMEM_BKPT
;
287 memset(pCsr
, 0, sizeof(StatCursor
));
288 pCsr
->base
.pVtab
= pVTab
;
289 pCsr
->iDb
= pTab
->iDb
;
292 *ppCursor
= (sqlite3_vtab_cursor
*)pCsr
;
296 static void statClearCells(StatPage
*p
){
299 for(i
=0; i
<p
->nCell
; i
++){
300 sqlite3_free(p
->aCell
[i
].aOvfl
);
302 sqlite3_free(p
->aCell
);
308 static void statClearPage(StatPage
*p
){
310 sqlite3PagerUnref(p
->pPg
);
311 sqlite3_free(p
->zPath
);
312 memset(p
, 0, sizeof(StatPage
));
315 static void statResetCsr(StatCursor
*pCsr
){
317 sqlite3_reset(pCsr
->pStmt
);
318 for(i
=0; i
<ArraySize(pCsr
->aPage
); i
++){
319 statClearPage(&pCsr
->aPage
[i
]);
322 sqlite3_free(pCsr
->zPath
);
327 /* Resize the space-used counters inside of the cursor */
328 static void statResetCounts(StatCursor
*pCsr
){
330 pCsr
->nMxPayload
= 0;
338 ** Close a DBSTAT cursor.
340 static int statClose(sqlite3_vtab_cursor
*pCursor
){
341 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
343 sqlite3_finalize(pCsr
->pStmt
);
349 ** For a single cell on a btree page, compute the number of bytes of
350 ** content (payload) stored on that page. That is to say, compute the
351 ** number of bytes of content not found on overflow pages.
353 static int getLocalPayload(
354 int nUsable
, /* Usable bytes per page */
355 u8 flags
, /* Page flags */
356 int nTotal
/* Total record (payload) size */
362 if( flags
==0x0D ){ /* Table leaf node */
363 nMinLocal
= (nUsable
- 12) * 32 / 255 - 23;
364 nMaxLocal
= nUsable
- 35;
365 }else{ /* Index interior and leaf nodes */
366 nMinLocal
= (nUsable
- 12) * 32 / 255 - 23;
367 nMaxLocal
= (nUsable
- 12) * 64 / 255 - 23;
370 nLocal
= nMinLocal
+ (nTotal
- nMinLocal
) % (nUsable
- 4);
371 if( nLocal
>nMaxLocal
) nLocal
= nMinLocal
;
375 /* Populate the StatPage object with information about the all
376 ** cells found on the page currently under analysis.
378 static int statDecodePage(Btree
*pBt
, StatPage
*p
){
385 u8
*aData
= sqlite3PagerGetData(p
->pPg
);
386 u8
*aHdr
= &aData
[p
->iPgno
==1 ? 100 : 0];
389 if( p
->flags
==0x0A || p
->flags
==0x0D ){
392 }else if( p
->flags
==0x05 || p
->flags
==0x02 ){
396 goto statPageIsCorrupt
;
398 if( p
->iPgno
==1 ) nHdr
+= 100;
399 p
->nCell
= get2byte(&aHdr
[3]);
401 szPage
= sqlite3BtreeGetPageSize(pBt
);
403 nUnused
= get2byte(&aHdr
[5]) - nHdr
- 2*p
->nCell
;
404 nUnused
+= (int)aHdr
[7];
405 iOff
= get2byte(&aHdr
[1]);
408 if( iOff
>=szPage
) goto statPageIsCorrupt
;
409 nUnused
+= get2byte(&aData
[iOff
+2]);
410 iNext
= get2byte(&aData
[iOff
]);
411 if( iNext
<iOff
+4 && iNext
>0 ) goto statPageIsCorrupt
;
414 p
->nUnused
= nUnused
;
415 p
->iRightChildPg
= isLeaf
? 0 : sqlite3Get4byte(&aHdr
[8]);
418 int i
; /* Used to iterate through cells */
419 int nUsable
; /* Usable bytes per page */
421 sqlite3BtreeEnter(pBt
);
422 nUsable
= szPage
- sqlite3BtreeGetReserveNoMutex(pBt
);
423 sqlite3BtreeLeave(pBt
);
424 p
->aCell
= sqlite3_malloc64((p
->nCell
+1) * sizeof(StatCell
));
425 if( p
->aCell
==0 ) return SQLITE_NOMEM_BKPT
;
426 memset(p
->aCell
, 0, (p
->nCell
+1) * sizeof(StatCell
));
428 for(i
=0; i
<p
->nCell
; i
++){
429 StatCell
*pCell
= &p
->aCell
[i
];
431 iOff
= get2byte(&aData
[nHdr
+i
*2]);
432 if( iOff
<nHdr
|| iOff
>=szPage
) goto statPageIsCorrupt
;
434 pCell
->iChildPg
= sqlite3Get4byte(&aData
[iOff
]);
437 if( p
->flags
==0x05 ){
438 /* A table interior node. nPayload==0. */
440 u32 nPayload
; /* Bytes of payload total (local+overflow) */
441 int nLocal
; /* Bytes of payload stored locally */
442 iOff
+= getVarint32(&aData
[iOff
], nPayload
);
443 if( p
->flags
==0x0D ){
445 iOff
+= sqlite3GetVarint(&aData
[iOff
], &dummy
);
447 if( nPayload
>(u32
)p
->nMxPayload
) p
->nMxPayload
= nPayload
;
448 nLocal
= getLocalPayload(nUsable
, p
->flags
, nPayload
);
449 if( nLocal
<0 ) goto statPageIsCorrupt
;
450 pCell
->nLocal
= nLocal
;
451 assert( nPayload
>=(u32
)nLocal
);
452 assert( nLocal
<=(nUsable
-35) );
453 if( nPayload
>(u32
)nLocal
){
455 int nOvfl
= ((nPayload
- nLocal
) + nUsable
-4 - 1) / (nUsable
- 4);
456 if( iOff
+nLocal
>nUsable
|| nPayload
>0x7fffffff ){
457 goto statPageIsCorrupt
;
459 pCell
->nLastOvfl
= (nPayload
-nLocal
) - (nOvfl
-1) * (nUsable
-4);
460 pCell
->nOvfl
= nOvfl
;
461 pCell
->aOvfl
= sqlite3_malloc64(sizeof(u32
)*nOvfl
);
462 if( pCell
->aOvfl
==0 ) return SQLITE_NOMEM_BKPT
;
463 pCell
->aOvfl
[0] = sqlite3Get4byte(&aData
[iOff
+nLocal
]);
464 for(j
=1; j
<nOvfl
; j
++){
466 u32 iPrev
= pCell
->aOvfl
[j
-1];
468 rc
= sqlite3PagerGet(sqlite3BtreePager(pBt
), iPrev
, &pPg
, 0);
473 pCell
->aOvfl
[j
] = sqlite3Get4byte(sqlite3PagerGetData(pPg
));
474 sqlite3PagerUnref(pPg
);
490 ** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on
491 ** the current value of pCsr->iPageno.
493 static void statSizeAndOffset(StatCursor
*pCsr
){
494 StatTable
*pTab
= (StatTable
*)((sqlite3_vtab_cursor
*)pCsr
)->pVtab
;
495 Btree
*pBt
= pTab
->db
->aDb
[pTab
->iDb
].pBt
;
496 Pager
*pPager
= sqlite3BtreePager(pBt
);
500 /* If connected to a ZIPVFS backend, find the page size and
501 ** offset from ZIPVFS.
503 fd
= sqlite3PagerFile(pPager
);
504 x
[0] = pCsr
->iPageno
;
505 if( sqlite3OsFileControl(fd
, 230440, &x
)==SQLITE_OK
){
506 pCsr
->iOffset
= x
[0];
507 pCsr
->szPage
+= x
[1];
509 /* Not ZIPVFS: The default page size and offset */
510 pCsr
->szPage
+= sqlite3BtreeGetPageSize(pBt
);
511 pCsr
->iOffset
= (i64
)pCsr
->szPage
* (pCsr
->iPageno
- 1);
516 ** Move a DBSTAT cursor to the next entry. Normally, the next
517 ** entry will be the next page, but in aggregated mode (pCsr->isAgg!=0),
518 ** the next entry is the next btree.
520 static int statNext(sqlite3_vtab_cursor
*pCursor
){
524 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
525 StatTable
*pTab
= (StatTable
*)pCursor
->pVtab
;
526 Btree
*pBt
= pTab
->db
->aDb
[pCsr
->iDb
].pBt
;
527 Pager
*pPager
= sqlite3BtreePager(pBt
);
529 sqlite3_free(pCsr
->zPath
);
533 if( pCsr
->aPage
[0].pPg
==0 ){
534 /* Start measuring space on the next btree */
535 statResetCounts(pCsr
);
536 rc
= sqlite3_step(pCsr
->pStmt
);
537 if( rc
==SQLITE_ROW
){
539 u32 iRoot
= (u32
)sqlite3_column_int64(pCsr
->pStmt
, 1);
540 sqlite3PagerPagecount(pPager
, &nPage
);
543 return sqlite3_reset(pCsr
->pStmt
);
545 rc
= sqlite3PagerGet(pPager
, iRoot
, &pCsr
->aPage
[0].pPg
, 0);
546 pCsr
->aPage
[0].iPgno
= iRoot
;
547 pCsr
->aPage
[0].iCell
= 0;
549 pCsr
->aPage
[0].zPath
= z
= sqlite3_mprintf("/");
550 if( z
==0 ) rc
= SQLITE_NOMEM_BKPT
;
556 return sqlite3_reset(pCsr
->pStmt
);
559 /* Continue analyzing the btree previously started */
560 StatPage
*p
= &pCsr
->aPage
[pCsr
->iPage
];
561 if( !pCsr
->isAgg
) statResetCounts(pCsr
);
562 while( p
->iCell
<p
->nCell
){
563 StatCell
*pCell
= &p
->aCell
[p
->iCell
];
564 while( pCell
->iOvfl
<pCell
->nOvfl
){
566 sqlite3BtreeEnter(pBt
);
567 nUsable
= sqlite3BtreeGetPageSize(pBt
) -
568 sqlite3BtreeGetReserveNoMutex(pBt
);
569 sqlite3BtreeLeave(pBt
);
571 statSizeAndOffset(pCsr
);
572 if( pCell
->iOvfl
<pCell
->nOvfl
-1 ){
573 pCsr
->nPayload
+= nUsable
- 4;
575 pCsr
->nPayload
+= pCell
->nLastOvfl
;
576 pCsr
->nUnused
+= nUsable
- 4 - pCell
->nLastOvfl
;
578 iOvfl
= pCell
->iOvfl
;
581 pCsr
->zName
= (char *)sqlite3_column_text(pCsr
->pStmt
, 0);
582 pCsr
->iPageno
= pCell
->aOvfl
[iOvfl
];
583 pCsr
->zPagetype
= "overflow";
584 pCsr
->zPath
= z
= sqlite3_mprintf(
585 "%s%.3x+%.6x", p
->zPath
, p
->iCell
, iOvfl
587 return z
==0 ? SQLITE_NOMEM_BKPT
: SQLITE_OK
;
590 if( p
->iRightChildPg
) break;
594 if( !p
->iRightChildPg
|| p
->iCell
>p
->nCell
){
598 }else if( pCsr
->isAgg
){
599 /* label-statNext-done: When computing aggregate space usage over
600 ** an entire btree, this is the exit point from this function */
603 goto statNextRestart
; /* Tail recursion */
606 if( pCsr
->iPage
>=ArraySize(pCsr
->aPage
) ){
608 return SQLITE_CORRUPT_BKPT
;
610 assert( p
==&pCsr
->aPage
[pCsr
->iPage
-1] );
612 if( p
->iCell
==p
->nCell
){
613 p
[1].iPgno
= p
->iRightChildPg
;
615 p
[1].iPgno
= p
->aCell
[p
->iCell
].iChildPg
;
617 rc
= sqlite3PagerGet(pPager
, p
[1].iPgno
, &p
[1].pPg
, 0);
621 p
[1].zPath
= z
= sqlite3_mprintf("%s%.3x/", p
->zPath
, p
->iCell
);
622 if( z
==0 ) rc
= SQLITE_NOMEM_BKPT
;
628 /* Populate the StatCursor fields with the values to be returned
629 ** by the xColumn() and xRowid() methods.
633 StatPage
*p
= &pCsr
->aPage
[pCsr
->iPage
];
634 pCsr
->zName
= (char *)sqlite3_column_text(pCsr
->pStmt
, 0);
635 pCsr
->iPageno
= p
->iPgno
;
637 rc
= statDecodePage(pBt
, p
);
639 statSizeAndOffset(pCsr
);
642 case 0x05: /* table internal */
643 case 0x02: /* index internal */
644 pCsr
->zPagetype
= "internal";
646 case 0x0D: /* table leaf */
647 case 0x0A: /* index leaf */
648 pCsr
->zPagetype
= "leaf";
651 pCsr
->zPagetype
= "corrupted";
654 pCsr
->nCell
+= p
->nCell
;
655 pCsr
->nUnused
+= p
->nUnused
;
656 if( p
->nMxPayload
>pCsr
->nMxPayload
) pCsr
->nMxPayload
= p
->nMxPayload
;
658 pCsr
->zPath
= z
= sqlite3_mprintf("%s", p
->zPath
);
659 if( z
==0 ) rc
= SQLITE_NOMEM_BKPT
;
662 for(i
=0; i
<p
->nCell
; i
++){
663 nPayload
+= p
->aCell
[i
].nLocal
;
665 pCsr
->nPayload
+= nPayload
;
667 /* If computing aggregate space usage by btree, continue with the
668 ** next page. The loop will exit via the return at label-statNext-done
670 if( pCsr
->isAgg
) goto statNextRestart
;
677 static int statEof(sqlite3_vtab_cursor
*pCursor
){
678 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
682 /* Initialize a cursor according to the query plan idxNum using the
683 ** arguments in argv[0]. See statBestIndex() for a description of the
684 ** meaning of the bits in idxNum.
686 static int statFilter(
687 sqlite3_vtab_cursor
*pCursor
,
688 int idxNum
, const char *idxStr
,
689 int argc
, sqlite3_value
**argv
691 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
692 StatTable
*pTab
= (StatTable
*)(pCursor
->pVtab
);
693 sqlite3_str
*pSql
; /* Query of btrees to analyze */
694 char *zSql
; /* String value of pSql */
695 int iArg
= 0; /* Count of argv[] parameters used so far */
696 int rc
= SQLITE_OK
; /* Result of this operation */
697 const char *zName
= 0; /* Only provide analysis of this table */
700 sqlite3_finalize(pCsr
->pStmt
);
703 /* schema=? constraint is present. Get its value */
704 const char *zDbase
= (const char*)sqlite3_value_text(argv
[iArg
++]);
705 pCsr
->iDb
= sqlite3FindDbName(pTab
->db
, zDbase
);
712 pCsr
->iDb
= pTab
->iDb
;
715 /* name=? constraint is present */
716 zName
= (const char*)sqlite3_value_text(argv
[iArg
++]);
719 /* aggregate=? constraint is present */
720 pCsr
->isAgg
= sqlite3_value_double(argv
[iArg
++])!=0.0;
724 pSql
= sqlite3_str_new(pTab
->db
);
725 sqlite3_str_appendf(pSql
,
727 "SELECT 'sqlite_master' AS name,1 AS rootpage,'table' AS type"
729 "SELECT name,rootpage,type"
730 " FROM \"%w\".sqlite_master WHERE rootpage!=0)",
731 pTab
->db
->aDb
[pCsr
->iDb
].zDbSName
);
733 sqlite3_str_appendf(pSql
, "WHERE name=%Q", zName
);
736 sqlite3_str_appendf(pSql
, " ORDER BY name");
738 zSql
= sqlite3_str_finish(pSql
);
740 return SQLITE_NOMEM_BKPT
;
742 rc
= sqlite3_prepare_v2(pTab
->db
, zSql
, -1, &pCsr
->pStmt
, 0);
747 rc
= statNext(pCursor
);
752 static int statColumn(
753 sqlite3_vtab_cursor
*pCursor
,
754 sqlite3_context
*ctx
,
757 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
760 sqlite3_result_text(ctx
, pCsr
->zName
, -1, SQLITE_TRANSIENT
);
764 sqlite3_result_text(ctx
, pCsr
->zPath
, -1, SQLITE_TRANSIENT
);
769 sqlite3_result_int64(ctx
, pCsr
->nPage
);
771 sqlite3_result_int64(ctx
, pCsr
->iPageno
);
774 case 3: /* pagetype */
776 sqlite3_result_text(ctx
, pCsr
->zPagetype
, -1, SQLITE_STATIC
);
780 sqlite3_result_int(ctx
, pCsr
->nCell
);
782 case 5: /* payload */
783 sqlite3_result_int(ctx
, pCsr
->nPayload
);
786 sqlite3_result_int(ctx
, pCsr
->nUnused
);
788 case 7: /* mx_payload */
789 sqlite3_result_int(ctx
, pCsr
->nMxPayload
);
791 case 8: /* pgoffset */
793 sqlite3_result_int64(ctx
, pCsr
->iOffset
);
797 sqlite3_result_int(ctx
, pCsr
->szPage
);
799 case 10: { /* schema */
800 sqlite3
*db
= sqlite3_context_db_handle(ctx
);
802 sqlite3_result_text(ctx
, db
->aDb
[iDb
].zDbSName
, -1, SQLITE_STATIC
);
805 default: { /* aggregate */
806 sqlite3_result_int(ctx
, pCsr
->isAgg
);
813 static int statRowid(sqlite3_vtab_cursor
*pCursor
, sqlite_int64
*pRowid
){
814 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
815 *pRowid
= pCsr
->iPageno
;
820 ** Invoke this routine to register the "dbstat" virtual table module
822 int sqlite3DbstatRegister(sqlite3
*db
){
823 static sqlite3_module dbstat_module
= {
825 statConnect
, /* xCreate */
826 statConnect
, /* xConnect */
827 statBestIndex
, /* xBestIndex */
828 statDisconnect
, /* xDisconnect */
829 statDisconnect
, /* xDestroy */
830 statOpen
, /* xOpen - open a cursor */
831 statClose
, /* xClose - close a cursor */
832 statFilter
, /* xFilter - configure scan constraints */
833 statNext
, /* xNext - advance a cursor */
834 statEof
, /* xEof - check for end of scan */
835 statColumn
, /* xColumn - read data */
836 statRowid
, /* xRowid - read data */
849 return sqlite3_create_module(db
, "dbstat", &dbstat_module
, 0);
851 #elif defined(SQLITE_ENABLE_DBSTAT_VTAB)
852 int sqlite3DbstatRegister(sqlite3
*db
){ return SQLITE_OK
; }
853 #endif /* SQLITE_ENABLE_DBSTAT_VTAB */