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 wrapper that
14 ** adds instrumentation to all vfs and file methods. C and Tcl interfaces
15 ** are provided to control the instrumentation.
19 ** This module contains code for a wrapper VFS that causes a log of
20 ** most VFS calls to be written into a nominated file on disk. The log
21 ** is stored in a compressed binary format to reduce the amount of IO
22 ** overhead introduced into the application by logging.
24 ** All calls on sqlite3_file objects except xFileControl() are logged.
25 ** Additionally, calls to the xAccess(), xOpen(), and xDelete()
26 ** methods are logged. The other sqlite3_vfs object methods (xDlXXX,
27 ** xRandomness, xSleep, xCurrentTime, xGetLastError and xCurrentTimeInt64)
30 ** The binary log files are read using a virtual table implementation
31 ** also contained in this file.
33 ** CREATING LOG FILES:
35 ** int sqlite3_vfslog_new(
36 ** const char *zVfs, // Name of new VFS
37 ** const char *zParentVfs, // Name of parent VFS (or NULL)
38 ** const char *zLog // Name of log file to write to
41 ** int sqlite3_vfslog_finalize(const char *zVfs);
43 ** ANNOTATING LOG FILES:
45 ** To write an arbitrary message into a log file:
47 ** int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg);
51 ** Log files are read using the "vfslog" virtual table implementation
52 ** in this file. To register the virtual table with SQLite, use:
54 ** int sqlite3_vfslog_register(sqlite3 *db);
56 ** Then, if the log file is named "vfs.log", the following SQL command:
58 ** CREATE VIRTUAL TABLE v USING vfslog('vfs.log');
60 ** creates a virtual table with 6 columns, as follows:
63 ** event TEXT, // "xOpen", "xRead" etc.
64 ** file TEXT, // Name of file this call applies to
65 ** clicks INTEGER, // Time spent in call
66 ** rc INTEGER, // Return value
67 ** size INTEGER, // Bytes read or written
68 ** offset INTEGER // File offset read or written
84 ** Maximum pathname length supported by the vfslog backend.
86 #define INST_MAX_PATHNAME 512
89 #define OS_CHECKRESERVEDLOCK 2
91 #define OS_CURRENTTIME 4
94 #define OS_FILECONTROL 7
96 #define OS_FULLPATHNAME 9
99 #define OS_RANDOMNESS 13
101 #define OS_SECTORSIZE 15
104 #define OS_TRUNCATE 18
107 #define OS_SHMUNMAP 22
109 #define OS_SHMLOCK 25
110 #define OS_SHMBARRIER 26
111 #define OS_ANNOTATE 28
113 #define OS_NUMEVENTS 29
115 #define VFSLOG_BUFFERSIZE 8192
117 typedef struct VfslogVfs VfslogVfs
;
118 typedef struct VfslogFile VfslogFile
;
121 sqlite3_vfs base
; /* VFS methods */
122 sqlite3_vfs
*pVfs
; /* Parent VFS */
123 int iNextFileId
; /* Next file id */
124 sqlite3_file
*pLog
; /* Log file handle */
125 sqlite3_int64 iOffset
; /* Log file offset of start of write buffer */
126 int nBuf
; /* Number of valid bytes in aBuf[] */
127 char aBuf
[VFSLOG_BUFFERSIZE
]; /* Write buffer */
131 sqlite3_file base
; /* IO methods */
132 sqlite3_file
*pReal
; /* Underlying file handle */
133 sqlite3_vfs
*pVfslog
; /* Associated VsflogVfs object */
134 int iFileId
; /* File id number */
137 #define REALVFS(p) (((VfslogVfs *)(p))->pVfs)
142 ** Method declarations for vfslog_file.
144 static int vfslogClose(sqlite3_file
*);
145 static int vfslogRead(sqlite3_file
*, void*, int iAmt
, sqlite3_int64 iOfst
);
146 static int vfslogWrite(sqlite3_file
*,const void*,int iAmt
, sqlite3_int64 iOfst
);
147 static int vfslogTruncate(sqlite3_file
*, sqlite3_int64 size
);
148 static int vfslogSync(sqlite3_file
*, int flags
);
149 static int vfslogFileSize(sqlite3_file
*, sqlite3_int64
*pSize
);
150 static int vfslogLock(sqlite3_file
*, int);
151 static int vfslogUnlock(sqlite3_file
*, int);
152 static int vfslogCheckReservedLock(sqlite3_file
*, int *pResOut
);
153 static int vfslogFileControl(sqlite3_file
*, int op
, void *pArg
);
154 static int vfslogSectorSize(sqlite3_file
*);
155 static int vfslogDeviceCharacteristics(sqlite3_file
*);
157 static int vfslogShmLock(sqlite3_file
*pFile
, int ofst
, int n
, int flags
);
158 static int vfslogShmMap(sqlite3_file
*pFile
,int,int,int,volatile void **);
159 static void vfslogShmBarrier(sqlite3_file
*);
160 static int vfslogShmUnmap(sqlite3_file
*pFile
, int deleteFlag
);
163 ** Method declarations for vfslog_vfs.
165 static int vfslogOpen(sqlite3_vfs
*, const char *, sqlite3_file
*, int , int *);
166 static int vfslogDelete(sqlite3_vfs
*, const char *zName
, int syncDir
);
167 static int vfslogAccess(sqlite3_vfs
*, const char *zName
, int flags
, int *);
168 static int vfslogFullPathname(sqlite3_vfs
*, const char *zName
, int, char *zOut
);
169 static void *vfslogDlOpen(sqlite3_vfs
*, const char *zFilename
);
170 static void vfslogDlError(sqlite3_vfs
*, int nByte
, char *zErrMsg
);
171 static void (*vfslogDlSym(sqlite3_vfs
*pVfs
, void *p
, const char*zSym
))(void);
172 static void vfslogDlClose(sqlite3_vfs
*, void*);
173 static int vfslogRandomness(sqlite3_vfs
*, int nByte
, char *zOut
);
174 static int vfslogSleep(sqlite3_vfs
*, int microseconds
);
175 static int vfslogCurrentTime(sqlite3_vfs
*, double*);
177 static int vfslogGetLastError(sqlite3_vfs
*, int, char *);
178 static int vfslogCurrentTimeInt64(sqlite3_vfs
*, sqlite3_int64
*);
180 static sqlite3_vfs vfslog_vfs
= {
182 sizeof(VfslogFile
), /* szOsFile */
183 INST_MAX_PATHNAME
, /* mxPathname */
187 vfslogOpen
, /* xOpen */
188 vfslogDelete
, /* xDelete */
189 vfslogAccess
, /* xAccess */
190 vfslogFullPathname
, /* xFullPathname */
191 vfslogDlOpen
, /* xDlOpen */
192 vfslogDlError
, /* xDlError */
193 vfslogDlSym
, /* xDlSym */
194 vfslogDlClose
, /* xDlClose */
195 vfslogRandomness
, /* xRandomness */
196 vfslogSleep
, /* xSleep */
197 vfslogCurrentTime
, /* xCurrentTime */
198 vfslogGetLastError
, /* xGetLastError */
199 vfslogCurrentTimeInt64
/* xCurrentTime */
202 static sqlite3_io_methods vfslog_io_methods
= {
204 vfslogClose
, /* xClose */
205 vfslogRead
, /* xRead */
206 vfslogWrite
, /* xWrite */
207 vfslogTruncate
, /* xTruncate */
208 vfslogSync
, /* xSync */
209 vfslogFileSize
, /* xFileSize */
210 vfslogLock
, /* xLock */
211 vfslogUnlock
, /* xUnlock */
212 vfslogCheckReservedLock
, /* xCheckReservedLock */
213 vfslogFileControl
, /* xFileControl */
214 vfslogSectorSize
, /* xSectorSize */
215 vfslogDeviceCharacteristics
, /* xDeviceCharacteristics */
216 vfslogShmMap
, /* xShmMap */
217 vfslogShmLock
, /* xShmLock */
218 vfslogShmBarrier
, /* xShmBarrier */
219 vfslogShmUnmap
/* xShmUnmap */
222 #if SQLITE_OS_UNIX && !defined(NO_GETTOD)
223 #include <sys/time.h>
224 static sqlite3_uint64
vfslog_time(){
225 struct timeval sTime
;
226 gettimeofday(&sTime
, 0);
227 return sTime
.tv_usec
+ (sqlite3_uint64
)sTime
.tv_sec
* 1000000;
231 static sqlite3_uint64
vfslog_time(){
233 sqlite3_uint64 u64time
= 0;
235 GetSystemTimeAsFileTime(&ft
);
237 u64time
|= ft
.dwHighDateTime
;
239 u64time
|= ft
.dwLowDateTime
;
241 /* ft is 100-nanosecond intervals, we want microseconds */
242 return u64time
/(sqlite3_uint64
)10;
245 static sqlite3_uint64
vfslog_time(){
250 static void vfslog_call(sqlite3_vfs
*, int, int, sqlite3_int64
, int, int, int);
251 static void vfslog_string(sqlite3_vfs
*, const char *);
254 ** Close an vfslog-file.
256 static int vfslogClose(sqlite3_file
*pFile
){
259 VfslogFile
*p
= (VfslogFile
*)pFile
;
262 if( p
->pReal
->pMethods
){
263 rc
= p
->pReal
->pMethods
->xClose(p
->pReal
);
265 t
= vfslog_time() - t
;
266 vfslog_call(p
->pVfslog
, OS_CLOSE
, p
->iFileId
, t
, rc
, 0, 0);
271 ** Read data from an vfslog-file.
273 static int vfslogRead(
281 VfslogFile
*p
= (VfslogFile
*)pFile
;
283 rc
= p
->pReal
->pMethods
->xRead(p
->pReal
, zBuf
, iAmt
, iOfst
);
284 t
= vfslog_time() - t
;
285 vfslog_call(p
->pVfslog
, OS_READ
, p
->iFileId
, t
, rc
, iAmt
, (int)iOfst
);
290 ** Write data to an vfslog-file.
292 static int vfslogWrite(
300 VfslogFile
*p
= (VfslogFile
*)pFile
;
302 rc
= p
->pReal
->pMethods
->xWrite(p
->pReal
, z
, iAmt
, iOfst
);
303 t
= vfslog_time() - t
;
304 vfslog_call(p
->pVfslog
, OS_WRITE
, p
->iFileId
, t
, rc
, iAmt
, (int)iOfst
);
309 ** Truncate an vfslog-file.
311 static int vfslogTruncate(sqlite3_file
*pFile
, sqlite_int64 size
){
314 VfslogFile
*p
= (VfslogFile
*)pFile
;
316 rc
= p
->pReal
->pMethods
->xTruncate(p
->pReal
, size
);
317 t
= vfslog_time() - t
;
318 vfslog_call(p
->pVfslog
, OS_TRUNCATE
, p
->iFileId
, t
, rc
, 0, (int)size
);
323 ** Sync an vfslog-file.
325 static int vfslogSync(sqlite3_file
*pFile
, int flags
){
328 VfslogFile
*p
= (VfslogFile
*)pFile
;
330 rc
= p
->pReal
->pMethods
->xSync(p
->pReal
, flags
);
331 t
= vfslog_time() - t
;
332 vfslog_call(p
->pVfslog
, OS_SYNC
, p
->iFileId
, t
, rc
, flags
, 0);
337 ** Return the current file-size of an vfslog-file.
339 static int vfslogFileSize(sqlite3_file
*pFile
, sqlite_int64
*pSize
){
342 VfslogFile
*p
= (VfslogFile
*)pFile
;
344 rc
= p
->pReal
->pMethods
->xFileSize(p
->pReal
, pSize
);
345 t
= vfslog_time() - t
;
346 vfslog_call(p
->pVfslog
, OS_FILESIZE
, p
->iFileId
, t
, rc
, 0, (int)*pSize
);
351 ** Lock an vfslog-file.
353 static int vfslogLock(sqlite3_file
*pFile
, int eLock
){
356 VfslogFile
*p
= (VfslogFile
*)pFile
;
358 rc
= p
->pReal
->pMethods
->xLock(p
->pReal
, eLock
);
359 t
= vfslog_time() - t
;
360 vfslog_call(p
->pVfslog
, OS_LOCK
, p
->iFileId
, t
, rc
, eLock
, 0);
365 ** Unlock an vfslog-file.
367 static int vfslogUnlock(sqlite3_file
*pFile
, int eLock
){
370 VfslogFile
*p
= (VfslogFile
*)pFile
;
372 rc
= p
->pReal
->pMethods
->xUnlock(p
->pReal
, eLock
);
373 t
= vfslog_time() - t
;
374 vfslog_call(p
->pVfslog
, OS_UNLOCK
, p
->iFileId
, t
, rc
, eLock
, 0);
379 ** Check if another file-handle holds a RESERVED lock on an vfslog-file.
381 static int vfslogCheckReservedLock(sqlite3_file
*pFile
, int *pResOut
){
384 VfslogFile
*p
= (VfslogFile
*)pFile
;
386 rc
= p
->pReal
->pMethods
->xCheckReservedLock(p
->pReal
, pResOut
);
387 t
= vfslog_time() - t
;
388 vfslog_call(p
->pVfslog
, OS_CHECKRESERVEDLOCK
, p
->iFileId
, t
, rc
, *pResOut
, 0);
393 ** File control method. For custom operations on an vfslog-file.
395 static int vfslogFileControl(sqlite3_file
*pFile
, int op
, void *pArg
){
396 VfslogFile
*p
= (VfslogFile
*)pFile
;
397 int rc
= p
->pReal
->pMethods
->xFileControl(p
->pReal
, op
, pArg
);
398 if( op
==SQLITE_FCNTL_VFSNAME
&& rc
==SQLITE_OK
){
399 *(char**)pArg
= sqlite3_mprintf("vfslog/%z", *(char**)pArg
);
405 ** Return the sector-size in bytes for an vfslog-file.
407 static int vfslogSectorSize(sqlite3_file
*pFile
){
410 VfslogFile
*p
= (VfslogFile
*)pFile
;
412 rc
= p
->pReal
->pMethods
->xSectorSize(p
->pReal
);
413 t
= vfslog_time() - t
;
414 vfslog_call(p
->pVfslog
, OS_SECTORSIZE
, p
->iFileId
, t
, rc
, 0, 0);
419 ** Return the device characteristic flags supported by an vfslog-file.
421 static int vfslogDeviceCharacteristics(sqlite3_file
*pFile
){
424 VfslogFile
*p
= (VfslogFile
*)pFile
;
426 rc
= p
->pReal
->pMethods
->xDeviceCharacteristics(p
->pReal
);
427 t
= vfslog_time() - t
;
428 vfslog_call(p
->pVfslog
, OS_DEVCHAR
, p
->iFileId
, t
, rc
, 0, 0);
432 static int vfslogShmLock(sqlite3_file
*pFile
, int ofst
, int n
, int flags
){
435 VfslogFile
*p
= (VfslogFile
*)pFile
;
437 rc
= p
->pReal
->pMethods
->xShmLock(p
->pReal
, ofst
, n
, flags
);
438 t
= vfslog_time() - t
;
439 vfslog_call(p
->pVfslog
, OS_SHMLOCK
, p
->iFileId
, t
, rc
, 0, 0);
442 static int vfslogShmMap(
451 VfslogFile
*p
= (VfslogFile
*)pFile
;
453 rc
= p
->pReal
->pMethods
->xShmMap(p
->pReal
, iRegion
, szRegion
, isWrite
, pp
);
454 t
= vfslog_time() - t
;
455 vfslog_call(p
->pVfslog
, OS_SHMMAP
, p
->iFileId
, t
, rc
, 0, 0);
458 static void vfslogShmBarrier(sqlite3_file
*pFile
){
460 VfslogFile
*p
= (VfslogFile
*)pFile
;
462 p
->pReal
->pMethods
->xShmBarrier(p
->pReal
);
463 t
= vfslog_time() - t
;
464 vfslog_call(p
->pVfslog
, OS_SHMBARRIER
, p
->iFileId
, t
, SQLITE_OK
, 0, 0);
466 static int vfslogShmUnmap(sqlite3_file
*pFile
, int deleteFlag
){
469 VfslogFile
*p
= (VfslogFile
*)pFile
;
471 rc
= p
->pReal
->pMethods
->xShmUnmap(p
->pReal
, deleteFlag
);
472 t
= vfslog_time() - t
;
473 vfslog_call(p
->pVfslog
, OS_SHMUNMAP
, p
->iFileId
, t
, rc
, 0, 0);
479 ** Open an vfslog file handle.
481 static int vfslogOpen(
490 VfslogFile
*p
= (VfslogFile
*)pFile
;
491 VfslogVfs
*pLog
= (VfslogVfs
*)pVfs
;
493 pFile
->pMethods
= &vfslog_io_methods
;
494 p
->pReal
= (sqlite3_file
*)&p
[1];
496 p
->iFileId
= ++pLog
->iNextFileId
;
499 rc
= REALVFS(pVfs
)->xOpen(REALVFS(pVfs
), zName
, p
->pReal
, flags
, pOutFlags
);
500 t
= vfslog_time() - t
;
502 vfslog_call(pVfs
, OS_OPEN
, p
->iFileId
, t
, rc
, 0, 0);
503 vfslog_string(pVfs
, zName
);
508 ** Delete the file located at zPath. If the dirSync argument is true,
509 ** ensure the file-system modifications are synced to disk before
512 static int vfslogDelete(sqlite3_vfs
*pVfs
, const char *zPath
, int dirSync
){
516 rc
= REALVFS(pVfs
)->xDelete(REALVFS(pVfs
), zPath
, dirSync
);
517 t
= vfslog_time() - t
;
518 vfslog_call(pVfs
, OS_DELETE
, 0, t
, rc
, dirSync
, 0);
519 vfslog_string(pVfs
, zPath
);
524 ** Test for access permissions. Return true if the requested permission
525 ** is available, or false otherwise.
527 static int vfslogAccess(
536 rc
= REALVFS(pVfs
)->xAccess(REALVFS(pVfs
), zPath
, flags
, pResOut
);
537 t
= vfslog_time() - t
;
538 vfslog_call(pVfs
, OS_ACCESS
, 0, t
, rc
, flags
, *pResOut
);
539 vfslog_string(pVfs
, zPath
);
544 ** Populate buffer zOut with the full canonical pathname corresponding
545 ** to the pathname in zPath. zOut is guaranteed to point to a buffer
546 ** of at least (INST_MAX_PATHNAME+1) bytes.
548 static int vfslogFullPathname(
554 return REALVFS(pVfs
)->xFullPathname(REALVFS(pVfs
), zPath
, nOut
, zOut
);
558 ** Open the dynamic library located at zPath and return a handle.
560 static void *vfslogDlOpen(sqlite3_vfs
*pVfs
, const char *zPath
){
561 return REALVFS(pVfs
)->xDlOpen(REALVFS(pVfs
), zPath
);
565 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
566 ** utf-8 string describing the most recent error encountered associated
567 ** with dynamic libraries.
569 static void vfslogDlError(sqlite3_vfs
*pVfs
, int nByte
, char *zErrMsg
){
570 REALVFS(pVfs
)->xDlError(REALVFS(pVfs
), nByte
, zErrMsg
);
574 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
576 static void (*vfslogDlSym(sqlite3_vfs
*pVfs
, void *p
, const char *zSym
))(void){
577 return REALVFS(pVfs
)->xDlSym(REALVFS(pVfs
), p
, zSym
);
581 ** Close the dynamic library handle pHandle.
583 static void vfslogDlClose(sqlite3_vfs
*pVfs
, void *pHandle
){
584 REALVFS(pVfs
)->xDlClose(REALVFS(pVfs
), pHandle
);
588 ** Populate the buffer pointed to by zBufOut with nByte bytes of
591 static int vfslogRandomness(sqlite3_vfs
*pVfs
, int nByte
, char *zBufOut
){
592 return REALVFS(pVfs
)->xRandomness(REALVFS(pVfs
), nByte
, zBufOut
);
596 ** Sleep for nMicro microseconds. Return the number of microseconds
599 static int vfslogSleep(sqlite3_vfs
*pVfs
, int nMicro
){
600 return REALVFS(pVfs
)->xSleep(REALVFS(pVfs
), nMicro
);
604 ** Return the current time as a Julian Day number in *pTimeOut.
606 static int vfslogCurrentTime(sqlite3_vfs
*pVfs
, double *pTimeOut
){
607 return REALVFS(pVfs
)->xCurrentTime(REALVFS(pVfs
), pTimeOut
);
610 static int vfslogGetLastError(sqlite3_vfs
*pVfs
, int a
, char *b
){
611 return REALVFS(pVfs
)->xGetLastError(REALVFS(pVfs
), a
, b
);
613 static int vfslogCurrentTimeInt64(sqlite3_vfs
*pVfs
, sqlite3_int64
*p
){
614 return REALVFS(pVfs
)->xCurrentTimeInt64(REALVFS(pVfs
), p
);
617 static void vfslog_flush(VfslogVfs
*p
){
619 extern int sqlite3_io_error_pending
;
620 extern int sqlite3_io_error_persist
;
621 extern int sqlite3_diskfull_pending
;
623 int pending
= sqlite3_io_error_pending
;
624 int persist
= sqlite3_io_error_persist
;
625 int diskfull
= sqlite3_diskfull_pending
;
627 sqlite3_io_error_pending
= 0;
628 sqlite3_io_error_persist
= 0;
629 sqlite3_diskfull_pending
= 0;
633 p
->pLog
->pMethods
->xWrite(p
->pLog
, p
->aBuf
, p
->nBuf
, p
->iOffset
);
634 p
->iOffset
+= p
->nBuf
;
639 sqlite3_io_error_pending
= pending
;
640 sqlite3_io_error_persist
= persist
;
641 sqlite3_diskfull_pending
= diskfull
;
645 static void put32bits(unsigned char *p
, unsigned int v
){
647 p
[1] = (unsigned char)(v
>>16);
648 p
[2] = (unsigned char)(v
>>8);
649 p
[3] = (unsigned char)v
;
652 static void vfslog_call(
656 sqlite3_int64 nClick
,
661 VfslogVfs
*p
= (VfslogVfs
*)pVfs
;
663 if( (24+p
->nBuf
)>sizeof(p
->aBuf
) ){
666 zRec
= (unsigned char *)&p
->aBuf
[p
->nBuf
];
667 put32bits(&zRec
[0], eEvent
);
668 put32bits(&zRec
[4], iFileid
);
669 put32bits(&zRec
[8], (unsigned int)(nClick
&0xffff));
670 put32bits(&zRec
[12], return_code
);
671 put32bits(&zRec
[16], size
);
672 put32bits(&zRec
[20], offset
);
676 static void vfslog_string(sqlite3_vfs
*pVfs
, const char *zStr
){
677 VfslogVfs
*p
= (VfslogVfs
*)pVfs
;
679 int nStr
= zStr
? (int)strlen(zStr
) : 0;
680 if( (4+nStr
+p
->nBuf
)>sizeof(p
->aBuf
) ){
683 zRec
= (unsigned char *)&p
->aBuf
[p
->nBuf
];
684 put32bits(&zRec
[0], nStr
);
686 memcpy(&zRec
[4], zStr
, nStr
);
688 p
->nBuf
+= (4 + nStr
);
691 static void vfslog_finalize(VfslogVfs
*p
){
692 if( p
->pLog
->pMethods
){
694 p
->pLog
->pMethods
->xClose(p
->pLog
);
699 int sqlite3_vfslog_finalize(const char *zVfs
){
701 pVfs
= sqlite3_vfs_find(zVfs
);
702 if( !pVfs
|| pVfs
->xOpen
!=vfslogOpen
){
705 sqlite3_vfs_unregister(pVfs
);
706 vfslog_finalize((VfslogVfs
*)pVfs
);
710 int sqlite3_vfslog_new(
711 const char *zVfs
, /* New VFS name */
712 const char *zParentVfs
, /* Parent VFS name (or NULL) */
713 const char *zLog
/* Log file name */
716 sqlite3_vfs
*pParent
;
723 pParent
= sqlite3_vfs_find(zParentVfs
);
728 nVfs
= (int)strlen(zVfs
);
729 nByte
= sizeof(VfslogVfs
) + pParent
->szOsFile
+ nVfs
+1+pParent
->mxPathname
+1;
730 p
= (VfslogVfs
*)sqlite3_malloc(nByte
);
734 p
->pLog
= (sqlite3_file
*)&p
[1];
735 memcpy(&p
->base
, &vfslog_vfs
, sizeof(sqlite3_vfs
));
736 p
->base
.zName
= &((char *)p
->pLog
)[pParent
->szOsFile
];
737 p
->base
.szOsFile
+= pParent
->szOsFile
;
738 memcpy((char *)p
->base
.zName
, zVfs
, nVfs
);
740 zFile
= (char *)&p
->base
.zName
[nVfs
+1];
741 pParent
->xFullPathname(pParent
, zLog
, pParent
->mxPathname
, zFile
);
743 flags
= SQLITE_OPEN_READWRITE
|SQLITE_OPEN_CREATE
|SQLITE_OPEN_MASTER_JOURNAL
;
744 pParent
->xDelete(pParent
, zFile
, 0);
745 rc
= pParent
->xOpen(pParent
, zFile
, p
->pLog
, flags
, &flags
);
747 memcpy(p
->aBuf
, "sqlite_ostrace1.....", 20);
750 rc
= sqlite3_vfs_register((sqlite3_vfs
*)p
, 1);
758 int sqlite3_vfslog_annotate(const char *zVfs
, const char *zMsg
){
760 pVfs
= sqlite3_vfs_find(zVfs
);
761 if( !pVfs
|| pVfs
->xOpen
!=vfslogOpen
){
764 vfslog_call(pVfs
, OS_ANNOTATE
, 0, 0, 0, 0, 0);
765 vfslog_string(pVfs
, zMsg
);
769 static const char *vfslog_eventname(int eEvent
){
770 const char *zEvent
= 0;
773 case OS_CLOSE
: zEvent
= "xClose"; break;
774 case OS_READ
: zEvent
= "xRead"; break;
775 case OS_WRITE
: zEvent
= "xWrite"; break;
776 case OS_TRUNCATE
: zEvent
= "xTruncate"; break;
777 case OS_SYNC
: zEvent
= "xSync"; break;
778 case OS_FILESIZE
: zEvent
= "xFilesize"; break;
779 case OS_LOCK
: zEvent
= "xLock"; break;
780 case OS_UNLOCK
: zEvent
= "xUnlock"; break;
781 case OS_CHECKRESERVEDLOCK
: zEvent
= "xCheckResLock"; break;
782 case OS_FILECONTROL
: zEvent
= "xFileControl"; break;
783 case OS_SECTORSIZE
: zEvent
= "xSectorSize"; break;
784 case OS_DEVCHAR
: zEvent
= "xDeviceChar"; break;
785 case OS_OPEN
: zEvent
= "xOpen"; break;
786 case OS_DELETE
: zEvent
= "xDelete"; break;
787 case OS_ACCESS
: zEvent
= "xAccess"; break;
788 case OS_FULLPATHNAME
: zEvent
= "xFullPathname"; break;
789 case OS_RANDOMNESS
: zEvent
= "xRandomness"; break;
790 case OS_SLEEP
: zEvent
= "xSleep"; break;
791 case OS_CURRENTTIME
: zEvent
= "xCurrentTime"; break;
793 case OS_SHMUNMAP
: zEvent
= "xShmUnmap"; break;
794 case OS_SHMLOCK
: zEvent
= "xShmLock"; break;
795 case OS_SHMBARRIER
: zEvent
= "xShmBarrier"; break;
796 case OS_SHMMAP
: zEvent
= "xShmMap"; break;
798 case OS_ANNOTATE
: zEvent
= "annotation"; break;
804 typedef struct VfslogVtab VfslogVtab
;
805 typedef struct VfslogCsr VfslogCsr
;
808 ** Virtual table type for the vfslog reader module.
811 sqlite3_vtab base
; /* Base class */
812 sqlite3_file
*pFd
; /* File descriptor open on vfslog file */
813 sqlite3_int64 nByte
; /* Size of file in bytes */
814 char *zFile
; /* File name for pFd */
818 ** Virtual table cursor type for the vfslog reader module.
821 sqlite3_vtab_cursor base
; /* Base class */
822 sqlite3_int64 iRowid
; /* Current rowid. */
823 sqlite3_int64 iOffset
; /* Offset of next record in file */
824 char *zTransient
; /* Transient 'file' string */
825 int nFile
; /* Size of array azFile[] */
826 char **azFile
; /* File strings */
827 unsigned char aBuf
[1024]; /* Current vfs log entry (read from file) */
830 static unsigned int get32bits(unsigned char *p
){
831 return (p
[0]<<24) + (p
[1]<<16) + (p
[2]<<8) + p
[3];
835 ** The argument must point to a buffer containing a nul-terminated string.
836 ** If the string begins with an SQL quote character it is overwritten by
837 ** the dequoted version. Otherwise the buffer is left unmodified.
839 static void dequote(char *z
){
840 char quote
; /* Quote character (if any ) */
842 if( quote
=='[' || quote
=='\'' || quote
=='"' || quote
=='`' ){
843 int iIn
= 1; /* Index of next byte to read from input */
844 int iOut
= 0; /* Index of next byte to write to output */
845 if( quote
=='[' ) quote
= ']';
848 if( z
[iIn
+1]!=quote
) break;
852 z
[iOut
++] = z
[iIn
++];
859 #ifndef SQLITE_OMIT_VIRTUALTABLE
861 ** Connect to or create a vfslog virtual table.
863 static int vlogConnect(
866 int argc
, const char *const*argv
,
867 sqlite3_vtab
**ppVtab
,
870 sqlite3_vfs
*pVfs
; /* VFS used to read log file */
871 int flags
; /* flags passed to pVfs->xOpen() */
878 pVfs
= sqlite3_vfs_find(0);
879 nByte
= sizeof(VfslogVtab
) + pVfs
->szOsFile
+ pVfs
->mxPathname
;
880 p
= sqlite3_malloc(nByte
);
881 if( p
==0 ) return SQLITE_NOMEM
;
884 p
->pFd
= (sqlite3_file
*)&p
[1];
885 p
->zFile
= &((char *)p
->pFd
)[pVfs
->szOsFile
];
887 zFile
= sqlite3_mprintf("%s", argv
[3]);
893 pVfs
->xFullPathname(pVfs
, zFile
, pVfs
->mxPathname
, p
->zFile
);
896 flags
= SQLITE_OPEN_READWRITE
|SQLITE_OPEN_MASTER_JOURNAL
;
897 rc
= pVfs
->xOpen(pVfs
, p
->zFile
, p
->pFd
, flags
, &flags
);
900 p
->pFd
->pMethods
->xFileSize(p
->pFd
, &p
->nByte
);
901 sqlite3_declare_vtab(db
,
902 "CREATE TABLE xxx(event, file, click, rc, size, offset)"
913 ** There is no "best-index". This virtual table always does a linear
914 ** scan of the binary VFS log file.
916 static int vlogBestIndex(sqlite3_vtab
*tab
, sqlite3_index_info
*pIdxInfo
){
917 pIdxInfo
->estimatedCost
= 10.0;
922 ** Disconnect from or destroy a vfslog virtual table.
924 static int vlogDisconnect(sqlite3_vtab
*pVtab
){
925 VfslogVtab
*p
= (VfslogVtab
*)pVtab
;
926 if( p
->pFd
->pMethods
){
927 p
->pFd
->pMethods
->xClose(p
->pFd
);
928 p
->pFd
->pMethods
= 0;
935 ** Open a new vfslog cursor.
937 static int vlogOpen(sqlite3_vtab
*pVTab
, sqlite3_vtab_cursor
**ppCursor
){
938 VfslogCsr
*pCsr
; /* Newly allocated cursor object */
940 pCsr
= sqlite3_malloc(sizeof(VfslogCsr
));
941 if( !pCsr
) return SQLITE_NOMEM
;
942 memset(pCsr
, 0, sizeof(VfslogCsr
));
943 *ppCursor
= &pCsr
->base
;
948 ** Close a vfslog cursor.
950 static int vlogClose(sqlite3_vtab_cursor
*pCursor
){
951 VfslogCsr
*p
= (VfslogCsr
*)pCursor
;
953 for(i
=0; i
<p
->nFile
; i
++){
954 sqlite3_free(p
->azFile
[i
]);
956 sqlite3_free(p
->azFile
);
957 sqlite3_free(p
->zTransient
);
963 ** Move a vfslog cursor to the next entry in the file.
965 static int vlogNext(sqlite3_vtab_cursor
*pCursor
){
966 VfslogCsr
*pCsr
= (VfslogCsr
*)pCursor
;
967 VfslogVtab
*p
= (VfslogVtab
*)pCursor
->pVtab
;
971 sqlite3_free(pCsr
->zTransient
);
972 pCsr
->zTransient
= 0;
975 if( pCsr
->iOffset
+nRead
<=p
->nByte
){
977 rc
= p
->pFd
->pMethods
->xRead(p
->pFd
, pCsr
->aBuf
, nRead
, pCsr
->iOffset
);
979 eEvent
= get32bits(pCsr
->aBuf
);
981 && (eEvent
==OS_OPEN
|| eEvent
==OS_DELETE
|| eEvent
==OS_ACCESS
)
984 rc
= p
->pFd
->pMethods
->xRead(p
->pFd
, buf
, 4, pCsr
->iOffset
+nRead
);
987 int nStr
= get32bits((unsigned char *)buf
);
988 char *zStr
= sqlite3_malloc(nStr
+1);
989 rc
= p
->pFd
->pMethods
->xRead(p
->pFd
, zStr
, nStr
, pCsr
->iOffset
+nRead
);
993 if( eEvent
==OS_OPEN
){
994 int iFileid
= get32bits(&pCsr
->aBuf
[4]);
995 if( iFileid
>=pCsr
->nFile
){
996 int nNew
= sizeof(pCsr
->azFile
[0])*(iFileid
+1);
997 pCsr
->azFile
= (char **)sqlite3_realloc(pCsr
->azFile
, nNew
);
998 nNew
-= sizeof(pCsr
->azFile
[0])*pCsr
->nFile
;
999 memset(&pCsr
->azFile
[pCsr
->nFile
], 0, nNew
);
1000 pCsr
->nFile
= iFileid
+1;
1002 sqlite3_free(pCsr
->azFile
[iFileid
]);
1003 pCsr
->azFile
[iFileid
] = zStr
;
1005 pCsr
->zTransient
= zStr
;
1012 pCsr
->iOffset
+= nRead
;
1016 static int vlogEof(sqlite3_vtab_cursor
*pCursor
){
1017 VfslogCsr
*pCsr
= (VfslogCsr
*)pCursor
;
1018 VfslogVtab
*p
= (VfslogVtab
*)pCursor
->pVtab
;
1019 return (pCsr
->iOffset
>=p
->nByte
);
1022 static int vlogFilter(
1023 sqlite3_vtab_cursor
*pCursor
,
1024 int idxNum
, const char *idxStr
,
1025 int argc
, sqlite3_value
**argv
1027 VfslogCsr
*pCsr
= (VfslogCsr
*)pCursor
;
1030 return vlogNext(pCursor
);
1033 static int vlogColumn(
1034 sqlite3_vtab_cursor
*pCursor
,
1035 sqlite3_context
*ctx
,
1039 VfslogCsr
*pCsr
= (VfslogCsr
*)pCursor
;
1042 val
= get32bits(&pCsr
->aBuf
[4*i
]);
1046 sqlite3_result_text(ctx
, vfslog_eventname(val
), -1, SQLITE_STATIC
);
1050 char *zStr
= pCsr
->zTransient
;
1051 if( val
!=0 && val
<(unsigned)pCsr
->nFile
){
1052 zStr
= pCsr
->azFile
[val
];
1054 sqlite3_result_text(ctx
, zStr
, -1, SQLITE_TRANSIENT
);
1058 sqlite3_result_int(ctx
, val
);
1065 static int vlogRowid(sqlite3_vtab_cursor
*pCursor
, sqlite_int64
*pRowid
){
1066 VfslogCsr
*pCsr
= (VfslogCsr
*)pCursor
;
1067 *pRowid
= pCsr
->iRowid
;
1071 int sqlite3_vfslog_register(sqlite3
*db
){
1072 static sqlite3_module vfslog_module
= {
1074 vlogConnect
, /* xCreate */
1075 vlogConnect
, /* xConnect */
1076 vlogBestIndex
, /* xBestIndex */
1077 vlogDisconnect
, /* xDisconnect */
1078 vlogDisconnect
, /* xDestroy */
1079 vlogOpen
, /* xOpen - open a cursor */
1080 vlogClose
, /* xClose - close a cursor */
1081 vlogFilter
, /* xFilter - configure scan constraints */
1082 vlogNext
, /* xNext - advance a cursor */
1083 vlogEof
, /* xEof - check for end of scan */
1084 vlogColumn
, /* xColumn - read data */
1085 vlogRowid
, /* xRowid - read data */
1091 0, /* xFindMethod */
1095 sqlite3_create_module(db
, "vfslog", &vfslog_module
, 0);
1098 #endif /* SQLITE_OMIT_VIRTUALTABLE */
1100 /**************************************************************************
1101 ***************************************************************************
1102 ** Tcl interface starts here.
1105 #if defined(SQLITE_TEST) || defined(TCLSH)
1107 #if defined(INCLUDE_SQLITE_TCL_H)
1108 # include "sqlite_tcl.h"
1111 # ifndef SQLITE_TCLAPI
1112 # define SQLITE_TCLAPI
1116 static int SQLITE_TCLAPI
test_vfslog(
1120 Tcl_Obj
*CONST objv
[]
1122 struct SqliteDb
{ sqlite3
*db
; };
1124 Tcl_CmdInfo cmdInfo
;
1125 int rc
= SQLITE_ERROR
;
1127 static const char *strs
[] = { "annotate", "finalize", "new", "register", 0 };
1128 enum VL_enum
{ VL_ANNOTATE
, VL_FINALIZE
, VL_NEW
, VL_REGISTER
};
1132 Tcl_WrongNumArgs(interp
, 1, objv
, "SUB-COMMAND ...");
1135 if( Tcl_GetIndexFromObj(interp
, objv
[1], strs
, "sub-command", 0, &iSub
) ){
1139 switch( (enum VL_enum
)iSub
){
1144 Tcl_WrongNumArgs(interp
, 3, objv
, "VFS");
1147 zVfs
= Tcl_GetString(objv
[2]);
1148 zMsg
= Tcl_GetString(objv
[3]);
1149 rc
= sqlite3_vfslog_annotate(zVfs
, zMsg
);
1150 if( rc
!=SQLITE_OK
){
1151 Tcl_AppendResult(interp
, "failed", 0);
1159 Tcl_WrongNumArgs(interp
, 2, objv
, "VFS");
1162 zVfs
= Tcl_GetString(objv
[2]);
1163 rc
= sqlite3_vfslog_finalize(zVfs
);
1164 if( rc
!=SQLITE_OK
){
1165 Tcl_AppendResult(interp
, "failed", 0);
1176 Tcl_WrongNumArgs(interp
, 2, objv
, "VFS PARENT LOGFILE");
1179 zVfs
= Tcl_GetString(objv
[2]);
1180 zParent
= Tcl_GetString(objv
[3]);
1181 zLog
= Tcl_GetString(objv
[4]);
1182 if( *zParent
=='\0' ) zParent
= 0;
1183 rc
= sqlite3_vfslog_new(zVfs
, zParent
, zLog
);
1184 if( rc
!=SQLITE_OK
){
1185 Tcl_AppendResult(interp
, "failed", 0);
1194 Tcl_WrongNumArgs(interp
, 2, objv
, "DB");
1197 #ifdef SQLITE_OMIT_VIRTUALTABLE
1198 Tcl_AppendResult(interp
, "vfslog not available because of "
1199 "SQLITE_OMIT_VIRTUALTABLE", (void*)0);
1202 zDb
= Tcl_GetString(objv
[2]);
1203 if( Tcl_GetCommandInfo(interp
, zDb
, &cmdInfo
) ){
1204 db
= ((struct SqliteDb
*)cmdInfo
.objClientData
)->db
;
1205 rc
= sqlite3_vfslog_register(db
);
1207 if( rc
!=SQLITE_OK
){
1208 Tcl_AppendResult(interp
, "bad sqlite3 handle: ", zDb
, (void*)0);
1219 int SqlitetestOsinst_Init(Tcl_Interp
*interp
){
1220 Tcl_CreateObjCommand(interp
, "vfslog", test_vfslog
, 0, 0);
1224 #endif /* SQLITE_TEST */