Index: third_party/sqlite/src/ext/misc/vfsstat.c |
diff --git a/third_party/sqlite/src/ext/misc/vfsstat.c b/third_party/sqlite/src/ext/misc/vfsstat.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..14753d277d6282683137f93b6707603fe53c78b8 |
--- /dev/null |
+++ b/third_party/sqlite/src/ext/misc/vfsstat.c |
@@ -0,0 +1,816 @@ |
+/* |
+** 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; |
+ 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 */ |
+}; |
+ |
+/* |
+** 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, |
+ const char **pzErrMsg, |
+ const struct 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); |
+ vstat_vfs.base.szOsFile = sizeof(VStatFile) + vstat_vfs.pVfs->szOsFile; |
+ rc = sqlite3_vfs_register(&vstat_vfs.base, 1); |
+ if( rc==SQLITE_OK ){ |
+ rc = sqlite3_auto_extension(vstatRegister); |
+ } |
+ if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; |
+ return rc; |
+} |