4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
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;
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);
46 ** SELECT * FROM vfsstat WHERE count>0;
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.
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", "*"
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",
110 /* Total number of counters */
111 #define VFSSTAT_MXCNT (VFSSTAT_nStat*VFSSTAT_nFile)
114 ** Performance stats are collected in an instance of the following
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 */
132 sqlite3_vfs base
; /* VFS methods */
133 sqlite3_vfs
*pVfs
; /* Parent VFS */
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
= {
187 0, /* szOsFile (set by register_vstat()) */
188 1024, /* mxPathname */
190 "vfslog", /* zName */
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
= {
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
;
240 if( p
->pReal
->pMethods
){
241 rc
= p
->pReal
->pMethods
->xClose(p
->pReal
);
248 ** Read data from an vstat-file.
250 static int vstatRead(
257 VStatFile
*p
= (VStatFile
*)pFile
;
259 rc
= p
->pReal
->pMethods
->xRead(p
->pReal
, zBuf
, iAmt
, iOfst
);
260 STATCNT(p
->eFiletype
,VFSSTAT_READ
)++;
262 STATCNT(p
->eFiletype
,VFSSTAT_BYTESIN
) += iAmt
;
268 ** Write data to an vstat-file.
270 static int vstatWrite(
277 VStatFile
*p
= (VStatFile
*)pFile
;
279 rc
= p
->pReal
->pMethods
->xWrite(p
->pReal
, z
, iAmt
, iOfst
);
280 STATCNT(p
->eFiletype
,VFSSTAT_WRITE
)++;
282 STATCNT(p
->eFiletype
,VFSSTAT_BYTESOUT
) += iAmt
;
288 ** Truncate an vstat-file.
290 static int vstatTruncate(sqlite3_file
*pFile
, sqlite_int64 size
){
292 VStatFile
*p
= (VStatFile
*)pFile
;
293 rc
= p
->pReal
->pMethods
->xTruncate(p
->pReal
, size
);
298 ** Sync an vstat-file.
300 static int vstatSync(sqlite3_file
*pFile
, int flags
){
302 VStatFile
*p
= (VStatFile
*)pFile
;
303 rc
= p
->pReal
->pMethods
->xSync(p
->pReal
, flags
);
304 STATCNT(p
->eFiletype
,VFSSTAT_SYNC
)++;
309 ** Return the current file-size of an vstat-file.
311 static int vstatFileSize(sqlite3_file
*pFile
, sqlite_int64
*pSize
){
313 VStatFile
*p
= (VStatFile
*)pFile
;
314 rc
= p
->pReal
->pMethods
->xFileSize(p
->pReal
, pSize
);
319 ** Lock an vstat-file.
321 static int vstatLock(sqlite3_file
*pFile
, int eLock
){
323 VStatFile
*p
= (VStatFile
*)pFile
;
324 rc
= p
->pReal
->pMethods
->xLock(p
->pReal
, eLock
);
325 STATCNT(p
->eFiletype
,VFSSTAT_LOCK
)++;
330 ** Unlock an vstat-file.
332 static int vstatUnlock(sqlite3_file
*pFile
, int eLock
){
334 VStatFile
*p
= (VStatFile
*)pFile
;
335 rc
= p
->pReal
->pMethods
->xUnlock(p
->pReal
, eLock
);
336 STATCNT(p
->eFiletype
,VFSSTAT_LOCK
)++;
341 ** Check if another file-handle holds a RESERVED lock on an vstat-file.
343 static int vstatCheckReservedLock(sqlite3_file
*pFile
, int *pResOut
){
345 VStatFile
*p
= (VStatFile
*)pFile
;
346 rc
= p
->pReal
->pMethods
->xCheckReservedLock(p
->pReal
, pResOut
);
347 STATCNT(p
->eFiletype
,VFSSTAT_LOCK
)++;
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
;
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
);
365 ** Return the sector-size in bytes for an vstat-file.
367 static int vstatSectorSize(sqlite3_file
*pFile
){
369 VStatFile
*p
= (VStatFile
*)pFile
;
370 rc
= p
->pReal
->pMethods
->xSectorSize(p
->pReal
);
375 ** Return the device characteristic flags supported by an vstat-file.
377 static int vstatDeviceCharacteristics(sqlite3_file
*pFile
){
379 VStatFile
*p
= (VStatFile
*)pFile
;
380 rc
= p
->pReal
->pMethods
->xDeviceCharacteristics(p
->pReal
);
384 /* Create a shared memory file mapping */
385 static int vstatShmMap(
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(
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(
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
;
461 p
->eFiletype
= VFSSTAT_TRANSIENT
;
463 STATCNT(p
->eFiletype
,VFSSTAT_OPEN
)++;
464 pFile
->pMethods
= rc
? 0 : &vstat_io_methods
;
469 ** Delete the file located at zPath. If the dirSync argument is true,
470 ** ensure the file-system modifications are synced to disk before
473 static int vstatDelete(sqlite3_vfs
*pVfs
, const char *zPath
, int dirSync
){
475 rc
= REALVFS(pVfs
)->xDelete(REALVFS(pVfs
), zPath
, dirSync
);
476 STATCNT(VFSSTAT_ANY
,VFSSTAT_DELETE
)++;
481 ** Test for access permissions. Return true if the requested permission
482 ** is available, or false otherwise.
484 static int vstatAccess(
491 rc
= REALVFS(pVfs
)->xAccess(REALVFS(pVfs
), zPath
, flags
, pResOut
);
492 STATCNT(VFSSTAT_ANY
,VFSSTAT_ACCESS
)++;
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(
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
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
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 */
599 static int vstattabConnect(
602 int argc
, const char *const*argv
,
603 sqlite3_vtab
**ppVtab
,
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)");
616 pNew
= *ppVtab
= sqlite3_malloc( sizeof(*pNew
) );
617 if( pNew
==0 ) return SQLITE_NOMEM
;
618 memset(pNew
, 0, sizeof(*pNew
));
624 ** This method is the destructor for vstat table object.
626 static int vstattabDisconnect(sqlite3_vtab
*pVtab
){
632 ** Constructor for a new vstat table cursor object.
634 static int vstattabOpen(sqlite3_vtab
*p
, sqlite3_vtab_cursor
**ppCursor
){
636 pCur
= sqlite3_malloc( sizeof(*pCur
) );
637 if( pCur
==0 ) return SQLITE_NOMEM
;
638 memset(pCur
, 0, sizeof(*pCur
));
639 *ppCursor
= &pCur
->base
;
645 ** Destructor for a VfsStatCursor.
647 static int vstattabClose(sqlite3_vtab_cursor
*cur
){
654 ** Advance a VfsStatCursor to its next row of output.
656 static int vstattabNext(sqlite3_vtab_cursor
*cur
){
657 ((VfsStatCursor
*)cur
)->i
++;
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
;
672 case VSTAT_COLUMN_FILE
: {
673 sqlite3_result_text(ctx
, azFile
[pCur
->i
/VFSSTAT_nStat
], -1, SQLITE_STATIC
);
676 case VSTAT_COLUMN_STAT
: {
678 az
= (pCur
->i
/VFSSTAT_nStat
)==VFSSTAT_ANY
? azStatAny
: azStat
;
679 sqlite3_result_text(ctx
, az
[pCur
->i
%VFSSTAT_nStat
], -1, SQLITE_STATIC
);
682 case VSTAT_COLUMN_COUNT
: {
683 sqlite3_result_int64(ctx
, aVfsCnt
[pCur
->i
]);
691 ** Return the rowid for the current row.
693 static int vstattabRowid(sqlite3_vtab_cursor
*cur
, sqlite_int64
*pRowid
){
694 VfsStatCursor
*pCur
= (VfsStatCursor
*)cur
;
700 ** Return TRUE if the cursor has been moved off of the last
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
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
;
723 ** Only a forwards full table scan is supported. xBestIndex is a no-op.
725 static int vstattabBestIndex(
727 sqlite3_index_info
*pIdxInfo
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(
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
){
751 x
= sqlite3_value_int64(argv
[VSTAT_COLUMN_COUNT
+2]);
752 if( x
<0 ) return SQLITE_ERROR
;
757 static sqlite3_module VfsStatModule
= {
760 vstattabConnect
, /* xConnect */
761 vstattabBestIndex
, /* xBestIndex */
762 vstattabDisconnect
, /* xDisconnect */
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 */
786 ** This routine is an sqlite3_auto_extension() callback, invoked to register
787 ** the vfsstat virtual table for all new database connections.
789 static int vstatRegister(
792 const sqlite3_api_routines
*pThunk
794 return sqlite3_create_module(db
, "vfsstat", &VfsStatModule
, 0);
798 __declspec(dllexport
)
801 ** This routine is called when the extension is loaded.
803 ** Register the new VFS. Make arrangement to register the virtual table
804 ** for each new database connection.
806 int sqlite3_vfsstat_init(
809 const sqlite3_api_routines
*pApi
812 SQLITE_EXTENSION_INIT2(pApi
);
813 vstat_vfs
.pVfs
= sqlite3_vfs_find(0);
814 if( vstat_vfs
.pVfs
==0 ) return SQLITE_ERROR
;
815 vstat_vfs
.base
.szOsFile
= sizeof(VStatFile
) + vstat_vfs
.pVfs
->szOsFile
;
816 rc
= sqlite3_vfs_register(&vstat_vfs
.base
, 1);
818 rc
= vstatRegister(db
, pzErrMsg
, pApi
);
820 rc
= sqlite3_auto_extension((void(*)(void))vstatRegister
);
823 if( rc
==SQLITE_OK
) rc
= SQLITE_OK_LOAD_PERMANENTLY
;