2016-05-28 14:53:48 +00:00
/*
* * 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 compliing , 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 ;
2016-06-01 05:02:05 +00:00
p - > pReal - > pMethods - > xShmBarrier ( p - > pReal ) ;
2016-05-28 14:53:48 +00:00
}
/* 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 */
2023-10-06 12:51:05 +00:00
0 , /* xSavepoint */
0 , /* xRelease */
0 , /* xRollbackTo */
0 , /* xShadowName */
0 /* xIntegrity */
2016-05-28 14:53:48 +00:00
} ;
/*
* * 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 ,
2019-02-12 12:25:34 +00:00
char * * pzErrMsg ,
const sqlite3_api_routines * pThunk
2016-05-28 14:53:48 +00:00
) {
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 ) ;
2016-05-28 17:45:15 +00:00
vstat_vfs . pVfs = sqlite3_vfs_find ( 0 ) ;
2021-06-15 15:15:40 +00:00
if ( vstat_vfs . pVfs = = 0 ) return SQLITE_ERROR ;
2016-06-01 05:02:05 +00:00
vstat_vfs . base . szOsFile = sizeof ( VStatFile ) + vstat_vfs . pVfs - > szOsFile ;
2016-05-28 17:45:15 +00:00
rc = sqlite3_vfs_register ( & vstat_vfs . base , 1 ) ;
2016-05-28 14:53:48 +00:00
if ( rc = = SQLITE_OK ) {
2019-02-12 12:25:34 +00:00
rc = vstatRegister ( db , pzErrMsg , pApi ) ;
if ( rc = = SQLITE_OK ) {
2020-05-25 12:49:58 +00:00
rc = sqlite3_auto_extension ( ( void ( * ) ( void ) ) vstatRegister ) ;
2019-02-12 12:25:34 +00:00
}
2016-05-28 14:53:48 +00:00
}
2016-05-28 17:23:08 +00:00
if ( rc = = SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY ;
2016-05-28 14:53:48 +00:00
return rc ;
}