#include <sqlite3ext.h>
SQLITE_EXTENSION_INIT1
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#define VFSSTAT_MAIN 0
#define VFSSTAT_JOURNAL 1
#define VFSSTAT_WAL 2
#define VFSSTAT_MASTERJRNL 3
#define VFSSTAT_SUBJRNL 4
#define VFSSTAT_TEMPDB 5
#define VFSSTAT_TEMPJRNL 6
#define VFSSTAT_TRANSIENT 7
#define VFSSTAT_ANY 8
#define VFSSTAT_nFile 9
static const char *azFile[] = {
"database", "journal", "wal", "master-journal", "sub-journal",
"temp-database", "temp-journal", "transient-db", "*"
};
#define VFSSTAT_BYTESIN 0
#define VFSSTAT_BYTESOUT 1
#define VFSSTAT_READ 2
#define VFSSTAT_WRITE 3
#define VFSSTAT_SYNC 4
#define VFSSTAT_OPEN 5
#define VFSSTAT_LOCK 6
#define VFSSTAT_ACCESS 0
#define VFSSTAT_DELETE 1
#define VFSSTAT_FULLPATH 2
#define VFSSTAT_RANDOM 3
#define VFSSTAT_SLEEP 4
#define VFSSTAT_CURTIME 5
#define VFSSTAT_nStat 7
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"
};
#define VFSSTAT_MXCNT (VFSSTAT_nStat*VFSSTAT_nFile)
static sqlite3_uint64 aVfsCnt[VFSSTAT_MXCNT];
#define STATCNT(filetype,stat) (aVfsCnt[(filetype)*VFSSTAT_nStat+(stat)])
typedef struct VStatVfs VStatVfs;
typedef struct VStatFile VStatFile;
struct VStatVfs {
sqlite3_vfs base;
sqlite3_vfs *pVfs;
};
struct VStatFile {
sqlite3_file base;
sqlite3_file *pReal;
unsigned char eFiletype;
};
#define REALVFS(p) (((VStatVfs*)(p))->pVfs)
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);
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,
0,
1024,
0,
"vfslog",
0,
vstatOpen,
vstatDelete,
vstatAccess,
vstatFullPathname,
vstatDlOpen,
vstatDlError,
vstatDlSym,
vstatDlClose,
vstatRandomness,
vstatSleep,
vstatCurrentTime,
vstatGetLastError,
vstatCurrentTimeInt64
},
0
};
static const sqlite3_io_methods vstat_io_methods = {
3,
vstatClose,
vstatRead,
vstatWrite,
vstatTruncate,
vstatSync,
vstatFileSize,
vstatLock,
vstatUnlock,
vstatCheckReservedLock,
vstatFileControl,
vstatSectorSize,
vstatDeviceCharacteristics,
vstatShmMap,
vstatShmLock,
vstatShmBarrier,
vstatShmUnmap,
vstatFetch,
vstatUnfetch
};
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
static int vstatSectorSize(sqlite3_file *pFile){
int rc;
VStatFile *p = (VStatFile *)pFile;
rc = p->pReal->pMethods->xSectorSize(p->pReal);
return rc;
}
static int vstatDeviceCharacteristics(sqlite3_file *pFile){
int rc;
VStatFile *p = (VStatFile *)pFile;
rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
return rc;
}
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);
}
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);
}
static void vstatShmBarrier(sqlite3_file *pFile){
VStatFile *p = (VStatFile *)pFile;
p->pReal->pMethods->xShmBarrier(p->pReal);
}
static int vstatShmUnmap(sqlite3_file *pFile, int deleteFlag){
VStatFile *p = (VStatFile *)pFile;
return p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag);
}
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);
}
static int vstatUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
VStatFile *p = (VStatFile *)pFile;
return p->pReal->pMethods->xUnfetch(p->pReal, iOfst, pPage);
}
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;
}
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;
}
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;
}
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);
}
static void *vstatDlOpen(sqlite3_vfs *pVfs, const char *zPath){
return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
}
static void vstatDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
}
static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym);
}
static void vstatDlClose(sqlite3_vfs *pVfs, void *pHandle){
REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
}
static int vstatRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
STATCNT(VFSSTAT_ANY,VFSSTAT_RANDOM)++;
return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
}
static int vstatSleep(sqlite3_vfs *pVfs, int nMicro){
STATCNT(VFSSTAT_ANY,VFSSTAT_SLEEP)++;
return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro);
}
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);
}
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*);
typedef struct VfsStatCursor {
sqlite3_vtab_cursor base;
int i;
} VfsStatCursor;
static int vstattabConnect(
sqlite3 *db,
void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVtab,
char **pzErr
){
sqlite3_vtab *pNew;
int rc;
#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;
}
static int vstattabDisconnect(sqlite3_vtab *pVtab){
sqlite3_free(pVtab);
return SQLITE_OK;
}
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;
}
static int vstattabClose(sqlite3_vtab_cursor *cur){
sqlite3_free(cur);
return SQLITE_OK;
}
static int vstattabNext(sqlite3_vtab_cursor *cur){
((VfsStatCursor*)cur)->i++;
return SQLITE_OK;
}
static int vstattabColumn(
sqlite3_vtab_cursor *cur,
sqlite3_context *ctx,
int i
){
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;
}
static int vstattabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
VfsStatCursor *pCur = (VfsStatCursor*)cur;
*pRowid = pCur->i;
return SQLITE_OK;
}
static int vstattabEof(sqlite3_vtab_cursor *cur){
VfsStatCursor *pCur = (VfsStatCursor*)cur;
return pCur->i >= VFSSTAT_MXCNT;
}
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;
}
static int vstattabBestIndex(
sqlite3_vtab *tab,
sqlite3_index_info *pIdxInfo
){
return SQLITE_OK;
}
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,
0,
vstattabConnect,
vstattabBestIndex,
vstattabDisconnect,
0,
vstattabOpen,
vstattabClose,
vstattabFilter,
vstattabNext,
vstattabEof,
vstattabColumn,
vstattabRowid,
vstattabUpdate,
0,
0,
0,
0,
0,
0,
};
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
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;
}