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.
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
61 " name TEXT, /* Name of table or index */" \
62 " path TEXT, /* Path to page from root */" \
63 " pageno INTEGER, /* Page number */" \
64 " pagetype TEXT, /* 'internal', 'leaf' or 'overflow' */" \
65 " ncell INTEGER, /* Cells on page (0 for overflow) */" \
66 " payload INTEGER, /* Bytes of payload on this page */" \
67 " unused INTEGER, /* Bytes of unused space on this page */" \
68 " mx_payload INTEGER, /* Largest payload size of all cells */" \
69 " pgoffset INTEGER, /* Offset of page in file */" \
70 " pgsize INTEGER, /* Size of the page */" \
71 " schema TEXT HIDDEN /* Database schema being analyzed */" \
75 typedef struct StatTable StatTable
;
76 typedef struct StatCursor StatCursor
;
77 typedef struct StatPage StatPage
;
78 typedef struct StatCell StatCell
;
81 int nLocal
; /* Bytes of local payload */
82 u32 iChildPg
; /* Child node (or 0 if this is a leaf) */
83 int nOvfl
; /* Entries in aOvfl[] */
84 u32
*aOvfl
; /* Array of overflow page numbers */
85 int nLastOvfl
; /* Bytes of payload on final overflow page */
86 int iOvfl
; /* Iterates through aOvfl[] */
94 char *zPath
; /* Path to this page */
96 /* Variables populated by statDecodePage(): */
97 u8 flags
; /* Copy of flags byte */
98 int nCell
; /* Number of cells on page */
99 int nUnused
; /* Number of unused bytes on page */
100 StatCell
*aCell
; /* Array of parsed cells */
101 u32 iRightChildPg
; /* Right-child page number (or 0) */
102 int nMxPayload
; /* Largest payload of any cell on this page */
106 sqlite3_vtab_cursor base
;
107 sqlite3_stmt
*pStmt
; /* Iterates through set of root pages */
108 int isEof
; /* After pStmt has returned SQLITE_DONE */
109 int iDb
; /* Schema used for this query */
112 int iPage
; /* Current entry in aPage[] */
114 /* Values to return. */
115 char *zName
; /* Value of 'name' column */
116 char *zPath
; /* Value of 'path' column */
117 u32 iPageno
; /* Value of 'pageno' column */
118 char *zPagetype
; /* Value of 'pagetype' column */
119 int nCell
; /* Value of 'ncell' column */
120 int nPayload
; /* Value of 'payload' column */
121 int nUnused
; /* Value of 'unused' column */
122 int nMxPayload
; /* Value of 'mx_payload' column */
123 i64 iOffset
; /* Value of 'pgOffset' column */
124 int szPage
; /* Value of 'pgSize' column */
130 int iDb
; /* Index of database to analyze */
134 # define get2byte(x) ((x)[0]<<8 | (x)[1])
138 ** Connect to or create a statvfs virtual table.
140 static int statConnect(
143 int argc
, const char *const*argv
,
144 sqlite3_vtab
**ppVtab
,
153 sqlite3TokenInit(&nm
, (char*)argv
[3]);
154 iDb
= sqlite3FindDb(db
, &nm
);
156 *pzErr
= sqlite3_mprintf("no such database: %s", argv
[3]);
162 rc
= sqlite3_declare_vtab(db
, VTAB_SCHEMA
);
164 pTab
= (StatTable
*)sqlite3_malloc64(sizeof(StatTable
));
165 if( pTab
==0 ) rc
= SQLITE_NOMEM_BKPT
;
168 assert( rc
==SQLITE_OK
|| pTab
==0 );
170 memset(pTab
, 0, sizeof(StatTable
));
175 *ppVtab
= (sqlite3_vtab
*)pTab
;
180 ** Disconnect from or destroy a statvfs virtual table.
182 static int statDisconnect(sqlite3_vtab
*pVtab
){
188 ** There is no "best-index". This virtual table always does a linear
189 ** scan. However, a schema=? constraint should cause this table to
190 ** operate on a different database schema, so check for it.
192 ** idxNum is normally 0, but will be 1 if a schema=? constraint exists.
194 static int statBestIndex(sqlite3_vtab
*tab
, sqlite3_index_info
*pIdxInfo
){
197 /* Look for a valid schema=? constraint. If found, change the idxNum to
198 ** 1 and request the value of that constraint be sent to xFilter. And
199 ** lower the cost estimate to encourage the constrained version to be
202 for(i
=0; i
<pIdxInfo
->nConstraint
; i
++){
203 if( pIdxInfo
->aConstraint
[i
].iColumn
!=10 ) continue;
204 if( pIdxInfo
->aConstraint
[i
].usable
==0 ) return SQLITE_CONSTRAINT
;
205 if( pIdxInfo
->aConstraint
[i
].op
!=SQLITE_INDEX_CONSTRAINT_EQ
) continue;
206 pIdxInfo
->idxNum
= 1;
207 pIdxInfo
->estimatedCost
= 1.0;
208 pIdxInfo
->aConstraintUsage
[i
].argvIndex
= 1;
209 pIdxInfo
->aConstraintUsage
[i
].omit
= 1;
214 /* Records are always returned in ascending order of (name, path).
215 ** If this will satisfy the client, set the orderByConsumed flag so that
216 ** SQLite does not do an external sort.
218 if( ( pIdxInfo
->nOrderBy
==1
219 && pIdxInfo
->aOrderBy
[0].iColumn
==0
220 && pIdxInfo
->aOrderBy
[0].desc
==0
222 ( pIdxInfo
->nOrderBy
==2
223 && pIdxInfo
->aOrderBy
[0].iColumn
==0
224 && pIdxInfo
->aOrderBy
[0].desc
==0
225 && pIdxInfo
->aOrderBy
[1].iColumn
==1
226 && pIdxInfo
->aOrderBy
[1].desc
==0
229 pIdxInfo
->orderByConsumed
= 1;
236 ** Open a new statvfs cursor.
238 static int statOpen(sqlite3_vtab
*pVTab
, sqlite3_vtab_cursor
**ppCursor
){
239 StatTable
*pTab
= (StatTable
*)pVTab
;
242 pCsr
= (StatCursor
*)sqlite3_malloc64(sizeof(StatCursor
));
244 return SQLITE_NOMEM_BKPT
;
246 memset(pCsr
, 0, sizeof(StatCursor
));
247 pCsr
->base
.pVtab
= pVTab
;
248 pCsr
->iDb
= pTab
->iDb
;
251 *ppCursor
= (sqlite3_vtab_cursor
*)pCsr
;
255 static void statClearCells(StatPage
*p
){
258 for(i
=0; i
<p
->nCell
; i
++){
259 sqlite3_free(p
->aCell
[i
].aOvfl
);
261 sqlite3_free(p
->aCell
);
267 static void statClearPage(StatPage
*p
){
269 sqlite3PagerUnref(p
->pPg
);
270 sqlite3_free(p
->zPath
);
271 memset(p
, 0, sizeof(StatPage
));
274 static void statResetCsr(StatCursor
*pCsr
){
276 sqlite3_reset(pCsr
->pStmt
);
277 for(i
=0; i
<ArraySize(pCsr
->aPage
); i
++){
278 statClearPage(&pCsr
->aPage
[i
]);
281 sqlite3_free(pCsr
->zPath
);
287 ** Close a statvfs cursor.
289 static int statClose(sqlite3_vtab_cursor
*pCursor
){
290 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
292 sqlite3_finalize(pCsr
->pStmt
);
297 static void getLocalPayload(
298 int nUsable
, /* Usable bytes per page */
299 u8 flags
, /* Page flags */
300 int nTotal
, /* Total record (payload) size */
301 int *pnLocal
/* OUT: Bytes stored locally */
307 if( flags
==0x0D ){ /* Table leaf node */
308 nMinLocal
= (nUsable
- 12) * 32 / 255 - 23;
309 nMaxLocal
= nUsable
- 35;
310 }else{ /* Index interior and leaf nodes */
311 nMinLocal
= (nUsable
- 12) * 32 / 255 - 23;
312 nMaxLocal
= (nUsable
- 12) * 64 / 255 - 23;
315 nLocal
= nMinLocal
+ (nTotal
- nMinLocal
) % (nUsable
- 4);
316 if( nLocal
>nMaxLocal
) nLocal
= nMinLocal
;
320 static int statDecodePage(Btree
*pBt
, StatPage
*p
){
327 u8
*aData
= sqlite3PagerGetData(p
->pPg
);
328 u8
*aHdr
= &aData
[p
->iPgno
==1 ? 100 : 0];
331 if( p
->flags
==0x0A || p
->flags
==0x0D ){
334 }else if( p
->flags
==0x05 || p
->flags
==0x02 ){
338 goto statPageIsCorrupt
;
340 if( p
->iPgno
==1 ) nHdr
+= 100;
341 p
->nCell
= get2byte(&aHdr
[3]);
343 szPage
= sqlite3BtreeGetPageSize(pBt
);
345 nUnused
= get2byte(&aHdr
[5]) - nHdr
- 2*p
->nCell
;
346 nUnused
+= (int)aHdr
[7];
347 iOff
= get2byte(&aHdr
[1]);
350 if( iOff
>=szPage
) goto statPageIsCorrupt
;
351 nUnused
+= get2byte(&aData
[iOff
+2]);
352 iNext
= get2byte(&aData
[iOff
]);
353 if( iNext
<iOff
+4 && iNext
>0 ) goto statPageIsCorrupt
;
356 p
->nUnused
= nUnused
;
357 p
->iRightChildPg
= isLeaf
? 0 : sqlite3Get4byte(&aHdr
[8]);
360 int i
; /* Used to iterate through cells */
361 int nUsable
; /* Usable bytes per page */
363 sqlite3BtreeEnter(pBt
);
364 nUsable
= szPage
- sqlite3BtreeGetReserveNoMutex(pBt
);
365 sqlite3BtreeLeave(pBt
);
366 p
->aCell
= sqlite3_malloc64((p
->nCell
+1) * sizeof(StatCell
));
367 if( p
->aCell
==0 ) return SQLITE_NOMEM_BKPT
;
368 memset(p
->aCell
, 0, (p
->nCell
+1) * sizeof(StatCell
));
370 for(i
=0; i
<p
->nCell
; i
++){
371 StatCell
*pCell
= &p
->aCell
[i
];
373 iOff
= get2byte(&aData
[nHdr
+i
*2]);
374 if( iOff
<nHdr
|| iOff
>=szPage
) goto statPageIsCorrupt
;
376 pCell
->iChildPg
= sqlite3Get4byte(&aData
[iOff
]);
379 if( p
->flags
==0x05 ){
380 /* A table interior node. nPayload==0. */
382 u32 nPayload
; /* Bytes of payload total (local+overflow) */
383 int nLocal
; /* Bytes of payload stored locally */
384 iOff
+= getVarint32(&aData
[iOff
], nPayload
);
385 if( p
->flags
==0x0D ){
387 iOff
+= sqlite3GetVarint(&aData
[iOff
], &dummy
);
389 if( nPayload
>(u32
)p
->nMxPayload
) p
->nMxPayload
= nPayload
;
390 getLocalPayload(nUsable
, p
->flags
, nPayload
, &nLocal
);
391 if( nLocal
<0 ) goto statPageIsCorrupt
;
392 pCell
->nLocal
= nLocal
;
393 assert( nPayload
>=(u32
)nLocal
);
394 assert( nLocal
<=(nUsable
-35) );
395 if( nPayload
>(u32
)nLocal
){
397 int nOvfl
= ((nPayload
- nLocal
) + nUsable
-4 - 1) / (nUsable
- 4);
398 if( iOff
+nLocal
>nUsable
) goto statPageIsCorrupt
;
399 pCell
->nLastOvfl
= (nPayload
-nLocal
) - (nOvfl
-1) * (nUsable
-4);
400 pCell
->nOvfl
= nOvfl
;
401 pCell
->aOvfl
= sqlite3_malloc64(sizeof(u32
)*nOvfl
);
402 if( pCell
->aOvfl
==0 ) return SQLITE_NOMEM_BKPT
;
403 pCell
->aOvfl
[0] = sqlite3Get4byte(&aData
[iOff
+nLocal
]);
404 for(j
=1; j
<nOvfl
; j
++){
406 u32 iPrev
= pCell
->aOvfl
[j
-1];
408 rc
= sqlite3PagerGet(sqlite3BtreePager(pBt
), iPrev
, &pPg
, 0);
413 pCell
->aOvfl
[j
] = sqlite3Get4byte(sqlite3PagerGetData(pPg
));
414 sqlite3PagerUnref(pPg
);
430 ** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on
431 ** the current value of pCsr->iPageno.
433 static void statSizeAndOffset(StatCursor
*pCsr
){
434 StatTable
*pTab
= (StatTable
*)((sqlite3_vtab_cursor
*)pCsr
)->pVtab
;
435 Btree
*pBt
= pTab
->db
->aDb
[pTab
->iDb
].pBt
;
436 Pager
*pPager
= sqlite3BtreePager(pBt
);
440 /* The default page size and offset */
441 pCsr
->szPage
= sqlite3BtreeGetPageSize(pBt
);
442 pCsr
->iOffset
= (i64
)pCsr
->szPage
* (pCsr
->iPageno
- 1);
444 /* If connected to a ZIPVFS backend, override the page size and
445 ** offset with actual values obtained from ZIPVFS.
447 fd
= sqlite3PagerFile(pPager
);
448 x
[0] = pCsr
->iPageno
;
449 if( sqlite3OsFileControl(fd
, 230440, &x
)==SQLITE_OK
){
450 pCsr
->iOffset
= x
[0];
451 pCsr
->szPage
= (int)x
[1];
456 ** Move a statvfs cursor to the next entry in the file.
458 static int statNext(sqlite3_vtab_cursor
*pCursor
){
462 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
463 StatTable
*pTab
= (StatTable
*)pCursor
->pVtab
;
464 Btree
*pBt
= pTab
->db
->aDb
[pCsr
->iDb
].pBt
;
465 Pager
*pPager
= sqlite3BtreePager(pBt
);
467 sqlite3_free(pCsr
->zPath
);
471 if( pCsr
->aPage
[0].pPg
==0 ){
472 rc
= sqlite3_step(pCsr
->pStmt
);
473 if( rc
==SQLITE_ROW
){
475 u32 iRoot
= (u32
)sqlite3_column_int64(pCsr
->pStmt
, 1);
476 sqlite3PagerPagecount(pPager
, &nPage
);
479 return sqlite3_reset(pCsr
->pStmt
);
481 rc
= sqlite3PagerGet(pPager
, iRoot
, &pCsr
->aPage
[0].pPg
, 0);
482 pCsr
->aPage
[0].iPgno
= iRoot
;
483 pCsr
->aPage
[0].iCell
= 0;
484 pCsr
->aPage
[0].zPath
= z
= sqlite3_mprintf("/");
486 if( z
==0 ) rc
= SQLITE_NOMEM_BKPT
;
489 return sqlite3_reset(pCsr
->pStmt
);
493 /* Page p itself has already been visited. */
494 StatPage
*p
= &pCsr
->aPage
[pCsr
->iPage
];
496 while( p
->iCell
<p
->nCell
){
497 StatCell
*pCell
= &p
->aCell
[p
->iCell
];
498 if( pCell
->iOvfl
<pCell
->nOvfl
){
500 sqlite3BtreeEnter(pBt
);
501 nUsable
= sqlite3BtreeGetPageSize(pBt
) -
502 sqlite3BtreeGetReserveNoMutex(pBt
);
503 sqlite3BtreeLeave(pBt
);
504 pCsr
->zName
= (char *)sqlite3_column_text(pCsr
->pStmt
, 0);
505 pCsr
->iPageno
= pCell
->aOvfl
[pCell
->iOvfl
];
506 pCsr
->zPagetype
= "overflow";
508 pCsr
->nMxPayload
= 0;
509 pCsr
->zPath
= z
= sqlite3_mprintf(
510 "%s%.3x+%.6x", p
->zPath
, p
->iCell
, pCell
->iOvfl
512 if( pCell
->iOvfl
<pCell
->nOvfl
-1 ){
514 pCsr
->nPayload
= nUsable
- 4;
516 pCsr
->nPayload
= pCell
->nLastOvfl
;
517 pCsr
->nUnused
= nUsable
- 4 - pCsr
->nPayload
;
520 statSizeAndOffset(pCsr
);
521 return z
==0 ? SQLITE_NOMEM_BKPT
: SQLITE_OK
;
523 if( p
->iRightChildPg
) break;
527 if( !p
->iRightChildPg
|| p
->iCell
>p
->nCell
){
529 if( pCsr
->iPage
==0 ) return statNext(pCursor
);
531 goto statNextRestart
; /* Tail recursion */
534 if( pCsr
->iPage
>=ArraySize(pCsr
->aPage
) ){
536 return SQLITE_CORRUPT_BKPT
;
538 assert( p
==&pCsr
->aPage
[pCsr
->iPage
-1] );
540 if( p
->iCell
==p
->nCell
){
541 p
[1].iPgno
= p
->iRightChildPg
;
543 p
[1].iPgno
= p
->aCell
[p
->iCell
].iChildPg
;
545 rc
= sqlite3PagerGet(pPager
, p
[1].iPgno
, &p
[1].pPg
, 0);
547 p
[1].zPath
= z
= sqlite3_mprintf("%s%.3x/", p
->zPath
, p
->iCell
);
549 if( z
==0 ) rc
= SQLITE_NOMEM_BKPT
;
553 /* Populate the StatCursor fields with the values to be returned
554 ** by the xColumn() and xRowid() methods.
558 StatPage
*p
= &pCsr
->aPage
[pCsr
->iPage
];
559 pCsr
->zName
= (char *)sqlite3_column_text(pCsr
->pStmt
, 0);
560 pCsr
->iPageno
= p
->iPgno
;
562 rc
= statDecodePage(pBt
, p
);
564 statSizeAndOffset(pCsr
);
567 case 0x05: /* table internal */
568 case 0x02: /* index internal */
569 pCsr
->zPagetype
= "internal";
571 case 0x0D: /* table leaf */
572 case 0x0A: /* index leaf */
573 pCsr
->zPagetype
= "leaf";
576 pCsr
->zPagetype
= "corrupted";
579 pCsr
->nCell
= p
->nCell
;
580 pCsr
->nUnused
= p
->nUnused
;
581 pCsr
->nMxPayload
= p
->nMxPayload
;
582 pCsr
->zPath
= z
= sqlite3_mprintf("%s", p
->zPath
);
583 if( z
==0 ) rc
= SQLITE_NOMEM_BKPT
;
585 for(i
=0; i
<p
->nCell
; i
++){
586 nPayload
+= p
->aCell
[i
].nLocal
;
588 pCsr
->nPayload
= nPayload
;
595 static int statEof(sqlite3_vtab_cursor
*pCursor
){
596 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
600 static int statFilter(
601 sqlite3_vtab_cursor
*pCursor
,
602 int idxNum
, const char *idxStr
,
603 int argc
, sqlite3_value
**argv
605 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
606 StatTable
*pTab
= (StatTable
*)(pCursor
->pVtab
);
611 const char *zDbase
= (const char*)sqlite3_value_text(argv
[0]);
612 pCsr
->iDb
= sqlite3FindDbName(pTab
->db
, zDbase
);
614 sqlite3_free(pCursor
->pVtab
->zErrMsg
);
615 pCursor
->pVtab
->zErrMsg
= sqlite3_mprintf("no such schema: %s", zDbase
);
616 return pCursor
->pVtab
->zErrMsg
? SQLITE_ERROR
: SQLITE_NOMEM_BKPT
;
619 pCsr
->iDb
= pTab
->iDb
;
622 sqlite3_finalize(pCsr
->pStmt
);
624 zSql
= sqlite3_mprintf(
625 "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
627 "SELECT name, rootpage, type"
628 " FROM \"%w\".sqlite_master WHERE rootpage!=0"
629 " ORDER BY name", pTab
->db
->aDb
[pCsr
->iDb
].zDbSName
);
631 return SQLITE_NOMEM_BKPT
;
633 rc
= sqlite3_prepare_v2(pTab
->db
, zSql
, -1, &pCsr
->pStmt
, 0);
638 rc
= statNext(pCursor
);
643 static int statColumn(
644 sqlite3_vtab_cursor
*pCursor
,
645 sqlite3_context
*ctx
,
648 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
651 sqlite3_result_text(ctx
, pCsr
->zName
, -1, SQLITE_TRANSIENT
);
654 sqlite3_result_text(ctx
, pCsr
->zPath
, -1, SQLITE_TRANSIENT
);
657 sqlite3_result_int64(ctx
, pCsr
->iPageno
);
659 case 3: /* pagetype */
660 sqlite3_result_text(ctx
, pCsr
->zPagetype
, -1, SQLITE_STATIC
);
663 sqlite3_result_int(ctx
, pCsr
->nCell
);
665 case 5: /* payload */
666 sqlite3_result_int(ctx
, pCsr
->nPayload
);
669 sqlite3_result_int(ctx
, pCsr
->nUnused
);
671 case 7: /* mx_payload */
672 sqlite3_result_int(ctx
, pCsr
->nMxPayload
);
674 case 8: /* pgoffset */
675 sqlite3_result_int64(ctx
, pCsr
->iOffset
);
678 sqlite3_result_int(ctx
, pCsr
->szPage
);
680 default: { /* schema */
681 sqlite3
*db
= sqlite3_context_db_handle(ctx
);
683 sqlite3_result_text(ctx
, db
->aDb
[iDb
].zDbSName
, -1, SQLITE_STATIC
);
690 static int statRowid(sqlite3_vtab_cursor
*pCursor
, sqlite_int64
*pRowid
){
691 StatCursor
*pCsr
= (StatCursor
*)pCursor
;
692 *pRowid
= pCsr
->iPageno
;
697 ** Invoke this routine to register the "dbstat" virtual table module
699 int sqlite3DbstatRegister(sqlite3
*db
){
700 static sqlite3_module dbstat_module
= {
702 statConnect
, /* xCreate */
703 statConnect
, /* xConnect */
704 statBestIndex
, /* xBestIndex */
705 statDisconnect
, /* xDisconnect */
706 statDisconnect
, /* xDestroy */
707 statOpen
, /* xOpen - open a cursor */
708 statClose
, /* xClose - close a cursor */
709 statFilter
, /* xFilter - configure scan constraints */
710 statNext
, /* xNext - advance a cursor */
711 statEof
, /* xEof - check for end of scan */
712 statColumn
, /* xColumn - read data */
713 statRowid
, /* xRowid - read data */
726 return sqlite3_create_module(db
, "dbstat", &dbstat_module
, 0);
728 #elif defined(SQLITE_ENABLE_DBSTAT_VTAB)
729 int sqlite3DbstatRegister(sqlite3
*db
){ return SQLITE_OK
; }
730 #endif /* SQLITE_ENABLE_DBSTAT_VTAB */