Enhance the command-line completion extension to return the names of
[sqlite.git] / ext / misc / vfsstat.c
blob14753d277d6282683137f93b6707603fe53c78b8
1 /*
2 ** 2016-05-27
3 **
4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
6 **
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 ******************************************************************************
13 ** This file contains the implementation of an SQLite vfs shim that
14 ** tracks I/O. Access to the accumulated status counts is provided using
15 ** an eponymous virtual table.
17 #include <sqlite3ext.h>
18 SQLITE_EXTENSION_INIT1
21 ** This module contains code for a wrapper VFS that cause stats for
22 ** most VFS calls to be recorded.
24 ** To use this module, first compile it as a loadable extension. See
25 ** https://www.sqlite.org/loadext.html#build for compilations instructions.
27 ** After compliing, load this extension, then open database connections to be
28 ** measured. Query usages status using the vfsstat virtual table:
30 ** SELECT * FROM vfsstat;
32 ** Reset counters using UPDATE statements against vfsstat:
34 ** UPDATE vfsstat SET count=0;
36 ** EXAMPLE SCRIPT:
38 ** .load ./vfsstat
39 ** .open test.db
40 ** DROP TABLE IF EXISTS t1;
41 ** CREATE TABLE t1(x,y);
42 ** INSERT INTO t1 VALUES(123, randomblob(5000));
43 ** CREATE INDEX t1x ON t1(x);
44 ** DROP TABLE t1;
45 ** VACUUM;
46 ** SELECT * FROM vfsstat WHERE count>0;
48 ** LIMITATIONS:
49 **
50 ** This module increments counters without using mutex protection. So if
51 ** two or more threads try to use this module at the same time, race conditions
52 ** may occur which mess up the counts. This is harmless, other than giving
53 ** incorrect statistics.
55 #include <string.h>
56 #include <stdlib.h>
57 #include <assert.h>
60 ** File types
62 #define VFSSTAT_MAIN 0 /* Main database file */
63 #define VFSSTAT_JOURNAL 1 /* Rollback journal */
64 #define VFSSTAT_WAL 2 /* Write-ahead log file */
65 #define VFSSTAT_MASTERJRNL 3 /* Master journal */
66 #define VFSSTAT_SUBJRNL 4 /* Subjournal */
67 #define VFSSTAT_TEMPDB 5 /* TEMP database */
68 #define VFSSTAT_TEMPJRNL 6 /* Journal for TEMP database */
69 #define VFSSTAT_TRANSIENT 7 /* Transient database */
70 #define VFSSTAT_ANY 8 /* Unspecified file type */
71 #define VFSSTAT_nFile 9 /* This many file types */
73 /* Names of the file types. These are allowed values for the
74 ** first column of the vfsstat virtual table.
76 static const char *azFile[] = {
77 "database", "journal", "wal", "master-journal", "sub-journal",
78 "temp-database", "temp-journal", "transient-db", "*"
82 ** Stat types
84 #define VFSSTAT_BYTESIN 0 /* Bytes read in */
85 #define VFSSTAT_BYTESOUT 1 /* Bytes written out */
86 #define VFSSTAT_READ 2 /* Read requests */
87 #define VFSSTAT_WRITE 3 /* Write requests */
88 #define VFSSTAT_SYNC 4 /* Syncs */
89 #define VFSSTAT_OPEN 5 /* File opens */
90 #define VFSSTAT_LOCK 6 /* Lock requests */
91 #define VFSSTAT_ACCESS 0 /* xAccess calls. filetype==ANY only */
92 #define VFSSTAT_DELETE 1 /* xDelete calls. filetype==ANY only */
93 #define VFSSTAT_FULLPATH 2 /* xFullPathname calls. ANY only */
94 #define VFSSTAT_RANDOM 3 /* xRandomness calls. ANY only */
95 #define VFSSTAT_SLEEP 4 /* xSleep calls. ANY only */
96 #define VFSSTAT_CURTIME 5 /* xCurrentTime calls. ANY only */
97 #define VFSSTAT_nStat 7 /* This many stat types */
100 /* Names for the second column of the vfsstat virtual table for all
101 ** cases except when the first column is "*" or VFSSTAT_ANY. */
102 static const char *azStat[] = {
103 "bytes-in", "bytes-out", "read", "write", "sync", "open", "lock",
105 static const char *azStatAny[] = {
106 "access", "delete", "fullpathname", "randomness", "sleep", "currenttimestamp",
107 "not-used"
110 /* Total number of counters */
111 #define VFSSTAT_MXCNT (VFSSTAT_nStat*VFSSTAT_nFile)
114 ** Performance stats are collected in an instance of the following
115 ** global array.
117 static sqlite3_uint64 aVfsCnt[VFSSTAT_MXCNT];
120 ** Access to a specific counter
122 #define STATCNT(filetype,stat) (aVfsCnt[(filetype)*VFSSTAT_nStat+(stat)])
125 ** Forward declaration of objects used by this utility
127 typedef struct VStatVfs VStatVfs;
128 typedef struct VStatFile VStatFile;
130 /* An instance of the VFS */
131 struct VStatVfs {
132 sqlite3_vfs base; /* VFS methods */
133 sqlite3_vfs *pVfs; /* Parent VFS */
136 /* An open file */
137 struct VStatFile {
138 sqlite3_file base; /* IO methods */
139 sqlite3_file *pReal; /* Underlying file handle */
140 unsigned char eFiletype; /* What type of file is this */
143 #define REALVFS(p) (((VStatVfs*)(p))->pVfs)
146 ** Methods for VStatFile
148 static int vstatClose(sqlite3_file*);
149 static int vstatRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
150 static int vstatWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
151 static int vstatTruncate(sqlite3_file*, sqlite3_int64 size);
152 static int vstatSync(sqlite3_file*, int flags);
153 static int vstatFileSize(sqlite3_file*, sqlite3_int64 *pSize);
154 static int vstatLock(sqlite3_file*, int);
155 static int vstatUnlock(sqlite3_file*, int);
156 static int vstatCheckReservedLock(sqlite3_file*, int *pResOut);
157 static int vstatFileControl(sqlite3_file*, int op, void *pArg);
158 static int vstatSectorSize(sqlite3_file*);
159 static int vstatDeviceCharacteristics(sqlite3_file*);
160 static int vstatShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
161 static int vstatShmLock(sqlite3_file*, int offset, int n, int flags);
162 static void vstatShmBarrier(sqlite3_file*);
163 static int vstatShmUnmap(sqlite3_file*, int deleteFlag);
164 static int vstatFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
165 static int vstatUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
168 ** Methods for VStatVfs
170 static int vstatOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
171 static int vstatDelete(sqlite3_vfs*, const char *zName, int syncDir);
172 static int vstatAccess(sqlite3_vfs*, const char *zName, int flags, int *);
173 static int vstatFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
174 static void *vstatDlOpen(sqlite3_vfs*, const char *zFilename);
175 static void vstatDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
176 static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
177 static void vstatDlClose(sqlite3_vfs*, void*);
178 static int vstatRandomness(sqlite3_vfs*, int nByte, char *zOut);
179 static int vstatSleep(sqlite3_vfs*, int microseconds);
180 static int vstatCurrentTime(sqlite3_vfs*, double*);
181 static int vstatGetLastError(sqlite3_vfs*, int, char *);
182 static int vstatCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
184 static VStatVfs vstat_vfs = {
186 2, /* iVersion */
187 0, /* szOsFile (set by register_vstat()) */
188 1024, /* mxPathname */
189 0, /* pNext */
190 "vfslog", /* zName */
191 0, /* pAppData */
192 vstatOpen, /* xOpen */
193 vstatDelete, /* xDelete */
194 vstatAccess, /* xAccess */
195 vstatFullPathname, /* xFullPathname */
196 vstatDlOpen, /* xDlOpen */
197 vstatDlError, /* xDlError */
198 vstatDlSym, /* xDlSym */
199 vstatDlClose, /* xDlClose */
200 vstatRandomness, /* xRandomness */
201 vstatSleep, /* xSleep */
202 vstatCurrentTime, /* xCurrentTime */
203 vstatGetLastError, /* xGetLastError */
204 vstatCurrentTimeInt64 /* xCurrentTimeInt64 */
209 static const sqlite3_io_methods vstat_io_methods = {
210 3, /* iVersion */
211 vstatClose, /* xClose */
212 vstatRead, /* xRead */
213 vstatWrite, /* xWrite */
214 vstatTruncate, /* xTruncate */
215 vstatSync, /* xSync */
216 vstatFileSize, /* xFileSize */
217 vstatLock, /* xLock */
218 vstatUnlock, /* xUnlock */
219 vstatCheckReservedLock, /* xCheckReservedLock */
220 vstatFileControl, /* xFileControl */
221 vstatSectorSize, /* xSectorSize */
222 vstatDeviceCharacteristics, /* xDeviceCharacteristics */
223 vstatShmMap, /* xShmMap */
224 vstatShmLock, /* xShmLock */
225 vstatShmBarrier, /* xShmBarrier */
226 vstatShmUnmap, /* xShmUnmap */
227 vstatFetch, /* xFetch */
228 vstatUnfetch /* xUnfetch */
234 ** Close an vstat-file.
236 static int vstatClose(sqlite3_file *pFile){
237 VStatFile *p = (VStatFile *)pFile;
238 int rc = SQLITE_OK;
240 if( p->pReal->pMethods ){
241 rc = p->pReal->pMethods->xClose(p->pReal);
243 return rc;
248 ** Read data from an vstat-file.
250 static int vstatRead(
251 sqlite3_file *pFile,
252 void *zBuf,
253 int iAmt,
254 sqlite_int64 iOfst
256 int rc;
257 VStatFile *p = (VStatFile *)pFile;
259 rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
260 STATCNT(p->eFiletype,VFSSTAT_READ)++;
261 if( rc==SQLITE_OK ){
262 STATCNT(p->eFiletype,VFSSTAT_BYTESIN) += iAmt;
264 return rc;
268 ** Write data to an vstat-file.
270 static int vstatWrite(
271 sqlite3_file *pFile,
272 const void *z,
273 int iAmt,
274 sqlite_int64 iOfst
276 int rc;
277 VStatFile *p = (VStatFile *)pFile;
279 rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst);
280 STATCNT(p->eFiletype,VFSSTAT_WRITE)++;
281 if( rc==SQLITE_OK ){
282 STATCNT(p->eFiletype,VFSSTAT_BYTESOUT) += iAmt;
284 return rc;
288 ** Truncate an vstat-file.
290 static int vstatTruncate(sqlite3_file *pFile, sqlite_int64 size){
291 int rc;
292 VStatFile *p = (VStatFile *)pFile;
293 rc = p->pReal->pMethods->xTruncate(p->pReal, size);
294 return rc;
298 ** Sync an vstat-file.
300 static int vstatSync(sqlite3_file *pFile, int flags){
301 int rc;
302 VStatFile *p = (VStatFile *)pFile;
303 rc = p->pReal->pMethods->xSync(p->pReal, flags);
304 STATCNT(p->eFiletype,VFSSTAT_SYNC)++;
305 return rc;
309 ** Return the current file-size of an vstat-file.
311 static int vstatFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
312 int rc;
313 VStatFile *p = (VStatFile *)pFile;
314 rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
315 return rc;
319 ** Lock an vstat-file.
321 static int vstatLock(sqlite3_file *pFile, int eLock){
322 int rc;
323 VStatFile *p = (VStatFile *)pFile;
324 rc = p->pReal->pMethods->xLock(p->pReal, eLock);
325 STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
326 return rc;
330 ** Unlock an vstat-file.
332 static int vstatUnlock(sqlite3_file *pFile, int eLock){
333 int rc;
334 VStatFile *p = (VStatFile *)pFile;
335 rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
336 STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
337 return rc;
341 ** Check if another file-handle holds a RESERVED lock on an vstat-file.
343 static int vstatCheckReservedLock(sqlite3_file *pFile, int *pResOut){
344 int rc;
345 VStatFile *p = (VStatFile *)pFile;
346 rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
347 STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
348 return rc;
352 ** File control method. For custom operations on an vstat-file.
354 static int vstatFileControl(sqlite3_file *pFile, int op, void *pArg){
355 VStatFile *p = (VStatFile *)pFile;
356 int rc;
357 rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
358 if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
359 *(char**)pArg = sqlite3_mprintf("vstat/%z", *(char**)pArg);
361 return rc;
365 ** Return the sector-size in bytes for an vstat-file.
367 static int vstatSectorSize(sqlite3_file *pFile){
368 int rc;
369 VStatFile *p = (VStatFile *)pFile;
370 rc = p->pReal->pMethods->xSectorSize(p->pReal);
371 return rc;
375 ** Return the device characteristic flags supported by an vstat-file.
377 static int vstatDeviceCharacteristics(sqlite3_file *pFile){
378 int rc;
379 VStatFile *p = (VStatFile *)pFile;
380 rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
381 return rc;
384 /* Create a shared memory file mapping */
385 static int vstatShmMap(
386 sqlite3_file *pFile,
387 int iPg,
388 int pgsz,
389 int bExtend,
390 void volatile **pp
392 VStatFile *p = (VStatFile *)pFile;
393 return p->pReal->pMethods->xShmMap(p->pReal, iPg, pgsz, bExtend, pp);
396 /* Perform locking on a shared-memory segment */
397 static int vstatShmLock(sqlite3_file *pFile, int offset, int n, int flags){
398 VStatFile *p = (VStatFile *)pFile;
399 return p->pReal->pMethods->xShmLock(p->pReal, offset, n, flags);
402 /* Memory barrier operation on shared memory */
403 static void vstatShmBarrier(sqlite3_file *pFile){
404 VStatFile *p = (VStatFile *)pFile;
405 p->pReal->pMethods->xShmBarrier(p->pReal);
408 /* Unmap a shared memory segment */
409 static int vstatShmUnmap(sqlite3_file *pFile, int deleteFlag){
410 VStatFile *p = (VStatFile *)pFile;
411 return p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag);
414 /* Fetch a page of a memory-mapped file */
415 static int vstatFetch(
416 sqlite3_file *pFile,
417 sqlite3_int64 iOfst,
418 int iAmt,
419 void **pp
421 VStatFile *p = (VStatFile *)pFile;
422 return p->pReal->pMethods->xFetch(p->pReal, iOfst, iAmt, pp);
425 /* Release a memory-mapped page */
426 static int vstatUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
427 VStatFile *p = (VStatFile *)pFile;
428 return p->pReal->pMethods->xUnfetch(p->pReal, iOfst, pPage);
432 ** Open an vstat file handle.
434 static int vstatOpen(
435 sqlite3_vfs *pVfs,
436 const char *zName,
437 sqlite3_file *pFile,
438 int flags,
439 int *pOutFlags
441 int rc;
442 VStatFile *p = (VStatFile*)pFile;
444 p->pReal = (sqlite3_file*)&p[1];
445 rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags);
446 if( flags & SQLITE_OPEN_MAIN_DB ){
447 p->eFiletype = VFSSTAT_MAIN;
448 }else if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
449 p->eFiletype = VFSSTAT_JOURNAL;
450 }else if( flags & SQLITE_OPEN_WAL ){
451 p->eFiletype = VFSSTAT_WAL;
452 }else if( flags & SQLITE_OPEN_MASTER_JOURNAL ){
453 p->eFiletype = VFSSTAT_MASTERJRNL;
454 }else if( flags & SQLITE_OPEN_SUBJOURNAL ){
455 p->eFiletype = VFSSTAT_SUBJRNL;
456 }else if( flags & SQLITE_OPEN_TEMP_DB ){
457 p->eFiletype = VFSSTAT_TEMPDB;
458 }else if( flags & SQLITE_OPEN_TEMP_JOURNAL ){
459 p->eFiletype = VFSSTAT_TEMPJRNL;
460 }else{
461 p->eFiletype = VFSSTAT_TRANSIENT;
463 STATCNT(p->eFiletype,VFSSTAT_OPEN)++;
464 pFile->pMethods = rc ? 0 : &vstat_io_methods;
465 return rc;
469 ** Delete the file located at zPath. If the dirSync argument is true,
470 ** ensure the file-system modifications are synced to disk before
471 ** returning.
473 static int vstatDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
474 int rc;
475 rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync);
476 STATCNT(VFSSTAT_ANY,VFSSTAT_DELETE)++;
477 return rc;
481 ** Test for access permissions. Return true if the requested permission
482 ** is available, or false otherwise.
484 static int vstatAccess(
485 sqlite3_vfs *pVfs,
486 const char *zPath,
487 int flags,
488 int *pResOut
490 int rc;
491 rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut);
492 STATCNT(VFSSTAT_ANY,VFSSTAT_ACCESS)++;
493 return rc;
497 ** Populate buffer zOut with the full canonical pathname corresponding
498 ** to the pathname in zPath. zOut is guaranteed to point to a buffer
499 ** of at least (INST_MAX_PATHNAME+1) bytes.
501 static int vstatFullPathname(
502 sqlite3_vfs *pVfs,
503 const char *zPath,
504 int nOut,
505 char *zOut
507 STATCNT(VFSSTAT_ANY,VFSSTAT_FULLPATH)++;
508 return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
512 ** Open the dynamic library located at zPath and return a handle.
514 static void *vstatDlOpen(sqlite3_vfs *pVfs, const char *zPath){
515 return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
519 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
520 ** utf-8 string describing the most recent error encountered associated
521 ** with dynamic libraries.
523 static void vstatDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
524 REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
528 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
530 static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
531 return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym);
535 ** Close the dynamic library handle pHandle.
537 static void vstatDlClose(sqlite3_vfs *pVfs, void *pHandle){
538 REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
542 ** Populate the buffer pointed to by zBufOut with nByte bytes of
543 ** random data.
545 static int vstatRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
546 STATCNT(VFSSTAT_ANY,VFSSTAT_RANDOM)++;
547 return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
551 ** Sleep for nMicro microseconds. Return the number of microseconds
552 ** actually slept.
554 static int vstatSleep(sqlite3_vfs *pVfs, int nMicro){
555 STATCNT(VFSSTAT_ANY,VFSSTAT_SLEEP)++;
556 return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro);
560 ** Return the current time as a Julian Day number in *pTimeOut.
562 static int vstatCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
563 STATCNT(VFSSTAT_ANY,VFSSTAT_CURTIME)++;
564 return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut);
567 static int vstatGetLastError(sqlite3_vfs *pVfs, int a, char *b){
568 return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b);
570 static int vstatCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
571 STATCNT(VFSSTAT_ANY,VFSSTAT_CURTIME)++;
572 return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p);
576 ** A virtual table for accessing the stats collected by this VFS shim
578 static int vstattabConnect(sqlite3*, void*, int, const char*const*,
579 sqlite3_vtab**,char**);
580 static int vstattabBestIndex(sqlite3_vtab*,sqlite3_index_info*);
581 static int vstattabDisconnect(sqlite3_vtab*);
582 static int vstattabOpen(sqlite3_vtab*, sqlite3_vtab_cursor**);
583 static int vstattabClose(sqlite3_vtab_cursor*);
584 static int vstattabFilter(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
585 int argc, sqlite3_value **argv);
586 static int vstattabNext(sqlite3_vtab_cursor*);
587 static int vstattabEof(sqlite3_vtab_cursor*);
588 static int vstattabColumn(sqlite3_vtab_cursor*,sqlite3_context*,int);
589 static int vstattabRowid(sqlite3_vtab_cursor*,sqlite3_int64*);
590 static int vstattabUpdate(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*);
592 /* A cursor for the vfsstat virtual table */
593 typedef struct VfsStatCursor {
594 sqlite3_vtab_cursor base; /* Base class. Must be first */
595 int i; /* Pointing to this aVfsCnt[] value */
596 } VfsStatCursor;
599 static int vstattabConnect(
600 sqlite3 *db,
601 void *pAux,
602 int argc, const char *const*argv,
603 sqlite3_vtab **ppVtab,
604 char **pzErr
606 sqlite3_vtab *pNew;
607 int rc;
609 /* Column numbers */
610 #define VSTAT_COLUMN_FILE 0
611 #define VSTAT_COLUMN_STAT 1
612 #define VSTAT_COLUMN_COUNT 2
614 rc = sqlite3_declare_vtab(db,"CREATE TABLE x(file,stat,count)");
615 if( rc==SQLITE_OK ){
616 pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
617 if( pNew==0 ) return SQLITE_NOMEM;
618 memset(pNew, 0, sizeof(*pNew));
620 return rc;
624 ** This method is the destructor for vstat table object.
626 static int vstattabDisconnect(sqlite3_vtab *pVtab){
627 sqlite3_free(pVtab);
628 return SQLITE_OK;
632 ** Constructor for a new vstat table cursor object.
634 static int vstattabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
635 VfsStatCursor *pCur;
636 pCur = sqlite3_malloc( sizeof(*pCur) );
637 if( pCur==0 ) return SQLITE_NOMEM;
638 memset(pCur, 0, sizeof(*pCur));
639 *ppCursor = &pCur->base;
640 return SQLITE_OK;
645 ** Destructor for a VfsStatCursor.
647 static int vstattabClose(sqlite3_vtab_cursor *cur){
648 sqlite3_free(cur);
649 return SQLITE_OK;
654 ** Advance a VfsStatCursor to its next row of output.
656 static int vstattabNext(sqlite3_vtab_cursor *cur){
657 ((VfsStatCursor*)cur)->i++;
658 return SQLITE_OK;
662 ** Return values of columns for the row at which the VfsStatCursor
663 ** is currently pointing.
665 static int vstattabColumn(
666 sqlite3_vtab_cursor *cur, /* The cursor */
667 sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
668 int i /* Which column to return */
670 VfsStatCursor *pCur = (VfsStatCursor*)cur;
671 switch( i ){
672 case VSTAT_COLUMN_FILE: {
673 sqlite3_result_text(ctx, azFile[pCur->i/VFSSTAT_nStat], -1, SQLITE_STATIC);
674 break;
676 case VSTAT_COLUMN_STAT: {
677 const char **az;
678 az = (pCur->i/VFSSTAT_nStat)==VFSSTAT_ANY ? azStatAny : azStat;
679 sqlite3_result_text(ctx, az[pCur->i%VFSSTAT_nStat], -1, SQLITE_STATIC);
680 break;
682 case VSTAT_COLUMN_COUNT: {
683 sqlite3_result_int64(ctx, aVfsCnt[pCur->i]);
684 break;
687 return SQLITE_OK;
691 ** Return the rowid for the current row.
693 static int vstattabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
694 VfsStatCursor *pCur = (VfsStatCursor*)cur;
695 *pRowid = pCur->i;
696 return SQLITE_OK;
700 ** Return TRUE if the cursor has been moved off of the last
701 ** row of output.
703 static int vstattabEof(sqlite3_vtab_cursor *cur){
704 VfsStatCursor *pCur = (VfsStatCursor*)cur;
705 return pCur->i >= VFSSTAT_MXCNT;
709 ** Only a full table scan is supported. So xFilter simply rewinds to
710 ** the beginning.
712 static int vstattabFilter(
713 sqlite3_vtab_cursor *pVtabCursor,
714 int idxNum, const char *idxStr,
715 int argc, sqlite3_value **argv
717 VfsStatCursor *pCur = (VfsStatCursor*)pVtabCursor;
718 pCur->i = 0;
719 return SQLITE_OK;
723 ** Only a forwards full table scan is supported. xBestIndex is a no-op.
725 static int vstattabBestIndex(
726 sqlite3_vtab *tab,
727 sqlite3_index_info *pIdxInfo
729 return SQLITE_OK;
733 ** Any VSTAT_COLUMN_COUNT can be changed to a positive integer.
734 ** No deletions or insertions are allowed. No changes to other
735 ** columns are allowed.
737 static int vstattabUpdate(
738 sqlite3_vtab *tab,
739 int argc, sqlite3_value **argv,
740 sqlite3_int64 *pRowid
742 sqlite3_int64 iRowid, x;
743 if( argc==1 ) return SQLITE_ERROR;
744 if( sqlite3_value_type(argv[0])!=SQLITE_INTEGER ) return SQLITE_ERROR;
745 iRowid = sqlite3_value_int64(argv[0]);
746 if( iRowid!=sqlite3_value_int64(argv[1]) ) return SQLITE_ERROR;
747 if( iRowid<0 || iRowid>=VFSSTAT_MXCNT ) return SQLITE_ERROR;
748 if( sqlite3_value_type(argv[VSTAT_COLUMN_COUNT+2])!=SQLITE_INTEGER ){
749 return SQLITE_ERROR;
751 x = sqlite3_value_int64(argv[VSTAT_COLUMN_COUNT+2]);
752 if( x<0 ) return SQLITE_ERROR;
753 aVfsCnt[iRowid] = x;
754 return SQLITE_OK;
757 static sqlite3_module VfsStatModule = {
758 0, /* iVersion */
759 0, /* xCreate */
760 vstattabConnect, /* xConnect */
761 vstattabBestIndex, /* xBestIndex */
762 vstattabDisconnect, /* xDisconnect */
763 0, /* xDestroy */
764 vstattabOpen, /* xOpen - open a cursor */
765 vstattabClose, /* xClose - close a cursor */
766 vstattabFilter, /* xFilter - configure scan constraints */
767 vstattabNext, /* xNext - advance a cursor */
768 vstattabEof, /* xEof - check for end of scan */
769 vstattabColumn, /* xColumn - read data */
770 vstattabRowid, /* xRowid - read data */
771 vstattabUpdate, /* xUpdate */
772 0, /* xBegin */
773 0, /* xSync */
774 0, /* xCommit */
775 0, /* xRollback */
776 0, /* xFindMethod */
777 0, /* xRename */
781 ** This routine is an sqlite3_auto_extension() callback, invoked to register
782 ** the vfsstat virtual table for all new database connections.
784 static int vstatRegister(
785 sqlite3 *db,
786 const char **pzErrMsg,
787 const struct sqlite3_api_routines *pThunk
789 return sqlite3_create_module(db, "vfsstat", &VfsStatModule, 0);
792 #ifdef _WIN32
793 __declspec(dllexport)
794 #endif
796 ** This routine is called when the extension is loaded.
798 ** Register the new VFS. Make arrangement to register the virtual table
799 ** for each new database connection.
801 int sqlite3_vfsstat_init(
802 sqlite3 *db,
803 char **pzErrMsg,
804 const sqlite3_api_routines *pApi
806 int rc = SQLITE_OK;
807 SQLITE_EXTENSION_INIT2(pApi);
808 vstat_vfs.pVfs = sqlite3_vfs_find(0);
809 vstat_vfs.base.szOsFile = sizeof(VStatFile) + vstat_vfs.pVfs->szOsFile;
810 rc = sqlite3_vfs_register(&vstat_vfs.base, 1);
811 if( rc==SQLITE_OK ){
812 rc = sqlite3_auto_extension(vstatRegister);
814 if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
815 return rc;