xref: /sqlite-3.40.0/src/dbstat.c (revision ad84bd84)
1 /*
2 ** 2010 July 12
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
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.
10 **
11 ******************************************************************************
12 **
13 ** This file contains an implementation of the "dbstat" virtual table.
14 **
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.
19 **
20 ** Additional information is available on the "dbstat.html" page of the
21 ** official SQLite documentation.
22 */
23 
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)
27 
28 /*
29 ** Page paths:
30 **
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 '/'.
34 **
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.
42 **
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
47 **   by the paths:
48 **
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
52 **
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:
56 **
57 **      '/1c2/000/'               // Left-most child of 451st child of root
58 */
59 #define VTAB_SCHEMA                                                          \
60   "CREATE TABLE xx( "                                                        \
61   "  name       TEXT,"          /*  0 Name of table or index */              \
62   "  path       TEXT,"          /*  1 Path to page from root */              \
63   "  pageno     INTEGER,"       /*  2 Page number */                         \
64   "  pagetype   TEXT,"          /*  3 'internal', 'leaf' or 'overflow' */    \
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 */              \
70   "  pgsize     INTEGER,"       /*  9 Size of the page */                    \
71   "  schema     TEXT HIDDEN,"   /* 10 Database schema being analyzed */      \
72   "  aggregate  BOOLEAN HIDDEN" /* 11 aggregate info for each table */       \
73   ");"
74 
75 /* Forward reference to data structured used in this module */
76 typedef struct StatTable StatTable;
77 typedef struct StatCursor StatCursor;
78 typedef struct StatPage StatPage;
79 typedef struct StatCell StatCell;
80 
81 /* Size information for a single cell within a btree page */
82 struct StatCell {
83   int nLocal;                     /* Bytes of local payload */
84   u32 iChildPg;                   /* Child node (or 0 if this is a leaf) */
85   int nOvfl;                      /* Entries in aOvfl[] */
86   u32 *aOvfl;                     /* Array of overflow page numbers */
87   int nLastOvfl;                  /* Bytes of payload on final overflow page */
88   int iOvfl;                      /* Iterates through aOvfl[] */
89 };
90 
91 /* Size information for a single btree page */
92 struct StatPage {
93   u32 iPgno;                      /* Page number */
94   DbPage *pPg;                    /* Page content */
95   int iCell;                      /* Current cell */
96 
97   char *zPath;                    /* Path to this page */
98 
99   /* Variables populated by statDecodePage(): */
100   u8 flags;                       /* Copy of flags byte */
101   int nCell;                      /* Number of cells on page */
102   int nUnused;                    /* Number of unused bytes on page */
103   StatCell *aCell;                /* Array of parsed cells */
104   u32 iRightChildPg;              /* Right-child page number (or 0) */
105   int nMxPayload;                 /* Largest payload of any cell on the page */
106 };
107 
108 /* The cursor for scanning the dbstat virtual table */
109 struct StatCursor {
110   sqlite3_vtab_cursor base;       /* base class.  MUST BE FIRST! */
111   sqlite3_stmt *pStmt;            /* Iterates through set of root pages */
112   int isEof;                      /* After pStmt has returned SQLITE_DONE */
113   int iDb;                        /* Schema used for this query */
114   int isAgg;                      /* Aggregate results for each table */
115 
116   StatPage aPage[32];             /* Pages in path to current page */
117   int iPage;                      /* Current entry in aPage[] */
118 
119   /* Values to return. */
120   char *zName;                    /* Value of 'name' column */
121   char *zPath;                    /* Value of 'path' column */
122   u32 iPageno;                    /* Value of 'pageno' column */
123   char *zPagetype;                /* Value of 'pagetype' column */
124   int nCell;                      /* Value of 'ncell' column */
125   int nPayload;                   /* Value of 'payload' column */
126   int nUnused;                    /* Value of 'unused' column */
127   int nMxPayload;                 /* Value of 'mx_payload' column */
128   i64 iOffset;                    /* Value of 'pgOffset' column */
129   int szPage;                     /* Value of 'pgSize' column */
130 };
131 
132 /* An instance of the DBSTAT virtual table */
133 struct StatTable {
134   sqlite3_vtab base;              /* base class.  MUST BE FIRST! */
135   sqlite3 *db;                    /* Database connection that owns this vtab */
136   int iDb;                        /* Index of database to analyze */
137 };
138 
139 #ifndef get2byte
140 # define get2byte(x)   ((x)[0]<<8 | (x)[1])
141 #endif
142 
143 /*
144 ** Connect to or create a new DBSTAT virtual table.
145 */
146 static int statConnect(
147   sqlite3 *db,
148   void *pAux,
149   int argc, const char *const*argv,
150   sqlite3_vtab **ppVtab,
151   char **pzErr
152 ){
153   StatTable *pTab = 0;
154   int rc = SQLITE_OK;
155   int iDb;
156 
157   if( argc>=4 ){
158     Token nm;
159     sqlite3TokenInit(&nm, (char*)argv[3]);
160     iDb = sqlite3FindDb(db, &nm);
161     if( iDb<0 ){
162       *pzErr = sqlite3_mprintf("no such database: %s", argv[3]);
163       return SQLITE_ERROR;
164     }
165   }else{
166     iDb = 0;
167   }
168   rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
169   if( rc==SQLITE_OK ){
170     pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
171     if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
172   }
173 
174   assert( rc==SQLITE_OK || pTab==0 );
175   if( rc==SQLITE_OK ){
176     memset(pTab, 0, sizeof(StatTable));
177     pTab->db = db;
178     pTab->iDb = iDb;
179   }
180 
181   *ppVtab = (sqlite3_vtab*)pTab;
182   return rc;
183 }
184 
185 /*
186 ** Disconnect from or destroy the DBSTAT virtual table.
187 */
188 static int statDisconnect(sqlite3_vtab *pVtab){
189   sqlite3_free(pVtab);
190   return SQLITE_OK;
191 }
192 
193 /*
194 ** Compute the best query strategy and return the result in idxNum.
195 **
196 **   idxNum-Bit        Meaning
197 **   ----------        ----------------------------------------------
198 **      0x01           There is a schema=? term in the WHERE clause
199 **      0x02           There is a name=? term in the WHERE clause
200 **      0x04           There is an aggregate=? term in the WHERE clause
201 **      0x08           Output should be ordered by name and path
202 */
203 static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
204   int i;
205   int iSchema = -1;
206   int iName = -1;
207   int iAgg = -1;
208 
209   /* Look for a valid schema=? constraint.  If found, change the idxNum to
210   ** 1 and request the value of that constraint be sent to xFilter.  And
211   ** lower the cost estimate to encourage the constrained version to be
212   ** used.
213   */
214   for(i=0; i<pIdxInfo->nConstraint; i++){
215     if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
216     if( pIdxInfo->aConstraint[i].usable==0 ){
217       /* Force DBSTAT table should always be the right-most table in a join */
218       return SQLITE_CONSTRAINT;
219     }
220     switch( pIdxInfo->aConstraint[i].iColumn ){
221       case 0: {    /* name */
222         iName = i;
223         break;
224       }
225       case 10: {   /* schema */
226         iSchema = i;
227         break;
228       }
229       case 11: {   /* aggregate */
230         iAgg = i;
231         break;
232       }
233     }
234   }
235   i = 0;
236   if( iSchema>=0 ){
237     pIdxInfo->aConstraintUsage[iSchema].argvIndex = ++i;
238     pIdxInfo->aConstraintUsage[iSchema].omit = 1;
239     pIdxInfo->idxNum |= 0x01;
240   }
241   if( iName>=0 ){
242     pIdxInfo->aConstraintUsage[iName].argvIndex = ++i;
243     pIdxInfo->aConstraintUsage[iName].omit = 1;
244     pIdxInfo->idxNum |= 0x02;
245   }
246   if( iAgg>=0 ){
247     pIdxInfo->aConstraintUsage[iAgg].argvIndex = ++i;
248     pIdxInfo->aConstraintUsage[iAgg].omit = 1;
249     pIdxInfo->idxNum |= 0x04;
250   }
251   pIdxInfo->estimatedCost = 1.0;
252 
253   /* Records are always returned in ascending order of (name, path).
254   ** If this will satisfy the client, set the orderByConsumed flag so that
255   ** SQLite does not do an external sort.
256   */
257   if( ( pIdxInfo->nOrderBy==1
258      && pIdxInfo->aOrderBy[0].iColumn==0
259      && pIdxInfo->aOrderBy[0].desc==0
260      ) ||
261       ( pIdxInfo->nOrderBy==2
262      && pIdxInfo->aOrderBy[0].iColumn==0
263      && pIdxInfo->aOrderBy[0].desc==0
264      && pIdxInfo->aOrderBy[1].iColumn==1
265      && pIdxInfo->aOrderBy[1].desc==0
266      )
267   ){
268     pIdxInfo->orderByConsumed = 1;
269     pIdxInfo->idxNum |= 0x08;
270   }
271 
272   return SQLITE_OK;
273 }
274 
275 /*
276 ** Open a new statvfs cursor.
277 */
278 static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
279   StatTable *pTab = (StatTable *)pVTab;
280   StatCursor *pCsr;
281 
282   pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
283   if( pCsr==0 ){
284     return SQLITE_NOMEM_BKPT;
285   }else{
286     memset(pCsr, 0, sizeof(StatCursor));
287     pCsr->base.pVtab = pVTab;
288     pCsr->iDb = pTab->iDb;
289   }
290 
291   *ppCursor = (sqlite3_vtab_cursor *)pCsr;
292   return SQLITE_OK;
293 }
294 
295 static void statClearCells(StatPage *p){
296   int i;
297   if( p->aCell ){
298     for(i=0; i<p->nCell; i++){
299       sqlite3_free(p->aCell[i].aOvfl);
300     }
301     sqlite3_free(p->aCell);
302   }
303   p->nCell = 0;
304   p->aCell = 0;
305 }
306 
307 static void statClearPage(StatPage *p){
308   statClearCells(p);
309   sqlite3PagerUnref(p->pPg);
310   sqlite3_free(p->zPath);
311   memset(p, 0, sizeof(StatPage));
312 }
313 
314 static void statResetCsr(StatCursor *pCsr){
315   int i;
316   sqlite3_reset(pCsr->pStmt);
317   for(i=0; i<ArraySize(pCsr->aPage); i++){
318     statClearPage(&pCsr->aPage[i]);
319   }
320   pCsr->iPage = 0;
321   sqlite3_free(pCsr->zPath);
322   pCsr->zPath = 0;
323   pCsr->isEof = 0;
324 }
325 
326 /*
327 ** Close a statvfs cursor.
328 */
329 static int statClose(sqlite3_vtab_cursor *pCursor){
330   StatCursor *pCsr = (StatCursor *)pCursor;
331   statResetCsr(pCsr);
332   sqlite3_finalize(pCsr->pStmt);
333   sqlite3_free(pCsr);
334   return SQLITE_OK;
335 }
336 
337 /*
338 ** For a single cell on a btree page, compute the number of bytes of
339 ** content (payload) stored on that page.  That is to say, compute the
340 ** number of bytes of content not found on overflow pages.
341 */
342 static int getLocalPayload(
343   int nUsable,                    /* Usable bytes per page */
344   u8 flags,                       /* Page flags */
345   int nTotal                      /* Total record (payload) size */
346 ){
347   int nLocal;
348   int nMinLocal;
349   int nMaxLocal;
350 
351   if( flags==0x0D ){              /* Table leaf node */
352     nMinLocal = (nUsable - 12) * 32 / 255 - 23;
353     nMaxLocal = nUsable - 35;
354   }else{                          /* Index interior and leaf nodes */
355     nMinLocal = (nUsable - 12) * 32 / 255 - 23;
356     nMaxLocal = (nUsable - 12) * 64 / 255 - 23;
357   }
358 
359   nLocal = nMinLocal + (nTotal - nMinLocal) % (nUsable - 4);
360   if( nLocal>nMaxLocal ) nLocal = nMinLocal;
361   return nLocal;
362 }
363 
364 static int statDecodePage(Btree *pBt, StatPage *p){
365   int nUnused;
366   int iOff;
367   int nHdr;
368   int isLeaf;
369   int szPage;
370 
371   u8 *aData = sqlite3PagerGetData(p->pPg);
372   u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0];
373 
374   p->flags = aHdr[0];
375   if( p->flags==0x0A || p->flags==0x0D ){
376     isLeaf = 1;
377     nHdr = 8;
378   }else if( p->flags==0x05 || p->flags==0x02 ){
379     isLeaf = 0;
380     nHdr = 12;
381   }else{
382     goto statPageIsCorrupt;
383   }
384   if( p->iPgno==1 ) nHdr += 100;
385   p->nCell = get2byte(&aHdr[3]);
386   p->nMxPayload = 0;
387   szPage = sqlite3BtreeGetPageSize(pBt);
388 
389   nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell;
390   nUnused += (int)aHdr[7];
391   iOff = get2byte(&aHdr[1]);
392   while( iOff ){
393     int iNext;
394     if( iOff>=szPage ) goto statPageIsCorrupt;
395     nUnused += get2byte(&aData[iOff+2]);
396     iNext = get2byte(&aData[iOff]);
397     if( iNext<iOff+4 && iNext>0 ) goto statPageIsCorrupt;
398     iOff = iNext;
399   }
400   p->nUnused = nUnused;
401   p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]);
402 
403   if( p->nCell ){
404     int i;                        /* Used to iterate through cells */
405     int nUsable;                  /* Usable bytes per page */
406 
407     sqlite3BtreeEnter(pBt);
408     nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt);
409     sqlite3BtreeLeave(pBt);
410     p->aCell = sqlite3_malloc64((p->nCell+1) * sizeof(StatCell));
411     if( p->aCell==0 ) return SQLITE_NOMEM_BKPT;
412     memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell));
413 
414     for(i=0; i<p->nCell; i++){
415       StatCell *pCell = &p->aCell[i];
416 
417       iOff = get2byte(&aData[nHdr+i*2]);
418       if( iOff<nHdr || iOff>=szPage ) goto statPageIsCorrupt;
419       if( !isLeaf ){
420         pCell->iChildPg = sqlite3Get4byte(&aData[iOff]);
421         iOff += 4;
422       }
423       if( p->flags==0x05 ){
424         /* A table interior node. nPayload==0. */
425       }else{
426         u32 nPayload;             /* Bytes of payload total (local+overflow) */
427         int nLocal;               /* Bytes of payload stored locally */
428         iOff += getVarint32(&aData[iOff], nPayload);
429         if( p->flags==0x0D ){
430           u64 dummy;
431           iOff += sqlite3GetVarint(&aData[iOff], &dummy);
432         }
433         if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload;
434         nLocal = getLocalPayload(nUsable, p->flags, nPayload);
435         if( nLocal<0 ) goto statPageIsCorrupt;
436         pCell->nLocal = nLocal;
437         assert( nPayload>=(u32)nLocal );
438         assert( nLocal<=(nUsable-35) );
439         if( nPayload>(u32)nLocal ){
440           int j;
441           int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);
442           if( iOff+nLocal>nUsable ) goto statPageIsCorrupt;
443           pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
444           pCell->nOvfl = nOvfl;
445           pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
446           if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT;
447           pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
448           for(j=1; j<nOvfl; j++){
449             int rc;
450             u32 iPrev = pCell->aOvfl[j-1];
451             DbPage *pPg = 0;
452             rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg, 0);
453             if( rc!=SQLITE_OK ){
454               assert( pPg==0 );
455               return rc;
456             }
457             pCell->aOvfl[j] = sqlite3Get4byte(sqlite3PagerGetData(pPg));
458             sqlite3PagerUnref(pPg);
459           }
460         }
461       }
462     }
463   }
464 
465   return SQLITE_OK;
466 
467 statPageIsCorrupt:
468   p->flags = 0;
469   statClearCells(p);
470   return SQLITE_OK;
471 }
472 
473 /*
474 ** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on
475 ** the current value of pCsr->iPageno.
476 */
477 static void statSizeAndOffset(StatCursor *pCsr){
478   StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab;
479   Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
480   Pager *pPager = sqlite3BtreePager(pBt);
481   sqlite3_file *fd;
482   sqlite3_int64 x[2];
483 
484   /* The default page size and offset */
485   pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
486   pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
487 
488   /* If connected to a ZIPVFS backend, override the page size and
489   ** offset with actual values obtained from ZIPVFS.
490   */
491   fd = sqlite3PagerFile(pPager);
492   x[0] = pCsr->iPageno;
493   if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
494     pCsr->iOffset = x[0];
495     pCsr->szPage = (int)x[1];
496   }
497 }
498 
499 /*
500 ** Move a statvfs cursor to the next entry in the file.
501 */
502 static int statNext(sqlite3_vtab_cursor *pCursor){
503   int rc;
504   int nPayload;
505   char *z;
506   StatCursor *pCsr = (StatCursor *)pCursor;
507   StatTable *pTab = (StatTable *)pCursor->pVtab;
508   Btree *pBt = pTab->db->aDb[pCsr->iDb].pBt;
509   Pager *pPager = sqlite3BtreePager(pBt);
510 
511   sqlite3_free(pCsr->zPath);
512   pCsr->zPath = 0;
513 
514 statNextRestart:
515   if( pCsr->aPage[0].pPg==0 ){
516     rc = sqlite3_step(pCsr->pStmt);
517     if( rc==SQLITE_ROW ){
518       int nPage;
519       u32 iRoot = (u32)sqlite3_column_int64(pCsr->pStmt, 1);
520       sqlite3PagerPagecount(pPager, &nPage);
521       if( nPage==0 ){
522         pCsr->isEof = 1;
523         return sqlite3_reset(pCsr->pStmt);
524       }
525       rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0);
526       pCsr->aPage[0].iPgno = iRoot;
527       pCsr->aPage[0].iCell = 0;
528       pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
529       pCsr->iPage = 0;
530       if( z==0 ) rc = SQLITE_NOMEM_BKPT;
531     }else{
532       pCsr->isEof = 1;
533       return sqlite3_reset(pCsr->pStmt);
534     }
535   }else{
536 
537     /* Page p itself has already been visited. */
538     StatPage *p = &pCsr->aPage[pCsr->iPage];
539 
540     while( p->iCell<p->nCell ){
541       StatCell *pCell = &p->aCell[p->iCell];
542       if( pCell->iOvfl<pCell->nOvfl ){
543         int nUsable;
544         sqlite3BtreeEnter(pBt);
545         nUsable = sqlite3BtreeGetPageSize(pBt) -
546                         sqlite3BtreeGetReserveNoMutex(pBt);
547         sqlite3BtreeLeave(pBt);
548         pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
549         pCsr->iPageno = pCell->aOvfl[pCell->iOvfl];
550         pCsr->zPagetype = "overflow";
551         pCsr->nCell = 0;
552         pCsr->nMxPayload = 0;
553         pCsr->zPath = z = sqlite3_mprintf(
554             "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl
555         );
556         if( pCell->iOvfl<pCell->nOvfl-1 ){
557           pCsr->nUnused = 0;
558           pCsr->nPayload = nUsable - 4;
559         }else{
560           pCsr->nPayload = pCell->nLastOvfl;
561           pCsr->nUnused = nUsable - 4 - pCsr->nPayload;
562         }
563         pCell->iOvfl++;
564         statSizeAndOffset(pCsr);
565         return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
566       }
567       if( p->iRightChildPg ) break;
568       p->iCell++;
569     }
570 
571     if( !p->iRightChildPg || p->iCell>p->nCell ){
572       statClearPage(p);
573       if( pCsr->iPage==0 ) return statNext(pCursor);
574       pCsr->iPage--;
575       goto statNextRestart; /* Tail recursion */
576     }
577     pCsr->iPage++;
578     if( pCsr->iPage>=ArraySize(pCsr->aPage) ){
579       statResetCsr(pCsr);
580       return SQLITE_CORRUPT_BKPT;
581     }
582     assert( p==&pCsr->aPage[pCsr->iPage-1] );
583 
584     if( p->iCell==p->nCell ){
585       p[1].iPgno = p->iRightChildPg;
586     }else{
587       p[1].iPgno = p->aCell[p->iCell].iChildPg;
588     }
589     rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0);
590     p[1].iCell = 0;
591     p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
592     p->iCell++;
593     if( z==0 ) rc = SQLITE_NOMEM_BKPT;
594   }
595 
596 
597   /* Populate the StatCursor fields with the values to be returned
598   ** by the xColumn() and xRowid() methods.
599   */
600   if( rc==SQLITE_OK ){
601     int i;
602     StatPage *p = &pCsr->aPage[pCsr->iPage];
603     pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
604     pCsr->iPageno = p->iPgno;
605 
606     rc = statDecodePage(pBt, p);
607     if( rc==SQLITE_OK ){
608       statSizeAndOffset(pCsr);
609 
610       switch( p->flags ){
611         case 0x05:             /* table internal */
612         case 0x02:             /* index internal */
613           pCsr->zPagetype = "internal";
614           break;
615         case 0x0D:             /* table leaf */
616         case 0x0A:             /* index leaf */
617           pCsr->zPagetype = "leaf";
618           break;
619         default:
620           pCsr->zPagetype = "corrupted";
621           break;
622       }
623       pCsr->nCell = p->nCell;
624       pCsr->nUnused = p->nUnused;
625       pCsr->nMxPayload = p->nMxPayload;
626       pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
627       if( z==0 ) rc = SQLITE_NOMEM_BKPT;
628       nPayload = 0;
629       for(i=0; i<p->nCell; i++){
630         nPayload += p->aCell[i].nLocal;
631       }
632       pCsr->nPayload = nPayload;
633     }
634   }
635 
636   return rc;
637 }
638 
639 static int statEof(sqlite3_vtab_cursor *pCursor){
640   StatCursor *pCsr = (StatCursor *)pCursor;
641   return pCsr->isEof;
642 }
643 
644 /* Initialize a cursor according to the query plan idxNum using the
645 ** arguments in argv[0].  See statBestIndex() for a description of the
646 ** meaning of the bits in idxNum.
647 */
648 static int statFilter(
649   sqlite3_vtab_cursor *pCursor,
650   int idxNum, const char *idxStr,
651   int argc, sqlite3_value **argv
652 ){
653   StatCursor *pCsr = (StatCursor *)pCursor;
654   StatTable *pTab = (StatTable*)(pCursor->pVtab);
655   sqlite3_str *pSql;      /* Query of btrees to analyze */
656   char *zSql;             /* String value of pSql */
657   int iArg = 0;           /* Count of argv[] parameters used so far */
658   int rc = SQLITE_OK;     /* Result of this operation */
659   const char *zName = 0;  /* Only provide analysis of this table */
660 
661   statResetCsr(pCsr);
662   sqlite3_finalize(pCsr->pStmt);
663   pCsr->pStmt = 0;
664   if( idxNum & 0x01 ){
665     /* schema=? constraint is present.  Get its value */
666     const char *zDbase = (const char*)sqlite3_value_text(argv[iArg++]);
667     pCsr->iDb = sqlite3FindDbName(pTab->db, zDbase);
668     if( pCsr->iDb<0 ){
669       sqlite3_free(pCursor->pVtab->zErrMsg);
670       pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase);
671       return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT;
672     }
673   }else{
674     pCsr->iDb = pTab->iDb;
675   }
676   if( idxNum & 0x02 ){
677     /* name=? constraint is present */
678     zName = (const char*)sqlite3_value_text(argv[iArg++]);
679   }
680   if( idxNum & 0x04 ){
681     /* aggregate=? constraint is present */
682     pCsr->isAgg = sqlite3_value_double(argv[iArg++])!=0.0;
683   }else{
684     pCsr->isAgg = 0;
685   }
686   pSql = sqlite3_str_new(pTab->db);
687   sqlite3_str_appendf(pSql,
688       "SELECT * FROM ("
689         "SELECT 'sqlite_master' AS name,1 AS rootpage,'table' AS type"
690         " UNION ALL "
691         "SELECT name,rootpage,type"
692         " FROM \"%w\".sqlite_master WHERE rootpage!=0)",
693       pTab->db->aDb[pCsr->iDb].zDbSName);
694   if( zName ){
695     sqlite3_str_appendf(pSql, "WHERE name=%Q", zName);
696   }
697   if( idxNum & 0x08 ){
698     sqlite3_str_appendf(pSql, " ORDER BY name");
699   }
700   zSql = sqlite3_str_finish(pSql);
701   if( zSql==0 ){
702     return SQLITE_NOMEM_BKPT;
703   }else{
704     rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
705     sqlite3_free(zSql);
706   }
707 
708   if( rc==SQLITE_OK ){
709     rc = statNext(pCursor);
710   }
711   return rc;
712 }
713 
714 static int statColumn(
715   sqlite3_vtab_cursor *pCursor,
716   sqlite3_context *ctx,
717   int i
718 ){
719   StatCursor *pCsr = (StatCursor *)pCursor;
720   switch( i ){
721     case 0:            /* name */
722       sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_TRANSIENT);
723       break;
724     case 1:            /* path */
725       sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
726       break;
727     case 2:            /* pageno */
728       sqlite3_result_int64(ctx, pCsr->iPageno);
729       break;
730     case 3:            /* pagetype */
731       sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC);
732       break;
733     case 4:            /* ncell */
734       sqlite3_result_int(ctx, pCsr->nCell);
735       break;
736     case 5:            /* payload */
737       sqlite3_result_int(ctx, pCsr->nPayload);
738       break;
739     case 6:            /* unused */
740       sqlite3_result_int(ctx, pCsr->nUnused);
741       break;
742     case 7:            /* mx_payload */
743       sqlite3_result_int(ctx, pCsr->nMxPayload);
744       break;
745     case 8:            /* pgoffset */
746       sqlite3_result_int64(ctx, pCsr->iOffset);
747       break;
748     case 9:            /* pgsize */
749       sqlite3_result_int(ctx, pCsr->szPage);
750       break;
751     case 10: {         /* schema */
752       sqlite3 *db = sqlite3_context_db_handle(ctx);
753       int iDb = pCsr->iDb;
754       sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC);
755       break;
756     }
757     default: {         /* aggregate */
758       sqlite3_result_int(ctx, pCsr->isAgg);
759       break;
760     }
761   }
762   return SQLITE_OK;
763 }
764 
765 static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
766   StatCursor *pCsr = (StatCursor *)pCursor;
767   *pRowid = pCsr->iPageno;
768   return SQLITE_OK;
769 }
770 
771 /*
772 ** Invoke this routine to register the "dbstat" virtual table module
773 */
774 int sqlite3DbstatRegister(sqlite3 *db){
775   static sqlite3_module dbstat_module = {
776     0,                            /* iVersion */
777     statConnect,                  /* xCreate */
778     statConnect,                  /* xConnect */
779     statBestIndex,                /* xBestIndex */
780     statDisconnect,               /* xDisconnect */
781     statDisconnect,               /* xDestroy */
782     statOpen,                     /* xOpen - open a cursor */
783     statClose,                    /* xClose - close a cursor */
784     statFilter,                   /* xFilter - configure scan constraints */
785     statNext,                     /* xNext - advance a cursor */
786     statEof,                      /* xEof - check for end of scan */
787     statColumn,                   /* xColumn - read data */
788     statRowid,                    /* xRowid - read data */
789     0,                            /* xUpdate */
790     0,                            /* xBegin */
791     0,                            /* xSync */
792     0,                            /* xCommit */
793     0,                            /* xRollback */
794     0,                            /* xFindMethod */
795     0,                            /* xRename */
796     0,                            /* xSavepoint */
797     0,                            /* xRelease */
798     0,                            /* xRollbackTo */
799     0                             /* xShadowName */
800   };
801   return sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
802 }
803 #elif defined(SQLITE_ENABLE_DBSTAT_VTAB)
804 int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
805 #endif /* SQLITE_ENABLE_DBSTAT_VTAB */
806