Annotation of embedaddon/sqlite3/src/test_stat.c, revision 1.1.1.1

1.1       misho       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>