123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826 |
- /*
- ** 2016-05-27
- **
- ** The author disclaims copyright to this source code. In place of
- ** a legal notice, here is a blessing:
- **
- ** May you do good and not evil.
- ** May you find forgiveness for yourself and forgive others.
- ** May you share freely, never taking more than you give.
- **
- ******************************************************************************
- **
- ** This file contains the implementation of an SQLite vfs shim that
- ** tracks I/O. Access to the accumulated status counts is provided using
- ** an eponymous virtual table.
- */
- #include <sqlite3ext.h>
- SQLITE_EXTENSION_INIT1
- /*
- ** This module contains code for a wrapper VFS that cause stats for
- ** most VFS calls to be recorded.
- **
- ** To use this module, first compile it as a loadable extension. See
- ** https://www.sqlite.org/loadext.html#build for compilations instructions.
- **
- ** After compiling, load this extension, then open database connections to be
- ** measured. Query usages status using the vfsstat virtual table:
- **
- ** SELECT * FROM vfsstat;
- **
- ** Reset counters using UPDATE statements against vfsstat:
- **
- ** UPDATE vfsstat SET count=0;
- **
- ** EXAMPLE SCRIPT:
- **
- ** .load ./vfsstat
- ** .open test.db
- ** DROP TABLE IF EXISTS t1;
- ** CREATE TABLE t1(x,y);
- ** INSERT INTO t1 VALUES(123, randomblob(5000));
- ** CREATE INDEX t1x ON t1(x);
- ** DROP TABLE t1;
- ** VACUUM;
- ** SELECT * FROM vfsstat WHERE count>0;
- **
- ** LIMITATIONS:
- **
- ** This module increments counters without using mutex protection. So if
- ** two or more threads try to use this module at the same time, race conditions
- ** may occur which mess up the counts. This is harmless, other than giving
- ** incorrect statistics.
- */
- #include <string.h>
- #include <stdlib.h>
- #include <assert.h>
- /*
- ** File types
- */
- #define VFSSTAT_MAIN 0 /* Main database file */
- #define VFSSTAT_JOURNAL 1 /* Rollback journal */
- #define VFSSTAT_WAL 2 /* Write-ahead log file */
- #define VFSSTAT_MASTERJRNL 3 /* Master journal */
- #define VFSSTAT_SUBJRNL 4 /* Subjournal */
- #define VFSSTAT_TEMPDB 5 /* TEMP database */
- #define VFSSTAT_TEMPJRNL 6 /* Journal for TEMP database */
- #define VFSSTAT_TRANSIENT 7 /* Transient database */
- #define VFSSTAT_ANY 8 /* Unspecified file type */
- #define VFSSTAT_nFile 9 /* This many file types */
- /* Names of the file types. These are allowed values for the
- ** first column of the vfsstat virtual table.
- */
- static const char *azFile[] = {
- "database", "journal", "wal", "master-journal", "sub-journal",
- "temp-database", "temp-journal", "transient-db", "*"
- };
- /*
- ** Stat types
- */
- #define VFSSTAT_BYTESIN 0 /* Bytes read in */
- #define VFSSTAT_BYTESOUT 1 /* Bytes written out */
- #define VFSSTAT_READ 2 /* Read requests */
- #define VFSSTAT_WRITE 3 /* Write requests */
- #define VFSSTAT_SYNC 4 /* Syncs */
- #define VFSSTAT_OPEN 5 /* File opens */
- #define VFSSTAT_LOCK 6 /* Lock requests */
- #define VFSSTAT_ACCESS 0 /* xAccess calls. filetype==ANY only */
- #define VFSSTAT_DELETE 1 /* xDelete calls. filetype==ANY only */
- #define VFSSTAT_FULLPATH 2 /* xFullPathname calls. ANY only */
- #define VFSSTAT_RANDOM 3 /* xRandomness calls. ANY only */
- #define VFSSTAT_SLEEP 4 /* xSleep calls. ANY only */
- #define VFSSTAT_CURTIME 5 /* xCurrentTime calls. ANY only */
- #define VFSSTAT_nStat 7 /* This many stat types */
- /* Names for the second column of the vfsstat virtual table for all
- ** cases except when the first column is "*" or VFSSTAT_ANY. */
- static const char *azStat[] = {
- "bytes-in", "bytes-out", "read", "write", "sync", "open", "lock",
- };
- static const char *azStatAny[] = {
- "access", "delete", "fullpathname", "randomness", "sleep", "currenttimestamp",
- "not-used"
- };
- /* Total number of counters */
- #define VFSSTAT_MXCNT (VFSSTAT_nStat*VFSSTAT_nFile)
- /*
- ** Performance stats are collected in an instance of the following
- ** global array.
- */
- static sqlite3_uint64 aVfsCnt[VFSSTAT_MXCNT];
- /*
- ** Access to a specific counter
- */
- #define STATCNT(filetype,stat) (aVfsCnt[(filetype)*VFSSTAT_nStat+(stat)])
- /*
- ** Forward declaration of objects used by this utility
- */
- typedef struct VStatVfs VStatVfs;
- typedef struct VStatFile VStatFile;
- /* An instance of the VFS */
- struct VStatVfs {
- sqlite3_vfs base; /* VFS methods */
- sqlite3_vfs *pVfs; /* Parent VFS */
- };
- /* An open file */
- struct VStatFile {
- sqlite3_file base; /* IO methods */
- sqlite3_file *pReal; /* Underlying file handle */
- unsigned char eFiletype; /* What type of file is this */
- };
- #define REALVFS(p) (((VStatVfs*)(p))->pVfs)
- /*
- ** Methods for VStatFile
- */
- static int vstatClose(sqlite3_file*);
- static int vstatRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
- static int vstatWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
- static int vstatTruncate(sqlite3_file*, sqlite3_int64 size);
- static int vstatSync(sqlite3_file*, int flags);
- static int vstatFileSize(sqlite3_file*, sqlite3_int64 *pSize);
- static int vstatLock(sqlite3_file*, int);
- static int vstatUnlock(sqlite3_file*, int);
- static int vstatCheckReservedLock(sqlite3_file*, int *pResOut);
- static int vstatFileControl(sqlite3_file*, int op, void *pArg);
- static int vstatSectorSize(sqlite3_file*);
- static int vstatDeviceCharacteristics(sqlite3_file*);
- static int vstatShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
- static int vstatShmLock(sqlite3_file*, int offset, int n, int flags);
- static void vstatShmBarrier(sqlite3_file*);
- static int vstatShmUnmap(sqlite3_file*, int deleteFlag);
- static int vstatFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
- static int vstatUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
- /*
- ** Methods for VStatVfs
- */
- static int vstatOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
- static int vstatDelete(sqlite3_vfs*, const char *zName, int syncDir);
- static int vstatAccess(sqlite3_vfs*, const char *zName, int flags, int *);
- static int vstatFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
- static void *vstatDlOpen(sqlite3_vfs*, const char *zFilename);
- static void vstatDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
- static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
- static void vstatDlClose(sqlite3_vfs*, void*);
- static int vstatRandomness(sqlite3_vfs*, int nByte, char *zOut);
- static int vstatSleep(sqlite3_vfs*, int microseconds);
- static int vstatCurrentTime(sqlite3_vfs*, double*);
- static int vstatGetLastError(sqlite3_vfs*, int, char *);
- static int vstatCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
- static VStatVfs vstat_vfs = {
- {
- 2, /* iVersion */
- 0, /* szOsFile (set by register_vstat()) */
- 1024, /* mxPathname */
- 0, /* pNext */
- "vfslog", /* zName */
- 0, /* pAppData */
- vstatOpen, /* xOpen */
- vstatDelete, /* xDelete */
- vstatAccess, /* xAccess */
- vstatFullPathname, /* xFullPathname */
- vstatDlOpen, /* xDlOpen */
- vstatDlError, /* xDlError */
- vstatDlSym, /* xDlSym */
- vstatDlClose, /* xDlClose */
- vstatRandomness, /* xRandomness */
- vstatSleep, /* xSleep */
- vstatCurrentTime, /* xCurrentTime */
- vstatGetLastError, /* xGetLastError */
- vstatCurrentTimeInt64 /* xCurrentTimeInt64 */
- },
- 0
- };
- static const sqlite3_io_methods vstat_io_methods = {
- 3, /* iVersion */
- vstatClose, /* xClose */
- vstatRead, /* xRead */
- vstatWrite, /* xWrite */
- vstatTruncate, /* xTruncate */
- vstatSync, /* xSync */
- vstatFileSize, /* xFileSize */
- vstatLock, /* xLock */
- vstatUnlock, /* xUnlock */
- vstatCheckReservedLock, /* xCheckReservedLock */
- vstatFileControl, /* xFileControl */
- vstatSectorSize, /* xSectorSize */
- vstatDeviceCharacteristics, /* xDeviceCharacteristics */
- vstatShmMap, /* xShmMap */
- vstatShmLock, /* xShmLock */
- vstatShmBarrier, /* xShmBarrier */
- vstatShmUnmap, /* xShmUnmap */
- vstatFetch, /* xFetch */
- vstatUnfetch /* xUnfetch */
- };
- /*
- ** Close an vstat-file.
- */
- static int vstatClose(sqlite3_file *pFile){
- VStatFile *p = (VStatFile *)pFile;
- int rc = SQLITE_OK;
- if( p->pReal->pMethods ){
- rc = p->pReal->pMethods->xClose(p->pReal);
- }
- return rc;
- }
- /*
- ** Read data from an vstat-file.
- */
- static int vstatRead(
- sqlite3_file *pFile,
- void *zBuf,
- int iAmt,
- sqlite_int64 iOfst
- ){
- int rc;
- VStatFile *p = (VStatFile *)pFile;
- rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
- STATCNT(p->eFiletype,VFSSTAT_READ)++;
- if( rc==SQLITE_OK ){
- STATCNT(p->eFiletype,VFSSTAT_BYTESIN) += iAmt;
- }
- return rc;
- }
- /*
- ** Write data to an vstat-file.
- */
- static int vstatWrite(
- sqlite3_file *pFile,
- const void *z,
- int iAmt,
- sqlite_int64 iOfst
- ){
- int rc;
- VStatFile *p = (VStatFile *)pFile;
- rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst);
- STATCNT(p->eFiletype,VFSSTAT_WRITE)++;
- if( rc==SQLITE_OK ){
- STATCNT(p->eFiletype,VFSSTAT_BYTESOUT) += iAmt;
- }
- return rc;
- }
- /*
- ** Truncate an vstat-file.
- */
- static int vstatTruncate(sqlite3_file *pFile, sqlite_int64 size){
- int rc;
- VStatFile *p = (VStatFile *)pFile;
- rc = p->pReal->pMethods->xTruncate(p->pReal, size);
- return rc;
- }
- /*
- ** Sync an vstat-file.
- */
- static int vstatSync(sqlite3_file *pFile, int flags){
- int rc;
- VStatFile *p = (VStatFile *)pFile;
- rc = p->pReal->pMethods->xSync(p->pReal, flags);
- STATCNT(p->eFiletype,VFSSTAT_SYNC)++;
- return rc;
- }
- /*
- ** Return the current file-size of an vstat-file.
- */
- static int vstatFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
- int rc;
- VStatFile *p = (VStatFile *)pFile;
- rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
- return rc;
- }
- /*
- ** Lock an vstat-file.
- */
- static int vstatLock(sqlite3_file *pFile, int eLock){
- int rc;
- VStatFile *p = (VStatFile *)pFile;
- rc = p->pReal->pMethods->xLock(p->pReal, eLock);
- STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
- return rc;
- }
- /*
- ** Unlock an vstat-file.
- */
- static int vstatUnlock(sqlite3_file *pFile, int eLock){
- int rc;
- VStatFile *p = (VStatFile *)pFile;
- rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
- STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
- return rc;
- }
- /*
- ** Check if another file-handle holds a RESERVED lock on an vstat-file.
- */
- static int vstatCheckReservedLock(sqlite3_file *pFile, int *pResOut){
- int rc;
- VStatFile *p = (VStatFile *)pFile;
- rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
- STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
- return rc;
- }
- /*
- ** File control method. For custom operations on an vstat-file.
- */
- static int vstatFileControl(sqlite3_file *pFile, int op, void *pArg){
- VStatFile *p = (VStatFile *)pFile;
- int rc;
- rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
- if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
- *(char**)pArg = sqlite3_mprintf("vstat/%z", *(char**)pArg);
- }
- return rc;
- }
- /*
- ** Return the sector-size in bytes for an vstat-file.
- */
- static int vstatSectorSize(sqlite3_file *pFile){
- int rc;
- VStatFile *p = (VStatFile *)pFile;
- rc = p->pReal->pMethods->xSectorSize(p->pReal);
- return rc;
- }
- /*
- ** Return the device characteristic flags supported by an vstat-file.
- */
- static int vstatDeviceCharacteristics(sqlite3_file *pFile){
- int rc;
- VStatFile *p = (VStatFile *)pFile;
- rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
- return rc;
- }
- /* Create a shared memory file mapping */
- static int vstatShmMap(
- sqlite3_file *pFile,
- int iPg,
- int pgsz,
- int bExtend,
- void volatile **pp
- ){
- VStatFile *p = (VStatFile *)pFile;
- return p->pReal->pMethods->xShmMap(p->pReal, iPg, pgsz, bExtend, pp);
- }
- /* Perform locking on a shared-memory segment */
- static int vstatShmLock(sqlite3_file *pFile, int offset, int n, int flags){
- VStatFile *p = (VStatFile *)pFile;
- return p->pReal->pMethods->xShmLock(p->pReal, offset, n, flags);
- }
- /* Memory barrier operation on shared memory */
- static void vstatShmBarrier(sqlite3_file *pFile){
- VStatFile *p = (VStatFile *)pFile;
- p->pReal->pMethods->xShmBarrier(p->pReal);
- }
- /* Unmap a shared memory segment */
- static int vstatShmUnmap(sqlite3_file *pFile, int deleteFlag){
- VStatFile *p = (VStatFile *)pFile;
- return p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag);
- }
- /* Fetch a page of a memory-mapped file */
- static int vstatFetch(
- sqlite3_file *pFile,
- sqlite3_int64 iOfst,
- int iAmt,
- void **pp
- ){
- VStatFile *p = (VStatFile *)pFile;
- return p->pReal->pMethods->xFetch(p->pReal, iOfst, iAmt, pp);
- }
- /* Release a memory-mapped page */
- static int vstatUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
- VStatFile *p = (VStatFile *)pFile;
- return p->pReal->pMethods->xUnfetch(p->pReal, iOfst, pPage);
- }
- /*
- ** Open an vstat file handle.
- */
- static int vstatOpen(
- sqlite3_vfs *pVfs,
- const char *zName,
- sqlite3_file *pFile,
- int flags,
- int *pOutFlags
- ){
- int rc;
- VStatFile *p = (VStatFile*)pFile;
- p->pReal = (sqlite3_file*)&p[1];
- rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags);
- if( flags & SQLITE_OPEN_MAIN_DB ){
- p->eFiletype = VFSSTAT_MAIN;
- }else if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
- p->eFiletype = VFSSTAT_JOURNAL;
- }else if( flags & SQLITE_OPEN_WAL ){
- p->eFiletype = VFSSTAT_WAL;
- }else if( flags & SQLITE_OPEN_MASTER_JOURNAL ){
- p->eFiletype = VFSSTAT_MASTERJRNL;
- }else if( flags & SQLITE_OPEN_SUBJOURNAL ){
- p->eFiletype = VFSSTAT_SUBJRNL;
- }else if( flags & SQLITE_OPEN_TEMP_DB ){
- p->eFiletype = VFSSTAT_TEMPDB;
- }else if( flags & SQLITE_OPEN_TEMP_JOURNAL ){
- p->eFiletype = VFSSTAT_TEMPJRNL;
- }else{
- p->eFiletype = VFSSTAT_TRANSIENT;
- }
- STATCNT(p->eFiletype,VFSSTAT_OPEN)++;
- pFile->pMethods = rc ? 0 : &vstat_io_methods;
- return rc;
- }
- /*
- ** Delete the file located at zPath. If the dirSync argument is true,
- ** ensure the file-system modifications are synced to disk before
- ** returning.
- */
- static int vstatDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
- int rc;
- rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync);
- STATCNT(VFSSTAT_ANY,VFSSTAT_DELETE)++;
- return rc;
- }
- /*
- ** Test for access permissions. Return true if the requested permission
- ** is available, or false otherwise.
- */
- static int vstatAccess(
- sqlite3_vfs *pVfs,
- const char *zPath,
- int flags,
- int *pResOut
- ){
- int rc;
- rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut);
- STATCNT(VFSSTAT_ANY,VFSSTAT_ACCESS)++;
- return rc;
- }
- /*
- ** Populate buffer zOut with the full canonical pathname corresponding
- ** to the pathname in zPath. zOut is guaranteed to point to a buffer
- ** of at least (INST_MAX_PATHNAME+1) bytes.
- */
- static int vstatFullPathname(
- sqlite3_vfs *pVfs,
- const char *zPath,
- int nOut,
- char *zOut
- ){
- STATCNT(VFSSTAT_ANY,VFSSTAT_FULLPATH)++;
- return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
- }
- /*
- ** Open the dynamic library located at zPath and return a handle.
- */
- static void *vstatDlOpen(sqlite3_vfs *pVfs, const char *zPath){
- return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
- }
- /*
- ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
- ** utf-8 string describing the most recent error encountered associated
- ** with dynamic libraries.
- */
- static void vstatDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
- REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
- }
- /*
- ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
- */
- static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
- return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym);
- }
- /*
- ** Close the dynamic library handle pHandle.
- */
- static void vstatDlClose(sqlite3_vfs *pVfs, void *pHandle){
- REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
- }
- /*
- ** Populate the buffer pointed to by zBufOut with nByte bytes of
- ** random data.
- */
- static int vstatRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
- STATCNT(VFSSTAT_ANY,VFSSTAT_RANDOM)++;
- return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
- }
- /*
- ** Sleep for nMicro microseconds. Return the number of microseconds
- ** actually slept.
- */
- static int vstatSleep(sqlite3_vfs *pVfs, int nMicro){
- STATCNT(VFSSTAT_ANY,VFSSTAT_SLEEP)++;
- return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro);
- }
- /*
- ** Return the current time as a Julian Day number in *pTimeOut.
- */
- static int vstatCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
- STATCNT(VFSSTAT_ANY,VFSSTAT_CURTIME)++;
- return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut);
- }
- static int vstatGetLastError(sqlite3_vfs *pVfs, int a, char *b){
- return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b);
- }
- static int vstatCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
- STATCNT(VFSSTAT_ANY,VFSSTAT_CURTIME)++;
- return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p);
- }
- /*
- ** A virtual table for accessing the stats collected by this VFS shim
- */
- static int vstattabConnect(sqlite3*, void*, int, const char*const*,
- sqlite3_vtab**,char**);
- static int vstattabBestIndex(sqlite3_vtab*,sqlite3_index_info*);
- static int vstattabDisconnect(sqlite3_vtab*);
- static int vstattabOpen(sqlite3_vtab*, sqlite3_vtab_cursor**);
- static int vstattabClose(sqlite3_vtab_cursor*);
- static int vstattabFilter(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
- int argc, sqlite3_value **argv);
- static int vstattabNext(sqlite3_vtab_cursor*);
- static int vstattabEof(sqlite3_vtab_cursor*);
- static int vstattabColumn(sqlite3_vtab_cursor*,sqlite3_context*,int);
- static int vstattabRowid(sqlite3_vtab_cursor*,sqlite3_int64*);
- static int vstattabUpdate(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*);
- /* A cursor for the vfsstat virtual table */
- typedef struct VfsStatCursor {
- sqlite3_vtab_cursor base; /* Base class. Must be first */
- int i; /* Pointing to this aVfsCnt[] value */
- } VfsStatCursor;
- static int vstattabConnect(
- sqlite3 *db,
- void *pAux,
- int argc, const char *const*argv,
- sqlite3_vtab **ppVtab,
- char **pzErr
- ){
- sqlite3_vtab *pNew;
- int rc;
- /* Column numbers */
- #define VSTAT_COLUMN_FILE 0
- #define VSTAT_COLUMN_STAT 1
- #define VSTAT_COLUMN_COUNT 2
- rc = sqlite3_declare_vtab(db,"CREATE TABLE x(file,stat,count)");
- if( rc==SQLITE_OK ){
- pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
- if( pNew==0 ) return SQLITE_NOMEM;
- memset(pNew, 0, sizeof(*pNew));
- }
- return rc;
- }
- /*
- ** This method is the destructor for vstat table object.
- */
- static int vstattabDisconnect(sqlite3_vtab *pVtab){
- sqlite3_free(pVtab);
- return SQLITE_OK;
- }
- /*
- ** Constructor for a new vstat table cursor object.
- */
- static int vstattabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
- VfsStatCursor *pCur;
- pCur = sqlite3_malloc( sizeof(*pCur) );
- if( pCur==0 ) return SQLITE_NOMEM;
- memset(pCur, 0, sizeof(*pCur));
- *ppCursor = &pCur->base;
- return SQLITE_OK;
- }
- /*
- ** Destructor for a VfsStatCursor.
- */
- static int vstattabClose(sqlite3_vtab_cursor *cur){
- sqlite3_free(cur);
- return SQLITE_OK;
- }
- /*
- ** Advance a VfsStatCursor to its next row of output.
- */
- static int vstattabNext(sqlite3_vtab_cursor *cur){
- ((VfsStatCursor*)cur)->i++;
- return SQLITE_OK;
- }
- /*
- ** Return values of columns for the row at which the VfsStatCursor
- ** is currently pointing.
- */
- static int vstattabColumn(
- sqlite3_vtab_cursor *cur, /* The cursor */
- sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
- int i /* Which column to return */
- ){
- VfsStatCursor *pCur = (VfsStatCursor*)cur;
- switch( i ){
- case VSTAT_COLUMN_FILE: {
- sqlite3_result_text(ctx, azFile[pCur->i/VFSSTAT_nStat], -1, SQLITE_STATIC);
- break;
- }
- case VSTAT_COLUMN_STAT: {
- const char **az;
- az = (pCur->i/VFSSTAT_nStat)==VFSSTAT_ANY ? azStatAny : azStat;
- sqlite3_result_text(ctx, az[pCur->i%VFSSTAT_nStat], -1, SQLITE_STATIC);
- break;
- }
- case VSTAT_COLUMN_COUNT: {
- sqlite3_result_int64(ctx, aVfsCnt[pCur->i]);
- break;
- }
- }
- return SQLITE_OK;
- }
- /*
- ** Return the rowid for the current row.
- */
- static int vstattabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
- VfsStatCursor *pCur = (VfsStatCursor*)cur;
- *pRowid = pCur->i;
- return SQLITE_OK;
- }
- /*
- ** Return TRUE if the cursor has been moved off of the last
- ** row of output.
- */
- static int vstattabEof(sqlite3_vtab_cursor *cur){
- VfsStatCursor *pCur = (VfsStatCursor*)cur;
- return pCur->i >= VFSSTAT_MXCNT;
- }
- /*
- ** Only a full table scan is supported. So xFilter simply rewinds to
- ** the beginning.
- */
- static int vstattabFilter(
- sqlite3_vtab_cursor *pVtabCursor,
- int idxNum, const char *idxStr,
- int argc, sqlite3_value **argv
- ){
- VfsStatCursor *pCur = (VfsStatCursor*)pVtabCursor;
- pCur->i = 0;
- return SQLITE_OK;
- }
- /*
- ** Only a forwards full table scan is supported. xBestIndex is a no-op.
- */
- static int vstattabBestIndex(
- sqlite3_vtab *tab,
- sqlite3_index_info *pIdxInfo
- ){
- return SQLITE_OK;
- }
- /*
- ** Any VSTAT_COLUMN_COUNT can be changed to a positive integer.
- ** No deletions or insertions are allowed. No changes to other
- ** columns are allowed.
- */
- static int vstattabUpdate(
- sqlite3_vtab *tab,
- int argc, sqlite3_value **argv,
- sqlite3_int64 *pRowid
- ){
- sqlite3_int64 iRowid, x;
- if( argc==1 ) return SQLITE_ERROR;
- if( sqlite3_value_type(argv[0])!=SQLITE_INTEGER ) return SQLITE_ERROR;
- iRowid = sqlite3_value_int64(argv[0]);
- if( iRowid!=sqlite3_value_int64(argv[1]) ) return SQLITE_ERROR;
- if( iRowid<0 || iRowid>=VFSSTAT_MXCNT ) return SQLITE_ERROR;
- if( sqlite3_value_type(argv[VSTAT_COLUMN_COUNT+2])!=SQLITE_INTEGER ){
- return SQLITE_ERROR;
- }
- x = sqlite3_value_int64(argv[VSTAT_COLUMN_COUNT+2]);
- if( x<0 ) return SQLITE_ERROR;
- aVfsCnt[iRowid] = x;
- return SQLITE_OK;
- }
- static sqlite3_module VfsStatModule = {
- 0, /* iVersion */
- 0, /* xCreate */
- vstattabConnect, /* xConnect */
- vstattabBestIndex, /* xBestIndex */
- vstattabDisconnect, /* xDisconnect */
- 0, /* xDestroy */
- vstattabOpen, /* xOpen - open a cursor */
- vstattabClose, /* xClose - close a cursor */
- vstattabFilter, /* xFilter - configure scan constraints */
- vstattabNext, /* xNext - advance a cursor */
- vstattabEof, /* xEof - check for end of scan */
- vstattabColumn, /* xColumn - read data */
- vstattabRowid, /* xRowid - read data */
- vstattabUpdate, /* xUpdate */
- 0, /* xBegin */
- 0, /* xSync */
- 0, /* xCommit */
- 0, /* xRollback */
- 0, /* xFindMethod */
- 0, /* xRename */
- 0, /* xSavepoint */
- 0, /* xRelease */
- 0, /* xRollbackTo */
- 0, /* xShadowName */
- 0 /* xIntegrity */
- };
- /*
- ** This routine is an sqlite3_auto_extension() callback, invoked to register
- ** the vfsstat virtual table for all new database connections.
- */
- static int vstatRegister(
- sqlite3 *db,
- char **pzErrMsg,
- const sqlite3_api_routines *pThunk
- ){
- return sqlite3_create_module(db, "vfsstat", &VfsStatModule, 0);
- }
- #ifdef _WIN32
- __declspec(dllexport)
- #endif
- /*
- ** This routine is called when the extension is loaded.
- **
- ** Register the new VFS. Make arrangement to register the virtual table
- ** for each new database connection.
- */
- int sqlite3_vfsstat_init(
- sqlite3 *db,
- char **pzErrMsg,
- const sqlite3_api_routines *pApi
- ){
- int rc = SQLITE_OK;
- SQLITE_EXTENSION_INIT2(pApi);
- vstat_vfs.pVfs = sqlite3_vfs_find(0);
- if( vstat_vfs.pVfs==0 ) return SQLITE_ERROR;
- vstat_vfs.base.szOsFile = sizeof(VStatFile) + vstat_vfs.pVfs->szOsFile;
- rc = sqlite3_vfs_register(&vstat_vfs.base, 1);
- if( rc==SQLITE_OK ){
- rc = vstatRegister(db, pzErrMsg, pApi);
- if( rc==SQLITE_OK ){
- rc = sqlite3_auto_extension((void(*)(void))vstatRegister);
- }
- }
- if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
- return rc;
- }
|