modernc.org/cc@v1.0.1/v2/testdata/_sqlite/src/dbstat.c (about)

     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 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.
    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,             /* 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 */"     \
    72    ");"
    73  
    74  
    75  typedef struct StatTable StatTable;
    76  typedef struct StatCursor StatCursor;
    77  typedef struct StatPage StatPage;
    78  typedef struct StatCell StatCell;
    79  
    80  struct 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[] */
    87  };
    88  
    89  struct StatPage {
    90    u32 iPgno;
    91    DbPage *pPg;
    92    int iCell;
    93  
    94    char *zPath;                    /* Path to this page */
    95  
    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 */
   103  };
   104  
   105  struct StatCursor {
   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 */
   110  
   111    StatPage aPage[32];
   112    int iPage;                      /* Current entry in aPage[] */
   113  
   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 */
   125  };
   126  
   127  struct StatTable {
   128    sqlite3_vtab base;
   129    sqlite3 *db;
   130    int iDb;                        /* Index of database to analyze */
   131  };
   132  
   133  #ifndef get2byte
   134  # define get2byte(x)   ((x)[0]<<8 | (x)[1])
   135  #endif
   136  
   137  /*
   138  ** Connect to or create a statvfs virtual table.
   139  */
   140  static int statConnect(
   141    sqlite3 *db,
   142    void *pAux,
   143    int argc, const char *const*argv,
   144    sqlite3_vtab **ppVtab,
   145    char **pzErr
   146  ){
   147    StatTable *pTab = 0;
   148    int rc = SQLITE_OK;
   149    int iDb;
   150  
   151    if( argc>=4 ){
   152      Token nm;
   153      sqlite3TokenInit(&nm, (char*)argv[3]);
   154      iDb = sqlite3FindDb(db, &nm);
   155      if( iDb<0 ){
   156        *pzErr = sqlite3_mprintf("no such database: %s", argv[3]);
   157        return SQLITE_ERROR;
   158      }
   159    }else{
   160      iDb = 0;
   161    }
   162    rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
   163    if( rc==SQLITE_OK ){
   164      pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
   165      if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
   166    }
   167  
   168    assert( rc==SQLITE_OK || pTab==0 );
   169    if( rc==SQLITE_OK ){
   170      memset(pTab, 0, sizeof(StatTable));
   171      pTab->db = db;
   172      pTab->iDb = iDb;
   173    }
   174  
   175    *ppVtab = (sqlite3_vtab*)pTab;
   176    return rc;
   177  }
   178  
   179  /*
   180  ** Disconnect from or destroy a statvfs virtual table.
   181  */
   182  static int statDisconnect(sqlite3_vtab *pVtab){
   183    sqlite3_free(pVtab);
   184    return SQLITE_OK;
   185  }
   186  
   187  /*
   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.
   191  **
   192  ** idxNum is normally 0, but will be 1 if a schema=? constraint exists.
   193  */
   194  static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
   195    int i;
   196  
   197    pIdxInfo->estimatedCost = 1.0e6;  /* Initial cost estimate */
   198  
   199    /* Look for a valid schema=? constraint.  If found, change the idxNum to
   200    ** 1 and request the value of that constraint be sent to xFilter.  And
   201    ** lower the cost estimate to encourage the constrained version to be
   202    ** used.
   203    */
   204    for(i=0; i<pIdxInfo->nConstraint; i++){
   205      if( pIdxInfo->aConstraint[i].usable==0 ) continue;
   206      if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
   207      if( pIdxInfo->aConstraint[i].iColumn!=10 ) continue;
   208      pIdxInfo->idxNum = 1;
   209      pIdxInfo->estimatedCost = 1.0;
   210      pIdxInfo->aConstraintUsage[i].argvIndex = 1;
   211      pIdxInfo->aConstraintUsage[i].omit = 1;
   212      break;
   213    }
   214  
   215  
   216    /* Records are always returned in ascending order of (name, path). 
   217    ** If this will satisfy the client, set the orderByConsumed flag so that 
   218    ** SQLite does not do an external sort.
   219    */
   220    if( ( pIdxInfo->nOrderBy==1
   221       && pIdxInfo->aOrderBy[0].iColumn==0
   222       && pIdxInfo->aOrderBy[0].desc==0
   223       ) ||
   224        ( pIdxInfo->nOrderBy==2
   225       && pIdxInfo->aOrderBy[0].iColumn==0
   226       && pIdxInfo->aOrderBy[0].desc==0
   227       && pIdxInfo->aOrderBy[1].iColumn==1
   228       && pIdxInfo->aOrderBy[1].desc==0
   229       )
   230    ){
   231      pIdxInfo->orderByConsumed = 1;
   232    }
   233  
   234    return SQLITE_OK;
   235  }
   236  
   237  /*
   238  ** Open a new statvfs cursor.
   239  */
   240  static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
   241    StatTable *pTab = (StatTable *)pVTab;
   242    StatCursor *pCsr;
   243  
   244    pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
   245    if( pCsr==0 ){
   246      return SQLITE_NOMEM_BKPT;
   247    }else{
   248      memset(pCsr, 0, sizeof(StatCursor));
   249      pCsr->base.pVtab = pVTab;
   250      pCsr->iDb = pTab->iDb;
   251    }
   252  
   253    *ppCursor = (sqlite3_vtab_cursor *)pCsr;
   254    return SQLITE_OK;
   255  }
   256  
   257  static void statClearPage(StatPage *p){
   258    int i;
   259    if( p->aCell ){
   260      for(i=0; i<p->nCell; i++){
   261        sqlite3_free(p->aCell[i].aOvfl);
   262      }
   263      sqlite3_free(p->aCell);
   264    }
   265    sqlite3PagerUnref(p->pPg);
   266    sqlite3_free(p->zPath);
   267    memset(p, 0, sizeof(StatPage));
   268  }
   269  
   270  static void statResetCsr(StatCursor *pCsr){
   271    int i;
   272    sqlite3_reset(pCsr->pStmt);
   273    for(i=0; i<ArraySize(pCsr->aPage); i++){
   274      statClearPage(&pCsr->aPage[i]);
   275    }
   276    pCsr->iPage = 0;
   277    sqlite3_free(pCsr->zPath);
   278    pCsr->zPath = 0;
   279    pCsr->isEof = 0;
   280  }
   281  
   282  /*
   283  ** Close a statvfs cursor.
   284  */
   285  static int statClose(sqlite3_vtab_cursor *pCursor){
   286    StatCursor *pCsr = (StatCursor *)pCursor;
   287    statResetCsr(pCsr);
   288    sqlite3_finalize(pCsr->pStmt);
   289    sqlite3_free(pCsr);
   290    return SQLITE_OK;
   291  }
   292  
   293  static void getLocalPayload(
   294    int nUsable,                    /* Usable bytes per page */
   295    u8 flags,                       /* Page flags */
   296    int nTotal,                     /* Total record (payload) size */
   297    int *pnLocal                    /* OUT: Bytes stored locally */
   298  ){
   299    int nLocal;
   300    int nMinLocal;
   301    int nMaxLocal;
   302   
   303    if( flags==0x0D ){              /* Table leaf node */
   304      nMinLocal = (nUsable - 12) * 32 / 255 - 23;
   305      nMaxLocal = nUsable - 35;
   306    }else{                          /* Index interior and leaf nodes */
   307      nMinLocal = (nUsable - 12) * 32 / 255 - 23;
   308      nMaxLocal = (nUsable - 12) * 64 / 255 - 23;
   309    }
   310  
   311    nLocal = nMinLocal + (nTotal - nMinLocal) % (nUsable - 4);
   312    if( nLocal>nMaxLocal ) nLocal = nMinLocal;
   313    *pnLocal = nLocal;
   314  }
   315  
   316  static int statDecodePage(Btree *pBt, StatPage *p){
   317    int nUnused;
   318    int iOff;
   319    int nHdr;
   320    int isLeaf;
   321    int szPage;
   322  
   323    u8 *aData = sqlite3PagerGetData(p->pPg);
   324    u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0];
   325  
   326    p->flags = aHdr[0];
   327    p->nCell = get2byte(&aHdr[3]);
   328    p->nMxPayload = 0;
   329  
   330    isLeaf = (p->flags==0x0A || p->flags==0x0D);
   331    nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100;
   332  
   333    nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell;
   334    nUnused += (int)aHdr[7];
   335    iOff = get2byte(&aHdr[1]);
   336    while( iOff ){
   337      nUnused += get2byte(&aData[iOff+2]);
   338      iOff = get2byte(&aData[iOff]);
   339    }
   340    p->nUnused = nUnused;
   341    p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]);
   342    szPage = sqlite3BtreeGetPageSize(pBt);
   343  
   344    if( p->nCell ){
   345      int i;                        /* Used to iterate through cells */
   346      int nUsable;                  /* Usable bytes per page */
   347  
   348      sqlite3BtreeEnter(pBt);
   349      nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt);
   350      sqlite3BtreeLeave(pBt);
   351      p->aCell = sqlite3_malloc64((p->nCell+1) * sizeof(StatCell));
   352      if( p->aCell==0 ) return SQLITE_NOMEM_BKPT;
   353      memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell));
   354  
   355      for(i=0; i<p->nCell; i++){
   356        StatCell *pCell = &p->aCell[i];
   357  
   358        iOff = get2byte(&aData[nHdr+i*2]);
   359        if( !isLeaf ){
   360          pCell->iChildPg = sqlite3Get4byte(&aData[iOff]);
   361          iOff += 4;
   362        }
   363        if( p->flags==0x05 ){
   364          /* A table interior node. nPayload==0. */
   365        }else{
   366          u32 nPayload;             /* Bytes of payload total (local+overflow) */
   367          int nLocal;               /* Bytes of payload stored locally */
   368          iOff += getVarint32(&aData[iOff], nPayload);
   369          if( p->flags==0x0D ){
   370            u64 dummy;
   371            iOff += sqlite3GetVarint(&aData[iOff], &dummy);
   372          }
   373          if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload;
   374          getLocalPayload(nUsable, p->flags, nPayload, &nLocal);
   375          pCell->nLocal = nLocal;
   376          assert( nLocal>=0 );
   377          assert( nPayload>=(u32)nLocal );
   378          assert( nLocal<=(nUsable-35) );
   379          if( nPayload>(u32)nLocal ){
   380            int j;
   381            int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);
   382            pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
   383            pCell->nOvfl = nOvfl;
   384            pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
   385            if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT;
   386            pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
   387            for(j=1; j<nOvfl; j++){
   388              int rc;
   389              u32 iPrev = pCell->aOvfl[j-1];
   390              DbPage *pPg = 0;
   391              rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg, 0);
   392              if( rc!=SQLITE_OK ){
   393                assert( pPg==0 );
   394                return rc;
   395              } 
   396              pCell->aOvfl[j] = sqlite3Get4byte(sqlite3PagerGetData(pPg));
   397              sqlite3PagerUnref(pPg);
   398            }
   399          }
   400        }
   401      }
   402    }
   403  
   404    return SQLITE_OK;
   405  }
   406  
   407  /*
   408  ** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on
   409  ** the current value of pCsr->iPageno.
   410  */
   411  static void statSizeAndOffset(StatCursor *pCsr){
   412    StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab;
   413    Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
   414    Pager *pPager = sqlite3BtreePager(pBt);
   415    sqlite3_file *fd;
   416    sqlite3_int64 x[2];
   417  
   418    /* The default page size and offset */
   419    pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
   420    pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
   421  
   422    /* If connected to a ZIPVFS backend, override the page size and
   423    ** offset with actual values obtained from ZIPVFS.
   424    */
   425    fd = sqlite3PagerFile(pPager);
   426    x[0] = pCsr->iPageno;
   427    if( fd->pMethods!=0 && sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
   428      pCsr->iOffset = x[0];
   429      pCsr->szPage = (int)x[1];
   430    }
   431  }
   432  
   433  /*
   434  ** Move a statvfs cursor to the next entry in the file.
   435  */
   436  static int statNext(sqlite3_vtab_cursor *pCursor){
   437    int rc;
   438    int nPayload;
   439    char *z;
   440    StatCursor *pCsr = (StatCursor *)pCursor;
   441    StatTable *pTab = (StatTable *)pCursor->pVtab;
   442    Btree *pBt = pTab->db->aDb[pCsr->iDb].pBt;
   443    Pager *pPager = sqlite3BtreePager(pBt);
   444  
   445    sqlite3_free(pCsr->zPath);
   446    pCsr->zPath = 0;
   447  
   448  statNextRestart:
   449    if( pCsr->aPage[0].pPg==0 ){
   450      rc = sqlite3_step(pCsr->pStmt);
   451      if( rc==SQLITE_ROW ){
   452        int nPage;
   453        u32 iRoot = (u32)sqlite3_column_int64(pCsr->pStmt, 1);
   454        sqlite3PagerPagecount(pPager, &nPage);
   455        if( nPage==0 ){
   456          pCsr->isEof = 1;
   457          return sqlite3_reset(pCsr->pStmt);
   458        }
   459        rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0);
   460        pCsr->aPage[0].iPgno = iRoot;
   461        pCsr->aPage[0].iCell = 0;
   462        pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
   463        pCsr->iPage = 0;
   464        if( z==0 ) rc = SQLITE_NOMEM_BKPT;
   465      }else{
   466        pCsr->isEof = 1;
   467        return sqlite3_reset(pCsr->pStmt);
   468      }
   469    }else{
   470  
   471      /* Page p itself has already been visited. */
   472      StatPage *p = &pCsr->aPage[pCsr->iPage];
   473  
   474      while( p->iCell<p->nCell ){
   475        StatCell *pCell = &p->aCell[p->iCell];
   476        if( pCell->iOvfl<pCell->nOvfl ){
   477          int nUsable;
   478          sqlite3BtreeEnter(pBt);
   479          nUsable = sqlite3BtreeGetPageSize(pBt) - 
   480                          sqlite3BtreeGetReserveNoMutex(pBt);
   481          sqlite3BtreeLeave(pBt);
   482          pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
   483          pCsr->iPageno = pCell->aOvfl[pCell->iOvfl];
   484          pCsr->zPagetype = "overflow";
   485          pCsr->nCell = 0;
   486          pCsr->nMxPayload = 0;
   487          pCsr->zPath = z = sqlite3_mprintf(
   488              "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl
   489          );
   490          if( pCell->iOvfl<pCell->nOvfl-1 ){
   491            pCsr->nUnused = 0;
   492            pCsr->nPayload = nUsable - 4;
   493          }else{
   494            pCsr->nPayload = pCell->nLastOvfl;
   495            pCsr->nUnused = nUsable - 4 - pCsr->nPayload;
   496          }
   497          pCell->iOvfl++;
   498          statSizeAndOffset(pCsr);
   499          return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
   500        }
   501        if( p->iRightChildPg ) break;
   502        p->iCell++;
   503      }
   504  
   505      if( !p->iRightChildPg || p->iCell>p->nCell ){
   506        statClearPage(p);
   507        if( pCsr->iPage==0 ) return statNext(pCursor);
   508        pCsr->iPage--;
   509        goto statNextRestart; /* Tail recursion */
   510      }
   511      pCsr->iPage++;
   512      assert( p==&pCsr->aPage[pCsr->iPage-1] );
   513  
   514      if( p->iCell==p->nCell ){
   515        p[1].iPgno = p->iRightChildPg;
   516      }else{
   517        p[1].iPgno = p->aCell[p->iCell].iChildPg;
   518      }
   519      rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0);
   520      p[1].iCell = 0;
   521      p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
   522      p->iCell++;
   523      if( z==0 ) rc = SQLITE_NOMEM_BKPT;
   524    }
   525  
   526  
   527    /* Populate the StatCursor fields with the values to be returned
   528    ** by the xColumn() and xRowid() methods.
   529    */
   530    if( rc==SQLITE_OK ){
   531      int i;
   532      StatPage *p = &pCsr->aPage[pCsr->iPage];
   533      pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
   534      pCsr->iPageno = p->iPgno;
   535  
   536      rc = statDecodePage(pBt, p);
   537      if( rc==SQLITE_OK ){
   538        statSizeAndOffset(pCsr);
   539  
   540        switch( p->flags ){
   541          case 0x05:             /* table internal */
   542          case 0x02:             /* index internal */
   543            pCsr->zPagetype = "internal";
   544            break;
   545          case 0x0D:             /* table leaf */
   546          case 0x0A:             /* index leaf */
   547            pCsr->zPagetype = "leaf";
   548            break;
   549          default:
   550            pCsr->zPagetype = "corrupted";
   551            break;
   552        }
   553        pCsr->nCell = p->nCell;
   554        pCsr->nUnused = p->nUnused;
   555        pCsr->nMxPayload = p->nMxPayload;
   556        pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
   557        if( z==0 ) rc = SQLITE_NOMEM_BKPT;
   558        nPayload = 0;
   559        for(i=0; i<p->nCell; i++){
   560          nPayload += p->aCell[i].nLocal;
   561        }
   562        pCsr->nPayload = nPayload;
   563      }
   564    }
   565  
   566    return rc;
   567  }
   568  
   569  static int statEof(sqlite3_vtab_cursor *pCursor){
   570    StatCursor *pCsr = (StatCursor *)pCursor;
   571    return pCsr->isEof;
   572  }
   573  
   574  static int statFilter(
   575    sqlite3_vtab_cursor *pCursor, 
   576    int idxNum, const char *idxStr,
   577    int argc, sqlite3_value **argv
   578  ){
   579    StatCursor *pCsr = (StatCursor *)pCursor;
   580    StatTable *pTab = (StatTable*)(pCursor->pVtab);
   581    char *zSql;
   582    int rc = SQLITE_OK;
   583    char *zMaster;
   584  
   585    if( idxNum==1 ){
   586      const char *zDbase = (const char*)sqlite3_value_text(argv[0]);
   587      pCsr->iDb = sqlite3FindDbName(pTab->db, zDbase);
   588      if( pCsr->iDb<0 ){
   589        sqlite3_free(pCursor->pVtab->zErrMsg);
   590        pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase);
   591        return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT;
   592      }
   593    }else{
   594      pCsr->iDb = pTab->iDb;
   595    }
   596    statResetCsr(pCsr);
   597    sqlite3_finalize(pCsr->pStmt);
   598    pCsr->pStmt = 0;
   599    zMaster = pCsr->iDb==1 ? "sqlite_temp_master" : "sqlite_master";
   600    zSql = sqlite3_mprintf(
   601        "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
   602        "  UNION ALL  "
   603        "SELECT name, rootpage, type"
   604        "  FROM \"%w\".%s WHERE rootpage!=0"
   605        "  ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName, zMaster);
   606    if( zSql==0 ){
   607      return SQLITE_NOMEM_BKPT;
   608    }else{
   609      rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
   610      sqlite3_free(zSql);
   611    }
   612  
   613    if( rc==SQLITE_OK ){
   614      rc = statNext(pCursor);
   615    }
   616    return rc;
   617  }
   618  
   619  static int statColumn(
   620    sqlite3_vtab_cursor *pCursor, 
   621    sqlite3_context *ctx, 
   622    int i
   623  ){
   624    StatCursor *pCsr = (StatCursor *)pCursor;
   625    switch( i ){
   626      case 0:            /* name */
   627        sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_TRANSIENT);
   628        break;
   629      case 1:            /* path */
   630        sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
   631        break;
   632      case 2:            /* pageno */
   633        sqlite3_result_int64(ctx, pCsr->iPageno);
   634        break;
   635      case 3:            /* pagetype */
   636        sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC);
   637        break;
   638      case 4:            /* ncell */
   639        sqlite3_result_int(ctx, pCsr->nCell);
   640        break;
   641      case 5:            /* payload */
   642        sqlite3_result_int(ctx, pCsr->nPayload);
   643        break;
   644      case 6:            /* unused */
   645        sqlite3_result_int(ctx, pCsr->nUnused);
   646        break;
   647      case 7:            /* mx_payload */
   648        sqlite3_result_int(ctx, pCsr->nMxPayload);
   649        break;
   650      case 8:            /* pgoffset */
   651        sqlite3_result_int64(ctx, pCsr->iOffset);
   652        break;
   653      case 9:            /* pgsize */
   654        sqlite3_result_int(ctx, pCsr->szPage);
   655        break;
   656      default: {          /* schema */
   657        sqlite3 *db = sqlite3_context_db_handle(ctx);
   658        int iDb = pCsr->iDb;
   659        sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC);
   660        break;
   661      }
   662    }
   663    return SQLITE_OK;
   664  }
   665  
   666  static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
   667    StatCursor *pCsr = (StatCursor *)pCursor;
   668    *pRowid = pCsr->iPageno;
   669    return SQLITE_OK;
   670  }
   671  
   672  /*
   673  ** Invoke this routine to register the "dbstat" virtual table module
   674  */
   675  int sqlite3DbstatRegister(sqlite3 *db){
   676    static sqlite3_module dbstat_module = {
   677      0,                            /* iVersion */
   678      statConnect,                  /* xCreate */
   679      statConnect,                  /* xConnect */
   680      statBestIndex,                /* xBestIndex */
   681      statDisconnect,               /* xDisconnect */
   682      statDisconnect,               /* xDestroy */
   683      statOpen,                     /* xOpen - open a cursor */
   684      statClose,                    /* xClose - close a cursor */
   685      statFilter,                   /* xFilter - configure scan constraints */
   686      statNext,                     /* xNext - advance a cursor */
   687      statEof,                      /* xEof - check for end of scan */
   688      statColumn,                   /* xColumn - read data */
   689      statRowid,                    /* xRowid - read data */
   690      0,                            /* xUpdate */
   691      0,                            /* xBegin */
   692      0,                            /* xSync */
   693      0,                            /* xCommit */
   694      0,                            /* xRollback */
   695      0,                            /* xFindMethod */
   696      0,                            /* xRename */
   697      0,                            /* xSavepoint */
   698      0,                            /* xRelease */
   699      0,                            /* xRollbackTo */
   700    };
   701    return sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
   702  }
   703  #elif defined(SQLITE_ENABLE_DBSTAT_VTAB)
   704  int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
   705  #endif /* SQLITE_ENABLE_DBSTAT_VTAB */