xref: /sqlite-3.40.0/src/test_osinst.c (revision ccb2113a)
15d1f5aa6Sdanielk1977 /*
25d1f5aa6Sdanielk1977 ** 2008 April 10
35d1f5aa6Sdanielk1977 **
45d1f5aa6Sdanielk1977 ** The author disclaims copyright to this source code.  In place of
55d1f5aa6Sdanielk1977 ** a legal notice, here is a blessing:
65d1f5aa6Sdanielk1977 **
75d1f5aa6Sdanielk1977 **    May you do good and not evil.
85d1f5aa6Sdanielk1977 **    May you find forgiveness for yourself and forgive others.
95d1f5aa6Sdanielk1977 **    May you share freely, never taking more than you give.
105d1f5aa6Sdanielk1977 **
115d1f5aa6Sdanielk1977 ******************************************************************************
125d1f5aa6Sdanielk1977 **
135d1f5aa6Sdanielk1977 ** This file contains the implementation of an SQLite vfs wrapper that
145d1f5aa6Sdanielk1977 ** adds instrumentation to all vfs and file methods. C and Tcl interfaces
155d1f5aa6Sdanielk1977 ** are provided to control the instrumentation.
165d1f5aa6Sdanielk1977 */
175d1f5aa6Sdanielk1977 
185d1f5aa6Sdanielk1977 /*
19fbefb894Sdan ** This module contains code for a wrapper VFS that causes a log of
209c0928dcSdan ** most VFS calls to be written into a nominated file on disk. The log
219c0928dcSdan ** is stored in a compressed binary format to reduce the amount of IO
229c0928dcSdan ** overhead introduced into the application by logging.
239c0928dcSdan **
249c0928dcSdan ** All calls on sqlite3_file objects except xFileControl() are logged.
252667be5eSdrh ** Additionally, calls to the xAccess(), xOpen(), and xDelete()
269c0928dcSdan ** methods are logged. The other sqlite3_vfs object methods (xDlXXX,
279c0928dcSdan ** xRandomness, xSleep, xCurrentTime, xGetLastError and xCurrentTimeInt64)
289c0928dcSdan ** are not logged.
295d1f5aa6Sdanielk1977 **
30fbefb894Sdan ** The binary log files are read using a virtual table implementation
31fbefb894Sdan ** also contained in this file.
325d1f5aa6Sdanielk1977 **
33fbefb894Sdan ** CREATING LOG FILES:
345d1f5aa6Sdanielk1977 **
35fbefb894Sdan **       int sqlite3_vfslog_new(
36fbefb894Sdan **         const char *zVfs,          // Name of new VFS
37fbefb894Sdan **         const char *zParentVfs,    // Name of parent VFS (or NULL)
38fbefb894Sdan **         const char *zLog           // Name of log file to write to
39fbefb894Sdan **       );
4070b9b04cSdanielk1977 **
41fbefb894Sdan **       int sqlite3_vfslog_finalize(const char *zVfs);
425d1f5aa6Sdanielk1977 **
4314740f1cSdan ** ANNOTATING LOG FILES:
4414740f1cSdan **
4514740f1cSdan **   To write an arbitrary message into a log file:
4614740f1cSdan **
4714740f1cSdan **       int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg);
4814740f1cSdan **
49fbefb894Sdan ** READING LOG FILES:
505d1f5aa6Sdanielk1977 **
51fbefb894Sdan **   Log files are read using the "vfslog" virtual table implementation
52fbefb894Sdan **   in this file. To register the virtual table with SQLite, use:
535d1f5aa6Sdanielk1977 **
54fbefb894Sdan **       int sqlite3_vfslog_register(sqlite3 *db);
555d1f5aa6Sdanielk1977 **
56fbefb894Sdan **   Then, if the log file is named "vfs.log", the following SQL command:
575d1f5aa6Sdanielk1977 **
58fbefb894Sdan **       CREATE VIRTUAL TABLE v USING vfslog('vfs.log');
595d1f5aa6Sdanielk1977 **
60fbefb894Sdan **   creates a virtual table with 6 columns, as follows:
615d1f5aa6Sdanielk1977 **
62fbefb894Sdan **       CREATE TABLE v(
63fbefb894Sdan **         event    TEXT,             // "xOpen", "xRead" etc.
64fbefb894Sdan **         file     TEXT,             // Name of file this call applies to
65fbefb894Sdan **         clicks   INTEGER,          // Time spent in call
66fbefb894Sdan **         rc       INTEGER,          // Return value
67fbefb894Sdan **         size     INTEGER,          // Bytes read or written
68fbefb894Sdan **         offset   INTEGER           // File offset read or written
69fbefb894Sdan **       );
705d1f5aa6Sdanielk1977 */
715d1f5aa6Sdanielk1977 
725d1f5aa6Sdanielk1977 #include "sqlite3.h"
73f74b9e09Smistachkin 
74f74b9e09Smistachkin #include "os_setup.h"
75f74b9e09Smistachkin #if SQLITE_OS_WIN
76f74b9e09Smistachkin #  include "os_win.h"
77f74b9e09Smistachkin #endif
78f74b9e09Smistachkin 
790520dbbaSdanielk1977 #include <string.h>
800520dbbaSdanielk1977 #include <assert.h>
815d1f5aa6Sdanielk1977 
82fbefb894Sdan 
83fbefb894Sdan /*
84fbefb894Sdan ** Maximum pathname length supported by the vfslog backend.
855d1f5aa6Sdanielk1977 */
865d1f5aa6Sdanielk1977 #define INST_MAX_PATHNAME 512
875d1f5aa6Sdanielk1977 
8870b9b04cSdanielk1977 #define OS_ACCESS            1
8970b9b04cSdanielk1977 #define OS_CHECKRESERVEDLOCK 2
9070b9b04cSdanielk1977 #define OS_CLOSE             3
9170b9b04cSdanielk1977 #define OS_CURRENTTIME       4
9270b9b04cSdanielk1977 #define OS_DELETE            5
9370b9b04cSdanielk1977 #define OS_DEVCHAR           6
9470b9b04cSdanielk1977 #define OS_FILECONTROL       7
9570b9b04cSdanielk1977 #define OS_FILESIZE          8
9670b9b04cSdanielk1977 #define OS_FULLPATHNAME      9
9770b9b04cSdanielk1977 #define OS_LOCK              11
9870b9b04cSdanielk1977 #define OS_OPEN              12
9970b9b04cSdanielk1977 #define OS_RANDOMNESS        13
10070b9b04cSdanielk1977 #define OS_READ              14
10170b9b04cSdanielk1977 #define OS_SECTORSIZE        15
10270b9b04cSdanielk1977 #define OS_SLEEP             16
10370b9b04cSdanielk1977 #define OS_SYNC              17
10470b9b04cSdanielk1977 #define OS_TRUNCATE          18
10570b9b04cSdanielk1977 #define OS_UNLOCK            19
10670b9b04cSdanielk1977 #define OS_WRITE             20
107da9fe0c3Sdan #define OS_SHMUNMAP          22
10818801915Sdan #define OS_SHMMAP            23
10914740f1cSdan #define OS_SHMLOCK           25
110286a2884Sdrh #define OS_SHMBARRIER        26
111286a2884Sdrh #define OS_ANNOTATE          28
1125d1f5aa6Sdanielk1977 
113286a2884Sdrh #define OS_NUMEVENTS         29
1145d1f5aa6Sdanielk1977 
115fbefb894Sdan #define VFSLOG_BUFFERSIZE 8192
1165d1f5aa6Sdanielk1977 
117fbefb894Sdan typedef struct VfslogVfs VfslogVfs;
118fbefb894Sdan typedef struct VfslogFile VfslogFile;
119374177ebSdanielk1977 
120fbefb894Sdan struct VfslogVfs {
121fbefb894Sdan   sqlite3_vfs base;               /* VFS methods */
122fbefb894Sdan   sqlite3_vfs *pVfs;              /* Parent VFS */
123fbefb894Sdan   int iNextFileId;                /* Next file id */
124fbefb894Sdan   sqlite3_file *pLog;             /* Log file handle */
125fbefb894Sdan   sqlite3_int64 iOffset;          /* Log file offset of start of write buffer */
126fbefb894Sdan   int nBuf;                       /* Number of valid bytes in aBuf[] */
127fbefb894Sdan   char aBuf[VFSLOG_BUFFERSIZE];   /* Write buffer */
1285d1f5aa6Sdanielk1977 };
1295d1f5aa6Sdanielk1977 
130fbefb894Sdan struct VfslogFile {
131fbefb894Sdan   sqlite3_file base;              /* IO methods */
132fbefb894Sdan   sqlite3_file *pReal;            /* Underlying file handle */
133fbefb894Sdan   sqlite3_vfs *pVfslog;           /* Associated VsflogVfs object */
134374177ebSdanielk1977   int iFileId;                    /* File id number */
1355d1f5aa6Sdanielk1977 };
1365d1f5aa6Sdanielk1977 
137fbefb894Sdan #define REALVFS(p) (((VfslogVfs *)(p))->pVfs)
138fbefb894Sdan 
139fbefb894Sdan 
1405d1f5aa6Sdanielk1977 
1415d1f5aa6Sdanielk1977 /*
142fbefb894Sdan ** Method declarations for vfslog_file.
1435d1f5aa6Sdanielk1977 */
144fbefb894Sdan static int vfslogClose(sqlite3_file*);
145fbefb894Sdan static int vfslogRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
146fbefb894Sdan static int vfslogWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
147fbefb894Sdan static int vfslogTruncate(sqlite3_file*, sqlite3_int64 size);
148fbefb894Sdan static int vfslogSync(sqlite3_file*, int flags);
149fbefb894Sdan static int vfslogFileSize(sqlite3_file*, sqlite3_int64 *pSize);
150fbefb894Sdan static int vfslogLock(sqlite3_file*, int);
151fbefb894Sdan static int vfslogUnlock(sqlite3_file*, int);
152fbefb894Sdan static int vfslogCheckReservedLock(sqlite3_file*, int *pResOut);
153fbefb894Sdan static int vfslogFileControl(sqlite3_file*, int op, void *pArg);
154fbefb894Sdan static int vfslogSectorSize(sqlite3_file*);
155fbefb894Sdan static int vfslogDeviceCharacteristics(sqlite3_file*);
1565d1f5aa6Sdanielk1977 
15773b64e4dSdrh static int vfslogShmLock(sqlite3_file *pFile, int ofst, int n, int flags);
1586b017cc6Sdrh static int vfslogShmMap(sqlite3_file *pFile,int,int,int,volatile void **);
159286a2884Sdrh static void vfslogShmBarrier(sqlite3_file*);
160da9fe0c3Sdan static int vfslogShmUnmap(sqlite3_file *pFile, int deleteFlag);
16114740f1cSdan 
162fbefb894Sdan /*
163fbefb894Sdan ** Method declarations for vfslog_vfs.
164fbefb894Sdan */
165fbefb894Sdan static int vfslogOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
166fbefb894Sdan static int vfslogDelete(sqlite3_vfs*, const char *zName, int syncDir);
167fbefb894Sdan static int vfslogAccess(sqlite3_vfs*, const char *zName, int flags, int *);
168fbefb894Sdan static int vfslogFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
169fbefb894Sdan static void *vfslogDlOpen(sqlite3_vfs*, const char *zFilename);
170fbefb894Sdan static void vfslogDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
171fbefb894Sdan static void (*vfslogDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
172fbefb894Sdan static void vfslogDlClose(sqlite3_vfs*, void*);
173fbefb894Sdan static int vfslogRandomness(sqlite3_vfs*, int nByte, char *zOut);
174fbefb894Sdan static int vfslogSleep(sqlite3_vfs*, int microseconds);
175fbefb894Sdan static int vfslogCurrentTime(sqlite3_vfs*, double*);
176374177ebSdanielk1977 
1779c0928dcSdan static int vfslogGetLastError(sqlite3_vfs*, int, char *);
1789c0928dcSdan static int vfslogCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
1799c0928dcSdan 
180fbefb894Sdan static sqlite3_vfs vfslog_vfs = {
1815d1f5aa6Sdanielk1977   1,                              /* iVersion */
182fbefb894Sdan   sizeof(VfslogFile),             /* szOsFile */
1835d1f5aa6Sdanielk1977   INST_MAX_PATHNAME,              /* mxPathname */
1845d1f5aa6Sdanielk1977   0,                              /* pNext */
1855d1f5aa6Sdanielk1977   0,                              /* zName */
1865d1f5aa6Sdanielk1977   0,                              /* pAppData */
187fbefb894Sdan   vfslogOpen,                     /* xOpen */
188fbefb894Sdan   vfslogDelete,                   /* xDelete */
189fbefb894Sdan   vfslogAccess,                   /* xAccess */
190fbefb894Sdan   vfslogFullPathname,             /* xFullPathname */
191fbefb894Sdan   vfslogDlOpen,                   /* xDlOpen */
192fbefb894Sdan   vfslogDlError,                  /* xDlError */
193fbefb894Sdan   vfslogDlSym,                    /* xDlSym */
194fbefb894Sdan   vfslogDlClose,                  /* xDlClose */
195fbefb894Sdan   vfslogRandomness,               /* xRandomness */
196fbefb894Sdan   vfslogSleep,                    /* xSleep */
197fbefb894Sdan   vfslogCurrentTime,              /* xCurrentTime */
1989c0928dcSdan   vfslogGetLastError,             /* xGetLastError */
1999c0928dcSdan   vfslogCurrentTimeInt64          /* xCurrentTime */
2005d1f5aa6Sdanielk1977 };
2015d1f5aa6Sdanielk1977 
202fbefb894Sdan static sqlite3_io_methods vfslog_io_methods = {
20314740f1cSdan   2,                              /* iVersion */
204fbefb894Sdan   vfslogClose,                    /* xClose */
205fbefb894Sdan   vfslogRead,                     /* xRead */
206fbefb894Sdan   vfslogWrite,                    /* xWrite */
207fbefb894Sdan   vfslogTruncate,                 /* xTruncate */
208fbefb894Sdan   vfslogSync,                     /* xSync */
209fbefb894Sdan   vfslogFileSize,                 /* xFileSize */
210fbefb894Sdan   vfslogLock,                     /* xLock */
211fbefb894Sdan   vfslogUnlock,                   /* xUnlock */
212fbefb894Sdan   vfslogCheckReservedLock,        /* xCheckReservedLock */
213fbefb894Sdan   vfslogFileControl,              /* xFileControl */
214fbefb894Sdan   vfslogSectorSize,               /* xSectorSize */
21514740f1cSdan   vfslogDeviceCharacteristics,    /* xDeviceCharacteristics */
2166b017cc6Sdrh   vfslogShmMap,                   /* xShmMap */
217da9fe0c3Sdan   vfslogShmLock,                  /* xShmLock */
218286a2884Sdrh   vfslogShmBarrier,               /* xShmBarrier */
219da9fe0c3Sdan   vfslogShmUnmap                  /* xShmUnmap */
2205d1f5aa6Sdanielk1977 };
2215d1f5aa6Sdanielk1977 
2223a2d29f8Sshaneh #if SQLITE_OS_UNIX && !defined(NO_GETTOD)
22314740f1cSdan #include <sys/time.h>
vfslog_time()224fbefb894Sdan static sqlite3_uint64 vfslog_time(){
22514740f1cSdan   struct timeval sTime;
22614740f1cSdan   gettimeofday(&sTime, 0);
22714740f1cSdan   return sTime.tv_usec + (sqlite3_uint64)sTime.tv_sec * 1000000;
2285d1f5aa6Sdanielk1977 }
2293a2d29f8Sshaneh #elif SQLITE_OS_WIN
2302796d336Sshaneh #include <time.h>
vfslog_time()2312796d336Sshaneh static sqlite3_uint64 vfslog_time(){
2322796d336Sshaneh   FILETIME ft;
2332796d336Sshaneh   sqlite3_uint64 u64time = 0;
2342796d336Sshaneh 
2352796d336Sshaneh   GetSystemTimeAsFileTime(&ft);
2362796d336Sshaneh 
2372796d336Sshaneh   u64time |= ft.dwHighDateTime;
2382796d336Sshaneh   u64time <<= 32;
2392796d336Sshaneh   u64time |= ft.dwLowDateTime;
2402796d336Sshaneh 
2412796d336Sshaneh   /* ft is 100-nanosecond intervals, we want microseconds */
2422796d336Sshaneh   return u64time /(sqlite3_uint64)10;
2432796d336Sshaneh }
244a9f0fc8eSdan #else
vfslog_time()245a9f0fc8eSdan static sqlite3_uint64 vfslog_time(){
246a9f0fc8eSdan   return 0;
247a9f0fc8eSdan }
248a9f0fc8eSdan #endif
2495d1f5aa6Sdanielk1977 
2507da5fcb0Sdrh static void vfslog_call(sqlite3_vfs *, int, int, sqlite3_int64, int, int, int);
251fbefb894Sdan static void vfslog_string(sqlite3_vfs *, const char *);
252fbefb894Sdan 
253fbefb894Sdan /*
254fbefb894Sdan ** Close an vfslog-file.
255fbefb894Sdan */
vfslogClose(sqlite3_file * pFile)256fbefb894Sdan static int vfslogClose(sqlite3_file *pFile){
257fbefb894Sdan   sqlite3_uint64 t;
258fbefb894Sdan   int rc = SQLITE_OK;
259fbefb894Sdan   VfslogFile *p = (VfslogFile *)pFile;
260fbefb894Sdan 
261fbefb894Sdan   t = vfslog_time();
262fbefb894Sdan   if( p->pReal->pMethods ){
263fbefb894Sdan     rc = p->pReal->pMethods->xClose(p->pReal);
264fbefb894Sdan   }
265fbefb894Sdan   t = vfslog_time() - t;
266fbefb894Sdan   vfslog_call(p->pVfslog, OS_CLOSE, p->iFileId, t, rc, 0, 0);
267fbefb894Sdan   return rc;
2685d1f5aa6Sdanielk1977 }
2695d1f5aa6Sdanielk1977 
2705d1f5aa6Sdanielk1977 /*
271fbefb894Sdan ** Read data from an vfslog-file.
2725d1f5aa6Sdanielk1977 */
vfslogRead(sqlite3_file * pFile,void * zBuf,int iAmt,sqlite_int64 iOfst)273fbefb894Sdan static int vfslogRead(
2745d1f5aa6Sdanielk1977   sqlite3_file *pFile,
2755d1f5aa6Sdanielk1977   void *zBuf,
2765d1f5aa6Sdanielk1977   int iAmt,
2775d1f5aa6Sdanielk1977   sqlite_int64 iOfst
2785d1f5aa6Sdanielk1977 ){
279fbefb894Sdan   int rc;
280fbefb894Sdan   sqlite3_uint64 t;
281fbefb894Sdan   VfslogFile *p = (VfslogFile *)pFile;
282fbefb894Sdan   t = vfslog_time();
283fbefb894Sdan   rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
284fbefb894Sdan   t = vfslog_time() - t;
285fbefb894Sdan   vfslog_call(p->pVfslog, OS_READ, p->iFileId, t, rc, iAmt, (int)iOfst);
286fbefb894Sdan   return rc;
2875d1f5aa6Sdanielk1977 }
2885d1f5aa6Sdanielk1977 
2895d1f5aa6Sdanielk1977 /*
290fbefb894Sdan ** Write data to an vfslog-file.
2915d1f5aa6Sdanielk1977 */
vfslogWrite(sqlite3_file * pFile,const void * z,int iAmt,sqlite_int64 iOfst)292fbefb894Sdan static int vfslogWrite(
2935d1f5aa6Sdanielk1977   sqlite3_file *pFile,
2945d1f5aa6Sdanielk1977   const void *z,
2955d1f5aa6Sdanielk1977   int iAmt,
2965d1f5aa6Sdanielk1977   sqlite_int64 iOfst
2975d1f5aa6Sdanielk1977 ){
298fbefb894Sdan   int rc;
299fbefb894Sdan   sqlite3_uint64 t;
300fbefb894Sdan   VfslogFile *p = (VfslogFile *)pFile;
301fbefb894Sdan   t = vfslog_time();
302fbefb894Sdan   rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst);
303fbefb894Sdan   t = vfslog_time() - t;
304fbefb894Sdan   vfslog_call(p->pVfslog, OS_WRITE, p->iFileId, t, rc, iAmt, (int)iOfst);
305fbefb894Sdan   return rc;
3065d1f5aa6Sdanielk1977 }
3075d1f5aa6Sdanielk1977 
3085d1f5aa6Sdanielk1977 /*
309fbefb894Sdan ** Truncate an vfslog-file.
3105d1f5aa6Sdanielk1977 */
vfslogTruncate(sqlite3_file * pFile,sqlite_int64 size)311fbefb894Sdan static int vfslogTruncate(sqlite3_file *pFile, sqlite_int64 size){
312fbefb894Sdan   int rc;
313fbefb894Sdan   sqlite3_uint64 t;
314fbefb894Sdan   VfslogFile *p = (VfslogFile *)pFile;
315fbefb894Sdan   t = vfslog_time();
316fbefb894Sdan   rc = p->pReal->pMethods->xTruncate(p->pReal, size);
317fbefb894Sdan   t = vfslog_time() - t;
318fbefb894Sdan   vfslog_call(p->pVfslog, OS_TRUNCATE, p->iFileId, t, rc, 0, (int)size);
319fbefb894Sdan   return rc;
3205d1f5aa6Sdanielk1977 }
3215d1f5aa6Sdanielk1977 
3225d1f5aa6Sdanielk1977 /*
323fbefb894Sdan ** Sync an vfslog-file.
3245d1f5aa6Sdanielk1977 */
vfslogSync(sqlite3_file * pFile,int flags)325fbefb894Sdan static int vfslogSync(sqlite3_file *pFile, int flags){
326fbefb894Sdan   int rc;
327fbefb894Sdan   sqlite3_uint64 t;
328fbefb894Sdan   VfslogFile *p = (VfslogFile *)pFile;
329fbefb894Sdan   t = vfslog_time();
330fbefb894Sdan   rc = p->pReal->pMethods->xSync(p->pReal, flags);
331fbefb894Sdan   t = vfslog_time() - t;
332fbefb894Sdan   vfslog_call(p->pVfslog, OS_SYNC, p->iFileId, t, rc, flags, 0);
333fbefb894Sdan   return rc;
3345d1f5aa6Sdanielk1977 }
3355d1f5aa6Sdanielk1977 
3365d1f5aa6Sdanielk1977 /*
337fbefb894Sdan ** Return the current file-size of an vfslog-file.
3385d1f5aa6Sdanielk1977 */
vfslogFileSize(sqlite3_file * pFile,sqlite_int64 * pSize)339fbefb894Sdan static int vfslogFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
340fbefb894Sdan   int rc;
341fbefb894Sdan   sqlite3_uint64 t;
342fbefb894Sdan   VfslogFile *p = (VfslogFile *)pFile;
343fbefb894Sdan   t = vfslog_time();
344fbefb894Sdan   rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
345fbefb894Sdan   t = vfslog_time() - t;
346fbefb894Sdan   vfslog_call(p->pVfslog, OS_FILESIZE, p->iFileId, t, rc, 0, (int)*pSize);
347fbefb894Sdan   return rc;
3485d1f5aa6Sdanielk1977 }
3495d1f5aa6Sdanielk1977 
3505d1f5aa6Sdanielk1977 /*
351fbefb894Sdan ** Lock an vfslog-file.
3525d1f5aa6Sdanielk1977 */
vfslogLock(sqlite3_file * pFile,int eLock)353fbefb894Sdan static int vfslogLock(sqlite3_file *pFile, int eLock){
354fbefb894Sdan   int rc;
355fbefb894Sdan   sqlite3_uint64 t;
356fbefb894Sdan   VfslogFile *p = (VfslogFile *)pFile;
357fbefb894Sdan   t = vfslog_time();
358fbefb894Sdan   rc = p->pReal->pMethods->xLock(p->pReal, eLock);
359fbefb894Sdan   t = vfslog_time() - t;
360fbefb894Sdan   vfslog_call(p->pVfslog, OS_LOCK, p->iFileId, t, rc, eLock, 0);
361fbefb894Sdan   return rc;
3625d1f5aa6Sdanielk1977 }
3635d1f5aa6Sdanielk1977 
3645d1f5aa6Sdanielk1977 /*
365fbefb894Sdan ** Unlock an vfslog-file.
3665d1f5aa6Sdanielk1977 */
vfslogUnlock(sqlite3_file * pFile,int eLock)367fbefb894Sdan static int vfslogUnlock(sqlite3_file *pFile, int eLock){
368fbefb894Sdan   int rc;
369fbefb894Sdan   sqlite3_uint64 t;
370fbefb894Sdan   VfslogFile *p = (VfslogFile *)pFile;
371fbefb894Sdan   t = vfslog_time();
372fbefb894Sdan   rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
373fbefb894Sdan   t = vfslog_time() - t;
374fbefb894Sdan   vfslog_call(p->pVfslog, OS_UNLOCK, p->iFileId, t, rc, eLock, 0);
375fbefb894Sdan   return rc;
3765d1f5aa6Sdanielk1977 }
3775d1f5aa6Sdanielk1977 
3785d1f5aa6Sdanielk1977 /*
379fbefb894Sdan ** Check if another file-handle holds a RESERVED lock on an vfslog-file.
3805d1f5aa6Sdanielk1977 */
vfslogCheckReservedLock(sqlite3_file * pFile,int * pResOut)381fbefb894Sdan static int vfslogCheckReservedLock(sqlite3_file *pFile, int *pResOut){
382fbefb894Sdan   int rc;
383fbefb894Sdan   sqlite3_uint64 t;
384fbefb894Sdan   VfslogFile *p = (VfslogFile *)pFile;
385fbefb894Sdan   t = vfslog_time();
386fbefb894Sdan   rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
387fbefb894Sdan   t = vfslog_time() - t;
388fbefb894Sdan   vfslog_call(p->pVfslog, OS_CHECKRESERVEDLOCK, p->iFileId, t, rc, *pResOut, 0);
389fbefb894Sdan   return rc;
3905d1f5aa6Sdanielk1977 }
3915d1f5aa6Sdanielk1977 
3925d1f5aa6Sdanielk1977 /*
393fbefb894Sdan ** File control method. For custom operations on an vfslog-file.
3945d1f5aa6Sdanielk1977 */
vfslogFileControl(sqlite3_file * pFile,int op,void * pArg)395fbefb894Sdan static int vfslogFileControl(sqlite3_file *pFile, int op, void *pArg){
396fbefb894Sdan   VfslogFile *p = (VfslogFile *)pFile;
397de60fc2dSdrh   int rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
398de60fc2dSdrh   if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
399de60fc2dSdrh     *(char**)pArg = sqlite3_mprintf("vfslog/%z", *(char**)pArg);
400de60fc2dSdrh   }
401de60fc2dSdrh   return rc;
4025d1f5aa6Sdanielk1977 }
4035d1f5aa6Sdanielk1977 
4045d1f5aa6Sdanielk1977 /*
405fbefb894Sdan ** Return the sector-size in bytes for an vfslog-file.
4065d1f5aa6Sdanielk1977 */
vfslogSectorSize(sqlite3_file * pFile)407fbefb894Sdan static int vfslogSectorSize(sqlite3_file *pFile){
408fbefb894Sdan   int rc;
409fbefb894Sdan   sqlite3_uint64 t;
410fbefb894Sdan   VfslogFile *p = (VfslogFile *)pFile;
411fbefb894Sdan   t = vfslog_time();
412fbefb894Sdan   rc = p->pReal->pMethods->xSectorSize(p->pReal);
413fbefb894Sdan   t = vfslog_time() - t;
414fbefb894Sdan   vfslog_call(p->pVfslog, OS_SECTORSIZE, p->iFileId, t, rc, 0, 0);
415fbefb894Sdan   return rc;
4165d1f5aa6Sdanielk1977 }
4175d1f5aa6Sdanielk1977 
4185d1f5aa6Sdanielk1977 /*
419fbefb894Sdan ** Return the device characteristic flags supported by an vfslog-file.
4205d1f5aa6Sdanielk1977 */
vfslogDeviceCharacteristics(sqlite3_file * pFile)421fbefb894Sdan static int vfslogDeviceCharacteristics(sqlite3_file *pFile){
422fbefb894Sdan   int rc;
423fbefb894Sdan   sqlite3_uint64 t;
424fbefb894Sdan   VfslogFile *p = (VfslogFile *)pFile;
425fbefb894Sdan   t = vfslog_time();
426fbefb894Sdan   rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
427fbefb894Sdan   t = vfslog_time() - t;
428fbefb894Sdan   vfslog_call(p->pVfslog, OS_DEVCHAR, p->iFileId, t, rc, 0, 0);
429fbefb894Sdan   return rc;
4305d1f5aa6Sdanielk1977 }
4315d1f5aa6Sdanielk1977 
vfslogShmLock(sqlite3_file * pFile,int ofst,int n,int flags)43273b64e4dSdrh static int vfslogShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
43314740f1cSdan   int rc;
43414740f1cSdan   sqlite3_uint64 t;
43514740f1cSdan   VfslogFile *p = (VfslogFile *)pFile;
43614740f1cSdan   t = vfslog_time();
43773b64e4dSdrh   rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
43814740f1cSdan   t = vfslog_time() - t;
43914740f1cSdan   vfslog_call(p->pVfslog, OS_SHMLOCK, p->iFileId, t, rc, 0, 0);
44014740f1cSdan   return rc;
44114740f1cSdan }
vfslogShmMap(sqlite3_file * pFile,int iRegion,int szRegion,int isWrite,volatile void ** pp)4426b017cc6Sdrh static int vfslogShmMap(
4436b017cc6Sdrh   sqlite3_file *pFile,
4446b017cc6Sdrh   int iRegion,
4456b017cc6Sdrh   int szRegion,
4466b017cc6Sdrh   int isWrite,
4476b017cc6Sdrh   volatile void **pp
4486b017cc6Sdrh ){
4496b017cc6Sdrh   int rc;
4506b017cc6Sdrh   sqlite3_uint64 t;
4516b017cc6Sdrh   VfslogFile *p = (VfslogFile *)pFile;
4526b017cc6Sdrh   t = vfslog_time();
4536b017cc6Sdrh   rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
4546b017cc6Sdrh   t = vfslog_time() - t;
4556b017cc6Sdrh   vfslog_call(p->pVfslog, OS_SHMMAP, p->iFileId, t, rc, 0, 0);
4566b017cc6Sdrh   return rc;
4576b017cc6Sdrh }
vfslogShmBarrier(sqlite3_file * pFile)458286a2884Sdrh static void vfslogShmBarrier(sqlite3_file *pFile){
459286a2884Sdrh   sqlite3_uint64 t;
460286a2884Sdrh   VfslogFile *p = (VfslogFile *)pFile;
461286a2884Sdrh   t = vfslog_time();
462286a2884Sdrh   p->pReal->pMethods->xShmBarrier(p->pReal);
463286a2884Sdrh   t = vfslog_time() - t;
464286a2884Sdrh   vfslog_call(p->pVfslog, OS_SHMBARRIER, p->iFileId, t, SQLITE_OK, 0, 0);
465286a2884Sdrh }
vfslogShmUnmap(sqlite3_file * pFile,int deleteFlag)466da9fe0c3Sdan static int vfslogShmUnmap(sqlite3_file *pFile, int deleteFlag){
46714740f1cSdan   int rc;
46814740f1cSdan   sqlite3_uint64 t;
46914740f1cSdan   VfslogFile *p = (VfslogFile *)pFile;
47014740f1cSdan   t = vfslog_time();
471da9fe0c3Sdan   rc = p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag);
47214740f1cSdan   t = vfslog_time() - t;
473da9fe0c3Sdan   vfslog_call(p->pVfslog, OS_SHMUNMAP, p->iFileId, t, rc, 0, 0);
47414740f1cSdan   return rc;
47514740f1cSdan }
47614740f1cSdan 
47714740f1cSdan 
4785d1f5aa6Sdanielk1977 /*
479fbefb894Sdan ** Open an vfslog file handle.
4805d1f5aa6Sdanielk1977 */
vfslogOpen(sqlite3_vfs * pVfs,const char * zName,sqlite3_file * pFile,int flags,int * pOutFlags)481fbefb894Sdan static int vfslogOpen(
4825d1f5aa6Sdanielk1977   sqlite3_vfs *pVfs,
4835d1f5aa6Sdanielk1977   const char *zName,
4845d1f5aa6Sdanielk1977   sqlite3_file *pFile,
4855d1f5aa6Sdanielk1977   int flags,
4865d1f5aa6Sdanielk1977   int *pOutFlags
4875d1f5aa6Sdanielk1977 ){
488fbefb894Sdan   int rc;
489fbefb894Sdan   sqlite3_uint64 t;
490fbefb894Sdan   VfslogFile *p = (VfslogFile *)pFile;
491fbefb894Sdan   VfslogVfs *pLog = (VfslogVfs *)pVfs;
4925d1f5aa6Sdanielk1977 
493fbefb894Sdan   pFile->pMethods = &vfslog_io_methods;
494fbefb894Sdan   p->pReal = (sqlite3_file *)&p[1];
495fbefb894Sdan   p->pVfslog = pVfs;
496fbefb894Sdan   p->iFileId = ++pLog->iNextFileId;
497fbefb894Sdan 
498fbefb894Sdan   t = vfslog_time();
499fbefb894Sdan   rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags);
500fbefb894Sdan   t = vfslog_time() - t;
501fbefb894Sdan 
502fbefb894Sdan   vfslog_call(pVfs, OS_OPEN, p->iFileId, t, rc, 0, 0);
503fbefb894Sdan   vfslog_string(pVfs, zName);
504fbefb894Sdan   return rc;
5055d1f5aa6Sdanielk1977 }
5065d1f5aa6Sdanielk1977 
5075d1f5aa6Sdanielk1977 /*
5085d1f5aa6Sdanielk1977 ** Delete the file located at zPath. If the dirSync argument is true,
5095d1f5aa6Sdanielk1977 ** ensure the file-system modifications are synced to disk before
5105d1f5aa6Sdanielk1977 ** returning.
5115d1f5aa6Sdanielk1977 */
vfslogDelete(sqlite3_vfs * pVfs,const char * zPath,int dirSync)512fbefb894Sdan static int vfslogDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
513fbefb894Sdan   int rc;
514fbefb894Sdan   sqlite3_uint64 t;
515fbefb894Sdan   t = vfslog_time();
516fbefb894Sdan   rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync);
517fbefb894Sdan   t = vfslog_time() - t;
518fbefb894Sdan   vfslog_call(pVfs, OS_DELETE, 0, t, rc, dirSync, 0);
519fbefb894Sdan   vfslog_string(pVfs, zPath);
520fbefb894Sdan   return rc;
5215d1f5aa6Sdanielk1977 }
5225d1f5aa6Sdanielk1977 
5235d1f5aa6Sdanielk1977 /*
5245d1f5aa6Sdanielk1977 ** Test for access permissions. Return true if the requested permission
5255d1f5aa6Sdanielk1977 ** is available, or false otherwise.
5265d1f5aa6Sdanielk1977 */
vfslogAccess(sqlite3_vfs * pVfs,const char * zPath,int flags,int * pResOut)527fbefb894Sdan static int vfslogAccess(
528861f7456Sdanielk1977   sqlite3_vfs *pVfs,
529861f7456Sdanielk1977   const char *zPath,
530861f7456Sdanielk1977   int flags,
531861f7456Sdanielk1977   int *pResOut
532861f7456Sdanielk1977 ){
533fbefb894Sdan   int rc;
534fbefb894Sdan   sqlite3_uint64 t;
535fbefb894Sdan   t = vfslog_time();
536fbefb894Sdan   rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut);
537fbefb894Sdan   t = vfslog_time() - t;
538fbefb894Sdan   vfslog_call(pVfs, OS_ACCESS, 0, t, rc, flags, *pResOut);
539fbefb894Sdan   vfslog_string(pVfs, zPath);
540fbefb894Sdan   return rc;
5415d1f5aa6Sdanielk1977 }
5425d1f5aa6Sdanielk1977 
5435d1f5aa6Sdanielk1977 /*
5445d1f5aa6Sdanielk1977 ** Populate buffer zOut with the full canonical pathname corresponding
5455d1f5aa6Sdanielk1977 ** to the pathname in zPath. zOut is guaranteed to point to a buffer
5465d1f5aa6Sdanielk1977 ** of at least (INST_MAX_PATHNAME+1) bytes.
5475d1f5aa6Sdanielk1977 */
vfslogFullPathname(sqlite3_vfs * pVfs,const char * zPath,int nOut,char * zOut)548fbefb894Sdan static int vfslogFullPathname(
5495d1f5aa6Sdanielk1977   sqlite3_vfs *pVfs,
5505d1f5aa6Sdanielk1977   const char *zPath,
5515d1f5aa6Sdanielk1977   int nOut,
5525d1f5aa6Sdanielk1977   char *zOut
5535d1f5aa6Sdanielk1977 ){
554fbefb894Sdan   return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
5555d1f5aa6Sdanielk1977 }
5565d1f5aa6Sdanielk1977 
5575d1f5aa6Sdanielk1977 /*
5585d1f5aa6Sdanielk1977 ** Open the dynamic library located at zPath and return a handle.
5595d1f5aa6Sdanielk1977 */
vfslogDlOpen(sqlite3_vfs * pVfs,const char * zPath)560fbefb894Sdan static void *vfslogDlOpen(sqlite3_vfs *pVfs, const char *zPath){
5610520dbbaSdanielk1977   return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
5625d1f5aa6Sdanielk1977 }
5635d1f5aa6Sdanielk1977 
5645d1f5aa6Sdanielk1977 /*
5655d1f5aa6Sdanielk1977 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
5665d1f5aa6Sdanielk1977 ** utf-8 string describing the most recent error encountered associated
5675d1f5aa6Sdanielk1977 ** with dynamic libraries.
5685d1f5aa6Sdanielk1977 */
vfslogDlError(sqlite3_vfs * pVfs,int nByte,char * zErrMsg)569fbefb894Sdan static void vfslogDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
5700520dbbaSdanielk1977   REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
5715d1f5aa6Sdanielk1977 }
5725d1f5aa6Sdanielk1977 
5735d1f5aa6Sdanielk1977 /*
5745d1f5aa6Sdanielk1977 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
5755d1f5aa6Sdanielk1977 */
vfslogDlSym(sqlite3_vfs * pVfs,void * p,const char * zSym)576fbefb894Sdan static void (*vfslogDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
577484fe37cSdanielk1977   return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym);
5785d1f5aa6Sdanielk1977 }
5795d1f5aa6Sdanielk1977 
5805d1f5aa6Sdanielk1977 /*
5815d1f5aa6Sdanielk1977 ** Close the dynamic library handle pHandle.
5825d1f5aa6Sdanielk1977 */
vfslogDlClose(sqlite3_vfs * pVfs,void * pHandle)583fbefb894Sdan static void vfslogDlClose(sqlite3_vfs *pVfs, void *pHandle){
5840520dbbaSdanielk1977   REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
5855d1f5aa6Sdanielk1977 }
5865d1f5aa6Sdanielk1977 
5875d1f5aa6Sdanielk1977 /*
5885d1f5aa6Sdanielk1977 ** Populate the buffer pointed to by zBufOut with nByte bytes of
5895d1f5aa6Sdanielk1977 ** random data.
5905d1f5aa6Sdanielk1977 */
vfslogRandomness(sqlite3_vfs * pVfs,int nByte,char * zBufOut)591fbefb894Sdan static int vfslogRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
592fbefb894Sdan   return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
5935d1f5aa6Sdanielk1977 }
5945d1f5aa6Sdanielk1977 
5955d1f5aa6Sdanielk1977 /*
5965d1f5aa6Sdanielk1977 ** Sleep for nMicro microseconds. Return the number of microseconds
5975d1f5aa6Sdanielk1977 ** actually slept.
5985d1f5aa6Sdanielk1977 */
vfslogSleep(sqlite3_vfs * pVfs,int nMicro)599fbefb894Sdan static int vfslogSleep(sqlite3_vfs *pVfs, int nMicro){
600fbefb894Sdan   return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro);
6015d1f5aa6Sdanielk1977 }
6025d1f5aa6Sdanielk1977 
6035d1f5aa6Sdanielk1977 /*
6045d1f5aa6Sdanielk1977 ** Return the current time as a Julian Day number in *pTimeOut.
6055d1f5aa6Sdanielk1977 */
vfslogCurrentTime(sqlite3_vfs * pVfs,double * pTimeOut)606fbefb894Sdan static int vfslogCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
607fbefb894Sdan   return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut);
6085d1f5aa6Sdanielk1977 }
6095d1f5aa6Sdanielk1977 
vfslogGetLastError(sqlite3_vfs * pVfs,int a,char * b)6109c0928dcSdan static int vfslogGetLastError(sqlite3_vfs *pVfs, int a, char *b){
6119c0928dcSdan   return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b);
6129c0928dcSdan }
vfslogCurrentTimeInt64(sqlite3_vfs * pVfs,sqlite3_int64 * p)6139c0928dcSdan static int vfslogCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
6149c0928dcSdan   return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p);
6159c0928dcSdan }
6169c0928dcSdan 
vfslog_flush(VfslogVfs * p)617fbefb894Sdan static void vfslog_flush(VfslogVfs *p){
61893f7af97Sdanielk1977 #ifdef SQLITE_TEST
61993f7af97Sdanielk1977   extern int sqlite3_io_error_pending;
62093f7af97Sdanielk1977   extern int sqlite3_io_error_persist;
62193f7af97Sdanielk1977   extern int sqlite3_diskfull_pending;
62293f7af97Sdanielk1977 
62393f7af97Sdanielk1977   int pending = sqlite3_io_error_pending;
62493f7af97Sdanielk1977   int persist = sqlite3_io_error_persist;
62593f7af97Sdanielk1977   int diskfull = sqlite3_diskfull_pending;
62693f7af97Sdanielk1977 
62793f7af97Sdanielk1977   sqlite3_io_error_pending = 0;
62893f7af97Sdanielk1977   sqlite3_io_error_persist = 0;
62993f7af97Sdanielk1977   sqlite3_diskfull_pending = 0;
63093f7af97Sdanielk1977 #endif
63193f7af97Sdanielk1977 
632fbefb894Sdan   if( p->nBuf ){
633fbefb894Sdan     p->pLog->pMethods->xWrite(p->pLog, p->aBuf, p->nBuf, p->iOffset);
634fbefb894Sdan     p->iOffset += p->nBuf;
635fbefb894Sdan     p->nBuf = 0;
636fbefb894Sdan   }
63793f7af97Sdanielk1977 
63893f7af97Sdanielk1977 #ifdef SQLITE_TEST
63993f7af97Sdanielk1977   sqlite3_io_error_pending = pending;
64093f7af97Sdanielk1977   sqlite3_io_error_persist = persist;
64193f7af97Sdanielk1977   sqlite3_diskfull_pending = diskfull;
64293f7af97Sdanielk1977 #endif
64393f7af97Sdanielk1977 }
64493f7af97Sdanielk1977 
put32bits(unsigned char * p,unsigned int v)645fbefb894Sdan static void put32bits(unsigned char *p, unsigned int v){
646fbefb894Sdan   p[0] = v>>24;
64777fac879Smistachkin   p[1] = (unsigned char)(v>>16);
64877fac879Smistachkin   p[2] = (unsigned char)(v>>8);
64977fac879Smistachkin   p[3] = (unsigned char)v;
65070b9b04cSdanielk1977 }
651fbefb894Sdan 
vfslog_call(sqlite3_vfs * pVfs,int eEvent,int iFileid,sqlite3_int64 nClick,int return_code,int size,int offset)652fbefb894Sdan static void vfslog_call(
653fbefb894Sdan   sqlite3_vfs *pVfs,
654fbefb894Sdan   int eEvent,
655fbefb894Sdan   int iFileid,
6567da5fcb0Sdrh   sqlite3_int64 nClick,
657fbefb894Sdan   int return_code,
658fbefb894Sdan   int size,
659fbefb894Sdan   int offset
660fbefb894Sdan ){
661fbefb894Sdan   VfslogVfs *p = (VfslogVfs *)pVfs;
662fbefb894Sdan   unsigned char *zRec;
663fbefb894Sdan   if( (24+p->nBuf)>sizeof(p->aBuf) ){
664fbefb894Sdan     vfslog_flush(p);
665fbefb894Sdan   }
666fbefb894Sdan   zRec = (unsigned char *)&p->aBuf[p->nBuf];
66770b9b04cSdanielk1977   put32bits(&zRec[0], eEvent);
668fbefb894Sdan   put32bits(&zRec[4], iFileid);
6697da5fcb0Sdrh   put32bits(&zRec[8], (unsigned int)(nClick&0xffff));
670374177ebSdanielk1977   put32bits(&zRec[12], return_code);
671fbefb894Sdan   put32bits(&zRec[16], size);
672fbefb894Sdan   put32bits(&zRec[20], offset);
673fbefb894Sdan   p->nBuf += 24;
67470b9b04cSdanielk1977 }
67570b9b04cSdanielk1977 
vfslog_string(sqlite3_vfs * pVfs,const char * zStr)676fbefb894Sdan static void vfslog_string(sqlite3_vfs *pVfs, const char *zStr){
677fbefb894Sdan   VfslogVfs *p = (VfslogVfs *)pVfs;
67827467047Sdanielk1977   unsigned char *zRec;
67983cc1392Sdrh   int nStr = zStr ? (int)strlen(zStr) : 0;
680fbefb894Sdan   if( (4+nStr+p->nBuf)>sizeof(p->aBuf) ){
681fbefb894Sdan     vfslog_flush(p);
682374177ebSdanielk1977   }
683fbefb894Sdan   zRec = (unsigned char *)&p->aBuf[p->nBuf];
684fbefb894Sdan   put32bits(&zRec[0], nStr);
685fbefb894Sdan   if( zStr ){
686fbefb894Sdan     memcpy(&zRec[4], zStr, nStr);
687fbefb894Sdan   }
688fbefb894Sdan   p->nBuf += (4 + nStr);
689374177ebSdanielk1977 }
690374177ebSdanielk1977 
vfslog_finalize(VfslogVfs * p)691fbefb894Sdan static void vfslog_finalize(VfslogVfs *p){
692fbefb894Sdan   if( p->pLog->pMethods ){
693fbefb894Sdan     vfslog_flush(p);
694fbefb894Sdan     p->pLog->pMethods->xClose(p->pLog);
695374177ebSdanielk1977   }
696fbefb894Sdan   sqlite3_free(p);
69727467047Sdanielk1977 }
698374177ebSdanielk1977 
sqlite3_vfslog_finalize(const char * zVfs)699fbefb894Sdan int sqlite3_vfslog_finalize(const char *zVfs){
70070b9b04cSdanielk1977   sqlite3_vfs *pVfs;
701fbefb894Sdan   pVfs = sqlite3_vfs_find(zVfs);
702fbefb894Sdan   if( !pVfs || pVfs->xOpen!=vfslogOpen ){
703fbefb894Sdan     return SQLITE_ERROR;
704fbefb894Sdan   }
70514740f1cSdan   sqlite3_vfs_unregister(pVfs);
706fbefb894Sdan   vfslog_finalize((VfslogVfs *)pVfs);
707fbefb894Sdan   return SQLITE_OK;
708fbefb894Sdan }
709fbefb894Sdan 
sqlite3_vfslog_new(const char * zVfs,const char * zParentVfs,const char * zLog)710fbefb894Sdan int sqlite3_vfslog_new(
711fbefb894Sdan   const char *zVfs,               /* New VFS name */
712fbefb894Sdan   const char *zParentVfs,         /* Parent VFS name (or NULL) */
713fbefb894Sdan   const char *zLog                /* Log file name */
714fbefb894Sdan ){
715fbefb894Sdan   VfslogVfs *p;
71670b9b04cSdanielk1977   sqlite3_vfs *pParent;
71770b9b04cSdanielk1977   int nByte;
71870b9b04cSdanielk1977   int flags;
71970b9b04cSdanielk1977   int rc;
720fbefb894Sdan   char *zFile;
721fbefb894Sdan   int nVfs;
72270b9b04cSdanielk1977 
72370b9b04cSdanielk1977   pParent = sqlite3_vfs_find(zParentVfs);
72470b9b04cSdanielk1977   if( !pParent ){
725fbefb894Sdan     return SQLITE_ERROR;
72670b9b04cSdanielk1977   }
72770b9b04cSdanielk1977 
72883cc1392Sdrh   nVfs = (int)strlen(zVfs);
729fbefb894Sdan   nByte = sizeof(VfslogVfs) + pParent->szOsFile + nVfs+1+pParent->mxPathname+1;
730fbefb894Sdan   p = (VfslogVfs *)sqlite3_malloc(nByte);
73170b9b04cSdanielk1977   memset(p, 0, nByte);
732fbefb894Sdan 
733fbefb894Sdan   p->pVfs = pParent;
734fbefb894Sdan   p->pLog = (sqlite3_file *)&p[1];
735fbefb894Sdan   memcpy(&p->base, &vfslog_vfs, sizeof(sqlite3_vfs));
736fbefb894Sdan   p->base.zName = &((char *)p->pLog)[pParent->szOsFile];
737fbefb894Sdan   p->base.szOsFile += pParent->szOsFile;
738fbefb894Sdan   memcpy((char *)p->base.zName, zVfs, nVfs);
739fbefb894Sdan 
740fbefb894Sdan   zFile = (char *)&p->base.zName[nVfs+1];
741fbefb894Sdan   pParent->xFullPathname(pParent, zLog, pParent->mxPathname, zFile);
742fbefb894Sdan 
743*ccb2113aSdrh   flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_SUPER_JOURNAL;
744fbefb894Sdan   pParent->xDelete(pParent, zFile, 0);
745fbefb894Sdan   rc = pParent->xOpen(pParent, zFile, p->pLog, flags, &flags);
74670b9b04cSdanielk1977   if( rc==SQLITE_OK ){
747fbefb894Sdan     memcpy(p->aBuf, "sqlite_ostrace1.....", 20);
74893f7af97Sdanielk1977     p->iOffset = 0;
74993f7af97Sdanielk1977     p->nBuf = 20;
750fbefb894Sdan     rc = sqlite3_vfs_register((sqlite3_vfs *)p, 1);
75170b9b04cSdanielk1977   }
75270b9b04cSdanielk1977   if( rc ){
753fbefb894Sdan     vfslog_finalize(p);
754fbefb894Sdan   }
755fbefb894Sdan   return rc;
75670b9b04cSdanielk1977 }
75770b9b04cSdanielk1977 
sqlite3_vfslog_annotate(const char * zVfs,const char * zMsg)75814740f1cSdan int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg){
75914740f1cSdan   sqlite3_vfs *pVfs;
76014740f1cSdan   pVfs = sqlite3_vfs_find(zVfs);
76114740f1cSdan   if( !pVfs || pVfs->xOpen!=vfslogOpen ){
76214740f1cSdan     return SQLITE_ERROR;
76314740f1cSdan   }
76414740f1cSdan   vfslog_call(pVfs, OS_ANNOTATE, 0, 0, 0, 0, 0);
76514740f1cSdan   vfslog_string(pVfs, zMsg);
76614740f1cSdan   return SQLITE_OK;
76714740f1cSdan }
76814740f1cSdan 
vfslog_eventname(int eEvent)769fbefb894Sdan static const char *vfslog_eventname(int eEvent){
770fbefb894Sdan   const char *zEvent = 0;
771fbefb894Sdan 
772fbefb894Sdan   switch( eEvent ){
773fbefb894Sdan     case OS_CLOSE:             zEvent = "xClose"; break;
774fbefb894Sdan     case OS_READ:              zEvent = "xRead"; break;
775fbefb894Sdan     case OS_WRITE:             zEvent = "xWrite"; break;
776fbefb894Sdan     case OS_TRUNCATE:          zEvent = "xTruncate"; break;
777fbefb894Sdan     case OS_SYNC:              zEvent = "xSync"; break;
778fbefb894Sdan     case OS_FILESIZE:          zEvent = "xFilesize"; break;
779fbefb894Sdan     case OS_LOCK:              zEvent = "xLock"; break;
780fbefb894Sdan     case OS_UNLOCK:            zEvent = "xUnlock"; break;
781fbefb894Sdan     case OS_CHECKRESERVEDLOCK: zEvent = "xCheckResLock"; break;
782fbefb894Sdan     case OS_FILECONTROL:       zEvent = "xFileControl"; break;
783fbefb894Sdan     case OS_SECTORSIZE:        zEvent = "xSectorSize"; break;
784fbefb894Sdan     case OS_DEVCHAR:           zEvent = "xDeviceChar"; break;
785fbefb894Sdan     case OS_OPEN:              zEvent = "xOpen"; break;
786fbefb894Sdan     case OS_DELETE:            zEvent = "xDelete"; break;
787fbefb894Sdan     case OS_ACCESS:            zEvent = "xAccess"; break;
788fbefb894Sdan     case OS_FULLPATHNAME:      zEvent = "xFullPathname"; break;
789fbefb894Sdan     case OS_RANDOMNESS:        zEvent = "xRandomness"; break;
790fbefb894Sdan     case OS_SLEEP:             zEvent = "xSleep"; break;
791fbefb894Sdan     case OS_CURRENTTIME:       zEvent = "xCurrentTime"; break;
79214740f1cSdan 
793da9fe0c3Sdan     case OS_SHMUNMAP:          zEvent = "xShmUnmap"; break;
79414740f1cSdan     case OS_SHMLOCK:           zEvent = "xShmLock"; break;
795286a2884Sdrh     case OS_SHMBARRIER:        zEvent = "xShmBarrier"; break;
79618801915Sdan     case OS_SHMMAP:            zEvent = "xShmMap"; break;
79714740f1cSdan 
79814740f1cSdan     case OS_ANNOTATE:          zEvent = "annotation"; break;
79970b9b04cSdanielk1977   }
80070b9b04cSdanielk1977 
801fbefb894Sdan   return zEvent;
80270b9b04cSdanielk1977 }
803fbefb894Sdan 
804fbefb894Sdan typedef struct VfslogVtab VfslogVtab;
805fbefb894Sdan typedef struct VfslogCsr VfslogCsr;
806fbefb894Sdan 
807fbefb894Sdan /*
808fbefb894Sdan ** Virtual table type for the vfslog reader module.
809fbefb894Sdan */
810fbefb894Sdan struct VfslogVtab {
811fbefb894Sdan   sqlite3_vtab base;              /* Base class */
812fbefb894Sdan   sqlite3_file *pFd;              /* File descriptor open on vfslog file */
813fbefb894Sdan   sqlite3_int64 nByte;            /* Size of file in bytes */
814fbefb894Sdan   char *zFile;                    /* File name for pFd */
815fbefb894Sdan };
816fbefb894Sdan 
817fbefb894Sdan /*
818fbefb894Sdan ** Virtual table cursor type for the vfslog reader module.
819fbefb894Sdan */
820fbefb894Sdan struct VfslogCsr {
821fbefb894Sdan   sqlite3_vtab_cursor base;       /* Base class */
822fbefb894Sdan   sqlite3_int64 iRowid;           /* Current rowid. */
823fbefb894Sdan   sqlite3_int64 iOffset;          /* Offset of next record in file */
824fbefb894Sdan   char *zTransient;               /* Transient 'file' string */
825fbefb894Sdan   int nFile;                      /* Size of array azFile[] */
826fbefb894Sdan   char **azFile;                  /* File strings */
827fbefb894Sdan   unsigned char aBuf[1024];       /* Current vfs log entry (read from file) */
828fbefb894Sdan };
829fbefb894Sdan 
get32bits(unsigned char * p)830fbefb894Sdan static unsigned int get32bits(unsigned char *p){
831fbefb894Sdan   return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
832fbefb894Sdan }
833fbefb894Sdan 
834fbefb894Sdan /*
835fbefb894Sdan ** The argument must point to a buffer containing a nul-terminated string.
836fbefb894Sdan ** If the string begins with an SQL quote character it is overwritten by
837fbefb894Sdan ** the dequoted version. Otherwise the buffer is left unmodified.
838fbefb894Sdan */
dequote(char * z)839fbefb894Sdan static void dequote(char *z){
840fbefb894Sdan   char quote;                     /* Quote character (if any ) */
841fbefb894Sdan   quote = z[0];
842fbefb894Sdan   if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){
843fbefb894Sdan     int iIn = 1;                  /* Index of next byte to read from input */
844fbefb894Sdan     int iOut = 0;                 /* Index of next byte to write to output */
845fbefb894Sdan     if( quote=='[' ) quote = ']';
846fbefb894Sdan     while( z[iIn] ){
847fbefb894Sdan       if( z[iIn]==quote ){
848fbefb894Sdan         if( z[iIn+1]!=quote ) break;
849fbefb894Sdan         z[iOut++] = quote;
850fbefb894Sdan         iIn += 2;
851fbefb894Sdan       }else{
852fbefb894Sdan         z[iOut++] = z[iIn++];
853fbefb894Sdan       }
854fbefb894Sdan     }
855fbefb894Sdan     z[iOut] = '\0';
856fbefb894Sdan   }
857fbefb894Sdan }
858fbefb894Sdan 
85900f699d5Sdrh #ifndef SQLITE_OMIT_VIRTUALTABLE
860fbefb894Sdan /*
861fbefb894Sdan ** Connect to or create a vfslog virtual table.
862fbefb894Sdan */
vlogConnect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)863fbefb894Sdan static int vlogConnect(
864fbefb894Sdan   sqlite3 *db,
865fbefb894Sdan   void *pAux,
866fbefb894Sdan   int argc, const char *const*argv,
867fbefb894Sdan   sqlite3_vtab **ppVtab,
868fbefb894Sdan   char **pzErr
869fbefb894Sdan ){
870fbefb894Sdan   sqlite3_vfs *pVfs;              /* VFS used to read log file */
871fbefb894Sdan   int flags;                      /* flags passed to pVfs->xOpen() */
872fbefb894Sdan   VfslogVtab *p;
873fbefb894Sdan   int rc;
874fbefb894Sdan   int nByte;
875fbefb894Sdan   char *zFile;
876fbefb894Sdan 
877fbefb894Sdan   *ppVtab = 0;
878fbefb894Sdan   pVfs = sqlite3_vfs_find(0);
879fbefb894Sdan   nByte = sizeof(VfslogVtab) + pVfs->szOsFile + pVfs->mxPathname;
880fbefb894Sdan   p = sqlite3_malloc(nByte);
881fbefb894Sdan   if( p==0 ) return SQLITE_NOMEM;
882fbefb894Sdan   memset(p, 0, nByte);
883fbefb894Sdan 
884fbefb894Sdan   p->pFd = (sqlite3_file *)&p[1];
885fbefb894Sdan   p->zFile = &((char *)p->pFd)[pVfs->szOsFile];
886fbefb894Sdan 
887fbefb894Sdan   zFile = sqlite3_mprintf("%s", argv[3]);
888fbefb894Sdan   if( !zFile ){
889fbefb894Sdan     sqlite3_free(p);
890fbefb894Sdan     return SQLITE_NOMEM;
891fbefb894Sdan   }
892fbefb894Sdan   dequote(zFile);
893fbefb894Sdan   pVfs->xFullPathname(pVfs, zFile, pVfs->mxPathname, p->zFile);
894fbefb894Sdan   sqlite3_free(zFile);
895fbefb894Sdan 
896*ccb2113aSdrh   flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_SUPER_JOURNAL;
897fbefb894Sdan   rc = pVfs->xOpen(pVfs, p->zFile, p->pFd, flags, &flags);
898fbefb894Sdan 
899fbefb894Sdan   if( rc==SQLITE_OK ){
900fbefb894Sdan     p->pFd->pMethods->xFileSize(p->pFd, &p->nByte);
901fbefb894Sdan     sqlite3_declare_vtab(db,
902fbefb894Sdan         "CREATE TABLE xxx(event, file, click, rc, size, offset)"
903fbefb894Sdan     );
904fbefb894Sdan     *ppVtab = &p->base;
905fbefb894Sdan   }else{
906fbefb894Sdan     sqlite3_free(p);
907fbefb894Sdan   }
908fbefb894Sdan 
909fbefb894Sdan   return rc;
910fbefb894Sdan }
911fbefb894Sdan 
912fbefb894Sdan /*
913fbefb894Sdan ** There is no "best-index". This virtual table always does a linear
914fbefb894Sdan ** scan of the binary VFS log file.
915fbefb894Sdan */
vlogBestIndex(sqlite3_vtab * tab,sqlite3_index_info * pIdxInfo)916fbefb894Sdan static int vlogBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
917fbefb894Sdan   pIdxInfo->estimatedCost = 10.0;
918fbefb894Sdan   return SQLITE_OK;
919fbefb894Sdan }
920fbefb894Sdan 
921fbefb894Sdan /*
922fbefb894Sdan ** Disconnect from or destroy a vfslog virtual table.
923fbefb894Sdan */
vlogDisconnect(sqlite3_vtab * pVtab)924fbefb894Sdan static int vlogDisconnect(sqlite3_vtab *pVtab){
925fbefb894Sdan   VfslogVtab *p = (VfslogVtab *)pVtab;
926fbefb894Sdan   if( p->pFd->pMethods ){
927fbefb894Sdan     p->pFd->pMethods->xClose(p->pFd);
928fbefb894Sdan     p->pFd->pMethods = 0;
929fbefb894Sdan   }
930fbefb894Sdan   sqlite3_free(p);
931fbefb894Sdan   return SQLITE_OK;
932fbefb894Sdan }
933fbefb894Sdan 
934fbefb894Sdan /*
935fbefb894Sdan ** Open a new vfslog cursor.
936fbefb894Sdan */
vlogOpen(sqlite3_vtab * pVTab,sqlite3_vtab_cursor ** ppCursor)937fbefb894Sdan static int vlogOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
938fbefb894Sdan   VfslogCsr *pCsr;                /* Newly allocated cursor object */
939fbefb894Sdan 
940fbefb894Sdan   pCsr = sqlite3_malloc(sizeof(VfslogCsr));
941fbefb894Sdan   if( !pCsr ) return SQLITE_NOMEM;
942fbefb894Sdan   memset(pCsr, 0, sizeof(VfslogCsr));
943fbefb894Sdan   *ppCursor = &pCsr->base;
944fbefb894Sdan   return SQLITE_OK;
945fbefb894Sdan }
946fbefb894Sdan 
947fbefb894Sdan /*
948fbefb894Sdan ** Close a vfslog cursor.
949fbefb894Sdan */
vlogClose(sqlite3_vtab_cursor * pCursor)950fbefb894Sdan static int vlogClose(sqlite3_vtab_cursor *pCursor){
951fbefb894Sdan   VfslogCsr *p = (VfslogCsr *)pCursor;
952fbefb894Sdan   int i;
953fbefb894Sdan   for(i=0; i<p->nFile; i++){
954fbefb894Sdan     sqlite3_free(p->azFile[i]);
955fbefb894Sdan   }
956fbefb894Sdan   sqlite3_free(p->azFile);
957fbefb894Sdan   sqlite3_free(p->zTransient);
958fbefb894Sdan   sqlite3_free(p);
959fbefb894Sdan   return SQLITE_OK;
960fbefb894Sdan }
961fbefb894Sdan 
962fbefb894Sdan /*
963fbefb894Sdan ** Move a vfslog cursor to the next entry in the file.
964fbefb894Sdan */
vlogNext(sqlite3_vtab_cursor * pCursor)965fbefb894Sdan static int vlogNext(sqlite3_vtab_cursor *pCursor){
966fbefb894Sdan   VfslogCsr *pCsr = (VfslogCsr *)pCursor;
967fbefb894Sdan   VfslogVtab *p = (VfslogVtab *)pCursor->pVtab;
968fbefb894Sdan   int rc = SQLITE_OK;
969fbefb894Sdan   int nRead;
970fbefb894Sdan 
971fbefb894Sdan   sqlite3_free(pCsr->zTransient);
972fbefb894Sdan   pCsr->zTransient = 0;
973fbefb894Sdan 
974fbefb894Sdan   nRead = 24;
975fbefb894Sdan   if( pCsr->iOffset+nRead<=p->nByte ){
976fbefb894Sdan     int eEvent;
977fbefb894Sdan     rc = p->pFd->pMethods->xRead(p->pFd, pCsr->aBuf, nRead, pCsr->iOffset);
978fbefb894Sdan 
979fbefb894Sdan     eEvent = get32bits(pCsr->aBuf);
980fbefb894Sdan     if( (rc==SQLITE_OK)
981fbefb894Sdan      && (eEvent==OS_OPEN || eEvent==OS_DELETE || eEvent==OS_ACCESS)
982fbefb894Sdan     ){
983fbefb894Sdan       char buf[4];
984fbefb894Sdan       rc = p->pFd->pMethods->xRead(p->pFd, buf, 4, pCsr->iOffset+nRead);
985fbefb894Sdan       nRead += 4;
986fbefb894Sdan       if( rc==SQLITE_OK ){
987fbefb894Sdan         int nStr = get32bits((unsigned char *)buf);
988fbefb894Sdan         char *zStr = sqlite3_malloc(nStr+1);
989fbefb894Sdan         rc = p->pFd->pMethods->xRead(p->pFd, zStr, nStr, pCsr->iOffset+nRead);
990fbefb894Sdan         zStr[nStr] = '\0';
991fbefb894Sdan         nRead += nStr;
992fbefb894Sdan 
993fbefb894Sdan         if( eEvent==OS_OPEN ){
994fbefb894Sdan           int iFileid = get32bits(&pCsr->aBuf[4]);
995fbefb894Sdan           if( iFileid>=pCsr->nFile ){
996fbefb894Sdan             int nNew = sizeof(pCsr->azFile[0])*(iFileid+1);
997fbefb894Sdan             pCsr->azFile = (char **)sqlite3_realloc(pCsr->azFile, nNew);
998fbefb894Sdan             nNew -= sizeof(pCsr->azFile[0])*pCsr->nFile;
999fbefb894Sdan             memset(&pCsr->azFile[pCsr->nFile], 0, nNew);
1000fbefb894Sdan             pCsr->nFile = iFileid+1;
1001fbefb894Sdan           }
1002fbefb894Sdan           sqlite3_free(pCsr->azFile[iFileid]);
1003fbefb894Sdan           pCsr->azFile[iFileid] = zStr;
1004fbefb894Sdan         }else{
1005fbefb894Sdan           pCsr->zTransient = zStr;
1006fbefb894Sdan         }
1007fbefb894Sdan       }
1008fbefb894Sdan     }
1009fbefb894Sdan   }
1010fbefb894Sdan 
1011fbefb894Sdan   pCsr->iRowid += 1;
1012fbefb894Sdan   pCsr->iOffset += nRead;
1013fbefb894Sdan   return rc;
1014fbefb894Sdan }
1015fbefb894Sdan 
vlogEof(sqlite3_vtab_cursor * pCursor)1016fbefb894Sdan static int vlogEof(sqlite3_vtab_cursor *pCursor){
1017fbefb894Sdan   VfslogCsr *pCsr = (VfslogCsr *)pCursor;
1018fbefb894Sdan   VfslogVtab *p = (VfslogVtab *)pCursor->pVtab;
1019fbefb894Sdan   return (pCsr->iOffset>=p->nByte);
1020fbefb894Sdan }
1021fbefb894Sdan 
vlogFilter(sqlite3_vtab_cursor * pCursor,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)1022fbefb894Sdan static int vlogFilter(
1023fbefb894Sdan   sqlite3_vtab_cursor *pCursor,
1024fbefb894Sdan   int idxNum, const char *idxStr,
1025fbefb894Sdan   int argc, sqlite3_value **argv
1026fbefb894Sdan ){
1027fbefb894Sdan   VfslogCsr *pCsr = (VfslogCsr *)pCursor;
1028fbefb894Sdan   pCsr->iRowid = 0;
1029fbefb894Sdan   pCsr->iOffset = 20;
1030fbefb894Sdan   return vlogNext(pCursor);
1031fbefb894Sdan }
1032fbefb894Sdan 
vlogColumn(sqlite3_vtab_cursor * pCursor,sqlite3_context * ctx,int i)1033fbefb894Sdan static int vlogColumn(
1034fbefb894Sdan   sqlite3_vtab_cursor *pCursor,
1035fbefb894Sdan   sqlite3_context *ctx,
1036fbefb894Sdan   int i
1037fbefb894Sdan ){
1038fbefb894Sdan   unsigned int val;
1039fbefb894Sdan   VfslogCsr *pCsr = (VfslogCsr *)pCursor;
1040fbefb894Sdan 
1041fbefb894Sdan   assert( i<7 );
1042fbefb894Sdan   val = get32bits(&pCsr->aBuf[4*i]);
1043fbefb894Sdan 
1044fbefb894Sdan   switch( i ){
1045fbefb894Sdan     case 0: {
1046fbefb894Sdan       sqlite3_result_text(ctx, vfslog_eventname(val), -1, SQLITE_STATIC);
1047fbefb894Sdan       break;
1048fbefb894Sdan     }
1049fbefb894Sdan     case 1: {
1050fbefb894Sdan       char *zStr = pCsr->zTransient;
10517da5fcb0Sdrh       if( val!=0 && val<(unsigned)pCsr->nFile ){
1052fbefb894Sdan         zStr = pCsr->azFile[val];
1053fbefb894Sdan       }
1054fbefb894Sdan       sqlite3_result_text(ctx, zStr, -1, SQLITE_TRANSIENT);
1055fbefb894Sdan       break;
1056fbefb894Sdan     }
1057fbefb894Sdan     default:
1058fbefb894Sdan       sqlite3_result_int(ctx, val);
1059fbefb894Sdan       break;
1060fbefb894Sdan   }
1061fbefb894Sdan 
1062fbefb894Sdan   return SQLITE_OK;
1063fbefb894Sdan }
1064fbefb894Sdan 
vlogRowid(sqlite3_vtab_cursor * pCursor,sqlite_int64 * pRowid)1065fbefb894Sdan static int vlogRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
1066fbefb894Sdan   VfslogCsr *pCsr = (VfslogCsr *)pCursor;
1067fbefb894Sdan   *pRowid = pCsr->iRowid;
1068fbefb894Sdan   return SQLITE_OK;
1069fbefb894Sdan }
1070fbefb894Sdan 
sqlite3_vfslog_register(sqlite3 * db)1071fbefb894Sdan int sqlite3_vfslog_register(sqlite3 *db){
1072fbefb894Sdan   static sqlite3_module vfslog_module = {
1073fbefb894Sdan     0,                            /* iVersion */
1074fbefb894Sdan     vlogConnect,                /* xCreate */
1075fbefb894Sdan     vlogConnect,                /* xConnect */
1076fbefb894Sdan     vlogBestIndex,              /* xBestIndex */
1077fbefb894Sdan     vlogDisconnect,             /* xDisconnect */
1078fbefb894Sdan     vlogDisconnect,             /* xDestroy */
1079fbefb894Sdan     vlogOpen,                   /* xOpen - open a cursor */
1080fbefb894Sdan     vlogClose,                  /* xClose - close a cursor */
1081fbefb894Sdan     vlogFilter,                 /* xFilter - configure scan constraints */
1082fbefb894Sdan     vlogNext,                   /* xNext - advance a cursor */
1083fbefb894Sdan     vlogEof,                    /* xEof - check for end of scan */
1084fbefb894Sdan     vlogColumn,                 /* xColumn - read data */
1085fbefb894Sdan     vlogRowid,                  /* xRowid - read data */
1086fbefb894Sdan     0,                            /* xUpdate */
1087fbefb894Sdan     0,                            /* xBegin */
1088fbefb894Sdan     0,                            /* xSync */
1089fbefb894Sdan     0,                            /* xCommit */
1090fbefb894Sdan     0,                            /* xRollback */
1091fbefb894Sdan     0,                            /* xFindMethod */
1092fbefb894Sdan     0,                            /* xRename */
1093fbefb894Sdan   };
1094fbefb894Sdan 
1095fbefb894Sdan   sqlite3_create_module(db, "vfslog", &vfslog_module, 0);
1096fbefb894Sdan   return SQLITE_OK;
1097fbefb894Sdan }
109800f699d5Sdrh #endif /* SQLITE_OMIT_VIRTUALTABLE */
109970b9b04cSdanielk1977 
11005d1f5aa6Sdanielk1977 /**************************************************************************
11015d1f5aa6Sdanielk1977 ***************************************************************************
11025d1f5aa6Sdanielk1977 ** Tcl interface starts here.
11035d1f5aa6Sdanielk1977 */
1104fbefb894Sdan 
110514740f1cSdan #if defined(SQLITE_TEST) || defined(TCLSH)
11065d1f5aa6Sdanielk1977 
110752b1dbb5Smistachkin #if defined(INCLUDE_SQLITE_TCL_H)
110852b1dbb5Smistachkin #  include "sqlite_tcl.h"
110952b1dbb5Smistachkin #else
111052b1dbb5Smistachkin #  include "tcl.h"
11117617e4a8Smistachkin #  ifndef SQLITE_TCLAPI
11127617e4a8Smistachkin #    define SQLITE_TCLAPI
11137617e4a8Smistachkin #  endif
111452b1dbb5Smistachkin #endif
11155d1f5aa6Sdanielk1977 
test_vfslog(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])11167617e4a8Smistachkin static int SQLITE_TCLAPI test_vfslog(
11175d1f5aa6Sdanielk1977   void *clientData,
11185d1f5aa6Sdanielk1977   Tcl_Interp *interp,
11195d1f5aa6Sdanielk1977   int objc,
11205d1f5aa6Sdanielk1977   Tcl_Obj *CONST objv[]
11215d1f5aa6Sdanielk1977 ){
1122fbefb894Sdan   struct SqliteDb { sqlite3 *db; };
1123fbefb894Sdan   sqlite3 *db;
1124fbefb894Sdan   Tcl_CmdInfo cmdInfo;
1125fbefb894Sdan   int rc = SQLITE_ERROR;
1126fbefb894Sdan 
112714740f1cSdan   static const char *strs[] = { "annotate", "finalize", "new",  "register", 0 };
112814740f1cSdan   enum VL_enum { VL_ANNOTATE, VL_FINALIZE, VL_NEW, VL_REGISTER };
11295d1f5aa6Sdanielk1977   int iSub;
11305d1f5aa6Sdanielk1977 
11315d1f5aa6Sdanielk1977   if( objc<2 ){
11325d1f5aa6Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
1133fbefb894Sdan     return TCL_ERROR;
11345d1f5aa6Sdanielk1977   }
1135fbefb894Sdan   if( Tcl_GetIndexFromObj(interp, objv[1], strs, "sub-command", 0, &iSub) ){
11365d1f5aa6Sdanielk1977     return TCL_ERROR;
11375d1f5aa6Sdanielk1977   }
11385d1f5aa6Sdanielk1977 
1139fbefb894Sdan   switch( (enum VL_enum)iSub ){
114014740f1cSdan     case VL_ANNOTATE: {
114114740f1cSdan       char *zVfs;
114214740f1cSdan       char *zMsg;
114314740f1cSdan       if( objc!=4 ){
114414740f1cSdan         Tcl_WrongNumArgs(interp, 3, objv, "VFS");
114514740f1cSdan         return TCL_ERROR;
114614740f1cSdan       }
114714740f1cSdan       zVfs = Tcl_GetString(objv[2]);
114814740f1cSdan       zMsg = Tcl_GetString(objv[3]);
114914740f1cSdan       rc = sqlite3_vfslog_annotate(zVfs, zMsg);
115014740f1cSdan       if( rc!=SQLITE_OK ){
115114740f1cSdan         Tcl_AppendResult(interp, "failed", 0);
115214740f1cSdan         return TCL_ERROR;
115314740f1cSdan       }
115414740f1cSdan       break;
115514740f1cSdan     }
1156fbefb894Sdan     case VL_FINALIZE: {
1157fbefb894Sdan       char *zVfs;
11585d1f5aa6Sdanielk1977       if( objc!=3 ){
1159fbefb894Sdan         Tcl_WrongNumArgs(interp, 2, objv, "VFS");
11605d1f5aa6Sdanielk1977         return TCL_ERROR;
11615d1f5aa6Sdanielk1977       }
1162fbefb894Sdan       zVfs = Tcl_GetString(objv[2]);
1163fbefb894Sdan       rc = sqlite3_vfslog_finalize(zVfs);
1164fbefb894Sdan       if( rc!=SQLITE_OK ){
1165fbefb894Sdan         Tcl_AppendResult(interp, "failed", 0);
11665d1f5aa6Sdanielk1977         return TCL_ERROR;
11675d1f5aa6Sdanielk1977       }
11685d1f5aa6Sdanielk1977       break;
1169fbefb894Sdan     };
1170fbefb894Sdan 
1171fbefb894Sdan     case VL_NEW: {
1172fbefb894Sdan       char *zVfs;
1173fbefb894Sdan       char *zParent;
1174fbefb894Sdan       char *zLog;
1175fbefb894Sdan       if( objc!=5 ){
1176fbefb894Sdan         Tcl_WrongNumArgs(interp, 2, objv, "VFS PARENT LOGFILE");
1177fbefb894Sdan         return TCL_ERROR;
11785d1f5aa6Sdanielk1977       }
1179fbefb894Sdan       zVfs = Tcl_GetString(objv[2]);
1180fbefb894Sdan       zParent = Tcl_GetString(objv[3]);
1181fbefb894Sdan       zLog = Tcl_GetString(objv[4]);
1182fbefb894Sdan       if( *zParent=='\0' ) zParent = 0;
1183fbefb894Sdan       rc = sqlite3_vfslog_new(zVfs, zParent, zLog);
1184fbefb894Sdan       if( rc!=SQLITE_OK ){
1185fbefb894Sdan         Tcl_AppendResult(interp, "failed", 0);
1186fbefb894Sdan         return TCL_ERROR;
1187fbefb894Sdan       }
1188fbefb894Sdan       break;
1189fbefb894Sdan     };
1190fbefb894Sdan 
1191fbefb894Sdan     case VL_REGISTER: {
1192fbefb894Sdan       char *zDb;
1193fbefb894Sdan       if( objc!=3 ){
1194fbefb894Sdan         Tcl_WrongNumArgs(interp, 2, objv, "DB");
1195fbefb894Sdan         return TCL_ERROR;
1196fbefb894Sdan       }
119700f699d5Sdrh #ifdef SQLITE_OMIT_VIRTUALTABLE
119800f699d5Sdrh       Tcl_AppendResult(interp, "vfslog not available because of "
119900f699d5Sdrh                                "SQLITE_OMIT_VIRTUALTABLE", (void*)0);
120000f699d5Sdrh       return TCL_ERROR;
120100f699d5Sdrh #else
1202fbefb894Sdan       zDb = Tcl_GetString(objv[2]);
1203fbefb894Sdan       if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
1204fbefb894Sdan         db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
1205fbefb894Sdan         rc = sqlite3_vfslog_register(db);
1206fbefb894Sdan       }
1207fbefb894Sdan       if( rc!=SQLITE_OK ){
120800f699d5Sdrh         Tcl_AppendResult(interp, "bad sqlite3 handle: ", zDb, (void*)0);
1209fbefb894Sdan         return TCL_ERROR;
1210fbefb894Sdan       }
1211fbefb894Sdan       break;
121200f699d5Sdrh #endif
121300f699d5Sdrh     }
12145d1f5aa6Sdanielk1977   }
12155d1f5aa6Sdanielk1977 
12165d1f5aa6Sdanielk1977   return TCL_OK;
12175d1f5aa6Sdanielk1977 }
12185d1f5aa6Sdanielk1977 
SqlitetestOsinst_Init(Tcl_Interp * interp)12195d1f5aa6Sdanielk1977 int SqlitetestOsinst_Init(Tcl_Interp *interp){
1220fbefb894Sdan   Tcl_CreateObjCommand(interp, "vfslog", test_vfslog, 0, 0);
12215d1f5aa6Sdanielk1977   return TCL_OK;
12225d1f5aa6Sdanielk1977 }
12235d1f5aa6Sdanielk1977 
122440f2c767Sdrh #endif /* SQLITE_TEST */
1225