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 for
14 ** unix that generates per-database log files of all disk activity.
18 ** This module contains code for a wrapper VFS that causes a log of
19 ** most VFS calls to be written into a file on disk.
21 ** Each database connection creates a separate log file in the same
22 ** directory as the original database and named after the original
23 ** database. A unique suffix is added to avoid name collisions.
24 ** Separate log files are used so that concurrent processes do not
25 ** try to write log operations to the same file at the same instant,
26 ** resulting in overwritten or comingled log text.
28 ** Each individual log file records operations by a single database
29 ** connection on both the original database and its associated rollback
32 ** The log files are in the comma-separated-value (CSV) format. The
33 ** log files can be imported into an SQLite database using the ".import"
34 ** command of the SQLite command-line shell for analysis.
36 ** One technique for using this module is to append the text of this
37 ** module to the end of a standard "sqlite3.c" amalgamation file then
38 ** add the following compile-time options:
40 ** -DSQLITE_EXTRA_INIT=sqlite3_register_vfslog
41 ** -DSQLITE_USE_FCNTL_TRACE
43 ** The first compile-time option causes the sqlite3_register_vfslog()
44 ** function, defined below, to be invoked when SQLite is initialized.
45 ** That causes this custom VFS to become the default VFS for all
46 ** subsequent connections. The SQLITE_USE_FCNTL_TRACE option causes
47 ** the SQLite core to issue extra sqlite3_file_control() operations
48 ** with SQLITE_FCNTL_TRACE to give some indication of what is going
61 ** Forward declaration of objects used by this utility
63 typedef struct VLogLog VLogLog
;
64 typedef struct VLogVfs VLogVfs
;
65 typedef struct VLogFile VLogFile
;
67 /* There is a pair (an array of size 2) of the following objects for
68 ** each database file being logged. The first contains the filename
69 ** and is used to log I/O with the main database. The second has
70 ** a NULL filename and is used to log I/O for the journal. Both
71 ** out pointers are the same.
74 VLogLog
*pNext
; /* Next in a list of all active logs */
75 VLogLog
**ppPrev
; /* Pointer to this in the list */
76 int nRef
; /* Number of references to this object */
77 int nFilename
; /* Length of zFilename in bytes */
78 char *zFilename
; /* Name of database file. NULL for journal */
79 FILE *out
; /* Write information here */
83 sqlite3_vfs base
; /* VFS methods */
84 sqlite3_vfs
*pVfs
; /* Parent VFS */
88 sqlite3_file base
; /* IO methods */
89 sqlite3_file
*pReal
; /* Underlying file handle */
90 VLogLog
*pLog
; /* The log file for this file */
93 #define REALVFS(p) (((VLogVfs*)(p))->pVfs)
96 ** Methods for VLogFile
98 static int vlogClose(sqlite3_file
*);
99 static int vlogRead(sqlite3_file
*, void*, int iAmt
, sqlite3_int64 iOfst
);
100 static int vlogWrite(sqlite3_file
*,const void*,int iAmt
, sqlite3_int64 iOfst
);
101 static int vlogTruncate(sqlite3_file
*, sqlite3_int64 size
);
102 static int vlogSync(sqlite3_file
*, int flags
);
103 static int vlogFileSize(sqlite3_file
*, sqlite3_int64
*pSize
);
104 static int vlogLock(sqlite3_file
*, int);
105 static int vlogUnlock(sqlite3_file
*, int);
106 static int vlogCheckReservedLock(sqlite3_file
*, int *pResOut
);
107 static int vlogFileControl(sqlite3_file
*, int op
, void *pArg
);
108 static int vlogSectorSize(sqlite3_file
*);
109 static int vlogDeviceCharacteristics(sqlite3_file
*);
112 ** Methods for VLogVfs
114 static int vlogOpen(sqlite3_vfs
*, const char *, sqlite3_file
*, int , int *);
115 static int vlogDelete(sqlite3_vfs
*, const char *zName
, int syncDir
);
116 static int vlogAccess(sqlite3_vfs
*, const char *zName
, int flags
, int *);
117 static int vlogFullPathname(sqlite3_vfs
*, const char *zName
, int, char *zOut
);
118 static void *vlogDlOpen(sqlite3_vfs
*, const char *zFilename
);
119 static void vlogDlError(sqlite3_vfs
*, int nByte
, char *zErrMsg
);
120 static void (*vlogDlSym(sqlite3_vfs
*pVfs
, void *p
, const char*zSym
))(void);
121 static void vlogDlClose(sqlite3_vfs
*, void*);
122 static int vlogRandomness(sqlite3_vfs
*, int nByte
, char *zOut
);
123 static int vlogSleep(sqlite3_vfs
*, int microseconds
);
124 static int vlogCurrentTime(sqlite3_vfs
*, double*);
125 static int vlogGetLastError(sqlite3_vfs
*, int, char *);
126 static int vlogCurrentTimeInt64(sqlite3_vfs
*, sqlite3_int64
*);
128 static VLogVfs vlog_vfs
= {
131 0, /* szOsFile (set by register_vlog()) */
132 1024, /* mxPathname */
134 "vfslog", /* zName */
136 vlogOpen
, /* xOpen */
137 vlogDelete
, /* xDelete */
138 vlogAccess
, /* xAccess */
139 vlogFullPathname
, /* xFullPathname */
140 vlogDlOpen
, /* xDlOpen */
141 vlogDlError
, /* xDlError */
142 vlogDlSym
, /* xDlSym */
143 vlogDlClose
, /* xDlClose */
144 vlogRandomness
, /* xRandomness */
145 vlogSleep
, /* xSleep */
146 vlogCurrentTime
, /* xCurrentTime */
147 vlogGetLastError
, /* xGetLastError */
148 vlogCurrentTimeInt64
/* xCurrentTimeInt64 */
153 static sqlite3_io_methods vlog_io_methods
= {
155 vlogClose
, /* xClose */
156 vlogRead
, /* xRead */
157 vlogWrite
, /* xWrite */
158 vlogTruncate
, /* xTruncate */
159 vlogSync
, /* xSync */
160 vlogFileSize
, /* xFileSize */
161 vlogLock
, /* xLock */
162 vlogUnlock
, /* xUnlock */
163 vlogCheckReservedLock
, /* xCheckReservedLock */
164 vlogFileControl
, /* xFileControl */
165 vlogSectorSize
, /* xSectorSize */
166 vlogDeviceCharacteristics
, /* xDeviceCharacteristics */
173 #if SQLITE_OS_UNIX && !defined(NO_GETTOD)
174 #include <sys/time.h>
175 static sqlite3_uint64
vlog_time(){
176 struct timeval sTime
;
177 gettimeofday(&sTime
, 0);
178 return sTime
.tv_usec
+ (sqlite3_uint64
)sTime
.tv_sec
* 1000000;
183 static sqlite3_uint64
vlog_time(){
185 sqlite3_uint64 u64time
= 0;
187 GetSystemTimeAsFileTime(&ft
);
189 u64time
|= ft
.dwHighDateTime
;
191 u64time
|= ft
.dwLowDateTime
;
193 /* ft is 100-nanosecond intervals, we want microseconds */
194 return u64time
/(sqlite3_uint64
)10;
197 static sqlite3_uint64
vlog_time(){
204 ** Write a message to the log file
206 static void vlogLogPrint(
207 VLogLog
*pLog
, /* The log file to write into */
208 sqlite3_int64 tStart
, /* Start time of system call */
209 sqlite3_int64 tElapse
, /* Elapse time of system call */
210 const char *zOp
, /* Type of system call */
211 sqlite3_int64 iArg1
, /* First argument */
212 sqlite3_int64 iArg2
, /* Second argument */
213 const char *zArg3
, /* Third argument */
214 int iRes
/* Result */
216 char z1
[40], z2
[40], z3
[2000];
217 if( pLog
==0 ) return;
219 sqlite3_snprintf(sizeof(z1
), z1
, "%lld", iArg1
);
224 sqlite3_snprintf(sizeof(z2
), z2
, "%lld", iArg2
);
229 sqlite3_snprintf(sizeof(z3
), z3
, "\"%.*w\"", sizeof(z3
)-4, zArg3
);
233 fprintf(pLog
->out
,"%lld,%lld,%s,%d,%s,%s,%s,%d\n",
234 tStart
, tElapse
, zOp
, pLog
->zFilename
==0, z1
, z2
, z3
, iRes
);
238 ** List of all active log connections. Protected by the master mutex.
240 static VLogLog
*allLogs
= 0;
243 ** Close a VLogLog object
245 static void vlogLogClose(VLogLog
*p
){
247 sqlite3_mutex
*pMutex
;
249 if( p
->nRef
>0 || p
->zFilename
==0 ) return;
250 pMutex
= sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER
);
251 sqlite3_mutex_enter(pMutex
);
252 *p
->ppPrev
= p
->pNext
;
253 if( p
->pNext
) p
->pNext
->ppPrev
= p
->ppPrev
;
254 sqlite3_mutex_leave(pMutex
);
261 ** Open a VLogLog object on the given file
263 static VLogLog
*vlogLogOpen(const char *zFilename
){
264 int nName
= (int)strlen(zFilename
);
266 sqlite3_mutex
*pMutex
;
267 VLogLog
*pLog
, *pTemp
;
268 sqlite3_int64 tNow
= 0;
269 if( nName
>4 && strcmp(zFilename
+nName
-4,"-wal")==0 ){
270 return 0; /* Do not log wal files */
272 if( nName
>8 && strcmp(zFilename
+nName
-8,"-journal")==0 ){
276 && sqlite3_strglob("-mj??????9??", zFilename
+nName
-12)==0 ){
277 return 0; /* Do not log master journal files */
279 pTemp
= sqlite3_malloc( sizeof(*pLog
)*2 + nName
+ 60 );
280 if( pTemp
==0 ) return 0;
281 pMutex
= sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER
);
282 sqlite3_mutex_enter(pMutex
);
283 for(pLog
=allLogs
; pLog
; pLog
=pLog
->pNext
){
284 if( pLog
->nFilename
==nName
&& !memcmp(pLog
->zFilename
, zFilename
, nName
) ){
291 memset(pLog
, 0, sizeof(*pLog
)*2);
292 pLog
->zFilename
= (char*)&pLog
[2];
294 sqlite3_snprintf(nName
+60, pLog
->zFilename
, "%.*s-debuglog-%lld",
295 nName
, zFilename
, tNow
);
296 pLog
->out
= fopen(pLog
->zFilename
, "a");
298 sqlite3_mutex_leave(pMutex
);
302 pLog
->nFilename
= nName
;
303 pLog
[1].out
= pLog
[0].out
;
304 pLog
->ppPrev
= &allLogs
;
305 if( allLogs
) allLogs
->ppPrev
= &pLog
->pNext
;
306 pLog
->pNext
= allLogs
;
309 sqlite3_mutex_leave(pMutex
);
316 gethostname(zHost
, sizeof(zHost
)-1);
317 zHost
[sizeof(zHost
)-1] = 0;
318 vlogLogPrint(pLog
, tNow
, 0, "IDENT", getpid(), -1, zHost
, 0);
321 if( pLog
&& isJournal
) pLog
++;
328 ** Close an vlog-file.
330 static int vlogClose(sqlite3_file
*pFile
){
331 sqlite3_uint64 tStart
, tElapse
;
333 VLogFile
*p
= (VLogFile
*)pFile
;
335 tStart
= vlog_time();
336 if( p
->pReal
->pMethods
){
337 rc
= p
->pReal
->pMethods
->xClose(p
->pReal
);
339 tElapse
= vlog_time() - tStart
;
340 vlogLogPrint(p
->pLog
, tStart
, tElapse
, "CLOSE", -1, -1, 0, rc
);
341 vlogLogClose(p
->pLog
);
346 ** Compute signature for a block of content.
348 ** For blocks of 16 or fewer bytes, the signature is just a hex dump of
351 ** For blocks of more than 16 bytes, the signature is a hex dump of the
352 ** first 8 bytes followed by a 64-bit has of the entire block.
354 static void vlogSignature(unsigned char *p
, int n
, char *zCksum
){
355 unsigned int s0
= 0, s1
= 0;
359 for(i
=0; i
<n
; i
++) sqlite3_snprintf(3, zCksum
+i
*2, "%02x", p
[i
]);
361 pI
= (unsigned int*)p
;
362 for(i
=0; i
<n
-7; i
+=8){
367 for(i
=0; i
<8; i
++) sqlite3_snprintf(3, zCksum
+i
*2, "%02x", p
[i
]);
368 sqlite3_snprintf(18, zCksum
+i
*2, "-%08x%08x", s0
, s1
);
373 ** Convert a big-endian 32-bit integer into a native integer
375 static int bigToNative(const unsigned char *x
){
376 return (x
[0]<<24) + (x
[1]<<16) + (x
[2]<<8) + x
[3];
380 ** Read data from an vlog-file.
389 sqlite3_uint64 tStart
, tElapse
;
390 VLogFile
*p
= (VLogFile
*)pFile
;
393 tStart
= vlog_time();
394 rc
= p
->pReal
->pMethods
->xRead(p
->pReal
, zBuf
, iAmt
, iOfst
);
395 tElapse
= vlog_time() - tStart
;
397 vlogSignature(zBuf
, iAmt
, zSig
);
401 vlogLogPrint(p
->pLog
, tStart
, tElapse
, "READ", iAmt
, iOfst
, zSig
, rc
);
404 && p
->pLog
->zFilename
408 unsigned char *x
= ((unsigned char*)zBuf
)+(24-iOfst
);
409 unsigned iCtr
, nFree
= -1;
412 iCtr
= bigToNative(x
);
413 if( iOfst
+iAmt
>=40 ){
415 sqlite3_snprintf(sizeof(zStr
), zStr
, "%d", bigToNative(x
+8));
416 nFree
= bigToNative(x
+12);
418 vlogLogPrint(p
->pLog
, tStart
, 0, "CHNGCTR-READ", iCtr
, nFree
, zFree
, 0);
424 ** Write data to an vlog-file.
426 static int vlogWrite(
433 sqlite3_uint64 tStart
, tElapse
;
434 VLogFile
*p
= (VLogFile
*)pFile
;
437 tStart
= vlog_time();
438 vlogSignature((unsigned char*)z
, iAmt
, zSig
);
439 rc
= p
->pReal
->pMethods
->xWrite(p
->pReal
, z
, iAmt
, iOfst
);
440 tElapse
= vlog_time() - tStart
;
441 vlogLogPrint(p
->pLog
, tStart
, tElapse
, "WRITE", iAmt
, iOfst
, zSig
, rc
);
444 && p
->pLog
->zFilename
448 unsigned char *x
= ((unsigned char*)z
)+(24-iOfst
);
449 unsigned iCtr
, nFree
= -1;
452 iCtr
= bigToNative(x
);
453 if( iOfst
+iAmt
>=40 ){
455 sqlite3_snprintf(sizeof(zStr
), zStr
, "%d", bigToNative(x
+8));
456 nFree
= bigToNative(x
+12);
458 vlogLogPrint(p
->pLog
, tStart
, 0, "CHNGCTR-WRITE", iCtr
, nFree
, zFree
, 0);
464 ** Truncate an vlog-file.
466 static int vlogTruncate(sqlite3_file
*pFile
, sqlite_int64 size
){
468 sqlite3_uint64 tStart
, tElapse
;
469 VLogFile
*p
= (VLogFile
*)pFile
;
470 tStart
= vlog_time();
471 rc
= p
->pReal
->pMethods
->xTruncate(p
->pReal
, size
);
472 tElapse
= vlog_time() - tStart
;
473 vlogLogPrint(p
->pLog
, tStart
, tElapse
, "TRUNCATE", size
, -1, 0, rc
);
478 ** Sync an vlog-file.
480 static int vlogSync(sqlite3_file
*pFile
, int flags
){
482 sqlite3_uint64 tStart
, tElapse
;
483 VLogFile
*p
= (VLogFile
*)pFile
;
484 tStart
= vlog_time();
485 rc
= p
->pReal
->pMethods
->xSync(p
->pReal
, flags
);
486 tElapse
= vlog_time() - tStart
;
487 vlogLogPrint(p
->pLog
, tStart
, tElapse
, "SYNC", flags
, -1, 0, rc
);
492 ** Return the current file-size of an vlog-file.
494 static int vlogFileSize(sqlite3_file
*pFile
, sqlite_int64
*pSize
){
496 sqlite3_uint64 tStart
, tElapse
;
497 VLogFile
*p
= (VLogFile
*)pFile
;
498 tStart
= vlog_time();
499 rc
= p
->pReal
->pMethods
->xFileSize(p
->pReal
, pSize
);
500 tElapse
= vlog_time() - tStart
;
501 vlogLogPrint(p
->pLog
, tStart
, tElapse
, "FILESIZE", *pSize
, -1, 0, rc
);
506 ** Lock an vlog-file.
508 static int vlogLock(sqlite3_file
*pFile
, int eLock
){
510 sqlite3_uint64 tStart
, tElapse
;
511 VLogFile
*p
= (VLogFile
*)pFile
;
512 tStart
= vlog_time();
513 rc
= p
->pReal
->pMethods
->xLock(p
->pReal
, eLock
);
514 tElapse
= vlog_time() - tStart
;
515 vlogLogPrint(p
->pLog
, tStart
, tElapse
, "LOCK", eLock
, -1, 0, rc
);
520 ** Unlock an vlog-file.
522 static int vlogUnlock(sqlite3_file
*pFile
, int eLock
){
524 sqlite3_uint64 tStart
;
525 VLogFile
*p
= (VLogFile
*)pFile
;
526 tStart
= vlog_time();
527 vlogLogPrint(p
->pLog
, tStart
, 0, "UNLOCK", eLock
, -1, 0, 0);
528 rc
= p
->pReal
->pMethods
->xUnlock(p
->pReal
, eLock
);
533 ** Check if another file-handle holds a RESERVED lock on an vlog-file.
535 static int vlogCheckReservedLock(sqlite3_file
*pFile
, int *pResOut
){
537 sqlite3_uint64 tStart
, tElapse
;
538 VLogFile
*p
= (VLogFile
*)pFile
;
539 tStart
= vlog_time();
540 rc
= p
->pReal
->pMethods
->xCheckReservedLock(p
->pReal
, pResOut
);
541 tElapse
= vlog_time() - tStart
;
542 vlogLogPrint(p
->pLog
, tStart
, tElapse
, "CHECKRESERVEDLOCK",
543 *pResOut
, -1, "", rc
);
548 ** File control method. For custom operations on an vlog-file.
550 static int vlogFileControl(sqlite3_file
*pFile
, int op
, void *pArg
){
551 VLogFile
*p
= (VLogFile
*)pFile
;
552 sqlite3_uint64 tStart
, tElapse
;
554 tStart
= vlog_time();
555 rc
= p
->pReal
->pMethods
->xFileControl(p
->pReal
, op
, pArg
);
556 if( op
==SQLITE_FCNTL_VFSNAME
&& rc
==SQLITE_OK
){
557 *(char**)pArg
= sqlite3_mprintf("vlog/%z", *(char**)pArg
);
559 tElapse
= vlog_time() - tStart
;
560 if( op
==SQLITE_FCNTL_TRACE
){
561 vlogLogPrint(p
->pLog
, tStart
, tElapse
, "TRACE", op
, -1, pArg
, rc
);
562 }else if( op
==SQLITE_FCNTL_PRAGMA
){
563 const char **azArg
= (const char **)pArg
;
564 vlogLogPrint(p
->pLog
, tStart
, tElapse
, "FILECONTROL", op
, -1, azArg
[1], rc
);
565 }else if( op
==SQLITE_FCNTL_SIZE_HINT
){
566 sqlite3_int64 sz
= *(sqlite3_int64
*)pArg
;
567 vlogLogPrint(p
->pLog
, tStart
, tElapse
, "FILECONTROL", op
, sz
, 0, rc
);
569 vlogLogPrint(p
->pLog
, tStart
, tElapse
, "FILECONTROL", op
, -1, 0, rc
);
575 ** Return the sector-size in bytes for an vlog-file.
577 static int vlogSectorSize(sqlite3_file
*pFile
){
579 sqlite3_uint64 tStart
, tElapse
;
580 VLogFile
*p
= (VLogFile
*)pFile
;
581 tStart
= vlog_time();
582 rc
= p
->pReal
->pMethods
->xSectorSize(p
->pReal
);
583 tElapse
= vlog_time() - tStart
;
584 vlogLogPrint(p
->pLog
, tStart
, tElapse
, "SECTORSIZE", -1, -1, 0, rc
);
589 ** Return the device characteristic flags supported by an vlog-file.
591 static int vlogDeviceCharacteristics(sqlite3_file
*pFile
){
593 sqlite3_uint64 tStart
, tElapse
;
594 VLogFile
*p
= (VLogFile
*)pFile
;
595 tStart
= vlog_time();
596 rc
= p
->pReal
->pMethods
->xDeviceCharacteristics(p
->pReal
);
597 tElapse
= vlog_time() - tStart
;
598 vlogLogPrint(p
->pLog
, tStart
, tElapse
, "DEVCHAR", -1, -1, 0, rc
);
604 ** Open an vlog file handle.
614 sqlite3_uint64 tStart
, tElapse
;
616 VLogFile
*p
= (VLogFile
*)pFile
;
618 p
->pReal
= (sqlite3_file
*)&p
[1];
619 if( (flags
& (SQLITE_OPEN_MAIN_DB
|SQLITE_OPEN_MAIN_JOURNAL
))!=0 ){
620 p
->pLog
= vlogLogOpen(zName
);
624 tStart
= vlog_time();
625 rc
= REALVFS(pVfs
)->xOpen(REALVFS(pVfs
), zName
, p
->pReal
, flags
, pOutFlags
);
626 tElapse
= vlog_time() - tStart
;
627 iArg2
= pOutFlags
? *pOutFlags
: -1;
628 vlogLogPrint(p
->pLog
, tStart
, tElapse
, "OPEN", flags
, iArg2
, 0, rc
);
630 pFile
->pMethods
= &vlog_io_methods
;
632 if( p
->pLog
) vlogLogClose(p
->pLog
);
639 ** Delete the file located at zPath. If the dirSync argument is true,
640 ** ensure the file-system modifications are synced to disk before
643 static int vlogDelete(sqlite3_vfs
*pVfs
, const char *zPath
, int dirSync
){
645 sqlite3_uint64 tStart
, tElapse
;
647 tStart
= vlog_time();
648 rc
= REALVFS(pVfs
)->xDelete(REALVFS(pVfs
), zPath
, dirSync
);
649 tElapse
= vlog_time() - tStart
;
650 pLog
= vlogLogOpen(zPath
);
651 vlogLogPrint(pLog
, tStart
, tElapse
, "DELETE", dirSync
, -1, 0, rc
);
657 ** Test for access permissions. Return true if the requested permission
658 ** is available, or false otherwise.
660 static int vlogAccess(
667 sqlite3_uint64 tStart
, tElapse
;
669 tStart
= vlog_time();
670 rc
= REALVFS(pVfs
)->xAccess(REALVFS(pVfs
), zPath
, flags
, pResOut
);
671 tElapse
= vlog_time() - tStart
;
672 pLog
= vlogLogOpen(zPath
);
673 vlogLogPrint(pLog
, tStart
, tElapse
, "ACCESS", flags
, *pResOut
, 0, rc
);
679 ** Populate buffer zOut with the full canonical pathname corresponding
680 ** to the pathname in zPath. zOut is guaranteed to point to a buffer
681 ** of at least (INST_MAX_PATHNAME+1) bytes.
683 static int vlogFullPathname(
689 return REALVFS(pVfs
)->xFullPathname(REALVFS(pVfs
), zPath
, nOut
, zOut
);
693 ** Open the dynamic library located at zPath and return a handle.
695 static void *vlogDlOpen(sqlite3_vfs
*pVfs
, const char *zPath
){
696 return REALVFS(pVfs
)->xDlOpen(REALVFS(pVfs
), zPath
);
700 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
701 ** utf-8 string describing the most recent error encountered associated
702 ** with dynamic libraries.
704 static void vlogDlError(sqlite3_vfs
*pVfs
, int nByte
, char *zErrMsg
){
705 REALVFS(pVfs
)->xDlError(REALVFS(pVfs
), nByte
, zErrMsg
);
709 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
711 static void (*vlogDlSym(sqlite3_vfs
*pVfs
, void *p
, const char *zSym
))(void){
712 return REALVFS(pVfs
)->xDlSym(REALVFS(pVfs
), p
, zSym
);
716 ** Close the dynamic library handle pHandle.
718 static void vlogDlClose(sqlite3_vfs
*pVfs
, void *pHandle
){
719 REALVFS(pVfs
)->xDlClose(REALVFS(pVfs
), pHandle
);
723 ** Populate the buffer pointed to by zBufOut with nByte bytes of
726 static int vlogRandomness(sqlite3_vfs
*pVfs
, int nByte
, char *zBufOut
){
727 return REALVFS(pVfs
)->xRandomness(REALVFS(pVfs
), nByte
, zBufOut
);
731 ** Sleep for nMicro microseconds. Return the number of microseconds
734 static int vlogSleep(sqlite3_vfs
*pVfs
, int nMicro
){
735 return REALVFS(pVfs
)->xSleep(REALVFS(pVfs
), nMicro
);
739 ** Return the current time as a Julian Day number in *pTimeOut.
741 static int vlogCurrentTime(sqlite3_vfs
*pVfs
, double *pTimeOut
){
742 return REALVFS(pVfs
)->xCurrentTime(REALVFS(pVfs
), pTimeOut
);
745 static int vlogGetLastError(sqlite3_vfs
*pVfs
, int a
, char *b
){
746 return REALVFS(pVfs
)->xGetLastError(REALVFS(pVfs
), a
, b
);
748 static int vlogCurrentTimeInt64(sqlite3_vfs
*pVfs
, sqlite3_int64
*p
){
749 return REALVFS(pVfs
)->xCurrentTimeInt64(REALVFS(pVfs
), p
);
753 ** Register debugvfs as the default VFS for this process.
755 int sqlite3_register_vfslog(const char *zArg
){
756 vlog_vfs
.pVfs
= sqlite3_vfs_find(0);
757 vlog_vfs
.base
.szOsFile
= sizeof(VLogFile
) + vlog_vfs
.pVfs
->szOsFile
;
758 return sqlite3_vfs_register(&vlog_vfs
.base
, 1);