| OLD | NEW | 
| (Empty) |  | 
 |     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  | 
 |    74 #include "os_setup.h" | 
 |    75 #if SQLITE_OS_WIN | 
 |    76 #  include "os_win.h" | 
 |    77 #endif | 
 |    78  | 
 |    79 #include <string.h> | 
 |    80 #include <assert.h> | 
 |    81  | 
 |    82  | 
 |    83 /* | 
 |    84 ** Maximum pathname length supported by the vfslog backend. | 
 |    85 */ | 
 |    86 #define INST_MAX_PATHNAME 512 | 
 |    87  | 
 |    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 | 
 |   112  | 
 |   113 #define OS_NUMEVENTS         29 | 
 |   114  | 
 |   115 #define VFSLOG_BUFFERSIZE 8192 | 
 |   116  | 
 |   117 typedef struct VfslogVfs VfslogVfs; | 
 |   118 typedef struct VfslogFile VfslogFile; | 
 |   119  | 
 |   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 */ | 
 |   128 }; | 
 |   129  | 
 |   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 */ | 
 |   135 }; | 
 |   136  | 
 |   137 #define REALVFS(p) (((VfslogVfs *)(p))->pVfs) | 
 |   138  | 
 |   139  | 
 |   140  | 
 |   141 /* | 
 |   142 ** Method declarations for vfslog_file. | 
 |   143 */ | 
 |   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*); | 
 |   156  | 
 |   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); | 
 |   161  | 
 |   162 /* | 
 |   163 ** Method declarations for vfslog_vfs. | 
 |   164 */ | 
 |   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*); | 
 |   176  | 
 |   177 static int vfslogGetLastError(sqlite3_vfs*, int, char *); | 
 |   178 static int vfslogCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); | 
 |   179  | 
 |   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 */ | 
 |   200 }; | 
 |   201  | 
 |   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 */ | 
 |   220 }; | 
 |   221  | 
 |   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; | 
 |   228 } | 
 |   229 #elif SQLITE_OS_WIN | 
 |   230 #include <time.h> | 
 |   231 static sqlite3_uint64 vfslog_time(){ | 
 |   232   FILETIME ft; | 
 |   233   sqlite3_uint64 u64time = 0; | 
 |   234   | 
 |   235   GetSystemTimeAsFileTime(&ft); | 
 |   236  | 
 |   237   u64time |= ft.dwHighDateTime; | 
 |   238   u64time <<= 32; | 
 |   239   u64time |= ft.dwLowDateTime; | 
 |   240  | 
 |   241   /* ft is 100-nanosecond intervals, we want microseconds */ | 
 |   242   return u64time /(sqlite3_uint64)10; | 
 |   243 } | 
 |   244 #else | 
 |   245 static sqlite3_uint64 vfslog_time(){ | 
 |   246   return 0; | 
 |   247 } | 
 |   248 #endif | 
 |   249  | 
 |   250 static void vfslog_call(sqlite3_vfs *, int, int, sqlite3_int64, int, int, int); | 
 |   251 static void vfslog_string(sqlite3_vfs *, const char *); | 
 |   252  | 
 |   253 /* | 
 |   254 ** Close an vfslog-file. | 
 |   255 */ | 
 |   256 static int vfslogClose(sqlite3_file *pFile){ | 
 |   257   sqlite3_uint64 t; | 
 |   258   int rc = SQLITE_OK; | 
 |   259   VfslogFile *p = (VfslogFile *)pFile; | 
 |   260  | 
 |   261   t = vfslog_time(); | 
 |   262   if( p->pReal->pMethods ){ | 
 |   263     rc = p->pReal->pMethods->xClose(p->pReal); | 
 |   264   } | 
 |   265   t = vfslog_time() - t; | 
 |   266   vfslog_call(p->pVfslog, OS_CLOSE, p->iFileId, t, rc, 0, 0); | 
 |   267   return rc; | 
 |   268 } | 
 |   269  | 
 |   270 /* | 
 |   271 ** Read data from an vfslog-file. | 
 |   272 */ | 
 |   273 static int vfslogRead( | 
 |   274   sqlite3_file *pFile,  | 
 |   275   void *zBuf,  | 
 |   276   int iAmt,  | 
 |   277   sqlite_int64 iOfst | 
 |   278 ){ | 
 |   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; | 
 |   287 } | 
 |   288  | 
 |   289 /* | 
 |   290 ** Write data to an vfslog-file. | 
 |   291 */ | 
 |   292 static int vfslogWrite( | 
 |   293   sqlite3_file *pFile, | 
 |   294   const void *z, | 
 |   295   int iAmt, | 
 |   296   sqlite_int64 iOfst | 
 |   297 ){ | 
 |   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; | 
 |   306 } | 
 |   307  | 
 |   308 /* | 
 |   309 ** Truncate an vfslog-file. | 
 |   310 */ | 
 |   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; | 
 |   320 } | 
 |   321  | 
 |   322 /* | 
 |   323 ** Sync an vfslog-file. | 
 |   324 */ | 
 |   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; | 
 |   334 } | 
 |   335  | 
 |   336 /* | 
 |   337 ** Return the current file-size of an vfslog-file. | 
 |   338 */ | 
 |   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; | 
 |   348 } | 
 |   349  | 
 |   350 /* | 
 |   351 ** Lock an vfslog-file. | 
 |   352 */ | 
 |   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; | 
 |   362 } | 
 |   363  | 
 |   364 /* | 
 |   365 ** Unlock an vfslog-file. | 
 |   366 */ | 
 |   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; | 
 |   376 } | 
 |   377  | 
 |   378 /* | 
 |   379 ** Check if another file-handle holds a RESERVED lock on an vfslog-file. | 
 |   380 */ | 
 |   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; | 
 |   390 } | 
 |   391  | 
 |   392 /* | 
 |   393 ** File control method. For custom operations on an vfslog-file. | 
 |   394 */ | 
 |   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); | 
 |   400   } | 
 |   401   return rc; | 
 |   402 } | 
 |   403  | 
 |   404 /* | 
 |   405 ** Return the sector-size in bytes for an vfslog-file. | 
 |   406 */ | 
 |   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; | 
 |   416 } | 
 |   417  | 
 |   418 /* | 
 |   419 ** Return the device characteristic flags supported by an vfslog-file. | 
 |   420 */ | 
 |   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; | 
 |   430 } | 
 |   431  | 
 |   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; | 
 |   441 } | 
 |   442 static int vfslogShmMap( | 
 |   443   sqlite3_file *pFile,  | 
 |   444   int iRegion,  | 
 |   445   int szRegion,  | 
 |   446   int isWrite,  | 
 |   447   volatile void **pp | 
 |   448 ){ | 
 |   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; | 
 |   457 } | 
 |   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); | 
 |   465 } | 
 |   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; | 
 |   475 } | 
 |   476  | 
 |   477  | 
 |   478 /* | 
 |   479 ** Open an vfslog file handle. | 
 |   480 */ | 
 |   481 static int vfslogOpen( | 
 |   482   sqlite3_vfs *pVfs, | 
 |   483   const char *zName, | 
 |   484   sqlite3_file *pFile, | 
 |   485   int flags, | 
 |   486   int *pOutFlags | 
 |   487 ){ | 
 |   488   int rc; | 
 |   489   sqlite3_uint64 t; | 
 |   490   VfslogFile *p = (VfslogFile *)pFile; | 
 |   491   VfslogVfs *pLog = (VfslogVfs *)pVfs; | 
 |   492  | 
 |   493   pFile->pMethods = &vfslog_io_methods; | 
 |   494   p->pReal = (sqlite3_file *)&p[1]; | 
 |   495   p->pVfslog = pVfs; | 
 |   496   p->iFileId = ++pLog->iNextFileId; | 
 |   497  | 
 |   498   t = vfslog_time(); | 
 |   499   rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags); | 
 |   500   t = vfslog_time() - t; | 
 |   501  | 
 |   502   vfslog_call(pVfs, OS_OPEN, p->iFileId, t, rc, 0, 0); | 
 |   503   vfslog_string(pVfs, zName); | 
 |   504   return rc; | 
 |   505 } | 
 |   506  | 
 |   507 /* | 
 |   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. | 
 |   511 */ | 
 |   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; | 
 |   521 } | 
 |   522  | 
 |   523 /* | 
 |   524 ** Test for access permissions. Return true if the requested permission | 
 |   525 ** is available, or false otherwise. | 
 |   526 */ | 
 |   527 static int vfslogAccess( | 
 |   528   sqlite3_vfs *pVfs,  | 
 |   529   const char *zPath,  | 
 |   530   int flags,  | 
 |   531   int *pResOut | 
 |   532 ){ | 
 |   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; | 
 |   541 } | 
 |   542  | 
 |   543 /* | 
 |   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. | 
 |   547 */ | 
 |   548 static int vfslogFullPathname( | 
 |   549   sqlite3_vfs *pVfs,  | 
 |   550   const char *zPath,  | 
 |   551   int nOut,  | 
 |   552   char *zOut | 
 |   553 ){ | 
 |   554   return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut); | 
 |   555 } | 
 |   556  | 
 |   557 /* | 
 |   558 ** Open the dynamic library located at zPath and return a handle. | 
 |   559 */ | 
 |   560 static void *vfslogDlOpen(sqlite3_vfs *pVfs, const char *zPath){ | 
 |   561   return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath); | 
 |   562 } | 
 |   563  | 
 |   564 /* | 
 |   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. | 
 |   568 */ | 
 |   569 static void vfslogDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ | 
 |   570   REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg); | 
 |   571 } | 
 |   572  | 
 |   573 /* | 
 |   574 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle. | 
 |   575 */ | 
 |   576 static void (*vfslogDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ | 
 |   577   return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym); | 
 |   578 } | 
 |   579  | 
 |   580 /* | 
 |   581 ** Close the dynamic library handle pHandle. | 
 |   582 */ | 
 |   583 static void vfslogDlClose(sqlite3_vfs *pVfs, void *pHandle){ | 
 |   584   REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle); | 
 |   585 } | 
 |   586  | 
 |   587 /* | 
 |   588 ** Populate the buffer pointed to by zBufOut with nByte bytes of  | 
 |   589 ** random data. | 
 |   590 */ | 
 |   591 static int vfslogRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ | 
 |   592   return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut); | 
 |   593 } | 
 |   594  | 
 |   595 /* | 
 |   596 ** Sleep for nMicro microseconds. Return the number of microseconds  | 
 |   597 ** actually slept. | 
 |   598 */ | 
 |   599 static int vfslogSleep(sqlite3_vfs *pVfs, int nMicro){ | 
 |   600   return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro); | 
 |   601 } | 
 |   602  | 
 |   603 /* | 
 |   604 ** Return the current time as a Julian Day number in *pTimeOut. | 
 |   605 */ | 
 |   606 static int vfslogCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ | 
 |   607   return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut); | 
 |   608 } | 
 |   609  | 
 |   610 static int vfslogGetLastError(sqlite3_vfs *pVfs, int a, char *b){ | 
 |   611   return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b); | 
 |   612 } | 
 |   613 static int vfslogCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){ | 
 |   614   return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p); | 
 |   615 } | 
 |   616  | 
 |   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; | 
 |   622  | 
 |   623   int pending = sqlite3_io_error_pending; | 
 |   624   int persist = sqlite3_io_error_persist; | 
 |   625   int diskfull = sqlite3_diskfull_pending; | 
 |   626  | 
 |   627   sqlite3_io_error_pending = 0; | 
 |   628   sqlite3_io_error_persist = 0; | 
 |   629   sqlite3_diskfull_pending = 0; | 
 |   630 #endif | 
 |   631  | 
 |   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; | 
 |   636   } | 
 |   637  | 
 |   638 #ifdef SQLITE_TEST | 
 |   639   sqlite3_io_error_pending = pending; | 
 |   640   sqlite3_io_error_persist = persist; | 
 |   641   sqlite3_diskfull_pending = diskfull; | 
 |   642 #endif | 
 |   643 } | 
 |   644  | 
 |   645 static void put32bits(unsigned char *p, unsigned int v){ | 
 |   646   p[0] = v>>24; | 
 |   647   p[1] = v>>16; | 
 |   648   p[2] = v>>8; | 
 |   649   p[3] = v; | 
 |   650 } | 
 |   651  | 
 |   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 | 
 |   660 ){ | 
 |   661   VfslogVfs *p = (VfslogVfs *)pVfs; | 
 |   662   unsigned char *zRec; | 
 |   663   if( (24+p->nBuf)>sizeof(p->aBuf) ){ | 
 |   664     vfslog_flush(p); | 
 |   665   } | 
 |   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; | 
 |   674 } | 
 |   675  | 
 |   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); | 
 |   682   } | 
 |   683   zRec = (unsigned char *)&p->aBuf[p->nBuf]; | 
 |   684   put32bits(&zRec[0], nStr); | 
 |   685   if( zStr ){ | 
 |   686     memcpy(&zRec[4], zStr, nStr); | 
 |   687   } | 
 |   688   p->nBuf += (4 + nStr); | 
 |   689 } | 
 |   690  | 
 |   691 static void vfslog_finalize(VfslogVfs *p){ | 
 |   692   if( p->pLog->pMethods ){ | 
 |   693     vfslog_flush(p); | 
 |   694     p->pLog->pMethods->xClose(p->pLog); | 
 |   695   } | 
 |   696   sqlite3_free(p); | 
 |   697 } | 
 |   698  | 
 |   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; | 
 |   704   }  | 
 |   705   sqlite3_vfs_unregister(pVfs); | 
 |   706   vfslog_finalize((VfslogVfs *)pVfs); | 
 |   707   return SQLITE_OK; | 
 |   708 } | 
 |   709  | 
 |   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 */ | 
 |   714 ){ | 
 |   715   VfslogVfs *p; | 
 |   716   sqlite3_vfs *pParent; | 
 |   717   int nByte; | 
 |   718   int flags; | 
 |   719   int rc; | 
 |   720   char *zFile; | 
 |   721   int nVfs; | 
 |   722  | 
 |   723   pParent = sqlite3_vfs_find(zParentVfs); | 
 |   724   if( !pParent ){ | 
 |   725     return SQLITE_ERROR; | 
 |   726   } | 
 |   727  | 
 |   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); | 
 |   732  | 
 |   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); | 
 |   739  | 
 |   740   zFile = (char *)&p->base.zName[nVfs+1]; | 
 |   741   pParent->xFullPathname(pParent, zLog, pParent->mxPathname, zFile); | 
 |   742  | 
 |   743   flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MASTER_JOURNAL; | 
 |   744   pParent->xDelete(pParent, zFile, 0); | 
 |   745   rc = pParent->xOpen(pParent, zFile, p->pLog, flags, &flags); | 
 |   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); | 
 |   751   } | 
 |   752   if( rc ){ | 
 |   753     vfslog_finalize(p); | 
 |   754   } | 
 |   755   return rc; | 
 |   756 } | 
 |   757  | 
 |   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; | 
 |   763   }  | 
 |   764   vfslog_call(pVfs, OS_ANNOTATE, 0, 0, 0, 0, 0); | 
 |   765   vfslog_string(pVfs, zMsg); | 
 |   766   return SQLITE_OK; | 
 |   767 } | 
 |   768  | 
 |   769 static const char *vfslog_eventname(int eEvent){ | 
 |   770   const char *zEvent = 0; | 
 |   771  | 
 |   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; | 
 |   792  | 
 |   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; | 
 |   797  | 
 |   798     case OS_ANNOTATE:          zEvent = "annotation"; break; | 
 |   799   } | 
 |   800  | 
 |   801   return zEvent; | 
 |   802 } | 
 |   803  | 
 |   804 typedef struct VfslogVtab VfslogVtab; | 
 |   805 typedef struct VfslogCsr VfslogCsr; | 
 |   806  | 
 |   807 /* | 
 |   808 ** Virtual table type for the vfslog reader module. | 
 |   809 */ | 
 |   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 */ | 
 |   815 }; | 
 |   816  | 
 |   817 /* | 
 |   818 ** Virtual table cursor type for the vfslog reader module. | 
 |   819 */ | 
 |   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) */ | 
 |   828 }; | 
 |   829  | 
 |   830 static unsigned int get32bits(unsigned char *p){ | 
 |   831   return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; | 
 |   832 } | 
 |   833  | 
 |   834 /* | 
 |   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. | 
 |   838 */ | 
 |   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++]; | 
 |   853       } | 
 |   854     } | 
 |   855     z[iOut] = '\0'; | 
 |   856   } | 
 |   857 } | 
 |   858  | 
 |   859 #ifndef SQLITE_OMIT_VIRTUALTABLE | 
 |   860 /* | 
 |   861 ** Connect to or create a vfslog virtual table. | 
 |   862 */ | 
 |   863 static int vlogConnect( | 
 |   864   sqlite3 *db, | 
 |   865   void *pAux, | 
 |   866   int argc, const char *const*argv, | 
 |   867   sqlite3_vtab **ppVtab, | 
 |   868   char **pzErr | 
 |   869 ){ | 
 |   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; | 
 |   876  | 
 |   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); | 
 |   883  | 
 |   884   p->pFd = (sqlite3_file *)&p[1]; | 
 |   885   p->zFile = &((char *)p->pFd)[pVfs->szOsFile]; | 
 |   886  | 
 |   887   zFile = sqlite3_mprintf("%s", argv[3]); | 
 |   888   if( !zFile ){ | 
 |   889     sqlite3_free(p); | 
 |   890     return SQLITE_NOMEM; | 
 |   891   } | 
 |   892   dequote(zFile); | 
 |   893   pVfs->xFullPathname(pVfs, zFile, pVfs->mxPathname, p->zFile); | 
 |   894   sqlite3_free(zFile); | 
 |   895  | 
 |   896   flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MASTER_JOURNAL; | 
 |   897   rc = pVfs->xOpen(pVfs, p->zFile, p->pFd, flags, &flags); | 
 |   898  | 
 |   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)" | 
 |   903     ); | 
 |   904     *ppVtab = &p->base; | 
 |   905   }else{ | 
 |   906     sqlite3_free(p); | 
 |   907   } | 
 |   908  | 
 |   909   return rc; | 
 |   910 } | 
 |   911  | 
 |   912 /* | 
 |   913 ** There is no "best-index". This virtual table always does a linear | 
 |   914 ** scan of the binary VFS log file. | 
 |   915 */ | 
 |   916 static int vlogBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ | 
 |   917   pIdxInfo->estimatedCost = 10.0; | 
 |   918   return SQLITE_OK; | 
 |   919 } | 
 |   920  | 
 |   921 /* | 
 |   922 ** Disconnect from or destroy a vfslog virtual table. | 
 |   923 */ | 
 |   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; | 
 |   929   } | 
 |   930   sqlite3_free(p); | 
 |   931   return SQLITE_OK; | 
 |   932 } | 
 |   933  | 
 |   934 /* | 
 |   935 ** Open a new vfslog cursor. | 
 |   936 */ | 
 |   937 static int vlogOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ | 
 |   938   VfslogCsr *pCsr;                /* Newly allocated cursor object */ | 
 |   939  | 
 |   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; | 
 |   945 } | 
 |   946  | 
 |   947 /* | 
 |   948 ** Close a vfslog cursor. | 
 |   949 */ | 
 |   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]); | 
 |   955   } | 
 |   956   sqlite3_free(p->azFile); | 
 |   957   sqlite3_free(p->zTransient); | 
 |   958   sqlite3_free(p); | 
 |   959   return SQLITE_OK; | 
 |   960 } | 
 |   961  | 
 |   962 /* | 
 |   963 ** Move a vfslog cursor to the next entry in the file. | 
 |   964 */ | 
 |   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; | 
 |   970  | 
 |   971   sqlite3_free(pCsr->zTransient); | 
 |   972   pCsr->zTransient = 0; | 
 |   973  | 
 |   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); | 
 |   978  | 
 |   979     eEvent = get32bits(pCsr->aBuf); | 
 |   980     if( (rc==SQLITE_OK) | 
 |   981      && (eEvent==OS_OPEN || eEvent==OS_DELETE || eEvent==OS_ACCESS)  | 
 |   982     ){ | 
 |   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; | 
 |   992  | 
 |   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; | 
 |  1001           } | 
 |  1002           sqlite3_free(pCsr->azFile[iFileid]); | 
 |  1003           pCsr->azFile[iFileid] = zStr; | 
 |  1004         }else{ | 
 |  1005           pCsr->zTransient = zStr; | 
 |  1006         } | 
 |  1007       } | 
 |  1008     } | 
 |  1009   } | 
 |  1010  | 
 |  1011   pCsr->iRowid += 1; | 
 |  1012   pCsr->iOffset += nRead; | 
 |  1013   return rc; | 
 |  1014 } | 
 |  1015  | 
 |  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); | 
 |  1020 } | 
 |  1021  | 
 |  1022 static int vlogFilter( | 
 |  1023   sqlite3_vtab_cursor *pCursor,  | 
 |  1024   int idxNum, const char *idxStr, | 
 |  1025   int argc, sqlite3_value **argv | 
 |  1026 ){ | 
 |  1027   VfslogCsr *pCsr = (VfslogCsr *)pCursor; | 
 |  1028   pCsr->iRowid = 0; | 
 |  1029   pCsr->iOffset = 20; | 
 |  1030   return vlogNext(pCursor); | 
 |  1031 } | 
 |  1032  | 
 |  1033 static int vlogColumn( | 
 |  1034   sqlite3_vtab_cursor *pCursor,  | 
 |  1035   sqlite3_context *ctx,  | 
 |  1036   int i | 
 |  1037 ){ | 
 |  1038   unsigned int val; | 
 |  1039   VfslogCsr *pCsr = (VfslogCsr *)pCursor; | 
 |  1040  | 
 |  1041   assert( i<7 ); | 
 |  1042   val = get32bits(&pCsr->aBuf[4*i]); | 
 |  1043  | 
 |  1044   switch( i ){ | 
 |  1045     case 0: { | 
 |  1046       sqlite3_result_text(ctx, vfslog_eventname(val), -1, SQLITE_STATIC); | 
 |  1047       break; | 
 |  1048     } | 
 |  1049     case 1: { | 
 |  1050       char *zStr = pCsr->zTransient; | 
 |  1051       if( val!=0 && val<(unsigned)pCsr->nFile ){ | 
 |  1052         zStr = pCsr->azFile[val]; | 
 |  1053       } | 
 |  1054       sqlite3_result_text(ctx, zStr, -1, SQLITE_TRANSIENT); | 
 |  1055       break; | 
 |  1056     } | 
 |  1057     default: | 
 |  1058       sqlite3_result_int(ctx, val); | 
 |  1059       break; | 
 |  1060   } | 
 |  1061  | 
 |  1062   return SQLITE_OK; | 
 |  1063 } | 
 |  1064  | 
 |  1065 static int vlogRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ | 
 |  1066   VfslogCsr *pCsr = (VfslogCsr *)pCursor; | 
 |  1067   *pRowid = pCsr->iRowid; | 
 |  1068   return SQLITE_OK; | 
 |  1069 } | 
 |  1070  | 
 |  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   }; | 
 |  1094  | 
 |  1095   sqlite3_create_module(db, "vfslog", &vfslog_module, 0); | 
 |  1096   return SQLITE_OK; | 
 |  1097 } | 
 |  1098 #endif /* SQLITE_OMIT_VIRTUALTABLE */ | 
 |  1099  | 
 |  1100 /************************************************************************** | 
 |  1101 *************************************************************************** | 
 |  1102 ** Tcl interface starts here. | 
 |  1103 */ | 
 |  1104  | 
 |  1105 #if defined(SQLITE_TEST) || defined(TCLSH) | 
 |  1106  | 
 |  1107 #include <tcl.h> | 
 |  1108  | 
 |  1109 static int test_vfslog( | 
 |  1110   void *clientData, | 
 |  1111   Tcl_Interp *interp, | 
 |  1112   int objc, | 
 |  1113   Tcl_Obj *CONST objv[] | 
 |  1114 ){ | 
 |  1115   struct SqliteDb { sqlite3 *db; }; | 
 |  1116   sqlite3 *db; | 
 |  1117   Tcl_CmdInfo cmdInfo; | 
 |  1118   int rc = SQLITE_ERROR; | 
 |  1119  | 
 |  1120   static const char *strs[] = { "annotate", "finalize", "new",  "register", 0 }; | 
 |  1121   enum VL_enum { VL_ANNOTATE, VL_FINALIZE, VL_NEW, VL_REGISTER }; | 
 |  1122   int iSub; | 
 |  1123  | 
 |  1124   if( objc<2 ){ | 
 |  1125     Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ..."); | 
 |  1126     return TCL_ERROR; | 
 |  1127   } | 
 |  1128   if( Tcl_GetIndexFromObj(interp, objv[1], strs, "sub-command", 0, &iSub) ){ | 
 |  1129     return TCL_ERROR; | 
 |  1130   } | 
 |  1131  | 
 |  1132   switch( (enum VL_enum)iSub ){ | 
 |  1133     case VL_ANNOTATE: { | 
 |  1134       int rc; | 
 |  1135       char *zVfs; | 
 |  1136       char *zMsg; | 
 |  1137       if( objc!=4 ){ | 
 |  1138         Tcl_WrongNumArgs(interp, 3, objv, "VFS"); | 
 |  1139         return TCL_ERROR; | 
 |  1140       } | 
 |  1141       zVfs = Tcl_GetString(objv[2]); | 
 |  1142       zMsg = Tcl_GetString(objv[3]); | 
 |  1143       rc = sqlite3_vfslog_annotate(zVfs, zMsg); | 
 |  1144       if( rc!=SQLITE_OK ){ | 
 |  1145         Tcl_AppendResult(interp, "failed", 0); | 
 |  1146         return TCL_ERROR; | 
 |  1147       } | 
 |  1148       break; | 
 |  1149     } | 
 |  1150     case VL_FINALIZE: { | 
 |  1151       int rc; | 
 |  1152       char *zVfs; | 
 |  1153       if( objc!=3 ){ | 
 |  1154         Tcl_WrongNumArgs(interp, 2, objv, "VFS"); | 
 |  1155         return TCL_ERROR; | 
 |  1156       } | 
 |  1157       zVfs = Tcl_GetString(objv[2]); | 
 |  1158       rc = sqlite3_vfslog_finalize(zVfs); | 
 |  1159       if( rc!=SQLITE_OK ){ | 
 |  1160         Tcl_AppendResult(interp, "failed", 0); | 
 |  1161         return TCL_ERROR; | 
 |  1162       } | 
 |  1163       break; | 
 |  1164     }; | 
 |  1165  | 
 |  1166     case VL_NEW: { | 
 |  1167       int rc; | 
 |  1168       char *zVfs; | 
 |  1169       char *zParent; | 
 |  1170       char *zLog; | 
 |  1171       if( objc!=5 ){ | 
 |  1172         Tcl_WrongNumArgs(interp, 2, objv, "VFS PARENT LOGFILE"); | 
 |  1173         return TCL_ERROR; | 
 |  1174       } | 
 |  1175       zVfs = Tcl_GetString(objv[2]); | 
 |  1176       zParent = Tcl_GetString(objv[3]); | 
 |  1177       zLog = Tcl_GetString(objv[4]); | 
 |  1178       if( *zParent=='\0' ) zParent = 0; | 
 |  1179       rc = sqlite3_vfslog_new(zVfs, zParent, zLog); | 
 |  1180       if( rc!=SQLITE_OK ){ | 
 |  1181         Tcl_AppendResult(interp, "failed", 0); | 
 |  1182         return TCL_ERROR; | 
 |  1183       } | 
 |  1184       break; | 
 |  1185     }; | 
 |  1186  | 
 |  1187     case VL_REGISTER: { | 
 |  1188       char *zDb; | 
 |  1189       if( objc!=3 ){ | 
 |  1190         Tcl_WrongNumArgs(interp, 2, objv, "DB"); | 
 |  1191         return TCL_ERROR; | 
 |  1192       } | 
 |  1193 #ifdef SQLITE_OMIT_VIRTUALTABLE | 
 |  1194       Tcl_AppendResult(interp, "vfslog not available because of " | 
 |  1195                                "SQLITE_OMIT_VIRTUALTABLE", (void*)0); | 
 |  1196       return TCL_ERROR; | 
 |  1197 #else | 
 |  1198       zDb = Tcl_GetString(objv[2]); | 
 |  1199       if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){ | 
 |  1200         db = ((struct SqliteDb*)cmdInfo.objClientData)->db; | 
 |  1201         rc = sqlite3_vfslog_register(db); | 
 |  1202       } | 
 |  1203       if( rc!=SQLITE_OK ){ | 
 |  1204         Tcl_AppendResult(interp, "bad sqlite3 handle: ", zDb, (void*)0); | 
 |  1205         return TCL_ERROR; | 
 |  1206       } | 
 |  1207       break; | 
 |  1208 #endif | 
 |  1209     } | 
 |  1210   } | 
 |  1211  | 
 |  1212   return TCL_OK; | 
 |  1213 } | 
 |  1214  | 
 |  1215 int SqlitetestOsinst_Init(Tcl_Interp *interp){ | 
 |  1216   Tcl_CreateObjCommand(interp, "vfslog", test_vfslog, 0, 0); | 
 |  1217   return TCL_OK; | 
 |  1218 } | 
 |  1219  | 
 |  1220 #endif /* SQLITE_TEST */ | 
| OLD | NEW |