Blame src/test_osinst.c

Packit 87b942
/*
Packit 87b942
** 2008 April 10
Packit 87b942
**
Packit 87b942
** The author disclaims copyright to this source code.  In place of
Packit 87b942
** a legal notice, here is a blessing:
Packit 87b942
**
Packit 87b942
**    May you do good and not evil.
Packit 87b942
**    May you find forgiveness for yourself and forgive others.
Packit 87b942
**    May you share freely, never taking more than you give.
Packit 87b942
**
Packit 87b942
******************************************************************************
Packit 87b942
**
Packit 87b942
** This file contains the implementation of an SQLite vfs wrapper that
Packit 87b942
** adds instrumentation to all vfs and file methods. C and Tcl interfaces
Packit 87b942
** are provided to control the instrumentation.
Packit 87b942
*/
Packit 87b942
Packit 87b942
/*
Packit 87b942
** This module contains code for a wrapper VFS that causes a log of
Packit 87b942
** most VFS calls to be written into a nominated file on disk. The log 
Packit 87b942
** is stored in a compressed binary format to reduce the amount of IO 
Packit 87b942
** overhead introduced into the application by logging.
Packit 87b942
**
Packit 87b942
** All calls on sqlite3_file objects except xFileControl() are logged.
Packit 87b942
** Additionally, calls to the xAccess(), xOpen(), and xDelete()
Packit 87b942
** methods are logged. The other sqlite3_vfs object methods (xDlXXX,
Packit 87b942
** xRandomness, xSleep, xCurrentTime, xGetLastError and xCurrentTimeInt64) 
Packit 87b942
** are not logged.
Packit 87b942
**
Packit 87b942
** The binary log files are read using a virtual table implementation
Packit 87b942
** also contained in this file. 
Packit 87b942
**
Packit 87b942
** CREATING LOG FILES:
Packit 87b942
**
Packit 87b942
**       int sqlite3_vfslog_new(
Packit 87b942
**         const char *zVfs,          // Name of new VFS
Packit 87b942
**         const char *zParentVfs,    // Name of parent VFS (or NULL)
Packit 87b942
**         const char *zLog           // Name of log file to write to
Packit 87b942
**       );
Packit 87b942
**
Packit 87b942
**       int sqlite3_vfslog_finalize(const char *zVfs);
Packit 87b942
**
Packit 87b942
** ANNOTATING LOG FILES:
Packit 87b942
**
Packit 87b942
**   To write an arbitrary message into a log file:
Packit 87b942
**
Packit 87b942
**       int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg);
Packit 87b942
**
Packit 87b942
** READING LOG FILES:
Packit 87b942
**
Packit 87b942
**   Log files are read using the "vfslog" virtual table implementation
Packit 87b942
**   in this file. To register the virtual table with SQLite, use:
Packit 87b942
**
Packit 87b942
**       int sqlite3_vfslog_register(sqlite3 *db);
Packit 87b942
**
Packit 87b942
**   Then, if the log file is named "vfs.log", the following SQL command:
Packit 87b942
**
Packit 87b942
**       CREATE VIRTUAL TABLE v USING vfslog('vfs.log');
Packit 87b942
**
Packit 87b942
**   creates a virtual table with 6 columns, as follows:
Packit 87b942
**
Packit 87b942
**       CREATE TABLE v(
Packit 87b942
**         event    TEXT,             // "xOpen", "xRead" etc.
Packit 87b942
**         file     TEXT,             // Name of file this call applies to
Packit 87b942
**         clicks   INTEGER,          // Time spent in call
Packit 87b942
**         rc       INTEGER,          // Return value
Packit 87b942
**         size     INTEGER,          // Bytes read or written
Packit 87b942
**         offset   INTEGER           // File offset read or written
Packit 87b942
**       );
Packit 87b942
*/
Packit 87b942
Packit 87b942
#include "sqlite3.h"
Packit 87b942
Packit 87b942
#include "os_setup.h"
Packit 87b942
#if SQLITE_OS_WIN
Packit 87b942
#  include "os_win.h"
Packit 87b942
#endif
Packit 87b942
Packit 87b942
#include <string.h>
Packit 87b942
#include <assert.h>
Packit 87b942
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Maximum pathname length supported by the vfslog backend.
Packit 87b942
*/
Packit 87b942
#define INST_MAX_PATHNAME 512
Packit 87b942
Packit 87b942
#define OS_ACCESS            1
Packit 87b942
#define OS_CHECKRESERVEDLOCK 2
Packit 87b942
#define OS_CLOSE             3
Packit 87b942
#define OS_CURRENTTIME       4
Packit 87b942
#define OS_DELETE            5
Packit 87b942
#define OS_DEVCHAR           6
Packit 87b942
#define OS_FILECONTROL       7
Packit 87b942
#define OS_FILESIZE          8
Packit 87b942
#define OS_FULLPATHNAME      9
Packit 87b942
#define OS_LOCK              11
Packit 87b942
#define OS_OPEN              12
Packit 87b942
#define OS_RANDOMNESS        13
Packit 87b942
#define OS_READ              14 
Packit 87b942
#define OS_SECTORSIZE        15
Packit 87b942
#define OS_SLEEP             16
Packit 87b942
#define OS_SYNC              17
Packit 87b942
#define OS_TRUNCATE          18
Packit 87b942
#define OS_UNLOCK            19
Packit 87b942
#define OS_WRITE             20
Packit 87b942
#define OS_SHMUNMAP          22
Packit 87b942
#define OS_SHMMAP            23
Packit 87b942
#define OS_SHMLOCK           25
Packit 87b942
#define OS_SHMBARRIER        26
Packit 87b942
#define OS_ANNOTATE          28
Packit 87b942
Packit 87b942
#define OS_NUMEVENTS         29
Packit 87b942
Packit 87b942
#define VFSLOG_BUFFERSIZE 8192
Packit 87b942
Packit 87b942
typedef struct VfslogVfs VfslogVfs;
Packit 87b942
typedef struct VfslogFile VfslogFile;
Packit 87b942
Packit 87b942
struct VfslogVfs {
Packit 87b942
  sqlite3_vfs base;               /* VFS methods */
Packit 87b942
  sqlite3_vfs *pVfs;              /* Parent VFS */
Packit 87b942
  int iNextFileId;                /* Next file id */
Packit 87b942
  sqlite3_file *pLog;             /* Log file handle */
Packit 87b942
  sqlite3_int64 iOffset;          /* Log file offset of start of write buffer */
Packit 87b942
  int nBuf;                       /* Number of valid bytes in aBuf[] */
Packit 87b942
  char aBuf[VFSLOG_BUFFERSIZE];   /* Write buffer */
Packit 87b942
};
Packit 87b942
Packit 87b942
struct VfslogFile {
Packit 87b942
  sqlite3_file base;              /* IO methods */
Packit 87b942
  sqlite3_file *pReal;            /* Underlying file handle */
Packit 87b942
  sqlite3_vfs *pVfslog;           /* Associated VsflogVfs object */
Packit 87b942
  int iFileId;                    /* File id number */
Packit 87b942
};
Packit 87b942
Packit 87b942
#define REALVFS(p) (((VfslogVfs *)(p))->pVfs)
Packit 87b942
Packit 87b942
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Method declarations for vfslog_file.
Packit 87b942
*/
Packit 87b942
static int vfslogClose(sqlite3_file*);
Packit 87b942
static int vfslogRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
Packit 87b942
static int vfslogWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
Packit 87b942
static int vfslogTruncate(sqlite3_file*, sqlite3_int64 size);
Packit 87b942
static int vfslogSync(sqlite3_file*, int flags);
Packit 87b942
static int vfslogFileSize(sqlite3_file*, sqlite3_int64 *pSize);
Packit 87b942
static int vfslogLock(sqlite3_file*, int);
Packit 87b942
static int vfslogUnlock(sqlite3_file*, int);
Packit 87b942
static int vfslogCheckReservedLock(sqlite3_file*, int *pResOut);
Packit 87b942
static int vfslogFileControl(sqlite3_file*, int op, void *pArg);
Packit 87b942
static int vfslogSectorSize(sqlite3_file*);
Packit 87b942
static int vfslogDeviceCharacteristics(sqlite3_file*);
Packit 87b942
Packit 87b942
static int vfslogShmLock(sqlite3_file *pFile, int ofst, int n, int flags);
Packit 87b942
static int vfslogShmMap(sqlite3_file *pFile,int,int,int,volatile void **);
Packit 87b942
static void vfslogShmBarrier(sqlite3_file*);
Packit 87b942
static int vfslogShmUnmap(sqlite3_file *pFile, int deleteFlag);
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Method declarations for vfslog_vfs.
Packit 87b942
*/
Packit 87b942
static int vfslogOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
Packit 87b942
static int vfslogDelete(sqlite3_vfs*, const char *zName, int syncDir);
Packit 87b942
static int vfslogAccess(sqlite3_vfs*, const char *zName, int flags, int *);
Packit 87b942
static int vfslogFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
Packit 87b942
static void *vfslogDlOpen(sqlite3_vfs*, const char *zFilename);
Packit 87b942
static void vfslogDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
Packit 87b942
static void (*vfslogDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
Packit 87b942
static void vfslogDlClose(sqlite3_vfs*, void*);
Packit 87b942
static int vfslogRandomness(sqlite3_vfs*, int nByte, char *zOut);
Packit 87b942
static int vfslogSleep(sqlite3_vfs*, int microseconds);
Packit 87b942
static int vfslogCurrentTime(sqlite3_vfs*, double*);
Packit 87b942
Packit 87b942
static int vfslogGetLastError(sqlite3_vfs*, int, char *);
Packit 87b942
static int vfslogCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
Packit 87b942
Packit 87b942
static sqlite3_vfs vfslog_vfs = {
Packit 87b942
  1,                              /* iVersion */
Packit 87b942
  sizeof(VfslogFile),             /* szOsFile */
Packit 87b942
  INST_MAX_PATHNAME,              /* mxPathname */
Packit 87b942
  0,                              /* pNext */
Packit 87b942
  0,                              /* zName */
Packit 87b942
  0,                              /* pAppData */
Packit 87b942
  vfslogOpen,                     /* xOpen */
Packit 87b942
  vfslogDelete,                   /* xDelete */
Packit 87b942
  vfslogAccess,                   /* xAccess */
Packit 87b942
  vfslogFullPathname,             /* xFullPathname */
Packit 87b942
  vfslogDlOpen,                   /* xDlOpen */
Packit 87b942
  vfslogDlError,                  /* xDlError */
Packit 87b942
  vfslogDlSym,                    /* xDlSym */
Packit 87b942
  vfslogDlClose,                  /* xDlClose */
Packit 87b942
  vfslogRandomness,               /* xRandomness */
Packit 87b942
  vfslogSleep,                    /* xSleep */
Packit 87b942
  vfslogCurrentTime,              /* xCurrentTime */
Packit 87b942
  vfslogGetLastError,             /* xGetLastError */
Packit 87b942
  vfslogCurrentTimeInt64          /* xCurrentTime */
Packit 87b942
};
Packit 87b942
Packit 87b942
static sqlite3_io_methods vfslog_io_methods = {
Packit 87b942
  2,                              /* iVersion */
Packit 87b942
  vfslogClose,                    /* xClose */
Packit 87b942
  vfslogRead,                     /* xRead */
Packit 87b942
  vfslogWrite,                    /* xWrite */
Packit 87b942
  vfslogTruncate,                 /* xTruncate */
Packit 87b942
  vfslogSync,                     /* xSync */
Packit 87b942
  vfslogFileSize,                 /* xFileSize */
Packit 87b942
  vfslogLock,                     /* xLock */
Packit 87b942
  vfslogUnlock,                   /* xUnlock */
Packit 87b942
  vfslogCheckReservedLock,        /* xCheckReservedLock */
Packit 87b942
  vfslogFileControl,              /* xFileControl */
Packit 87b942
  vfslogSectorSize,               /* xSectorSize */
Packit 87b942
  vfslogDeviceCharacteristics,    /* xDeviceCharacteristics */
Packit 87b942
  vfslogShmMap,                   /* xShmMap */
Packit 87b942
  vfslogShmLock,                  /* xShmLock */
Packit 87b942
  vfslogShmBarrier,               /* xShmBarrier */
Packit 87b942
  vfslogShmUnmap                  /* xShmUnmap */
Packit 87b942
};
Packit 87b942
Packit 87b942
#if SQLITE_OS_UNIX && !defined(NO_GETTOD)
Packit 87b942
#include <sys/time.h>
Packit 87b942
static sqlite3_uint64 vfslog_time(){
Packit 87b942
  struct timeval sTime;
Packit 87b942
  gettimeofday(&sTime, 0);
Packit 87b942
  return sTime.tv_usec + (sqlite3_uint64)sTime.tv_sec * 1000000;
Packit 87b942
}
Packit 87b942
#elif SQLITE_OS_WIN
Packit 87b942
#include <time.h>
Packit 87b942
static sqlite3_uint64 vfslog_time(){
Packit 87b942
  FILETIME ft;
Packit 87b942
  sqlite3_uint64 u64time = 0;
Packit 87b942
 
Packit 87b942
  GetSystemTimeAsFileTime(&ft;;
Packit 87b942
Packit 87b942
  u64time |= ft.dwHighDateTime;
Packit 87b942
  u64time <<= 32;
Packit 87b942
  u64time |= ft.dwLowDateTime;
Packit 87b942
Packit 87b942
  /* ft is 100-nanosecond intervals, we want microseconds */
Packit 87b942
  return u64time /(sqlite3_uint64)10;
Packit 87b942
}
Packit 87b942
#else
Packit 87b942
static sqlite3_uint64 vfslog_time(){
Packit 87b942
  return 0;
Packit 87b942
}
Packit 87b942
#endif
Packit 87b942
Packit 87b942
static void vfslog_call(sqlite3_vfs *, int, int, sqlite3_int64, int, int, int);
Packit 87b942
static void vfslog_string(sqlite3_vfs *, const char *);
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Close an vfslog-file.
Packit 87b942
*/
Packit 87b942
static int vfslogClose(sqlite3_file *pFile){
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  int rc = SQLITE_OK;
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
Packit 87b942
  t = vfslog_time();
Packit 87b942
  if( p->pReal->pMethods ){
Packit 87b942
    rc = p->pReal->pMethods->xClose(p->pReal);
Packit 87b942
  }
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(p->pVfslog, OS_CLOSE, p->iFileId, t, rc, 0, 0);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Read data from an vfslog-file.
Packit 87b942
*/
Packit 87b942
static int vfslogRead(
Packit 87b942
  sqlite3_file *pFile, 
Packit 87b942
  void *zBuf, 
Packit 87b942
  int iAmt, 
Packit 87b942
  sqlite_int64 iOfst
Packit 87b942
){
Packit 87b942
  int rc;
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
  t = vfslog_time();
Packit 87b942
  rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(p->pVfslog, OS_READ, p->iFileId, t, rc, iAmt, (int)iOfst);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Write data to an vfslog-file.
Packit 87b942
*/
Packit 87b942
static int vfslogWrite(
Packit 87b942
  sqlite3_file *pFile,
Packit 87b942
  const void *z,
Packit 87b942
  int iAmt,
Packit 87b942
  sqlite_int64 iOfst
Packit 87b942
){
Packit 87b942
  int rc;
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
  t = vfslog_time();
Packit 87b942
  rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(p->pVfslog, OS_WRITE, p->iFileId, t, rc, iAmt, (int)iOfst);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Truncate an vfslog-file.
Packit 87b942
*/
Packit 87b942
static int vfslogTruncate(sqlite3_file *pFile, sqlite_int64 size){
Packit 87b942
  int rc;
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
  t = vfslog_time();
Packit 87b942
  rc = p->pReal->pMethods->xTruncate(p->pReal, size);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(p->pVfslog, OS_TRUNCATE, p->iFileId, t, rc, 0, (int)size);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Sync an vfslog-file.
Packit 87b942
*/
Packit 87b942
static int vfslogSync(sqlite3_file *pFile, int flags){
Packit 87b942
  int rc;
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
  t = vfslog_time();
Packit 87b942
  rc = p->pReal->pMethods->xSync(p->pReal, flags);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(p->pVfslog, OS_SYNC, p->iFileId, t, rc, flags, 0);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Return the current file-size of an vfslog-file.
Packit 87b942
*/
Packit 87b942
static int vfslogFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
Packit 87b942
  int rc;
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
  t = vfslog_time();
Packit 87b942
  rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(p->pVfslog, OS_FILESIZE, p->iFileId, t, rc, 0, (int)*pSize);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Lock an vfslog-file.
Packit 87b942
*/
Packit 87b942
static int vfslogLock(sqlite3_file *pFile, int eLock){
Packit 87b942
  int rc;
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
  t = vfslog_time();
Packit 87b942
  rc = p->pReal->pMethods->xLock(p->pReal, eLock);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(p->pVfslog, OS_LOCK, p->iFileId, t, rc, eLock, 0);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Unlock an vfslog-file.
Packit 87b942
*/
Packit 87b942
static int vfslogUnlock(sqlite3_file *pFile, int eLock){
Packit 87b942
  int rc;
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
  t = vfslog_time();
Packit 87b942
  rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(p->pVfslog, OS_UNLOCK, p->iFileId, t, rc, eLock, 0);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Check if another file-handle holds a RESERVED lock on an vfslog-file.
Packit 87b942
*/
Packit 87b942
static int vfslogCheckReservedLock(sqlite3_file *pFile, int *pResOut){
Packit 87b942
  int rc;
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
  t = vfslog_time();
Packit 87b942
  rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(p->pVfslog, OS_CHECKRESERVEDLOCK, p->iFileId, t, rc, *pResOut, 0);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** File control method. For custom operations on an vfslog-file.
Packit 87b942
*/
Packit 87b942
static int vfslogFileControl(sqlite3_file *pFile, int op, void *pArg){
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
  int rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
Packit 87b942
  if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
Packit 87b942
    *(char**)pArg = sqlite3_mprintf("vfslog/%z", *(char**)pArg);
Packit 87b942
  }
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Return the sector-size in bytes for an vfslog-file.
Packit 87b942
*/
Packit 87b942
static int vfslogSectorSize(sqlite3_file *pFile){
Packit 87b942
  int rc;
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
  t = vfslog_time();
Packit 87b942
  rc = p->pReal->pMethods->xSectorSize(p->pReal);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(p->pVfslog, OS_SECTORSIZE, p->iFileId, t, rc, 0, 0);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Return the device characteristic flags supported by an vfslog-file.
Packit 87b942
*/
Packit 87b942
static int vfslogDeviceCharacteristics(sqlite3_file *pFile){
Packit 87b942
  int rc;
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
  t = vfslog_time();
Packit 87b942
  rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(p->pVfslog, OS_DEVCHAR, p->iFileId, t, rc, 0, 0);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
static int vfslogShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
Packit 87b942
  int rc;
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
  t = vfslog_time();
Packit 87b942
  rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(p->pVfslog, OS_SHMLOCK, p->iFileId, t, rc, 0, 0);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
static int vfslogShmMap(
Packit 87b942
  sqlite3_file *pFile, 
Packit 87b942
  int iRegion, 
Packit 87b942
  int szRegion, 
Packit 87b942
  int isWrite, 
Packit 87b942
  volatile void **pp
Packit 87b942
){
Packit 87b942
  int rc;
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
  t = vfslog_time();
Packit 87b942
  rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(p->pVfslog, OS_SHMMAP, p->iFileId, t, rc, 0, 0);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
static void vfslogShmBarrier(sqlite3_file *pFile){
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
  t = vfslog_time();
Packit 87b942
  p->pReal->pMethods->xShmBarrier(p->pReal);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(p->pVfslog, OS_SHMBARRIER, p->iFileId, t, SQLITE_OK, 0, 0);
Packit 87b942
}
Packit 87b942
static int vfslogShmUnmap(sqlite3_file *pFile, int deleteFlag){
Packit 87b942
  int rc;
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
  t = vfslog_time();
Packit 87b942
  rc = p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(p->pVfslog, OS_SHMUNMAP, p->iFileId, t, rc, 0, 0);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Open an vfslog file handle.
Packit 87b942
*/
Packit 87b942
static int vfslogOpen(
Packit 87b942
  sqlite3_vfs *pVfs,
Packit 87b942
  const char *zName,
Packit 87b942
  sqlite3_file *pFile,
Packit 87b942
  int flags,
Packit 87b942
  int *pOutFlags
Packit 87b942
){
Packit 87b942
  int rc;
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  VfslogFile *p = (VfslogFile *)pFile;
Packit 87b942
  VfslogVfs *pLog = (VfslogVfs *)pVfs;
Packit 87b942
Packit 87b942
  pFile->pMethods = &vfslog_io_methods;
Packit 87b942
  p->pReal = (sqlite3_file *)&p[1];
Packit 87b942
  p->pVfslog = pVfs;
Packit 87b942
  p->iFileId = ++pLog->iNextFileId;
Packit 87b942
Packit 87b942
  t = vfslog_time();
Packit 87b942
  rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
Packit 87b942
  vfslog_call(pVfs, OS_OPEN, p->iFileId, t, rc, 0, 0);
Packit 87b942
  vfslog_string(pVfs, zName);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Delete the file located at zPath. If the dirSync argument is true,
Packit 87b942
** ensure the file-system modifications are synced to disk before
Packit 87b942
** returning.
Packit 87b942
*/
Packit 87b942
static int vfslogDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
Packit 87b942
  int rc;
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  t = vfslog_time();
Packit 87b942
  rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(pVfs, OS_DELETE, 0, t, rc, dirSync, 0);
Packit 87b942
  vfslog_string(pVfs, zPath);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Test for access permissions. Return true if the requested permission
Packit 87b942
** is available, or false otherwise.
Packit 87b942
*/
Packit 87b942
static int vfslogAccess(
Packit 87b942
  sqlite3_vfs *pVfs, 
Packit 87b942
  const char *zPath, 
Packit 87b942
  int flags, 
Packit 87b942
  int *pResOut
Packit 87b942
){
Packit 87b942
  int rc;
Packit 87b942
  sqlite3_uint64 t;
Packit 87b942
  t = vfslog_time();
Packit 87b942
  rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut);
Packit 87b942
  t = vfslog_time() - t;
Packit 87b942
  vfslog_call(pVfs, OS_ACCESS, 0, t, rc, flags, *pResOut);
Packit 87b942
  vfslog_string(pVfs, zPath);
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Populate buffer zOut with the full canonical pathname corresponding
Packit 87b942
** to the pathname in zPath. zOut is guaranteed to point to a buffer
Packit 87b942
** of at least (INST_MAX_PATHNAME+1) bytes.
Packit 87b942
*/
Packit 87b942
static int vfslogFullPathname(
Packit 87b942
  sqlite3_vfs *pVfs, 
Packit 87b942
  const char *zPath, 
Packit 87b942
  int nOut, 
Packit 87b942
  char *zOut
Packit 87b942
){
Packit 87b942
  return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Open the dynamic library located at zPath and return a handle.
Packit 87b942
*/
Packit 87b942
static void *vfslogDlOpen(sqlite3_vfs *pVfs, const char *zPath){
Packit 87b942
  return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Populate the buffer zErrMsg (size nByte bytes) with a human readable
Packit 87b942
** utf-8 string describing the most recent error encountered associated 
Packit 87b942
** with dynamic libraries.
Packit 87b942
*/
Packit 87b942
static void vfslogDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
Packit 87b942
  REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
Packit 87b942
*/
Packit 87b942
static void (*vfslogDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
Packit 87b942
  return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym);
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Close the dynamic library handle pHandle.
Packit 87b942
*/
Packit 87b942
static void vfslogDlClose(sqlite3_vfs *pVfs, void *pHandle){
Packit 87b942
  REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Populate the buffer pointed to by zBufOut with nByte bytes of 
Packit 87b942
** random data.
Packit 87b942
*/
Packit 87b942
static int vfslogRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
Packit 87b942
  return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Sleep for nMicro microseconds. Return the number of microseconds 
Packit 87b942
** actually slept.
Packit 87b942
*/
Packit 87b942
static int vfslogSleep(sqlite3_vfs *pVfs, int nMicro){
Packit 87b942
  return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro);
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Return the current time as a Julian Day number in *pTimeOut.
Packit 87b942
*/
Packit 87b942
static int vfslogCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
Packit 87b942
  return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut);
Packit 87b942
}
Packit 87b942
Packit 87b942
static int vfslogGetLastError(sqlite3_vfs *pVfs, int a, char *b){
Packit 87b942
  return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b);
Packit 87b942
}
Packit 87b942
static int vfslogCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
Packit 87b942
  return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p);
Packit 87b942
}
Packit 87b942
Packit 87b942
static void vfslog_flush(VfslogVfs *p){
Packit 87b942
#ifdef SQLITE_TEST
Packit 87b942
  extern int sqlite3_io_error_pending;
Packit 87b942
  extern int sqlite3_io_error_persist;
Packit 87b942
  extern int sqlite3_diskfull_pending;
Packit 87b942
Packit 87b942
  int pending = sqlite3_io_error_pending;
Packit 87b942
  int persist = sqlite3_io_error_persist;
Packit 87b942
  int diskfull = sqlite3_diskfull_pending;
Packit 87b942
Packit 87b942
  sqlite3_io_error_pending = 0;
Packit 87b942
  sqlite3_io_error_persist = 0;
Packit 87b942
  sqlite3_diskfull_pending = 0;
Packit 87b942
#endif
Packit 87b942
Packit 87b942
  if( p->nBuf ){
Packit 87b942
    p->pLog->pMethods->xWrite(p->pLog, p->aBuf, p->nBuf, p->iOffset);
Packit 87b942
    p->iOffset += p->nBuf;
Packit 87b942
    p->nBuf = 0;
Packit 87b942
  }
Packit 87b942
Packit 87b942
#ifdef SQLITE_TEST
Packit 87b942
  sqlite3_io_error_pending = pending;
Packit 87b942
  sqlite3_io_error_persist = persist;
Packit 87b942
  sqlite3_diskfull_pending = diskfull;
Packit 87b942
#endif
Packit 87b942
}
Packit 87b942
Packit 87b942
static void put32bits(unsigned char *p, unsigned int v){
Packit 87b942
  p[0] = v>>24;
Packit 87b942
  p[1] = (unsigned char)(v>>16);
Packit 87b942
  p[2] = (unsigned char)(v>>8);
Packit 87b942
  p[3] = (unsigned char)v;
Packit 87b942
}
Packit 87b942
Packit 87b942
static void vfslog_call(
Packit 87b942
  sqlite3_vfs *pVfs,
Packit 87b942
  int eEvent,
Packit 87b942
  int iFileid,
Packit 87b942
  sqlite3_int64 nClick,
Packit 87b942
  int return_code,
Packit 87b942
  int size,
Packit 87b942
  int offset
Packit 87b942
){
Packit 87b942
  VfslogVfs *p = (VfslogVfs *)pVfs;
Packit 87b942
  unsigned char *zRec;
Packit 87b942
  if( (24+p->nBuf)>sizeof(p->aBuf) ){
Packit 87b942
    vfslog_flush(p);
Packit 87b942
  }
Packit 87b942
  zRec = (unsigned char *)&p->aBuf[p->nBuf];
Packit 87b942
  put32bits(&zRec[0], eEvent);
Packit 87b942
  put32bits(&zRec[4], iFileid);
Packit 87b942
  put32bits(&zRec[8], (unsigned int)(nClick&0xffff));
Packit 87b942
  put32bits(&zRec[12], return_code);
Packit 87b942
  put32bits(&zRec[16], size);
Packit 87b942
  put32bits(&zRec[20], offset);
Packit 87b942
  p->nBuf += 24;
Packit 87b942
}
Packit 87b942
Packit 87b942
static void vfslog_string(sqlite3_vfs *pVfs, const char *zStr){
Packit 87b942
  VfslogVfs *p = (VfslogVfs *)pVfs;
Packit 87b942
  unsigned char *zRec;
Packit 87b942
  int nStr = zStr ? (int)strlen(zStr) : 0;
Packit 87b942
  if( (4+nStr+p->nBuf)>sizeof(p->aBuf) ){
Packit 87b942
    vfslog_flush(p);
Packit 87b942
  }
Packit 87b942
  zRec = (unsigned char *)&p->aBuf[p->nBuf];
Packit 87b942
  put32bits(&zRec[0], nStr);
Packit 87b942
  if( zStr ){
Packit 87b942
    memcpy(&zRec[4], zStr, nStr);
Packit 87b942
  }
Packit 87b942
  p->nBuf += (4 + nStr);
Packit 87b942
}
Packit 87b942
Packit 87b942
static void vfslog_finalize(VfslogVfs *p){
Packit 87b942
  if( p->pLog->pMethods ){
Packit 87b942
    vfslog_flush(p);
Packit 87b942
    p->pLog->pMethods->xClose(p->pLog);
Packit 87b942
  }
Packit 87b942
  sqlite3_free(p);
Packit 87b942
}
Packit 87b942
Packit 87b942
int sqlite3_vfslog_finalize(const char *zVfs){
Packit 87b942
  sqlite3_vfs *pVfs;
Packit 87b942
  pVfs = sqlite3_vfs_find(zVfs);
Packit 87b942
  if( !pVfs || pVfs->xOpen!=vfslogOpen ){
Packit 87b942
    return SQLITE_ERROR;
Packit 87b942
  } 
Packit 87b942
  sqlite3_vfs_unregister(pVfs);
Packit 87b942
  vfslog_finalize((VfslogVfs *)pVfs);
Packit 87b942
  return SQLITE_OK;
Packit 87b942
}
Packit 87b942
Packit 87b942
int sqlite3_vfslog_new(
Packit 87b942
  const char *zVfs,               /* New VFS name */
Packit 87b942
  const char *zParentVfs,         /* Parent VFS name (or NULL) */
Packit 87b942
  const char *zLog                /* Log file name */
Packit 87b942
){
Packit 87b942
  VfslogVfs *p;
Packit 87b942
  sqlite3_vfs *pParent;
Packit 87b942
  int nByte;
Packit 87b942
  int flags;
Packit 87b942
  int rc;
Packit 87b942
  char *zFile;
Packit 87b942
  int nVfs;
Packit 87b942
Packit 87b942
  pParent = sqlite3_vfs_find(zParentVfs);
Packit 87b942
  if( !pParent ){
Packit 87b942
    return SQLITE_ERROR;
Packit 87b942
  }
Packit 87b942
Packit 87b942
  nVfs = (int)strlen(zVfs);
Packit 87b942
  nByte = sizeof(VfslogVfs) + pParent->szOsFile + nVfs+1+pParent->mxPathname+1;
Packit 87b942
  p = (VfslogVfs *)sqlite3_malloc(nByte);
Packit 87b942
  memset(p, 0, nByte);
Packit 87b942
Packit 87b942
  p->pVfs = pParent;
Packit 87b942
  p->pLog = (sqlite3_file *)&p[1];
Packit 87b942
  memcpy(&p->base, &vfslog_vfs, sizeof(sqlite3_vfs));
Packit 87b942
  p->base.zName = &((char *)p->pLog)[pParent->szOsFile];
Packit 87b942
  p->base.szOsFile += pParent->szOsFile;
Packit 87b942
  memcpy((char *)p->base.zName, zVfs, nVfs);
Packit 87b942
Packit 87b942
  zFile = (char *)&p->base.zName[nVfs+1];
Packit 87b942
  pParent->xFullPathname(pParent, zLog, pParent->mxPathname, zFile);
Packit 87b942
Packit 87b942
  flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MASTER_JOURNAL;
Packit 87b942
  pParent->xDelete(pParent, zFile, 0);
Packit 87b942
  rc = pParent->xOpen(pParent, zFile, p->pLog, flags, &flags);
Packit 87b942
  if( rc==SQLITE_OK ){
Packit 87b942
    memcpy(p->aBuf, "sqlite_ostrace1.....", 20);
Packit 87b942
    p->iOffset = 0;
Packit 87b942
    p->nBuf = 20;
Packit 87b942
    rc = sqlite3_vfs_register((sqlite3_vfs *)p, 1);
Packit 87b942
  }
Packit 87b942
  if( rc ){
Packit 87b942
    vfslog_finalize(p);
Packit 87b942
  }
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg){
Packit 87b942
  sqlite3_vfs *pVfs;
Packit 87b942
  pVfs = sqlite3_vfs_find(zVfs);
Packit 87b942
  if( !pVfs || pVfs->xOpen!=vfslogOpen ){
Packit 87b942
    return SQLITE_ERROR;
Packit 87b942
  } 
Packit 87b942
  vfslog_call(pVfs, OS_ANNOTATE, 0, 0, 0, 0, 0);
Packit 87b942
  vfslog_string(pVfs, zMsg);
Packit 87b942
  return SQLITE_OK;
Packit 87b942
}
Packit 87b942
Packit 87b942
static const char *vfslog_eventname(int eEvent){
Packit 87b942
  const char *zEvent = 0;
Packit 87b942
Packit 87b942
  switch( eEvent ){
Packit 87b942
    case OS_CLOSE:             zEvent = "xClose"; break;
Packit 87b942
    case OS_READ:              zEvent = "xRead"; break;
Packit 87b942
    case OS_WRITE:             zEvent = "xWrite"; break;
Packit 87b942
    case OS_TRUNCATE:          zEvent = "xTruncate"; break;
Packit 87b942
    case OS_SYNC:              zEvent = "xSync"; break;
Packit 87b942
    case OS_FILESIZE:          zEvent = "xFilesize"; break;
Packit 87b942
    case OS_LOCK:              zEvent = "xLock"; break;
Packit 87b942
    case OS_UNLOCK:            zEvent = "xUnlock"; break;
Packit 87b942
    case OS_CHECKRESERVEDLOCK: zEvent = "xCheckResLock"; break;
Packit 87b942
    case OS_FILECONTROL:       zEvent = "xFileControl"; break;
Packit 87b942
    case OS_SECTORSIZE:        zEvent = "xSectorSize"; break;
Packit 87b942
    case OS_DEVCHAR:           zEvent = "xDeviceChar"; break;
Packit 87b942
    case OS_OPEN:              zEvent = "xOpen"; break;
Packit 87b942
    case OS_DELETE:            zEvent = "xDelete"; break;
Packit 87b942
    case OS_ACCESS:            zEvent = "xAccess"; break;
Packit 87b942
    case OS_FULLPATHNAME:      zEvent = "xFullPathname"; break;
Packit 87b942
    case OS_RANDOMNESS:        zEvent = "xRandomness"; break;
Packit 87b942
    case OS_SLEEP:             zEvent = "xSleep"; break;
Packit 87b942
    case OS_CURRENTTIME:       zEvent = "xCurrentTime"; break;
Packit 87b942
Packit 87b942
    case OS_SHMUNMAP:          zEvent = "xShmUnmap"; break;
Packit 87b942
    case OS_SHMLOCK:           zEvent = "xShmLock"; break;
Packit 87b942
    case OS_SHMBARRIER:        zEvent = "xShmBarrier"; break;
Packit 87b942
    case OS_SHMMAP:            zEvent = "xShmMap"; break;
Packit 87b942
Packit 87b942
    case OS_ANNOTATE:          zEvent = "annotation"; break;
Packit 87b942
  }
Packit 87b942
Packit 87b942
  return zEvent;
Packit 87b942
}
Packit 87b942
Packit 87b942
typedef struct VfslogVtab VfslogVtab;
Packit 87b942
typedef struct VfslogCsr VfslogCsr;
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Virtual table type for the vfslog reader module.
Packit 87b942
*/
Packit 87b942
struct VfslogVtab {
Packit 87b942
  sqlite3_vtab base;              /* Base class */
Packit 87b942
  sqlite3_file *pFd;              /* File descriptor open on vfslog file */
Packit 87b942
  sqlite3_int64 nByte;            /* Size of file in bytes */
Packit 87b942
  char *zFile;                    /* File name for pFd */
Packit 87b942
};
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Virtual table cursor type for the vfslog reader module.
Packit 87b942
*/
Packit 87b942
struct VfslogCsr {
Packit 87b942
  sqlite3_vtab_cursor base;       /* Base class */
Packit 87b942
  sqlite3_int64 iRowid;           /* Current rowid. */
Packit 87b942
  sqlite3_int64 iOffset;          /* Offset of next record in file */
Packit 87b942
  char *zTransient;               /* Transient 'file' string */
Packit 87b942
  int nFile;                      /* Size of array azFile[] */
Packit 87b942
  char **azFile;                  /* File strings */
Packit 87b942
  unsigned char aBuf[1024];       /* Current vfs log entry (read from file) */
Packit 87b942
};
Packit 87b942
Packit 87b942
static unsigned int get32bits(unsigned char *p){
Packit 87b942
  return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** The argument must point to a buffer containing a nul-terminated string.
Packit 87b942
** If the string begins with an SQL quote character it is overwritten by
Packit 87b942
** the dequoted version. Otherwise the buffer is left unmodified.
Packit 87b942
*/
Packit 87b942
static void dequote(char *z){
Packit 87b942
  char quote;                     /* Quote character (if any ) */
Packit 87b942
  quote = z[0];
Packit 87b942
  if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){
Packit 87b942
    int iIn = 1;                  /* Index of next byte to read from input */
Packit 87b942
    int iOut = 0;                 /* Index of next byte to write to output */
Packit 87b942
    if( quote=='[' ) quote = ']';  
Packit 87b942
    while( z[iIn] ){
Packit 87b942
      if( z[iIn]==quote ){
Packit 87b942
        if( z[iIn+1]!=quote ) break;
Packit 87b942
        z[iOut++] = quote;
Packit 87b942
        iIn += 2;
Packit 87b942
      }else{
Packit 87b942
        z[iOut++] = z[iIn++];
Packit 87b942
      }
Packit 87b942
    }
Packit 87b942
    z[iOut] = '\0';
Packit 87b942
  }
Packit 87b942
}
Packit 87b942
Packit 87b942
#ifndef SQLITE_OMIT_VIRTUALTABLE
Packit 87b942
/*
Packit 87b942
** Connect to or create a vfslog virtual table.
Packit 87b942
*/
Packit 87b942
static int vlogConnect(
Packit 87b942
  sqlite3 *db,
Packit 87b942
  void *pAux,
Packit 87b942
  int argc, const char *const*argv,
Packit 87b942
  sqlite3_vtab **ppVtab,
Packit 87b942
  char **pzErr
Packit 87b942
){
Packit 87b942
  sqlite3_vfs *pVfs;              /* VFS used to read log file */
Packit 87b942
  int flags;                      /* flags passed to pVfs->xOpen() */
Packit 87b942
  VfslogVtab *p;
Packit 87b942
  int rc;
Packit 87b942
  int nByte;
Packit 87b942
  char *zFile;
Packit 87b942
Packit 87b942
  *ppVtab = 0;
Packit 87b942
  pVfs = sqlite3_vfs_find(0);
Packit 87b942
  nByte = sizeof(VfslogVtab) + pVfs->szOsFile + pVfs->mxPathname;
Packit 87b942
  p = sqlite3_malloc(nByte);
Packit 87b942
  if( p==0 ) return SQLITE_NOMEM;
Packit 87b942
  memset(p, 0, nByte);
Packit 87b942
Packit 87b942
  p->pFd = (sqlite3_file *)&p[1];
Packit 87b942
  p->zFile = &((char *)p->pFd)[pVfs->szOsFile];
Packit 87b942
Packit 87b942
  zFile = sqlite3_mprintf("%s", argv[3]);
Packit 87b942
  if( !zFile ){
Packit 87b942
    sqlite3_free(p);
Packit 87b942
    return SQLITE_NOMEM;
Packit 87b942
  }
Packit 87b942
  dequote(zFile);
Packit 87b942
  pVfs->xFullPathname(pVfs, zFile, pVfs->mxPathname, p->zFile);
Packit 87b942
  sqlite3_free(zFile);
Packit 87b942
Packit 87b942
  flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MASTER_JOURNAL;
Packit 87b942
  rc = pVfs->xOpen(pVfs, p->zFile, p->pFd, flags, &flags);
Packit 87b942
Packit 87b942
  if( rc==SQLITE_OK ){
Packit 87b942
    p->pFd->pMethods->xFileSize(p->pFd, &p->nByte);
Packit 87b942
    sqlite3_declare_vtab(db, 
Packit 87b942
        "CREATE TABLE xxx(event, file, click, rc, size, offset)"
Packit 87b942
    );
Packit 87b942
    *ppVtab = &p->base;
Packit 87b942
  }else{
Packit 87b942
    sqlite3_free(p);
Packit 87b942
  }
Packit 87b942
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** There is no "best-index". This virtual table always does a linear
Packit 87b942
** scan of the binary VFS log file.
Packit 87b942
*/
Packit 87b942
static int vlogBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
Packit 87b942
  pIdxInfo->estimatedCost = 10.0;
Packit 87b942
  return SQLITE_OK;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Disconnect from or destroy a vfslog virtual table.
Packit 87b942
*/
Packit 87b942
static int vlogDisconnect(sqlite3_vtab *pVtab){
Packit 87b942
  VfslogVtab *p = (VfslogVtab *)pVtab;
Packit 87b942
  if( p->pFd->pMethods ){
Packit 87b942
    p->pFd->pMethods->xClose(p->pFd);
Packit 87b942
    p->pFd->pMethods = 0;
Packit 87b942
  }
Packit 87b942
  sqlite3_free(p);
Packit 87b942
  return SQLITE_OK;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Open a new vfslog cursor.
Packit 87b942
*/
Packit 87b942
static int vlogOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
Packit 87b942
  VfslogCsr *pCsr;                /* Newly allocated cursor object */
Packit 87b942
Packit 87b942
  pCsr = sqlite3_malloc(sizeof(VfslogCsr));
Packit 87b942
  if( !pCsr ) return SQLITE_NOMEM;
Packit 87b942
  memset(pCsr, 0, sizeof(VfslogCsr));
Packit 87b942
  *ppCursor = &pCsr->base;
Packit 87b942
  return SQLITE_OK;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Close a vfslog cursor.
Packit 87b942
*/
Packit 87b942
static int vlogClose(sqlite3_vtab_cursor *pCursor){
Packit 87b942
  VfslogCsr *p = (VfslogCsr *)pCursor;
Packit 87b942
  int i;
Packit 87b942
  for(i=0; i<p->nFile; i++){
Packit 87b942
    sqlite3_free(p->azFile[i]);
Packit 87b942
  }
Packit 87b942
  sqlite3_free(p->azFile);
Packit 87b942
  sqlite3_free(p->zTransient);
Packit 87b942
  sqlite3_free(p);
Packit 87b942
  return SQLITE_OK;
Packit 87b942
}
Packit 87b942
Packit 87b942
/*
Packit 87b942
** Move a vfslog cursor to the next entry in the file.
Packit 87b942
*/
Packit 87b942
static int vlogNext(sqlite3_vtab_cursor *pCursor){
Packit 87b942
  VfslogCsr *pCsr = (VfslogCsr *)pCursor;
Packit 87b942
  VfslogVtab *p = (VfslogVtab *)pCursor->pVtab;
Packit 87b942
  int rc = SQLITE_OK;
Packit 87b942
  int nRead;
Packit 87b942
Packit 87b942
  sqlite3_free(pCsr->zTransient);
Packit 87b942
  pCsr->zTransient = 0;
Packit 87b942
Packit 87b942
  nRead = 24;
Packit 87b942
  if( pCsr->iOffset+nRead<=p->nByte ){
Packit 87b942
    int eEvent;
Packit 87b942
    rc = p->pFd->pMethods->xRead(p->pFd, pCsr->aBuf, nRead, pCsr->iOffset);
Packit 87b942
Packit 87b942
    eEvent = get32bits(pCsr->aBuf);
Packit 87b942
    if( (rc==SQLITE_OK)
Packit 87b942
     && (eEvent==OS_OPEN || eEvent==OS_DELETE || eEvent==OS_ACCESS) 
Packit 87b942
    ){
Packit 87b942
      char buf[4];
Packit 87b942
      rc = p->pFd->pMethods->xRead(p->pFd, buf, 4, pCsr->iOffset+nRead);
Packit 87b942
      nRead += 4;
Packit 87b942
      if( rc==SQLITE_OK ){
Packit 87b942
        int nStr = get32bits((unsigned char *)buf);
Packit 87b942
        char *zStr = sqlite3_malloc(nStr+1);
Packit 87b942
        rc = p->pFd->pMethods->xRead(p->pFd, zStr, nStr, pCsr->iOffset+nRead);
Packit 87b942
        zStr[nStr] = '\0';
Packit 87b942
        nRead += nStr;
Packit 87b942
Packit 87b942
        if( eEvent==OS_OPEN ){
Packit 87b942
          int iFileid = get32bits(&pCsr->aBuf[4]);
Packit 87b942
          if( iFileid>=pCsr->nFile ){
Packit 87b942
            int nNew = sizeof(pCsr->azFile[0])*(iFileid+1);
Packit 87b942
            pCsr->azFile = (char **)sqlite3_realloc(pCsr->azFile, nNew);
Packit 87b942
            nNew -= sizeof(pCsr->azFile[0])*pCsr->nFile;
Packit 87b942
            memset(&pCsr->azFile[pCsr->nFile], 0, nNew);
Packit 87b942
            pCsr->nFile = iFileid+1;
Packit 87b942
          }
Packit 87b942
          sqlite3_free(pCsr->azFile[iFileid]);
Packit 87b942
          pCsr->azFile[iFileid] = zStr;
Packit 87b942
        }else{
Packit 87b942
          pCsr->zTransient = zStr;
Packit 87b942
        }
Packit 87b942
      }
Packit 87b942
    }
Packit 87b942
  }
Packit 87b942
Packit 87b942
  pCsr->iRowid += 1;
Packit 87b942
  pCsr->iOffset += nRead;
Packit 87b942
  return rc;
Packit 87b942
}
Packit 87b942
Packit 87b942
static int vlogEof(sqlite3_vtab_cursor *pCursor){
Packit 87b942
  VfslogCsr *pCsr = (VfslogCsr *)pCursor;
Packit 87b942
  VfslogVtab *p = (VfslogVtab *)pCursor->pVtab;
Packit 87b942
  return (pCsr->iOffset>=p->nByte);
Packit 87b942
}
Packit 87b942
Packit 87b942
static int vlogFilter(
Packit 87b942
  sqlite3_vtab_cursor *pCursor, 
Packit 87b942
  int idxNum, const char *idxStr,
Packit 87b942
  int argc, sqlite3_value **argv
Packit 87b942
){
Packit 87b942
  VfslogCsr *pCsr = (VfslogCsr *)pCursor;
Packit 87b942
  pCsr->iRowid = 0;
Packit 87b942
  pCsr->iOffset = 20;
Packit 87b942
  return vlogNext(pCursor);
Packit 87b942
}
Packit 87b942
Packit 87b942
static int vlogColumn(
Packit 87b942
  sqlite3_vtab_cursor *pCursor, 
Packit 87b942
  sqlite3_context *ctx, 
Packit 87b942
  int i
Packit 87b942
){
Packit 87b942
  unsigned int val;
Packit 87b942
  VfslogCsr *pCsr = (VfslogCsr *)pCursor;
Packit 87b942
Packit 87b942
  assert( i<7 );
Packit 87b942
  val = get32bits(&pCsr->aBuf[4*i]);
Packit 87b942
Packit 87b942
  switch( i ){
Packit 87b942
    case 0: {
Packit 87b942
      sqlite3_result_text(ctx, vfslog_eventname(val), -1, SQLITE_STATIC);
Packit 87b942
      break;
Packit 87b942
    }
Packit 87b942
    case 1: {
Packit 87b942
      char *zStr = pCsr->zTransient;
Packit 87b942
      if( val!=0 && val<(unsigned)pCsr->nFile ){
Packit 87b942
        zStr = pCsr->azFile[val];
Packit 87b942
      }
Packit 87b942
      sqlite3_result_text(ctx, zStr, -1, SQLITE_TRANSIENT);
Packit 87b942
      break;
Packit 87b942
    }
Packit 87b942
    default:
Packit 87b942
      sqlite3_result_int(ctx, val);
Packit 87b942
      break;
Packit 87b942
  }
Packit 87b942
Packit 87b942
  return SQLITE_OK;
Packit 87b942
}
Packit 87b942
Packit 87b942
static int vlogRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
Packit 87b942
  VfslogCsr *pCsr = (VfslogCsr *)pCursor;
Packit 87b942
  *pRowid = pCsr->iRowid;
Packit 87b942
  return SQLITE_OK;
Packit 87b942
}
Packit 87b942
Packit 87b942
int sqlite3_vfslog_register(sqlite3 *db){
Packit 87b942
  static sqlite3_module vfslog_module = {
Packit 87b942
    0,                            /* iVersion */
Packit 87b942
    vlogConnect,                /* xCreate */
Packit 87b942
    vlogConnect,                /* xConnect */
Packit 87b942
    vlogBestIndex,              /* xBestIndex */
Packit 87b942
    vlogDisconnect,             /* xDisconnect */
Packit 87b942
    vlogDisconnect,             /* xDestroy */
Packit 87b942
    vlogOpen,                   /* xOpen - open a cursor */
Packit 87b942
    vlogClose,                  /* xClose - close a cursor */
Packit 87b942
    vlogFilter,                 /* xFilter - configure scan constraints */
Packit 87b942
    vlogNext,                   /* xNext - advance a cursor */
Packit 87b942
    vlogEof,                    /* xEof - check for end of scan */
Packit 87b942
    vlogColumn,                 /* xColumn - read data */
Packit 87b942
    vlogRowid,                  /* xRowid - read data */
Packit 87b942
    0,                            /* xUpdate */
Packit 87b942
    0,                            /* xBegin */
Packit 87b942
    0,                            /* xSync */
Packit 87b942
    0,                            /* xCommit */
Packit 87b942
    0,                            /* xRollback */
Packit 87b942
    0,                            /* xFindMethod */
Packit 87b942
    0,                            /* xRename */
Packit 87b942
  };
Packit 87b942
Packit 87b942
  sqlite3_create_module(db, "vfslog", &vfslog_module, 0);
Packit 87b942
  return SQLITE_OK;
Packit 87b942
}
Packit 87b942
#endif /* SQLITE_OMIT_VIRTUALTABLE */
Packit 87b942
Packit 87b942
/**************************************************************************
Packit 87b942
***************************************************************************
Packit 87b942
** Tcl interface starts here.
Packit 87b942
*/
Packit 87b942
Packit 87b942
#if defined(SQLITE_TEST) || defined(TCLSH)
Packit 87b942
Packit 87b942
#if defined(INCLUDE_SQLITE_TCL_H)
Packit 87b942
#  include "sqlite_tcl.h"
Packit 87b942
#else
Packit 87b942
#  include "tcl.h"
Packit 87b942
#  ifndef SQLITE_TCLAPI
Packit 87b942
#    define SQLITE_TCLAPI
Packit 87b942
#  endif
Packit 87b942
#endif
Packit 87b942
Packit 87b942
static int SQLITE_TCLAPI test_vfslog(
Packit 87b942
  void *clientData,
Packit 87b942
  Tcl_Interp *interp,
Packit 87b942
  int objc,
Packit 87b942
  Tcl_Obj *CONST objv[]
Packit 87b942
){
Packit 87b942
  struct SqliteDb { sqlite3 *db; };
Packit 87b942
  sqlite3 *db;
Packit 87b942
  Tcl_CmdInfo cmdInfo;
Packit 87b942
  int rc = SQLITE_ERROR;
Packit 87b942
Packit 87b942
  static const char *strs[] = { "annotate", "finalize", "new",  "register", 0 };
Packit 87b942
  enum VL_enum { VL_ANNOTATE, VL_FINALIZE, VL_NEW, VL_REGISTER };
Packit 87b942
  int iSub;
Packit 87b942
Packit 87b942
  if( objc<2 ){
Packit 87b942
    Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
Packit 87b942
    return TCL_ERROR;
Packit 87b942
  }
Packit 87b942
  if( Tcl_GetIndexFromObj(interp, objv[1], strs, "sub-command", 0, &iSub) ){
Packit 87b942
    return TCL_ERROR;
Packit 87b942
  }
Packit 87b942
Packit 87b942
  switch( (enum VL_enum)iSub ){
Packit 87b942
    case VL_ANNOTATE: {
Packit 87b942
      char *zVfs;
Packit 87b942
      char *zMsg;
Packit 87b942
      if( objc!=4 ){
Packit 87b942
        Tcl_WrongNumArgs(interp, 3, objv, "VFS");
Packit 87b942
        return TCL_ERROR;
Packit 87b942
      }
Packit 87b942
      zVfs = Tcl_GetString(objv[2]);
Packit 87b942
      zMsg = Tcl_GetString(objv[3]);
Packit 87b942
      rc = sqlite3_vfslog_annotate(zVfs, zMsg);
Packit 87b942
      if( rc!=SQLITE_OK ){
Packit 87b942
        Tcl_AppendResult(interp, "failed", 0);
Packit 87b942
        return TCL_ERROR;
Packit 87b942
      }
Packit 87b942
      break;
Packit 87b942
    }
Packit 87b942
    case VL_FINALIZE: {
Packit 87b942
      char *zVfs;
Packit 87b942
      if( objc!=3 ){
Packit 87b942
        Tcl_WrongNumArgs(interp, 2, objv, "VFS");
Packit 87b942
        return TCL_ERROR;
Packit 87b942
      }
Packit 87b942
      zVfs = Tcl_GetString(objv[2]);
Packit 87b942
      rc = sqlite3_vfslog_finalize(zVfs);
Packit 87b942
      if( rc!=SQLITE_OK ){
Packit 87b942
        Tcl_AppendResult(interp, "failed", 0);
Packit 87b942
        return TCL_ERROR;
Packit 87b942
      }
Packit 87b942
      break;
Packit 87b942
    };
Packit 87b942
Packit 87b942
    case VL_NEW: {
Packit 87b942
      char *zVfs;
Packit 87b942
      char *zParent;
Packit 87b942
      char *zLog;
Packit 87b942
      if( objc!=5 ){
Packit 87b942
        Tcl_WrongNumArgs(interp, 2, objv, "VFS PARENT LOGFILE");
Packit 87b942
        return TCL_ERROR;
Packit 87b942
      }
Packit 87b942
      zVfs = Tcl_GetString(objv[2]);
Packit 87b942
      zParent = Tcl_GetString(objv[3]);
Packit 87b942
      zLog = Tcl_GetString(objv[4]);
Packit 87b942
      if( *zParent=='\0' ) zParent = 0;
Packit 87b942
      rc = sqlite3_vfslog_new(zVfs, zParent, zLog);
Packit 87b942
      if( rc!=SQLITE_OK ){
Packit 87b942
        Tcl_AppendResult(interp, "failed", 0);
Packit 87b942
        return TCL_ERROR;
Packit 87b942
      }
Packit 87b942
      break;
Packit 87b942
    };
Packit 87b942
Packit 87b942
    case VL_REGISTER: {
Packit 87b942
      char *zDb;
Packit 87b942
      if( objc!=3 ){
Packit 87b942
        Tcl_WrongNumArgs(interp, 2, objv, "DB");
Packit 87b942
        return TCL_ERROR;
Packit 87b942
      }
Packit 87b942
#ifdef SQLITE_OMIT_VIRTUALTABLE
Packit 87b942
      Tcl_AppendResult(interp, "vfslog not available because of "
Packit 87b942
                               "SQLITE_OMIT_VIRTUALTABLE", (void*)0);
Packit 87b942
      return TCL_ERROR;
Packit 87b942
#else
Packit 87b942
      zDb = Tcl_GetString(objv[2]);
Packit 87b942
      if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
Packit 87b942
        db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
Packit 87b942
        rc = sqlite3_vfslog_register(db);
Packit 87b942
      }
Packit 87b942
      if( rc!=SQLITE_OK ){
Packit 87b942
        Tcl_AppendResult(interp, "bad sqlite3 handle: ", zDb, (void*)0);
Packit 87b942
        return TCL_ERROR;
Packit 87b942
      }
Packit 87b942
      break;
Packit 87b942
#endif
Packit 87b942
    }
Packit 87b942
  }
Packit 87b942
Packit 87b942
  return TCL_OK;
Packit 87b942
}
Packit 87b942
Packit 87b942
int SqlitetestOsinst_Init(Tcl_Interp *interp){
Packit 87b942
  Tcl_CreateObjCommand(interp, "vfslog", test_vfslog, 0, 0);
Packit 87b942
  return TCL_OK;
Packit 87b942
}
Packit 87b942
Packit 87b942
#endif /* SQLITE_TEST */