Merge sqlite-release(3.44.2) into prerelease-integration
[sqlcipher.git] / src / test_osinst.c
blob062e83159b2aa14c7c28875a64a511b142eea6cd
1 /*
2 ** 2008 April 10
3 **
4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
6 **
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 ******************************************************************************
13 ** This file contains the implementation of an SQLite vfs 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)
28 ** are not logged.
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
39 ** );
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);
49 ** READING LOG FILES:
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:
62 ** CREATE TABLE v(
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
69 ** );
72 #include "sqlite3.h"
74 #include "os_setup.h"
75 #if SQLITE_OS_WIN
76 # include "os_win.h"
77 #endif
79 #include <string.h>
80 #include <assert.h>
84 ** Maximum pathname length supported by the vfslog backend.
86 #define INST_MAX_PATHNAME 512
88 #define OS_ACCESS 1
89 #define OS_CHECKRESERVEDLOCK 2
90 #define OS_CLOSE 3
91 #define OS_CURRENTTIME 4
92 #define OS_DELETE 5
93 #define OS_DEVCHAR 6
94 #define OS_FILECONTROL 7
95 #define OS_FILESIZE 8
96 #define OS_FULLPATHNAME 9
97 #define OS_LOCK 11
98 #define OS_OPEN 12
99 #define OS_RANDOMNESS 13
100 #define OS_READ 14
101 #define OS_SECTORSIZE 15
102 #define OS_SLEEP 16
103 #define OS_SYNC 17
104 #define OS_TRUNCATE 18
105 #define OS_UNLOCK 19
106 #define OS_WRITE 20
107 #define OS_SHMUNMAP 22
108 #define OS_SHMMAP 23
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;
120 struct VfslogVfs {
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 */
130 struct VfslogFile {
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 = {
181 1, /* iVersion */
182 sizeof(VfslogFile), /* szOsFile */
183 INST_MAX_PATHNAME, /* mxPathname */
184 0, /* pNext */
185 0, /* zName */
186 0, /* pAppData */
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 = {
203 2, /* iVersion */
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;
229 #elif SQLITE_OS_WIN
230 #include <time.h>
231 static sqlite3_uint64 vfslog_time(){
232 FILETIME ft;
233 sqlite3_uint64 u64time = 0;
235 GetSystemTimeAsFileTime(&ft);
237 u64time |= ft.dwHighDateTime;
238 u64time <<= 32;
239 u64time |= ft.dwLowDateTime;
241 /* ft is 100-nanosecond intervals, we want microseconds */
242 return u64time /(sqlite3_uint64)10;
244 #else
245 static sqlite3_uint64 vfslog_time(){
246 return 0;
248 #endif
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){
257 sqlite3_uint64 t;
258 int rc = SQLITE_OK;
259 VfslogFile *p = (VfslogFile *)pFile;
261 t = vfslog_time();
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);
267 return rc;
271 ** Read data from an vfslog-file.
273 static int vfslogRead(
274 sqlite3_file *pFile,
275 void *zBuf,
276 int iAmt,
277 sqlite_int64 iOfst
279 int rc;
280 sqlite3_uint64 t;
281 VfslogFile *p = (VfslogFile *)pFile;
282 t = vfslog_time();
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);
286 return rc;
290 ** Write data to an vfslog-file.
292 static int vfslogWrite(
293 sqlite3_file *pFile,
294 const void *z,
295 int iAmt,
296 sqlite_int64 iOfst
298 int rc;
299 sqlite3_uint64 t;
300 VfslogFile *p = (VfslogFile *)pFile;
301 t = vfslog_time();
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);
305 return rc;
309 ** Truncate an vfslog-file.
311 static int vfslogTruncate(sqlite3_file *pFile, sqlite_int64 size){
312 int rc;
313 sqlite3_uint64 t;
314 VfslogFile *p = (VfslogFile *)pFile;
315 t = vfslog_time();
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);
319 return rc;
323 ** Sync an vfslog-file.
325 static int vfslogSync(sqlite3_file *pFile, int flags){
326 int rc;
327 sqlite3_uint64 t;
328 VfslogFile *p = (VfslogFile *)pFile;
329 t = vfslog_time();
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);
333 return rc;
337 ** Return the current file-size of an vfslog-file.
339 static int vfslogFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
340 int rc;
341 sqlite3_uint64 t;
342 VfslogFile *p = (VfslogFile *)pFile;
343 t = vfslog_time();
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);
347 return rc;
351 ** Lock an vfslog-file.
353 static int vfslogLock(sqlite3_file *pFile, int eLock){
354 int rc;
355 sqlite3_uint64 t;
356 VfslogFile *p = (VfslogFile *)pFile;
357 t = vfslog_time();
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);
361 return rc;
365 ** Unlock an vfslog-file.
367 static int vfslogUnlock(sqlite3_file *pFile, int eLock){
368 int rc;
369 sqlite3_uint64 t;
370 VfslogFile *p = (VfslogFile *)pFile;
371 t = vfslog_time();
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);
375 return rc;
379 ** Check if another file-handle holds a RESERVED lock on an vfslog-file.
381 static int vfslogCheckReservedLock(sqlite3_file *pFile, int *pResOut){
382 int rc;
383 sqlite3_uint64 t;
384 VfslogFile *p = (VfslogFile *)pFile;
385 t = vfslog_time();
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);
389 return rc;
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);
401 return rc;
405 ** Return the sector-size in bytes for an vfslog-file.
407 static int vfslogSectorSize(sqlite3_file *pFile){
408 int rc;
409 sqlite3_uint64 t;
410 VfslogFile *p = (VfslogFile *)pFile;
411 t = vfslog_time();
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);
415 return rc;
419 ** Return the device characteristic flags supported by an vfslog-file.
421 static int vfslogDeviceCharacteristics(sqlite3_file *pFile){
422 int rc;
423 sqlite3_uint64 t;
424 VfslogFile *p = (VfslogFile *)pFile;
425 t = vfslog_time();
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);
429 return rc;
432 static int vfslogShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
433 int rc;
434 sqlite3_uint64 t;
435 VfslogFile *p = (VfslogFile *)pFile;
436 t = vfslog_time();
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);
440 return rc;
442 static int vfslogShmMap(
443 sqlite3_file *pFile,
444 int iRegion,
445 int szRegion,
446 int isWrite,
447 volatile void **pp
449 int rc;
450 sqlite3_uint64 t;
451 VfslogFile *p = (VfslogFile *)pFile;
452 t = vfslog_time();
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);
456 return rc;
458 static void vfslogShmBarrier(sqlite3_file *pFile){
459 sqlite3_uint64 t;
460 VfslogFile *p = (VfslogFile *)pFile;
461 t = vfslog_time();
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){
467 int rc;
468 sqlite3_uint64 t;
469 VfslogFile *p = (VfslogFile *)pFile;
470 t = vfslog_time();
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);
474 return rc;
479 ** Open an vfslog file handle.
481 static int vfslogOpen(
482 sqlite3_vfs *pVfs,
483 const char *zName,
484 sqlite3_file *pFile,
485 int flags,
486 int *pOutFlags
488 int rc;
489 sqlite3_uint64 t;
490 VfslogFile *p = (VfslogFile *)pFile;
491 VfslogVfs *pLog = (VfslogVfs *)pVfs;
493 pFile->pMethods = &vfslog_io_methods;
494 p->pReal = (sqlite3_file *)&p[1];
495 p->pVfslog = pVfs;
496 p->iFileId = ++pLog->iNextFileId;
498 t = vfslog_time();
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);
504 return rc;
508 ** Delete the file located at zPath. If the dirSync argument is true,
509 ** ensure the file-system modifications are synced to disk before
510 ** returning.
512 static int vfslogDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
513 int rc;
514 sqlite3_uint64 t;
515 t = vfslog_time();
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);
520 return rc;
524 ** Test for access permissions. Return true if the requested permission
525 ** is available, or false otherwise.
527 static int vfslogAccess(
528 sqlite3_vfs *pVfs,
529 const char *zPath,
530 int flags,
531 int *pResOut
533 int rc;
534 sqlite3_uint64 t;
535 t = vfslog_time();
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);
540 return rc;
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(
549 sqlite3_vfs *pVfs,
550 const char *zPath,
551 int nOut,
552 char *zOut
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
589 ** random data.
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
597 ** actually slept.
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){
618 #ifdef SQLITE_TEST
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;
630 #endif
632 if( p->nBuf ){
633 p->pLog->pMethods->xWrite(p->pLog, p->aBuf, p->nBuf, p->iOffset);
634 p->iOffset += p->nBuf;
635 p->nBuf = 0;
638 #ifdef SQLITE_TEST
639 sqlite3_io_error_pending = pending;
640 sqlite3_io_error_persist = persist;
641 sqlite3_diskfull_pending = diskfull;
642 #endif
645 static void put32bits(unsigned char *p, unsigned int v){
646 p[0] = v>>24;
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(
653 sqlite3_vfs *pVfs,
654 int eEvent,
655 int iFileid,
656 sqlite3_int64 nClick,
657 int return_code,
658 int size,
659 int offset
661 VfslogVfs *p = (VfslogVfs *)pVfs;
662 unsigned char *zRec;
663 if( (24+p->nBuf)>sizeof(p->aBuf) ){
664 vfslog_flush(p);
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);
673 p->nBuf += 24;
676 static void vfslog_string(sqlite3_vfs *pVfs, const char *zStr){
677 VfslogVfs *p = (VfslogVfs *)pVfs;
678 unsigned char *zRec;
679 int nStr = zStr ? (int)strlen(zStr) : 0;
680 if( (4+nStr+p->nBuf)>sizeof(p->aBuf) ){
681 vfslog_flush(p);
683 zRec = (unsigned char *)&p->aBuf[p->nBuf];
684 put32bits(&zRec[0], nStr);
685 if( zStr ){
686 memcpy(&zRec[4], zStr, nStr);
688 p->nBuf += (4 + nStr);
691 static void vfslog_finalize(VfslogVfs *p){
692 if( p->pLog->pMethods ){
693 vfslog_flush(p);
694 p->pLog->pMethods->xClose(p->pLog);
696 sqlite3_free(p);
699 int sqlite3_vfslog_finalize(const char *zVfs){
700 sqlite3_vfs *pVfs;
701 pVfs = sqlite3_vfs_find(zVfs);
702 if( !pVfs || pVfs->xOpen!=vfslogOpen ){
703 return SQLITE_ERROR;
705 sqlite3_vfs_unregister(pVfs);
706 vfslog_finalize((VfslogVfs *)pVfs);
707 return SQLITE_OK;
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 */
715 VfslogVfs *p;
716 sqlite3_vfs *pParent;
717 int nByte;
718 int flags;
719 int rc;
720 char *zFile;
721 int nVfs;
723 pParent = sqlite3_vfs_find(zParentVfs);
724 if( !pParent ){
725 return SQLITE_ERROR;
728 nVfs = (int)strlen(zVfs);
729 nByte = sizeof(VfslogVfs) + pParent->szOsFile + nVfs+1+pParent->mxPathname+1;
730 p = (VfslogVfs *)sqlite3_malloc(nByte);
731 memset(p, 0, nByte);
733 p->pVfs = pParent;
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_SUPER_JOURNAL;
744 pParent->xDelete(pParent, zFile, 0);
745 rc = pParent->xOpen(pParent, zFile, p->pLog, flags, &flags);
746 if( rc==SQLITE_OK ){
747 memcpy(p->aBuf, "sqlite_ostrace1.....", 20);
748 p->iOffset = 0;
749 p->nBuf = 20;
750 rc = sqlite3_vfs_register((sqlite3_vfs *)p, 1);
752 if( rc ){
753 vfslog_finalize(p);
755 return rc;
758 int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg){
759 sqlite3_vfs *pVfs;
760 pVfs = sqlite3_vfs_find(zVfs);
761 if( !pVfs || pVfs->xOpen!=vfslogOpen ){
762 return SQLITE_ERROR;
764 vfslog_call(pVfs, OS_ANNOTATE, 0, 0, 0, 0, 0);
765 vfslog_string(pVfs, zMsg);
766 return SQLITE_OK;
769 static const char *vfslog_eventname(int eEvent){
770 const char *zEvent = 0;
772 switch( eEvent ){
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;
801 return zEvent;
804 typedef struct VfslogVtab VfslogVtab;
805 typedef struct VfslogCsr VfslogCsr;
808 ** Virtual table type for the vfslog reader module.
810 struct VfslogVtab {
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.
820 struct VfslogCsr {
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 ) */
841 quote = z[0];
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 = ']';
846 while( z[iIn] ){
847 if( z[iIn]==quote ){
848 if( z[iIn+1]!=quote ) break;
849 z[iOut++] = quote;
850 iIn += 2;
851 }else{
852 z[iOut++] = z[iIn++];
855 z[iOut] = '\0';
859 #ifndef SQLITE_OMIT_VIRTUALTABLE
861 ** Connect to or create a vfslog virtual table.
863 static int vlogConnect(
864 sqlite3 *db,
865 void *pAux,
866 int argc, const char *const*argv,
867 sqlite3_vtab **ppVtab,
868 char **pzErr
870 sqlite3_vfs *pVfs; /* VFS used to read log file */
871 int flags; /* flags passed to pVfs->xOpen() */
872 VfslogVtab *p;
873 int rc;
874 int nByte;
875 char *zFile;
877 *ppVtab = 0;
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;
882 memset(p, 0, nByte);
884 p->pFd = (sqlite3_file *)&p[1];
885 p->zFile = &((char *)p->pFd)[pVfs->szOsFile];
887 zFile = sqlite3_mprintf("%s", argv[3]);
888 if( !zFile ){
889 sqlite3_free(p);
890 return SQLITE_NOMEM;
892 dequote(zFile);
893 pVfs->xFullPathname(pVfs, zFile, pVfs->mxPathname, p->zFile);
894 sqlite3_free(zFile);
896 flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_SUPER_JOURNAL;
897 rc = pVfs->xOpen(pVfs, p->zFile, p->pFd, flags, &flags);
899 if( rc==SQLITE_OK ){
900 p->pFd->pMethods->xFileSize(p->pFd, &p->nByte);
901 sqlite3_declare_vtab(db,
902 "CREATE TABLE xxx(event, file, click, rc, size, offset)"
904 *ppVtab = &p->base;
905 }else{
906 sqlite3_free(p);
909 return rc;
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;
918 return SQLITE_OK;
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;
930 sqlite3_free(p);
931 return SQLITE_OK;
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;
944 return SQLITE_OK;
948 ** Close a vfslog cursor.
950 static int vlogClose(sqlite3_vtab_cursor *pCursor){
951 VfslogCsr *p = (VfslogCsr *)pCursor;
952 int i;
953 for(i=0; i<p->nFile; i++){
954 sqlite3_free(p->azFile[i]);
956 sqlite3_free(p->azFile);
957 sqlite3_free(p->zTransient);
958 sqlite3_free(p);
959 return SQLITE_OK;
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;
968 int rc = SQLITE_OK;
969 int nRead;
971 sqlite3_free(pCsr->zTransient);
972 pCsr->zTransient = 0;
974 nRead = 24;
975 if( pCsr->iOffset+nRead<=p->nByte ){
976 int eEvent;
977 rc = p->pFd->pMethods->xRead(p->pFd, pCsr->aBuf, nRead, pCsr->iOffset);
979 eEvent = get32bits(pCsr->aBuf);
980 if( (rc==SQLITE_OK)
981 && (eEvent==OS_OPEN || eEvent==OS_DELETE || eEvent==OS_ACCESS)
983 char buf[4];
984 rc = p->pFd->pMethods->xRead(p->pFd, buf, 4, pCsr->iOffset+nRead);
985 nRead += 4;
986 if( rc==SQLITE_OK ){
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);
990 zStr[nStr] = '\0';
991 nRead += nStr;
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;
1004 }else{
1005 pCsr->zTransient = zStr;
1011 pCsr->iRowid += 1;
1012 pCsr->iOffset += nRead;
1013 return rc;
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;
1028 pCsr->iRowid = 0;
1029 pCsr->iOffset = 20;
1030 return vlogNext(pCursor);
1033 static int vlogColumn(
1034 sqlite3_vtab_cursor *pCursor,
1035 sqlite3_context *ctx,
1036 int i
1038 unsigned int val;
1039 VfslogCsr *pCsr = (VfslogCsr *)pCursor;
1041 assert( i<7 );
1042 val = get32bits(&pCsr->aBuf[4*i]);
1044 switch( i ){
1045 case 0: {
1046 sqlite3_result_text(ctx, vfslog_eventname(val), -1, SQLITE_STATIC);
1047 break;
1049 case 1: {
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);
1055 break;
1057 default:
1058 sqlite3_result_int(ctx, val);
1059 break;
1062 return SQLITE_OK;
1065 static int vlogRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
1066 VfslogCsr *pCsr = (VfslogCsr *)pCursor;
1067 *pRowid = pCsr->iRowid;
1068 return SQLITE_OK;
1071 int sqlite3_vfslog_register(sqlite3 *db){
1072 static sqlite3_module vfslog_module = {
1073 0, /* iVersion */
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 */
1086 0, /* xUpdate */
1087 0, /* xBegin */
1088 0, /* xSync */
1089 0, /* xCommit */
1090 0, /* xRollback */
1091 0, /* xFindMethod */
1092 0, /* xRename */
1093 0, /* xSavepoint */
1094 0, /* xRelease */
1095 0, /* xRollbackTo */
1096 0, /* xShadowName */
1097 0 /* xIntegrity */
1100 sqlite3_create_module(db, "vfslog", &vfslog_module, 0);
1101 return SQLITE_OK;
1103 #endif /* SQLITE_OMIT_VIRTUALTABLE */
1105 /**************************************************************************
1106 ***************************************************************************
1107 ** Tcl interface starts here.
1110 #if defined(SQLITE_TEST) || defined(TCLSH)
1112 #if defined(INCLUDE_SQLITE_TCL_H)
1113 # include "sqlite_tcl.h"
1114 #else
1115 # include "tcl.h"
1116 # ifndef SQLITE_TCLAPI
1117 # define SQLITE_TCLAPI
1118 # endif
1119 #endif
1121 static int SQLITE_TCLAPI test_vfslog(
1122 void *clientData,
1123 Tcl_Interp *interp,
1124 int objc,
1125 Tcl_Obj *CONST objv[]
1127 struct SqliteDb { sqlite3 *db; };
1128 sqlite3 *db;
1129 Tcl_CmdInfo cmdInfo;
1130 int rc = SQLITE_ERROR;
1132 static const char *strs[] = { "annotate", "finalize", "new", "register", 0 };
1133 enum VL_enum { VL_ANNOTATE, VL_FINALIZE, VL_NEW, VL_REGISTER };
1134 int iSub;
1136 if( objc<2 ){
1137 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
1138 return TCL_ERROR;
1140 if( Tcl_GetIndexFromObj(interp, objv[1], strs, "sub-command", 0, &iSub) ){
1141 return TCL_ERROR;
1144 switch( (enum VL_enum)iSub ){
1145 case VL_ANNOTATE: {
1146 char *zVfs;
1147 char *zMsg;
1148 if( objc!=4 ){
1149 Tcl_WrongNumArgs(interp, 3, objv, "VFS");
1150 return TCL_ERROR;
1152 zVfs = Tcl_GetString(objv[2]);
1153 zMsg = Tcl_GetString(objv[3]);
1154 rc = sqlite3_vfslog_annotate(zVfs, zMsg);
1155 if( rc!=SQLITE_OK ){
1156 Tcl_AppendResult(interp, "failed", 0);
1157 return TCL_ERROR;
1159 break;
1161 case VL_FINALIZE: {
1162 char *zVfs;
1163 if( objc!=3 ){
1164 Tcl_WrongNumArgs(interp, 2, objv, "VFS");
1165 return TCL_ERROR;
1167 zVfs = Tcl_GetString(objv[2]);
1168 rc = sqlite3_vfslog_finalize(zVfs);
1169 if( rc!=SQLITE_OK ){
1170 Tcl_AppendResult(interp, "failed", 0);
1171 return TCL_ERROR;
1173 break;
1176 case VL_NEW: {
1177 char *zVfs;
1178 char *zParent;
1179 char *zLog;
1180 if( objc!=5 ){
1181 Tcl_WrongNumArgs(interp, 2, objv, "VFS PARENT LOGFILE");
1182 return TCL_ERROR;
1184 zVfs = Tcl_GetString(objv[2]);
1185 zParent = Tcl_GetString(objv[3]);
1186 zLog = Tcl_GetString(objv[4]);
1187 if( *zParent=='\0' ) zParent = 0;
1188 rc = sqlite3_vfslog_new(zVfs, zParent, zLog);
1189 if( rc!=SQLITE_OK ){
1190 Tcl_AppendResult(interp, "failed", 0);
1191 return TCL_ERROR;
1193 break;
1196 case VL_REGISTER: {
1197 char *zDb;
1198 if( objc!=3 ){
1199 Tcl_WrongNumArgs(interp, 2, objv, "DB");
1200 return TCL_ERROR;
1202 #ifdef SQLITE_OMIT_VIRTUALTABLE
1203 Tcl_AppendResult(interp, "vfslog not available because of "
1204 "SQLITE_OMIT_VIRTUALTABLE", (void*)0);
1205 return TCL_ERROR;
1206 #else
1207 zDb = Tcl_GetString(objv[2]);
1208 if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
1209 db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
1210 rc = sqlite3_vfslog_register(db);
1212 if( rc!=SQLITE_OK ){
1213 Tcl_AppendResult(interp, "bad sqlite3 handle: ", zDb, (void*)0);
1214 return TCL_ERROR;
1216 break;
1217 #endif
1221 return TCL_OK;
1224 int SqlitetestOsinst_Init(Tcl_Interp *interp){
1225 Tcl_CreateObjCommand(interp, "vfslog", test_vfslog, 0, 0);
1226 return TCL_OK;
1229 #endif /* SQLITE_TEST */