- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / sqlite / src / src / test_osinst.c
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.
10 **
11 ******************************************************************************
12 **
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.
16 */
17
18 /*
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.
23 **
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.
29 **
30 ** The binary log files are read using a virtual table implementation
31 ** also contained in this file. 
32 **
33 ** CREATING LOG FILES:
34 **
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 **       );
40 **
41 **       int sqlite3_vfslog_finalize(const char *zVfs);
42 **
43 ** ANNOTATING LOG FILES:
44 **
45 **   To write an arbitrary message into a log file:
46 **
47 **       int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg);
48 **
49 ** READING LOG FILES:
50 **
51 **   Log files are read using the "vfslog" virtual table implementation
52 **   in this file. To register the virtual table with SQLite, use:
53 **
54 **       int sqlite3_vfslog_register(sqlite3 *db);
55 **
56 **   Then, if the log file is named "vfs.log", the following SQL command:
57 **
58 **       CREATE VIRTUAL TABLE v USING vfslog('vfs.log');
59 **
60 **   creates a virtual table with 6 columns, as follows:
61 **
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 **       );
70 */
71
72 #include "sqlite3.h"
73 #include <string.h>
74 #include <assert.h>
75
76
77 /*
78 ** Maximum pathname length supported by the vfslog backend.
79 */
80 #define INST_MAX_PATHNAME 512
81
82 #define OS_ACCESS            1
83 #define OS_CHECKRESERVEDLOCK 2
84 #define OS_CLOSE             3
85 #define OS_CURRENTTIME       4
86 #define OS_DELETE            5
87 #define OS_DEVCHAR           6
88 #define OS_FILECONTROL       7
89 #define OS_FILESIZE          8
90 #define OS_FULLPATHNAME      9
91 #define OS_LOCK              11
92 #define OS_OPEN              12
93 #define OS_RANDOMNESS        13
94 #define OS_READ              14 
95 #define OS_SECTORSIZE        15
96 #define OS_SLEEP             16
97 #define OS_SYNC              17
98 #define OS_TRUNCATE          18
99 #define OS_UNLOCK            19
100 #define OS_WRITE             20
101 #define OS_SHMUNMAP          22
102 #define OS_SHMMAP            23
103 #define OS_SHMLOCK           25
104 #define OS_SHMBARRIER        26
105 #define OS_ANNOTATE          28
106
107 #define OS_NUMEVENTS         29
108
109 #define VFSLOG_BUFFERSIZE 8192
110
111 typedef struct VfslogVfs VfslogVfs;
112 typedef struct VfslogFile VfslogFile;
113
114 struct VfslogVfs {
115   sqlite3_vfs base;               /* VFS methods */
116   sqlite3_vfs *pVfs;              /* Parent VFS */
117   int iNextFileId;                /* Next file id */
118   sqlite3_file *pLog;             /* Log file handle */
119   sqlite3_int64 iOffset;          /* Log file offset of start of write buffer */
120   int nBuf;                       /* Number of valid bytes in aBuf[] */
121   char aBuf[VFSLOG_BUFFERSIZE];   /* Write buffer */
122 };
123
124 struct VfslogFile {
125   sqlite3_file base;              /* IO methods */
126   sqlite3_file *pReal;            /* Underlying file handle */
127   sqlite3_vfs *pVfslog;           /* Associated VsflogVfs object */
128   int iFileId;                    /* File id number */
129 };
130
131 #define REALVFS(p) (((VfslogVfs *)(p))->pVfs)
132
133
134
135 /*
136 ** Method declarations for vfslog_file.
137 */
138 static int vfslogClose(sqlite3_file*);
139 static int vfslogRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
140 static int vfslogWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
141 static int vfslogTruncate(sqlite3_file*, sqlite3_int64 size);
142 static int vfslogSync(sqlite3_file*, int flags);
143 static int vfslogFileSize(sqlite3_file*, sqlite3_int64 *pSize);
144 static int vfslogLock(sqlite3_file*, int);
145 static int vfslogUnlock(sqlite3_file*, int);
146 static int vfslogCheckReservedLock(sqlite3_file*, int *pResOut);
147 static int vfslogFileControl(sqlite3_file*, int op, void *pArg);
148 static int vfslogSectorSize(sqlite3_file*);
149 static int vfslogDeviceCharacteristics(sqlite3_file*);
150
151 static int vfslogShmLock(sqlite3_file *pFile, int ofst, int n, int flags);
152 static int vfslogShmMap(sqlite3_file *pFile,int,int,int,volatile void **);
153 static void vfslogShmBarrier(sqlite3_file*);
154 static int vfslogShmUnmap(sqlite3_file *pFile, int deleteFlag);
155
156 /*
157 ** Method declarations for vfslog_vfs.
158 */
159 static int vfslogOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
160 static int vfslogDelete(sqlite3_vfs*, const char *zName, int syncDir);
161 static int vfslogAccess(sqlite3_vfs*, const char *zName, int flags, int *);
162 static int vfslogFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
163 static void *vfslogDlOpen(sqlite3_vfs*, const char *zFilename);
164 static void vfslogDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
165 static void (*vfslogDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
166 static void vfslogDlClose(sqlite3_vfs*, void*);
167 static int vfslogRandomness(sqlite3_vfs*, int nByte, char *zOut);
168 static int vfslogSleep(sqlite3_vfs*, int microseconds);
169 static int vfslogCurrentTime(sqlite3_vfs*, double*);
170
171 static int vfslogGetLastError(sqlite3_vfs*, int, char *);
172 static int vfslogCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
173
174 static sqlite3_vfs vfslog_vfs = {
175   1,                              /* iVersion */
176   sizeof(VfslogFile),             /* szOsFile */
177   INST_MAX_PATHNAME,              /* mxPathname */
178   0,                              /* pNext */
179   0,                              /* zName */
180   0,                              /* pAppData */
181   vfslogOpen,                     /* xOpen */
182   vfslogDelete,                   /* xDelete */
183   vfslogAccess,                   /* xAccess */
184   vfslogFullPathname,             /* xFullPathname */
185   vfslogDlOpen,                   /* xDlOpen */
186   vfslogDlError,                  /* xDlError */
187   vfslogDlSym,                    /* xDlSym */
188   vfslogDlClose,                  /* xDlClose */
189   vfslogRandomness,               /* xRandomness */
190   vfslogSleep,                    /* xSleep */
191   vfslogCurrentTime,              /* xCurrentTime */
192   vfslogGetLastError,             /* xGetLastError */
193   vfslogCurrentTimeInt64          /* xCurrentTime */
194 };
195
196 static sqlite3_io_methods vfslog_io_methods = {
197   2,                              /* iVersion */
198   vfslogClose,                    /* xClose */
199   vfslogRead,                     /* xRead */
200   vfslogWrite,                    /* xWrite */
201   vfslogTruncate,                 /* xTruncate */
202   vfslogSync,                     /* xSync */
203   vfslogFileSize,                 /* xFileSize */
204   vfslogLock,                     /* xLock */
205   vfslogUnlock,                   /* xUnlock */
206   vfslogCheckReservedLock,        /* xCheckReservedLock */
207   vfslogFileControl,              /* xFileControl */
208   vfslogSectorSize,               /* xSectorSize */
209   vfslogDeviceCharacteristics,    /* xDeviceCharacteristics */
210   vfslogShmMap,                   /* xShmMap */
211   vfslogShmLock,                  /* xShmLock */
212   vfslogShmBarrier,               /* xShmBarrier */
213   vfslogShmUnmap                  /* xShmUnmap */
214 };
215
216 #if SQLITE_OS_UNIX && !defined(NO_GETTOD)
217 #include <sys/time.h>
218 static sqlite3_uint64 vfslog_time(){
219   struct timeval sTime;
220   gettimeofday(&sTime, 0);
221   return sTime.tv_usec + (sqlite3_uint64)sTime.tv_sec * 1000000;
222 }
223 #elif SQLITE_OS_WIN
224 #include <windows.h>
225 #include <time.h>
226 static sqlite3_uint64 vfslog_time(){
227   FILETIME ft;
228   sqlite3_uint64 u64time = 0;
229  
230   GetSystemTimeAsFileTime(&ft);
231
232   u64time |= ft.dwHighDateTime;
233   u64time <<= 32;
234   u64time |= ft.dwLowDateTime;
235
236   /* ft is 100-nanosecond intervals, we want microseconds */
237   return u64time /(sqlite3_uint64)10;
238 }
239 #else
240 static sqlite3_uint64 vfslog_time(){
241   return 0;
242 }
243 #endif
244
245 static void vfslog_call(sqlite3_vfs *, int, int, int, int, int, int);
246 static void vfslog_string(sqlite3_vfs *, const char *);
247
248 /*
249 ** Close an vfslog-file.
250 */
251 static int vfslogClose(sqlite3_file *pFile){
252   sqlite3_uint64 t;
253   int rc = SQLITE_OK;
254   VfslogFile *p = (VfslogFile *)pFile;
255
256   t = vfslog_time();
257   if( p->pReal->pMethods ){
258     rc = p->pReal->pMethods->xClose(p->pReal);
259   }
260   t = vfslog_time() - t;
261   vfslog_call(p->pVfslog, OS_CLOSE, p->iFileId, t, rc, 0, 0);
262   return rc;
263 }
264
265 /*
266 ** Read data from an vfslog-file.
267 */
268 static int vfslogRead(
269   sqlite3_file *pFile, 
270   void *zBuf, 
271   int iAmt, 
272   sqlite_int64 iOfst
273 ){
274   int rc;
275   sqlite3_uint64 t;
276   VfslogFile *p = (VfslogFile *)pFile;
277   t = vfslog_time();
278   rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
279   t = vfslog_time() - t;
280   vfslog_call(p->pVfslog, OS_READ, p->iFileId, t, rc, iAmt, (int)iOfst);
281   return rc;
282 }
283
284 /*
285 ** Write data to an vfslog-file.
286 */
287 static int vfslogWrite(
288   sqlite3_file *pFile,
289   const void *z,
290   int iAmt,
291   sqlite_int64 iOfst
292 ){
293   int rc;
294   sqlite3_uint64 t;
295   VfslogFile *p = (VfslogFile *)pFile;
296   t = vfslog_time();
297   rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst);
298   t = vfslog_time() - t;
299   vfslog_call(p->pVfslog, OS_WRITE, p->iFileId, t, rc, iAmt, (int)iOfst);
300   return rc;
301 }
302
303 /*
304 ** Truncate an vfslog-file.
305 */
306 static int vfslogTruncate(sqlite3_file *pFile, sqlite_int64 size){
307   int rc;
308   sqlite3_uint64 t;
309   VfslogFile *p = (VfslogFile *)pFile;
310   t = vfslog_time();
311   rc = p->pReal->pMethods->xTruncate(p->pReal, size);
312   t = vfslog_time() - t;
313   vfslog_call(p->pVfslog, OS_TRUNCATE, p->iFileId, t, rc, 0, (int)size);
314   return rc;
315 }
316
317 /*
318 ** Sync an vfslog-file.
319 */
320 static int vfslogSync(sqlite3_file *pFile, int flags){
321   int rc;
322   sqlite3_uint64 t;
323   VfslogFile *p = (VfslogFile *)pFile;
324   t = vfslog_time();
325   rc = p->pReal->pMethods->xSync(p->pReal, flags);
326   t = vfslog_time() - t;
327   vfslog_call(p->pVfslog, OS_SYNC, p->iFileId, t, rc, flags, 0);
328   return rc;
329 }
330
331 /*
332 ** Return the current file-size of an vfslog-file.
333 */
334 static int vfslogFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
335   int rc;
336   sqlite3_uint64 t;
337   VfslogFile *p = (VfslogFile *)pFile;
338   t = vfslog_time();
339   rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
340   t = vfslog_time() - t;
341   vfslog_call(p->pVfslog, OS_FILESIZE, p->iFileId, t, rc, 0, (int)*pSize);
342   return rc;
343 }
344
345 /*
346 ** Lock an vfslog-file.
347 */
348 static int vfslogLock(sqlite3_file *pFile, int eLock){
349   int rc;
350   sqlite3_uint64 t;
351   VfslogFile *p = (VfslogFile *)pFile;
352   t = vfslog_time();
353   rc = p->pReal->pMethods->xLock(p->pReal, eLock);
354   t = vfslog_time() - t;
355   vfslog_call(p->pVfslog, OS_LOCK, p->iFileId, t, rc, eLock, 0);
356   return rc;
357 }
358
359 /*
360 ** Unlock an vfslog-file.
361 */
362 static int vfslogUnlock(sqlite3_file *pFile, int eLock){
363   int rc;
364   sqlite3_uint64 t;
365   VfslogFile *p = (VfslogFile *)pFile;
366   t = vfslog_time();
367   rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
368   t = vfslog_time() - t;
369   vfslog_call(p->pVfslog, OS_UNLOCK, p->iFileId, t, rc, eLock, 0);
370   return rc;
371 }
372
373 /*
374 ** Check if another file-handle holds a RESERVED lock on an vfslog-file.
375 */
376 static int vfslogCheckReservedLock(sqlite3_file *pFile, int *pResOut){
377   int rc;
378   sqlite3_uint64 t;
379   VfslogFile *p = (VfslogFile *)pFile;
380   t = vfslog_time();
381   rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
382   t = vfslog_time() - t;
383   vfslog_call(p->pVfslog, OS_CHECKRESERVEDLOCK, p->iFileId, t, rc, *pResOut, 0);
384   return rc;
385 }
386
387 /*
388 ** File control method. For custom operations on an vfslog-file.
389 */
390 static int vfslogFileControl(sqlite3_file *pFile, int op, void *pArg){
391   VfslogFile *p = (VfslogFile *)pFile;
392   return p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
393 }
394
395 /*
396 ** Return the sector-size in bytes for an vfslog-file.
397 */
398 static int vfslogSectorSize(sqlite3_file *pFile){
399   int rc;
400   sqlite3_uint64 t;
401   VfslogFile *p = (VfslogFile *)pFile;
402   t = vfslog_time();
403   rc = p->pReal->pMethods->xSectorSize(p->pReal);
404   t = vfslog_time() - t;
405   vfslog_call(p->pVfslog, OS_SECTORSIZE, p->iFileId, t, rc, 0, 0);
406   return rc;
407 }
408
409 /*
410 ** Return the device characteristic flags supported by an vfslog-file.
411 */
412 static int vfslogDeviceCharacteristics(sqlite3_file *pFile){
413   int rc;
414   sqlite3_uint64 t;
415   VfslogFile *p = (VfslogFile *)pFile;
416   t = vfslog_time();
417   rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
418   t = vfslog_time() - t;
419   vfslog_call(p->pVfslog, OS_DEVCHAR, p->iFileId, t, rc, 0, 0);
420   return rc;
421 }
422
423 static int vfslogShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
424   int rc;
425   sqlite3_uint64 t;
426   VfslogFile *p = (VfslogFile *)pFile;
427   t = vfslog_time();
428   rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
429   t = vfslog_time() - t;
430   vfslog_call(p->pVfslog, OS_SHMLOCK, p->iFileId, t, rc, 0, 0);
431   return rc;
432 }
433 static int vfslogShmMap(
434   sqlite3_file *pFile, 
435   int iRegion, 
436   int szRegion, 
437   int isWrite, 
438   volatile void **pp
439 ){
440   int rc;
441   sqlite3_uint64 t;
442   VfslogFile *p = (VfslogFile *)pFile;
443   t = vfslog_time();
444   rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
445   t = vfslog_time() - t;
446   vfslog_call(p->pVfslog, OS_SHMMAP, p->iFileId, t, rc, 0, 0);
447   return rc;
448 }
449 static void vfslogShmBarrier(sqlite3_file *pFile){
450   sqlite3_uint64 t;
451   VfslogFile *p = (VfslogFile *)pFile;
452   t = vfslog_time();
453   p->pReal->pMethods->xShmBarrier(p->pReal);
454   t = vfslog_time() - t;
455   vfslog_call(p->pVfslog, OS_SHMBARRIER, p->iFileId, t, SQLITE_OK, 0, 0);
456 }
457 static int vfslogShmUnmap(sqlite3_file *pFile, int deleteFlag){
458   int rc;
459   sqlite3_uint64 t;
460   VfslogFile *p = (VfslogFile *)pFile;
461   t = vfslog_time();
462   rc = p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag);
463   t = vfslog_time() - t;
464   vfslog_call(p->pVfslog, OS_SHMUNMAP, p->iFileId, t, rc, 0, 0);
465   return rc;
466 }
467
468
469 /*
470 ** Open an vfslog file handle.
471 */
472 static int vfslogOpen(
473   sqlite3_vfs *pVfs,
474   const char *zName,
475   sqlite3_file *pFile,
476   int flags,
477   int *pOutFlags
478 ){
479   int rc;
480   sqlite3_uint64 t;
481   VfslogFile *p = (VfslogFile *)pFile;
482   VfslogVfs *pLog = (VfslogVfs *)pVfs;
483
484   pFile->pMethods = &vfslog_io_methods;
485   p->pReal = (sqlite3_file *)&p[1];
486   p->pVfslog = pVfs;
487   p->iFileId = ++pLog->iNextFileId;
488
489   t = vfslog_time();
490   rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags);
491   t = vfslog_time() - t;
492
493   vfslog_call(pVfs, OS_OPEN, p->iFileId, t, rc, 0, 0);
494   vfslog_string(pVfs, zName);
495   return rc;
496 }
497
498 /*
499 ** Delete the file located at zPath. If the dirSync argument is true,
500 ** ensure the file-system modifications are synced to disk before
501 ** returning.
502 */
503 static int vfslogDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
504   int rc;
505   sqlite3_uint64 t;
506   t = vfslog_time();
507   rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync);
508   t = vfslog_time() - t;
509   vfslog_call(pVfs, OS_DELETE, 0, t, rc, dirSync, 0);
510   vfslog_string(pVfs, zPath);
511   return rc;
512 }
513
514 /*
515 ** Test for access permissions. Return true if the requested permission
516 ** is available, or false otherwise.
517 */
518 static int vfslogAccess(
519   sqlite3_vfs *pVfs, 
520   const char *zPath, 
521   int flags, 
522   int *pResOut
523 ){
524   int rc;
525   sqlite3_uint64 t;
526   t = vfslog_time();
527   rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut);
528   t = vfslog_time() - t;
529   vfslog_call(pVfs, OS_ACCESS, 0, t, rc, flags, *pResOut);
530   vfslog_string(pVfs, zPath);
531   return rc;
532 }
533
534 /*
535 ** Populate buffer zOut with the full canonical pathname corresponding
536 ** to the pathname in zPath. zOut is guaranteed to point to a buffer
537 ** of at least (INST_MAX_PATHNAME+1) bytes.
538 */
539 static int vfslogFullPathname(
540   sqlite3_vfs *pVfs, 
541   const char *zPath, 
542   int nOut, 
543   char *zOut
544 ){
545   return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
546 }
547
548 /*
549 ** Open the dynamic library located at zPath and return a handle.
550 */
551 static void *vfslogDlOpen(sqlite3_vfs *pVfs, const char *zPath){
552   return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
553 }
554
555 /*
556 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
557 ** utf-8 string describing the most recent error encountered associated 
558 ** with dynamic libraries.
559 */
560 static void vfslogDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
561   REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
562 }
563
564 /*
565 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
566 */
567 static void (*vfslogDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
568   return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym);
569 }
570
571 /*
572 ** Close the dynamic library handle pHandle.
573 */
574 static void vfslogDlClose(sqlite3_vfs *pVfs, void *pHandle){
575   REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
576 }
577
578 /*
579 ** Populate the buffer pointed to by zBufOut with nByte bytes of 
580 ** random data.
581 */
582 static int vfslogRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
583   return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
584 }
585
586 /*
587 ** Sleep for nMicro microseconds. Return the number of microseconds 
588 ** actually slept.
589 */
590 static int vfslogSleep(sqlite3_vfs *pVfs, int nMicro){
591   return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro);
592 }
593
594 /*
595 ** Return the current time as a Julian Day number in *pTimeOut.
596 */
597 static int vfslogCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
598   return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut);
599 }
600
601 static int vfslogGetLastError(sqlite3_vfs *pVfs, int a, char *b){
602   return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b);
603 }
604 static int vfslogCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
605   return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p);
606 }
607
608 static void vfslog_flush(VfslogVfs *p){
609 #ifdef SQLITE_TEST
610   extern int sqlite3_io_error_pending;
611   extern int sqlite3_io_error_persist;
612   extern int sqlite3_diskfull_pending;
613
614   int pending = sqlite3_io_error_pending;
615   int persist = sqlite3_io_error_persist;
616   int diskfull = sqlite3_diskfull_pending;
617
618   sqlite3_io_error_pending = 0;
619   sqlite3_io_error_persist = 0;
620   sqlite3_diskfull_pending = 0;
621 #endif
622
623   if( p->nBuf ){
624     p->pLog->pMethods->xWrite(p->pLog, p->aBuf, p->nBuf, p->iOffset);
625     p->iOffset += p->nBuf;
626     p->nBuf = 0;
627   }
628
629 #ifdef SQLITE_TEST
630   sqlite3_io_error_pending = pending;
631   sqlite3_io_error_persist = persist;
632   sqlite3_diskfull_pending = diskfull;
633 #endif
634 }
635
636 static void put32bits(unsigned char *p, unsigned int v){
637   p[0] = v>>24;
638   p[1] = v>>16;
639   p[2] = v>>8;
640   p[3] = v;
641 }
642
643 static void vfslog_call(
644   sqlite3_vfs *pVfs,
645   int eEvent,
646   int iFileid,
647   int nClick,
648   int return_code,
649   int size,
650   int offset
651 ){
652   VfslogVfs *p = (VfslogVfs *)pVfs;
653   unsigned char *zRec;
654   if( (24+p->nBuf)>sizeof(p->aBuf) ){
655     vfslog_flush(p);
656   }
657   zRec = (unsigned char *)&p->aBuf[p->nBuf];
658   put32bits(&zRec[0], eEvent);
659   put32bits(&zRec[4], iFileid);
660   put32bits(&zRec[8], nClick);
661   put32bits(&zRec[12], return_code);
662   put32bits(&zRec[16], size);
663   put32bits(&zRec[20], offset);
664   p->nBuf += 24;
665 }
666
667 static void vfslog_string(sqlite3_vfs *pVfs, const char *zStr){
668   VfslogVfs *p = (VfslogVfs *)pVfs;
669   unsigned char *zRec;
670   int nStr = zStr ? strlen(zStr) : 0;
671   if( (4+nStr+p->nBuf)>sizeof(p->aBuf) ){
672     vfslog_flush(p);
673   }
674   zRec = (unsigned char *)&p->aBuf[p->nBuf];
675   put32bits(&zRec[0], nStr);
676   if( zStr ){
677     memcpy(&zRec[4], zStr, nStr);
678   }
679   p->nBuf += (4 + nStr);
680 }
681
682 static void vfslog_finalize(VfslogVfs *p){
683   if( p->pLog->pMethods ){
684     vfslog_flush(p);
685     p->pLog->pMethods->xClose(p->pLog);
686   }
687   sqlite3_free(p);
688 }
689
690 int sqlite3_vfslog_finalize(const char *zVfs){
691   sqlite3_vfs *pVfs;
692   pVfs = sqlite3_vfs_find(zVfs);
693   if( !pVfs || pVfs->xOpen!=vfslogOpen ){
694     return SQLITE_ERROR;
695   } 
696   sqlite3_vfs_unregister(pVfs);
697   vfslog_finalize((VfslogVfs *)pVfs);
698   return SQLITE_OK;
699 }
700
701 int sqlite3_vfslog_new(
702   const char *zVfs,               /* New VFS name */
703   const char *zParentVfs,         /* Parent VFS name (or NULL) */
704   const char *zLog                /* Log file name */
705 ){
706   VfslogVfs *p;
707   sqlite3_vfs *pParent;
708   int nByte;
709   int flags;
710   int rc;
711   char *zFile;
712   int nVfs;
713
714   pParent = sqlite3_vfs_find(zParentVfs);
715   if( !pParent ){
716     return SQLITE_ERROR;
717   }
718
719   nVfs = strlen(zVfs);
720   nByte = sizeof(VfslogVfs) + pParent->szOsFile + nVfs+1+pParent->mxPathname+1;
721   p = (VfslogVfs *)sqlite3_malloc(nByte);
722   memset(p, 0, nByte);
723
724   p->pVfs = pParent;
725   p->pLog = (sqlite3_file *)&p[1];
726   memcpy(&p->base, &vfslog_vfs, sizeof(sqlite3_vfs));
727   p->base.zName = &((char *)p->pLog)[pParent->szOsFile];
728   p->base.szOsFile += pParent->szOsFile;
729   memcpy((char *)p->base.zName, zVfs, nVfs);
730
731   zFile = (char *)&p->base.zName[nVfs+1];
732   pParent->xFullPathname(pParent, zLog, pParent->mxPathname, zFile);
733
734   flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MASTER_JOURNAL;
735   pParent->xDelete(pParent, zFile, 0);
736   rc = pParent->xOpen(pParent, zFile, p->pLog, flags, &flags);
737   if( rc==SQLITE_OK ){
738     memcpy(p->aBuf, "sqlite_ostrace1.....", 20);
739     p->iOffset = 0;
740     p->nBuf = 20;
741     rc = sqlite3_vfs_register((sqlite3_vfs *)p, 1);
742   }
743   if( rc ){
744     vfslog_finalize(p);
745   }
746   return rc;
747 }
748
749 int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg){
750   sqlite3_vfs *pVfs;
751   pVfs = sqlite3_vfs_find(zVfs);
752   if( !pVfs || pVfs->xOpen!=vfslogOpen ){
753     return SQLITE_ERROR;
754   } 
755   vfslog_call(pVfs, OS_ANNOTATE, 0, 0, 0, 0, 0);
756   vfslog_string(pVfs, zMsg);
757   return SQLITE_OK;
758 }
759
760 static const char *vfslog_eventname(int eEvent){
761   const char *zEvent = 0;
762
763   switch( eEvent ){
764     case OS_CLOSE:             zEvent = "xClose"; break;
765     case OS_READ:              zEvent = "xRead"; break;
766     case OS_WRITE:             zEvent = "xWrite"; break;
767     case OS_TRUNCATE:          zEvent = "xTruncate"; break;
768     case OS_SYNC:              zEvent = "xSync"; break;
769     case OS_FILESIZE:          zEvent = "xFilesize"; break;
770     case OS_LOCK:              zEvent = "xLock"; break;
771     case OS_UNLOCK:            zEvent = "xUnlock"; break;
772     case OS_CHECKRESERVEDLOCK: zEvent = "xCheckResLock"; break;
773     case OS_FILECONTROL:       zEvent = "xFileControl"; break;
774     case OS_SECTORSIZE:        zEvent = "xSectorSize"; break;
775     case OS_DEVCHAR:           zEvent = "xDeviceChar"; break;
776     case OS_OPEN:              zEvent = "xOpen"; break;
777     case OS_DELETE:            zEvent = "xDelete"; break;
778     case OS_ACCESS:            zEvent = "xAccess"; break;
779     case OS_FULLPATHNAME:      zEvent = "xFullPathname"; break;
780     case OS_RANDOMNESS:        zEvent = "xRandomness"; break;
781     case OS_SLEEP:             zEvent = "xSleep"; break;
782     case OS_CURRENTTIME:       zEvent = "xCurrentTime"; break;
783
784     case OS_SHMUNMAP:          zEvent = "xShmUnmap"; break;
785     case OS_SHMLOCK:           zEvent = "xShmLock"; break;
786     case OS_SHMBARRIER:        zEvent = "xShmBarrier"; break;
787     case OS_SHMMAP:            zEvent = "xShmMap"; break;
788
789     case OS_ANNOTATE:          zEvent = "annotation"; break;
790   }
791
792   return zEvent;
793 }
794
795 typedef struct VfslogVtab VfslogVtab;
796 typedef struct VfslogCsr VfslogCsr;
797
798 /*
799 ** Virtual table type for the vfslog reader module.
800 */
801 struct VfslogVtab {
802   sqlite3_vtab base;              /* Base class */
803   sqlite3_file *pFd;              /* File descriptor open on vfslog file */
804   sqlite3_int64 nByte;            /* Size of file in bytes */
805   char *zFile;                    /* File name for pFd */
806 };
807
808 /*
809 ** Virtual table cursor type for the vfslog reader module.
810 */
811 struct VfslogCsr {
812   sqlite3_vtab_cursor base;       /* Base class */
813   sqlite3_int64 iRowid;           /* Current rowid. */
814   sqlite3_int64 iOffset;          /* Offset of next record in file */
815   char *zTransient;               /* Transient 'file' string */
816   int nFile;                      /* Size of array azFile[] */
817   char **azFile;                  /* File strings */
818   unsigned char aBuf[1024];       /* Current vfs log entry (read from file) */
819 };
820
821 static unsigned int get32bits(unsigned char *p){
822   return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
823 }
824
825 /*
826 ** The argument must point to a buffer containing a nul-terminated string.
827 ** If the string begins with an SQL quote character it is overwritten by
828 ** the dequoted version. Otherwise the buffer is left unmodified.
829 */
830 static void dequote(char *z){
831   char quote;                     /* Quote character (if any ) */
832   quote = z[0];
833   if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){
834     int iIn = 1;                  /* Index of next byte to read from input */
835     int iOut = 0;                 /* Index of next byte to write to output */
836     if( quote=='[' ) quote = ']';  
837     while( z[iIn] ){
838       if( z[iIn]==quote ){
839         if( z[iIn+1]!=quote ) break;
840         z[iOut++] = quote;
841         iIn += 2;
842       }else{
843         z[iOut++] = z[iIn++];
844       }
845     }
846     z[iOut] = '\0';
847   }
848 }
849
850 #ifndef SQLITE_OMIT_VIRTUALTABLE
851 /*
852 ** Connect to or create a vfslog virtual table.
853 */
854 static int vlogConnect(
855   sqlite3 *db,
856   void *pAux,
857   int argc, const char *const*argv,
858   sqlite3_vtab **ppVtab,
859   char **pzErr
860 ){
861   sqlite3_vfs *pVfs;              /* VFS used to read log file */
862   int flags;                      /* flags passed to pVfs->xOpen() */
863   VfslogVtab *p;
864   int rc;
865   int nByte;
866   char *zFile;
867
868   *ppVtab = 0;
869   pVfs = sqlite3_vfs_find(0);
870   nByte = sizeof(VfslogVtab) + pVfs->szOsFile + pVfs->mxPathname;
871   p = sqlite3_malloc(nByte);
872   if( p==0 ) return SQLITE_NOMEM;
873   memset(p, 0, nByte);
874
875   p->pFd = (sqlite3_file *)&p[1];
876   p->zFile = &((char *)p->pFd)[pVfs->szOsFile];
877
878   zFile = sqlite3_mprintf("%s", argv[3]);
879   if( !zFile ){
880     sqlite3_free(p);
881     return SQLITE_NOMEM;
882   }
883   dequote(zFile);
884   pVfs->xFullPathname(pVfs, zFile, pVfs->mxPathname, p->zFile);
885   sqlite3_free(zFile);
886
887   flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MASTER_JOURNAL;
888   rc = pVfs->xOpen(pVfs, p->zFile, p->pFd, flags, &flags);
889
890   if( rc==SQLITE_OK ){
891     p->pFd->pMethods->xFileSize(p->pFd, &p->nByte);
892     sqlite3_declare_vtab(db, 
893         "CREATE TABLE xxx(event, file, click, rc, size, offset)"
894     );
895     *ppVtab = &p->base;
896   }else{
897     sqlite3_free(p);
898   }
899
900   return rc;
901 }
902
903 /*
904 ** There is no "best-index". This virtual table always does a linear
905 ** scan of the binary VFS log file.
906 */
907 static int vlogBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
908   pIdxInfo->estimatedCost = 10.0;
909   return SQLITE_OK;
910 }
911
912 /*
913 ** Disconnect from or destroy a vfslog virtual table.
914 */
915 static int vlogDisconnect(sqlite3_vtab *pVtab){
916   VfslogVtab *p = (VfslogVtab *)pVtab;
917   if( p->pFd->pMethods ){
918     p->pFd->pMethods->xClose(p->pFd);
919     p->pFd->pMethods = 0;
920   }
921   sqlite3_free(p);
922   return SQLITE_OK;
923 }
924
925 /*
926 ** Open a new vfslog cursor.
927 */
928 static int vlogOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
929   VfslogCsr *pCsr;                /* Newly allocated cursor object */
930
931   pCsr = sqlite3_malloc(sizeof(VfslogCsr));
932   if( !pCsr ) return SQLITE_NOMEM;
933   memset(pCsr, 0, sizeof(VfslogCsr));
934   *ppCursor = &pCsr->base;
935   return SQLITE_OK;
936 }
937
938 /*
939 ** Close a vfslog cursor.
940 */
941 static int vlogClose(sqlite3_vtab_cursor *pCursor){
942   VfslogCsr *p = (VfslogCsr *)pCursor;
943   int i;
944   for(i=0; i<p->nFile; i++){
945     sqlite3_free(p->azFile[i]);
946   }
947   sqlite3_free(p->azFile);
948   sqlite3_free(p->zTransient);
949   sqlite3_free(p);
950   return SQLITE_OK;
951 }
952
953 /*
954 ** Move a vfslog cursor to the next entry in the file.
955 */
956 static int vlogNext(sqlite3_vtab_cursor *pCursor){
957   VfslogCsr *pCsr = (VfslogCsr *)pCursor;
958   VfslogVtab *p = (VfslogVtab *)pCursor->pVtab;
959   int rc = SQLITE_OK;
960   int nRead;
961
962   sqlite3_free(pCsr->zTransient);
963   pCsr->zTransient = 0;
964
965   nRead = 24;
966   if( pCsr->iOffset+nRead<=p->nByte ){
967     int eEvent;
968     rc = p->pFd->pMethods->xRead(p->pFd, pCsr->aBuf, nRead, pCsr->iOffset);
969
970     eEvent = get32bits(pCsr->aBuf);
971     if( (rc==SQLITE_OK)
972      && (eEvent==OS_OPEN || eEvent==OS_DELETE || eEvent==OS_ACCESS) 
973     ){
974       char buf[4];
975       rc = p->pFd->pMethods->xRead(p->pFd, buf, 4, pCsr->iOffset+nRead);
976       nRead += 4;
977       if( rc==SQLITE_OK ){
978         int nStr = get32bits((unsigned char *)buf);
979         char *zStr = sqlite3_malloc(nStr+1);
980         rc = p->pFd->pMethods->xRead(p->pFd, zStr, nStr, pCsr->iOffset+nRead);
981         zStr[nStr] = '\0';
982         nRead += nStr;
983
984         if( eEvent==OS_OPEN ){
985           int iFileid = get32bits(&pCsr->aBuf[4]);
986           if( iFileid>=pCsr->nFile ){
987             int nNew = sizeof(pCsr->azFile[0])*(iFileid+1);
988             pCsr->azFile = (char **)sqlite3_realloc(pCsr->azFile, nNew);
989             nNew -= sizeof(pCsr->azFile[0])*pCsr->nFile;
990             memset(&pCsr->azFile[pCsr->nFile], 0, nNew);
991             pCsr->nFile = iFileid+1;
992           }
993           sqlite3_free(pCsr->azFile[iFileid]);
994           pCsr->azFile[iFileid] = zStr;
995         }else{
996           pCsr->zTransient = zStr;
997         }
998       }
999     }
1000   }
1001
1002   pCsr->iRowid += 1;
1003   pCsr->iOffset += nRead;
1004   return rc;
1005 }
1006
1007 static int vlogEof(sqlite3_vtab_cursor *pCursor){
1008   VfslogCsr *pCsr = (VfslogCsr *)pCursor;
1009   VfslogVtab *p = (VfslogVtab *)pCursor->pVtab;
1010   return (pCsr->iOffset>=p->nByte);
1011 }
1012
1013 static int vlogFilter(
1014   sqlite3_vtab_cursor *pCursor, 
1015   int idxNum, const char *idxStr,
1016   int argc, sqlite3_value **argv
1017 ){
1018   VfslogCsr *pCsr = (VfslogCsr *)pCursor;
1019   pCsr->iRowid = 0;
1020   pCsr->iOffset = 20;
1021   return vlogNext(pCursor);
1022 }
1023
1024 static int vlogColumn(
1025   sqlite3_vtab_cursor *pCursor, 
1026   sqlite3_context *ctx, 
1027   int i
1028 ){
1029   unsigned int val;
1030   VfslogCsr *pCsr = (VfslogCsr *)pCursor;
1031
1032   assert( i<7 );
1033   val = get32bits(&pCsr->aBuf[4*i]);
1034
1035   switch( i ){
1036     case 0: {
1037       sqlite3_result_text(ctx, vfslog_eventname(val), -1, SQLITE_STATIC);
1038       break;
1039     }
1040     case 1: {
1041       char *zStr = pCsr->zTransient;
1042       if( val!=0 && val<pCsr->nFile ){
1043         zStr = pCsr->azFile[val];
1044       }
1045       sqlite3_result_text(ctx, zStr, -1, SQLITE_TRANSIENT);
1046       break;
1047     }
1048     default:
1049       sqlite3_result_int(ctx, val);
1050       break;
1051   }
1052
1053   return SQLITE_OK;
1054 }
1055
1056 static int vlogRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
1057   VfslogCsr *pCsr = (VfslogCsr *)pCursor;
1058   *pRowid = pCsr->iRowid;
1059   return SQLITE_OK;
1060 }
1061
1062 int sqlite3_vfslog_register(sqlite3 *db){
1063   static sqlite3_module vfslog_module = {
1064     0,                            /* iVersion */
1065     vlogConnect,                /* xCreate */
1066     vlogConnect,                /* xConnect */
1067     vlogBestIndex,              /* xBestIndex */
1068     vlogDisconnect,             /* xDisconnect */
1069     vlogDisconnect,             /* xDestroy */
1070     vlogOpen,                   /* xOpen - open a cursor */
1071     vlogClose,                  /* xClose - close a cursor */
1072     vlogFilter,                 /* xFilter - configure scan constraints */
1073     vlogNext,                   /* xNext - advance a cursor */
1074     vlogEof,                    /* xEof - check for end of scan */
1075     vlogColumn,                 /* xColumn - read data */
1076     vlogRowid,                  /* xRowid - read data */
1077     0,                            /* xUpdate */
1078     0,                            /* xBegin */
1079     0,                            /* xSync */
1080     0,                            /* xCommit */
1081     0,                            /* xRollback */
1082     0,                            /* xFindMethod */
1083     0,                            /* xRename */
1084   };
1085
1086   sqlite3_create_module(db, "vfslog", &vfslog_module, 0);
1087   return SQLITE_OK;
1088 }
1089 #endif /* SQLITE_OMIT_VIRTUALTABLE */
1090
1091 /**************************************************************************
1092 ***************************************************************************
1093 ** Tcl interface starts here.
1094 */
1095
1096 #if defined(SQLITE_TEST) || defined(TCLSH)
1097
1098 #include <tcl.h>
1099
1100 static int test_vfslog(
1101   void *clientData,
1102   Tcl_Interp *interp,
1103   int objc,
1104   Tcl_Obj *CONST objv[]
1105 ){
1106   struct SqliteDb { sqlite3 *db; };
1107   sqlite3 *db;
1108   Tcl_CmdInfo cmdInfo;
1109   int rc = SQLITE_ERROR;
1110
1111   static const char *strs[] = { "annotate", "finalize", "new",  "register", 0 };
1112   enum VL_enum { VL_ANNOTATE, VL_FINALIZE, VL_NEW, VL_REGISTER };
1113   int iSub;
1114
1115   if( objc<2 ){
1116     Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
1117     return TCL_ERROR;
1118   }
1119   if( Tcl_GetIndexFromObj(interp, objv[1], strs, "sub-command", 0, &iSub) ){
1120     return TCL_ERROR;
1121   }
1122
1123   switch( (enum VL_enum)iSub ){
1124     case VL_ANNOTATE: {
1125       int rc;
1126       char *zVfs;
1127       char *zMsg;
1128       if( objc!=4 ){
1129         Tcl_WrongNumArgs(interp, 3, objv, "VFS");
1130         return TCL_ERROR;
1131       }
1132       zVfs = Tcl_GetString(objv[2]);
1133       zMsg = Tcl_GetString(objv[3]);
1134       rc = sqlite3_vfslog_annotate(zVfs, zMsg);
1135       if( rc!=SQLITE_OK ){
1136         Tcl_AppendResult(interp, "failed", 0);
1137         return TCL_ERROR;
1138       }
1139       break;
1140     }
1141     case VL_FINALIZE: {
1142       int rc;
1143       char *zVfs;
1144       if( objc!=3 ){
1145         Tcl_WrongNumArgs(interp, 2, objv, "VFS");
1146         return TCL_ERROR;
1147       }
1148       zVfs = Tcl_GetString(objv[2]);
1149       rc = sqlite3_vfslog_finalize(zVfs);
1150       if( rc!=SQLITE_OK ){
1151         Tcl_AppendResult(interp, "failed", 0);
1152         return TCL_ERROR;
1153       }
1154       break;
1155     };
1156
1157     case VL_NEW: {
1158       int rc;
1159       char *zVfs;
1160       char *zParent;
1161       char *zLog;
1162       if( objc!=5 ){
1163         Tcl_WrongNumArgs(interp, 2, objv, "VFS PARENT LOGFILE");
1164         return TCL_ERROR;
1165       }
1166       zVfs = Tcl_GetString(objv[2]);
1167       zParent = Tcl_GetString(objv[3]);
1168       zLog = Tcl_GetString(objv[4]);
1169       if( *zParent=='\0' ) zParent = 0;
1170       rc = sqlite3_vfslog_new(zVfs, zParent, zLog);
1171       if( rc!=SQLITE_OK ){
1172         Tcl_AppendResult(interp, "failed", 0);
1173         return TCL_ERROR;
1174       }
1175       break;
1176     };
1177
1178     case VL_REGISTER: {
1179       char *zDb;
1180       if( objc!=3 ){
1181         Tcl_WrongNumArgs(interp, 2, objv, "DB");
1182         return TCL_ERROR;
1183       }
1184 #ifdef SQLITE_OMIT_VIRTUALTABLE
1185       Tcl_AppendResult(interp, "vfslog not available because of "
1186                                "SQLITE_OMIT_VIRTUALTABLE", (void*)0);
1187       return TCL_ERROR;
1188 #else
1189       zDb = Tcl_GetString(objv[2]);
1190       if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
1191         db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
1192         rc = sqlite3_vfslog_register(db);
1193       }
1194       if( rc!=SQLITE_OK ){
1195         Tcl_AppendResult(interp, "bad sqlite3 handle: ", zDb, (void*)0);
1196         return TCL_ERROR;
1197       }
1198       break;
1199 #endif
1200     }
1201   }
1202
1203   return TCL_OK;
1204 }
1205
1206 int SqlitetestOsinst_Init(Tcl_Interp *interp){
1207   Tcl_CreateObjCommand(interp, "vfslog", test_vfslog, 0, 0);
1208   return TCL_OK;
1209 }
1210
1211 #endif /* SQLITE_TEST */