File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sqlite3 / src / test_stat.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:04:17 2012 UTC (12 years, 8 months ago) by misho
Branches: sqlite3, MAIN
CVS tags: v3_7_10, HEAD
sqlite3

    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: 
   21: #ifndef SQLITE_AMALGAMATION
   22: # include "sqliteInt.h"
   23: #endif
   24: 
   25: #ifndef SQLITE_OMIT_VIRTUALTABLE
   26: 
   27: /*
   28: ** Page paths:
   29: ** 
   30: **   The value of the 'path' column describes the path taken from the 
   31: **   root-node of the b-tree structure to each page. The value of the 
   32: **   root-node path is '/'.
   33: **
   34: **   The value of the path for the left-most child page of the root of
   35: **   a b-tree is '/000/'. (Btrees store content ordered from left to right
   36: **   so the pages to the left have smaller keys than the pages to the right.)
   37: **   The next to left-most child of the root page is
   38: **   '/001', and so on, each sibling page identified by a 3-digit hex 
   39: **   value. The children of the 451st left-most sibling have paths such
   40: **   as '/1c2/000/, '/1c2/001/' etc.
   41: **
   42: **   Overflow pages are specified by appending a '+' character and a 
   43: **   six-digit hexadecimal value to the path to the cell they are linked
   44: **   from. For example, the three overflow pages in a chain linked from 
   45: **   the left-most cell of the 450th child of the root page are identified
   46: **   by the paths:
   47: **
   48: **      '/1c2/000+000000'         // First page in overflow chain
   49: **      '/1c2/000+000001'         // Second page in overflow chain
   50: **      '/1c2/000+000002'         // Third page in overflow chain
   51: **
   52: **   If the paths are sorted using the BINARY collation sequence, then
   53: **   the overflow pages associated with a cell will appear earlier in the
   54: **   sort-order than its child page:
   55: **
   56: **      '/1c2/000/'               // Left-most child of 451st child of root
   57: */
   58: #define VTAB_SCHEMA                                                         \
   59:   "CREATE TABLE xx( "                                                       \
   60:   "  name       STRING,           /* Name of table or index */"             \
   61:   "  path       INTEGER,          /* Path to page from root */"             \
   62:   "  pageno     INTEGER,          /* Page number */"                        \
   63:   "  pagetype   STRING,           /* 'internal', 'leaf' or 'overflow' */"   \
   64:   "  ncell      INTEGER,          /* Cells on page (0 for overflow) */"     \
   65:   "  payload    INTEGER,          /* Bytes of payload on this page */"      \
   66:   "  unused     INTEGER,          /* Bytes of unused space on this page */" \
   67:   "  mx_payload INTEGER,          /* Largest payload size of all cells */"  \
   68:   "  pgoffset   INTEGER,          /* Offset of page in file */"             \
   69:   "  pgsize     INTEGER           /* Size of the page */"                   \
   70:   ");"
   71: 
   72: 
   73: typedef struct StatTable StatTable;
   74: typedef struct StatCursor StatCursor;
   75: typedef struct StatPage StatPage;
   76: typedef struct StatCell StatCell;
   77: 
   78: struct StatCell {
   79:   int nLocal;                     /* Bytes of local payload */
   80:   u32 iChildPg;                   /* Child node (or 0 if this is a leaf) */
   81:   int nOvfl;                      /* Entries in aOvfl[] */
   82:   u32 *aOvfl;                     /* Array of overflow page numbers */
   83:   int nLastOvfl;                  /* Bytes of payload on final overflow page */
   84:   int iOvfl;                      /* Iterates through aOvfl[] */
   85: };
   86: 
   87: struct StatPage {
   88:   u32 iPgno;
   89:   DbPage *pPg;
   90:   int iCell;
   91: 
   92:   char *zPath;                    /* Path to this page */
   93: 
   94:   /* Variables populated by statDecodePage(): */
   95:   u8 flags;                       /* Copy of flags byte */
   96:   int nCell;                      /* Number of cells on page */
   97:   int nUnused;                    /* Number of unused bytes on page */
   98:   StatCell *aCell;                /* Array of parsed cells */
   99:   u32 iRightChildPg;              /* Right-child page number (or 0) */
  100:   int nMxPayload;                 /* Largest payload of any cell on this page */
  101: };
  102: 
  103: struct StatCursor {
  104:   sqlite3_vtab_cursor base;
  105:   sqlite3_stmt *pStmt;            /* Iterates through set of root pages */
  106:   int isEof;                      /* After pStmt has returned SQLITE_DONE */
  107: 
  108:   StatPage aPage[32];
  109:   int iPage;                      /* Current entry in aPage[] */
  110: 
  111:   /* Values to return. */
  112:   char *zName;                    /* Value of 'name' column */
  113:   char *zPath;                    /* Value of 'path' column */
  114:   u32 iPageno;                    /* Value of 'pageno' column */
  115:   char *zPagetype;                /* Value of 'pagetype' column */
  116:   int nCell;                      /* Value of 'ncell' column */
  117:   int nPayload;                   /* Value of 'payload' column */
  118:   int nUnused;                    /* Value of 'unused' column */
  119:   int nMxPayload;                 /* Value of 'mx_payload' column */
  120:   i64 iOffset;                    /* Value of 'pgOffset' column */
  121:   int szPage;                     /* Value of 'pgSize' column */
  122: };
  123: 
  124: struct StatTable {
  125:   sqlite3_vtab base;
  126:   sqlite3 *db;
  127: };
  128: 
  129: #ifndef get2byte
  130: # define get2byte(x)   ((x)[0]<<8 | (x)[1])
  131: #endif
  132: 
  133: /*
  134: ** Connect to or create a statvfs virtual table.
  135: */
  136: static int statConnect(
  137:   sqlite3 *db,
  138:   void *pAux,
  139:   int argc, const char *const*argv,
  140:   sqlite3_vtab **ppVtab,
  141:   char **pzErr
  142: ){
  143:   StatTable *pTab;
  144: 
  145:   pTab = (StatTable *)sqlite3_malloc(sizeof(StatTable));
  146:   memset(pTab, 0, sizeof(StatTable));
  147:   pTab->db = db;
  148: 
  149:   sqlite3_declare_vtab(db, VTAB_SCHEMA);
  150:   *ppVtab = &pTab->base;
  151:   return SQLITE_OK;
  152: }
  153: 
  154: /*
  155: ** Disconnect from or destroy a statvfs virtual table.
  156: */
  157: static int statDisconnect(sqlite3_vtab *pVtab){
  158:   sqlite3_free(pVtab);
  159:   return SQLITE_OK;
  160: }
  161: 
  162: /*
  163: ** There is no "best-index". This virtual table always does a linear
  164: ** scan of the binary VFS log file.
  165: */
  166: static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
  167: 
  168:   /* Records are always returned in ascending order of (name, path). 
  169:   ** If this will satisfy the client, set the orderByConsumed flag so that 
  170:   ** SQLite does not do an external sort.
  171:   */
  172:   if( ( pIdxInfo->nOrderBy==1
  173:      && pIdxInfo->aOrderBy[0].iColumn==0
  174:      && pIdxInfo->aOrderBy[0].desc==0
  175:      ) ||
  176:       ( pIdxInfo->nOrderBy==2
  177:      && pIdxInfo->aOrderBy[0].iColumn==0
  178:      && pIdxInfo->aOrderBy[0].desc==0
  179:      && pIdxInfo->aOrderBy[1].iColumn==1
  180:      && pIdxInfo->aOrderBy[1].desc==0
  181:      )
  182:   ){
  183:     pIdxInfo->orderByConsumed = 1;
  184:   }
  185: 
  186:   pIdxInfo->estimatedCost = 10.0;
  187:   return SQLITE_OK;
  188: }
  189: 
  190: /*
  191: ** Open a new statvfs cursor.
  192: */
  193: static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
  194:   StatTable *pTab = (StatTable *)pVTab;
  195:   StatCursor *pCsr;
  196:   int rc;
  197: 
  198:   pCsr = (StatCursor *)sqlite3_malloc(sizeof(StatCursor));
  199:   memset(pCsr, 0, sizeof(StatCursor));
  200:   pCsr->base.pVtab = pVTab;
  201: 
  202:   rc = sqlite3_prepare_v2(pTab->db, 
  203:       "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
  204:       "  UNION ALL  "
  205:       "SELECT name, rootpage, type FROM sqlite_master WHERE rootpage!=0"
  206:       "  ORDER BY name", -1,
  207:       &pCsr->pStmt, 0
  208:   );
  209:   if( rc!=SQLITE_OK ){
  210:     sqlite3_free(pCsr);
  211:     return rc;
  212:   }
  213: 
  214:   *ppCursor = (sqlite3_vtab_cursor *)pCsr;
  215:   return SQLITE_OK;
  216: }
  217: 
  218: static void statClearPage(StatPage *p){
  219:   int i;
  220:   for(i=0; i<p->nCell; i++){
  221:     sqlite3_free(p->aCell[i].aOvfl);
  222:   }
  223:   sqlite3PagerUnref(p->pPg);
  224:   sqlite3_free(p->aCell);
  225:   sqlite3_free(p->zPath);
  226:   memset(p, 0, sizeof(StatPage));
  227: }
  228: 
  229: static void statResetCsr(StatCursor *pCsr){
  230:   int i;
  231:   sqlite3_reset(pCsr->pStmt);
  232:   for(i=0; i<ArraySize(pCsr->aPage); i++){
  233:     statClearPage(&pCsr->aPage[i]);
  234:   }
  235:   pCsr->iPage = 0;
  236:   sqlite3_free(pCsr->zPath);
  237:   pCsr->zPath = 0;
  238: }
  239: 
  240: /*
  241: ** Close a statvfs cursor.
  242: */
  243: static int statClose(sqlite3_vtab_cursor *pCursor){
  244:   StatCursor *pCsr = (StatCursor *)pCursor;
  245:   statResetCsr(pCsr);
  246:   sqlite3_finalize(pCsr->pStmt);
  247:   sqlite3_free(pCsr);
  248:   return SQLITE_OK;
  249: }
  250: 
  251: static void getLocalPayload(
  252:   int nUsable,                    /* Usable bytes per page */
  253:   u8 flags,                       /* Page flags */
  254:   int nTotal,                     /* Total record (payload) size */
  255:   int *pnLocal                    /* OUT: Bytes stored locally */
  256: ){
  257:   int nLocal;
  258:   int nMinLocal;
  259:   int nMaxLocal;
  260:  
  261:   if( flags==0x0D ){              /* Table leaf node */
  262:     nMinLocal = (nUsable - 12) * 32 / 255 - 23;
  263:     nMaxLocal = nUsable - 35;
  264:   }else{                          /* Index interior and leaf nodes */
  265:     nMinLocal = (nUsable - 12) * 32 / 255 - 23;
  266:     nMaxLocal = (nUsable - 12) * 64 / 255 - 23;
  267:   }
  268: 
  269:   nLocal = nMinLocal + (nTotal - nMinLocal) % (nUsable - 4);
  270:   if( nLocal>nMaxLocal ) nLocal = nMinLocal;
  271:   *pnLocal = nLocal;
  272: }
  273: 
  274: static int statDecodePage(Btree *pBt, StatPage *p){
  275:   int nUnused;
  276:   int iOff;
  277:   int nHdr;
  278:   int isLeaf;
  279:   int szPage;
  280: 
  281:   u8 *aData = sqlite3PagerGetData(p->pPg);
  282:   u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0];
  283: 
  284:   p->flags = aHdr[0];
  285:   p->nCell = get2byte(&aHdr[3]);
  286:   p->nMxPayload = 0;
  287: 
  288:   isLeaf = (p->flags==0x0A || p->flags==0x0D);
  289:   nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100;
  290: 
  291:   nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell;
  292:   nUnused += (int)aHdr[7];
  293:   iOff = get2byte(&aHdr[1]);
  294:   while( iOff ){
  295:     nUnused += get2byte(&aData[iOff+2]);
  296:     iOff = get2byte(&aData[iOff]);
  297:   }
  298:   p->nUnused = nUnused;
  299:   p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]);
  300:   szPage = sqlite3BtreeGetPageSize(pBt);
  301: 
  302:   if( p->nCell ){
  303:     int i;                        /* Used to iterate through cells */
  304:     int nUsable = szPage - sqlite3BtreeGetReserve(pBt);
  305: 
  306:     p->aCell = sqlite3_malloc((p->nCell+1) * sizeof(StatCell));
  307:     memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell));
  308: 
  309:     for(i=0; i<p->nCell; i++){
  310:       StatCell *pCell = &p->aCell[i];
  311: 
  312:       iOff = get2byte(&aData[nHdr+i*2]);
  313:       if( !isLeaf ){
  314:         pCell->iChildPg = sqlite3Get4byte(&aData[iOff]);
  315:         iOff += 4;
  316:       }
  317:       if( p->flags==0x05 ){
  318:         /* A table interior node. nPayload==0. */
  319:       }else{
  320:         u32 nPayload;             /* Bytes of payload total (local+overflow) */
  321:         int nLocal;               /* Bytes of payload stored locally */
  322:         iOff += getVarint32(&aData[iOff], nPayload);
  323:         if( p->flags==0x0D ){
  324:           u64 dummy;
  325:           iOff += sqlite3GetVarint(&aData[iOff], &dummy);
  326:         }
  327:         if( nPayload>p->nMxPayload ) p->nMxPayload = nPayload;
  328:         getLocalPayload(nUsable, p->flags, nPayload, &nLocal);
  329:         pCell->nLocal = nLocal;
  330:         assert( nPayload>=nLocal );
  331:         assert( nLocal<=(nUsable-35) );
  332:         if( nPayload>nLocal ){
  333:           int j;
  334:           int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);
  335:           pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
  336:           pCell->nOvfl = nOvfl;
  337:           pCell->aOvfl = sqlite3_malloc(sizeof(u32)*nOvfl);
  338:           pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
  339:           for(j=1; j<nOvfl; j++){
  340:             int rc;
  341:             u32 iPrev = pCell->aOvfl[j-1];
  342:             DbPage *pPg = 0;
  343:             rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg);
  344:             if( rc!=SQLITE_OK ){
  345:               assert( pPg==0 );
  346:               return rc;
  347:             } 
  348:             pCell->aOvfl[j] = sqlite3Get4byte(sqlite3PagerGetData(pPg));
  349:             sqlite3PagerUnref(pPg);
  350:           }
  351:         }
  352:       }
  353:     }
  354:   }
  355: 
  356:   return SQLITE_OK;
  357: }
  358: 
  359: /*
  360: ** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on
  361: ** the current value of pCsr->iPageno.
  362: */
  363: static void statSizeAndOffset(StatCursor *pCsr){
  364:   StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab;
  365:   Btree *pBt = pTab->db->aDb[0].pBt;
  366:   Pager *pPager = sqlite3BtreePager(pBt);
  367:   sqlite3_file *fd;
  368:   sqlite3_int64 x[2];
  369: 
  370:   /* The default page size and offset */
  371:   pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
  372:   pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
  373: 
  374:   /* If connected to a ZIPVFS backend, override the page size and
  375:   ** offset with actual values obtained from ZIPVFS.
  376:   */
  377:   fd = sqlite3PagerFile(pPager);
  378:   x[0] = pCsr->iPageno;
  379:   if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
  380:     pCsr->iOffset = x[0];
  381:     pCsr->szPage = x[1];
  382:   }
  383: }
  384: 
  385: /*
  386: ** Move a statvfs cursor to the next entry in the file.
  387: */
  388: static int statNext(sqlite3_vtab_cursor *pCursor){
  389:   int rc;
  390:   int nPayload;
  391:   StatCursor *pCsr = (StatCursor *)pCursor;
  392:   StatTable *pTab = (StatTable *)pCursor->pVtab;
  393:   Btree *pBt = pTab->db->aDb[0].pBt;
  394:   Pager *pPager = sqlite3BtreePager(pBt);
  395: 
  396:   sqlite3_free(pCsr->zPath);
  397:   pCsr->zPath = 0;
  398: 
  399:   if( pCsr->aPage[0].pPg==0 ){
  400:     rc = sqlite3_step(pCsr->pStmt);
  401:     if( rc==SQLITE_ROW ){
  402:       int nPage;
  403:       u32 iRoot = sqlite3_column_int64(pCsr->pStmt, 1);
  404:       sqlite3PagerPagecount(pPager, &nPage);
  405:       if( nPage==0 ){
  406:         pCsr->isEof = 1;
  407:         return sqlite3_reset(pCsr->pStmt);
  408:       }
  409:       rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg);
  410:       pCsr->aPage[0].iPgno = iRoot;
  411:       pCsr->aPage[0].iCell = 0;
  412:       pCsr->aPage[0].zPath = sqlite3_mprintf("/");
  413:       pCsr->iPage = 0;
  414:     }else{
  415:       pCsr->isEof = 1;
  416:       return sqlite3_reset(pCsr->pStmt);
  417:     }
  418:   }else{
  419: 
  420:     /* Page p itself has already been visited. */
  421:     StatPage *p = &pCsr->aPage[pCsr->iPage];
  422: 
  423:     while( p->iCell<p->nCell ){
  424:       StatCell *pCell = &p->aCell[p->iCell];
  425:       if( pCell->iOvfl<pCell->nOvfl ){
  426:         int nUsable = sqlite3BtreeGetPageSize(pBt)-sqlite3BtreeGetReserve(pBt);
  427:         pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
  428:         pCsr->iPageno = pCell->aOvfl[pCell->iOvfl];
  429:         pCsr->zPagetype = "overflow";
  430:         pCsr->nCell = 0;
  431:         pCsr->nMxPayload = 0;
  432:         pCsr->zPath = sqlite3_mprintf(
  433:             "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl
  434:         );
  435:         if( pCell->iOvfl<pCell->nOvfl-1 ){
  436:           pCsr->nUnused = 0;
  437:           pCsr->nPayload = nUsable - 4;
  438:         }else{
  439:           pCsr->nPayload = pCell->nLastOvfl;
  440:           pCsr->nUnused = nUsable - 4 - pCsr->nPayload;
  441:         }
  442:         pCell->iOvfl++;
  443:         statSizeAndOffset(pCsr);
  444:         return SQLITE_OK;
  445:       }
  446:       if( p->iRightChildPg ) break;
  447:       p->iCell++;
  448:     }
  449: 
  450:     while( !p->iRightChildPg || p->iCell>p->nCell ){
  451:       statClearPage(p);
  452:       if( pCsr->iPage==0 ) return statNext(pCursor);
  453:       pCsr->iPage--;
  454:       p = &pCsr->aPage[pCsr->iPage];
  455:     }
  456:     pCsr->iPage++;
  457:     assert( p==&pCsr->aPage[pCsr->iPage-1] );
  458: 
  459:     if( p->iCell==p->nCell ){
  460:       p[1].iPgno = p->iRightChildPg;
  461:     }else{
  462:       p[1].iPgno = p->aCell[p->iCell].iChildPg;
  463:     }
  464:     rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg);
  465:     p[1].iCell = 0;
  466:     p[1].zPath = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
  467:     p->iCell++;
  468:   }
  469: 
  470: 
  471:   /* Populate the StatCursor fields with the values to be returned
  472:   ** by the xColumn() and xRowid() methods.
  473:   */
  474:   if( rc==SQLITE_OK ){
  475:     int i;
  476:     StatPage *p = &pCsr->aPage[pCsr->iPage];
  477:     pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
  478:     pCsr->iPageno = p->iPgno;
  479: 
  480:     statDecodePage(pBt, p);
  481:     statSizeAndOffset(pCsr);
  482: 
  483:     switch( p->flags ){
  484:       case 0x05:             /* table internal */
  485:       case 0x02:             /* index internal */
  486:         pCsr->zPagetype = "internal";
  487:         break;
  488:       case 0x0D:             /* table leaf */
  489:       case 0x0A:             /* index leaf */
  490:         pCsr->zPagetype = "leaf";
  491:         break;
  492:       default:
  493:         pCsr->zPagetype = "corrupted";
  494:         break;
  495:     }
  496:     pCsr->nCell = p->nCell;
  497:     pCsr->nUnused = p->nUnused;
  498:     pCsr->nMxPayload = p->nMxPayload;
  499:     pCsr->zPath = sqlite3_mprintf("%s", p->zPath);
  500:     nPayload = 0;
  501:     for(i=0; i<p->nCell; i++){
  502:       nPayload += p->aCell[i].nLocal;
  503:     }
  504:     pCsr->nPayload = nPayload;
  505:   }
  506: 
  507:   return rc;
  508: }
  509: 
  510: static int statEof(sqlite3_vtab_cursor *pCursor){
  511:   StatCursor *pCsr = (StatCursor *)pCursor;
  512:   return pCsr->isEof;
  513: }
  514: 
  515: static int statFilter(
  516:   sqlite3_vtab_cursor *pCursor, 
  517:   int idxNum, const char *idxStr,
  518:   int argc, sqlite3_value **argv
  519: ){
  520:   StatCursor *pCsr = (StatCursor *)pCursor;
  521: 
  522:   statResetCsr(pCsr);
  523:   return statNext(pCursor);
  524: }
  525: 
  526: static int statColumn(
  527:   sqlite3_vtab_cursor *pCursor, 
  528:   sqlite3_context *ctx, 
  529:   int i
  530: ){
  531:   StatCursor *pCsr = (StatCursor *)pCursor;
  532:   switch( i ){
  533:     case 0:            /* name */
  534:       sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_STATIC);
  535:       break;
  536:     case 1:            /* path */
  537:       sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
  538:       break;
  539:     case 2:            /* pageno */
  540:       sqlite3_result_int64(ctx, pCsr->iPageno);
  541:       break;
  542:     case 3:            /* pagetype */
  543:       sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC);
  544:       break;
  545:     case 4:            /* ncell */
  546:       sqlite3_result_int(ctx, pCsr->nCell);
  547:       break;
  548:     case 5:            /* payload */
  549:       sqlite3_result_int(ctx, pCsr->nPayload);
  550:       break;
  551:     case 6:            /* unused */
  552:       sqlite3_result_int(ctx, pCsr->nUnused);
  553:       break;
  554:     case 7:            /* mx_payload */
  555:       sqlite3_result_int(ctx, pCsr->nMxPayload);
  556:       break;
  557:     case 8:            /* pgoffset */
  558:       sqlite3_result_int64(ctx, pCsr->iOffset);
  559:       break;
  560:     case 9:            /* pgsize */
  561:       sqlite3_result_int(ctx, pCsr->szPage);
  562:       break;
  563:   }
  564:   return SQLITE_OK;
  565: }
  566: 
  567: static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
  568:   StatCursor *pCsr = (StatCursor *)pCursor;
  569:   *pRowid = pCsr->iPageno;
  570:   return SQLITE_OK;
  571: }
  572: 
  573: int sqlite3_dbstat_register(sqlite3 *db){
  574:   static sqlite3_module dbstat_module = {
  575:     0,                            /* iVersion */
  576:     statConnect,                  /* xCreate */
  577:     statConnect,                  /* xConnect */
  578:     statBestIndex,                /* xBestIndex */
  579:     statDisconnect,               /* xDisconnect */
  580:     statDisconnect,               /* xDestroy */
  581:     statOpen,                     /* xOpen - open a cursor */
  582:     statClose,                    /* xClose - close a cursor */
  583:     statFilter,                   /* xFilter - configure scan constraints */
  584:     statNext,                     /* xNext - advance a cursor */
  585:     statEof,                      /* xEof - check for end of scan */
  586:     statColumn,                   /* xColumn - read data */
  587:     statRowid,                    /* xRowid - read data */
  588:     0,                            /* xUpdate */
  589:     0,                            /* xBegin */
  590:     0,                            /* xSync */
  591:     0,                            /* xCommit */
  592:     0,                            /* xRollback */
  593:     0,                            /* xFindMethod */
  594:     0,                            /* xRename */
  595:   };
  596:   sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
  597:   return SQLITE_OK;
  598: }
  599: 
  600: #endif
  601: 
  602: #if defined(SQLITE_TEST) || TCLSH==2
  603: #include <tcl.h>
  604: 
  605: static int test_dbstat(
  606:   void *clientData,
  607:   Tcl_Interp *interp,
  608:   int objc,
  609:   Tcl_Obj *CONST objv[]
  610: ){
  611: #ifdef SQLITE_OMIT_VIRTUALTABLE
  612:   Tcl_AppendResult(interp, "dbstat not available because of "
  613:                            "SQLITE_OMIT_VIRTUALTABLE", (void*)0);
  614:   return TCL_ERROR;
  615: #else
  616:   struct SqliteDb { sqlite3 *db; };
  617:   char *zDb;
  618:   Tcl_CmdInfo cmdInfo;
  619: 
  620:   if( objc!=2 ){
  621:     Tcl_WrongNumArgs(interp, 1, objv, "DB");
  622:     return TCL_ERROR;
  623:   }
  624: 
  625:   zDb = Tcl_GetString(objv[1]);
  626:   if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
  627:     sqlite3* db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
  628:     sqlite3_dbstat_register(db);
  629:   }
  630:   return TCL_OK;
  631: #endif
  632: }
  633: 
  634: int SqlitetestStat_Init(Tcl_Interp *interp){
  635:   Tcl_CreateObjCommand(interp, "register_dbstat_vtab", test_dbstat, 0, 0);
  636:   return TCL_OK;
  637: }
  638: #endif /* if defined(SQLITE_TEST) || TCLSH==2 */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>